Bushfire protection system
An automated spraying system for when you are told to evacuate your home
Components and supplies
1
Automotive Relay, 12 VDC
1
ESP32
1
Solar Power Manager For 12V Lead-Acid Battery
1
Battery, 12 V
1
8 Channel Relay Board 12VDC XC-4418
1
MQ2 gas and smoke sensor
1
Sprinkler System
1
TMP36- Analog Temperature sensor
Tools and machines
1
Custom PCB Board
Apps and platforms
1
Arduino IDE 2.0 (beta)
1
Blynk
Project description
Code
Bushfire protection system main code
cpp
Arduino .ino file, main component
1// The support of the Arduino fraternity is acknowledged and also https://somik.org/esp-ota-code-upload/ for the guide on WiFi updating (OTA) of the board software and monitoring/debugging via Telnet. 2// Diagnostics are includede.They may be deleted but are a most useful guide if you intend making changes. 3// -- GDM, santo@southcom.com.au 200524 4 5#include <WiFiUdp.h> 6#include <WiFi.h> 7#include <WiFiClient.h> 8#include <WiFiServer.h> 9#include "OTA_telnet_2.h" 10 11// Blynk template and token details are comfidential and in creds.h 12#include <BlynkSimpleEsp32.h> 13 14const char* ssid = MYssid; 15const char* password = MYpassword; 16const byte ledPin = 15; // ESP32 Pin to which my LED is connected 17int LEDValue; 18const byte tempPin = 4; //the analog pin the TMP36's Vout (sense) pin is connected to 19float TMP36_mV = 0; // temp sensor voltage 20float temp; // for temp in C 21const byte MQ2Pin = 16; //GAS sensor output pin to Arduino analog A0 pin 22int gasPinValue = 0; 23const byte buttonPin = 13; // the number of the pushbutton pin 24byte started = 0; // denotes the pumping system as started up 25int pumpSecCounter; // starts a second count, initiated by Telnet 26float numPumpCycles = 0.0; 27float lineNowPumping = 0.0; 28float aboutPumping = 0.0; 29unsigned long timeB4 = millis(); // used in Telnet to get a starting value, then it runs itself... 30int V3Pin = 0; // virtual pin in Blynk 31const char* fileName = "OTATelnet_Blynk_PCB_UA_4-31"; 32// unsigned long getSecs; // for getting time since start // no longer used 33// unsigned long getMin; // for getting time since start 34 35///>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 36//// this section for the triggers >>>>>>>>>>>>>>>>>>>>>>>>>. 37const float ramp = 4.0; // a sudden rise in temp will start the pump. Degrees C. 38float minTemp = 45.0; // for getting the minumum of an array of temp values. Set it high to start. ramp will compare with this. 39const float maxTemp = 50.0; // startup temp 40const int gasTrigr = 4000; // this value will set off the system 41const int gasTrigrLowr = 2500; // this value will set off the system in combination with elevted temp. 42const byte numLines = 7; // the number of pumping lines connected to the relays 43const byte lineTime = 30; // how long each water line will pump for in seconds 44 45///>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 46int countSecs = 0; //for the count to 10 secs 47int decadeComplete = 0; // measures the ten sec interval for average 48const byte countTempSecs[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 }; //for getting ave temp over a 10 second period 49float tempDecade[10] = { 49.0, 49.0, 49.0, 49.0, 49.0, 49.0, 49.0, 49.0, 49.0, 49.0 }; 50float tenSecAve = 0; 51float secTemp[10] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; 52float lineIndicator[7] = { 0.1, 0.2, 0.3, 0.4, 0.5, 0.6, 0.7 }; // designates the water line 53 54// getting average temp 55const int c = 35; // y=mx+c equation for temp sensor calibration; 610 before 5v adj 56const float m = 14.6; // y=mx+c equation for temp sensor calibration; 8.5 before 57float aveTemp = 0; // in Mv 58const byte numTempReads = 10; // delay period x number of reads must be well less than 1000 ; for checksensors C 59int thisTempRead = 0; // in Mvs, note integer, to stabilise the averaging maths... 60long tempReadBucket = 0; //collects the reads 61 62//// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 63//// reset if Blynk drops out and won't restart after 20m.. 64int downDecades = 0; // a variable to count the minutes offline 65byte blynkStatus = 0; // 0 is down, 1 is up. 66void Blynk_now() { 67 bool isconnected = Blynk.connected(); 68 if (isconnected == false) { 69 blynkStatus = 0; 70 } else if (isconnected == true) { 71 blynkStatus = 1; 72 } 73} 74// Activates as part of decadecomplete, i.e. each 10 seconds 75 76void downTime() { 77 if (blynkStatus == 1) { 78 downDecades = 0; 79 } else if (blynkStatus != 1) { 80 downDecades = downDecades + 1; 81 } 82} 83 84void restart() { 85 if ((downDecades > 120) && (started == 0)) ESP.restart(); 86} 87// In main loop 88 89// getting ready to send temp, gas and LED data 90BLYNK_WRITE(V0) { 91 Blynk.virtualWrite(V0, param.asFloat()); 92} 93 94BLYNK_WRITE(V1) { 95 Blynk.virtualWrite(V1, param.asFloat()); 96} 97 98BLYNK_WRITE(V2) { 99 Blynk.virtualWrite(V2, param.asInt()); 100} 101 102BLYNK_WRITE(V3) { //getting button press from the Blynk app. BLYNK_WRITE both sends and recieves values 103 int V3Pin = param.asInt(); 104 if (V3Pin == 1) { started = 1; } 105} 106 107BLYNK_WRITE(V4) { 108 Blynk.virtualWrite(V4, param.asInt()); 109} 110 111 112/// Pins 113// define the pins that will connect to the relays to drive the hose solenoids for sprinklers and sprayers 114const byte pumpingPins[8]{ 42, 39, 38, 37, 36, 35, 48, 47 }; 115 116byte startFlag = 0; // a flag for managing the pump timer 117const unsigned long tn_count = 1000UL; // for counting the loop iteration to 1000 then send telnet stuff 118unsigned long timeNow; // used in Telnet... 119 120void setup() { 121 ArduinoOTA.setHostname("UnitA"); 122 setupOTA(); 123 Blynk.config(BLYNK_AUTH_TOKEN); 124 Blynk.connect(); 125 pinMode(ledPin, OUTPUT); 126 digitalWrite(ledPin, LOW); 127 pinMode(buttonPin, INPUT); 128 129 // set pumpingPins as OUTPUT 130 for (int j = 0; j < 8; j++) { 131 pinMode(pumpingPins[j], OUTPUT); 132 } 133 // // de-activate these 134 for (int k = 0; k < 8; k++) { 135 digitalWrite(pumpingPins[k], LOW); 136 } 137} // end Void Setup 138 139 140// FUNCTIONS for TRIGGERS.................FUNCTIONS................. FUNCTIONS .................FUNCTIONS................. FUNCTIONS .................FUNCTIONS................. FUNCTIONS .................FUNCTIONS................. 141 142void decades() { 143 for (int i = 0; (i < 10); i++) { 144 if (countTempSecs[i] == (i + 1)) secTemp[i] = temp; 145 } 146 if (countSecs == 10) { 147 tenSecAve = 0; 148 for (int i = 0; (i < 10); i++) { 149 tenSecAve = tenSecAve + (secTemp[i] / 10); 150 } 151 decadeComplete = 1; 152 downTime(); 153 } 154} 155 156void allMoveUp() { 157 if (decadeComplete > 0) { 158 for (int i = 9; i > 0; i--) { 159 tempDecade[i] = tempDecade[i - 1]; 160 } 161 tempDecade[0] = tenSecAve; 162 countSecs = 0; // restarting the loop 163 decadeComplete = 0; 164 } 165} 166 167//temperature ramping trigger 168void tempRampTrigr() { 169 minTemp = tempDecade[0]; 170 for (int i = 1; i < 10; i++) { 171 if (tempDecade[i] < minTemp) { 172 minTemp = tempDecade[i]; 173 } 174 } 175 if ((tempDecade[0] - minTemp > ramp) && (tempDecade[9] <= 48)) { // wait until readings settle after startup... 176 started = 1; 177 digitalWrite(ledPin, HIGH); 178 TelnetStream.print(" ! Temp Ramp Trigger!"); 179 } 180} 181 182void tempMaxTrigr() { 183 if ((started == 0) && (tenSecAve > maxTemp)) { 184 started = 1; 185 digitalWrite(ledPin, HIGH); 186 } 187} 188 189void tempANDsmokeTrigr() { 190 if ((tenSecAve > minTemp) && (gasPinValue > gasTrigrLowr) && (started == 0)) { 191 started = 1; 192 digitalWrite(ledPin, HIGH); 193 } 194} 195 196void too_smokey() { 197 if ((started == 0) && (gasPinValue > gasTrigr)) { 198 started = 1; 199 digitalWrite(ledPin, HIGH); 200 TelnetStream.print(" ! Smoke detected!"); 201 } 202} 203 204void buttonStart() { 205 if (digitalRead(buttonPin) == HIGH && digitalRead(ledPin) == LOW) { 206 started = 1; 207 digitalWrite(ledPin, HIGH); 208 } 209} 210 211void checkSensorsAve() { 212 for (int j = 1; j <= numTempReads && analogRead(tempPin) > 0; j++) { // easy maths 213 thisTempRead = (analogRead(tempPin)); 214 tempReadBucket = tempReadBucket + thisTempRead; 215 } 216 // aveTemp = tempReadBucket; 217 aveTemp = (tempReadBucket / 10); 218 tempReadBucket = 0; // empty the bucket ready for next time 219 temp = (((aveTemp - 500) - c) / m); 220 temp = round(temp * 10) / 10; // for one decimal place. 221 gasPinValue = (analogRead(MQ2Pin)); 222} 223 224void pumping() { 225 if ((started == 1) && (startFlag == 0)) { 226 startFlag = 1; 227 } 228 // set up the array for pumping control : 229 int pumpControl[7] = { lineTime * 0, lineTime * 1, lineTime * 2, lineTime * 3, lineTime * 4, lineTime * 5, lineTime * 6 }; 230 231 for (int i = 0; i < numLines; i++) { 232 if (pumpSecCounter == pumpControl[i] + 1) { 233 digitalWrite(pumpingPins[i], HIGH); // open the line 234 lineNowPumping = lineIndicator[i]; // show which line is pumping 235 } else if (pumpSecCounter == pumpControl[i] + 3) { 236 digitalWrite(pumpingPins[7], HIGH); // start the pump 237 } else if (pumpSecCounter == (pumpControl[i] + lineTime) - 3) { 238 digitalWrite(pumpingPins[7], LOW); // stop the pump 239 } else if (pumpSecCounter == (pumpControl[i] + lineTime) - 1) { 240 digitalWrite(pumpingPins[i], LOW); // close the line 241 } 242 } 243 if (pumpSecCounter == (lineTime * numLines) + 1) { // for one cycle through 244 digitalWrite(ledPin, LOW); 245 numPumpCycles = numPumpCycles + 1.0; 246 lineNowPumping = 0.0; 247 started = 0; 248 startFlag = 0; 249 pumpSecCounter = 0; // reset counter 250 } 251} 252 253void telnetSend() { 254 timeNow = millis(); 255 if ((timeNow - timeB4) > tn_count) { 256 countSecs = countSecs + 1; // increments the temperature ramp each sec 257 timeB4 = millis(); 258 TelnetStream.print(F(" File is: ")); 259 TelnetStream.print(fileName); 260 TelnetStream.println(); 261 TelnetStream.print(F(" Cycle and Line is: ")); 262 TelnetStream.print(aboutPumping); 263 TelnetStream.println(); 264 TelnetStream.print(F(" Smoke PPI = ")); 265 TelnetStream.print(gasPinValue); 266 TelnetStream.print(" "); 267 TelnetStream.print(F(" TEMPERATURE = ")); 268 TelnetStream.print(temp); // display temperature value 269 TelnetStream.print("*C"); 270 TelnetStream.println(); 271 TelnetStream.print(F(" Temp voltage = ")); 272 TelnetStream.print(thisTempRead); // display temperature value 273 TelnetStream.print(F(" Mv")); 274 TelnetStream.println(); 275 276 // DIAGNOSTICS <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< 277 TelnetStream.print(F("Counter = ")); 278 TelnetStream.print(countSecs); // display temperature value 279 TelnetStream.println(); 280 TelnetStream.print(F("Latest Ten Sec Ave = ")); 281 TelnetStream.print(tenSecAve); // display this temperature value 282 TelnetStream.println(); 283 for (int i = 0; i < 10; i++) { 284 TelnetStream.print(" "); 285 TelnetStream.print(tempDecade[i]); // display this temperature value 286 TelnetStream.println(); 287 } 288 TelnetStream.print(F(" minTemp = ")); 289 TelnetStream.print(minTemp); 290 TelnetStream.print(F(" Down decades = ")); 291 TelnetStream.print(downDecades); // display this value 292 TelnetStream.println(); 293 // Check startbutton status 294 if (digitalRead(buttonPin) == HIGH) { 295 TelnetStream.print(F("Start button is HIGH ")); 296 TelnetStream.println(); 297 } 298 299 // END DIAGNOSTICS <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< 300 301 if (started == 1) { 302 TelnetStream.print(F("Started ")); 303 TelnetStream.print(started); 304 pumpSecCounter = pumpSecCounter + 1; // for the pump control 305 TelnetStream.print(" pumping seconds elapsed "); 306 TelnetStream.print(pumpSecCounter); 307 TelnetStream.println(); 308 } else { 309 TelnetStream.print(F(" Waiting to start... ")); 310 TelnetStream.print(started); 311 } 312 TelnetStream.print(" --!-- "); 313 TelnetStream.println(); 314 TelnetStream.println(); 315 TelnetStream.println(); 316 // and do Blynk on these occasions... 317 Blynk.run(); 318 BlynkDataSend(); 319 } 320} 321void BlynkDataSend() { 322 // Blynk.virtualWrite(V0,tempC); // sending sensor value to Blynk app 323 Blynk.virtualWrite(V0, temp); 324 // sensorValue_gas = analogRead(A1); // reading sensor from analog pin 325 Blynk.virtualWrite(V1, gasPinValue); // sending sensor value to Blynk app 326 327 // LEDValue = digitalRead(UA_Status); // Tell Blynk we are pumping... 328 LEDValue = started; // Tell Blynk we are pumping... 329 if (started != 0) { 330 Blynk.virtualWrite(V3, 0); //reset the button 331 digitalWrite(ledPin, HIGH); // turn the LEd on 332 } 333 Blynk.virtualWrite(V2, LEDValue); // sending Unit A working status 334 aboutPumping = numPumpCycles + lineNowPumping; 335 336 Blynk.virtualWrite(V4, aboutPumping); // number of completed pump cycles & no of current water line 337 // Blynk.virtualWrite(V5, LineNowPumping); // the number of the water line 338} 339 340void loop() { 341 decades(); 342 allMoveUp(); 343 pumping(); 344 Blynk_now(); 345 buttonStart(); 346 telnetSend(); 347 checkSensorsAve(); 348 tempRampTrigr(); 349 tempMaxTrigr(); 350 too_smokey(); 351 restart(); 352 ArduinoOTA.handle(); 353}
Bushfire prevention system, comms
cpp
Arduino .h file. OTA, Blynk, Telnet
1#include <WiFi.h> 2#include <ESPmDNS.h> 3#include <WiFiUdp.h> 4#include <ArduinoOTA.h> 5#include <TelnetStream.h> 6// #include </media/drasgard/DATA/Gavin/Arduino/sketchbook/credentials/creds.h> 7//#include <credentials.h> 8#include <creds.h> 9 10void setupOTA() { 11 WiFi.mode(WIFI_STA); 12 WiFi.begin(MYssid, MYpassword); 13 // while (WiFi.waitForConnectResult() != WL_CONNECTED) { 14 // Serial.println("Connection Failed! Rebooting..."); 15 // delay(5000); 16 // ESP.restart(); 17 18// Try to reconnect once every 5 seconds 19static unsigned long reconnectTime; 20if(WiFi.status() != WL_CONNECTED && millis() - reconnectTime > 5000) { 21 reconnectTime = millis(); 22 WiFi.begin(MYssid, MYpassword); 23 } 24 25 // Port defaults to 3232 26 // ArduinoOTA.setPort(3232); 27 28 // No authentication by default 29 // ArduinoOTA.setPassword("admin"); 30 31 // Password can be set with it's md5 value as well 32 // MD5(admin) = 21232f297a57a5a743894a0e4a801fc3 33 // ArduinoOTA.setPasswordHash("21232f297a57a5a743894a0e4a801fc3"); 34 35 ArduinoOTA 36 .onStart([]() { 37 String type; 38 if (ArduinoOTA.getCommand() == U_FLASH) 39 type = "sketch"; 40 else // U_SPIFFS 41 type = "filesystem"; 42 43 // NOTE: if updating SPIFFS this would be the place to unmount SPIFFS using SPIFFS.end() 44 Serial.println("Start updating " + type); 45 }) 46 .onEnd([]() { 47 Serial.println("\nEnd"); 48 }) 49 .onProgress([](unsigned int progress, unsigned int total) { 50 Serial.printf("Progress: %u%%\r", (progress / (total / 100))); 51 }) 52 .onError([](ota_error_t error) { 53 Serial.printf("Error[%u]: ", error); 54 if (error == OTA_AUTH_ERROR) Serial.println("Auth Failed"); 55 else if (error == OTA_BEGIN_ERROR) Serial.println("Begin Failed"); 56 else if (error == OTA_CONNECT_ERROR) Serial.println("Connect Failed"); 57 else if (error == OTA_RECEIVE_ERROR) Serial.println("Receive Failed"); 58 else if (error == OTA_END_ERROR) Serial.println("End Failed"); 59 }); 60 61 ArduinoOTA.begin(); 62 TelnetStream.begin(); 63 64 Serial.println("OTA Initialized"); 65 Serial.print("IP address: "); 66 Serial.println(WiFi.localIP()); 67}
Downloadable files
Gerber_files.zip
PCB designed in KiCad.
Gerber_files.zip
Comments
Only logged in users can leave comments