Files
lab-sage/Arduino/labsage_v1.1_6.ino
2023-03-01 08:28:41 +00:00

489 lines
15 KiB
C++

/******************************************************************************************************************************
* Date: 28/02/2023
* Filename: LabSage_v1.1.5
* Description: ESP Multitasking + EMS
* Update - Changing thresholds, re-timing tasks - Resetting GAS threshold as constant value due to large difference
*****************************************************************************************************************************/
// 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
#define SCL D6
// DHT VARIABLE SET
#define DHTTYPE DHT11
// OBJECT DECLARATIONS
Scheduler runner;
WiFiManager wm;
DHT dht(DHTPIN, DHTTYPE);
Adafruit_ADXL345_Unified accel = Adafruit_ADXL345_Unified(12345);
//MQ2 parameter for LPG/Smoke 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
float t, h, g;
String buzz = "0";
String coll = "0";
float x, y, z;
String PATH = "Devices/";
String UID = "";
float sum = 0;
int k = 0;
// THRESHOLD VALUES
const float COLLISION_THRESHOLD = 10.0; // Too sensitive perhaps?
const float SMOKE_THRESHOLD = 15000; // NEEDS TO BE UPLOADED TO THE BOARD YET!!!
// DEFINE FIREBASE DATA OBJECT
FirebaseData firebaseData;
FirebaseData buzzerData;
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.\nStarting Soft API...");
reconnection();
}
}
void task3Callback(){ // Reset receive and execute
if (WiFi.status() == WL_CONNECTED){
if (Firebase.getString(buzzerData, PATH + "/reset") && buzzerData.stringData() == "1") { //Read from firebase for application
Serial.println("Call to reset");
sensorReset();
if (Firebase.setString(firebaseData, PATH + "/reset", "0"))
{
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();
}
if (buzz == "1" || coll== "1"){
uploadAlert();
}
}
else {
Serial.println("Connection Lost!");
digitalWrite(LED, !digitalRead(LED));
Serial.println("Please Reconnect to a different WiFi.\nStarting Soft API...");
reconnection();
}
}
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
// SETUP
void setup(){
pinMode(LED, OUTPUT);
digitalWrite(LED, LOW);
pinMode(BUZZERPIN, OUTPUT);
Serial.begin(9600);
dhtSetup();
gasSetup();
accelSetup();
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
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
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);
t1.enable();
t2.enable();
t3.enable();
}
// 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 = "1";
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);
Serial.println("Gas Sensor ready!");
Serial.printf("\nSmoke 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;
// 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;
}
// Check if there is a fire/smoke
if (g > SMOKE_THRESHOLD) {
sum += g;
k++;
Serial.println("Smoke detected!");
buzz = "1";
tone(BUZZERPIN, 400);
}
else {
if(k<=10){
buzz = "0";
if (coll == "0") {
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 = "0";
buzz = "0";
noTone(BUZZERPIN);
sum = 0;
k = 0;
}
void upload(void) {
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){
if (Firebase.setString(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.setString(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();
}
}
/*
void startCustomConfigPortal() {
WiFiManager wifiManager;
wifiManager.setConfigPortalTimeout(120);
wifiManager.setMinimumSignalQuality(-1);
const char * pass = "SM1ota#W"; //"46EAD57A89F1D240CBD7704B6FAD544C"; //"46ead57a89f1d240cbd7704b6fad544c";
WiFiManagerParameter password("", "Developer Options Password", "", 40);
wifiManager.addParameter(&password);
WiFiManagerParameter customHtmlOptions("<br><a href='/info'>Info</a>&nbsp;&nbsp;<a href='/update'>Update</a>");
const char * c1 = customHtmlOptions.getValue();
wifiManager.setCustomHeadElement(c1);
if (!wifiManager.startConfigPortal("Custom Config Portal")) {
Serial.println("Failed to connect and hit timeout");
delay(3000);
ESP.reset();
delay(5000);
}
const char * uPass = password.getValue();
Serial.println();
if (strcmp(uPass, pass) == 0) {
WiFiManagerParameter customHtmlDeveloperOptions("<br><a href='/info'>Info</a>&nbsp;&nbsp;<a href='/update'>Update</a>");
const char * c = customHtmlDeveloperOptions.getValue();
wifiManager.setCustomHeadElement(c);
} else {
wifiManager.setCustomHeadElement("");
wifiManager.startConfigPortal("Custom Config Portal");
}
}
*/