Controller for Chemical Dosing Pump
A portable WiFi / smart phone based pump system for dosing drip irrigation systems with chemicals.
Components and supplies
Buzzer
30A Relay Modual
Switches Automotive 10A
Generic ESP8266 IC
Single Channel FET trigger board
ESP8266 WeMos D1 R2 Uno Compatible
ESP8266 ESP-12E
Fuse and Holder 10A
Tools and machines
Soldering iron (generic)
Apps and platforms
Arduino IDE
Chrome Web Browser
Project description
Code
h2o2Injector.ino Ver 2.0
c_cpp
This a WeMos D1 R2 version with an WiFi access point / web interface. You control the pump via the web browser on a mobile phone or tablet.
1#include <ESP8266WiFi.h> 2#include <WiFiClient.h> 3#include <ESP8266WebServer.h> 4#include <TimeLib.h> 5//#include <Wire.h> 6//#include <SPI.h> 7#include <EEPROM.h> 8 9const byte MOTOR1 = D7 ; // PWM 10const byte BEEPER = D8 ; // pezo 11const byte SCOPE_PIN = D5 ; // for cycle timer measure 12 13 14/* Set these to your desired credentials. */ 15const char *ssid = "Injector"; 16const char *password = "password"; 17byte rtc_sec ; 18byte rtc_min ; 19byte rtc_hour ; 20int iOut1 = 0 ; 21int iOut2 = 0 ; 22long lPrime ; 23long lOnTime ; 24long lOffTime ; 25long lOnCounter ; 26long lOffCounter ; 27int lCyclesCounter ; 28int lCycles ; 29float dblMLPerSecond ; 30float dblQty ; 31float dblCurrentQty ; 32bool bState ; 33bool bOnOff = false ; 34bool bPrime = false ; 35int iCurPos ; 36long lTimePrev ; 37long lTimePrev2 ; 38int iFinish = 30 ; 39ESP8266WebServer server(80); 40 41/* Just a little test message. Go to http://192.168.4.1 in a web browser 42 * connected to this access point to see it. 43 */ 44void handleRoot() { 45 boolean currentLineIsBlank = true; 46 char buff[40] ; 47 long i = 0 ; 48 Serial.println("web Request"); 49 for (uint8_t j=0; j<server.args(); j++){ 50 i = String(server.argName(j)).indexOf("command"); 51 if (i != -1){ // have a request to set the time zone 52 switch (String(server.arg(j)).toInt()){ 53 case 1: // load values 54 LoadParamsFromEEPROM(true); 55 Serial.println("Load from EEPROM"); 56 break; 57 case 2: // Save values 58 LoadParamsFromEEPROM(false); 59 Serial.println("Save to EEPROM"); 60 break; 61 case 3: // prime command 62 bPrime = true ; 63 Serial.println("Prime Pumps"); 64 break; 65 case 4: // Clear current qty 66 dblCurrentQty = 0 ; 67 Serial.println("Clear current qty"); 68 break; 69 case 5: // Clear current qty 70 lCyclesCounter = 0 ; 71 Serial.println("Clear current cycles"); 72 break; 73 } 74 } 75 i = String(server.argName(j)).indexOf("prime"); 76 if (i != -1){ // have a request to set the time zone 77 lPrime = String(server.arg(j)).toInt() ; 78 if (lPrime > 32000 ){ 79 lPrime = 32000 ; 80 } 81 if ( lPrime < 500 ){ 82 lPrime = 500 ; 83 } 84 } 85 86 i = String(server.argName(j)).indexOf("timon"); 87 if (i != -1){ // have a request to set the time zone 88 lOnTime = String(server.arg(j)).toInt() ; 89 if ( lOnTime > 100000 ){ 90 lOnTime = 100000 ; 91 } 92 if ( lOnTime < 1000 ){ 93 lOnTime = 1000 ; 94 } 95 } 96 i = String(server.argName(j)).indexOf("timof"); 97 if (i != -1){ // have a request to set the time zone 98 lOffTime = String(server.arg(j)).toInt() ; 99 if ( lOffTime > 100000 ){ 100 lOffTime = 100000 ; 101 } 102 if ( lOffTime < 1000 ){ 103 lOffTime = 1000 ; 104 } 105 } 106 i = String(server.argName(j)).indexOf("cycnt"); 107 if (i != -1){ // have a request to set the time zone 108 lCycles = String(server.arg(j)).toInt() ; 109 if ( lCycles > 32000 ){ 110 lCycles = 32000 ; 111 } 112 if ( lCycles < 0 ){ 113 lCycles = 0 ; 114 } 115 } 116 i = String(server.argName(j)).indexOf("pumpea"); 117 if (i != -1){ // have a request to set the time zone 118 if ( String(server.arg(j)).toInt()== 1){ //on 119 bOnOff = true ; 120 bState = true ; 121 }else{ 122 bOnOff = false ; 123 bState = false ; 124 } 125 } 126 127 i = String(server.argName(j)).indexOf("pmlps"); // pump ml per second 128 if (i != -1){ // have a request to set the latitude 129 dblMLPerSecond = String(server.arg(j)).toFloat() ; 130 if ( dblMLPerSecond < 50){ 131 dblMLPerSecond = 50 ; 132 } 133 if ( dblMLPerSecond > 10000 ){ 134 dblMLPerSecond = 10000 ; 135 } 136 } 137 i = String(server.argName(j)).indexOf("quant"); // maximum qty to be pumped 138 if (i != -1){ // have a request to set the latitude 139 dblQty = String(server.arg(j)).toFloat() ; 140 if ( dblQty < 1){ 141 dblQty = 1 ; 142 } 143 if ( dblQty > 1000 ){ 144 dblQty = 1000 ; 145 } 146 } 147 148 } 149 150// server.send(200, "text/html", "<h1>YO DUDE - You are connected</h1>"); 151 server.sendHeader("HTTP/1.1 200 OK","Content-Type: text/html",true); 152 server.sendContent("<!DOCTYPE HTML>"); 153 server.sendContent("<head><title>Team Trouble - Chemical Injector</title>"); 154 server.sendContent("<meta name=viewport content='width=320, auto inital-scale=1'>"); 155 156 server.sendContent("</head><body><html><center><h2>Chemical Injector Mk2.0</h2>"); 157 158 server.sendContent("<a href='/'>Refresh</a><br><br>") ; 159 server.sendContent("<a href='/?command=2'>Save Parameters to EEPROM</a><br>") ; 160 161 server.sendContent("<table border=1 title='Pump Control'>"); 162 server.sendContent("<tr><th> Parameter</th><th>Value</th><th>.</th></tr>"); 163 164 server.sendContent("<form method=get action=/><tr><td>Pump Control</td><td align=center><select name='pumpea'>") ; 165 if (bOnOff){ 166 server.sendContent("<option value='0' >OFF<option value='1' SELECTED>ON"); 167 }else{ 168 server.sendContent("<option value='0' SELECTED>OFF<option value='1'>ON"); 169 } 170 server.sendContent("</select></td><td><input type='submit' value='SET'></td></tr></form>"); 171 172 server.sendContent("<form method=get action=" + server.uri() + "><tr><td>Time On</td><td align=center>") ; 173 server.sendContent("<input type='text' name='timon' value='" + String(lOnTime) + "' size=6></td><td><input type='submit' value='SET'></td></tr></form>"); 174 175 server.sendContent("<form method=get action=" + server.uri() + "><tr><td>Time Off</td><td align=center>") ; 176 server.sendContent("<input type='text' name='timof' value='" + String(lOffTime) + "' size=6></td><td><input type='submit' value='SET'></td></tr></form>"); 177 178 server.sendContent("<form method=get action=" + server.uri() + "><tr><td><a href='/?command=3' title='Click to Prime Pump'>Prime Time (ms)</a></td><td align=center>") ; 179 server.sendContent("<input type='text' name='prime' value='" + String(lPrime) + "' size=6></td><td><input type='submit' value='SET'></td></tr></form>"); 180 181 server.sendContent("<form method=get action=" + server.uri() + "><tr><td>Max Cycles</td><td align=center>") ; 182 server.sendContent("<input type='text' name='cycnt' value='" + String(lCycles) + "' size=6></td><td><input type='submit' value='SET'></td></tr></form>"); 183 184 server.sendContent("<form method=get action=" + server.uri() + "><tr><td>ml Per Second</td><td align=center>") ; 185 server.sendContent("<input type='text' name='pmlps' value='" + String(dblMLPerSecond,2) + "' size=6></td><td><input type='submit' value='SET'></td></tr></form>"); 186 187 server.sendContent("<form method=get action=" + server.uri() + "><tr><td>Max Quanity (l)</td><td align=center>") ; 188 server.sendContent("<input type='text' name='quant' value='" + String(dblQty,2) + "' size=6></td><td><input type='submit' value='SET'></td></tr></form>"); 189 190 server.sendContent("<tr><td><a href='/?command=4' title='click to clear'>Current Qty</a></td><td align=center>" + String(dblCurrentQty,3) + "</td><td>(l)</td></tr>"); 191// server.sendContent("<tr><td>Current On Counter</td><td align=center>" + String(lOnCounter) + "</td><td>(ms)</td></tr>"); 192// server.sendContent("<tr><td>Current Off Counter</td><td align=center>" + String(lOffCounter) + "</td><td>(ms)</td></tr>"); 193 server.sendContent("<tr><td><a href='/?command=5' title='click to clear'>Current Cycles</td><td align=center>" + String(lCyclesCounter) + "</a></td><td>.</td></tr>"); 194 server.sendContent("</table>"); 195 server.sendContent("<a href='/?command=1'>Load Parameters from EEPROM</a><br>") ; 196 server.sendContent("</body></html>"); 197 198} 199 200void FloatToModbusWords(float src_value , uint16_t * dest_lo , uint16_t * dest_hi ) { 201 uint16_t tempdata[2] ; 202 float *tf ; 203 tf = (float * )&tempdata[0] ; 204 *tf = src_value ; 205 *dest_lo = tempdata[1] ; 206 *dest_hi = tempdata[0] ; 207} 208float FloatFromModbusWords( uint16_t dest_lo , uint16_t dest_hi ) { 209 uint16_t tempdata[2] ; 210 float *tf ; 211 tf = (float * )&tempdata[0] ; 212 tempdata[1] = dest_lo ; 213 tempdata[0] = dest_hi ; 214 return (*tf) ; 215} 216int NumberOK (float target) { 217 int tmp = 0 ; 218 tmp = isnan(target); 219 if ( tmp != 1 ) { 220 tmp = isinf(target); 221 } 222 return (tmp); 223} 224 225int LoadIntFromEEPROM(int address,int minval,int maxval, int defaultval){ 226int dummy1 = 0 ; // belt and braces ... dont know which way the stack works 227int tmp ; 228int dummy2 = 0 ; // yep write this one as well ... maybe 229int i ; 230byte *ba ; 231 232 ba =(byte *)&tmp ; // set the byte array to point at the long 233 for ( i = 0 ; i < 4 ; i++ ){ 234 ba[i] = EEPROM.read((address*4)+i); // read the 4 bytes 235 } 236 if (( tmp < minval ) || ( tmp > maxval )) { 237 tmp = defaultval ; 238 for ( i = 0 ; i < 4 ; i++ ){ 239 EEPROM.write((address*4)+i , ba[i] ); 240 EEPROM.commit(); // save changes in one go ??? 241 } 242 } 243 return(tmp); 244} 245int LoadLongFromEEPROM(int address,long minval,long maxval, long defaultval){ 246long tmp ; 247int i ; 248byte *ba ; 249 250 ba =(byte *)&tmp ; // set the byte array to point at the long 251 for ( i = 0 ; i < 4 ; i++ ){ 252 ba[i] = EEPROM.read((address*4)+i); // read the 4 bytes 253 } 254 if (( tmp < minval ) || ( tmp > maxval )) { 255 tmp = defaultval ; 256 for ( i = 0 ; i < 4 ; i++ ){ 257 EEPROM.write((address*4)+i , ba[i] ); 258 EEPROM.commit(); // save changes in one go ??? 259 } 260 } 261 return(tmp); 262} 263float LoadFloatFromEEPROM(int address,float minval,float maxval, float defaultval){ 264float tmp ; 265int i ; 266byte *ba ; 267 268 ba =(byte *)&tmp ; // set the byte array to point at the long 269 for ( i = 0 ; i < 4 ; i++ ){ 270 ba[i] = EEPROM.read((address*4)+i); // read the 4 bytes 271 } 272 if (( tmp < minval ) || ( tmp > maxval )) { 273 tmp = defaultval ; 274 for ( i = 0 ; i < 4 ; i++ ){ 275 EEPROM.write((address*4)+i , ba[i] ); 276 EEPROM.commit(); // save changes in one go ??? 277 } 278 } 279 return(tmp); 280} 281void SaveFloatToEEPROM(int address,float val){ 282float tmp ; 283int i ; 284byte *ba ; 285 tmp = val ; 286 ba =(byte *)&tmp ; // set the byte array to point at the long 287 for ( i = 0 ; i < 4 ; i++ ){ 288 EEPROM.write((address*4)+i , ba[i] ); 289 } 290} 291void SaveLongToEEPROM(int address,long val){ 292long tmp ; 293int i ; 294byte *ba ; 295 tmp = val ; 296 ba =(byte *)&tmp ; // set the byte array to point at the long 297 for ( i = 0 ; i < 4 ; i++ ){ 298 EEPROM.write((address*4)+i , ba[i] ); 299 } 300} 301void SaveIntToEEPROM(int address,int val){ 302int dummy1 = 0 ; 303int tmp ; 304int dummy2 = 0 ; 305int i ; 306byte *ba ; 307 tmp = val ; 308 ba =(byte *)&tmp ; // set the byte array to point at the long 309 for ( i = 0 ; i < 4 ; i++ ){ 310 EEPROM.write((address*4)+i , ba[i] ); 311 } 312} 313 314void LoadParamsFromEEPROM(bool bLoad){ 315 if ( bLoad ) { 316 lOnTime = LoadLongFromEEPROM(0,500,100000,4000); // On time in ms 317 lOffTime = LoadLongFromEEPROM(1,500,100000, 26000); // Off time in ms 318 lCycles = LoadLongFromEEPROM(2,0,100000,32000); // maximum no of cycles 319 320 dblMLPerSecond = LoadFloatFromEEPROM(3,10,1000.0,100.0); // pump rate 321 dblQty = LoadFloatFromEEPROM(4,5,1000,10); // Total Qty Required Literds 322 lPrime = LoadLongFromEEPROM(5,500,32000, 15000); // Off time in ms 323 324 }else{ 325 SaveLongToEEPROM(0,lOnTime ); 326 SaveLongToEEPROM(1 , lOffTime ); 327 SaveLongToEEPROM(2, lCycles ); 328 SaveFloatToEEPROM(3 , dblMLPerSecond ); 329 SaveFloatToEEPROM(4 , dblQty ); 330 SaveLongToEEPROM(5 , lPrime ); 331 EEPROM.commit(); // save changes in one go ??? 332 } 333} 334 335 336void setup() { 337 delay(1000); 338 Serial.begin(115200); 339 Serial.setDebugOutput(true); 340 Serial.println("\ 341"); 342 Serial.print("Configuring access point..."); 343 /* You can remove the password parameter if you want the AP to be open. */ 344 WiFi.softAP(ssid, password); 345 346 IPAddress myIP = WiFi.softAPIP(); 347 Serial.print("AP IP address: "); 348 Serial.println(myIP); 349 server.on("/", handleRoot); 350 server.begin(); 351 Serial.println("HTTP server started"); 352 353 pinMode(BUILTIN_LED,OUTPUT); 354 pinMode(MOTOR1,OUTPUT); 355 pinMode(BEEPER,OUTPUT); 356 pinMode(SCOPE_PIN,OUTPUT); 357 digitalWrite(MOTOR1,LOW); // Off I think 358 digitalWrite(BEEPER,LOW); 359 360 EEPROM.begin(512); 361 LoadParamsFromEEPROM(true); 362} 363 364void loop() { 365long lTime ; 366 server.handleClient(); 367 368 lTime = millis() ; 369 lOffCounter = constrain(lOffCounter,0, lOffTime); 370 lOnCounter = constrain(lOnCounter,0, lOnTime); 371 lCyclesCounter = constrain(lCyclesCounter,0, lCycles); 372 373 if ((dblCurrentQty >= dblQty )|| (!bOnOff ) || (lCyclesCounter >= lCycles)){ 374 bState = false ; 375 if ( bOnOff ){ 376 iFinish = 1 ; 377 } 378 bOnOff = false ; 379 } 380 if (( lTimePrev2 ) < lTime ){ // look every 2 ms 381 if ((bState)|| (bPrime )){ // soft starter 382 if ( iOut1 < 1023 ){ // speed up 383 iOut1 ++ ; 384 } 385 }else{ 386 if ( iOut1 > 0 ){ // slow down 387 iOut1 -- ; 388 } 389 } 390 lTimePrev2 = lTime ; 391 } 392 if (lTimePrev > ( lTime + 100000 )){ // has wrapped around so back to zero 393 lTimePrev = lTime ; // skip a bit 394 Serial.println("Wrap around"); 395 } 396 397 if (( lTimePrev + 100 ) < lTime ){ // look every 1/10 of a second ish 398 if (( bState) || ( bPrime )) { // true is on - assume called once per second 399 lOnCounter+= (lTime - lTimePrev) ; 400 if (bPrime){ 401 if ( lOnCounter >= lPrime ){ 402 Serial.println("prime complete"); 403 lOnCounter = 0 ; 404 bPrime = false ; 405 bState = false ; 406 } 407 }else{ 408 if ( lOnCounter >= lOnTime ){ 409 lOnCounter = 0 ; 410 lCyclesCounter++ ; 411 bState = !bState ; 412 } 413 } 414 dblCurrentQty += ( dblMLPerSecond * (float(lTime - lTimePrev)/1000))/1000 ; //work out how much 415 }else{ 416 if (bOnOff){ 417 lOffCounter += (lTime - lTimePrev) ; 418 digitalWrite(BUILTIN_LED,!digitalRead(BUILTIN_LED)); 419 if ( lOffCounter >= lOffTime ) { 420 lOffCounter = 0 ; 421 bState = !bState ; 422 } 423 }else{ 424 lOffCounter = 0 ; 425 } 426 } 427 lTimePrev += 100 ; 428 } 429 430 analogWrite(MOTOR1,iOut1) ; // soft start the motor 431// analogWrite(MOTOR2,iOut2) ; // soft start the motor 432 433 if (rtc_sec != second() ) { 434 digitalWrite(BUILTIN_LED,!digitalRead(BUILTIN_LED)); 435 if (iFinish < 31 ){ 436 iFinish++ ; 437 } 438 if ((iFinish < 30 )&& (iFinish >0 )){ 439 digitalWrite(BEEPER,!digitalRead(BEEPER)); 440 }else{ 441 digitalWrite(BEEPER,0); 442 } 443 444 rtc_sec = second(); 445// if ( iOut1 > 0 ) 446// Serial.println(iOut1); 447 } 448 digitalWrite(SCOPE_PIN,!digitalRead(SCOPE_PIN)); // my scope says we are doing this loop at an unreasonable speed except when we do web stuff 449 450} 451
PeroxideInjector.ino
c_cpp
Proof of Concept First attempt As simple as possible, really rude/rough hack. Hardware:- Uno with relay board
1#define MAX_TIME 32000 2#define MIN_TIME 1 3#define BUFF_MAX 32 4 5const byte RELAY1 = 7 ; 6const byte RELAY2 = 6 ; 7const byte RELAY3 = 5 ; 8const byte RELAY4 = 4 ; 9 10#include <avr/wdt.h> 11#include <EEPROM.h> 12 13int lOnTime ; 14int lOffTime ; 15int lOnCounter ; 16int lOffCounter ; 17int lCyclesCounter ; 18bool bState ; 19int iCurPos ; 20 21int LoadLongFromEEPROM(int address,long minval,long maxval, long defaultval){ 22long tmp ; 23 EEPROM.get(0 + (address * sizeof(long)) , tmp ); 24 if (( tmp < minval ) || ( tmp > maxval )) { 25 tmp = defaultval ; 26 EEPROM.put(0 + (address * sizeof(long)) , tmp ); 27 } 28 return(tmp); 29} 30 31 32void setup() { 33 34 pinMode(RELAY1,OUTPUT); 35 pinMode(RELAY2,OUTPUT); 36 pinMode(RELAY3,OUTPUT); 37 pinMode(RELAY4,OUTPUT); 38 digitalWrite(RELAY1,LOW); 39 digitalWrite(RELAY2,LOW); 40 digitalWrite(RELAY3,LOW); 41 digitalWrite(RELAY4,LOW); 42 43} 44 45void loop() { 46 47 digitalWrite(RELAY1,HIGH); 48 digitalWrite(RELAY2,HIGH); 49 digitalWrite(RELAY3,HIGH); 50 digitalWrite(RELAY4,HIGH); 51 delay(2000); 52 digitalWrite(RELAY1,LOW); 53 delay(2000); 54 digitalWrite(RELAY2,LOW); 55 delay(4000); 56 digitalWrite(RELAY3,LOW); 57 delay(7000); 58 digitalWrite(RELAY4,LOW); 59 delay(15000); 60} 61 62 63 64
h2o2Injector.ino Ver 2.0
c_cpp
This a WeMos D1 R2 version with an WiFi access point / web interface. You control the pump via the web browser on a mobile phone or tablet.
1#include <ESP8266WiFi.h> 2#include <WiFiClient.h> 3#include <ESP8266WebServer.h> 4#include <TimeLib.h> 5//#include <Wire.h> 6//#include <SPI.h> 7#include <EEPROM.h> 8 9const byte MOTOR1 = D7 ; // PWM 10const byte BEEPER = D8 ; // pezo 11const byte SCOPE_PIN = D5 ; // for cycle timer measure 12 13 14/* Set these to your desired credentials. */ 15const char *ssid = "Injector"; 16const char *password = "password"; 17byte rtc_sec ; 18byte rtc_min ; 19byte rtc_hour ; 20int iOut1 = 0 ; 21int iOut2 = 0 ; 22long lPrime ; 23long lOnTime ; 24long lOffTime ; 25long lOnCounter ; 26long lOffCounter ; 27int lCyclesCounter ; 28int lCycles ; 29float dblMLPerSecond ; 30float dblQty ; 31float dblCurrentQty ; 32bool bState ; 33bool bOnOff = false ; 34bool bPrime = false ; 35int iCurPos ; 36long lTimePrev ; 37long lTimePrev2 ; 38int iFinish = 30 ; 39ESP8266WebServer server(80); 40 41/* Just a little test message. Go to http://192.168.4.1 in a web browser 42 * connected to this access point to see it. 43 */ 44void handleRoot() { 45 boolean currentLineIsBlank = true; 46 char buff[40] ; 47 long i = 0 ; 48 Serial.println("web Request"); 49 for (uint8_t j=0; j<server.args(); j++){ 50 i = String(server.argName(j)).indexOf("command"); 51 if (i != -1){ // have a request to set the time zone 52 switch (String(server.arg(j)).toInt()){ 53 case 1: // load values 54 LoadParamsFromEEPROM(true); 55 Serial.println("Load from EEPROM"); 56 break; 57 case 2: // Save values 58 LoadParamsFromEEPROM(false); 59 Serial.println("Save to EEPROM"); 60 break; 61 case 3: // prime command 62 bPrime = true ; 63 Serial.println("Prime Pumps"); 64 break; 65 case 4: // Clear current qty 66 dblCurrentQty = 0 ; 67 Serial.println("Clear current qty"); 68 break; 69 case 5: // Clear current qty 70 lCyclesCounter = 0 ; 71 Serial.println("Clear current cycles"); 72 break; 73 } 74 } 75 i = String(server.argName(j)).indexOf("prime"); 76 if (i != -1){ // have a request to set the time zone 77 lPrime = String(server.arg(j)).toInt() ; 78 if (lPrime > 32000 ){ 79 lPrime = 32000 ; 80 } 81 if ( lPrime < 500 ){ 82 lPrime = 500 ; 83 } 84 } 85 86 i = String(server.argName(j)).indexOf("timon"); 87 if (i != -1){ // have a request to set the time zone 88 lOnTime = String(server.arg(j)).toInt() ; 89 if ( lOnTime > 100000 ){ 90 lOnTime = 100000 ; 91 } 92 if ( lOnTime < 1000 ){ 93 lOnTime = 1000 ; 94 } 95 } 96 i = String(server.argName(j)).indexOf("timof"); 97 if (i != -1){ // have a request to set the time zone 98 lOffTime = String(server.arg(j)).toInt() ; 99 if ( lOffTime > 100000 ){ 100 lOffTime = 100000 ; 101 } 102 if ( lOffTime < 1000 ){ 103 lOffTime = 1000 ; 104 } 105 } 106 i = String(server.argName(j)).indexOf("cycnt"); 107 if (i != -1){ // have a request to set the time zone 108 lCycles = String(server.arg(j)).toInt() ; 109 if ( lCycles > 32000 ){ 110 lCycles = 32000 ; 111 } 112 if ( lCycles < 0 ){ 113 lCycles = 0 ; 114 } 115 } 116 i = String(server.argName(j)).indexOf("pumpea"); 117 if (i != -1){ // have a request to set the time zone 118 if ( String(server.arg(j)).toInt()== 1){ //on 119 bOnOff = true ; 120 bState = true ; 121 }else{ 122 bOnOff = false ; 123 bState = false ; 124 } 125 } 126 127 i = String(server.argName(j)).indexOf("pmlps"); // pump ml per second 128 if (i != -1){ // have a request to set the latitude 129 dblMLPerSecond = String(server.arg(j)).toFloat() ; 130 if ( dblMLPerSecond < 50){ 131 dblMLPerSecond = 50 ; 132 } 133 if ( dblMLPerSecond > 10000 ){ 134 dblMLPerSecond = 10000 ; 135 } 136 } 137 i = String(server.argName(j)).indexOf("quant"); // maximum qty to be pumped 138 if (i != -1){ // have a request to set the latitude 139 dblQty = String(server.arg(j)).toFloat() ; 140 if ( dblQty < 1){ 141 dblQty = 1 ; 142 } 143 if ( dblQty > 1000 ){ 144 dblQty = 1000 ; 145 } 146 } 147 148 } 149 150// server.send(200, "text/html", "<h1>YO DUDE - You are connected</h1>"); 151 server.sendHeader("HTTP/1.1 200 OK","Content-Type: text/html",true); 152 server.sendContent("<!DOCTYPE HTML>"); 153 server.sendContent("<head><title>Team Trouble - Chemical Injector</title>"); 154 server.sendContent("<meta name=viewport content='width=320, auto inital-scale=1'>"); 155 156 server.sendContent("</head><body><html><center><h2>Chemical Injector Mk2.0</h2>"); 157 158 server.sendContent("<a href='/'>Refresh</a><br><br>") ; 159 server.sendContent("<a href='/?command=2'>Save Parameters to EEPROM</a><br>") ; 160 161 server.sendContent("<table border=1 title='Pump Control'>"); 162 server.sendContent("<tr><th> Parameter</th><th>Value</th><th>.</th></tr>"); 163 164 server.sendContent("<form method=get action=/><tr><td>Pump Control</td><td align=center><select name='pumpea'>") ; 165 if (bOnOff){ 166 server.sendContent("<option value='0' >OFF<option value='1' SELECTED>ON"); 167 }else{ 168 server.sendContent("<option value='0' SELECTED>OFF<option value='1'>ON"); 169 } 170 server.sendContent("</select></td><td><input type='submit' value='SET'></td></tr></form>"); 171 172 server.sendContent("<form method=get action=" + server.uri() + "><tr><td>Time On</td><td align=center>") ; 173 server.sendContent("<input type='text' name='timon' value='" + String(lOnTime) + "' size=6></td><td><input type='submit' value='SET'></td></tr></form>"); 174 175 server.sendContent("<form method=get action=" + server.uri() + "><tr><td>Time Off</td><td align=center>") ; 176 server.sendContent("<input type='text' name='timof' value='" + String(lOffTime) + "' size=6></td><td><input type='submit' value='SET'></td></tr></form>"); 177 178 server.sendContent("<form method=get action=" + server.uri() + "><tr><td><a href='/?command=3' title='Click to Prime Pump'>Prime Time (ms)</a></td><td align=center>") ; 179 server.sendContent("<input type='text' name='prime' value='" + String(lPrime) + "' size=6></td><td><input type='submit' value='SET'></td></tr></form>"); 180 181 server.sendContent("<form method=get action=" + server.uri() + "><tr><td>Max Cycles</td><td align=center>") ; 182 server.sendContent("<input type='text' name='cycnt' value='" + String(lCycles) + "' size=6></td><td><input type='submit' value='SET'></td></tr></form>"); 183 184 server.sendContent("<form method=get action=" + server.uri() + "><tr><td>ml Per Second</td><td align=center>") ; 185 server.sendContent("<input type='text' name='pmlps' value='" + String(dblMLPerSecond,2) + "' size=6></td><td><input type='submit' value='SET'></td></tr></form>"); 186 187 server.sendContent("<form method=get action=" + server.uri() + "><tr><td>Max Quanity (l)</td><td align=center>") ; 188 server.sendContent("<input type='text' name='quant' value='" + String(dblQty,2) + "' size=6></td><td><input type='submit' value='SET'></td></tr></form>"); 189 190 server.sendContent("<tr><td><a href='/?command=4' title='click to clear'>Current Qty</a></td><td align=center>" + String(dblCurrentQty,3) + "</td><td>(l)</td></tr>"); 191// server.sendContent("<tr><td>Current On Counter</td><td align=center>" + String(lOnCounter) + "</td><td>(ms)</td></tr>"); 192// server.sendContent("<tr><td>Current Off Counter</td><td align=center>" + String(lOffCounter) + "</td><td>(ms)</td></tr>"); 193 server.sendContent("<tr><td><a href='/?command=5' title='click to clear'>Current Cycles</td><td align=center>" + String(lCyclesCounter) + "</a></td><td>.</td></tr>"); 194 server.sendContent("</table>"); 195 server.sendContent("<a href='/?command=1'>Load Parameters from EEPROM</a><br>") ; 196 server.sendContent("</body></html>"); 197 198} 199 200void FloatToModbusWords(float src_value , uint16_t * dest_lo , uint16_t * dest_hi ) { 201 uint16_t tempdata[2] ; 202 float *tf ; 203 tf = (float * )&tempdata[0] ; 204 *tf = src_value ; 205 *dest_lo = tempdata[1] ; 206 *dest_hi = tempdata[0] ; 207} 208float FloatFromModbusWords( uint16_t dest_lo , uint16_t dest_hi ) { 209 uint16_t tempdata[2] ; 210 float *tf ; 211 tf = (float * )&tempdata[0] ; 212 tempdata[1] = dest_lo ; 213 tempdata[0] = dest_hi ; 214 return (*tf) ; 215} 216int NumberOK (float target) { 217 int tmp = 0 ; 218 tmp = isnan(target); 219 if ( tmp != 1 ) { 220 tmp = isinf(target); 221 } 222 return (tmp); 223} 224 225int LoadIntFromEEPROM(int address,int minval,int maxval, int defaultval){ 226int dummy1 = 0 ; // belt and braces ... dont know which way the stack works 227int tmp ; 228int dummy2 = 0 ; // yep write this one as well ... maybe 229int i ; 230byte *ba ; 231 232 ba =(byte *)&tmp ; // set the byte array to point at the long 233 for ( i = 0 ; i < 4 ; i++ ){ 234 ba[i] = EEPROM.read((address*4)+i); // read the 4 bytes 235 } 236 if (( tmp < minval ) || ( tmp > maxval )) { 237 tmp = defaultval ; 238 for ( i = 0 ; i < 4 ; i++ ){ 239 EEPROM.write((address*4)+i , ba[i] ); 240 EEPROM.commit(); // save changes in one go ??? 241 } 242 } 243 return(tmp); 244} 245int LoadLongFromEEPROM(int address,long minval,long maxval, long defaultval){ 246long tmp ; 247int i ; 248byte *ba ; 249 250 ba =(byte *)&tmp ; // set the byte array to point at the long 251 for ( i = 0 ; i < 4 ; i++ ){ 252 ba[i] = EEPROM.read((address*4)+i); // read the 4 bytes 253 } 254 if (( tmp < minval ) || ( tmp > maxval )) { 255 tmp = defaultval ; 256 for ( i = 0 ; i < 4 ; i++ ){ 257 EEPROM.write((address*4)+i , ba[i] ); 258 EEPROM.commit(); // save changes in one go ??? 259 } 260 } 261 return(tmp); 262} 263float LoadFloatFromEEPROM(int address,float minval,float maxval, float defaultval){ 264float tmp ; 265int i ; 266byte *ba ; 267 268 ba =(byte *)&tmp ; // set the byte array to point at the long 269 for ( i = 0 ; i < 4 ; i++ ){ 270 ba[i] = EEPROM.read((address*4)+i); // read the 4 bytes 271 } 272 if (( tmp < minval ) || ( tmp > maxval )) { 273 tmp = defaultval ; 274 for ( i = 0 ; i < 4 ; i++ ){ 275 EEPROM.write((address*4)+i , ba[i] ); 276 EEPROM.commit(); // save changes in one go ??? 277 } 278 } 279 return(tmp); 280} 281void SaveFloatToEEPROM(int address,float val){ 282float tmp ; 283int i ; 284byte *ba ; 285 tmp = val ; 286 ba =(byte *)&tmp ; // set the byte array to point at the long 287 for ( i = 0 ; i < 4 ; i++ ){ 288 EEPROM.write((address*4)+i , ba[i] ); 289 } 290} 291void SaveLongToEEPROM(int address,long val){ 292long tmp ; 293int i ; 294byte *ba ; 295 tmp = val ; 296 ba =(byte *)&tmp ; // set the byte array to point at the long 297 for ( i = 0 ; i < 4 ; i++ ){ 298 EEPROM.write((address*4)+i , ba[i] ); 299 } 300} 301void SaveIntToEEPROM(int address,int val){ 302int dummy1 = 0 ; 303int tmp ; 304int dummy2 = 0 ; 305int i ; 306byte *ba ; 307 tmp = val ; 308 ba =(byte *)&tmp ; // set the byte array to point at the long 309 for ( i = 0 ; i < 4 ; i++ ){ 310 EEPROM.write((address*4)+i , ba[i] ); 311 } 312} 313 314void LoadParamsFromEEPROM(bool bLoad){ 315 if ( bLoad ) { 316 lOnTime = LoadLongFromEEPROM(0,500,100000,4000); // On time in ms 317 lOffTime = LoadLongFromEEPROM(1,500,100000, 26000); // Off time in ms 318 lCycles = LoadLongFromEEPROM(2,0,100000,32000); // maximum no of cycles 319 320 dblMLPerSecond = LoadFloatFromEEPROM(3,10,1000.0,100.0); // pump rate 321 dblQty = LoadFloatFromEEPROM(4,5,1000,10); // Total Qty Required Literds 322 lPrime = LoadLongFromEEPROM(5,500,32000, 15000); // Off time in ms 323 324 }else{ 325 SaveLongToEEPROM(0,lOnTime ); 326 SaveLongToEEPROM(1 , lOffTime ); 327 SaveLongToEEPROM(2, lCycles ); 328 SaveFloatToEEPROM(3 , dblMLPerSecond ); 329 SaveFloatToEEPROM(4 , dblQty ); 330 SaveLongToEEPROM(5 , lPrime ); 331 EEPROM.commit(); // save changes in one go ??? 332 } 333} 334 335 336void setup() { 337 delay(1000); 338 Serial.begin(115200); 339 Serial.setDebugOutput(true); 340 Serial.println("\ 341"); 342 Serial.print("Configuring access point..."); 343 /* You can remove the password parameter if you want the AP to be open. */ 344 WiFi.softAP(ssid, password); 345 346 IPAddress myIP = WiFi.softAPIP(); 347 Serial.print("AP IP address: "); 348 Serial.println(myIP); 349 server.on("/", handleRoot); 350 server.begin(); 351 Serial.println("HTTP server started"); 352 353 pinMode(BUILTIN_LED,OUTPUT); 354 pinMode(MOTOR1,OUTPUT); 355 pinMode(BEEPER,OUTPUT); 356 pinMode(SCOPE_PIN,OUTPUT); 357 digitalWrite(MOTOR1,LOW); // Off I think 358 digitalWrite(BEEPER,LOW); 359 360 EEPROM.begin(512); 361 LoadParamsFromEEPROM(true); 362} 363 364void loop() { 365long lTime ; 366 server.handleClient(); 367 368 lTime = millis() ; 369 lOffCounter = constrain(lOffCounter,0, lOffTime); 370 lOnCounter = constrain(lOnCounter,0, lOnTime); 371 lCyclesCounter = constrain(lCyclesCounter,0, lCycles); 372 373 if ((dblCurrentQty >= dblQty )|| (!bOnOff ) || (lCyclesCounter >= lCycles)){ 374 bState = false ; 375 if ( bOnOff ){ 376 iFinish = 1 ; 377 } 378 bOnOff = false ; 379 } 380 if (( lTimePrev2 ) < lTime ){ // look every 2 ms 381 if ((bState)|| (bPrime )){ // soft starter 382 if ( iOut1 < 1023 ){ // speed up 383 iOut1 ++ ; 384 } 385 }else{ 386 if ( iOut1 > 0 ){ // slow down 387 iOut1 -- ; 388 } 389 } 390 lTimePrev2 = lTime ; 391 } 392 if (lTimePrev > ( lTime + 100000 )){ // has wrapped around so back to zero 393 lTimePrev = lTime ; // skip a bit 394 Serial.println("Wrap around"); 395 } 396 397 if (( lTimePrev + 100 ) < lTime ){ // look every 1/10 of a second ish 398 if (( bState) || ( bPrime )) { // true is on - assume called once per second 399 lOnCounter+= (lTime - lTimePrev) ; 400 if (bPrime){ 401 if ( lOnCounter >= lPrime ){ 402 Serial.println("prime complete"); 403 lOnCounter = 0 ; 404 bPrime = false ; 405 bState = false ; 406 } 407 }else{ 408 if ( lOnCounter >= lOnTime ){ 409 lOnCounter = 0 ; 410 lCyclesCounter++ ; 411 bState = !bState ; 412 } 413 } 414 dblCurrentQty += ( dblMLPerSecond * (float(lTime - lTimePrev)/1000))/1000 ; //work out how much 415 }else{ 416 if (bOnOff){ 417 lOffCounter += (lTime - lTimePrev) ; 418 digitalWrite(BUILTIN_LED,!digitalRead(BUILTIN_LED)); 419 if ( lOffCounter >= lOffTime ) { 420 lOffCounter = 0 ; 421 bState = !bState ; 422 } 423 }else{ 424 lOffCounter = 0 ; 425 } 426 } 427 lTimePrev += 100 ; 428 } 429 430 analogWrite(MOTOR1,iOut1) ; // soft start the motor 431// analogWrite(MOTOR2,iOut2) ; // soft start the motor 432 433 if (rtc_sec != second() ) { 434 digitalWrite(BUILTIN_LED,!digitalRead(BUILTIN_LED)); 435 if (iFinish < 31 ){ 436 iFinish++ ; 437 } 438 if ((iFinish < 30 )&& (iFinish >0 )){ 439 digitalWrite(BEEPER,!digitalRead(BEEPER)); 440 }else{ 441 digitalWrite(BEEPER,0); 442 } 443 444 rtc_sec = second(); 445// if ( iOut1 > 0 ) 446// Serial.println(iOut1); 447 } 448 digitalWrite(SCOPE_PIN,!digitalRead(SCOPE_PIN)); // my scope says we are doing this loop at an unreasonable speed except when we do web stuff 449 450} 451
h2o2Injector.ino Ver 2.1
c_cpp
This version can drive a relay or FET board.
1#include <ESP8266WiFi.h> 2#include <WiFiClient.h> 3#include <ESP8266WebServer.h> 4#include <ESP8266mDNS.h> 5//#include <DNSServer.h> 6#include <TimeLib.h> 7//#include <Wire.h> 8//#include <SPI.h> 9#include <EEPROM.h> 10 11const byte MOTOR1 = D7 ; // PWM 12const byte BEEPER = D8 ; // pezo 13const byte SCOPE_PIN = D5 ; // for cycle timer measure 14 15 16/* Set these to your desired credentials. */ 17const char *ssid = "Injector"; 18const char *password = "password"; 19const char *host = "injector"; 20 21byte rtc_sec ; 22byte rtc_min ; 23byte rtc_hour ; 24int iOut1 = 0 ; 25int iOut2 = 0 ; 26long lPrime ; 27long lOnTime ; 28long lOffTime ; 29long lOnCounter ; 30long lOffCounter ; 31int lCyclesCounter ; 32int lCycles ; 33float dblMLPerSecond ; 34float dblQty ; 35float dblCurrentQty ; 36bool bState ; 37bool bOnOff = false ; 38bool bPrime = false ; 39int iCurPos ; 40long lTimePrev ; 41long lTimePrev2 ; 42int iFinish = 30 ; 43long PWM_inc = 5 ; 44 45ESP8266WebServer server(80); 46//DNSServer dnsServer; 47 48/* Just a little test message. Go to http://192.168.4.1 in a web browser 49 * connected to this access point to see it. 50 */ 51void handleNotFound(){ 52 String message = "Seriously - No way DUDE\ 53\ 54"; 55 message += "URI: "; 56 message += server.uri(); 57 message += "\ 58Method: "; 59 message += (server.method() == HTTP_GET)?"GET":"POST"; 60 message += "\ 61Arguments: "; 62 message += server.args(); 63 message += "\ 64"; 65 for (uint8_t i=0; i<server.args(); i++){ 66 message += " NAME:"+server.argName(i) + "\ 67 VALUE:" + server.arg(i) + "\ 68"; 69 } 70 server.send(404, "text/plain", message); 71 Serial.print(message); 72} 73 74 75void handleRoot() { 76 boolean currentLineIsBlank = true; 77 char buff[40] ; 78 long i = 0 ; 79 80 String message = "Web Request URI: "; 81 message += server.uri(); 82 message += "\ 83Method: "; 84 message += (server.method() == HTTP_GET)?"GET":"POST"; 85 message += "\ 86Arguments: "; 87 message += server.args(); 88 message += "\ 89"; 90 for (uint8_t i=0; i<server.args(); i++){ 91 message += " NAME:"+server.argName(i) + "\ 92 VALUE:" + server.arg(i) + "\ 93"; 94 } 95 Serial.println(message); 96 97 for (uint8_t j=0; j<server.args(); j++){ 98 i = String(server.argName(j)).indexOf("command"); 99 if (i != -1){ // have a request to set the time zone 100 switch (String(server.arg(j)).toInt()){ 101 case 1: // load values 102 LoadParamsFromEEPROM(true); 103 Serial.println("Load from EEPROM"); 104 break; 105 case 2: // Save values 106 LoadParamsFromEEPROM(false); 107 Serial.println("Save to EEPROM"); 108 break; 109 case 3: // prime command 110 bPrime = true ; 111 Serial.println("Prime Pumps"); 112 break; 113 case 4: // Clear current qty 114 dblCurrentQty = 0 ; 115 Serial.println("Clear current qty"); 116 break; 117 case 5: // Clear current qty 118 lCyclesCounter = 0 ; 119 Serial.println("Clear current cycles"); 120 break; 121 } 122 } 123 i = String(server.argName(j)).indexOf("prime"); 124 if (i != -1){ // have a request to set the time zone 125 lPrime = String(server.arg(j)).toInt() ; 126 if (lPrime > 32000 ){ 127 lPrime = 32000 ; 128 } 129 if ( lPrime < 500 ){ 130 lPrime = 500 ; 131 } 132 } 133 134 i = String(server.argName(j)).indexOf("timon"); 135 if (i != -1){ // have a request to set the time zone 136 lOnTime = String(server.arg(j)).toInt() ; 137 if ( lOnTime > 100000 ){ 138 lOnTime = 100000 ; 139 } 140 if ( lOnTime < 1000 ){ 141 lOnTime = 1000 ; 142 } 143 } 144 i = String(server.argName(j)).indexOf("timof"); 145 if (i != -1){ // have a request to set the time zone 146 lOffTime = String(server.arg(j)).toInt() ; 147 if ( lOffTime > 100000 ){ 148 lOffTime = 100000 ; 149 } 150 if ( lOffTime < 1000 ){ 151 lOffTime = 1000 ; 152 } 153 } 154 i = String(server.argName(j)).indexOf("cycnt"); 155 if (i != -1){ // have a request to set the time zone 156 lCycles = String(server.arg(j)).toInt() ; 157 if ( lCycles > 32000 ){ 158 lCycles = 32000 ; 159 } 160 if ( lCycles < 0 ){ 161 lCycles = 0 ; 162 } 163 } 164 i = String(server.argName(j)).indexOf("pwminc"); 165 if (i != -1){ // have a request to set the time zone 166 PWM_inc = String(server.arg(j)).toInt() ; 167 if ( PWM_inc > 50 ){ 168 PWM_inc = 50 ; 169 } 170 if ( PWM_inc < 0 ){ 171 PWM_inc = 0 ; 172 } 173 } 174 i = String(server.argName(j)).indexOf("pumpea"); 175 if (i != -1){ // have a request to set the time zone 176 if ( String(server.arg(j)).toInt()== 1){ //on 177 bOnOff = true ; 178 bState = true ; 179 }else{ 180 bOnOff = false ; 181 bState = false ; 182 } 183 } 184 185 i = String(server.argName(j)).indexOf("pmlps"); // pump ml per second 186 if (i != -1){ // have a request to set the latitude 187 dblMLPerSecond = String(server.arg(j)).toFloat() ; 188 if ( dblMLPerSecond < 50){ 189 dblMLPerSecond = 50 ; 190 } 191 if ( dblMLPerSecond > 10000 ){ 192 dblMLPerSecond = 10000 ; 193 } 194 } 195 i = String(server.argName(j)).indexOf("quant"); // maximum qty to be pumped 196 if (i != -1){ // have a request to set the latitude 197 dblQty = String(server.arg(j)).toFloat() ; 198 if ( dblQty < 0){ 199 dblQty = 0 ; 200 } 201 if ( dblQty > 100000 ){ 202 dblQty = 100000 ; 203 } 204 } 205 206 } 207 208 server.sendHeader("Server","ESP8266-on-steroids",false); 209 server.sendHeader("X-Powered-by","Dougal-1.0",false); 210 server.setContentLength(CONTENT_LENGTH_UNKNOWN); 211 server.send(200, "text/html", ""); 212 server.sendContent("<!DOCTYPE HTML>"); 213 server.sendContent("<head><title>Team Trouble - Chemical Injector</title>"); 214 server.sendContent("<meta name=viewport content='width=320, auto inital-scale=1'>"); 215 216 server.sendContent("</head><body><html><center><h2>Chemical Injector Mk2.1</h2>"); 217 218 server.sendContent("<a href='/'>Refresh</a><br><br>") ; 219 server.sendContent("<a href='/?command=2'>Save Parameters to EEPROM</a><br>") ; 220 221 server.sendContent("<table border=1 title='Pump Control'>"); 222 server.sendContent("<tr><th> Parameter</th><th>Value</th><th>.</th></tr>"); 223 224 server.sendContent("<form method=get action=/><tr><td>Pump Control</td><td align=center><select name='pumpea'>") ; 225 if (bOnOff){ 226 server.sendContent("<option value='0' >OFF<option value='1' SELECTED>ON"); 227 }else{ 228 server.sendContent("<option value='0' SELECTED>OFF<option value='1'>ON"); 229 } 230 server.sendContent("</select></td><td><input type='submit' value='SET'></td></tr></form>"); 231 232 server.sendContent("<form method=get action=" + server.uri() + "><tr><td>Time On (ms)</td><td align=center>") ; 233 server.sendContent("<input type='text' name='timon' value='" + String(lOnTime) + "' size=6></td><td><input type='submit' value='SET'></td></tr></form>"); 234 235 server.sendContent("<form method=get action=" + server.uri() + "><tr><td>Time Off (ms)</td><td align=center>") ; 236 server.sendContent("<input type='text' name='timof' value='" + String(lOffTime) + "' size=6></td><td><input type='submit' value='SET'></td></tr></form>"); 237 238 server.sendContent("<form method=get action=" + server.uri() + "><tr><td><a href='/?command=3' title='Click to Prime Pump'>Prime Time (ms)</a></td><td align=center>") ; 239 server.sendContent("<input type='text' name='prime' value='" + String(lPrime) + "' size=6></td><td><input type='submit' value='SET'></td></tr></form>"); 240 241 server.sendContent("<form method=get action=" + server.uri() + "><tr><td>Max Cycles</td><td align=center>") ; 242 server.sendContent("<input type='text' name='cycnt' value='" + String(lCycles) + "' size=6></td><td><input type='submit' value='SET'></td></tr></form>"); 243 244 server.sendContent("<form method=get action=" + server.uri() + "><tr><td>ml Per Second</td><td align=center>") ; 245 server.sendContent("<input type='text' name='pmlps' value='" + String(dblMLPerSecond,2) + "' size=6></td><td><input type='submit' value='SET'></td></tr></form>"); 246 247 server.sendContent("<form method=get action=" + server.uri() + "><tr><td>Max Quanity (l)</td><td align=center>") ; 248 server.sendContent("<input type='text' name='quant' value='" + String(dblQty,2) + "' size=6></td><td><input type='submit' value='SET'></td></tr></form>"); 249 250 server.sendContent("<form method=get action=" + server.uri() + "><tr><td>PWM inc (0 Disable)</td><td align=center>") ; 251 server.sendContent("<input type='text' name='pwminc' value='" + String(PWM_inc) + "' size=6></td><td><input type='submit' value='SET'></td></tr></form>"); 252 253 server.sendContent("<tr><td><a href='/?command=4' title='click to clear'>Current Qty</a></td><td align=center>" + String(dblCurrentQty,3) + "</td><td>(l)</td></tr>"); 254// server.sendContent("<tr><td>Current On Counter</td><td align=center>" + String(lOnCounter) + "</td><td>(ms)</td></tr>"); 255// server.sendContent("<tr><td>Current Off Counter</td><td align=center>" + String(lOffCounter) + "</td><td>(ms)</td></tr>"); 256 server.sendContent("<tr><td><a href='/?command=5' title='click to clear'>Current Cycles</td><td align=center>" + String(lCyclesCounter) + "</a></td><td>.</td></tr>"); 257 server.sendContent("</table>"); 258 server.sendContent("<a href='/?command=1'>Load Parameters from EEPROM</a><br>") ; 259 server.sendContent("</body></html>\ \ 260"); 261 262} 263 264void FloatToModbusWords(float src_value , uint16_t * dest_lo , uint16_t * dest_hi ) { 265 uint16_t tempdata[2] ; 266 float *tf ; 267 tf = (float * )&tempdata[0] ; 268 *tf = src_value ; 269 *dest_lo = tempdata[1] ; 270 *dest_hi = tempdata[0] ; 271} 272float FloatFromModbusWords( uint16_t dest_lo , uint16_t dest_hi ) { 273 uint16_t tempdata[2] ; 274 float *tf ; 275 tf = (float * )&tempdata[0] ; 276 tempdata[1] = dest_lo ; 277 tempdata[0] = dest_hi ; 278 return (*tf) ; 279} 280int NumberOK (float target) { 281 int tmp = 0 ; 282 tmp = isnan(target); 283 if ( tmp != 1 ) { 284 tmp = isinf(target); 285 } 286 return (tmp); 287} 288 289int LoadIntFromEEPROM(int address,int minval,int maxval, int defaultval){ 290int dummy1 = 0 ; // belt and braces ... dont know which way the stack works 291int tmp ; 292int dummy2 = 0 ; // yep write this one as well ... maybe 293int i ; 294byte *ba ; 295 296 ba =(byte *)&tmp ; // set the byte array to point at the long 297 for ( i = 0 ; i < 4 ; i++ ){ 298 ba[i] = EEPROM.read((address*4)+i); // read the 4 bytes 299 } 300 if (( tmp < minval ) || ( tmp > maxval )) { 301 tmp = defaultval ; 302 for ( i = 0 ; i < 4 ; i++ ){ 303 EEPROM.write((address*4)+i , ba[i] ); 304 EEPROM.commit(); // save changes in one go ??? 305 } 306 } 307 return(tmp); 308} 309int LoadLongFromEEPROM(int address,long minval,long maxval, long defaultval){ 310long tmp ; 311int i ; 312byte *ba ; 313 314 ba =(byte *)&tmp ; // set the byte array to point at the long 315 for ( i = 0 ; i < 4 ; i++ ){ 316 ba[i] = EEPROM.read((address*4)+i); // read the 4 bytes 317 } 318 if (( tmp < minval ) || ( tmp > maxval )) { 319 tmp = defaultval ; 320 for ( i = 0 ; i < 4 ; i++ ){ 321 EEPROM.write((address*4)+i , ba[i] ); 322 EEPROM.commit(); // save changes in one go ??? 323 } 324 } 325 return(tmp); 326} 327float LoadFloatFromEEPROM(int address,float minval,float maxval, float defaultval){ 328float tmp ; 329int i ; 330byte *ba ; 331 332 ba =(byte *)&tmp ; // set the byte array to point at the long 333 for ( i = 0 ; i < 4 ; i++ ){ 334 ba[i] = EEPROM.read((address*4)+i); // read the 4 bytes 335 } 336 if (( tmp < minval ) || ( tmp > maxval )) { 337 tmp = defaultval ; 338 for ( i = 0 ; i < 4 ; i++ ){ 339 EEPROM.write((address*4)+i , ba[i] ); 340 EEPROM.commit(); // save changes in one go ??? 341 } 342 } 343 return(tmp); 344} 345void SaveFloatToEEPROM(int address,float val){ 346float tmp ; 347int i ; 348byte *ba ; 349 tmp = val ; 350 ba =(byte *)&tmp ; // set the byte array to point at the long 351 for ( i = 0 ; i < 4 ; i++ ){ 352 EEPROM.write((address*4)+i , ba[i] ); 353 } 354} 355void SaveLongToEEPROM(int address,long val){ 356long tmp ; 357int i ; 358byte *ba ; 359 tmp = val ; 360 ba =(byte *)&tmp ; // set the byte array to point at the long 361 for ( i = 0 ; i < 4 ; i++ ){ 362 EEPROM.write((address*4)+i , ba[i] ); 363 } 364} 365void SaveIntToEEPROM(int address,int val){ 366int dummy1 = 0 ; 367int tmp ; 368int dummy2 = 0 ; 369int i ; 370byte *ba ; 371 tmp = val ; 372 ba =(byte *)&tmp ; // set the byte array to point at the long 373 for ( i = 0 ; i < 4 ; i++ ){ 374 EEPROM.write((address*4)+i , ba[i] ); 375 } 376} 377 378void LoadParamsFromEEPROM(bool bLoad){ 379long lTmp ; 380 if ( bLoad ) { 381 lOnTime = LoadLongFromEEPROM(0,500,100000,4000); // On time in ms 382 lOffTime = LoadLongFromEEPROM(1,500,100000, 26000); // Off time in ms 383 lCycles = LoadLongFromEEPROM(2,0,100000,32000); // maximum no of cycles 384 385 dblMLPerSecond = LoadFloatFromEEPROM(3,10,1000.0,100.0); // pump rate 386 dblQty = LoadFloatFromEEPROM(4,0,100000,0); // Total Qty Required Literds 387 lPrime = LoadLongFromEEPROM(5,500,32000, 1000); // Off time in ms 388 lTmp = LoadLongFromEEPROM(6,1,10, 0); // start and run 389 if (lTmp != 0){ 390 bOnOff = true ; 391 } 392 PWM_inc = LoadLongFromEEPROM(7,0,50, 0); // pwm increment 0 is no PWM 393 }else{ 394 SaveLongToEEPROM(0,lOnTime ); 395 SaveLongToEEPROM(1 , lOffTime ); 396 SaveLongToEEPROM(2, lCycles ); 397 SaveFloatToEEPROM(3 , dblMLPerSecond ); 398 SaveFloatToEEPROM(4 , dblQty ); 399 SaveLongToEEPROM(5 , lPrime ); 400 if ( bOnOff ){ 401 SaveLongToEEPROM(6 , 1 ); 402 }else{ 403 SaveLongToEEPROM(6 , 0 ); 404 } 405 SaveLongToEEPROM(7, PWM_inc ); 406 EEPROM.commit(); // save changes in one go ??? 407 } 408} 409 410 411void setup() { 412 delay(1000); 413 Serial.begin(115200); 414 Serial.setDebugOutput(true); 415 Serial.print("\ 416Chip ID "); 417 Serial.println(ESP.getChipId(), HEX); 418 Serial.println("Configuring access point..."); 419 /* You can remove the password parameter if you want the AP to be open. */ 420 WiFi.softAP(ssid, password); 421 422 if (MDNS.begin(host)) { 423 MDNS.addService("http", "tcp", 80); 424 Serial.println("MDNS responder started"); 425 Serial.print("You can now connect to http://"); 426 Serial.print(host); 427 Serial.println(".local"); 428 } 429 430 IPAddress myIP = WiFi.softAPIP(); 431 Serial.print("AP IP address: "); 432 Serial.println(myIP); 433 server.on("/", handleRoot); 434 server.onNotFound(handleNotFound); 435 server.begin(); 436 Serial.println("HTTP server started"); 437 438 pinMode(BUILTIN_LED,OUTPUT); 439 pinMode(MOTOR1,OUTPUT); 440 pinMode(BEEPER,OUTPUT); 441 pinMode(SCOPE_PIN,OUTPUT); 442 digitalWrite(MOTOR1,LOW); // Off I think 443 digitalWrite(BEEPER,LOW); 444 445 EEPROM.begin(512); 446 LoadParamsFromEEPROM(true); 447// dnsServer.setTTL(300); 448// dnsServer.setErrorReplyCode(DNSReplyCode::ServerFailure); 449// dnsServer.start(53,"injector.local",myIP); 450} 451 452void loop() { 453long lTime ; 454 server.handleClient(); 455 456 lTime = millis() ; 457 lOffCounter = constrain(lOffCounter,0, lOffTime); 458 if (lPrime > lOnTime ){ 459 lOnCounter = constrain(lOnCounter,0, lPrime); 460 }else{ 461 lOnCounter = constrain(lOnCounter,0, lOnTime); 462 } 463 lCyclesCounter = constrain(lCyclesCounter,0, 100000); 464 465 if (( lCycles > 0 ) || ( dblQty > 0 )){ 466 if ((dblCurrentQty >= dblQty )|| (!bOnOff ) || (lCyclesCounter >= lCycles)){ 467 bState = false ; 468 if ( bOnOff ){ 469 iFinish = 1 ; 470 } 471 bOnOff = false ; 472 } 473 } 474 if (( lTimePrev2 ) < lTime ){ // look every 2 ms 475 if ((bState)|| (bPrime )){ // soft starter 476 if ( iOut1 < 1023 ){ // speed up 477 iOut1 =iOut1 + PWM_inc ; 478 if ( iOut1 > 1023 ){ 479 iOut1 = 1023 ; 480 } 481 } 482 }else{ 483 if ( iOut1 > 0 ){ // slow down 484 iOut1 = iOut1 - PWM_inc ; 485 if (iOut1 < 0 ){ 486 iOut1 = 0 ; 487 } 488 } 489 } 490 lTimePrev2 = lTime ; 491 } 492 if (lTimePrev > ( lTime + 100000 )){ // has wrapped around so back to zero 493 lTimePrev = lTime ; // skip a bit 494 Serial.println("Wrap around"); 495 } 496 497 if (( lTimePrev + 100 ) < lTime ){ // look every 1/10 of a second ish 498 if (( bState) || ( bPrime )) { // true is on - assume called once per second 499 lOnCounter+= (lTime - lTimePrev) ; 500 if (bPrime){ 501 if ( lOnCounter >= lPrime ){ 502 Serial.println("prime complete"); 503 lOnCounter = 0 ; 504 bPrime = false ; 505 bState = false ; 506 } 507 }else{ 508 if ( lOnCounter >= lOnTime ){ 509 lOnCounter = 0 ; 510 lCyclesCounter++ ; 511 bState = !bState ; 512 } 513 } 514 dblCurrentQty += ( dblMLPerSecond * (float(lTime - lTimePrev)/1000))/1000 ; //work out how much 515 }else{ 516 if (bOnOff){ 517 lOffCounter += (lTime - lTimePrev) ; 518 digitalWrite(BUILTIN_LED,!digitalRead(BUILTIN_LED)); 519 if ( lOffCounter >= lOffTime ) { 520 lOffCounter = 0 ; 521 bState = !bState ; 522 } 523 }else{ 524 lOffCounter = 0 ; 525 } 526 } 527 lTimePrev += 100 ; 528 } 529 if ( PWM_inc > 0 ){ 530 analogWrite(MOTOR1,iOut1) ; // soft start the motor 531 }else{ 532 if (bState) { 533 digitalWrite(MOTOR1,true) ; // using a realy clunck clunk 534 }else{ 535 digitalWrite(MOTOR1,false) ; 536 } 537 } 538// analogWrite(MOTOR2,iOut2) ; // soft start the motor 539 540 if (rtc_sec != second() ) { 541 digitalWrite(BUILTIN_LED,!digitalRead(BUILTIN_LED)); 542 if (iFinish < 31 ){ 543 iFinish++ ; 544 } 545 if ((iFinish < 30 )&& (iFinish >0 )){ 546 digitalWrite(BEEPER,!digitalRead(BEEPER)); 547 }else{ 548 digitalWrite(BEEPER,0); 549 } 550 551 rtc_sec = second(); 552// if ( iOut1 > 0 ) 553// Serial.println(iOut1); 554 } 555 digitalWrite(SCOPE_PIN,!digitalRead(SCOPE_PIN)); // my scope says we are doing this loop at an unreasonable speed except when we do web stuff 556// dnsServer.processNextRequest(); 557} 558
h2o2Injector.ino Ver 2.1
c_cpp
This version can drive a relay or FET board.
1#include <ESP8266WiFi.h> 2#include <WiFiClient.h> 3#include <ESP8266WebServer.h> 4#include 5 <ESP8266mDNS.h> 6//#include <DNSServer.h> 7#include <TimeLib.h> 8//#include 9 <Wire.h> 10//#include <SPI.h> 11#include <EEPROM.h> 12 13const byte MOTOR1 = 14 D7 ; // PWM 15const byte BEEPER = D8 ; // pezo 16const byte SCOPE_PIN = D5 17 ; // for cycle timer measure 18 19 20/* Set these to your desired credentials. 21 */ 22const char *ssid = "Injector"; 23const char *password = "password"; 24const 25 char *host = "injector"; 26 27byte rtc_sec ; 28byte rtc_min ; 29byte rtc_hour 30 ; 31int iOut1 = 0 ; 32int iOut2 = 0 ; 33long lPrime ; 34long lOnTime ; 35long 36 lOffTime ; 37long lOnCounter ; 38long lOffCounter ; 39int lCyclesCounter ; 40int 41 lCycles ; 42float dblMLPerSecond ; 43float dblQty ; 44float dblCurrentQty ; 45 46bool bState ; 47bool bOnOff = false ; 48bool bPrime = false ; 49int iCurPos 50 ; 51long lTimePrev ; 52long lTimePrev2 ; 53int iFinish = 30 ; 54long PWM_inc 55 = 5 ; 56 57ESP8266WebServer server(80); 58//DNSServer dnsServer; 59 60/* Just 61 a little test message. Go to http://192.168.4.1 in a web browser 62 * connected 63 to this access point to see it. 64 */ 65void handleNotFound(){ 66 String message 67 = "Seriously - No way DUDE\ 68\ 69"; 70 message += "URI: "; 71 message += 72 server.uri(); 73 message += "\ 74Method: "; 75 message += (server.method() 76 == HTTP_GET)?"GET":"POST"; 77 message += "\ 78Arguments: "; 79 message 80 += server.args(); 81 message += "\ 82"; 83 for (uint8_t i=0; i<server.args(); 84 i++){ 85 message += " NAME:"+server.argName(i) + "\ 86 VALUE:" + server.arg(i) 87 + "\ 88"; 89 } 90 server.send(404, "text/plain", message); 91 Serial.print(message); 92} 93 94 95 96void handleRoot() { 97 boolean currentLineIsBlank = true; 98 char buff[40] 99 ; 100 long i = 0 ; 101 102 String message = "Web Request URI: "; 103 message 104 += server.uri(); 105 message += "\ 106Method: "; 107 message += (server.method() 108 == HTTP_GET)?"GET":"POST"; 109 message += "\ 110Arguments: "; 111 message 112 += server.args(); 113 message += "\ 114"; 115 for (uint8_t i=0; i<server.args(); 116 i++){ 117 message += " NAME:"+server.argName(i) + "\ 118 VALUE:" + server.arg(i) 119 + "\ 120"; 121 } 122 Serial.println(message); 123 124 for (uint8_t j=0; j<server.args(); 125 j++){ 126 i = String(server.argName(j)).indexOf("command"); 127 if (i != 128 -1){ // have a request to set the time zone 129 switch (String(server.arg(j)).toInt()){ 130 131 case 1: // load values 132 LoadParamsFromEEPROM(true); 133 Serial.println("Load 134 from EEPROM"); 135 break; 136 case 2: // Save values 137 LoadParamsFromEEPROM(false); 138 139 Serial.println("Save to EEPROM"); 140 break; 141 case 142 3: // prime command 143 bPrime = true ; 144 Serial.println("Prime 145 Pumps"); 146 break; 147 case 4: // Clear current qty 148 dblCurrentQty 149 = 0 ; 150 Serial.println("Clear current qty"); 151 break; 152 153 case 5: // Clear current qty 154 lCyclesCounter = 0 ; 155 Serial.println("Clear 156 current cycles"); 157 break; 158 } 159 } 160 i = String(server.argName(j)).indexOf("prime"); 161 162 if (i != -1){ // have a request to set the time zone 163 lPrime = String(server.arg(j)).toInt() 164 ; 165 if (lPrime > 32000 ){ 166 lPrime = 32000 ; 167 } 168 if 169 ( lPrime < 500 ){ 170 lPrime = 500 ; 171 } 172 } 173 174 175 i = String(server.argName(j)).indexOf("timon"); 176 if (i != -1){ // have 177 a request to set the time zone 178 lOnTime = String(server.arg(j)).toInt() 179 ; 180 if ( lOnTime > 100000 ){ 181 lOnTime = 100000 ; 182 } 183 184 if ( lOnTime < 1000 ){ 185 lOnTime = 1000 ; 186 } 187 } 188 189 i = String(server.argName(j)).indexOf("timof"); 190 if (i != -1){ // have 191 a request to set the time zone 192 lOffTime = String(server.arg(j)).toInt() 193 ; 194 if ( lOffTime > 100000 ){ 195 lOffTime = 100000 ; 196 } 197 198 if ( lOffTime < 1000 ){ 199 lOffTime = 1000 ; 200 } 201 } 202 203 i = String(server.argName(j)).indexOf("cycnt"); 204 if (i != -1){ // have 205 a request to set the time zone 206 lCycles = String(server.arg(j)).toInt() 207 ; 208 if ( lCycles > 32000 ){ 209 lCycles = 32000 ; 210 } 211 if 212 ( lCycles < 0 ){ 213 lCycles = 0 ; 214 } 215 } 216 i = 217 String(server.argName(j)).indexOf("pwminc"); 218 if (i != -1){ // have a request 219 to set the time zone 220 PWM_inc = String(server.arg(j)).toInt() ; 221 if 222 ( PWM_inc > 50 ){ 223 PWM_inc = 50 ; 224 } 225 if ( PWM_inc < 0 226 ){ 227 PWM_inc = 0 ; 228 } 229 } 230 i = String(server.argName(j)).indexOf("pumpea"); 231 232 if (i != -1){ // have a request to set the time zone 233 if ( String(server.arg(j)).toInt()== 234 1){ //on 235 bOnOff = true ; 236 bState = true ; 237 }else{ 238 239 bOnOff = false ; 240 bState = false ; 241 } 242 243 } 244 245 i = String(server.argName(j)).indexOf("pmlps"); // 246 pump ml per second 247 if (i != -1){ // have a request to set the latitude 248 249 dblMLPerSecond = String(server.arg(j)).toFloat() ; 250 if ( dblMLPerSecond 251 < 50){ 252 dblMLPerSecond = 50 ; 253 } 254 if ( dblMLPerSecond 255 > 10000 ){ 256 dblMLPerSecond = 10000 ; 257 } 258 } 259 260 i = String(server.argName(j)).indexOf("quant"); // maximum qty to be pumped 261 262 if (i != -1){ // have a request to set the latitude 263 dblQty = String(server.arg(j)).toFloat() 264 ; 265 if ( dblQty < 0){ 266 dblQty = 0 ; 267 } 268 if ( dblQty 269 > 100000 ){ 270 dblQty = 100000 ; 271 } 272 } 273 274 275 } 276 277 server.sendHeader("Server","ESP8266-on-steroids",false); 278 279 server.sendHeader("X-Powered-by","Dougal-1.0",false); 280 server.setContentLength(CONTENT_LENGTH_UNKNOWN); 281 282 server.send(200, "text/html", ""); 283 server.sendContent("<!DOCTYPE HTML>"); 284 285 server.sendContent("<head><title>Team Trouble - Chemical Injector</title>"); 286 287 server.sendContent("<meta name=viewport content='width=320, auto inital-scale=1'>"); 288 289 290 server.sendContent("</head><body><html><center><h2>Chemical Injector Mk2.1</h2>"); 291 292 293 server.sendContent("<a href='/'>Refresh</a><br><br>") ; 294 server.sendContent("<a 295 href='/?command=2'>Save Parameters to EEPROM</a><br>") ; 296 297 server.sendContent("<table 298 border=1 title='Pump Control'>"); 299 server.sendContent("<tr><th> Parameter</th><th>Value</th><th>.</th></tr>"); 300 301 302 server.sendContent("<form method=get action=/><tr><td>Pump Control</td><td align=center><select 303 name='pumpea'>") ; 304 if (bOnOff){ 305 server.sendContent("<option value='0' 306 >OFF<option value='1' SELECTED>ON"); 307 }else{ 308 server.sendContent("<option 309 value='0' SELECTED>OFF<option value='1'>ON"); 310 } 311 server.sendContent("</select></td><td><input 312 type='submit' value='SET'></td></tr></form>"); 313 314 server.sendContent("<form 315 method=get action=" + server.uri() + "><tr><td>Time On (ms)</td><td align=center>") 316 ; 317 server.sendContent("<input type='text' name='timon' value='" + String(lOnTime) 318 + "' size=6></td><td><input type='submit' value='SET'></td></tr></form>"); 319 320 321 server.sendContent("<form method=get action=" + server.uri() + "><tr><td>Time 322 Off (ms)</td><td align=center>") ; 323 server.sendContent("<input type='text' 324 name='timof' value='" + String(lOffTime) + "' size=6></td><td><input type='submit' 325 value='SET'></td></tr></form>"); 326 327 server.sendContent("<form method=get 328 action=" + server.uri() + "><tr><td><a href='/?command=3' title='Click to Prime 329 Pump'>Prime Time (ms)</a></td><td align=center>") ; 330 server.sendContent("<input 331 type='text' name='prime' value='" + String(lPrime) + "' size=6></td><td><input 332 type='submit' value='SET'></td></tr></form>"); 333 334 server.sendContent("<form 335 method=get action=" + server.uri() + "><tr><td>Max Cycles</td><td align=center>") 336 ; 337 server.sendContent("<input type='text' name='cycnt' value='" + String(lCycles) 338 + "' size=6></td><td><input type='submit' value='SET'></td></tr></form>"); 339 340 341 server.sendContent("<form method=get action=" + server.uri() + "><tr><td>ml 342 Per Second</td><td align=center>") ; 343 server.sendContent("<input type='text' 344 name='pmlps' value='" + String(dblMLPerSecond,2) + "' size=6></td><td><input type='submit' 345 value='SET'></td></tr></form>"); 346 347 server.sendContent("<form method=get 348 action=" + server.uri() + "><tr><td>Max Quanity (l)</td><td align=center>") ; 349 350 server.sendContent("<input type='text' name='quant' value='" + String(dblQty,2) 351 + "' size=6></td><td><input type='submit' value='SET'></td></tr></form>"); 352 353 354 server.sendContent("<form method=get action=" + server.uri() + "><tr><td>PWM 355 inc (0 Disable)</td><td align=center>") ; 356 server.sendContent("<input type='text' 357 name='pwminc' value='" + String(PWM_inc) + "' size=6></td><td><input type='submit' 358 value='SET'></td></tr></form>"); 359 360 server.sendContent("<tr><td><a href='/?command=4' 361 title='click to clear'>Current Qty</a></td><td align=center>" + String(dblCurrentQty,3) 362 + "</td><td>(l)</td></tr>"); 363// server.sendContent("<tr><td>Current On Counter</td><td 364 align=center>" + String(lOnCounter) + "</td><td>(ms)</td></tr>"); 365// server.sendContent("<tr><td>Current 366 Off Counter</td><td align=center>" + String(lOffCounter) + "</td><td>(ms)</td></tr>"); 367 368 server.sendContent("<tr><td><a href='/?command=5' title='click to clear'>Current 369 Cycles</td><td align=center>" + String(lCyclesCounter) + "</a></td><td>.</td></tr>"); 370 371 server.sendContent("</table>"); 372 server.sendContent("<a href='/?command=1'>Load 373 Parameters from EEPROM</a><br>") ; 374 server.sendContent("</body></html>\ \ 375"); 376 377 378} 379 380void FloatToModbusWords(float src_value , uint16_t * dest_lo , uint16_t 381 * dest_hi ) { 382 uint16_t tempdata[2] ; 383 float *tf ; 384 tf = (float * )&tempdata[0] 385 ; 386 *tf = src_value ; 387 *dest_lo = tempdata[1] ; 388 *dest_hi = tempdata[0] 389 ; 390} 391float FloatFromModbusWords( uint16_t dest_lo , uint16_t dest_hi ) { 392 393 uint16_t tempdata[2] ; 394 float *tf ; 395 tf = (float * )&tempdata[0] ; 396 397 tempdata[1] = dest_lo ; 398 tempdata[0] = dest_hi ; 399 return (*tf) ; 400} 401int 402 NumberOK (float target) { 403 int tmp = 0 ; 404 tmp = isnan(target); 405 if ( 406 tmp != 1 ) { 407 tmp = isinf(target); 408 } 409 return (tmp); 410} 411 412int 413 LoadIntFromEEPROM(int address,int minval,int maxval, int defaultval){ 414int dummy1 415 = 0 ; // belt and braces ... dont know which way the stack works 416int tmp ; 417int 418 dummy2 = 0 ; // yep write this one as well ... maybe 419int i ; 420byte *ba ; 421 422 423 ba =(byte *)&tmp ; // set the byte array to point at the long 424 for ( i = 0 425 ; i < 4 ; i++ ){ 426 ba[i] = EEPROM.read((address*4)+i); // read the 4 bytes 427 428 } 429 if (( tmp < minval ) || ( tmp > maxval )) { 430 tmp = defaultval ; 431 432 for ( i = 0 ; i < 4 ; i++ ){ 433 EEPROM.write((address*4)+i , ba[i] ); 434 435 EEPROM.commit(); // save changes in one go ??? 436 } 437 } 438 439 return(tmp); 440} 441int LoadLongFromEEPROM(int address,long minval,long maxval, 442 long defaultval){ 443long tmp ; 444int i ; 445byte *ba ; 446 447 ba =(byte *)&tmp 448 ; // set the byte array to point at the long 449 for ( i = 0 ; i < 4 ; i++ ){ 450 451 ba[i] = EEPROM.read((address*4)+i); // read the 4 bytes 452 } 453 if (( tmp 454 < minval ) || ( tmp > maxval )) { 455 tmp = defaultval ; 456 for ( i = 0 ; 457 i < 4 ; i++ ){ 458 EEPROM.write((address*4)+i , ba[i] ); 459 EEPROM.commit(); 460 // save changes in one go ??? 461 } 462 } 463 return(tmp); 464} 465float 466 LoadFloatFromEEPROM(int address,float minval,float maxval, float defaultval){ 467float 468 tmp ; 469int i ; 470byte *ba ; 471 472 ba =(byte *)&tmp ; // set the byte 473 array to point at the long 474 for ( i = 0 ; i < 4 ; i++ ){ 475 ba[i] = EEPROM.read((address*4)+i); 476 // read the 4 bytes 477 } 478 if (( tmp < minval ) || ( tmp > maxval )) { 479 480 tmp = defaultval ; 481 for ( i = 0 ; i < 4 ; i++ ){ 482 EEPROM.write((address*4)+i 483 , ba[i] ); 484 EEPROM.commit(); // save changes in one go ??? 485 } 486 487 } 488 return(tmp); 489} 490void SaveFloatToEEPROM(int address,float val){ 491float 492 tmp ; 493int i ; 494byte *ba ; 495 tmp = val ; 496 ba =(byte *)&tmp ; // 497 set the byte array to point at the long 498 for ( i = 0 ; i < 4 ; i++ ){ 499 EEPROM.write((address*4)+i 500 , ba[i] ); 501 } 502} 503void SaveLongToEEPROM(int address,long val){ 504long 505 tmp ; 506int i ; 507byte *ba ; 508 tmp = val ; 509 ba =(byte *)&tmp ; // 510 set the byte array to point at the long 511 for ( i = 0 ; i < 4 ; i++ ){ 512 EEPROM.write((address*4)+i 513 , ba[i] ); 514 } 515} 516void SaveIntToEEPROM(int address,int val){ 517int dummy1 518 = 0 ; 519int tmp ; 520int dummy2 = 0 ; 521int i ; 522byte *ba ; 523 tmp = 524 val ; 525 ba =(byte *)&tmp ; // set the byte array to point at the long 526 for 527 ( i = 0 ; i < 4 ; i++ ){ 528 EEPROM.write((address*4)+i , ba[i] ); 529 } 530} 531 532void 533 LoadParamsFromEEPROM(bool bLoad){ 534long lTmp ; 535 if ( bLoad ) { 536 lOnTime 537 = LoadLongFromEEPROM(0,500,100000,4000); // On time in ms 538 lOffTime 539 = LoadLongFromEEPROM(1,500,100000, 26000); // Off time in ms 540 lCycles 541 = LoadLongFromEEPROM(2,0,100000,32000); // maximum no of cycles 542 543 544 dblMLPerSecond = LoadFloatFromEEPROM(3,10,1000.0,100.0); // pump 545 rate 546 dblQty = LoadFloatFromEEPROM(4,0,100000,0); // Total 547 Qty Required Literds 548 lPrime = LoadLongFromEEPROM(5,500,32000, 1000); // 549 Off time in ms 550 lTmp = LoadLongFromEEPROM(6,1,10, 0); // 551 start and run 552 if (lTmp != 0){ 553 bOnOff = true ; 554 } 555 556 PWM_inc = LoadLongFromEEPROM(7,0,50, 0); // pwm increment 557 0 is no PWM 558 }else{ 559 SaveLongToEEPROM(0,lOnTime ); 560 SaveLongToEEPROM(1 561 , lOffTime ); 562 SaveLongToEEPROM(2, lCycles ); 563 SaveFloatToEEPROM(3 , 564 dblMLPerSecond ); 565 SaveFloatToEEPROM(4 , dblQty ); 566 SaveLongToEEPROM(5 567 , lPrime ); 568 if ( bOnOff ){ 569 SaveLongToEEPROM(6 , 1 ); 570 }else{ 571 572 SaveLongToEEPROM(6 , 0 ); 573 } 574 SaveLongToEEPROM(7, PWM_inc 575 ); 576 EEPROM.commit(); // save changes in one go ??? 577 } 578} 579 580 581void 582 setup() { 583 delay(1000); 584 Serial.begin(115200); 585 Serial.setDebugOutput(true); 586 587 Serial.print("\ 588Chip ID "); 589 Serial.println(ESP.getChipId(), HEX); 590 591 Serial.println("Configuring access point..."); 592 /* You can remove the password 593 parameter if you want the AP to be open. */ 594 WiFi.softAP(ssid, password); 595 596 597 if (MDNS.begin(host)) { 598 MDNS.addService("http", "tcp", 80); 599 Serial.println("MDNS 600 responder started"); 601 Serial.print("You can now connect to http://"); 602 603 Serial.print(host); 604 Serial.println(".local"); 605 } 606 607 IPAddress 608 myIP = WiFi.softAPIP(); 609 Serial.print("AP IP address: "); 610 Serial.println(myIP); 611 612 server.on("/", handleRoot); 613 server.onNotFound(handleNotFound); 614 server.begin(); 615 616 Serial.println("HTTP server started"); 617 618 pinMode(BUILTIN_LED,OUTPUT); 619 620 pinMode(MOTOR1,OUTPUT); 621 pinMode(BEEPER,OUTPUT); 622 pinMode(SCOPE_PIN,OUTPUT); 623 624 digitalWrite(MOTOR1,LOW); // Off I think 625 digitalWrite(BEEPER,LOW); 626 627 628 EEPROM.begin(512); 629 LoadParamsFromEEPROM(true); 630// dnsServer.setTTL(300); 631// 632 dnsServer.setErrorReplyCode(DNSReplyCode::ServerFailure); 633// dnsServer.start(53,"injector.local",myIP); 634} 635 636void 637 loop() { 638long lTime ; 639 server.handleClient(); 640 641 lTime = millis() 642 ; 643 lOffCounter = constrain(lOffCounter,0, lOffTime); 644 if (lPrime > lOnTime 645 ){ 646 lOnCounter = constrain(lOnCounter,0, lPrime); 647 }else{ 648 lOnCounter 649 = constrain(lOnCounter,0, lOnTime); 650 } 651 lCyclesCounter = constrain(lCyclesCounter,0, 652 100000); 653 654 if (( lCycles > 0 ) || ( dblQty > 0 )){ 655 if ((dblCurrentQty 656 >= dblQty )|| (!bOnOff ) || (lCyclesCounter >= lCycles)){ 657 bState = false 658 ; 659 if ( bOnOff ){ 660 iFinish = 1 ; 661 } 662 bOnOff = 663 false ; 664 } 665 } 666 if (( lTimePrev2 ) < lTime ){ // look every 2 ms 667 668 if ((bState)|| (bPrime )){ // soft starter 669 if ( iOut1 < 1023 670 ){ // speed up 671 iOut1 =iOut1 + PWM_inc ; 672 if ( iOut1 > 1023 673 ){ 674 iOut1 = 1023 ; 675 } 676 } 677 }else{ 678 if 679 ( iOut1 > 0 ){ // slow down 680 iOut1 = iOut1 - PWM_inc ; 681 if 682 (iOut1 < 0 ){ 683 iOut1 = 0 ; 684 } 685 } 686 } 687 lTimePrev2 688 = lTime ; 689 } 690 if (lTimePrev > ( lTime + 100000 )){ // has wrapped around 691 so back to zero 692 lTimePrev = lTime ; // skip a bit 693 Serial.println("Wrap 694 around"); 695 } 696 697 if (( lTimePrev + 100 ) < lTime ){ // look every 1/10 698 of a second ish 699 if (( bState) || ( bPrime )) { // true is on - assume called 700 once per second 701 lOnCounter+= (lTime - lTimePrev) ; 702 if (bPrime){ 703 704 if ( lOnCounter >= lPrime ){ 705 Serial.println("prime complete"); 706 707 lOnCounter = 0 ; 708 bPrime = false ; 709 bState = false 710 ; 711 } 712 }else{ 713 if ( lOnCounter >= lOnTime ){ 714 715 lOnCounter = 0 ; 716 lCyclesCounter++ ; 717 bState = 718 !bState ; 719 } 720 } 721 dblCurrentQty += ( dblMLPerSecond * (float(lTime 722 - lTimePrev)/1000))/1000 ; //work out how much 723 }else{ 724 if (bOnOff){ 725 726 lOffCounter += (lTime - lTimePrev) ; 727 digitalWrite(BUILTIN_LED,!digitalRead(BUILTIN_LED)); 728 729 if ( lOffCounter >= lOffTime ) { 730 lOffCounter = 0 ; 731 732 bState = !bState ; 733 } 734 }else{ 735 lOffCounter 736 = 0 ; 737 } 738 } 739 lTimePrev += 100 ; 740 } 741 if 742 ( PWM_inc > 0 ){ 743 analogWrite(MOTOR1,iOut1) ; // soft start the motor 744 745 }else{ 746 if (bState) { 747 digitalWrite(MOTOR1,true) ; // using a realy 748 clunck clunk 749 }else{ 750 digitalWrite(MOTOR1,false) ; 751 } 752 753 } 754// analogWrite(MOTOR2,iOut2) ; // soft start the motor 755 756 if (rtc_sec 757 != second() ) { 758 digitalWrite(BUILTIN_LED,!digitalRead(BUILTIN_LED)); 759 760 if (iFinish < 31 ){ 761 iFinish++ ; 762 } 763 if ((iFinish < 30 )&& 764 (iFinish >0 )){ 765 digitalWrite(BEEPER,!digitalRead(BEEPER)); 766 }else{ 767 768 digitalWrite(BEEPER,0); 769 } 770 771 rtc_sec = second(); 772// 773 if ( iOut1 > 0 ) 774// Serial.println(iOut1); 775 } 776 digitalWrite(SCOPE_PIN,!digitalRead(SCOPE_PIN)); 777 // my scope says we are doing this loop at an unreasonable speed except when we 778 do web stuff 779// dnsServer.processNextRequest(); 780} 781
Downloadable files
Circuits for Proof of concept and prototype
Mud map of circuits. All basic stuff
Circuits for Proof of concept and prototype
Circuits for Proof of concept and prototype
Mud map of circuits. All basic stuff
Circuits for Proof of concept and prototype
Comments
Only logged in users can leave comments