Components and supplies
Automotive Relay, 12 VDC
ESP32
Solar Power Manager For 12V Lead-Acid Battery
Battery, 12 V
8 Channel Relay Board 12VDC XC-4418
MQ2 gas and smoke sensor
Sprinkler System
TMP36- Analog Temperature sensor
Tools and machines
Custom PCB Board
Apps and platforms
Arduino IDE 2.0 (beta)
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