Components and supplies
Relais Modul
Arduino Mega 2560
Alphanumeric LCD, 20 x 4
Temperature Sensor
Arduino Ethernet Shield 2
PZEM004T
DS3231M - ±5ppm, I2C Real-Time Clock
Project description
Code
ats.htm
html
1<html><head> 2 <title>ATS</title> 3 <link rel="shortcut icon" type="image/x-icon" href="http://joergmahn.de/ats.ico"> 4 <meta name="referrer" content="no-referrer" /> 5 <meta http-equiv="refresh" content="10; URL=http://ats.joergmahn.de"> 6</head><body><center> 7 <div class="hl">Automatic-Transfer-Switch</div> 8 <div class="h2">Version %ver% (c) 2019 by Jörg Mahn</div><br> 9 <table id="a"> 10 <tr><td id="a"><font class="e">Status:</font></td><td id="a"><font class="v">%sta%</font></td></tr> 11 <tr><td id="a"><font class="e">Generator:</font></td><td id="a"><font class="v">%gen%</font></td></tr> 12 <tr><td id="a"><font class="e">Zeit:</font></td><td id="a"><font class="v">%d% %z%</font></td></tr> 13 <tr><td id="a"><font class="e">RAM:</font></td><td id="a"><font class="v">%ram% Bytes frei</font></td></tr> 14 <tr><td id="a"><font class="e">ATS:</font></td><td id="a"><font class="v">%sys% °C</font></td></tr> 15 <tr><td id="a"><font class="e">Halle:</font></td><td id="a"><font class="v">%aut% °C</font></td></tr> 16 <tr><td id="a"><font class="e">Motor:</font></td><td id="a"><font class="v">%mot% °C</font></td></tr> 17 <tr><td id="a"><font class="e">Batterie:</font></td><td id="a"><font class="v">%bat% V</font></td></tr> 18 <tr><td id="a"><font class="e">Leistung:</font></td><td id="a"><font class="v">%p%</font></td></tr> 19 </table><br> 20 <table id="b"> 21 <tr><td id="b"><font class="e">L1</font></td><td id="b"><font class="e">L2</font></td><td id="b"><font class="e">L3</font></td></tr> 22 <tr><td id="b"><font class="v">%1v% V</font></td><td id="b"><font class="v">%2v% V</font></td><td id="b"><font class="v">%3v% V</font></td></tr> 23 <tr><td id="b"><font class="v">%1c% A</font></td><td id="b"><font class="v">%2c% A</font></td><td id="b"><font class="v">%3c% A</font></td></tr> 24 </table><br> 25 <form method="get" name="ats"> 26 <table id="c"> 27 <tr><td id="c"><input type="submit" class="gr" name="refresh" value="Aktualisieren"></td> 28 <td id="c"><input type="submit" class="gr" name="sendmail" value="EMail senden"></td></tr> 29 <tr><td id="c"><input type="submit" class="gr" name="config" value="Konfiguration"></td> 30 <td id="c"><input type="submit" class="ge" name="reset" value="System Reset"></td></tr> 31 <tr><td id="c"><input type="submit" class="gr" name="genstop" value="Generator stoppen"></td> 32 <td id="c"><input type="submit" class="bl" name="genstart" value="Generator starten"></td></tr> 33 <tr><td id="c"><input type="submit" class="gn" name="mainbet" value="Netzbetrieb"></td> 34 <td id="c"><input type="submit" class="rt" name="genbet" value="Generatorbetrieb"></td></tr> 35 </table> 36 </form> 37</center></body></html> 38
C_checkstate.ino
arduino
Check States
1void CheckState() { 2 unsigned long currentMillis = millis(); 3 noInterrupts(); 4 5 // Freien Speicher berechnen 6 ram = FreeRam(); 7 8 // Temepraturwerte holen 9 GetTemp(&t_data); 10 11 // Stromwerte holen 12 GetCurrent(&p_data); 13 Leistung = p_data.L1_Leistung + p_data.L2_Leistung + p_data.L3_Leistung; 14 15 16 // Zum VZ puschen 17 unsigned long interval = 1000; // 1sec "delay" 18 if (millis() - VZTime > interval ) { 19 PushVZ(VZServer, VZRequest, UUID, Leistung); 20 VZTime = millis(); 21 } 22 23 if (Leistung > 999) { 24 Leistung = Leistung / 1000; 25 StrLeistung = form(String(Leistung, 2) + " KW", 6); 26 } else { 27 StrLeistung = form(String(Leistung, 0) + " W", 6); 28 } 29 30 // zum MQTT Broker pushen 31 if (MQTTenable) { 32 // mqtt_table[0-3] = subsriber Topics 33 34 strcpy_P(buffer, (char *)pgm_read_word(&(mqtt_table[4]))); 35 MQTT.publish(String(MQTTTopic) + (String) buffer, StrLeistung); 36 strcpy_P(buffer, (char *)pgm_read_word(&(mqtt_table[5]))); 37 MQTT.publish(String(MQTTTopic) + (String) buffer, String(Status)); 38 strcpy_P(buffer, (char *)pgm_read_word(&(mqtt_table[6]))); 39 MQTT.publish(String(MQTTTopic) + (String) buffer, String(ram)); 40 41 strcpy_P(buffer, (char *)pgm_read_word(&(mqtt_table[7]))); 42 MQTT.publish(String(MQTTTopic) + (String) buffer, String(p_data.L1_Leistung)); 43 strcpy_P(buffer, (char *)pgm_read_word(&(mqtt_table[8]))); 44 MQTT.publish(String(MQTTTopic) + (String) buffer, String(p_data.L1_Strom)); 45 strcpy_P(buffer, (char *)pgm_read_word(&(mqtt_table[9]))); 46 MQTT.publish(String(MQTTTopic) + (String) buffer, String(p_data.L1_Spannung)); 47 48 strcpy_P(buffer, (char *)pgm_read_word(&(mqtt_table[10]))); 49 MQTT.publish(String(MQTTTopic) + (String) buffer, String(p_data.L2_Leistung)); 50 strcpy_P(buffer, (char *)pgm_read_word(&(mqtt_table[11]))); 51 MQTT.publish(String(MQTTTopic) + (String) buffer, String(p_data.L2_Strom)); 52 strcpy_P(buffer, (char *)pgm_read_word(&(mqtt_table[12]))); 53 MQTT.publish(String(MQTTTopic) + (String) buffer, String(p_data.L2_Spannung)); 54 55 strcpy_P(buffer, (char *)pgm_read_word(&(mqtt_table[13]))); 56 MQTT.publish(String(MQTTTopic) + (String) buffer, String(p_data.L3_Leistung)); 57 strcpy_P(buffer, (char *)pgm_read_word(&(mqtt_table[14]))); 58 MQTT.publish(String(MQTTTopic) + (String) buffer, String(p_data.L3_Strom)); 59 strcpy_P(buffer, (char *)pgm_read_word(&(mqtt_table[15]))); 60 MQTT.publish(String(MQTTTopic) + (String) buffer, String(p_data.L3_Spannung)); 61 62 strcpy_P(buffer, (char *)pgm_read_word(&(mqtt_table[16]))); 63 MQTT.publish(String(MQTTTopic) + (String) buffer, String(t_data.SysTemperatur)); 64 strcpy_P(buffer, (char *)pgm_read_word(&(mqtt_table[17]))); 65 MQTT.publish(String(MQTTTopic) + (String) buffer, String(t_data.MotorTemperatur)); 66 strcpy_P(buffer, (char *)pgm_read_word(&(mqtt_table[18]))); 67 MQTT.publish(String(MQTTTopic) + (String) buffer, String(t_data.AussenTemperatur)); 68 69 70 // Netzbetrieb 71 if (Status==0) { 72 strcpy_P(buffer, (char *)pgm_read_word(&(mqtt_table[19]))); // /get/betrieb 73 MQTT.publish(String(MQTTTopic) + (String) buffer, "netz"); 74 } 75 76 // Generatorbetrieb 77 if (Status==1) { 78 strcpy_P(buffer, (char *)pgm_read_word(&(mqtt_table[19]))); // /get/betrieb 79 MQTT.publish(String(MQTTTopic) + (String) buffer, "generator"); 80 } 81 82 // Generator luft 83 if (Status==1) { // Generatorbetrieb 84 strcpy_P(buffer, (char *)pgm_read_word(&(mqtt_table[20]))); // /get/generator 85 MQTT.publish(String(MQTTTopic) + (String) buffer, F("start")); 86 } 87 if (Status==18) { // Generator luft 88 strcpy_P(buffer, (char *)pgm_read_word(&(mqtt_table[20]))); // /get/generator 89 MQTT.publish(String(MQTTTopic) + (String) buffer, F("start")); 90 } 91 92 // Generator luft nicht 93 if (Status==0) { // Netzbetrieb 94 strcpy_P(buffer, (char *)pgm_read_word(&(mqtt_table[20]))); // /get/generator 95 MQTT.publish(String(MQTTTopic) + (String) buffer, F("stop")); 96 } 97 if (Status==3) { // Strung Generator 98 strcpy_P(buffer, (char *)pgm_read_word(&(mqtt_table[20]))); // /get/generator 99 MQTT.publish(String(MQTTTopic) + (String) buffer, F("stop")); 100 } 101 if (Status==4) { // Strung Manuell 102 strcpy_P(buffer, (char *)pgm_read_word(&(mqtt_table[20]))); // /get/generator 103 MQTT.publish(String(MQTTTopic) + (String) buffer, F("stop")); 104 } 105 106 for (int i=0; i<=MaxStatus; i++) { 107 if (i==Status) { 108 strcpy_P(buffer, (char *)pgm_read_word(&(status_table[i]))); // Lesbaren Status pushen 109 MQTT.publish(String(MQTTTopic) + F("/get/status"), (String) buffer); 110 } 111 } 112 113 if (zuendung) { 114 if (Status == 1 || Status == 18) { 115 MQTT.publish(String(MQTTTopic) + F("/get/generator"), F("Ein")); 116 } else { 117 MQTT.publish(String(MQTTTopic) + F("/get/generator"), F("Standby")); 118 } 119 } else { 120 MQTT.publish(String(MQTTTopic) + F("/get/generator"), F("Aus")); 121 } 122 123 strcpy_P(buffer, (char *)pgm_read_word(&(mqtt_table[22]))); // /get/version 124 MQTT.publish(String(MQTTTopic) + (String) buffer, version); 125 126 strcpy_P(buffer, (char *)pgm_read_word(&(mqtt_table[23]))); // /get/batterie 127 MQTT.publish(String(MQTTTopic) + (String) buffer, ConvSeperator(GeneratorBatterie)); 128 129 } 130 131 // Sende keine E-Mail whrend der Initalisierung 132 // Zndung an? 133 134 int value = 0; 135 value = analogRead(ZUENDSCHLOSS); 136 if (value > 0) { 137 if (!zuendung) { 138 zuendung = true; 139 sendEmail(17); 140 } 141 } else { 142 if (zuendung) { 143 zuendung = false; 144 sendEmail(18); 145 } 146 } 147 148 //Batteriespannung holen 149 genbat = GetBatteryVoltage(); 150 GeneratorBatterie = String(genbat, 1); 151 if (genbat < minbatvoltage) { 152 if (!batlow) { 153 sendEmail(15); 154 } 155 batlow = true; 156 } else { 157 batlow = false; 158 } 159 160 // Alles LOW-Active! 161 // HIGH = Strom ausgefallen 162 163 // Netzwiederkehr bevor Timeout Netzausfall 164 if (!digitalRead(PIN_PHASE_NETZ) && Status == 8) { 165 piep(); 166 page = 1; 167 Status = 0; // "Netzbetrieb" 168 timeout = 0; 169 LCD_Status(Status); 170 previousMillis = 0; 171 sendEmail(9); 172 PgmPrintln("Netzwiederkehr bevor Timeout Netzausfall"); 173 } 174 175 // Netzausfall bevor Timeout Netzwiederkehr 176 if (digitalRead(PIN_PHASE_NETZ) && Status == 9) { 177 piep(); 178 page = 1; 179 Status = 1; // "Generatorbetrieb" 180 timeout = 0; 181 LCD_Status(Status); 182 previousMillis = 0; 183 sendEmail(8); 184 PgmPrintln("Netzausfall bevor Timeout Netzwiederkehr"); 185 } 186 187 // Netzausfall im Status "Netzbetrieb" oder "Netztrennung in..." 188 if (digitalRead(PIN_PHASE_NETZ) && (Status == 0 || Status == 8)) { 189 if (previousMillis == 0) previousMillis = currentMillis; 190 if (Status == 0) { 191 page = 1; 192 Status = 8; // "Netztrennung" 193 sendEmail(Status); 194 Alert(HCServer, HCRequest, HCLoss); 195 PgmPrintln("Netzausfall im Status Netzbetrieb, Countdown gestartet."); 196 piep(); 197 } 198 timeout = lostmain * 60 - ((currentMillis - previousMillis) / 1000); 199 LCD_Status(Status); 200 201 if (timeout <= 0) { 202 previousMillis = 0; 203 piep(); 204 PgmPrintln("Netzausfall!"); 205 Alert(HCServer, HCRequest, HCStart); 206 if (Generator(ON)) { // Wenn Generator gestartet... 207 if (!digitalRead(PIN_PHASE_GEN)) { // ...und alle drei Phasen vorhanden... 208 Status = 1; // "Generatorbetrieb" 209 LCD_Status(Status); 210 SwitchGeneratorbetrieb(); // ...dann Umschalten auf Generatorbetrieb. 211 sendEmail(10); 212 PgmPrintln("Generator gestartet, Umschalten auf Generatorbetrieb."); 213 } else { // Generator liefert keine Spannungen 214 Status = 3; // "Strung Generator" 215 Alert(HCServer, HCRequest, HCError); 216 LCD_Status(Status); 217 Generator(OFF); // Generator ausschalten 218 sendEmail(12); 219 PgmPrintln("Generator gestartet, aber Phasen liefern keine Spannung!"); 220 } 221 } else { // Generator konnte nicht gestartet werden 222 Status = 3; // "Strung Generator" 223 Alert(HCServer, HCRequest, HCError); 224 LCD_Status(Status); 225 Generator(OFF); 226 sendEmail(12); 227 PgmPrintln("Generator konnte nicht gestartet werden!"); 228 } 229 } 230 } 231 232 // Netzwiederkehr im Status "Generatorbetrieb" und "Netzwiederkehr in..." 233 if (!digitalRead(PIN_PHASE_NETZ) && (Status == 1 || Status == 9)) { 234 if (previousMillis == 0) previousMillis = currentMillis; 235 if (Status == 1) { 236 page = 1; 237 Status = 9; // "Netzwiederkehr" 238 Alert(HCServer, HCRequest, HCBack); 239 PgmPrintln("Netzwiederkehr im Status Generatorbetrieb, Countdown gestartet."); 240 sendEmail(Status); 241 piep(); 242 } 243 timeout = (backmain * 60) - ((currentMillis - previousMillis) / 1000); 244 LCD_Status(Status); 245 246 if (timeout <= 0) { 247 previousMillis = 0; 248 PgmPrintln("Netzwiederkehr im Status Generatorbetrieb"); 249 Status = 0; // "Netzbetrieb" 250 Alert(HCServer, HCRequest, HCStop); 251 piep(); 252 Generator(OFF); 253 LCD_Status(Status); 254 SwitchNetzbetrieb(); // Umschalten auf Netzbetrieb 255 sendEmail(11); 256 } 257 } 258 259 // Netzwiederkehr im Status "Strung Generator" 260 if (!digitalRead(PIN_PHASE_NETZ) && Status == 3) { 261 PgmPrintln("Netzwiederkehr im Status Strung"); 262 page = 1; 263 Status = 0; // "Netzbetrieb"; 264 Alert(HCServer, HCRequest, HCBack); 265 piep(); 266 Generator(OFF); 267 LCD_Status(Status); 268 SwitchNetzbetrieb(); 269 sendEmail(9); 270 } 271 272 // Generatorwiederkehr im Status "Strung Generator" 273 if (!digitalRead(PIN_PHASE_GEN) && Status == 3) { 274 PgmPrintln("Generatorwiederkehr im Status Strung Generator"); 275 page = 1; 276 Status = 1; // "Generatorbetrieb" 277 piep(); 278 //Generator(ON); 279 LCD_Status(Status); 280 SwitchGeneratorbetrieb(); // Umschalten auf Generatorbetrieb 281 sendEmail(10); 282 } 283 284 // Generatorausfall im Status "Generatorbetrieb" 285 if (digitalRead(PIN_PHASE_GEN) && Status == 1) { 286 PgmPrintln("Generatorausfall im Status Generatorbetrieb"); 287 Generator(OFF); 288 SwitchNetzbetrieb(); // Umschalten auf Netzbetrieb und hoffen, dass der Strom bald wieder kommt! 289 page = 1; 290 Status = 3; // "Strung Generator" 291 Alert(HCServer, HCRequest, HCError); 292 piep(); 293 LCD_Status(Status); 294 sendEmail(12); 295 } 296 297 // Generatorausfall im Status "Manueller Betrieb" 298 if (digitalRead(PIN_PHASE_GEN) && Status == 2) { 299 PgmPrintln("Generatorausfall im Status Manuellerbetrieb"); 300 Generator(OFF); 301 page = 1; 302 Status = 4; // "Strung Manuell" 303 Alert(HCServer, HCRequest, HCError); 304 piep(); 305 LCD_Status(Status); 306 sendEmail(12); 307 } 308 309 // Generatorwiederkehr im Status "Strung Manuell" 310 if (!digitalRead(PIN_PHASE_GEN) && Status == 4) { 311 PgmPrintln("Generatorwiederkehr im Status Strung Manuell"); 312 page = 1; 313 Status = 2; // "Manueller Betrieb" 314 piep(); 315 Generator(ON); 316 LCD_Status(Status); 317 // SwitchGeneratorbetrieb(); // Umschalten auf Generatorbetrieb 318 sendEmail(10); 319 } 320 321 interrupts(); 322} 323
config.htm
html
Config Web Document
1<html><head> 2<title>ATS-Konfiguration</title> 3<link rel="shortcut icon" type="image/x-icon" href="http://webserver.com/favicon.ico"> 4<meta name="referrer" content="no-referrer" /> 5</head><body><center> 6 <div class="hl">Automatic-Transfer-Switch</div> 7 <div class="h2">Version %ver% (c) 2019 by Jörg Mahn</div> 8 <br><div class="h2">Generator</div> 9 <table id="a"> 10 <tr><td id="a"><font class="n">Umschaltzeit nach Stromausfall</font></td><td id="a"><font class="n">%lm% Min.</font></td></tr> 11 <tr><td id="a"><font class="n">Umschaltzeit nach Stromwiederkehr</font></td><td id="a"><font class="n">%bm% Min.</font></td></tr> 12 <tr><td id="a"><font class="n">Vorglühdauer</font></td><td id="a"><font class="n">%gt% Sek.</font></td></tr> 13 <tr><td id="a"><font class="n">Startdauer</font></td><td id="a"><font class="n">%it% Millisek.</font></td></tr> 14 <tr><td id="a"><font class="n">Startversuche</font></td><td id="a"><font class="n">%st% Mal</font></td></tr> 15 <tr><td id="a"><font class="n">Wartezeit nach Start</font></td><td id="a"><font class="n">%startd% Sek.</font></td></tr> 16 <tr><td id="a"><font class="n">Wartezeit nach Stop</font></td><td id="a"><font class="n">%stopd% Sek.</font></td></tr> 17 <tr><td id="a"><font class="n">Umschaltdauer</font></td><td id="a"><font class="n">%sd% Sek.</font></td></tr> 18 <tr><td id="a"><font class="n">Warnschwelle Starterbatterie</font></td><td id="a"><font class="n">%mv% Volt</font></td></tr> 19 </table> 20 <br><div class="h2">SD-Card</div> 21 <table id="a"> 22 <tr><td id="a"><font class="n">Name</font></td> 23 <td id="a"><font class="n">Größe</font></td> 24 <td id="a"><font class="n">löschen</font></td></tr> 25 <sdcontent>Hier wird der Inhalt der SD-Card eingefuegt</sdcontent> 26 </table> 27 <br><div class="h2">Datei Speichern</div> 28 <form method="post" enctype="multipart/form-data"> 29 <table id="c"> 30 <tr><td id="c" colspan="2"><input class="gr" type="file" name="datei" accept="text/*"></td></tr> 31 <tr><td id="c"><input class="gr" type="submit" value="Speichern"></td> 32 <td id="c"><input class="gr" type="button" value="Aktualisieren" onclick="window.location.href='http://ats.joergmahn.de/?config'" /></td></tr> 33 <tr><td id="c"><input class="gr" type="button" value="Zurück" onclick="window.location.href='http://ats.joergmahn.de'" /></td> 34 <td id="c"><input class="gr" type="button" value="Neu Starten" onclick="window.location.href='http://ats.joergmahn.de/?reset'" /></td></tr> 35 </table> 36 </form> 37</center></body></html> 38
mail.htm
html
Mail Web Document
1<!DOCTYPE html> 2<html> 3<head> 4 <title>ATS</title> 5</head> 6<body> 7 <font size="5"><b>Automatic-Transfer-Switch</b></font><br> 8 <font>(c) 2019 by Jörg Mahn</font><br><br> 9 <table> 10 <tr><td><b>Version:</b></td><td><a href="ats.webserver.com">%ver%</a></td></tr> 11 <tr><td><b>Status:</b></td><td>%sta%</td></tr> 12 <tr><td><b>Generator:</b></td><td>%gen%</td></tr> 13 <tr><td><b>RAM:</b></td><td>%ram% Bytes frei</td></tr> 14 <tr><td><b>Zeit:</b></td><td>%d% %z%</td></tr> 15 <tr><td><b>ATS:</b></td><td>%sys% °C</td></tr> 16 <tr><td><b>Motor:</b></td><td>%mot% °C</td></tr> 17 <tr><td><b>Halle:</b></td><td>%aut% °C</td></tr> 18 <tr><td><b>Batterie:</b></td><td>%bat% V</td></tr> 19 <tr><td><b>Leistung:</b></td><td>%p%</td></tr> 20 </table> 21 <br> 22 <table> 23 <tr><td><b>L1</b></td><td><b>L2</b></td><td><b>L3</b></td><td></tr> 24 <tr><td>%1v% V</td><td>%2v% V</td><td>%3v% V</td><td></tr> 25 <tr><td>%1c% A</td><td>%2c% A</td><td>%3c% A</td><td></tr> 26 </table> 27</body> 28</html>
ats.css
ini
CSS
1body { 2 background-color: #151515; 3 font-family: Helvetica, Arial, Geneva, sans-serif; 4 color: yellow; 5 font-size: 3vmin; 6} 7.hl { 8 font-size: 6vmin; 9 font-weight: bold; 10} 11a { 12 text-decoration: none; 13} 14table#a, td#a { 15 height: 5vmin; 16 width: 80%; 17 table-layout:fixed; 18 text-align: left; 19 border-collapse: collapse; 20 border: 1px solid white; 21 padding: 5px; 22} 23table#b, td#b { 24 height: 5vmin; 25 width: 80%; 26 table-layout:fixed; 27 text-align: center; 28 border-collapse: collapse; 29 border: 1px solid white; 30 padding: 5px; 31} 32 table#c, td#c{ 33 width: 80%; 34 table-layout:fixed; 35 text-align: center; 36 border: none; 37 /*border: 1px solid white;*/ 38 padding: 10px; 39} 40.e { 41 font-size: 5vmin; 42 font-weight: bold; 43} 44.n { 45 font-size: 4vmin; 46 color: lightyellow; 47} 48.v { 49 font-size: 5vmin; 50 color: lightyellow; 51} 52.gn { 53 background-color: #58FA58; 54 color: black; 55} 56.rt { 57 background-color: #FA5858; 58 color: black; 59} 60.gr { 61 /*background-color: #BDBDBD;*/ 62 background-color: lightyellow; 63 color: black; 64} 65.bl { 66 background-color: #5882FA; 67 color: black; 68} 69.ge { 70 background-color: #F4FA58; 71 color: black; 72} 73input[type="submit"], input[type="button"]{ 74 width: 35vmin; 75 font-size: 3vmin; 76 border: none; 77 padding: 20px; 78 text-align: center; 79 display: inline-block; 80} 81input[type="file"]{ 82 width: 68vmin; 83 font-size: 3vmin; 84 border: none; 85 padding: 20px; 86 text-align: center; 87 display: inline-block; 88} 89
mail.htm
html
Mail Web Document
1<!DOCTYPE html> 2<html> 3<head> 4 <title>ATS</title> 5</head> 6<body> 7 <font size="5"><b>Automatic-Transfer-Switch</b></font><br> 8 <font>(c) 2019 by Jörg Mahn</font><br><br> 9 <table> 10 <tr><td><b>Version:</b></td><td><a href="ats.webserver.com">%ver%</a></td></tr> 11 <tr><td><b>Status:</b></td><td>%sta%</td></tr> 12 <tr><td><b>Generator:</b></td><td>%gen%</td></tr> 13 <tr><td><b>RAM:</b></td><td>%ram% Bytes frei</td></tr> 14 <tr><td><b>Zeit:</b></td><td>%d% %z%</td></tr> 15 <tr><td><b>ATS:</b></td><td>%sys% °C</td></tr> 16 <tr><td><b>Motor:</b></td><td>%mot% °C</td></tr> 17 <tr><td><b>Halle:</b></td><td>%aut% °C</td></tr> 18 <tr><td><b>Batterie:</b></td><td>%bat% V</td></tr> 19 <tr><td><b>Leistung:</b></td><td>%p%</td></tr> 20 </table> 21 <br> 22 <table> 23 <tr><td><b>L1</b></td><td><b>L2</b></td><td><b>L3</b></td><td></tr> 24 <tr><td>%1v% V</td><td>%2v% V</td><td>%3v% V</td><td></tr> 25 <tr><td>%1c% A</td><td>%2c% A</td><td>%3c% A</td><td></tr> 26 </table> 27</body> 28</html>
C_checkstate.ino
arduino
Check States
1void CheckState() { 2 unsigned long currentMillis = millis(); 3 noInterrupts(); 4 5 // Freien Speicher berechnen 6 ram = FreeRam(); 7 8 // Temepraturwerte holen 9 GetTemp(&t_data); 10 11 // Stromwerte holen 12 GetCurrent(&p_data); 13 Leistung = p_data.L1_Leistung + p_data.L2_Leistung + p_data.L3_Leistung; 14 15 16 // Zum VZ puschen 17 unsigned long interval = 1000; // 1sec "delay" 18 if (millis() - VZTime > interval ) { 19 PushVZ(VZServer, VZRequest, UUID, Leistung); 20 VZTime = millis(); 21 } 22 23 if (Leistung > 999) { 24 Leistung = Leistung / 1000; 25 StrLeistung = form(String(Leistung, 2) + " KW", 6); 26 } else { 27 StrLeistung = form(String(Leistung, 0) + " W", 6); 28 } 29 30 // zum MQTT Broker pushen 31 if (MQTTenable) { 32 // mqtt_table[0-3] = subsriber Topics 33 34 strcpy_P(buffer, (char *)pgm_read_word(&(mqtt_table[4]))); 35 MQTT.publish(String(MQTTTopic) + (String) buffer, StrLeistung); 36 strcpy_P(buffer, (char *)pgm_read_word(&(mqtt_table[5]))); 37 MQTT.publish(String(MQTTTopic) + (String) buffer, String(Status)); 38 strcpy_P(buffer, (char *)pgm_read_word(&(mqtt_table[6]))); 39 MQTT.publish(String(MQTTTopic) + (String) buffer, String(ram)); 40 41 strcpy_P(buffer, (char *)pgm_read_word(&(mqtt_table[7]))); 42 MQTT.publish(String(MQTTTopic) + (String) buffer, String(p_data.L1_Leistung)); 43 strcpy_P(buffer, (char *)pgm_read_word(&(mqtt_table[8]))); 44 MQTT.publish(String(MQTTTopic) + (String) buffer, String(p_data.L1_Strom)); 45 strcpy_P(buffer, (char *)pgm_read_word(&(mqtt_table[9]))); 46 MQTT.publish(String(MQTTTopic) + (String) buffer, String(p_data.L1_Spannung)); 47 48 strcpy_P(buffer, (char *)pgm_read_word(&(mqtt_table[10]))); 49 MQTT.publish(String(MQTTTopic) + (String) buffer, String(p_data.L2_Leistung)); 50 strcpy_P(buffer, (char *)pgm_read_word(&(mqtt_table[11]))); 51 MQTT.publish(String(MQTTTopic) + (String) buffer, String(p_data.L2_Strom)); 52 strcpy_P(buffer, (char *)pgm_read_word(&(mqtt_table[12]))); 53 MQTT.publish(String(MQTTTopic) + (String) buffer, String(p_data.L2_Spannung)); 54 55 strcpy_P(buffer, (char *)pgm_read_word(&(mqtt_table[13]))); 56 MQTT.publish(String(MQTTTopic) + (String) buffer, String(p_data.L3_Leistung)); 57 strcpy_P(buffer, (char *)pgm_read_word(&(mqtt_table[14]))); 58 MQTT.publish(String(MQTTTopic) + (String) buffer, String(p_data.L3_Strom)); 59 strcpy_P(buffer, (char *)pgm_read_word(&(mqtt_table[15]))); 60 MQTT.publish(String(MQTTTopic) + (String) buffer, String(p_data.L3_Spannung)); 61 62 strcpy_P(buffer, (char *)pgm_read_word(&(mqtt_table[16]))); 63 MQTT.publish(String(MQTTTopic) + (String) buffer, String(t_data.SysTemperatur)); 64 strcpy_P(buffer, (char *)pgm_read_word(&(mqtt_table[17]))); 65 MQTT.publish(String(MQTTTopic) + (String) buffer, String(t_data.MotorTemperatur)); 66 strcpy_P(buffer, (char *)pgm_read_word(&(mqtt_table[18]))); 67 MQTT.publish(String(MQTTTopic) + (String) buffer, String(t_data.AussenTemperatur)); 68 69 70 // Netzbetrieb 71 if (Status==0) { 72 strcpy_P(buffer, (char *)pgm_read_word(&(mqtt_table[19]))); // /get/betrieb 73 MQTT.publish(String(MQTTTopic) + (String) buffer, "netz"); 74 } 75 76 // Generatorbetrieb 77 if (Status==1) { 78 strcpy_P(buffer, (char *)pgm_read_word(&(mqtt_table[19]))); // /get/betrieb 79 MQTT.publish(String(MQTTTopic) + (String) buffer, "generator"); 80 } 81 82 // Generator luft 83 if (Status==1) { // Generatorbetrieb 84 strcpy_P(buffer, (char *)pgm_read_word(&(mqtt_table[20]))); // /get/generator 85 MQTT.publish(String(MQTTTopic) + (String) buffer, F("start")); 86 } 87 if (Status==18) { // Generator luft 88 strcpy_P(buffer, (char *)pgm_read_word(&(mqtt_table[20]))); // /get/generator 89 MQTT.publish(String(MQTTTopic) + (String) buffer, F("start")); 90 } 91 92 // Generator luft nicht 93 if (Status==0) { // Netzbetrieb 94 strcpy_P(buffer, (char *)pgm_read_word(&(mqtt_table[20]))); // /get/generator 95 MQTT.publish(String(MQTTTopic) + (String) buffer, F("stop")); 96 } 97 if (Status==3) { // Strung Generator 98 strcpy_P(buffer, (char *)pgm_read_word(&(mqtt_table[20]))); // /get/generator 99 MQTT.publish(String(MQTTTopic) + (String) buffer, F("stop")); 100 } 101 if (Status==4) { // Strung Manuell 102 strcpy_P(buffer, (char *)pgm_read_word(&(mqtt_table[20]))); // /get/generator 103 MQTT.publish(String(MQTTTopic) + (String) buffer, F("stop")); 104 } 105 106 for (int i=0; i<=MaxStatus; i++) { 107 if (i==Status) { 108 strcpy_P(buffer, (char *)pgm_read_word(&(status_table[i]))); // Lesbaren Status pushen 109 MQTT.publish(String(MQTTTopic) + F("/get/status"), (String) buffer); 110 } 111 } 112 113 if (zuendung) { 114 if (Status == 1 || Status == 18) { 115 MQTT.publish(String(MQTTTopic) + F("/get/generator"), F("Ein")); 116 } else { 117 MQTT.publish(String(MQTTTopic) + F("/get/generator"), F("Standby")); 118 } 119 } else { 120 MQTT.publish(String(MQTTTopic) + F("/get/generator"), F("Aus")); 121 } 122 123 strcpy_P(buffer, (char *)pgm_read_word(&(mqtt_table[22]))); // /get/version 124 MQTT.publish(String(MQTTTopic) + (String) buffer, version); 125 126 strcpy_P(buffer, (char *)pgm_read_word(&(mqtt_table[23]))); // /get/batterie 127 MQTT.publish(String(MQTTTopic) + (String) buffer, ConvSeperator(GeneratorBatterie)); 128 129 } 130 131 // Sende keine E-Mail whrend der Initalisierung 132 // Zndung an? 133 134 int value = 0; 135 value = analogRead(ZUENDSCHLOSS); 136 if (value > 0) { 137 if (!zuendung) { 138 zuendung = true; 139 sendEmail(17); 140 } 141 } else { 142 if (zuendung) { 143 zuendung = false; 144 sendEmail(18); 145 } 146 } 147 148 //Batteriespannung holen 149 genbat = GetBatteryVoltage(); 150 GeneratorBatterie = String(genbat, 1); 151 if (genbat < minbatvoltage) { 152 if (!batlow) { 153 sendEmail(15); 154 } 155 batlow = true; 156 } else { 157 batlow = false; 158 } 159 160 // Alles LOW-Active! 161 // HIGH = Strom ausgefallen 162 163 // Netzwiederkehr bevor Timeout Netzausfall 164 if (!digitalRead(PIN_PHASE_NETZ) && Status == 8) { 165 piep(); 166 page = 1; 167 Status = 0; // "Netzbetrieb" 168 timeout = 0; 169 LCD_Status(Status); 170 previousMillis = 0; 171 sendEmail(9); 172 PgmPrintln("Netzwiederkehr bevor Timeout Netzausfall"); 173 } 174 175 // Netzausfall bevor Timeout Netzwiederkehr 176 if (digitalRead(PIN_PHASE_NETZ) && Status == 9) { 177 piep(); 178 page = 1; 179 Status = 1; // "Generatorbetrieb" 180 timeout = 0; 181 LCD_Status(Status); 182 previousMillis = 0; 183 sendEmail(8); 184 PgmPrintln("Netzausfall bevor Timeout Netzwiederkehr"); 185 } 186 187 // Netzausfall im Status "Netzbetrieb" oder "Netztrennung in..." 188 if (digitalRead(PIN_PHASE_NETZ) && (Status == 0 || Status == 8)) { 189 if (previousMillis == 0) previousMillis = currentMillis; 190 if (Status == 0) { 191 page = 1; 192 Status = 8; // "Netztrennung" 193 sendEmail(Status); 194 Alert(HCServer, HCRequest, HCLoss); 195 PgmPrintln("Netzausfall im Status Netzbetrieb, Countdown gestartet."); 196 piep(); 197 } 198 timeout = lostmain * 60 - ((currentMillis - previousMillis) / 1000); 199 LCD_Status(Status); 200 201 if (timeout <= 0) { 202 previousMillis = 0; 203 piep(); 204 PgmPrintln("Netzausfall!"); 205 Alert(HCServer, HCRequest, HCStart); 206 if (Generator(ON)) { // Wenn Generator gestartet... 207 if (!digitalRead(PIN_PHASE_GEN)) { // ...und alle drei Phasen vorhanden... 208 Status = 1; // "Generatorbetrieb" 209 LCD_Status(Status); 210 SwitchGeneratorbetrieb(); // ...dann Umschalten auf Generatorbetrieb. 211 sendEmail(10); 212 PgmPrintln("Generator gestartet, Umschalten auf Generatorbetrieb."); 213 } else { // Generator liefert keine Spannungen 214 Status = 3; // "Strung Generator" 215 Alert(HCServer, HCRequest, HCError); 216 LCD_Status(Status); 217 Generator(OFF); // Generator ausschalten 218 sendEmail(12); 219 PgmPrintln("Generator gestartet, aber Phasen liefern keine Spannung!"); 220 } 221 } else { // Generator konnte nicht gestartet werden 222 Status = 3; // "Strung Generator" 223 Alert(HCServer, HCRequest, HCError); 224 LCD_Status(Status); 225 Generator(OFF); 226 sendEmail(12); 227 PgmPrintln("Generator konnte nicht gestartet werden!"); 228 } 229 } 230 } 231 232 // Netzwiederkehr im Status "Generatorbetrieb" und "Netzwiederkehr in..." 233 if (!digitalRead(PIN_PHASE_NETZ) && (Status == 1 || Status == 9)) { 234 if (previousMillis == 0) previousMillis = currentMillis; 235 if (Status == 1) { 236 page = 1; 237 Status = 9; // "Netzwiederkehr" 238 Alert(HCServer, HCRequest, HCBack); 239 PgmPrintln("Netzwiederkehr im Status Generatorbetrieb, Countdown gestartet."); 240 sendEmail(Status); 241 piep(); 242 } 243 timeout = (backmain * 60) - ((currentMillis - previousMillis) / 1000); 244 LCD_Status(Status); 245 246 if (timeout <= 0) { 247 previousMillis = 0; 248 PgmPrintln("Netzwiederkehr im Status Generatorbetrieb"); 249 Status = 0; // "Netzbetrieb" 250 Alert(HCServer, HCRequest, HCStop); 251 piep(); 252 Generator(OFF); 253 LCD_Status(Status); 254 SwitchNetzbetrieb(); // Umschalten auf Netzbetrieb 255 sendEmail(11); 256 } 257 } 258 259 // Netzwiederkehr im Status "Strung Generator" 260 if (!digitalRead(PIN_PHASE_NETZ) && Status == 3) { 261 PgmPrintln("Netzwiederkehr im Status Strung"); 262 page = 1; 263 Status = 0; // "Netzbetrieb"; 264 Alert(HCServer, HCRequest, HCBack); 265 piep(); 266 Generator(OFF); 267 LCD_Status(Status); 268 SwitchNetzbetrieb(); 269 sendEmail(9); 270 } 271 272 // Generatorwiederkehr im Status "Strung Generator" 273 if (!digitalRead(PIN_PHASE_GEN) && Status == 3) { 274 PgmPrintln("Generatorwiederkehr im Status Strung Generator"); 275 page = 1; 276 Status = 1; // "Generatorbetrieb" 277 piep(); 278 //Generator(ON); 279 LCD_Status(Status); 280 SwitchGeneratorbetrieb(); // Umschalten auf Generatorbetrieb 281 sendEmail(10); 282 } 283 284 // Generatorausfall im Status "Generatorbetrieb" 285 if (digitalRead(PIN_PHASE_GEN) && Status == 1) { 286 PgmPrintln("Generatorausfall im Status Generatorbetrieb"); 287 Generator(OFF); 288 SwitchNetzbetrieb(); // Umschalten auf Netzbetrieb und hoffen, dass der Strom bald wieder kommt! 289 page = 1; 290 Status = 3; // "Strung Generator" 291 Alert(HCServer, HCRequest, HCError); 292 piep(); 293 LCD_Status(Status); 294 sendEmail(12); 295 } 296 297 // Generatorausfall im Status "Manueller Betrieb" 298 if (digitalRead(PIN_PHASE_GEN) && Status == 2) { 299 PgmPrintln("Generatorausfall im Status Manuellerbetrieb"); 300 Generator(OFF); 301 page = 1; 302 Status = 4; // "Strung Manuell" 303 Alert(HCServer, HCRequest, HCError); 304 piep(); 305 LCD_Status(Status); 306 sendEmail(12); 307 } 308 309 // Generatorwiederkehr im Status "Strung Manuell" 310 if (!digitalRead(PIN_PHASE_GEN) && Status == 4) { 311 PgmPrintln("Generatorwiederkehr im Status Strung Manuell"); 312 page = 1; 313 Status = 2; // "Manueller Betrieb" 314 piep(); 315 Generator(ON); 316 LCD_Status(Status); 317 // SwitchGeneratorbetrieb(); // Umschalten auf Generatorbetrieb 318 sendEmail(10); 319 } 320 321 interrupts(); 322} 323
B_setup.ino
arduino
Setup Routines
1void setup() { 2 while (!Serial) { } // wait for serial port to connect. Needed for native USB port only 3 Serial.begin(9600); 4 PgmPrintln("ATS Version "); 5 Serial.println(version); 6 7 // LCD Initalisieren 8 lcd.begin(LCD_Cols, LCD_Rows); 9 delay(2); 10 LCD_Head(); 11 LCD_Status(Status); 12 13 // Initalisieren der drei Power Meter 14 while (!Serial1) { } 15 pzem1 = new PZEM004T(&Serial1); 16 pzem1->setAddress(pip1); 17 while (!Serial2) { } 18 pzem2 = new PZEM004T(&Serial2); 19 pzem2->setAddress(pip2); 20 while (!Serial3) { } 21 pzem3 = new PZEM004T(&Serial3); 22 pzem3->setAddress(pip3); 23 24 // Digital-Eingnge 25 pinMode(PIN_BUTTON, INPUT_PULLUP); // Menbutton 26 attachInterrupt(digitalPinToInterrupt(PIN_BUTTON), InterruptButton, LOW); 27 pinMode(PIN_PHASE_NETZ, INPUT_PULLUP);// Phasenkontrolle Netzversorger 28 pinMode(PIN_PHASE_GEN, INPUT_PULLUP); // Phasenkontrolle Generator 29 pinMode(PIN_OEL, INPUT); // Digital-Eingang Kontrolle ldruck LED grn 30 31 // Analog-Eingnge 32 pinMode(BAT_INPUT, INPUT); // Batteriespannungsmessung (Spannungsteiler (10K - 100k) 33 pinMode(ZUENDSCHLOSS, INPUT); // Spannungsmessung Zndschloss (Off / Standby) (10K - 100k) 34 35 // Digital Ausgnge 36 pinMode(PIN_BUZZER, OUTPUT); // Digitalausgang Pieper 37 pinMode(SD_SELECT, OUTPUT); 38 digitalWrite(SD_SELECT, HIGH); // disable SD card 39 pinMode(ETHERNET_SELECT, OUTPUT); 40 digitalWrite(ETHERNET_SELECT, HIGH); // disable Ethernet 41 pinMode(10, OUTPUT); // set the SS pin as an output (necessary!) 42 digitalWrite(10, HIGH); // but turn off the W5100 chip! 43 44 // Umschalt Relais sind LOW-Active! 45 pinMode(REL_NETZ, OUTPUT); // Relais Netzversorger 46 digitalWrite(REL_NETZ, HIGH); 47 pinMode(REL_GEN, OUTPUT); // Relais Generator 48 digitalWrite(REL_GEN, HIGH); 49 50 // Generator Relais sind HIGH-Active! 51 pinMode(PIN_Z_EIN, OUTPUT); // Zndschloss "Ein" 52 digitalWrite(PIN_Z_EIN, LOW); 53 pinMode(PIN_Z_START, OUTPUT); // Zndschloss "Start" 54 digitalWrite(PIN_Z_START, LOW); 55 56 SPI.begin(); 57 58 if (!SD.begin(SD_SELECT)) { 59 while (1) { 60 PgmPrintln("SD.begin() failed"); 61 LCD_Status(11); // "SD-Card Fehler" 62 } 63 } 64 delay(1); 65 66 // INI-File von SD-Card einlesen und Variabeln setzen. 67 ReadIniFile(); 68 69 // Start the I2C interface 70 Wire.begin(); 71 delay(1); 72 73 // Start the Ethernet connection and the server: 74 Ethernet.begin(mac, ip, dns, gateway, subnet); 75 server.begin(); 76 delay(1000); // Ethernet Start abwarten. 77 // Check for Ethernet hardware present 78 PgmPrintln("Waiting for Network"); 79 80 if (Ethernet.hardwareStatus() == EthernetNoHardware) { 81 PgmPrintln("Ethernet shield was not found. Sorry, can't run without hardware. :("); 82 while (true) { 83 LCD_Status(7); // "Kein Netzwerk" 84 delay(1); // do nothing, no point running without Ethernet hardware 85 } 86 } 87 88 // Teste Ethernet Kabel Verbindung 89 testLink(); 90 while (!etherStatus) { 91 LCD_Status(7); // Kein Netzwerk 92 testLink(); 93 } 94 95 // verbinde zum MQTT Brooker 96 if (MQTTenable) { 97 MQTT.begin(MQTTServer, MQTTnet); 98 MQTT.onMessage(MQTTmessageReceived); 99 // Last will and testament 100 strcpy_P(buffer, (char *)pgm_read_word(&(mqtt_table[21]))); // /get/status 101 char topic[bufferLen] = ""; strcat(topic, MQTTTopic); strcat(topic, buffer); 102 MQTT.setWill(topic, "Offline", true, 0); 103 MQTTconnect(); 104 } 105 106 LCD_Status(10); // LCD-Status: Initalisierung 107 108 // Webserver starten 109 PgmPrintln("Webserver starting at: "); 110 Serial.print(Ethernet.localIP()); 111 PgmPrintln(":80"); 112 113 // NTP-Eintrag aus INI-Datei in IP-Adresse auflsen (Egal ob IP oder Hostname) 114 DNSClient dns; 115 dns.begin(Ethernet.dnsServerIP()); 116 dns.getHostByName(ntp, timeServer); 117 118 // Zeit mit Internetzeit Synchronisieren 119 Udp.begin(localPort); 120 PgmPrintln("Waiting for Timesync..."); 121 delay(1000); // Ethernet Start abwarten. 122 syncTime(); 123 Serial.println(showDate()); 124 Serial.println(showTime()); 125 126 // set date time callback function 127 SdFile::dateTimeCallback(dateTime); 128 129 // Freien RAM ermitteln 130 // ram = (String) FreeRam(); 131 ram = FreeRam(); 132 Serial.print(ram); 133 PgmPrintln(" Bytes RAM free"); 134 135 // Auf Netzbetrieb schalten 136 digitalWrite(REL_GEN, HIGH); 137 digitalWrite(REL_NETZ, LOW); 138 delay(switchdelay * 1000); 139 digitalWrite(REL_NETZ, HIGH); 140 page = 1; 141 142 // Zndung an? 143 int value = 0; 144 value = analogRead(ZUENDSCHLOSS); 145 if (value > 0) { 146 zuendung = true; 147 } else { 148 zuendung = false; 149 } 150 151 if (HCenable) { Serial.println(F("Home-Controll: aktive")); } else { Serial.println(F("Home-Controll: not aktive")); } 152 if (VZenable) { Serial.println(F("Volkzaehler: aktive")); } else { Serial.println(F("Volkzaehler: not aktive")); } 153 if (MQTTenable) { Serial.println(F("MQTT: aktive")); } else { Serial.println(F("MQTT: not aktive")); } 154 155 CheckState(); 156 Webserver(); 157 sendEmail(13); 158 piep(); 159 Status = 0; 160 PgmPrintln("READY"); 161} 162
ats.ino
arduino
Arduino Sketch
1/* 2 ATS - Automatic Transfer Switch 3 (c) 03'2019 by Jrg R. Mahn 4 For Arduino Mega 2560 5 6 Erkennt einen Stromausfall, trennt das Versorgungsnetz, 7 startet das Notstromaggreagt, schaltet die Stromversorung auf das Aggregat um. 8 Nach dem das Versorgungnetz wieder verfgbar ist, wird das Notstromaggregat getrennt, 9 die Stromversorgung wird wieder auf das Versorgungsnetz umgeschaltet, 10 das Notstromaggregat wird gestoppt. 11 12 Features: 13 - 20x4 LCD 14 - DS3231 Realtime Clock with Internet Sync 15 - Webserver (Port 80) (Pages stored on SD-Card) 16 - E-Mail Client to send status E-Mail 17 - One Wire Temperature Measurement 18 - 3 x PZEM004T Power Meter 19 20 09.04.2019 Erstes Release mit allen Modulen 21 04.05.2019 Settings von SD-Karte laden 22 06.05.2019 IP Settings von SD Karte laden 23 08.05.2019 Zeiten von SD-Karte laden 24 17.05.2019 Umstellung auf INI-Datei 25 24.05.2019 Verschiebung der Strings in den Flash-Speicher 26 10.06.2019 ndern der Reihenfolge beim Rckschalten. 27 Esrt Generator ausschalten, dann Netzwiederkehr 28 12.06.2019 Optische Verbesserungen am LCD 29 22.07.2019 nderung der Leistungsanzeige 30 25.07.2019 Anzeige der Batteriespannung 31 28.07.2019 Temperaturanzeige (Motor und Auen) erfolgreich. (Pullup Widerstand von 2,2K auf 1,5K gesenkt 32 05.08.2019 LCD Status "Fehler INI-File" eingefhrt, Variable "Leistung" globalisiert. 33 13.08.2019 PIN 5 (ldruck OK) als Indikator fr den Lauf des Motors hinzugefgt. Funktion Generator abgendert. 34 Funktion CheckState (Abschnitt Netzausfall im Status "Netzbetrieb" oder "Netztrennung in...") auf 35 berwachung des Motors und Phasen ergnzt. Tastenpiep hinzugefgt. 36 minbatvoltage zur INI-Datei hinzugefgt 37 19.08.2019 Weiterer Web-Parameter hinzugefgt: showconfig. Zeigt die Aktuelle Konfiguration aus der INI-Datei an. 38 20.08.2019 INDEX.HTM in drei Dateien (a.htm, b.htm, c.htm) zerlegt. 39 21.08.2019 Webseiten der config.ini hinzugefgt. Styles der a.htm hinzugefgt. 40 22.08.2019 Funktion Alert fr die Sprachausgabe ber die Haussteuerung hinzugefgt. (=> V.2.7) 41 23.08.2019 Bug in der Generatorfunktion behoben. (Zndung ging nicht wieder an beim >1 Startversuch.) 42 Startzeit (ignitiontime) wird nach jedem erfolglosem Startversuch um 100ms verlngert 43 24.08.2019 berwachung des Zndschlosses hinzugefgt. Analogeingang A1 (=> V.2.8) 44 13.09.2019 Struckturen fr Generator und Temperaturdaten eingefhrt 45 17.09.2019 Datei-Upload implementiert. (=> V.2.9) 46 19.09.2019 ATS-Konfiguration komplett neu gestaltet. (=> V.3.0) 47 20.09.2019 Sicherheitsabfrage beim Lschen hinzugefgt 48 27.09.2019 JSON Abfrage eingefhrt (=> V.3.1) 49 02.10.2019 Volkszhler Option eingefhrt 50 04.10.2019 Bug beim Dateiupload entfernt, HC und VZ enable eingefhrt (=> V.3.2) 51 07.10.2019 MQTT eingefhrt (=> V.3.3) 52 08.10.2019 Verbesserung des Webservers (Zeilenweise auslieferung) 53 HTML-Vorlagen auf eine Datei reduziert. 54 JSON Abfrage entfernt. 55 09.10.2019 Last will and testament und Version hinzugefgt. 56*/ 57 58String version = "3.3 09.10.2019"; 59 60#include <PZEM004T.h> // Digitale Multifunktions Meter PZEM-004T 61#include <Time.h> // Timekeeping functionality 62#include <TimeLib.h> 63#include <DS3231.h> // DS3231 - Version: Latest 64#include <Wire.h> // IC bus (Mega2560: 20 (SDA), 21 (SCL)) 65#include <LiquidCrystal.h> // LC-Display 66#include <OneWire.h> // Access 1-wire Bus (Pin 22) 67#include <DallasTemperature.h> // OneWire Temperatursensor 68#include <SPI.h> // Serial Peripheral Interface 69#include <Ethernet.h> // Ethernet library 70#include <EthernetUdp.h> // UDP library (for Internet-Time-Sync) 71#include <SD.h> // Access SD-Card 72#include <IniFile.h> // INI-File Acces Routines 73#include <Dns.h> // getHostByName 74#include <avr/pgmspace.h> // Um Strings in den Flash-Speicher zu verschieben 75#include <MQTT.h> 76 77//#define BUFSIZ 100 78File sdFile; 79const char *configFile = "/config.ini"; 80 81// The select pin used for the SD card 82#define SD_SELECT 4 83#define ETHERNET_SELECT 53 84 85// Settings Konfiguration 86const size_t bufferLen = 80; // Pufferlnge fr INI-Datei = Maximale Zeilenlnge 87char buffer[bufferLen]; 88 89byte lostmain; 90byte backmain; 91byte glowtime; 92byte ignitiontime; 93byte starttrying; 94byte genstartdelay; 95byte genstoppdelay; 96byte switchdelay; 97float minbatvoltage; // Minimale Batteriespannung bevor Warnung 98char domain[20]; 99char host[20]; 100byte ip[4]; 101byte dns[4]; 102byte gateway[4]; 103byte subnet[4]; 104char ntp[bufferLen] = ""; // Aus INI-Datei, kann IP oder Hostname sein 105char m_server[20] = ""; 106String m_to; 107String m_to_rn; 108String m_from; 109String m_from_rn; 110 111bool VZenable = false; 112char UUID[bufferLen] = ""; // Daten zum Volkserver puschen 113char VZServer[bufferLen] = ""; 114char VZRequest[bufferLen] = ""; 115unsigned long VZTime; 116 117char Mail_File[20] = {}; // HTML-Seiten fr das Webfrontend 118char ATS_File[20] = {}; 119char Config_File[20] = {}; 120char CSS_File[20] = {}; 121 122bool HCenable = false; 123char HCServer[bufferLen] = ""; 124char HCRequest[bufferLen] = ""; 125byte HCStart; 126byte HCStop; 127byte HCError; 128byte HCLoss; 129byte HCBack; 130 131bool MQTTenable = false; 132char MQTTServer[bufferLen] = ""; 133char MQTTTopic[bufferLen] = ""; 134char MQTTMessage[bufferLen] = ""; 135char MQTTUsername[bufferLen] = ""; 136char MQTTPassword[bufferLen] = ""; 137 138// Konfiguration Netzwerk und Webserver 139EthernetServer server(80); 140byte mac[] = { 0xA8, 0x61, 0x0A, 0xAE, 0x3E, 0x54 }; 141IPAddress timeServer; // TimeServer (IP-Adresse) fr NTP-Sync 142 143// Konfiguration E-Mail-Server 144EthernetClient mailclient; 145 146// Konfiguration MQTT 147EthernetClient MQTTnet; 148MQTTClient MQTT; 149 150// Konfiguration NTP-Server 151EthernetUDP Udp; 152unsigned int localPort = 8888; 153const int NTP_PACKET_SIZE = 48; 154byte packetBuffer[NTP_PACKET_SIZE]; 155 156// Konfiguration DS3231 RTC 157DS3231 Clock; 158bool Century = false; 159bool h12; 160bool PM; 161 162// Konfiguration One-Wire 163#define ONE_WIRE_BUS 22 164OneWire oneWire(ONE_WIRE_BUS); 165 166// 1-Wire (Dallas) Temperatursensoren 167DallasTemperature sensors(&oneWire); 168 169// Konfiguration LCD 170#define LCD_RS 37 171#define LCD_E 36 172#define LCD_D4 35 173#define LCD_D5 34 174#define LCD_D6 33 175#define LCD_D7 32 176#define LCD_Rows 4 177#define LCD_Cols 20 178LiquidCrystal lcd(LCD_RS, LCD_E, LCD_D4, LCD_D5, LCD_D6, LCD_D7); 179String lcdHead = "ATS (c) 2019 J. Mahn"; 180 181// Konfiguration PZEM004T Power-Meter 182PZEM004T* pzem1; 183PZEM004T* pzem2; 184PZEM004T* pzem3; 185IPAddress pip1(192, 168, 1, 1); 186IPAddress pip2(192, 168, 1, 2); 187IPAddress pip3(192, 168, 1, 3); 188 189//LCD Sonderzeichen 190#define dg 0xDF // 191 192// Ausgnge fr das Zndschloss 193#define PIN_BUTTON 2 // Mentaste 194#define PIN_BUZZER 3 // Pieper 195#define PIN_OEL 5 // Eingang ldruck LED grn 196#define PIN_PHASE_NETZ 24 // Phasenkontrolle Netzversorger 197#define PIN_PHASE_GEN 25 // Phasenkontrolle Generator 198#define PIN_Z_EIN 28 // Zndschloss "Ein" 199#define PIN_Z_START 29 // Zndschloss "Start" 200#define REL_NETZ 30 // Schtz Netzversorger 201#define REL_GEN 31 // Schtz Generator 202#define BAT_INPUT 0 // Analogeingang fr Generator-Batteriespannung 203#define ZUENDSCHLOSS 1 // Analogeingang fr Zuendschloss (Off / Standby) 204 205#define ON 2 206#define OFF 1 207 208byte page = 1; // Start-Menseite 209bool batlow = false; // Generatorbatteriespannung zu gering 210const byte maxPage = 5; // Max. Anzahl Menseiten 211long time = 0; // used for debounce 212long debounce = 50; // how many ms to "debounce" between presses 213bool etherStatus; // Zustand der Ethernet-Verbindung 214char weekDay[7][2] = {"So", "Mo", "Di", "Mi", "Do", "Fr", "Sa" }; 215byte Status = 10; // Index fr Betriebsart (Initalisierung) 216byte timeZone = 1; // Zeitzone 217float Leistung = 0; // Gesammt-Leistung 218byte byte_array[4]; // Puffer fr IP-Adressen aus der INI-Datei / Char2IP() 219bool zuendung = false; // Zndschloss (Off / Standby) 220int ram; 221char timestamp[30]; 222 223// Status-Strings (Max 20 Chars) 224const char status_0[] PROGMEM = "Netzbetrieb"; 225const char status_1[] PROGMEM = "Generatorbetrieb"; 226const char status_2[] PROGMEM = "Manueller Betrieb"; 227const char status_3[] PROGMEM = "Strung Generator"; 228const char status_4[] PROGMEM = "Strung Manuell"; 229const char status_5[] PROGMEM = "Stromausfall"; 230const char status_6[] PROGMEM = "Generator Start"; 231const char status_7[] PROGMEM = "Kein Netzwerk"; 232const char status_8[] PROGMEM = "Netztrennung"; 233const char status_9[] PROGMEM = "Netzwiederkehr"; 234const char status_10[] PROGMEM = "Initialisierung"; 235const char status_11[] PROGMEM = "SD-Card Fehler"; 236const char status_12[] PROGMEM = "Umschaltung"; 237const char status_13[] PROGMEM = "Vorglhen"; 238const char status_14[] PROGMEM = "Zndung"; 239const char status_15[] PROGMEM = "Drehzal berprfen"; 240const char status_16[] PROGMEM = "Generator stoppen"; 241const char status_17[] PROGMEM = "Fehler INI-File"; 242const char status_18[] PROGMEM = "Generator luft"; 243 244byte MaxStatus = 18; 245 246const char *const status_table[] PROGMEM = { 247 status_0, 248 status_1, 249 status_2, 250 status_3, 251 status_4, 252 status_5, 253 status_6, 254 status_7, 255 status_8, 256 status_9, 257 status_10, 258 status_11, 259 status_12, 260 status_13, 261 status_14, 262 status_15, 263 status_16, 264 status_17, 265 status_18 266}; 267 268// INI-Strings 269const char ini_0[] PROGMEM = "Generator Einstellungen"; 270const char ini_1[] PROGMEM = "lostmain"; 271const char ini_2[] PROGMEM = "backmain"; 272const char ini_3[] PROGMEM = "glowtime"; 273const char ini_4[] PROGMEM = "ignitiontime"; 274const char ini_5[] PROGMEM = "starttrying"; 275const char ini_6[] PROGMEM = "genstartdelay"; 276const char ini_7[] PROGMEM = "genstoppdelay"; 277const char ini_8[] PROGMEM = "switchdelay"; 278const char ini_9[] PROGMEM = "minbatvoltage"; 279 280const char ini_10[] PROGMEM = "Network"; 281const char ini_11[] PROGMEM = "IP"; 282const char ini_12[] PROGMEM = "DNS"; 283const char ini_13[] PROGMEM = "GW"; 284const char ini_14[] PROGMEM = "SUB"; 285const char ini_15[] PROGMEM = "NTP"; 286 287const char ini_16[] PROGMEM = "Mail"; 288const char ini_17[] PROGMEM = "Server"; 289const char ini_18[] PROGMEM = "From"; 290const char ini_19[] PROGMEM = "To"; 291const char ini_20[] PROGMEM = "From_RN"; 292const char ini_21[] PROGMEM = "To_RN"; 293 294const char ini_22[] PROGMEM = "Webserver"; 295const char ini_23[] PROGMEM = "Files"; 296 297const char ini_24[] PROGMEM = "HC"; 298const char ini_25[] PROGMEM = "Enabled"; 299const char ini_26[] PROGMEM = "Server"; 300const char ini_27[] PROGMEM = "Request"; 301const char ini_28[] PROGMEM = "Start"; 302const char ini_29[] PROGMEM = "Stop"; 303const char ini_30[] PROGMEM = "Error"; 304const char ini_31[] PROGMEM = "Loss"; 305const char ini_32[] PROGMEM = "Back"; 306 307const char *const ini_table[] PROGMEM = { 308 ini_0, 309 ini_1, 310 ini_2, 311 ini_3, 312 ini_4, 313 ini_5, 314 ini_6, 315 ini_7, 316 ini_8, 317 ini_9, 318 ini_10, 319 ini_11, 320 ini_12, 321 ini_13, 322 ini_14, 323 ini_15, 324 ini_16, 325 ini_17, 326 ini_18, 327 ini_19, 328 ini_20, 329 ini_21, 330 ini_22, 331 ini_23, 332 ini_24, 333 ini_25, 334 ini_26, 335 ini_27, 336 ini_28, 337 ini_29, 338 ini_30, 339 ini_31, 340 ini_32 341}; 342 343// Mail-Strings (Max 80 Chars) 344const char mail_0[] PROGMEM = "Anforderung zum Generatorbetrieb, Generator gestartet"; 345const char mail_1[] PROGMEM = "Anforderung zum Generatorbetrieb, Generator nicht gestartet"; 346const char mail_2[] PROGMEM = "Anforderung zum Netzbetrieb, Generator gestoppt"; 347const char mail_3[] PROGMEM = "Anforderung zum Netzbetrieb, Generator nicht gestoppt"; 348const char mail_4[] PROGMEM = "Anforderung zum Generatorstart, Generator gestartet"; 349const char mail_5[] PROGMEM = "Anforderung zum Generatorstart, Generator nicht gestartet"; 350const char mail_6[] PROGMEM = "Anforderung zum Generatorstopp, Generator gestoppt"; 351const char mail_7[] PROGMEM = "Anforderung zum Generatorstopp, Generator nicht gestoppt"; 352const char mail_8[] PROGMEM = "Netzausfall"; 353const char mail_9[] PROGMEM = "Netzwiederkehr"; 354const char mail_10[] PROGMEM = "Generator gestartet"; 355const char mail_11[] PROGMEM = "Generator gestoppt"; 356const char mail_12[] PROGMEM = "Strung Generator"; 357const char mail_13[] PROGMEM = "Neustart"; 358const char mail_14[] PROGMEM = "Status"; 359const char mail_15[] PROGMEM = "Spannung Starterbatterie zu gering"; 360const char mail_16[] PROGMEM = "Anforderung zum Reboot"; 361const char mail_17[] PROGMEM = "Generator ist Standby"; 362const char mail_18[] PROGMEM = "Generator ist aus"; 363 364const char *const mail_table[] PROGMEM = { 365 mail_0, 366 mail_1, 367 mail_2, 368 mail_3, 369 mail_4, 370 mail_5, 371 mail_6, 372 mail_7, 373 mail_8, 374 mail_9, 375 mail_10, 376 mail_11, 377 mail_12, 378 mail_13, 379 mail_14, 380 mail_15, 381 mail_16, 382 mail_17, 383 mail_18 384}; 385 386//MQTT-Strings 387const char mqtt_0[25] PROGMEM = "/set/reset"; 388const char mqtt_1[25] PROGMEM = "/set/betrieb"; 389const char mqtt_2[25] PROGMEM = "/set/email"; 390const char mqtt_3[25] PROGMEM = "/set/generator"; 391 392const char mqtt_4[25] PROGMEM = "/leistung"; 393const char mqtt_5[25] PROGMEM = "/status"; 394const char mqtt_6[25] PROGMEM = "/ram"; 395 396const char mqtt_7[25] PROGMEM = "/phase1/leistung"; 397const char mqtt_8[25] PROGMEM = "/phase1/strom"; 398const char mqtt_9[25] PROGMEM = "/phase1/spannung"; 399 400const char mqtt_10[25] PROGMEM = "/phase2/leistung"; 401const char mqtt_11[25] PROGMEM = "/phase2/strom"; 402const char mqtt_12[25] PROGMEM = "/phase2/spannung"; 403 404const char mqtt_13[25] PROGMEM = "/phase3/leistung"; 405const char mqtt_14[25] PROGMEM = "/phase3/strom"; 406const char mqtt_15[25] PROGMEM = "/phase3/spannung"; 407 408const char mqtt_16[25] PROGMEM = "/temperatur/system"; 409const char mqtt_17[25] PROGMEM = "/temperatur/motor"; 410const char mqtt_18[25] PROGMEM = "/temperatur/aussen"; 411 412const char mqtt_19[25] PROGMEM = "/get/betrieb"; 413const char mqtt_20[25] PROGMEM = "/get/generator"; 414const char mqtt_21[25] PROGMEM = "/get/status"; 415const char mqtt_22[25] PROGMEM = "/get/version"; 416const char mqtt_23[25] PROGMEM = "/get/batterie"; 417 418const char *const mqtt_table[] PROGMEM = { 419 mqtt_0, 420 mqtt_1, 421 mqtt_2, 422 mqtt_3, 423 mqtt_4, 424 mqtt_5, 425 mqtt_6, 426 mqtt_7, 427 mqtt_8, 428 mqtt_9, 429 mqtt_10, 430 mqtt_11, 431 mqtt_12, 432 mqtt_13, 433 mqtt_14, 434 mqtt_15, 435 mqtt_16, 436 mqtt_17, 437 mqtt_18, 438 mqtt_19, 439 mqtt_20, 440 mqtt_21, 441 mqtt_22, 442 mqtt_23 443}; 444 445byte letztertag = 0; // Fr die tgliche Zeitsynchronosation 446 447typedef struct _Temperaturen_ { 448 String SysTemperatur; // Temperatur auf dem RTC 449 String MotorTemperatur; // One-Wire Temperatursensor Motor 450 String AussenTemperatur; // One-Wire Temperatursensor Generator 451} Temperaturen; 452Temperaturen t_data; 453 454String StrLeistung; // Gesamtleistung 455 456float genbat; 457String GeneratorBatterie; 458int timeout = 0; 459// Deklarierung fr die Pausen 460unsigned long previousMillis = 0; 461 462typedef struct _Powermeter_ { 463 float L1_Spannung = 0; 464 float L2_Spannung = 0; 465 float L3_Spannung = 0; 466 float L1_Strom = 0; 467 float L2_Strom = 0; 468 float L3_Strom = 0; 469 float L1_Leistung = 0; 470 float L2_Leistung = 0; 471 float L3_Leistung = 0; 472} Powermeter; 473Powermeter p_data; 474 475void MQTTconnect() { 476 Serial.print("Connecting to MQTT..."); 477 while (!MQTT.connect("ats", MQTTUsername, MQTTPassword)) { 478 Serial.print("."); 479 delay(1000); 480 } 481 Serial.println("\ 482Connected!"); 483 MQTT.subscribe(String(MQTTTopic)+"/set/#"); 484} 485 486void LCD_Start() { 487 LCD_Head(); 488 lcd.setCursor(0, 1); 489 delay(2); 490 lcd.print(showDate()); 491 lcd.print(" "); 492 lcd.print(showTime()); 493 LCD_Status(Status); 494 Link_Gen(); 495} 496 497void LCD_Verbrauch() { 498 String str; 499 LCD_Head(); 500 501 lcd.setCursor(0, 1); 502 delay(2); 503 str = form(String(p_data.L1_Spannung, 0) + "V", 6); 504 str += form(String(p_data.L2_Spannung, 0) + "V", 6); 505 str += form(String(p_data.L3_Spannung, 0) + "V", 6); 506 lcd.print(fillup(str)); 507 508 lcd.setCursor(0, 2); 509 delay(2); 510 str = form(String(p_data.L1_Strom, 1) + "A", 6); 511 str += form(String(p_data.L2_Strom, 1) + "A", 6); 512 str += form(String(p_data.L3_Strom, 1) + "A", 6); 513 lcd.print(fillup(str)); 514 515 lcd.setCursor(0, 3); 516 delay(2); 517 if (p_data.L1_Leistung > 1000) { 518 p_data.L1_Leistung = p_data.L1_Leistung / 1000; 519 str = form(String(p_data.L1_Leistung, 1) + "KW", 6); 520 } else { 521 str = form(String(p_data.L1_Leistung, 0) + "W", 6); 522 } 523 if (p_data.L2_Leistung > 1000) { 524 p_data.L2_Leistung = p_data.L2_Leistung / 1000; 525 str += form(String(p_data.L2_Leistung, 1) + "KW", 6); 526 } else { 527 str += form(String(p_data.L2_Leistung, 0) + "W", 6); 528 } 529 if (p_data.L3_Leistung > 1000) { 530 p_data.L3_Leistung = p_data.L3_Leistung / 1000; 531 str += form(String(p_data.L3_Leistung, 1) + "KW", 6); 532 } else { 533 str += form(String(p_data.L3_Leistung, 0) + "W", 6); 534 } 535 lcd.print(fillup(str)); 536} 537 538void LCD_Leistungen() { 539 String str; 540 Leistung = p_data.L1_Leistung + p_data.L2_Leistung + p_data.L3_Leistung; 541 LCD_Head(); 542 543 lcd.setCursor(0, 1); 544 delay(2); 545 str = "Leistung: "; 546 str += form(String(Leistung, 0) + " W", 8); 547 lcd.print(fillup(str)); 548 549 lcd.setCursor(0, 2); 550 delay(2); 551 str = "Batterie: "; 552 str += form(ConvSeperator(GeneratorBatterie) + " V", 8); 553 lcd.print(fillup(str)); 554 555 lcd.setCursor(0, 3); 556 delay(2); 557 str = " "; 558 lcd.print(fillup(str)); 559} 560 561void LCD_Temperaturen() { 562 String str; 563 LCD_Head(); 564 lcd.setCursor(0, 1); 565 delay(2); 566 str = "Motor: "; 567 str += form(t_data.MotorTemperatur + " " + (char)dg + "C", 8); 568 lcd.print(fillup(str)); 569 570 lcd.setCursor(0, 2); 571 delay(2); 572 str = "Aussen: "; 573 str += form(t_data.AussenTemperatur + " " + (char)dg + "C", 8); 574 lcd.print(fillup(str)); 575 576 lcd.setCursor(0, 3); 577 delay(2); 578 str = "System: "; 579 str += form(t_data.SysTemperatur + " " + (char)dg + "C", 8); 580 lcd.print(fillup(str)); 581} 582 583void LCD_Infos() { 584 LCD_Head(); 585 586 lcd.setCursor(0, 1); 587 delay(2); 588 lcd.print(fillup((String) "Ver. " + version)); 589 590 lcd.setCursor(0, 2); 591 delay(2); 592 testLink(); 593 if (etherStatus) { 594 lcd.print(fillup("IP " + DisplayAddress(Ethernet.localIP()) + "*")); 595 } else { 596 lcd.print(fillup("IP " + DisplayAddress(Ethernet.localIP()))); 597 } 598 599 lcd.setCursor(0, 3); 600 delay(2); 601 lcd.print(fillup((String) ram + " Bytes RAM free")); 602} 603 604void loop(void) { 605 CheckState(); 606 607 if (MQTTenable) { 608 MQTT.loop(); 609 if (!MQTT.connected()) { 610 MQTTconnect(); 611 } 612 } 613 614 Webserver(); 615 switch (page) { 616 case 1: 617 LCD_Start(); 618 break; 619 case 2: 620 LCD_Verbrauch(); 621 break; 622 case 3: 623 LCD_Leistungen(); 624 break; 625 case 4: 626 LCD_Temperaturen(); 627 break; 628 case 5: 629 LCD_Infos(); 630 break; 631 } 632} 633
config.ini
ini
INI-File
1; INI-Datei fuer den ATS (c) 2019 by Joerg Mahn 2; 3; Wegen der Puffer-Einstellung, darf die maximale Zeilenlaenge 80 Zeichen 4; nicht ueberschreiten! 5; 6 7[Generator] 8; Zeit in Minuten bis Stromausfall akzeptiert wird 9lostmain = 5 10 11; Zeit in Minuten bis nach Strom-Wiederkehr auf 12; Normalbetrieb zurueck geschaltet wird 13backmain = 20 14 15; Vorglueh-Zeit in Sekunden (15) 16glowtime = 15 17 18; Startdauer (x 100ms) (8) 19ignitiontime = 8 20 21; Startversuche (3) 22starttrying = 3 23 24; Wartezeit nach dem Start in Sekunden 25genstartdelay = 8 26 27; Wartezeit nach dem Stopp in Sekunden 28genstoppdelay = 5 29 30; Dauer zwischen den Umschaltungen in Sekunden (2) 31switchdelay = 2 32 33; Minimale Batteriespannung bevor Warnung (20.0) 34minbatvoltage = 20.0 35 36[Network] 37Host = ats 38Domain = webserver.com 39IP = 192.168.100.29 40DNS = 192.168.100.1 41GW = 192.168.100.251 42SUB = 255.255.255.0 43; ntp = Zeitserver, IP oder Hostname 44NTP = ptbtime1.ptb.de 45 46[Mail] 47Server = mail.webserver.com 48To = me@webserver.com 49To_RN = Joerg Mahn 50From = ats@webserver.com 51From_RN = ATS 52 53[Webserver] 54; Webfrontend Vorlagen 55Mail = mail.htm 56ATS = ats.htm 57Config = config.htm 58CSS = ats.css 59 60[HC] 61; Homecontrol 62; Texte werden in der settings.ini (Haussteuerung - Sound) festgelegt. 63enable = true 64Server = home.webserver.com 65Request = GET /sound/index.php? 66Start = 7 67Stop = 8 68Error = 9 69Loss = 10 70Back = 11 71 72[VZ] 73; Volkazaehler 74; Werte werden an die angegebene UUID gepusht. 75enable = true 76Server = vz.webserver.com 77Request = GET /middleware/data/ 78UUID = f4fd4310-e4ee-11e9-9c45-a9ae0b49728e 79 80[MQTT] 81; Zugangsdaten zum Broker und Topic-Settings 82; <Topic>/set zum Konfigurieren 83; <Topic>/get zum Abfragen 84enable = true 85Server = mqtt.webserver.com 86Topic = home/ats 87Username = user 88Password = ******* 89
ats.css
css
Cascading Style Sheets
1body { 2 background-color: #151515; 3 font-family: Helvetica, Arial, Geneva, sans-serif; 4 color: yellow; 5 font-size: 3vmin; 6} 7.hl { 8 font-size: 6vmin; 9 font-weight: bold; 10} 11a { 12 text-decoration: none; 13} 14table#a, td#a { 15 height: 5vmin; 16 width: 80%; 17 table-layout:fixed; 18 text-align: left; 19 border-collapse: collapse; 20 border: 1px solid white; 21 padding: 5px; 22} 23table#b, td#b { 24 height: 5vmin; 25 width: 80%; 26 table-layout:fixed; 27 text-align: center; 28 border-collapse: collapse; 29 border: 1px solid white; 30 padding: 5px; 31} 32 table#c, td#c{ 33 width: 80%; 34 table-layout:fixed; 35 text-align: center; 36 border: none; 37 /*border: 1px solid white;*/ 38 padding: 10px; 39} 40.e { 41 font-size: 5vmin; 42 font-weight: bold; 43} 44.n { 45 font-size: 4vmin; 46 color: lightyellow; 47} 48.v { 49 font-size: 5vmin; 50 color: lightyellow; 51} 52.gn { 53 background-color: #58FA58; 54 color: black; 55} 56.rt { 57 background-color: #FA5858; 58 color: black; 59} 60.gr { 61 /*background-color: #BDBDBD;*/ 62 background-color: lightyellow; 63 color: black; 64} 65.bl { 66 background-color: #5882FA; 67 color: black; 68} 69.ge { 70 background-color: #F4FA58; 71 color: black; 72} 73input[type="submit"], input[type="button"]{ 74 width: 35vmin; 75 font-size: 3vmin; 76 border: none; 77 padding: 20px; 78 text-align: center; 79 display: inline-block; 80} 81input[type="file"]{ 82 width: 68vmin; 83 font-size: 3vmin; 84 border: none; 85 padding: 20px; 86 text-align: center; 87 display: inline-block; 88} 89
functions.ino
arduino
Functions
1/////////////////////////////////////////////////////////////////////////////// 2// functions.ino 3/////////////////////////////////////////////////////////////////////////////// 4 5void GetCurrent(Powermeter *data) { 6 float v = pzem1->voltage(pip1); 7 if (v < 0.0) v = 0.0; 8 float p = pzem1->power(pip1); 9 if (p < 0.0) p = 0.0; 10 float i = pzem1->current(pip1); 11 if (i < 0.0) i = 0.0; 12 data->L1_Spannung = v; 13 data->L1_Strom = i; 14 data->L1_Leistung = p; 15 16 v = pzem2->voltage(pip2); 17 if (v < 0.0) v = 0.0; 18 p = pzem2->power(pip2); 19 if (p < 0.0) p = 0.0; 20 i = pzem2->current(pip2); 21 if (i < 0.0) i = 0.0; 22 data->L2_Spannung = v; 23 data->L2_Strom = i; 24 data->L2_Leistung = p; 25 26 v = pzem3->voltage(pip3); 27 if (v < 0.0) v = 0.0; 28 p = pzem3->power(pip3); 29 if (p < 0.0) p = 0.0; 30 i = pzem3->current(pip3); 31 if (i < 0.0) i = 0.0; 32 data->L3_Spannung = v; 33 data->L3_Strom = i; 34 data->L3_Leistung = p; 35} 36 37void GetTemp(Temperaturen *data) { 38 //Temepraturwerte holen 39 sensors.requestTemperatures(); // Send the command to get temperature readings 40 data->AussenTemperatur = String(sensors.getTempCByIndex(0), 1); 41 data->MotorTemperatur = String(sensors.getTempCByIndex(1), 1); 42 data->SysTemperatur = String(Clock.getTemperature(), 1); // Fragt die Temperatur auf dem RTC ab 43} 44 45 46void testLink() { 47 if (Ethernet.linkStatus() == Unknown) { 48 etherStatus = false; 49 } 50 else if (Ethernet.linkStatus() == LinkON) { 51 etherStatus = true; 52 } 53 else if (Ethernet.linkStatus() == LinkOFF) { 54 etherStatus = false; 55 } 56} 57 58void Link_Gen() { 59 #define on 0xFF 60 #define off 0x20 61 62 testLink(); 63 lcd.setCursor(0, 3); 64 delay(2); 65 66 lcd.print(" LAN"); 67 if (etherStatus) { 68 lcd.write(on); 69 } else { 70 lcd.write(off); 71 } 72 lcd.print(" NETZ"); 73 if (!digitalRead(PIN_PHASE_NETZ)) { 74 lcd.write(on); 75 } else { 76 lcd.write(off); 77 } 78 lcd.print(" GEN"); 79 if (!digitalRead(PIN_PHASE_GEN)) { 80 lcd.write(on); 81 } else { 82 lcd.write(off); 83 } 84 lcd.print(" "); 85} 86 87 88String DisplayAddress(IPAddress address) { 89 return String(address[0]) + "." + 90 String(address[1]) + "." + 91 String(address[2]) + "." + 92 String(address[3]); 93} 94 95String fillup(String str) { 96 str = str.substring(0, (LCD_Cols)); 97 while (str.length() < LCD_Cols) { 98 str = str + " "; 99 } 100 return str; 101} 102 103void SwitchNetzbetrieb() { 104 piep(); 105 LCD_Status(12); 106 switchREL(2, HIGH); 107 switchREL(1, LOW); 108 delay(switchdelay * 1000); 109 switchREL(1, HIGH); 110} 111 112void SwitchGeneratorbetrieb() { 113 piep(); 114 LCD_Status(12); //"Umschaltung" 115 switchREL(1, HIGH); 116 switchREL(2, LOW); 117 delay(switchdelay * 1000); 118 switchREL(2, HIGH); 119} 120 121void switchREL(int i, bool status) { 122 // Releais sind LOW-Active! 123 if (i == 1) { // Netz-Schtz 124 if (digitalRead(REL_GEN)) { 125 digitalWrite(REL_NETZ, status); 126 } 127 } 128 if (i == 2) { // Generator-Schtz 129 if (digitalRead(REL_NETZ)) { 130 digitalWrite(REL_GEN, status); 131 } 132 } 133} 134 135void InterruptButton() { // Menbutton 136 if (millis() - time > debounce) { 137 piep(); 138 page++; 139 if (page > maxPage) { 140 page = 1; 141 } 142 if (page < 1) { 143 page = 1; 144 } 145 // lcd.clear(); 146 } 147 time = millis(); 148 delay(10); 149} 150 151String zero(String str) { 152 if (str.length() < 2) { 153 str = "0" + str; 154 } 155 return str; 156} 157 158String showDate() { 159 return zero(String(Clock.getDate())) + "." + zero(String(Clock.getMonth(Century))) + ".20" + String(Clock.getYear()); 160} 161 162String showTime() { 163 return zero(String(Clock.getHour(h12, PM))) + ":" + zero(String(Clock.getMinute())) + ":" + zero(String(Clock.getSecond())); 164} 165 166void syncTime() { 167 Clock.setClockMode(false); // set to 24h 168 169 // Internetzeit holen und RTC syncen 170 setSyncProvider(getNtpTime); 171 while (timeStatus() == timeNotSet); // wait until the time is set by the sync provider 172 173 Clock.setYear(year() - 2000); 174 Clock.setMonth(month()); 175 Clock.setDate(day()); 176 Clock.setDoW(weekday()); 177 Clock.setHour(hour()); 178 Clock.setMinute(minute()); 179 Clock.setSecond(second()); 180 181 if (sommerzeit(year(), month(), day(), hour(), 1)) { 182 PgmPrintln("Sommerzeit"); 183 Clock.setHour(hour() + 1); 184 if (hour() >= 24) { 185 Clock.setHour(0); 186 Clock.setDate(day() + 1); 187 } 188 } 189} 190 191/*-------- NTP code ----------*/ 192unsigned long getNtpTime() 193{ 194 // IPAddress timeServer(arr_ntp); 195 sendNTPpacket(timeServer); // send an NTP packet to a time server 196 delay(1000); 197 if ( Udp.parsePacket() ) { 198 Udp.read(packetBuffer, NTP_PACKET_SIZE); // read packet into buffer 199 //the timestamp starts at byte 40, convert four bytes into a long integer 200 unsigned long hi = word(packetBuffer[40], packetBuffer[41]); 201 unsigned long low = word(packetBuffer[42], packetBuffer[43]); 202 // this is NTP time (seconds since Jan 1 1900 203 ////unsigned long secsSince1900 = hi << 16 | low; 204 // Unix time starts on Jan 1 1970 205 ////const unsigned long seventyYears = 2208988800UL; 206 ////unsigned long epoch = secsSince1900 - seventyYears; // subtract 70 years 207 ////return epoch; 208 209 unsigned long secsSince1900; 210 secsSince1900 = (unsigned long)packetBuffer[40] << 24; 211 secsSince1900 |= (unsigned long)packetBuffer[41] << 16; 212 secsSince1900 |= (unsigned long)packetBuffer[42] << 8; 213 secsSince1900 |= (unsigned long)packetBuffer[43]; 214 return secsSince1900 - 2208988800UL + timeZone * SECS_PER_HOUR; 215 216 } 217 return 0; // return 0 if unable to get the time 218} 219 220 221// send an NTP request to the time server at the given address 222unsigned long sendNTPpacket(IPAddress address) 223{ 224 memset(packetBuffer, 0, NTP_PACKET_SIZE); // set all bytes in the buffer to 0 225 226 // Initialize values needed to form NTP request 227 packetBuffer[0] = B11100011; // LI, Version, Mode 228 packetBuffer[1] = 0; // Stratum 229 packetBuffer[2] = 6; // Max Interval between messages in seconds 230 packetBuffer[3] = 0xEC; // Clock Precision 231 // bytes 4 - 11 are for Root Delay and Dispersion and were set to 0 by memset 232 packetBuffer[12] = 49; // four-byte reference ID identifying 233 packetBuffer[13] = 0x4E; 234 packetBuffer[14] = 49; 235 packetBuffer[15] = 52; 236 237 // send the packet requesting a timestamp: 238 Udp.beginPacket(address, 123); //NTP requests are to port 123 239 Udp.write(packetBuffer, NTP_PACKET_SIZE); 240 Udp.endPacket(); 241} 242 243byte sendEmail(int sub) { 244 String subject; 245 char buffer[81]; 246 247 //Serial.print(F("Mailserver: "));Serial.println(m_server); 248 249 if (mailclient.connect(m_server, 25)) { 250 PgmPrintln("Sending email"); 251 } else { 252 PgmPrintln("Connection to mailserver failed"); 253 return 0; 254 } 255 256 257 strcpy_P(buffer, (char *)pgm_read_word(&(mail_table[sub]))); 258 subject = (String) buffer; 259 subject.trim(); 260 subject.replace("", "\\xF6"); 261 262 if (!eRcv()) return 0; 263 mailclient.print(F("HELO ")); 264 mailclient.println(DisplayAddress(Ethernet.localIP())); 265 if (!eRcv()) return 0; 266 mailclient.print(F("MAIL From: <")); 267 mailclient.print(m_from); 268 mailclient.println(F(">")); 269 if (!eRcv()) return 0; 270 mailclient.print(F("RCPT To: <")); 271 mailclient.print(m_to); 272 mailclient.println(F(">")); 273 if (!eRcv()) return 0; 274 mailclient.println(F("DATA")); 275 if (!eRcv()) return 0; 276 mailclient.print(F("To: ")); 277 mailclient.print(m_to_rn); 278 mailclient.print(F("<")); 279 mailclient.print(m_to); 280 mailclient.println(F(">")); 281 mailclient.print(F("From: ")); 282 mailclient.print(m_from_rn); 283 mailclient.print(F("<")); 284 mailclient.print(m_from); 285 mailclient.println(F(">")); 286 mailclient.print(F("Subject: ")); 287 mailclient.println(subject); 288 mailclient.println(F("MIME-Version: 1.0")); 289 mailclient.println(F("Content-type: text/html")); 290 ParseContent(&mailclient, Mail_File); 291 mailclient.println(F(".")); 292 if (!eRcv()) return 0; 293 mailclient.println(F("QUIT")); 294 if (!eRcv()) return 0; 295 delay(1); 296 mailclient.stop(); 297 return 1; 298} 299 300byte eRcv() { 301 byte respCode; 302 byte thisByte; 303 int loopCount = 0; 304 while (!mailclient.available()) { 305 delay(1); 306 loopCount++; 307 // if nothing received for 10 seconds, timeout 308 if (loopCount > 10000) { 309 mailclient.stop(); 310 PgmPrintln("\ \ 311Timeout"); 312 return 0; 313 } 314 } 315 respCode = mailclient.peek(); 316 /* 317 while (mailclient.available()) { 318 thisByte = mailclient.read(); 319 Serial.write(thisByte); 320 } 321 */ 322 if (respCode >= '4') { 323 efail(); 324 return 0; 325 } 326 return 1; 327} 328 329void efail() { 330 byte thisByte = 0; 331 int loopCount = 0; 332 mailclient.println(F("QUIT")); 333 while (!mailclient.available()) { 334 delay(1); 335 loopCount++; 336 // if nothing received for 10 seconds, timeout 337 if (loopCount > 10000) { 338 mailclient.stop(); 339 PgmPrintln("\ \ 340Timeout"); 341 return; 342 } 343 } 344 while (mailclient.available()) { 345 thisByte = mailclient.read(); 346 Serial.write(thisByte); 347 } 348 mailclient.stop(); 349 PgmPrintln("disconnected"); 350} 351 352boolean sommerzeit(int s_jahr, byte s_monat, byte s_tag, byte s_stunde, byte s_zeitzone) { 353 if (s_monat < 3 || s_monat > 10) return false; 354 if (s_monat > 3 && s_monat < 10) return true; 355 if (s_monat == 3 && (s_stunde + 24 * s_tag) >= (1 + s_zeitzone + 24 * (31 - (5 * s_jahr / 4 + 4) % 7)) || s_monat == 10 && (s_stunde + 24 * s_tag) < (1 + s_zeitzone + 24 * (31 - (5 * s_jahr / 4 + 1) % 7))) { 356 return true; 357 } else { 358 return false; 359 } 360} 361 362/* 363 void error_P(const char* str) { 364 PgmPrint("error: "); 365 SerialPrintln_P(str); 366 if (card.errorCode()) { 367 PgmPrint("SD error: "); 368 Serial.print(card.errorCode(), HEX); 369 PgmPrintln(","); 370 Serial.println(card.errorData(), HEX); 371 } 372 while (1); 373 } 374*/ 375 376boolean Generator(byte start) { 377 bool running = false; 378 lcd.clear(); 379 LCD_Head(); 380 // Generator Relais sind HIGH-Active! 381 switch (start) { 382 case 1: // OFF - Ausschalten 383 if (!digitalRead(PIN_OEL)) { 384 PgmPrintln("Generator luft nicht.\ \ 385Kein Aktion durchgefhrt."); 386 } else { 387 digitalWrite(PIN_Z_EIN, LOW); 388 PgmPrintln("Generator stoppen"); 389 LCD_Status(16); 390 delay(genstoppdelay * 1000); 391 if (digitalRead(PIN_OEL)) { 392 // if (!digitalRead(PIN_PHASE_GEN)) { 393 running = true; 394 } else { 395 PgmPrintln("Generator gestoppt"); 396 } 397 } 398 break; 399 400 case 2: // ON - Einschalten 401 if (digitalRead(PIN_OEL)) { 402 // if (!digitalRead(PIN_PHASE_GEN)) { 403 running = true; 404 PgmPrintln("Generator luft bereits.\ \ 405Kein Aktion durchgefhrt."); 406 } else { 407 byte i = 1; 408 while (i <= starttrying && !running) { 409 PgmPrintln("Generator starten"); 410 LCD_Status(13); // "Vorglhen" 411 PgmPrintln("Vorglhen"); 412 digitalWrite(PIN_Z_EIN, HIGH); 413 delay(glowtime * 1000); 414 digitalWrite(PIN_Z_START, HIGH); 415 LCD_Status(14); // "Zndung" 416 Serial.print(i); 417 PgmPrintln(". Zndung"); 418 // Ab der zweiten Zndung wird um 100ms lnger gestartet 419 delay((ignitiontime + i - 1) * 100); 420 digitalWrite(PIN_Z_START, LOW); 421 LCD_Status(15); // "Drehzal berprfen" 422 delay(genstartdelay * 1000); 423 // if (!digitalRead(PIN_PHASE_GEN)) { 424 if (digitalRead(PIN_OEL)) { 425 running = true; 426 PgmPrintln("Generator gestartet"); 427 } else { 428 PgmPrintln("Generator Start fehlgeschlagen"); 429 digitalWrite(PIN_Z_EIN, LOW); 430 delay(5000); 431 } 432 i++; 433 } 434 } 435 break; 436 } 437 return running; 438} 439 440void Print_Status(byte stat) { 441 char buffer[21]; 442 strcpy_P(buffer, (char *)pgm_read_word(&(status_table[stat]))); 443 Serial.println(buffer); 444} 445 446String Web_Status(byte stat) { 447 String temp_str; 448 char buffer[21]; 449 strcpy_P(buffer, (char *)pgm_read_word(&(status_table[stat]))); 450 temp_str = (String) buffer; 451 while (temp_str.endsWith(" ")) { 452 temp_str.remove(temp_str.length() - 1); 453 } 454 temp_str.replace("", "ö"); 455 temp_str.replace("", "ü"); 456 return temp_str; 457} 458 459void LCD_Status(byte stat) { 460 String temp_str; 461 char buffer[21]; 462 int offset; 463 strcpy_P(buffer, (char *)pgm_read_word(&(status_table[stat]))); 464 temp_str = (String) buffer; 465 466 while (temp_str.endsWith(" ")) { 467 temp_str.remove(temp_str.length() - 1); 468 } 469 470 if (timeout > 0) { 471 temp_str = temp_str + " in " + String (timeout); 472 } 473 474 temp_str.replace("", "\\xEF"); 475 temp_str.replace("", "\\xF5"); 476 temp_str.replace("", "\\xE1"); 477 bool vorne = false; 478 while (temp_str.length() < 20) { 479 if (vorne) { 480 temp_str = " " + temp_str; 481 } else { 482 temp_str = temp_str + " "; 483 } 484 vorne = !vorne; 485 } 486 487 lcd.setCursor(0, 2); 488 delay(2); 489 //lcd.print(fillup(temp_str)); 490 lcd.print(temp_str); 491} 492 493void LCD_Head() { 494 lcd.setCursor(0, 0); 495 delay(2); 496 lcd.print(fillup(lcdHead)); 497} 498 499void Char2IP(char* str) { 500 char *ptr; 501 char delimiter[] = "."; 502 ptr = strtok(str, delimiter); 503 byte_array[0] = byte(atoi(ptr)); 504 ptr = strtok(NULL, delimiter); 505 byte_array[1] = byte(atoi(ptr)); 506 ptr = strtok(NULL, delimiter); 507 byte_array[2] = byte(atoi(ptr)); 508 ptr = strtok(NULL, delimiter); 509 byte_array[3] = byte(atoi(ptr)); 510} 511 512void printErrorMessage(uint8_t e, bool eol = true) // INI-File 513{ 514 switch (e) { 515 case IniFile::errorNoError: 516 PgmPrintln("no error"); 517 break; 518 case IniFile::errorFileNotFound: 519 PgmPrintln("file not found"); 520 break; 521 case IniFile::errorFileNotOpen: 522 PgmPrintln("file not open"); 523 break; 524 case IniFile::errorBufferTooSmall: 525 PgmPrintln("buffer too small"); 526 break; 527 case IniFile::errorSeekError: 528 PgmPrintln("seek error"); 529 break; 530 case IniFile::errorSectionNotFound: 531 PgmPrintln("section not found"); 532 break; 533 case IniFile::errorKeyNotFound: 534 PgmPrintln("key not found"); 535 break; 536 case IniFile::errorEndOfFile: 537 PgmPrintln("end of file"); 538 break; 539 case IniFile::errorUnknownError: 540 PgmPrintln("unknown error"); 541 break; 542 default: 543 PgmPrintln("unknown error value"); 544 break; 545 } 546 if (eol) 547 PgmPrintln(""); 548} 549 550void ReadIniFile() { 551 552 IniFile ini(configFile); 553 if (!ini.open()) { 554 PgmPrintln("Ini file "); 555 Serial.print(configFile); 556 PgmPrintln(" does not exist"); 557 // Cannot do anything else 558 LCD_Status(17); 559 560 while (1) 561 ; 562 } 563 PgmPrintln("Ini file found"); 564 565 // Check the file is valid. This can be used to warn if any lines 566 // are longer than the buffer. 567 if (!ini.validate(buffer, bufferLen)) { 568 PgmPrintln("ini file "); 569 Serial.print(ini.getFilename()); 570 PgmPrint(" not valid: "); 571 printErrorMessage(ini.getError()); 572 // Cannot do anything else 573 LCD_Status(17); 574 while (1) 575 ; 576 } 577 578 if (ini.getValue("Generator", "lostmain", buffer, bufferLen)) { 579 lostmain = int(atoi(buffer)); 580 } 581 if (ini.getValue("Generator", "backmain", buffer, bufferLen)) { 582 backmain = int(atoi(buffer)); 583 } 584 if (ini.getValue("Generator", "glowtime", buffer, bufferLen)) { 585 glowtime = int(atoi(buffer)); 586 } 587 if (ini.getValue("Generator", "ignitiontime", buffer, bufferLen)) { 588 ignitiontime = int(atoi(buffer)); 589 } 590 if (ini.getValue("Generator", "starttrying", buffer, bufferLen)) { 591 starttrying = int(atoi(buffer)); 592 } 593 if (ini.getValue("Generator", "genstartdelay", buffer, bufferLen)) { 594 genstartdelay = int(atoi(buffer)); 595 } 596 if (ini.getValue("Generator", "genstoppdelay", buffer, bufferLen)) { 597 genstoppdelay = int(atoi(buffer)); 598 } 599 if (ini.getValue("Generator", "switchdelay", buffer, bufferLen)) { 600 switchdelay = int(atoi(buffer)); 601 } 602 if (ini.getValue("Generator", "minbatvoltage", buffer, bufferLen)) { 603 minbatvoltage = float(atof(buffer)); 604 } 605 606 if (ini.getValue("Network", "Host", buffer, bufferLen)) { 607 strcpy(host,buffer); 608 } 609 if (ini.getValue("Network", "Domain", buffer, bufferLen)) { 610 strcpy(domain,buffer); 611 } 612 if (ini.getValue("Network", "IP", buffer, bufferLen)) { 613 Char2IP(buffer); 614 for (int i = 0; i < 4; i++) { 615 ip[i] = byte_array[i]; 616 } 617 } 618 if (ini.getValue("Network", "DNS", buffer, bufferLen)) { 619 Char2IP(buffer); 620 for (int i = 0; i < 4; i++) { 621 dns[i] = byte_array[i]; 622 } 623 } 624 if (ini.getValue("Network", "GW", buffer, bufferLen)) { 625 Char2IP(buffer); 626 for (int i = 0; i < 4; i++) { 627 gateway[i] = byte_array[i]; 628 } 629 } 630 if (ini.getValue("Network", "SUB", buffer, bufferLen)) { 631 Char2IP(buffer); 632 for (int i = 0; i < 4; i++) { 633 subnet[i] = byte_array[i]; 634 } 635 } 636 if (ini.getValue("Network", "NTP", buffer, bufferLen)) { 637 strcpy(ntp,buffer); 638 } 639 640 if (ini.getValue("Mail", "Server", buffer, bufferLen)) { 641 strcpy(m_server, buffer); 642 } 643 if (ini.getValue("Mail", "From", buffer, bufferLen)) { 644 m_from = (String) buffer; 645 } 646 if (ini.getValue("Mail", "To", buffer, bufferLen)) { 647 m_to = (String) buffer; 648 } 649 if (ini.getValue("Mail", "To_RN", buffer, bufferLen)) { 650 m_to_rn = (String) buffer; 651 } 652 if (ini.getValue("Mail", "From_RN", buffer, bufferLen)) { 653 m_from_rn = (String) buffer; 654 } 655 656 if (ini.getValue("Webserver", "Mail", buffer, bufferLen)) { 657 strcpy(Mail_File, buffer); 658 } 659 if (ini.getValue("Webserver", "ATS", buffer, bufferLen)) { 660 strcpy(ATS_File, buffer); 661 } 662 if (ini.getValue("Webserver", "Config", buffer, bufferLen)) { 663 strcpy(Config_File, buffer); 664 } 665 if (ini.getValue("Webserver", "CSS", buffer, bufferLen)) { 666 strcpy(CSS_File, buffer); 667 } 668 669 bool found = ini.getValue("HC", "enable", buffer, bufferLen, HCenable); 670 671 if (ini.getValue("HC", "Server", buffer, bufferLen)) { 672 strcpy(HCServer, buffer); 673 } 674 if (ini.getValue("HC", "Request", buffer, bufferLen)) { 675 strcpy(HCRequest, buffer); 676 } 677 if (ini.getValue("HC", "Start", buffer, bufferLen)) { 678 HCStart = int(atoi(buffer)); 679 } 680 if (ini.getValue("HC", "Stop", buffer, bufferLen)) { 681 HCStop = int(atoi(buffer)); 682 } 683 if (ini.getValue("HC", "Error", buffer, bufferLen)) { 684 HCError = int(atoi(buffer)); 685 } 686 if (ini.getValue("HC", "Loss", buffer, bufferLen)) { 687 HCLoss = int(atoi(buffer)); 688 } 689 if (ini.getValue("HC", "Back", buffer, bufferLen)) { 690 HCBack = int(atoi(buffer)); 691 } 692 693 found = ini.getValue("VZ", "enable", buffer, bufferLen, VZenable); 694 695 if (ini.getValue("VZ", "Server", buffer, bufferLen)) { 696 strcpy(VZServer, buffer); 697 } 698 if (ini.getValue("VZ", "Request", buffer, bufferLen)) { 699 strcpy(VZRequest, buffer); 700 } 701 if (ini.getValue("VZ", "UUID", buffer, bufferLen)) { 702 strcpy(UUID, buffer); 703 } 704 705 found = ini.getValue("MQTT", "enable", buffer, bufferLen, MQTTenable); 706 707 if (ini.getValue("MQTT", "Server", buffer, bufferLen)) { 708 strcpy(MQTTServer, buffer); 709 } 710 if (ini.getValue("MQTT", "Topic", buffer, bufferLen)) { 711 strcpy(MQTTTopic, buffer); 712 } 713 if (ini.getValue("MQTT", "Username", buffer, bufferLen)) { 714 strcpy(MQTTUsername, buffer); 715 } 716 if (ini.getValue("MQTT", "Password", buffer, bufferLen)) { 717 strcpy(MQTTPassword, buffer); 718 } 719 720} 721 722void piep() { 723 digitalWrite(PIN_BUZZER, HIGH); 724 delay(100); 725 digitalWrite(PIN_BUZZER, LOW); 726} 727 728String form(String str, int c) { 729 while (str.length() < c) { 730 str = " " + str; 731 } 732 return str; 733} 734 735float GetBatteryVoltage() { 736 float vout = 0.0; 737 float vin = 0.0; 738 float R1 = 99600.0; 739 // float R1 = 100000.0; // resistance of R1 (100K) 740 float R2 = 10015.0; 741 // float R2 = 10000.0; // resistance of R2 (10K) 742 int value = 0; 743 value = analogRead(BAT_INPUT); 744 vout = (value * 5.0) / 1024.0; 745 vin = vout / (R2 / (R1 + R2)); 746 if (vin < 0.09) { 747 vin = 0.0; //statement to quash undesired reading ! 748 } 749 return vin; 750} 751 752String ConvSeperator(String str) { 753 str.replace(".", ","); 754 return str; 755} 756 757void softReset() { 758 asm volatile (" jmp 0"); 759} 760 761void Alert(char* server, char* request, byte message) { 762 if (HCenable) { 763 unsigned long byteCount = 0; 764 EthernetClient client; 765 766 if (client.connect(server, 80)) { 767 client.print(request); 768 client.print(message); 769 client.println(F(" HTTP/1.1")); 770 client.print(F("Host: ")); 771 client.println(server); 772 client.println(F("Connection: close")); 773 client.println(); 774 delay(1); 775 client.stop(); 776 } else { 777 Serial.print(F("Connection to ")); 778 Serial.print(server); 779 Serial.println(F(" failed!")); 780 } 781 } 782} 783 784// call back for file timestamps 785void dateTime(uint16_t* date, uint16_t* time) { 786 *date = FAT_DATE(Clock.getYear()+2000, Clock.getMonth(Century), Clock.getDate()); 787 *time = FAT_TIME(Clock.getHour(h12, PM), Clock.getMinute(), Clock.getSecond()); 788} 789 790void PushVZ(char* server, char* request, char* uuid, float wert) { 791 if (VZenable) { 792 EthernetClient client; 793 char w; 794 if (client.connect(server, 80)) { 795 client.print(request); 796 client.print(uuid); 797 client.print(F(".json?operation=add&value=")); 798 client.print((int) wert); 799 client.println(F(" HTTP/1.1")); 800 client.print(F("Host: ")); 801 client.println(server); 802 client.println(F("Connection: close")); 803 client.println(); 804 delay(10); 805 client.stop(); 806 } else { 807 Serial.print(F("Connection to ")); 808 Serial.print(server); 809 Serial.println(F(" failed!")); 810 } 811 } 812} 813 814// MQTT Callback 815void MQTTmessageReceived(String &topic, String &payload) { 816 817 Serial.println("incoming: " + topic + " - " + payload); 818 819 // Reset 820 strcpy_P(buffer, (char *)pgm_read_word(&(mqtt_table[0]))); 821 if (topic == MQTTTopic + (String) buffer && payload == "true") { 822 PgmPrintln("Anforderung per MQTT zum Reset"); 823 sendEmail(16); 824 softReset(); 825 } 826 827 // Betrieb (netz) 828 strcpy_P(buffer, (char *)pgm_read_word(&(mqtt_table[1]))); 829 if (topic == MQTTTopic + (String) buffer && payload == "netz") { 830 PgmPrintln("Anforderung per NQTT zum Netzbetrieb"); 831 Status = 0; // "Netzbetrieb" 832 Alert(HCServer, HCRequest, HCStop); 833 if (!Generator(OFF)) { 834 SwitchNetzbetrieb(); 835 sendEmail(2); 836 } else { 837 Status = 4; // "Strung Manuell" 838 sendEmail(3); 839 } 840 Print_Status[Status]; 841 } 842 843 // Betrieb (generator) 844 strcpy_P(buffer, (char *)pgm_read_word(&(mqtt_table[1]))); 845 if (topic == MQTTTopic + (String) buffer && payload == "generator") { 846 PgmPrintln("Anforderung per MQTT zum Generatorbetrieb"); 847 Status = 2; // "Generatorbetrieb" 848 Alert(HCServer, HCRequest, HCStop); 849 if (!Generator(OFF)) { 850 SwitchNetzbetrieb(); 851 sendEmail(2); 852 } else { 853 Status = 4; // "Strung Manuell" 854 sendEmail(3); 855 } 856 Print_Status[Status]; 857 } 858 859 strcpy_P(buffer, (char *)pgm_read_word(&(mqtt_table[2]))); 860 if (topic == MQTTTopic + (String) buffer && payload == "send") { 861 PgmPrintln("Anforderung per MQTT zum Status-Mail-Versand"); 862 sendEmail(14); 863 } 864 865 866 // Generator start 867 strcpy_P(buffer, (char *)pgm_read_word(&(mqtt_table[3]))); 868 if (topic == MQTTTopic + (String) buffer && payload == "start") { 869 PgmPrintln("Anforderung per MQTT zum Generatorstart"); 870 Alert(HCServer, HCRequest, HCStart); 871 if (Generator(ON)) { 872 Status = 18; // "Generator luft" 873 sendEmail(4); 874 } else { 875 Status = 4; // "Strung Manuell" 876 Alert(HCServer, HCRequest, HCError); 877 sendEmail(5); 878 } 879 Print_Status[Status]; 880 } 881 882 // Generator stop 883 strcpy_P(buffer, (char *)pgm_read_word(&(mqtt_table[3]))); 884 if (topic == MQTTTopic + (String) buffer && payload == "stop") { 885 PgmPrintln("Anforderung per MQTT zum Generatorstopp"); 886 Alert(HCServer, HCRequest, HCStop); 887 if (!Generator(OFF)) { 888 Status = 0; // "Netzbetrieb" 889 sendEmail(6); 890 } else { 891 Status = 4; // Strung Manuell 892 sendEmail(7); 893 } 894 Print_Status[Status]; 895 } 896} 897
ats.htm
html
Main Web Document
1<html><head> 2 <title>ATS</title> 3 <link rel="shortcut icon" type="image/x-icon" href="http://webserver.com/favicon.ico"> 4 <meta name="referrer" content="no-referrer" /> 5 <meta http-equiv="refresh" content="10; URL=http://ats.webserver.com"> 6</head><body><center> 7 <div class="hl">Automatic-Transfer-Switch</div> 8 <div class="h2">Version %ver% (c) 2019 by Jörg Mahn</div><br> 9 <table id="a"> 10 <tr><td id="a"><font class="e">Status:</font></td><td id="a"><font class="v">%sta%</font></td></tr> 11 <tr><td id="a"><font class="e">Generator:</font></td><td id="a"><font class="v">%gen%</font></td></tr> 12 <tr><td id="a"><font class="e">Zeit:</font></td><td id="a"><font class="v">%d% %z%</font></td></tr> 13 <tr><td id="a"><font class="e">RAM:</font></td><td id="a"><font class="v">%ram% Bytes frei</font></td></tr> 14 <tr><td id="a"><font class="e">ATS:</font></td><td id="a"><font class="v">%sys% °C</font></td></tr> 15 <tr><td id="a"><font class="e">Halle:</font></td><td id="a"><font class="v">%aut% °C</font></td></tr> 16 <tr><td id="a"><font class="e">Motor:</font></td><td id="a"><font class="v">%mot% °C</font></td></tr> 17 <tr><td id="a"><font class="e">Batterie:</font></td><td id="a"><font class="v">%bat% V</font></td></tr> 18 <tr><td id="a"><font class="e">Leistung:</font></td><td id="a"><font class="v">%p%</font></td></tr> 19 </table><br> 20 <table id="b"> 21 <tr><td id="b"><font class="e">L1</font></td><td id="b"><font class="e">L2</font></td><td id="b"><font class="e">L3</font></td></tr> 22 <tr><td id="b"><font class="v">%1v% V</font></td><td id="b"><font class="v">%2v% V</font></td><td id="b"><font class="v">%3v% V</font></td></tr> 23 <tr><td id="b"><font class="v">%1c% A</font></td><td id="b"><font class="v">%2c% A</font></td><td id="b"><font class="v">%3c% A</font></td></tr> 24 </table><br> 25 <form method="get" name="ats"> 26 <table id="c"> 27 <tr><td id="c"><input type="submit" class="gr" name="refresh" value="Aktualisieren"></td> 28 <td id="c"><input type="submit" class="gr" name="sendmail" value="EMail senden"></td></tr> 29 <tr><td id="c"><input type="submit" class="gr" name="config" value="Konfiguration"></td> 30 <td id="c"><input type="submit" class="ge" name="reset" value="System Reset"></td></tr> 31 <tr><td id="c"><input type="submit" class="gr" name="genstop" value="Generator stoppen"></td> 32 <td id="c"><input type="submit" class="bl" name="genstart" value="Generator starten"></td></tr> 33 <tr><td id="c"><input type="submit" class="gn" name="mainbet" value="Netzbetrieb"></td> 34 <td id="c"><input type="submit" class="rt" name="genbet" value="Generatorbetrieb"></td></tr> 35 </table> 36 </form> 37</center></body></html> 38
D_webserver.ino
arduino
Webserver & Parser
1void Webserver() { 2 String readString = ""; 3 char c; 4 char br[5] = "<br>"; 5 char dp[3] = ": "; 6 7 EthernetClient client = server.available(); 8 if (client) { 9 10 11 // an http request ends with a blank line 12 boolean currentLineIsBlank = true; 13 while (client.connected()) { 14 15 if (client.available()) { 16 c = client.read(); 17 18 readString += c; 19 20 if (c == '\n' && currentLineIsBlank) { 21 22 // Datei Upload 23 if (readString.indexOf("multipart/form-data;") > 0) { 24 25 readString = ""; 26 currentLineIsBlank = true; 27 while (client.connected()) { 28 29 if (client.available()) { 30 char w = client.read(); 31 readString += w; 32 33 if (w == '\n' && currentLineIsBlank) { 34 // Dateiname extrahieren, Datei anlegen 35 int a = readString.indexOf("filename=") + 10; 36 readString = readString.substring(a); 37 a = readString.indexOf("\\""); 38 readString.remove(a); 39 if (SD.exists(readString)) { 40 Serial.print(F("Upload: ")); Serial.print(readString); Serial.println(F(" ist bereits vorhanden, wird berschrieben.")); 41 SD.remove(readString); 42 } 43 sdFile = SD.open(readString, FILE_WRITE); 44 int i = 0; 45 46 // stay in this loop until the file has been received 47 while (client.connected()) { 48 49 if (client.available()) { 50 w = client.read(); // get file byte 51 52 if (w == 0x2D) { // 1. 53 w = client.read(); 54 if (w == 0x2D) { // 2. 55 w = client.read(); 56 if (w == 0x2D) { // 3. 57 w = client.read(); 58 if (w == 0x2D) { // 4. 59 w = client.read(); 60 if (w == 0x2D) { // 5. 61 w = client.read(); 62 if (w == 0x2D) { // 6. 63 sdFile.close(); 64 if (SD.exists(readString)) { 65 Serial.print(F("Upload: ")); 66 Serial.print(readString); 67 Serial.println(F(" OK")); 68 } else { 69 Serial.print(F("Upload: ")); 70 Serial.print(readString); 71 Serial.println(F(" Fehlgeschlagen")); 72 } 73 goto Configuration; 74 //client.stop(); 75 //break; 76 } else { 77 sdFile.print("-"); 78 sdFile.print("-"); 79 sdFile.print("-"); 80 sdFile.print("-"); 81 sdFile.print("-"); 82 sdFile.print(w); 83 } 84 } else { 85 sdFile.print("-"); 86 sdFile.print("-"); 87 sdFile.print("-"); 88 sdFile.print("-"); 89 sdFile.print(w); 90 } 91 } else { 92 sdFile.print("-"); 93 sdFile.print("-"); 94 sdFile.print("-"); 95 sdFile.print(w); 96 } 97 } else { 98 sdFile.print("-"); 99 sdFile.print("-"); 100 sdFile.print(w); 101 } 102 } else { 103 sdFile.print("-"); 104 sdFile.print(w); 105 } 106 } else { 107 sdFile.print(w); 108 } 109 } 110 } 111 } 112 // detect the end of the incoming HTTP header 113 if (w == '\n') { 114 // starting a new line 115 currentLineIsBlank = true; 116 } 117 else if (w != '\r') { 118 // got a character on the current line 119 currentLineIsBlank = false; 120 } 121 } 122 } 123 } 124 125 126 // Download von Dateien von der SD-Karte 127 if (readString.indexOf("?download") > 0 ) { 128 int a = readString.indexOf("?download") + 10; 129 int b = readString.indexOf(" HTTP/"); 130 readString = readString.substring(a, b); 131 client.println(F("HTTP/1.1 200 OK")); 132 client.println(F("Content-Type: text/html")); 133 client.println(); 134 client.println(F("<!DOCTYPE html>")); 135 client.println(F("<html>")); 136 client.println(F("<head>")); 137 client.print(F("<title>ATS-Konfiguration (")); client.print(readString); client.println(F(")</title>")); 138 client.println(F("<meta name=\\"referrer\\" content=\\"no-referrer\\" />")); 139 client.println(F("</head><body><pre>")); 140 readString.toUpperCase(); 141 sdFile = SD.open(readString); 142 if (!sdFile) { 143 client.println(F("<h1>File not Found!</h1>")); 144 Serial.println(F("Download: ")); Serial.print(readString); Serial.println(F(" nicht gefunden!")); 145 client.stop(); 146 break; 147 } else { 148 Serial.print(F("Download: ")); Serial.println(readString); 149 while (sdFile.available()) { 150 int x = sdFile.read(); 151 if (x == 60) client.print("<"); 152 if (x == 62) client.print(">"); 153 if (x != 60 && x != 62) client.print(char(x)); 154 } 155 sdFile.close(); 156 } 157 client.println(F("</pre></body></html>")); 158 client.stop(); 159 break; 160 } 161 162 // Reboot Arduino 163 if (readString.indexOf("?reset") > 0 ) { 164 PgmPrintln("Anforderung per Webfrontend zum Reset."); 165 sendEmail(16); 166 client.println(F("HTTP/1.1 200 OK")); 167 client.println(F("Content-Type: text/html")); 168 client.println(); 169 client.print(F("<!DOCTYPE html><html><head><title>ATS</title><meta http-equiv=\\"refresh\\" content=\\"10; URL=http://")); 170 client.print(host); client.print(F(".")); client.print(domain); 171 client.print(F("\\"><meta name=\\"referrer\\" content=\\"no-referrer\\" /></head><body><h1>Rebooting...</h1></body></html>")); 172 delay(1); 173 client.stop(); 174 delay(2000); 175 softReset(); 176 break; 177 } 178 179 // Datei von SD-Karte lschen 180 if (readString.indexOf("?deletefile") > 0 ) { 181 //Serial.print(readString); 182 int a = readString.indexOf("?deletefile") + 12; 183 int b = readString.indexOf("&"); 184 int c = readString.indexOf(" HTTP"); 185 String filename = readString.substring(a, b); 186 187 if (readString.substring(b + 1, c) == "delete=OK") { 188 filename.toUpperCase(); 189 if (filename != "CONFIG.INI") { 190 if (SD.exists(filename)) { 191 SD.remove(filename); 192 if (!SD.exists(filename)) { 193 Serial.print(F("Delete: ")); Serial.print(filename); Serial.println(F(" OK")); 194 } else { 195 Serial.print(F("Delete: ")); Serial.print(filename); Serial.println(F(" Fehlgeschlagen")); 196 } 197 } else { 198 Serial.println(F("Delete: ")); Serial.print(filename); Serial.println(F(" nicht gefunden!")); 199 } 200 } else { 201 Serial.println(F("Delete: config.ini darf nicht gelscht werden!")); 202 } 203 } 204 goto Configuration; 205 break; 206 } 207 208 // Datei lschen / Sicherheitsabfrage 209 if (readString.indexOf("?askdelete") > 0 ) { 210 int a = readString.indexOf("?askdelete") + 11; 211 int b = readString.indexOf(" HTTP/"); 212 readString = readString.substring(a, b); 213 client.println(F("HTTP/1.1 200 OK")); 214 client.println(F("Content-Type: text/html")); 215 client.println(); 216 client.print(F("<!DOCTYPE html><html><head><title>ATS-Konfiguration</title>")); 217 client.print(F("<meta name=\\"referrer\\" content=\\"no-referrer\\" /></head><style>")); 218 client.print(F("table {background-color: #D8D8D8;border-collapse: collapse;border: none;}")); 219 client.print(F("thead {background-color: #DF0101;}")); 220 client.print(F("input[type=submit] { padding:15px 15px; background:#ccc; border:0 none; cursor:pointer; -webkit-border-radius: 5px; border-radius: 5px; }")); 221 client.print(F("td, th {text-align: center;padding: 0.5em 1em;}</style><body>")); 222 client.print(F("<form method=\\"get\\" name=\\"ats\\">")); 223 client.print(F("<input type=\\"hidden\\" name=\\"deletefile\\" value=\\"")); 224 client.print(readString); 225 client.print(F("\\">")); 226 client.print(F("<table>")); 227 client.print(F("<thead><tr><th colspan=\\"2\\"><h1><font face=\\"verdana\\" color=\\"white\\">Achtung!</font></h1></th><thead></tr>")); 228 client.print(F("<tbody><tr><td colspan=\\"2\\"><h2><font face=\\"verdana\\">Soll ")); client.print(readString); client.print(F(" wirklich gelöscht werden?</font></h2></td></tr></tbody>")); 229 client.print(F("<tbody><tr>")); 230 client.print(F("<td><input type=\\"submit\\" name=\\"delete\\" value=\\"OK\\"></td>")); 231 client.print(F("<td><input type=\\"submit\\" name=\\"delete\\" value=\\"Cancel\\"></td>")); 232 client.print(F("</tr></tbody></table></form>")); 233 client.print(F("</body></html>")); 234 delay(1); 235 client.stop(); 236 break; 237 } 238 239 // Konfiguration anzeigen 240 if (readString.indexOf("?config") > 0 ) { 241Configuration: 242 client.println(F("HTTP/1.1 200 OK")); 243 client.println(F("Content-Type: text/html")); 244 client.println(); 245 client.println(F("<!DOCTYPE html>")); 246 client.println(F("<style>")); 247 DeliverContent(&client, CSS_File); 248 client.println(F("</style>")); 249 ParseContent(&client, Config_File); 250 break; 251 } 252 253 // Notfall Formular um Dateien hoch zu laden 254 if (readString.indexOf("?upload") > 0 ) { 255 client.println(F("HTTP/1.1 200 OK")); 256 client.println(F("Content-Type: text/html")); 257 client.println(); 258 client.print(F("<!DOCTYPE html><html><head><title>ATS</title><meta name=\\"referrer\\" content=\\"no-referrer\\" /></head><body><h1>Datei auf SD-Karte speichern</h1></body></html>")); 259 client.print(F("<form method=\\"post\\" enctype=\\"multipart/form-data\\">")); 260 client.print(F("<input type=\\"button\\" value=\\"Zurück\\" onclick=\\"window.location.href='http://")); 261 client.print(host); client.print(F(".")); client.print(domain); 262 client.print(F("'\\" /> ")); 263 client.print(F("<input type=\\"file\\" name=\\"datei\\" accept=\\"text/*\\"><input class=\\"button\\" type=\\"submit\\" value=\\"Upload\\"> ")); 264 client.print(F("<input type=\\"button\\" value=\\"Reboot\\" onclick=\\"window.location.href='http://")); 265 client.print(host); client.print(F(".")); client.print(domain); 266 client.print(F("/?reset'\\" /> ")); 267 client.print(F("</form></body></html>")); 268 delay(1); 269 client.stop(); 270 break; 271 } 272 273 if (readString.indexOf("?power") > 0 ) { // Abfrage der aktuellen Leistung 274 client.println(F("HTTP/1.1 200 OK")); 275 client.println(F("Content-Type: text/plain")); 276 client.println(); 277 client.println(ConvSeperator(StrLeistung)); 278 delay(1); 279 client.stop(); 280 break; 281 } 282 283 if (readString.indexOf("?mainbet") > 0 ) { // Netzbetrieb 284 PgmPrintln("Anforderung per Webfrontend zum Netzbetrieb"); 285 Status = 0; // "Netzbetrieb" 286 Alert(HCServer, HCRequest, HCStop); 287 if (!Generator(OFF)) { 288 SwitchNetzbetrieb(); 289 sendEmail(2); 290 } else { 291 Status = 4; // "Strung Manuell" 292 sendEmail(3); 293 } 294 Print_Status[Status]; 295 } 296 297 if (readString.indexOf("?genbet") > 0 ) { // Generatorbetrieb, Stromausfall simulieren 298 PgmPrintln("Anforderung per Webfrontend zum Generatorbetrieb"); 299 Status = 2; // Manueller Betrieb 300 Alert(HCServer, HCRequest, HCStart); 301 if (Generator(ON)) { 302 SwitchGeneratorbetrieb(); 303 sendEmail(0); 304 } else { 305 Status = 4; // "Strung Manuell" 306 Alert(HCServer, HCRequest, HCError); 307 sendEmail(1); 308 } 309 Print_Status[Status]; 310 } 311 312 if (readString.indexOf("?genstart") > 0 ) { // Generator starten 313 PgmPrintln("Anforderung per Webfrontend zum Generatorstart"); 314 Alert(HCServer, HCRequest, HCStart); 315 if (Generator(ON)) { 316 Status = 18; // "Generator luft" 317 sendEmail(4); 318 } else { 319 Status = 4; // "Strung Manuell" 320 Alert(HCServer, HCRequest, HCError); 321 sendEmail(5); 322 } 323 Print_Status[Status]; 324 } 325 326 if (readString.indexOf("?genstop") > 0 ) { // Generator stoppen 327 PgmPrintln("Anforderung per Webfrontend zum Generatorstopp"); 328 Alert(HCServer, HCRequest, HCStop); 329 if (!Generator(OFF)) { 330 Status = 0; // "Netzbetrieb" 331 sendEmail(6); 332 } else { 333 Status = 4; // Strung Manuell 334 sendEmail(7); 335 } 336 Print_Status[Status]; 337 } 338 339 if (readString.indexOf("?sendmail") > 0 ) { // Status-Seite als E-Mail versenden 340 PgmPrintln("Anforderung per Webfrontend zum Status-Mail-Versand"); 341 sendEmail(14); 342 } 343 344 // HTTP-Request lschen um Speicher frei zu geben. 345 readString = ""; 346 347 // Webseite an Client ausliefern 348 client.println(F("HTTP/1.1 200 OK")); 349 client.println(F("Content-Type: text/html")); 350 client.println(); 351 client.println(F("<!DOCTYPE html>")); 352 client.println(F("<style>")); 353 DeliverContent(&client, CSS_File); 354 client.println(F("</style>")); 355 ParseContent(&client, ATS_File); 356 357 break; 358 } 359 if (c == '\n') { 360 // you're starting a new line 361 currentLineIsBlank = true; 362 } else if (c != '\r') { 363 // you've gotten a character on the current line 364 currentLineIsBlank = false; 365 } 366 } 367 } 368 delay(1); 369 client.stop(); 370 } 371} 372 373 374void DeliverSDRoot(EthernetClient *client) { 375 File root; 376 root = SD.open("/"); 377 while (true) { 378 File entry = root.openNextFile(); 379 if (! entry) { // no more files 380 break; 381 } 382 if (!entry.isDirectory()) { 383 client->print(F("<tr><td id=\\"a\\">")); 384 String filename = String(entry.name()); 385 filename.toLowerCase(); 386 client->print(F("<a href=\\"http://")); 387 client->print(host); client->print(F(".")); client->print(domain); 388 client->print(F("/?download=")); 389 client->print(filename); 390 client->print(F("\\"><font class=\\"n\\">")); 391 client->print(filename); 392 client->print(F("</font></a>")); 393 client->print(F("</td><td id=\\"a\\"><font class=\\"n\\">")); 394 client->print(entry.size(), DEC); 395 client->print(F("</font></td><td id=\\"a\\">")); 396 client->print(F("<a href=\\"http://")); 397 client->print(host); client->print(F(".")); client->print(domain); 398 client->print(F("/?askdelete=")); 399 client->print(filename); 400 if (filename == "config.ini") { 401 client->print(F("\\"><font class=\\"n\\">")); 402 } else { 403 client->print(F("\\"><font class=\\"n\\">X")); 404 } 405 client->print(F("</font></a></td>")); 406 client->println(F("</tr>")); 407 } 408 entry.close(); 409 } 410 delay(1); 411} 412 413void DeliverContent(EthernetClient *client, char *filename) { 414 char c; 415 char temp[200] = {}; 416 int i = 0; 417 418 sdFile = SD.open(filename); 419 if (!sdFile) { 420 Serial.println(F("DeliverContent")); 421 Serial.print(filename); Serial.println(F(" nicht gefunden!")); 422 return false; 423 } 424 while (sdFile.available()) { 425 c = sdFile.read(); 426 if ((c == '\n')) { // Zeile fertig eingelesen 427 int len = strlen(temp); 428 temp[len] = '\\0'; 429 client->print(temp); // ... und an Webclient ausliefern 430 i = 0; 431 memset(temp, '\\0', sizeof(temp)); 432 } else { 433 temp[i] = c; 434 i++; 435 } 436 } 437 sdFile.close(); 438} 439 440void ParseContent(EthernetClient *client, char *filename) { 441 char c; 442 char temp[200] = {}; 443 String strLine = ""; 444 int i = 0; 445 446 // Ist die Datei berhaupt da? 447 sdFile = SD.open(filename); 448 if (!sdFile) { 449 Serial.println(F("ParseWebContent")); 450 Serial.print(filename); Serial.println(F(" nicht gefunden!")); 451 return false; 452 } 453 454 while (sdFile.available()) { 455 c = sdFile.read(); 456 if ((c == '\n')) { // Zeile fertig eingelesen 457 int len = strlen(temp); 458 temp[len] = '\\0'; 459 strLine = String(temp); 460 461 // SD-Karteninhalt ausgeben 462 if (strLine.indexOf("<sdcontent>") > 0) { 463 DeliverSDRoot(client); 464 } 465 466 strLine.replace("%ram%", String(ram)); 467 strLine.replace("%ver%", version); 468 strLine.replace("%z%", showTime()); 469 strLine.replace("%d%", showDate()); 470 strLine.replace("%sta%", Web_Status(Status)); 471 if (zuendung) { 472 if (Status == 1 || Status == 18) { 473 strLine.replace("%gen%", "Ein"); 474 } else { 475 strLine.replace("%gen%", "Standby"); 476 } 477 } else { 478 strLine.replace("%gen%", "Aus"); 479 } 480 strLine.replace("%sys%", ConvSeperator(t_data.SysTemperatur)); 481 strLine.replace("%mot%", ConvSeperator(t_data.MotorTemperatur)); 482 strLine.replace("%aut%", ConvSeperator(t_data.AussenTemperatur)); 483 strLine.replace("%bat%", ConvSeperator(GeneratorBatterie)); 484 strLine.replace("%p%", ConvSeperator(StrLeistung)); 485 strLine.replace("%1v%", String(p_data.L1_Spannung, 0)); 486 strLine.replace("%2v%", String(p_data.L2_Spannung, 0)); 487 strLine.replace("%3v%", String(p_data.L3_Spannung, 0)); 488 strLine.replace("%1c%", ConvSeperator(String(p_data.L1_Strom, 1))); 489 strLine.replace("%2c%", ConvSeperator(String(p_data.L2_Strom, 1))); 490 strLine.replace("%3c%", ConvSeperator(String(p_data.L3_Strom, 1))); 491 492 strLine.replace("%lm%", String(lostmain)); 493 strLine.replace("%bm%", String(backmain)); 494 strLine.replace("%gt%", String(glowtime)); 495 strLine.replace("%it%", String(ignitiontime * 100)); 496 strLine.replace("%st%", String(starttrying)); 497 strLine.replace("%startd%", String(genstartdelay)); 498 strLine.replace("%stopd%", String(genstoppdelay)); 499 strLine.replace("%sd%", String(switchdelay)); 500 strLine.replace("%mv%", ConvSeperator(String(minbatvoltage, 1))); 501 502 strLine.replace("", "ö"); 503 strLine.replace("", "ä"); 504 strLine.replace("", "ü"); 505 strLine.trim(); 506 507 client->println(strLine); // ... und an Webclient ausliefern 508 509 i = 0; 510 memset(temp, '\\0', sizeof(temp)); 511 512 } else { 513 temp[i] = c; 514 i++; 515 } 516 } 517 sdFile.close(); 518} 519