Kalif Purce
Published © MIT

Capstone Project-Smart Restroom

Have you ever been in a large city looking for a restroom and cannot find one for public use, I created this to hopefully solve this problem

IntermediateShowcase (no instructions)102
Capstone Project-Smart Restroom

Things used in this project

Hardware components

Argon
Particle Argon
×1
Particle featherwing Tripler Board
×1
Water Sensors
×1
SG90 Micro-servo motor
SG90 Micro-servo motor
×1
Occupancy Sensor
×1
mq-3 Sensor for air quality
×1
0.96" OLED 64x128 Display Module
ElectroPeak 0.96" OLED 64x128 Display Module
×1
Relay connected to a Target MiniFan
×1

Software apps and online services

Visual Studio Code Extension for Arduino
Microsoft Visual Studio Code Extension for Arduino

Hand tools and fabrication machines

Soldering iron (generic)
Soldering iron (generic)

Story

Read more

Schematics

Capstone Fritzing Layout

Argon on featherboard with GPS

All sensors laid out next to each other

Written schematic(Power and Ground unattached for each)

Dashboard Layout

Pieces and their functions 1

Pieces and their functions 2

Code

Code in completion

C/C++
/*
 * Project Capstone
 * Description:Smart Restroom
 * Author:Kalif Purce
 * Date:July 30th, 2021
 */

#include "credentials.h"
#include <JsonParserGeneratorRK.h>

//Dashboard library setup
#include <Adafruit_MQTT.h>
#include "Adafruit_MQTT/Adafruit_MQTT.h"
#include "Adafruit_MQTT/Adafruit_MQTT_SPARK.h"

//Library setup for particle and GPS
#include "Particle.h"
#include "TinyGPS++.h"
const unsigned long PUBLISH_PERIOD = 120000;
const unsigned long SERIAL_PERIOD = 5000;
const unsigned long MAX_GPS_AGE_MS = 10000;
TinyGPSPlus gps;
//Setting offset to PST
const int UTC_offset = -6;
unsigned long lastSerial = 0;
unsigned long lastPublish = 0;
unsigned long startFix = 0;
bool gettingFix = false;
//Longitude,Latitude,Altitude
float lat, lon, alt;

//rotation setting for oled, and its defines,library's, etc
int rot = 0;
#include "Adafruit_GFX.h"
#include "Adafruit_SSD1306.h"
#define OLED_RESET 4        // Reset pin # (or -1 if sharing Arduino reset pin)
#define SCREEN_ADDRESS 0x3C ///< See datasheet for Address; 0x3D for 128x64, 0x3C for 128x32
Adafruit_SSD1306 display(OLED_RESET);

Servo myServo;

//Water Sensor Setup
const int WATERSENSORTOILET = A0;
int waterSensorTValue;

const int WATERSENSORSINK = A1;
int waterSensorSValue;

//Occupancy Sensor Setup
const int OCCUPANTSENSOR = A2;
int occupantSensorValue;

//Air Quality Sensor Setup
const int AIRQUALITYSENSOR = A3;
int airQualitySensorValue;

//Setting Servo Position
int servoPosition = 0;

const int SERVOPIN = D5;

const int RELAYPIN = D6;

int Hour;
//adafruit.io settings for publish and sub
TCPClient TheClient;
Adafruit_MQTT_SPARK mqtt(&TheClient, AIO_SERVER, AIO_SERVERPORT, AIO_USERNAME, AIO_KEY);
Adafruit_MQTT_Publish GPSObject = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/GPS");
Adafruit_MQTT_Publish ToiletSensorObject = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/toiletsensor");
Adafruit_MQTT_Publish SinkSensorObject = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/sinksensor");
Adafruit_MQTT_Publish AirQualityObject = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/air-quality");
Adafruit_MQTT_Publish OccupancyObject = Adafruit_MQTT_Publish(&mqtt, AIO_USERNAME "/feeds/occupancy");
unsigned long last, lastTime;
unsigned long timeStamp; //Timestamp for current time
unsigned long lastStamp;

//oled and adafruit live time
String DateTime, TimeOnly;
float gpsValue, sinkSensorValue, toiletSensorValue, airQualityValue, OccupancyValue;

void setup()

{

  Serial.begin(9600);

  //Servo motor set to D5 pin
  myServo.attach(SERVOPIN);

  //Fan via relay set to D6 pin
  pinMode(RELAYPIN, OUTPUT);

  // The GPS module initialization
  Serial1.begin(9600);
  startFix = millis();
  gettingFix = true;

  // //PinMode setup for water sensor
  pinMode(WATERSENSORTOILET, INPUT);
  pinMode(WATERSENSORSINK, INPUT);

  //Oled display turned on
  display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
  helloWorld();
  Serial.printf("Hello World\n");

  Time.zone(-7);       // MST = -7, MDT = -6
  Particle.syncTime(); // Sync time with Particle Cloud
}

void loop()

{
  //connects argon to MQTT Service
  MQTT_connect();
  timeStamp = millis();      // TIMESTAMP TO MILLISECONDS
  DateTime = Time.timeStr(); // Current Date and Time from Particle Time class
  TimeOnly = DateTime.substring(11, 13);
  Hour = TimeOnly.toInt();
  //turns on gps printouts
  while (Serial1.available() > 0)
  {
    if (gps.encode(Serial1.read()))
    {
      displayGPSInfo();
    }
  }
  delay(1000);

  analogReads();

  servoMotor();

  FanWithOccupancyAndAQ();

  // AirQualityfan();

  MQTTPing();

  MQTTPublish();

  // the . c_str () method converts a String to an array of char
  Serial.printf(" Date and time is %s\n", DateTime.c_str());
  Serial.printf(" Time is %i\n", TimeOnly.toInt());
  delay(1000); // only loop every 10 seconds
}

//Does just about everything for GPS prints/time and display outputs
void displayGPSInfo()
{
  float lat, lon, alt;
  uint8_t hr, mn, se, sat;
  if (millis() - lastSerial >= SERIAL_PERIOD)
  {
    lastSerial = millis();

    char buf[128];
    if (gps.location.isValid() && gps.location.age() < MAX_GPS_AGE_MS)
    {
      lat = gps.location.lat();
      lon = gps.location.lng();
      alt = gps.altitude.meters();
      hr = gps.time.hour();
      mn = gps.time.minute();
      se = gps.time.second();
      sat = gps.satellites.value();

      if (hr > 7)
      {
        hr = hr + UTC_offset;
      }
      else
      {
        hr = hr + 24 + UTC_offset;
      }
      Serial.printf("Time: %02i:%02i:%02i --- ", hr, mn, se);
      Serial.printf("lat: %f, long: %f, alt: %f \n", lat, lon, alt);
      if (gettingFix)
      {
        gettingFix = false;
        unsigned long elapsed = millis() - startFix;
        Serial.printlnf("%lu milliseconds to get GPS fix", elapsed);
      }
      display.clearDisplay();
      display.setCursor(0, 0);
      display.printf("Time: %02i:%02i:%02i \n", hr, mn, se);
      display.printf("lat  %f \nlong %f \nalt %f\n", lat, lon, alt);
      display.printf("satelites %i", sat);
      display.display();
    }
    else
    {
      strcpy(buf, "no location");
      if (!gettingFix)
      {
        gettingFix = true;
        startFix = millis();
      }
    }
  }
}

//GPS initialization for GPS
void helloWorld()
{
  display.clearDisplay();
  display.setTextSize(1);
  display.setTextColor(WHITE);
  display.setCursor(20, 5);
  display.println("GPS Initializing");
  display.display();
}

//connects MQTT automatically using function
void MQTT_connect()
{
  int8_t ret;
  // Stop if already connected.
  if (mqtt.connected())
  {
    return;
  }
  Serial.print("Connecting to MQTT... ");
  while ((ret = mqtt.connect()) != 0)
  { // connect will return 0 for connected
    Serial.printf("%s\n", (char *)mqtt.connectErrorString(ret));
    Serial.printf("Retrying MQTT connection in 5 seconds..\n");
    mqtt.disconnect();
    delay(5000); // wait 5 seconds
  }
  Serial.printf("MQTT Connected!\n");
}

//JSON for gps on dashboard
void createEventPayLoad()
{
  JsonWriterStatic<256> jw;
  {
    JsonWriterAutoObject obj(&jw);

    jw.insertKeyValue("lat", gps.location.lat());
    jw.insertKeyValue("lon", gps.location.lng());
  }
  GPSObject.publish(jw.getBuffer());
}

//Analog Readouts for water sensors,occupancy sensor, and Air Quality Sensor
void analogReads()
{
  //Reading WaterSensor Value
  waterSensorTValue = analogRead(WATERSENSORTOILET);
  Serial.printf("Behind Toilet Water Value is %d \n", waterSensorTValue);
  //Reading WaterSensor Value
  waterSensorSValue = analogRead(WATERSENSORSINK);
  Serial.printf("Sink Water Value is %d \n", waterSensorSValue);
  //Reading AirQuality
  airQualitySensorValue = analogRead(AIRQUALITYSENSOR);
  Serial.printf("air Quality is %d \n", airQualitySensorValue);
  //Reading Occupancy Value
  occupantSensorValue = analogRead(OCCUPANTSENSOR);
  Serial.printf("Occupancy value is %d \n", occupantSensorValue);
}

//Setting servo motor to turn on and off via time signature
void servoMotor()
{
  if ((Hour >= 13) && (servoPosition != 180))
  {
     servoPosition=180;
    myServo.write(servoPosition);                                 // tell servo to go to position in variable 'pos'
  }
  if ((Hour < 13) && (servoPosition != 0))
   {
     servoPosition=5;
        myServo.write(servoPosition);
  }
}

//pings MQTT to see if still active
void MQTTPing()
{
  //MQTT ping to make sure it still works
  if ((millis() - last) > 120000)
  {
    Serial.printf("Pinging MQTT \n");
    if (!mqtt.ping())
    {
      Serial.printf("Disconnecting \n");
      mqtt.disconnect();
    }
    last = millis();
  }
}

//publishes mqtt to cloud every 30 seconds
void MQTTPublish()
{
  toiletSensorValue = (analogRead(A0));
  sinkSensorValue = (analogRead(A1));
  occupantSensorValue = (analogRead(A2));
  airQualityValue = (analogRead(A3));
  if ((millis() - lastTime > 15000))
  {
    if (mqtt.Update())
    {
      createEventPayLoad();
      ToiletSensorObject.publish(toiletSensorValue);
      SinkSensorObject.publish(sinkSensorValue);
      AirQualityObject.publish(airQualityValue);
      OccupancyObject.publish(occupantSensorValue);
    }
    lastTime = millis();
  }
}

//turns on fan when occupancy sensor detects movement or air quality is harmful
void FanWithOccupancyAndAQ()
{
  if (analogRead(A2) >= 2200 | analogRead(A3) >= 1000)
  {
    digitalWrite(D6, HIGH);
  }
  else
  {
    digitalWrite(D6, LOW);
  }
}

Credits

Kalif Purce

Kalif Purce

3 projects • 7 followers

Comments

Add projectSign up / Login