Загрузка данных
// #include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include <GY21.h>
#include <FS.h>
#include <SD.h>
#include <ArduinoJson.h>
String modes[] = {"Idle", "Calibration", "Send report"};
char chrmode[] = {'m', 'i', 'c', 'r'};
struct UserData {
String data;
String value;
};
UserData userdata[50] {};
struct ConfigData {
String data;
int value;
};
ConfigData configdata[50] {};
char mode = 'm';
int Checktime2 = 0;
int Checktime = 0;
int cursor = 0;
int buzzervolume = 100; // %
int maxbuzzervolume = 2048; //hz
int MAXnormal_gas_level = 800;
int MAXhigh_gas_level = 1500;
int dangerous_gas_level = 2000;
int normaltemp[] = {20, 25};
int hightemp[] = {30, 40};
int dangeroustemp = 50;
bool OKBTN = false;
bool DOWNBTN = false;
bool UPBTN = false;
bool BACKBTN = false;
bool critical;
bool emergency;
const char* userDataPath = "/UserData.json";
const char* configDataPath = "/ConfigData.json";
float startgas;
float starttemp;
float totalDanger;
unsigned long lastSmsTime = 0;
bool smsSent = false;
#define GASPIN 39
#define BUZZERPIN 26
#define REDPIN 12
#define GREENPIN 27
#define BLUEPIN 16
#define SDCS 5
#define UPBUTTON 32
#define OKBUTTON 13
#define DOWNBUTTON 14
#define GSMTX 17
#define GSMRX 16
GY21 sensor;
#define SCREEN_WIDTH 128 // OLED display width, in pixels
#define SCREEN_HEIGHT 64 // OLED display height, in pixels
#define OLED_RESET -1
#define SCREEN_ADDRESS 0x3C
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT, &Wire, OLED_RESET);
void setRGB(bool red, bool green, bool blue) {
digitalWrite(REDPIN, red);
digitalWrite(GREENPIN, green);
digitalWrite(BLUEPIN, blue);
}
void setBuzzer(bool status) {
if (status) {
float freq = (maxbuzzervolume * buzzervolume) / 100;
tone(BUZZERPIN, freq);
} else {
noTone(BUZZERPIN);
}
}
bool getuserdata() {
File file = SD.open(userDataPath, FILE_READ);
if (!file) {
Serial.println("Failed to open userdata, all internet and sim features disabled!");
return false;
}
JsonDocument doc;
DeserializationError error = deserializeJson(doc, file);
if (!error) {
userdata[0].data = "name";
userdata[0].value = doc["name"].as<String>();
userdata[1].data = "email";
userdata[1].value = doc["email"].as<String>();
userdata[2].data = "address";
userdata[2].value = doc["address"].as<String>();
userdata[3].data = "app_password";
userdata[3].value = doc["app_password"].as<String>();
userdata[4].data = "wifi_name";
userdata[4].value = doc["wifi_name"].as<String>();
userdata[5].data = "wifipass";
userdata[5].value = doc["wifi_pass"].as<String>();
userdata[6].data = "emergencyphone";
userdata[6].value = doc["emergencyphone"].as<String>();
for (int i = 0; i <= 7; i++) {
Serial.print(userdata[i].data);
Serial.print(": ");
Serial.print(userdata[i].value);
}
file.close();
return true;
} else {
Serial.print("JSON Parsing failed: ");
Serial.println(error.f_str());
file.close();
return false;
}
}
bool getconfig() {
File file = SD.open(configDataPath, FILE_READ);
if (!file) {
Serial.println("Failed to open config!");
return false;
}
JsonDocument doc;
DeserializationError error = deserializeJson(doc, file);
if (!error) {
configdata[0].data = "buzzer";
configdata[0].value = doc["buzzerVolume"].as<int>();
configdata[1].data = "gas";
configdata[1].value = doc["normalgas"].as<int>();
configdata[2].data = "temp";
configdata[2].value = doc["normaltemp"].as<int>();
for (int i = 0; i <= 3; i++) {
Serial.print(configdata[i].data);
Serial.print(": ");
Serial.print(configdata[i].value);
}
file.close();
return true;
} else {
Serial.print("JSON Parsing failed: ");
Serial.println(error.f_str());
file.close();
return false;
}
}
void startsaving(char type, float data) {
if (type == 'T') {
configdata[2].value = data;
} else if (type == 'G') {
configdata[1].value = data;
}
JsonDocument doc;
for (int i = 0; i < 3; i++) {
if (configdata[i].data.length() > 0) {
doc[configdata[i].data] = configdata[i].value;
}
}
File file = SD.open(configDataPath, FILE_WRITE);
if (!file) {
Serial.print("failed to open config!");
return;
}
if (serializeJsonPretty(doc, file) == 0) {
Serial.println("failed to dump json!");
} else {
Serial.println("Json dumped succsesfully!");
}
mode = 'm';
file.close();
}
void mainmenu() {
}
void idlemode() {
if (millis() - Checktime >= 300) {
Checktime = millis();
display.clearDisplay();
display.setTextSize(1);
display.setCursor(70, 20);
display.print(analogRead(39));
display.print(" ppm");
display.setCursor(10, 20);
display.print(sensor.GY21_Temperature());
display.print((char)247);
display.print("C");
display.setCursor(20, 50);
display.print("Danger%: ");
display.print(totalDanger);
display.display();
}
}
void starttempcalibration() {
display.clearDisplay();
display.setCursor(0, 10);
display.print("TEMP: ");
display.print(starttemp);
display.setCursor(0, 30);
display.print("choose level with buttons");
if (UPBTN) {
UPBTN = false;
starttemp += 1;
} else if (DOWNBTN) {
DOWNBTN = false;
starttemp -= 1;
} else if (OKBTN) {
startsaving('T', starttemp);
}
display.display();
}
void startgascalibration() {
display.clearDisplay();
display.setCursor(0, 10);
display.print("GAS: ");
display.print(startgas);
display.setCursor(0, 30);
display.print("choose level with buttons");
if (UPBTN) {
UPBTN = false;
startgas += 1;
} else if (DOWNBTN) {
DOWNBTN = false;
startgas -= 1;
} else if (OKBTN) {
startsaving('G', startgas);
}
display.display();
}
void calibration() {
display.clearDisplay();
display.setCursor(0, 10);
display.print("Temp calibration");
display.setCursor(0, 30);
display.print("Gas calibration");
if (cursor == 0) {
display.setCursor(60, 10);
} else if (cursor == 1) {
display.setCursor(60, 30);
}
display.print("<");
if (OKBTN) {
if (cursor == 0) {
starttemp = sensor.GY21_Temperature();
starttempcalibration();
mode = 'T';
}
else if (cursor == 1) {
startgas = analogRead(39);
startgascalibration();
mode = 'G';
}
}
}
display.display();
}
void sendreport() {
}
void setup() {
Serial.begin(115200);
Serial2.begin(9600, SERIAL_8N1, GSMRX, GSMTX);
delay(1000);
Serial2.println("AT");
delay(200);
Serial2.println("AT+CMGF=1");
delay(200);
Serial2.println("AT+CSCS=\"GSM\"");
delay(200);
// SPI.begin();
Wire.begin(21, 22);
// Wire.setClock(1000000);
pinMode(BUZZERPIN, OUTPUT);
pinMode(REDPIN, OUTPUT);
pinMode(GREENPIN, OUTPUT);
pinMode(BLUEPIN, OUTPUT);
pinMode(SDCS, OUTPUT);
pinMode(UPBUTTON, INPUT);
pinMode(DOWNBUTTON, INPUT);
pinMode(OKBUTTON, INPUT);
if(!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) {
Serial.println(F("SSD1306 allocation failed"));
for(;;); // Don't proceed, loop forever
}
delay(100);
if (!SD.begin(SDCS)) {
Serial.println("Sd mount failed!");
return;
}
display.display();
display.setCursor(0,0);
display.setTextSize(1);
bool importeduser = getuserdata();
bool importedconf = getconfig();
if (importeduser) {
display.print("Userdata found and imported");
}
if (importedconf) {
display.print("Config found and imported");
MAXnormal_gas_level = configdata[1].value;
MAXhigh_gas_level = MAXnormal_gas_level + 700;
dangerous_gas_level = MAXnormal_gas_level + 1400;
normaltemp[0] = configdata[2].value;
normaltemp[1] = normaltemp[0] + 5;
hightemp[0] = normaltemp[0] + 10;
hightemp[1] = normaltemp[0] + 20;
dangeroustemp = 50;
if (configdata[0].value == 0) {
Serial.println("Buzzer volume is 0, please change it, or it can be problem, when emergency starts");
}
buzzervolume = configdata[0].value;
}
setBuzzer(true);
delay(400);
setBuzzer(false);
delay(2000);
setRGB(1, 0, 0);
delay(100);
setRGB(0, 1, 0);
delay(100);
setRGB(0, 0, 1);
display.clearDisplay();
display.setTextColor(SSD1306_WHITE);
display.setCursor(0,0);
display.setTextSize(1);
display.print("Hello world!:)");
display.display();
Checktime = millis();
Checktime2 = millis();
}
float calculateDanger(float value,
float normal,
float dangerous,
float high)
{
float percent;
if (value <= normal) {
percent = 0.0;
}
else if (value < dangerous) {
percent = 50.0 * (value - normal) / (dangerous - normal);
}
else if (value < high) {
percent = 50.0 + 50.0 * (value - dangerous) / (high - dangerous);
}
else {
percent = 100.0;
}
return constrain(percent, 0.0, 100.0);
}
void modechoose() {
switch (mode) {
case 'm':
mainmenu();
break;
case 'i':
idlemode();
break;
case 'c':
calibration();
break;
//case 's':
//settings();
//break;
case 'r':
sendreport();
break;
case 'T':
starttempcalibration();
break;
case 'G':
startgascalibration();
break;
default:
break;
}
}
String compileReport() {
String message = "FIRE ALARM!";
message += "Current temperature: " + String(sensor.GY21_Temperature()) + " C\n";
message += "Gas: " + String(analogRead(39)) + " ppm\n";
message += "Danger: " + String(totalDanger) + "%\n";
message += "Name: " + userdata[0].value + "\n";
message += "Email: " + userdata[1].value + "\n";
message += "Address: " + userdata[2].value + "\n";
return message;
}
void sendSMS(String message) {
if (userdata[6].value.length() <= 5) {
Serial.println("Phone is incorrect or not included, aborting sending");
return;
}
Serial2.print("AT+CMGS=\"");
Serial2.print(userdata[6].value);
Serial2.println("\"");
delay(500);
Serial2.print(message);
delay(100);
Serial2.write(26);
delay(3000);
Serial.println("GSM: SMS sent command executed.");
}
void loop() {
if (critical) {
if (millis() - Checktime2 >= 300) {
Checktime2 = millis();
flashwarning();
setBuzzer(true);
delay(10);
} else {
setBuzzer(false);
}
smsSent = false;
}
if (millis() - Checktime2 >= 2000) {
Checktime2 = millis();
}
if (emergency) {
flashwarning();
setBuzzer(true);
if (!smsSent) {
String message = compileReport();
sendSMS(message);
smsSent = true;
}
} else if (!critical) {
setBuzzer(false);
smsSent = false;
}
float TEMPpercentage = calculateDanger(sensor.GY21_Temperature(), normaltemp[0], dangeroustemp, hightemp[0]);
float GASpercentage = calculateDanger(analogRead(39), MAXnormal_gas_level, dangerous_gas_level, MAXhigh_gas_level);
totalDanger = 0.4 * TEMPpercentage + 0.6 * GASpercentage;
totalDanger = max(totalDanger, max(TEMPpercentage, GASpercentage));
if (totalDanger >= 70) {
critical = true;
emergency = false;
}
else {critical = false;}
if (totalDanger >= 90) {
emergency = true;
critical = false;
} else {emergency = false;}
modechoose();
if (millis() - Checktime >= 300 && mode == 'm') {
Checktime = millis();
display.clearDisplay();
display.setCursor(0, 8);
display.print("Gas level: ");
display.print(analogRead(39));
display.setCursor(0, 16);
display.print("Temperature: ");
display.print(sensor.GY21_Temperature());
display.setCursor(0, 32);
display.print("Danger%: ");
display.print(totalDanger);
display.setTextSize(1);
display.setCursor(15, 48);
display.print("--");
display.print(modes[cursor]);
display.print("--");
display.setTextSize(1);
display.display();
}
if (digitalRead(DOWNBUTTON) == LOW && digitalRead(UPBUTTON) == LOW) {
BACKBTN = true;
DOWNBTN = false;
UPBTN = false;
mode = 'm';
delay(150);
} else if (digitalRead(DOWNBUTTON) == LOW) {
DOWNBTN = true;
if (cursor <= 0) {
cursor = 0;
} else {
cursor -= 1;
}
delay(150);
} else if (digitalRead(UPBUTTON) == LOW) {
UPBTN = true;
int len = sizeof(modes) / sizeof(modes[0]);
if (cursor >= len - 1 && mode = 'm') {
cursor = len - 1;
}
else if (cursor >= 1 && mode == 'c') {
cursor = 1;
}
else {
cursor += 1;
}
delay(150);
} else {
BACKBTN = false;
DOWNBTN = false;
UPBTN = false;
}
if (digitalRead(OKBUTTON) == LOW) {
OKBTN = true;
if (mode == 'm') {
if (cursor == 0) mode = 'i';
if (cursor == 1) mode = 'c';
if (cursor == 2) mode = 'r';
cursor = 0;
}
delay(150);
} else {OKBTN = false;}
}