Components and supplies
Arduino Nano R3
NodeMCU ESP8266 Breakout Board
Wemos D1 Mini
Apps and platforms
Ubidots
Arduino IDE
Project description
Code
LoadMaster_Ubidots_Interface_LMOnly-_Release_1.0.ino
arduino
Takes a serial data stream of Loadmaster variables (Nextion Display format), Parses values and publises to Ubidots at defined interval or if status value changes (due to say an error or power fail etc). For ESP8266, Wemos D1, Node MCU etc
1/**************************************** 2 * Loadmaster MQTT (Ubidots) - Data Logger 3 * Release V1.0 4 * This interface provides an Online Dashboard and data logging function for Loadmaster, 5 * Data sets are published to the Ubidots MQTT broker. 6 * Tested on a ESP8266 / Wemos D1 Mini. The interface extracts data values from Loadmasters Nextion display serial data stream. 7 * We look for the resetting of PVWattHrs to zero as an indication of the end of a day and this triggers a publishing 8 * of the daily values 9 * Code optionally Includes I/O alarm functionality (for say flood alert or Hi-Low temperature alarms.- Requires uncommenting OR just load code already configured for Temp and IO alarms! 10 * 11 * 12 * Include Libraries 13Board NODE MCU 1.0 ESP 12E / Wemos D1 mini etc. 14PubSub client library from Nick Oleary - in the list of arduino libraries 15Ubidots ESP library V1.2 from https://github.com/ubidots/ubidots-mqtt-esp 16Follow readme instructions to install boards 17 18****************************************/ 19#include "UbidotsESPMQTT.h" 20#include <SoftwareSerial.h> 21//#include <OneWire.h> 22//#include <DallasTemperature.h> 23/**************************************** 24 * Define Constants 25 ****************************************/ 26#define TOKEN "ENTER YOUR UBIDOTS TOKEN HERE" // This is for Loasmaster Device Enter Your Ubidots device TOKEN 27#define WIFINAME "YOUR WIFI SSID HERE" //Enter Your WiFi SSID 28#define WIFIPASS "YOUR WIFI PASSWORD HERE" // Enter Your Wifi Password 29 30Ubidots client(TOKEN); 31 32unsigned long FastInterval = 900000; //Update Ubidots with TopC, MidC, BotC, Watts, Whrs & Status values every 15minutes =900,000mS, 15min=900000 33unsigned long SlowInterval = 1800000; //Update Ubidots with values every 30 minutes 1800,000ms 34unsigned long HourlyInterval = 3600000; //Update Ubidots with I/O Alarm values every 60 minutes 35unsigned long BootPublishDelay=8000; //At boot up a test publish happens after 10secs 36 37unsigned long DataRxdMillis =0; //used to detect a loss of data being received from the LoadMaster 38unsigned long LastRxdMillis; //used to detect a loss of data being received from the LoadMaster 39 40//unsigned long TempUpdateInterval=2000; //Timing for reading DS18B20 -if required 41//unsigned long IOScanInterval=100; //Timing for reading IO inputs -if I/O alarms are used 42//unsigned long LastIOScan; 43//unsigned long LastTempRead; 44 45//float MaxTempLimit =30.0; 46//float MinTempLimit =10.0; 47 48unsigned long CurrentMillis; 49 50unsigned long SafetyIntervalStart; // All publish functions are limited by an overall publishing rate safety timeout 51unsigned long SafetyIntervalDuration=300000; // We check we dont exceed 10 publish events over a 5 minute interval. 52unsigned long LastPublishMillis; 53int PublishLimit=15; 54int PublishCount; 55 56 57unsigned long ActiveUpdateInterval; // At power up the first update will ocurr after 15secs. After first publish Active update rate will depend on level of PVWatts 58 59SoftwareSerial espSerial(14, 12); // (rx, tx) GPIO14 = Wemos Pin marked D5, GPIO12 = Wemos Pin marked D6 60 61// For DS18B20 Temperature if required. Data wire to port 2 on the Arduino 62//#define ONE_WIRE_BUS D3 63 64//OneWire oneWire(ONE_WIRE_BUS); // create a oneWire instance to communicate with OneWire devices 65//DallasTemperature sensors(&oneWire); // Pass our oneWire reference to Dallas Temperature. 66 67 68//Pin Allocations 69//int LED_BUILTIN = D4; wrong 70byte RedLED = 2; //D4= GPIO-2; 71 72//Program Variables 73float BottomTemp = 0; 74float TopTemp = 0; 75float MidTemp = 0; 76float MaxTemp = 0; 77float LastWattHrs = 0; // used to determine the end of a day when loadmaster resets the WHrs value 78float MaxDailyTemp=0; 79 80//For DS18B20 Temperature sensor on D3 (D3 has a pullup and works with DS18B20 but ideally an external 2k7 pullup to 5V should be used) 81//float Temperature=0; 82 83 84int PVWatts = 0; 85int WattHrs = 0; 86int LMStatus = 0; //LoadMaster's Status code - represents the current operating status or error code 87int LastLMStatus=0; // 0=Turned OFF, 1=Running, 3=Hot, 4= Reset OFF(Power up reset), 88 89 90//For managing extra I/O Alarm inputs (Flood etc)and DS18B20 Temperature sensor 91//int AlarmStatus=0; // Alarms from IO pins 0=OK, 1 = Flood 1 on D1, 2=Flood2 on D2, 3= Both D1 and D2 triggered! 92//int LastAlarmStatus=0; // used to detect a change in alarm state. 93//unsigned long LastAlarmPublish=0; 94//unsigned long AlarmPublishInterval; 95//char IOAlarm1Str[] = "Boiler Flood"; 96 97 98 99//For creating status and max temp Context string arrays 100char context[60]; //Character array to creating context text string in Ubidots 'status' topic. see https://ubidots.com/community/t/solved-send-string-variable-in-context-with-ubidots-library-and-arduino/1631/6 101char outstr[20]; 102//char IOAlarmStr1[16]; 103//char IOAlarmStr2[16]; 104//char TempAlarmStr3[16]; 105 106//Common Variables for Serial CLI and Message Parsing 107int RxdInt1 = 0; 108const byte bufferSize = 40; // Maximum Char length of received serial messages terminated in a Linefeed. 109char ReceivedSerialChars[bufferSize]; 110char tempChars[bufferSize]; 111char VariableID[bufferSize]={0}; //populates array with null \\0 112char StatusChars[bufferSize]; 113int BufferIndex = 0; 114bool dataReady = false; 115bool Overflow = false; 116bool JustBooted = true; 117//bool EndOfDay=false; 118bool IsNumber = false; 119 120 121//---------------------------------------------------------------------------------------------- 122 123//**************************************************************************************************************************** 124// 125 126void setup() { 127 128 // Setup code goes here,runs once at boot: 129 //client.ubidotsSetBroker("industrial.api.ubidots.com"); // Sets the broker properly for the industrial account 130 Serial.begin(9600); 131 espSerial.begin(9600); 132 133 client.setDebug(false); // Pass a true or false bool value to activate debug messages 134 client.wifiConnection(WIFINAME, WIFIPASS); 135 client.begin(callback); 136 client.ubidotsSubscribe("loadmaster","switch"); // Insert the dataSource and Variable's Labels 137 138 139 ActiveUpdateInterval=BootPublishDelay; //This is used to set the first publish interval to 6 seconds..see a transmission after plugging in 140 pinMode(RedLED, OUTPUT); 141 digitalWrite(RedLED, LOW); 142 //pinMode(LED_BUILTIN, OUTPUT); 143 //digitalWrite(LED_BUILTIN, LOW); //Low is LED ON 144 145 146// pinMode(D1, INPUT); //Used for Flood sens input #1 - ***!!!!EXTERNAL PULL UPs WILL BE REQUIRED on D1&D2!!!!! 147// pinMode(D2, INPUT); //Used for Flood sens input #2 148 149 //For DS18B20 temp sensor if required 150 // sensors.begin(); 151 152 delay(400); 153 digitalWrite(RedLED, HIGH); 154 // digitalWrite(LED_BUILTIN, HIGH); //Low is LED ON 155 delay(400); 156 157 // sensors.setWaitForConversion(false); // makes it async 158 // sensors.requestTemperatures(); 159 // sensors.setWaitForConversion(true); 160 161 LastPublishMillis=millis(); 162 // LastAlarmPublish=millis(); 163 // LastTempRead =millis(); 164 165 LastRxdMillis=millis(); 166 167 Serial.println("LoadMaster Ubidots Uploader - Release V5.0"); 168 Serial.println("Setup Done"); 169 170 SafetyIntervalStart=millis(); 171 172 173 } 174 175 176 177//******* MAIN LOOP Starts Here ********************************************************************************************************* 178 179void loop() { 180 //Receive the Nextion serial data messages and extract variable data values 181RxNextionData(); //Service the software serial Port, reads in Nextion format Data values, calls Parse routine if newdata Rx'd 182 183//ReadTempSensor(); 184 185//If you wishto use an I/O alarm functions on D1 &D2, Un-comment the code below upto end of Alarm comment 186//Manage Publishing of I/O Alarm status - used for say flood Sensors / logic inputs etc 187 188/*if(millis()-LastIOScan>IOScanInterval){ //Read IO inputs every 200mS 189 if(AlarmStatusChanged()){ // Function to read sensor inputs (D1, D2 & Temp)ever 0.5S - Returns true if any sensor states changed 190 Serial.println("Alarm State Changed!!"); 191 PublishAlarm(); //publish new alarm state. 192 } 193 LastIOScan=millis(); 194} 195 196//Establish the update interval of publishing I/O Alarm Status:- 197if(JustBooted){ 198 AlarmPublishInterval=BootPublishDelay; 199 } 200else if(AlarmStatus==0){ 201 AlarmPublishInterval=HourlyInterval; // no alarm condition is present - i.e D1 or D2 pulled high 202} 203else { 204 AlarmPublishInterval 205 =SlowInterval; // alarm condition active - i.e D1 or D2 pulled high, 30 min publishing 206} 207 208 209if(millis()-LastAlarmPublish > AlarmPublishInterval){ 210 PublishAlarm(); //publish new alarm state 211 LastAlarmPublish=millis(); 212 } 213 214 //End of Code to publish I/O Alarms 215*/ 216 217 218// Check the MQTT connection and subscribing to the required topic(s) plus publishing appropriate data sets to the MQTT Broker:- 219if(!client.connected()){ 220 client.reconnect(); 221 client.ubidotsSubscribe("loadmaster", "switch"); // Insert the dataSource and Variable's Labels 222 } 223 224//Determine the currrent logging rate:- following bootup it publishes after 10secs, then every 15min in daytime or 60mins at night 225 226 if(JustBooted){ 227 ActiveUpdateInterval=BootPublishDelay; 228 } 229 else if (PVWatts>2){ 230 ActiveUpdateInterval = FastInterval; //We have faster logging of data in daytime - 10mins 231 } 232 else { 233 ActiveUpdateInterval = SlowInterval; 234 } 235 236 237//Is it time to send main data values to Ubidots via MQTT? 238 239if((millis()- LastPublishMillis)> ActiveUpdateInterval) { //Publish main Data at required update interval ONLY during daytime 240 JustBooted=false; 241 242 PublishMainData(); //Function to Publish the regular data set - 15min interval during daytime, Hrly at night 243 LastPublishMillis = millis(); 244 245 LastLMStatus = LMStatus; //Remember the last published status, if it changes we publish again 246 if(PVWatts>2 && WattHrs>10 ){ //when publishing data in any sunshine, update the daily max temperature which is logged at end of day data 247 MaxDailyTemp=MaxTemp; 248 } 249 } 250 251 252 253if (LossOfDatafromLM()&& LMStatusChanged()){ //Loss of LoadMaster serial data input?, Sets LMStatus to 99 to communicate a Loss of Loadmaster data input 254 Serial.println("No Serial Data from Loadmaster"); 255 PublishMainData(); 256 // PublishSwitch(); 257 } 258 259 260// Publish data if Loadmaster Status has just changed - publish changed status so we can quickly report errors etc 261if(!JustBooted && LMStatusChanged()){ //Loadmaster State just changed - i.e system turned off? a temp sensor error? etc - publish the status urgently for display or button control 262 PublishMainData(); 263 PublishSwitch(); 264} 265 266 267// Publish end of day 'Daily' values 268 if(EndOfDay()){ // Returns true when it sees LoadMasters PVWhrs value reset to zero at the end of a day (3 hrs of darkness) 269 PublishDailyData(); 270 LastWattHrs=0; // Clear values ready for the next day 271 } 272 else{ 273 LastWattHrs=WattHrs; 274 } 275 276//Publish alarm IO status - usually only at slow interval, or fast interval if alarm state is present 277 278 client.loop(); // we must do this to check for subscribed data...or you only get it every 15min or 60min during publishes! 279 280} 281 282 283//******END OF MAIN LOOP **************************************************************************************** 284/****************************************************************************************************************/ 285// * Subroutine Functions Below:- 286/*--------------------------------------------------------------------------------------------------------------*/ 287 288//CallBack Subscribe function for Ubidots Library 289 290void callback(char* topic, byte* payload, unsigned int length) { 291 292 // To see subscribed message, un comment code below: 293 //Serial.print("Msg arrived"); 294 //delay(250); 295 296 // Serial.print(topic); 297 // Serial.print("] "); 298 // for (int i=0;i<length;i++) { 299 // Serial.print((char)payload[i]); 300 // } 301 // Serial.println(); 302 303 if ((char)payload[0] == '1') { 304 digitalWrite(16, HIGH); 305 if(JustBooted==false){ 306 Serial.println("Switch.val=1"); //Nextion format command to turn System ON (same message as button press on LCD) 307 espSerial.println("Switch.val=1"); // also send this to LoadMaster - for remote turn on / off 308 } 309 } 310 else { 311 digitalWrite(16, LOW); 312 if(JustBooted==false){ 313 Serial.println("Switch.val=0"); //Nextion format command to turn System OFF 314 espSerial.println("Switch.val=0"); // also send this to LoadMaster - for remote turn on / off 315 } 316 } 317} 318 319 320//******************************************************************************************************* 321 322void RxNextionData (){ //Function to receive Nextion data on Software Serial Port 323 324 char RxdChar; 325 static uint8_t charCount; 326 static uint8_t ffCount; 327 328 while (espSerial.available() > 0 && dataReady == false) { 329 RxdChar = espSerial.read(); 330 // Serial.println(RxdChar); // for testing - to see every rx'd character 331 332 if (RxdChar == 0xff) { 333 ++ffCount; 334 if (ffCount >= 3) { //Nextion display messages are terminated with 0xFF 0xFF 0xFF 335 ffCount = 0; 336 ReceivedSerialChars[BufferIndex] = '\\0'; // terminate the string 337 BufferIndex = 0; 338 dataReady = true; 339 } 340 } 341 else { 342 ReceivedSerialChars[BufferIndex] = RxdChar; 343 ++BufferIndex; 344 if (BufferIndex >= bufferSize) { 345 BufferIndex = bufferSize - 1; 346 Overflow = true; } 347 } 348 } 349 350 if (dataReady) { 351 if(!Overflow) 352 ParseNextionData(); //parse messages and populate data variables 353 354 else{ 355 Serial.println("Overflow"); 356 Overflow=false; 357 } 358 dataReady = false; 359 } 360 361} 362 363//*************************************************************************************************** 364 365void ParseNextionData () { //Function to parse received nextion format messages and extract variable values 366 367 char * strtokIndx; // this is used by strtok()as an index 368 369 //Serial.println(ReceivedSerialChars); 370 strcpy(tempChars, ReceivedSerialChars); // this temporary copy is necessary to protect the original data 371 // because strtok() used in parseData() replaces the found token with \\0 372 373 strtokIndx = strtok(tempChars,"="); // get the first part get the first part of string before the '=' char 374 375 if (strtokIndx == NULL){ // strtokIndex couldnt find the token - corrupt message so just return from function 376 return; 377 } 378 strcpy(VariableID, strtokIndx); 379 380 strtokIndx = strtok(NULL, ""); // get the remaining part of string after the "=" ....which is the variables int number 381 382 if (strtokIndx == NULL){ 383 // Serial.println("StrtoInx = NULL"); 384 return; 385 } 386 387 IsNumber=true; 388 for (byte i = 0; i<=(strlen(strtokIndx)-1); i++) { 389 if (!(isdigit(strtokIndx[i]))){ 390 IsNumber=false; 391 } 392 } 393 394 if(IsNumber){ 395 RxdInt1 = atoi(strtokIndx); 396 } 397 else{ 398 return; 399 } 400 401 // Now lets try to match the received variable ID... 402 403 if (strcmp(VariableID, "TopC.val") == 0) { 404 // Serial.print("Found TopC.val = "); 405 TopTemp = RxdInt1/10.0; 406 // Serial.println(TopTemp); 407 } 408 else if (strcmp(VariableID, "MidC.val") == 0) { 409 // Serial.print("Found MidC.val= "); 410 MidTemp = RxdInt1/10.0; 411 // Serial.println(MidTemp); 412 } 413 else if (strcmp(VariableID, "BotC.val") == 0) { 414 //Serial.print("Found BotC.val= "); 415 BottomTemp= RxdInt1/10.0; 416 //Serial.println(BottomTemp); 417 } 418 else if (strcmp(VariableID, "MaxC.val") == 0) { 419 //Serial.print("Found MaxC.val= "); 420 MaxTemp= RxdInt1/10.0; 421 //Serial.println(MaxTemp); 422 } 423 else if (strcmp(VariableID, "Whrs.val") == 0) { 424 // Serial.print("Found Whrs.val= "); 425 WattHrs = RxdInt1; 426 // Serial.println(WattHrs); 427 } 428 else if (strcmp(VariableID, "Watts.val") == 0) { 429 // Serial.print("Found Watts.val= "); 430 PVWatts = RxdInt1; 431 // Serial.println(PVWatts); 432 } 433 else if (strcmp(VariableID, "Status.val") == 0) { 434 //Serial.print("Found Status.val= "); 435 DataRxdMillis =millis(); 436 LMStatus = RxdInt1; 437 438 // if(LMStatus!=1){ 439 // Serial.print("RxdSerialChars= "); 440 // Serial.println(ReceivedSerialChars); 441 // Serial.print("RxdInt="); 442 // Serial.println(LMStatus); 443 // } 444 } 445 else{ 446 //Serial.print("Message not recognised"); 447 } 448 449} 450 451//********************************************************************************* 452 453 454 bool EndOfDay (void) { //Function to detect the change to night time, triggers a sending of the daily value(s) 455 //Loadmaster resets the WattHrs value a few hrs after darkness detected. 456 457 if ((WattHrs == 0) && (LastWattHrs>10.0)){ //its the end of the day...Loadmaster just reset the WHrs value 458 459 return true; 460 } 461 else{ 462 return false; 463 } 464 465 } 466 467 468 //******************************************************************************************************************* 469 470 471 void PublishDailyData (void){ // After darkness we send the days accumulated KWhrs energy value (any anything else of interests) 472 473 if(PublishLimitOK()){ //Check the rate of publising has not been too high - say from repeated alarm triggers 474 475 Serial.println("Publishing Daily"); 476 477 dtostrf(MaxDailyTemp,4, 1, outstr); // sprintf wont take in floats...ie MaxTemp is a float 478 sprintf(context, "\\"MaxMidTemp\\":\\"%s\\"", outstr); // because of x10 variable limit in free Unbidots account, a context field 'MaxMidTemp' is used in the daily Kwhr variable to showing the days MaxTemp 479 // Serial.print(context); 480 481 client.add("daykwhrs", LastWattHrs,context); 482 client.ubidotsPublish("loadmaster"); 483 } 484 else{ 485 Serial.println("Publish was blocked - limit exceeded"); 486 } 487 } 488 489//************************************************************************************** 490 491void PublishMainData (void){ // Function publishes the main 15min data set to Ubidots MQTT broker 492 493if(PublishLimitOK()){ //Check the rate of publising has not been too high - say from repeated alarm triggers 494 495 digitalWrite(RedLED, LOW); 496// digitalWrite(LED_BUILTIN, LOW); //Low is LED ON 497 Serial.println("Publishing Main Data"); 498 499 LMStatustoText(); 500 501 client.add("power", PVWatts); 502 client.add("kwhrs", WattHrs); 503 client.add("status", LMStatus, context); 504 client.ubidotsPublish("loadmaster"); 505 506 //delay(200); 507 508 client.add("bottemp", BottomTemp); 509 client.add("midtemp", MidTemp); 510 client.add("toptemp", TopTemp); 511 client.ubidotsPublish("loadmaster"); 512 513 // client.add("maxtemp", MaxTemp); 514 // client.ubidotsPublish("loadmaster"); 515 516 digitalWrite(RedLED, HIGH); 517 // digitalWrite(LED_BUILTIN, HIGH); //Low is LED ON 518 519 PublishCount++; 520} 521else{ 522 Serial.println("Publish was blocked - limit exceeded"); 523} 524} 525//********************************************************************************* 526 527void PublishSwitch (void) { 528 529if(PublishLimitOK()){ //Check the rate of publising has not been too high - say from repeated alarm triggers 530 531 if(LMStatus>=1 && LMStatus<5){ 532 client.add("switch", 1); 533 } 534 else{ 535 client.add("switch", 0); 536 } 537 client.ubidotsPublish("loadmaster"); 538 PublishCount++; 539} 540else{ 541 Serial.println("Publish was blocked - limit exceeded"); 542 } 543} 544//********************************************************************************* 545void LMStatustoText(void){ 546 547 // char test[20] = "\\"Running All O.K\\""; //see escape sequences https://circuits4you.com/2019/01/25/arduino-how-to-put-quotation-marks-in-a-string/ 548 // sprintf(context, "\\"Status\\":\\"%i - O.K\\"", LMStatus); 549 // strcpy(context,"\\"Status\\":\\"Flood Alert\\""); //for adding context to a variable, see 550 // sprintf(context, "\\"Status\\": All O.K"); //sprintf = string print formatted, https://www.programmingelectronics.com/sprintf-arduino/ 551 552switch (LMStatus) { 553 554 555 case 0: 556 sprintf(context, "\\"Status\\":\\"%i - System OFF\\"", LMStatus); 557 break; 558 559 case 1: 560 sprintf(context, "\\"Status\\":\\"%i - System ON - OK\\"", LMStatus); //Bottom Temp error 561 break; 562 563 case 2: 564 sprintf(context, "\\"Status\\":\\"%i - System ON - HOT !\\"", LMStatus); //Bottom Temp error 565 break; 566 567 case 3: 568 sprintf(context, "\\"Status\\":\\"%i - Aux Output Active\\"", LMStatus); //Bottom Temp error 569 break; 570 571 case 5: 572 sprintf(context, "\\"Status\\":\\"%i - Power Fail Reset\\"", LMStatus); //Bottom Temp error 573 break; 574 575 case 6: 576 sprintf(context, "\\"Status\\":\\"%i - Bottom Temp Err\\"", LMStatus); //Mid Temp error 577 break; 578 579 case 7: 580 sprintf(context, "\\"Status\\":\\"%i - Mid Temp Err\\"", LMStatus); //Mid Temp error 581 break; 582 583 case 8: 584 sprintf(context, "\\"Status\\":\\"%i - Top Temp Err\\"", LMStatus); //Top Temp error 585 break; 586 587 case 9: 588 sprintf(context, "\\"Status\\":\\"%i - Aux Temp error\\"", LMStatus); //Aux Temp error 589 break; 590 591 case 10: 592 sprintf(context, "\\"Status\\":\\"%i - FET Temp Err\\"", LMStatus); //12V Error 593 break; 594 595 case 11: 596 sprintf(context, "\\"Status\\":\\"%i - 12V Supply Err\\"", LMStatus); //12V Error 597 break; 598 599 case 12: 600 sprintf(context, "\\"Status\\":\\"%i - PWM Test Timeout\\"", LMStatus); // Stereaming PWM tests timed out 601 break; 602 603 case 13: 604 sprintf(context, "\\"Status\\":\\"%i - PWM Sweep Complete\\"", LMStatus); // Stereaming PWM tests timed out 605 break; 606 607 case 99: 608 sprintf(context, "\\"Status\\":\\"%i - Data Loss!\\"", LMStatus); // Stereaming PWM tests timed out 609 break; 610 611 default: 612 sprintf(context, "\\"Status\\":\\"%i - Unknown Status I.D\\"", LMStatus); // Stereaming PWM tests timed out 613 break; 614 } 615 616} 617 618//*************************************************************************************** 619bool LMStatusChanged (void){ 620 621 if (LMStatus != LastLMStatus){ 622 LastLMStatus = LMStatus; 623 return true; 624 } 625 else{ 626 return false; 627 } 628} 629 630// ************************************************************************************** 631 632bool LossOfDatafromLM(void){ 633 if(millis()-DataRxdMillis>15000){ //used to detect a loss of data being received from the LoadMaster 634 LMStatus=99; 635 LastRxdMillis=DataRxdMillis; 636 return true; 637 } 638 else{ 639 return false; 640 } 641} 642 643//***************************************************************************************** 644 645 646bool PublishLimitOK(void){ 647 648 if ((millis()-SafetyIntervalStart) > SafetyIntervalDuration){ 649 SafetyIntervalStart=millis(); 650 PublishCount=0; 651 } 652 653 if(PublishCount<PublishLimit){ // used to indentify the start mS for a publishing safety timeout 654 return true; 655 } 656 else{ 657 return false; 658 } 659} 660 661// ************************************************************************************** 662/* 663 664bool AlarmStatusChanged (void){ 665 666 //Determine the current Alarm status code BCD:- 667 bitWrite(AlarmStatus,0,!digitalRead(D1)); // FYI bitWrite(x, n, b) where x= variable ID, n: bit position to write -0 being LSB rightmost, b: written bit value(0 or 1) 668 bitWrite(AlarmStatus,1,!digitalRead(D2)); 669 bitWrite(AlarmStatus,2,((Temperature>MaxTempLimit) || (Temperature<MinTempLimit))); 670 671 // Serial.print("Alm Status ="); 672 //Serial.println(AlarmStatus); 673 674 if(JustBooted){ 675 LastAlarmStatus=AlarmStatus; //Avoids an intitial status change at boot up - Alarm is always published at startup so state doesnt matter 676 } 677 678 // Serial.print("Alarm Status -"); 679 // Serial.println(AlarmStatus); 680 // Serial.print("LastAlarm Status -"); 681 // Serial.println(LastAlarmStatus); 682 683 if (AlarmStatus != LastAlarmStatus){ 684 LastAlarmStatus=AlarmStatus; 685 return true; 686 } 687 688 else{ 689 return false; 690 } 691 692 } 693 694 695// *************************************************************************************** 696 697 void PublishAlarm (void){ // After darkness we send the days accumulated KWhrs energy value (any anything else of interests) 698 //the variable includes a text 'context' field called "Alarm" 699 if(PublishLimitOK()){ //Check the rate of publising has not been too high - say from repeated alarm triggers 700 701 digitalWrite(LED_BUILTIN, LOW); // flash Wemos D1 LED during publish to MQTT broker 702 Serial.print("Publishing I/O Alarm -"); 703 704 strcpy(IOAlarmStr1,""); 705 strcpy(IOAlarmStr2,""); 706 strcpy(TempAlarmStr3,""); 707 dtostrf(Temperature,4, 1, outstr); // sprintf wont take in floats...ie Temperature is a float 708 709 if(AlarmStatus == 0) { 710 sprintf(context, "\\"Alarm\\":\\"%i: Alarms All O.K %sC\\"",AlarmStatus,outstr); // Alarm variable has text context field 'alarm' 711 } 712 else{ 713 if(bitRead(AlarmStatus,0)){ //if bit 0 is 1, i.e D1 is low in alarm state 714 strcpy(IOAlarmStr1,"Cylinder leak,"); 715 } 716 if(bitRead(AlarmStatus,1)){ //if bit 1 is 1, i.e D2 is low in alarm state 717 strcpy(IOAlarmStr2,"Boiler leak,"); 718 } 719 if(bitRead(AlarmStatus,2)){ //if bit 2 is 1, i.e temperature is high or low 720 strcpy(TempAlarmStr3,"Temp!"); 721 } 722 723 sprintf(context, "\\"Alarm\\":\\"%i:%s%s%s%sC\\"",AlarmStatus,IOAlarmStr1,IOAlarmStr2,TempAlarmStr3,outstr); // Alarm variable has text context field 'alarm' 724 } 725 Serial.println(context); 726 727 client.add("alarms", AlarmStatus,context); 728 client.ubidotsPublish("loadmaster"); 729 digitalWrite(LED_BUILTIN, HIGH); 730 PublishCount++; 731 } 732 else{ 733 Serial.println("Publish was blocked - limit exceeded"); 734 } 735} 736 737//************************************************************************************** 738 739void ReadTempSensor(void){ 740 741 if(millis()-LastTempRead>TempUpdateInterval){ 742 Temperature=sensors.getTempCByIndex(0); //Request temperature reading from the first sensor only. 743 // Serial.println("in temp read"); 744 745 sensors.setWaitForConversion(false); // makes it async 746 sensors.requestTemperatures(); 747 sensors.setWaitForConversion(true); 748 749 LastTempRead=millis(); 750 751 } 752} 753*/ 754
Downloadable files
Wiring Loadmaster to a Wemos D1 WiFi Module
This shows how a WiFi module can be directly connected to the Loadmaster (using say <1m of SCREENED four core cable)
Wiring Loadmaster to a Wemos D1 WiFi Module
Wiring Loadmaster to a Wemos D1 WiFi Module
This shows how a WiFi module can be directly connected to the Loadmaster (using say <1m of SCREENED four core cable)
Wiring Loadmaster to a Wemos D1 WiFi Module
Comments
Only logged in users can leave comments