2023-04-12 09:02:38 +00:00
/******************************************************************************************************************************
2023-04-12 09:03:08 +00:00
Date : 12 / 04 / 2023
2023-04-12 09:02:38 +00:00
Filename : LabSage_v1 .1 .9 .1
Description : updated 1.1 .9
Update - Increased threshold counting values . False alarm aversion .
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
// INCLUDE LIBRARIES
# include <TaskScheduler.h> // Install TaskScheduler Arduino Library
# include <WiFiManager.h> // Install WiFiManager Library
# include <FirebaseESP8266.h> // Install Firebase ESP8266 library (Mobitz?)
# include <MB_NTP.h>
# include <ESP8266WiFi.h>
# include <DHT.h> // Install DHT11 Library and Adafruit Unified Sensor Library
# include <Wire.h>
# include <Adafruit_Sensor.h>
# include <Adafruit_ADXL345_U.h> // Install Adafruit ADXL345 accelerometer library
// FIREBASE RTDB PATH AND KEY
# define FIREBASE_HOST "https: //smartlab-9b83e-default-rtdb.firebaseio.com/"
# define FIREBASE_AUTH "AIzaSyCiO5owTmUgosDyjL0_SqpxRoAwgKtn5-o"
// SETTING PINS FOR SENSORS
# define LED D1
# define DHTPIN D2 // Connect Data pin of DHT to D2
# define GASPIN A0 // Gas sensor analog pin
# define BUZZERPIN D7 // Connect LED to D7
# define SDA D5 // Accelerometer Serial Data
# define SCL D6 // Accelerometer Serial Clock
// DHT VARIABLE SET
# define DHTTYPE DHT11
// OBJECT DECLARATIONS
Scheduler runner ; // Multi tasking object
WiFiManager wm ; // Wi-Fi Manager Object
DHT dht ( DHTPIN , DHTTYPE ) ; // DHT Object
Adafruit_ADXL345_Unified accel = Adafruit_ADXL345_Unified ( 12345 ) ; // Accelerometer Object
//MQ2 parameter for CO Gas sensing
float gasSensor_volt ;
float RS ;
const float R0 = 2.12 ;
const float b = 1.5120222 ;
const float m = - 0.33975668 ;
float RS_R0_ratio ;
float ppm_log ;
float ppm ;
// VARIABLE DEFINITION
bool autoUpdateThresh = true ;
long timer = 0L ;
float t , h , g ; // Temp, Humidity, gas value (ppm)
bool buzz = false ; // Smoke alarm
bool coll = false ; // Collision Alarm
float x , y , z ; // Acceleration in x, y, z directions, storage variables for previous state
float sum = 0 ; // checksum for smoke detection - false alarm avoidance
unsigned int k = 0 ; // smoke alarm duration counter
float sThreshSum = 0 ; // Sum used for threshold updating
unsigned int j = 0 ; // Counter used for threshold updating
String PATH = " Devices/ " ; // Base path on RTDB
String UID = " " ; // ESP Unique ID - Device ID necessary for dynamic path allocation
// THRESHOLD VALUES // Not constant because it needs to be updated every min
float COLLISION_THRESHOLD = 12.0 ;
float SMOKE_THRESHOLD = 2000 ;
// DEFINE FIREBASE DATA OBJECTs
FirebaseData firebaseData ;
FirebaseData buzzerData ;
FirebaseData collData ;
FirebaseJson json ;
// FUNCTION DECLARATION
void dhtSetup ( void ) ;
void gasSetup ( void ) ;
void ambiRead ( void ) ;
void accelSetup ( void ) ;
void accelRead ( void ) ;
void sensorUpdate ( void ) ;
void upload ( void ) ;
void uploadAlert ( void ) ;
void sensorReset ( void ) ;
void reconnection ( void ) ;
// TASK SCHEDULE FUNCTIONS
void task1Callback ( ) { // Sensor update
// code for task 1
sensorUpdate ( ) ;
}
void task2Callback ( ) { // Sensor value upload
// code for task 2
if ( WiFi . status ( ) = = WL_CONNECTED ) {
upload ( ) ;
}
else {
Serial . println ( " Connection Lost! " ) ;
digitalWrite ( LED , ! digitalRead ( LED ) ) ;
Serial . println ( " Please Reconnect to a different WiFi. \n Starting Soft API... " ) ;
reconnection ( ) ;
}
}
void task3Callback ( ) { // Reset receive and execute
// Check if there is a fire/smoke
if ( WiFi . status ( ) = = WL_CONNECTED ) {
if ( Firebase . getBool ( buzzerData , PATH + " /reset " ) & & buzzerData . boolData ( ) = = true ) { //Read from firebase for application
Serial . println ( " Call to reset " ) ;
sensorReset ( ) ;
if ( Firebase . setBool ( firebaseData , PATH + " /reset " , false ) ) // Reset the 'reset' value on the database
{
Serial . println ( " PASSED " ) ;
Serial . println ( " PATH: " + firebaseData . dataPath ( ) ) ;
Serial . println ( " TYPE: " + firebaseData . dataType ( ) ) ;
Serial . println ( " ETag: " + firebaseData . ETag ( ) ) ;
Serial . println ( " ------------------------------------ " ) ;
Serial . println ( ) ;
}
else
{
Serial . println ( " FAILED " ) ;
Serial . println ( " REASON: " + firebaseData . errorReason ( ) ) ;
Serial . println ( " ------------------------------------ " ) ;
Serial . println ( ) ;
}
uploadAlert ( ) ; // Resetting buzzer and collision values on rtdb
}
if ( Firebase . getFloat ( collData , PATH + " /collThresh " ) & & collData . floatData ( ) ! = COLLISION_THRESHOLD ) { //Read from firebase for application
COLLISION_THRESHOLD = collData . floatData ( ) ;
Serial . print ( " New Collision Threshold = " ) ;
Serial . println ( COLLISION_THRESHOLD ) ;
}
if ( Firebase . getFloat ( buzzerData , PATH + " /smokeThresh " ) & & buzzerData . floatData ( ) ! = SMOKE_THRESHOLD ) { //Read from firebase for application
SMOKE_THRESHOLD = buzzerData . floatData ( ) ;
Serial . print ( " New Smoke Threshold = " ) ;
Serial . println ( SMOKE_THRESHOLD ) ;
}
if ( buzz | | coll ) {
uploadAlert ( ) ; // Setting the buzzer and collision values on rtdb
}
}
else {
Serial . println ( " Connection Lost! " ) ;
digitalWrite ( LED , ! digitalRead ( LED ) ) ;
Serial . println ( " Please Reconnect to a different WiFi. \n Starting Soft API... " ) ;
reconnection ( ) ;
}
}
void task4Callback ( ) { // Update Smoke sensor threshold
// code for task 4
if ( autoUpdateThresh ) {
if ( sThreshSum ! = 0 ) { // To avoid accidental wrongful updates
if ( j = = 0 ) { // To avoid divide-by-zero error
j = 1 ;
}
SMOKE_THRESHOLD = sThreshSum / j + 2000 ; // Taking an average value of gas sensor readings because depending on use, the threshold changes greatly
Serial . print ( " Smoke threshold auto updated to " ) ;
Serial . println ( SMOKE_THRESHOLD ) ;
sThreshSum = 0 ; // Reset these values for counting again
j = 0 ;
}
}
if ( WiFi . status ( ) = = WL_CONNECTED ) {
if ( Firebase . setFloat ( firebaseData , PATH + " /smokeThresh " , SMOKE_THRESHOLD ) ) // Update Smoke Threshold
{
Serial . println ( " PASSED " ) ;
Serial . println ( " PATH: " + firebaseData . dataPath ( ) ) ;
Serial . println ( " TYPE: " + firebaseData . dataType ( ) ) ;
Serial . println ( " ETag: " + firebaseData . ETag ( ) ) ;
Serial . println ( " ------------------------------------ " ) ;
Serial . println ( ) ;
}
else
{
Serial . println ( " FAILED " ) ;
Serial . println ( " REASON: " + firebaseData . errorReason ( ) ) ;
Serial . println ( " ------------------------------------ " ) ;
Serial . println ( ) ;
}
}
}
Task t1 ( 1000 , TASK_FOREVER , & task1Callback ) ; // Task rate: Once every second
Task t2 ( 60000 , TASK_FOREVER , & task2Callback ) ; // Task rate: Once every minute
Task t3 ( 3000 , TASK_FOREVER , & task3Callback ) ; // Task rate: Once every 3 seconds
Task t4 ( 30000 , TASK_FOREVER , & task4Callback ) ; // Task rate: Once every 30 seconds
// SETUP
void setup ( ) {
// Set Pin Modes
pinMode ( LED , OUTPUT ) ;
digitalWrite ( LED , LOW ) ;
pinMode ( BUZZERPIN , OUTPUT ) ;
Serial . begin ( 9600 ) ;
dhtSetup ( ) ;
accelSetup ( ) ;
gasSetup ( ) ;
UID = ESP . getChipId ( ) ; // Extract Unique Chip ID for authentication and identity purposes
Serial . printf ( " ESP8266 Unique Chip id = %s \n " , UID ) ; // For hex representation, use %08X
Serial . println ( ) ;
Serial . println ( " Opening WiFi AP " ) ;
// wm.resetSettings(); // Comment out before deployment
bool res ;
wm . setConnectTimeout ( 60 ) ;
wm . setConfigPortalTimeoutCallback ( reconnection ) ;
wm . setWiFiAutoReconnect ( true ) ;
res = wm . autoConnect ( " SMI_LBS_ESP " ) ; // auto generated AP name from chipid
wm . setShowInfoUpdate ( false ) ;
wm . setShowInfoErase ( false ) ;
if ( ! res ) {
Serial . println ( " Failed to connect " ) ;
}
else {
//if you get here you have connected to the WiFi
Serial . println ( " Connected " ) ;
}
Firebase . begin ( FIREBASE_HOST , FIREBASE_AUTH ) ; // Begin Firebase Server
Firebase . reconnectWiFi ( true ) ;
Serial . println ( PATH . concat ( UID ) ) ; // Dynamic database path allocation
if ( Firebase . setFloat ( firebaseData , PATH + " /smokeThresh " , SMOKE_THRESHOLD ) ) //Uploading the default smoke threshold for the first time
{
Serial . println ( " PASSED " ) ;
Serial . println ( " PATH: " + firebaseData . dataPath ( ) ) ;
Serial . println ( " TYPE: " + firebaseData . dataType ( ) ) ;
Serial . println ( " ETag: " + firebaseData . ETag ( ) ) ;
Serial . println ( " ------------------------------------ " ) ;
Serial . println ( ) ;
}
else
{
Serial . println ( " FAILED " ) ;
Serial . println ( " REASON: " + firebaseData . errorReason ( ) ) ;
Serial . println ( " ------------------------------------ " ) ;
Serial . println ( ) ;
}
if ( Firebase . setFloat ( firebaseData , PATH + " /collThresh " , COLLISION_THRESHOLD ) ) // Uploading the default collision threshold for the first time
{
Serial . println ( " PASSED " ) ;
Serial . println ( " PATH: " + firebaseData . dataPath ( ) ) ;
Serial . println ( " TYPE: " + firebaseData . dataType ( ) ) ;
Serial . println ( " ETag: " + firebaseData . ETag ( ) ) ;
Serial . println ( " ------------------------------------ " ) ;
Serial . println ( ) ;
}
else
{
Serial . println ( " FAILED " ) ;
Serial . println ( " REASON: " + firebaseData . errorReason ( ) ) ;
Serial . println ( " ------------------------------------ " ) ;
Serial . println ( ) ;
}
digitalWrite ( LED , HIGH ) ;
runner . init ( ) ; // Initialise Scheduler, add tasks to it, and then enable the tasks for multitasking
runner . addTask ( t1 ) ;
runner . addTask ( t2 ) ;
runner . addTask ( t3 ) ;
runner . addTask ( t4 ) ;
t1 . enable ( ) ;
t2 . enable ( ) ;
t3 . enable ( ) ;
t4 . enable ( ) ;
timer = millis ( ) ;
}
// MAIN LOOP CODE
void loop ( ) {
runner . execute ( ) ; // Run the tasks simultaneously
}
void reconnection ( void ) { // Re-establishing network with new Wi-Fi using Soft AP
bool res = wm . autoConnect ( ) ;
if ( ! res ) {
Serial . println ( " Failed to connect " ) ;
}
else {
Serial . println ( " Connected " ) ;
}
}
void accelSetup ( void ) { // Setup Accelerometer
Serial . println ( " Accelerometer Test " ) ; Serial . println ( " " ) ;
// Initialise I2C communication as MASTER
Wire . begin ( SDA , SCL ) ;
if ( ! accel . begin ( ) ) {
Serial . println ( " Failed to initialize ADXL345 sensor. " ) ;
while ( 1 ) ;
}
accel . setRange ( ADXL345_RANGE_16_G ) ; // Setting Max Range
// Get accelerometer data
sensors_event_t event ;
accel . getEvent ( & event ) ;
// Assign current values to states
x = event . acceleration . x ;
y = event . acceleration . y ;
z = event . acceleration . z ;
Serial . println ( " Accelerometer Ready! " ) ; Serial . println ( " " ) ;
}
void accelRead ( void ) { // Read Accelerometer
// Get accelerometer data
sensors_event_t event ;
accel . getEvent ( & event ) ;
// Print the accelerometer data to serial monitor
Serial . print ( " Acceleration: " ) ;
Serial . print ( event . acceleration . x ) ;
Serial . print ( " m/s^2 " ) ;
Serial . print ( event . acceleration . y ) ;
Serial . print ( " m/s^2 " ) ;
Serial . print ( event . acceleration . z ) ;
Serial . println ( " m/s^2 " ) ;
if ( isnan ( event . acceleration . x ) | | isnan ( event . acceleration . y ) | | isnan ( event . acceleration . z ) ) {
Serial . println ( F ( " Failed to read from Accelerometer! " ) ) ;
return ;
}
// Check if there is a collision
if ( ( abs ( event . acceleration . x - x ) ) > COLLISION_THRESHOLD | |
( abs ( event . acceleration . y - y ) ) > COLLISION_THRESHOLD | |
( abs ( event . acceleration . z - z ) ) > COLLISION_THRESHOLD ) {
Serial . println ( " Collision detected! " ) ;
coll = true ;
tone ( BUZZERPIN , 100 ) ;
}
// Assign current values to states
x = event . acceleration . x ;
y = event . acceleration . y ;
z = event . acceleration . z ;
}
void dhtSetup ( void ) { // Setup DHT11
Serial . println ( F ( " DHT11 setting up... " ) ) ;
dht . begin ( ) ;
Serial . println ( " DHT11 ready! " ) ;
}
void gasSetup ( void ) { // Setup MQ-2 Smoke Sensor
Serial . println ( " Gas Sensor setting up... " ) ;
pinMode ( GASPIN , INPUT_PULLUP ) ;
delay ( 10000 ) ; // 10 second delay for some level of preheating
int maxG = 0 ;
// Smoke Threshold established by taking average of the first five readings from the sensor
int cnt = 100 ;
float temp = 0 ;
for ( int i = 0 ; i < cnt ; i + + ) {
float gasSensorValue = analogRead ( GASPIN ) ;
gasSensor_volt = gasSensorValue / 1024 * 5.0 ;
RS = ( ( 5 - gasSensor_volt ) / gasSensor_volt ) ;
RS_R0_ratio = RS / R0 ;
ppm_log = ( ( log ( RS_R0_ratio ) - b ) / m ) ;
ppm = pow ( 10 , ppm_log ) ;
// Check if any reads failed and exit early (to try again).
if ( isnan ( ppm ) ) {
Serial . println ( F ( " Failed to read from Gas sensor! " ) ) ;
return ;
}
if ( ppm > maxG ) maxG = ppm ;
temp = temp + ppm ;
delay ( 500 ) ;
}
SMOKE_THRESHOLD = SMOKE_THRESHOLD + maxG ; //(temp / cnt); // Taking an average value of gas sensor readings because depending on use, the threshold changes greatly
Serial . println ( " Gas Sensor ready! " ) ;
Serial . printf ( " \n Smoke Threshold: %f ppm \n " , SMOKE_THRESHOLD ) ;
Serial . println ( " " ) ;
}
void ambiRead ( void ) { // Temp, Humidity, Gas reading
// Read relative humidity in % (the default)
h = dht . readHumidity ( ) ;
// Read temperature as Celsius (the default)
t = dht . readTemperature ( ) ;
// Read gas sensor analog data
float gasSensorValue = analogRead ( GASPIN ) ;
gasSensor_volt = gasSensorValue / 1024 * 5.0 ;
RS = ( ( 5 - gasSensor_volt ) / gasSensor_volt ) ;
RS_R0_ratio = RS / R0 ;
ppm_log = ( ( log ( RS_R0_ratio ) - b ) / m ) ;
ppm = pow ( 10 , ppm_log ) ;
g = ppm ;
/*
IF SMOKE THRESHOLD SHOULD BE UPDATED EVEN WITH THE SMOKE VALUES , UNCOMMENT THE FOLLOWING
sThreshSum + = g ;
j + + ;
AND COMMENT IT IN LINES 412 - 413 ( SUBJECT TO CHANGE )
*/
// Check if any reads failed and exit early (to try again).
if ( isnan ( h ) | | isnan ( t ) ) {
Serial . println ( F ( " Failed to read from DHT sensor! " ) ) ;
return ;
}
if ( isnan ( g ) ) {
Serial . println ( F ( " Failed to read from Gas sensor! " ) ) ;
return ;
}
if ( t > 50 ) {
Serial . println ( " Fire Detected! " ) ;
buzz = true ;
tone ( BUZZERPIN , 400 ) ;
}
// Smoke Detection
if ( g > SMOKE_THRESHOLD & & ( ( millis ( ) - timer ) > 180000 ) ) { // excluding the first 3 minutes of the program running to ensure no false alarms
sum + = g ;
k + + ;
Serial . println ( " Smoke detected! " ) ;
buzz = true ;
tone ( BUZZERPIN , 400 ) ;
}
else { // If smoke is not detected, continue to updating the smoke threshold
// because smoke threshold ideally should not be updated for beyond limit values
sThreshSum + = g ;
j + + ;
// if fewer than 5 values are detecting smoke and it comes back to regular measurement, it is detected as a false alarm and the alarm auto turns off.
if ( k < = 5 ) { // Temporary tolerance count is 5 readings. Could change it depending on the tolerance desired.
buzz = false ;
if ( coll = = false ) {
noTone ( BUZZERPIN ) ;
}
}
}
Serial . print ( F ( " Humidity: " ) ) ;
Serial . print ( h ) ;
Serial . print ( F ( " % Temperature: " ) ) ;
Serial . print ( t ) ;
Serial . print ( F ( " C PPM: " ) ) ;
Serial . print ( g ) ;
Serial . println ( ) ;
}
void sensorUpdate ( void ) {
ambiRead ( ) ;
accelRead ( ) ;
}
void sensorReset ( void ) {
coll = false ;
buzz = false ;
noTone ( BUZZERPIN ) ;
sum = 0 ;
k = 0 ;
}
void upload ( void ) { // Uploading Sensor values
if ( Firebase . setFloat ( firebaseData , PATH + " /temperature " , t ) )
{
Serial . println ( " PASSED " ) ;
Serial . println ( " PATH: " + firebaseData . dataPath ( ) ) ;
Serial . println ( " TYPE: " + firebaseData . dataType ( ) ) ;
Serial . println ( " ETag: " + firebaseData . ETag ( ) ) ;
Serial . println ( " ------------------------------------ " ) ;
Serial . println ( ) ;
}
else
{
Serial . println ( " FAILED " ) ;
Serial . println ( " REASON: " + firebaseData . errorReason ( ) ) ;
Serial . println ( " ------------------------------------ " ) ;
Serial . println ( ) ;
}
if ( Firebase . setFloat ( firebaseData , PATH + " /humidity " , h ) )
{
Serial . println ( " PASSED " ) ;
Serial . println ( " PATH: " + firebaseData . dataPath ( ) ) ;
Serial . println ( " TYPE: " + firebaseData . dataType ( ) ) ;
Serial . println ( " ETag: " + firebaseData . ETag ( ) ) ;
Serial . println ( " ------------------------------------ " ) ;
Serial . println ( ) ;
}
else
{
Serial . println ( " FAILED " ) ;
Serial . println ( " REASON: " + firebaseData . errorReason ( ) ) ;
Serial . println ( " ------------------------------------ " ) ;
Serial . println ( ) ;
}
if ( Firebase . setFloat ( firebaseData , PATH + " /ppm " , g ) )
{
Serial . println ( " PASSED " ) ;
Serial . println ( " PATH: " + firebaseData . dataPath ( ) ) ;
Serial . println ( " TYPE: " + firebaseData . dataType ( ) ) ;
Serial . println ( " ETag: " + firebaseData . ETag ( ) ) ;
Serial . println ( " ------------------------------------ " ) ;
Serial . println ( ) ;
}
else
{
Serial . println ( " FAILED " ) ;
Serial . println ( " REASON: " + firebaseData . errorReason ( ) ) ;
Serial . println ( " ------------------------------------ " ) ;
Serial . println ( ) ;
}
if ( Firebase . setFloat ( firebaseData , PATH + " /x " , x ) )
{
Serial . println ( " PASSED " ) ;
Serial . println ( " PATH: " + firebaseData . dataPath ( ) ) ;
Serial . println ( " TYPE: " + firebaseData . dataType ( ) ) ;
Serial . println ( " ETag: " + firebaseData . ETag ( ) ) ;
Serial . println ( " ------------------------------------ " ) ;
Serial . println ( ) ;
}
else
{
Serial . println ( " FAILED " ) ;
Serial . println ( " REASON: " + firebaseData . errorReason ( ) ) ;
Serial . println ( " ------------------------------------ " ) ;
Serial . println ( ) ;
}
if ( Firebase . setFloat ( firebaseData , PATH + " /y " , y ) )
{
Serial . println ( " PASSED " ) ;
Serial . println ( " PATH: " + firebaseData . dataPath ( ) ) ;
Serial . println ( " TYPE: " + firebaseData . dataType ( ) ) ;
Serial . println ( " ETag: " + firebaseData . ETag ( ) ) ;
Serial . println ( " ------------------------------------ " ) ;
Serial . println ( ) ;
}
else
{
Serial . println ( " FAILED " ) ;
Serial . println ( " REASON: " + firebaseData . errorReason ( ) ) ;
Serial . println ( " ------------------------------------ " ) ;
Serial . println ( ) ;
}
if ( Firebase . setFloat ( firebaseData , PATH + " /z " , z ) )
{
Serial . println ( " PASSED " ) ;
Serial . println ( " PATH: " + firebaseData . dataPath ( ) ) ;
Serial . println ( " TYPE: " + firebaseData . dataType ( ) ) ;
Serial . println ( " ETag: " + firebaseData . ETag ( ) ) ;
Serial . println ( " ------------------------------------ " ) ;
Serial . println ( ) ;
}
else
{
Serial . println ( " FAILED " ) ;
Serial . println ( " REASON: " + firebaseData . errorReason ( ) ) ;
Serial . println ( " ------------------------------------ " ) ;
Serial . println ( ) ;
}
}
void uploadAlert ( void ) { // Uploading Alarm status
if ( Firebase . setBool ( firebaseData , PATH + " /buzzer " , buzz ) )
{
Serial . println ( " PASSED " ) ;
Serial . println ( " PATH: " + firebaseData . dataPath ( ) ) ;
Serial . println ( " TYPE: " + firebaseData . dataType ( ) ) ;
Serial . println ( " ETag: " + firebaseData . ETag ( ) ) ;
Serial . println ( " ------------------------------------ " ) ;
Serial . println ( ) ;
}
else
{
Serial . println ( " FAILED " ) ;
Serial . println ( " REASON: " + firebaseData . errorReason ( ) ) ;
Serial . println ( " ------------------------------------ " ) ;
Serial . println ( ) ;
}
if ( Firebase . setBool ( firebaseData , PATH + " /collision " , coll ) )
{
Serial . println ( " PASSED " ) ;
Serial . println ( " PATH: " + firebaseData . dataPath ( ) ) ;
Serial . println ( " TYPE: " + firebaseData . dataType ( ) ) ;
Serial . println ( " ETag: " + firebaseData . ETag ( ) ) ;
Serial . println ( " ------------------------------------ " ) ;
Serial . println ( ) ;
}
else
{
Serial . println ( " FAILED " ) ;
Serial . println ( " REASON: " + firebaseData . errorReason ( ) ) ;
Serial . println ( " ------------------------------------ " ) ;
Serial . println ( ) ;
}
}