Welcome to Hackster!
Hackster is a community dedicated to learning hardware, from beginner to pro. Join us, it's free!
stevetearle
Published © GPL3+

Loadmaster - Online Dashboard and Data Logging on Ubidots

LoadMaster's serial output stream (in Nextion display format) is decoded and values published to Ubidots MQTT broker. (Wemos D1 NodeMCU)

IntermediateFull instructions provided837
Loadmaster - Online Dashboard and Data Logging on Ubidots

Things used in this project

Story

Read more

Schematics

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)

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
/****************************************
 * Loadmaster MQTT (Ubidots) - Data Logger 
 * Release V1.0 
 * This interface provides an Online Dashboard and data logging function for Loadmaster, 
 * Data sets are published to the Ubidots MQTT broker.
 * Tested on a ESP8266 / Wemos D1 Mini. The interface extracts data values from Loadmasters Nextion display serial data stream. 
 * We look for the resetting of PVWattHrs to zero as an indication of the end of a day and this triggers a publishing 
 * of the daily values
 * 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!
 *
 * 
 * Include Libraries
Board NODE MCU 1.0 ESP 12E / Wemos D1 mini etc.
PubSub client library from Nick Oleary - in the list of arduino libraries 
Ubidots ESP library V1.2 from  https://github.com/ubidots/ubidots-mqtt-esp
Follow readme instructions to install boards

****************************************/
#include "UbidotsESPMQTT.h"
#include <SoftwareSerial.h>
//#include <OneWire.h>
//#include <DallasTemperature.h>
/****************************************
 * Define Constants
 ****************************************/
#define TOKEN "ENTER YOUR UBIDOTS TOKEN HERE" // This is for Loasmaster Device Enter Your Ubidots device TOKEN
#define WIFINAME "YOUR WIFI SSID HERE" //Enter Your WiFi SSID
#define WIFIPASS "YOUR WIFI PASSWORD HERE" // Enter Your Wifi Password

Ubidots client(TOKEN);

unsigned long FastInterval = 900000;    //Update Ubidots with TopC, MidC, BotC, Watts, Whrs & Status values every 15minutes =900,000mS, 15min=900000 
unsigned long SlowInterval = 1800000;   //Update Ubidots with values every 30 minutes 1800,000ms
unsigned long HourlyInterval = 3600000; //Update Ubidots with I/O Alarm values every 60 minutes
unsigned long BootPublishDelay=8000;    //At boot up a test publish happens after 10secs

unsigned long DataRxdMillis =0;       //used to detect a loss of data being received from the LoadMaster
unsigned long LastRxdMillis;          //used to detect a loss of data being received from the LoadMaster

//unsigned long TempUpdateInterval=2000;    //Timing for reading DS18B20 -if required
//unsigned long IOScanInterval=100;    //Timing for reading IO inputs -if I/O alarms are used
//unsigned long LastIOScan;
//unsigned long LastTempRead;

//float MaxTempLimit =30.0;
//float MinTempLimit =10.0;

unsigned long CurrentMillis;

unsigned long SafetyIntervalStart;     // All publish functions are limited by an overall publishing rate safety timeout 
unsigned long SafetyIntervalDuration=300000;    // We check we dont exceed 10 publish events over a 5 minute interval.
unsigned long LastPublishMillis;
int PublishLimit=15;
int PublishCount;


unsigned long ActiveUpdateInterval;     // At power up the first update will ocurr after 15secs. After first publish Active update rate will depend on level of PVWatts

SoftwareSerial espSerial(14, 12);  // (rx, tx)    GPIO14 = Wemos Pin marked D5, GPIO12 = Wemos Pin marked D6     
                                           
// For DS18B20 Temperature if required. Data wire to port 2 on the Arduino
//#define ONE_WIRE_BUS D3

//OneWire oneWire(ONE_WIRE_BUS);         // create a oneWire instance to communicate with OneWire devices
//DallasTemperature sensors(&oneWire);       // Pass our oneWire reference to Dallas Temperature. 


//Pin Allocations
//int LED_BUILTIN = D4; wrong
byte RedLED = 2;   //D4= GPIO-2;  

//Program Variables
float BottomTemp = 0;
float TopTemp = 0;
float MidTemp = 0;
float MaxTemp = 0;
float LastWattHrs = 0;    // used to determine the end of a day when loadmaster resets the WHrs value
float MaxDailyTemp=0;

//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) 
//float Temperature=0;


int PVWatts = 0;
int WattHrs = 0;
int LMStatus = 0;       //LoadMaster's Status code - represents the current operating status or error code
int LastLMStatus=0;     // 0=Turned OFF, 1=Running, 3=Hot, 4= Reset OFF(Power up reset), 


//For managing extra I/O Alarm inputs (Flood etc)and DS18B20 Temperature sensor
//int AlarmStatus=0;         // Alarms from IO pins  0=OK,  1 = Flood 1 on D1, 2=Flood2 on D2, 3= Both D1 and D2 triggered!   
//int LastAlarmStatus=0;     // used to detect a change in alarm state.
//unsigned long LastAlarmPublish=0;
//unsigned long AlarmPublishInterval;        
//char IOAlarm1Str[] = "Boiler Flood";



//For creating status and max temp Context string arrays
char 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
char outstr[20]; 
//char IOAlarmStr1[16]; 
//char IOAlarmStr2[16];  
//char TempAlarmStr3[16];
  
//Common Variables for Serial CLI and Message Parsing            
int RxdInt1 = 0;
const byte bufferSize = 40;  // Maximum Char length of received serial messages terminated in a Linefeed.
char ReceivedSerialChars[bufferSize];
char tempChars[bufferSize];   
char VariableID[bufferSize]={0};  //populates array with null \0
char StatusChars[bufferSize];
int BufferIndex = 0;
bool dataReady = false;
bool Overflow = false;
bool JustBooted = true;
//bool EndOfDay=false;
bool IsNumber = false;


//----------------------------------------------------------------------------------------------

//****************************************************************************************************************************
//  

void setup() {
  
  // Setup code goes here,runs once at boot:
  //client.ubidotsSetBroker("industrial.api.ubidots.com"); // Sets the broker properly for the industrial account
  Serial.begin(9600);
  espSerial.begin(9600);
  
  client.setDebug(false); // Pass a true or false bool value to activate debug messages
  client.wifiConnection(WIFINAME, WIFIPASS);
  client.begin(callback);
  client.ubidotsSubscribe("loadmaster","switch");  // Insert the dataSource and Variable's Labels


  ActiveUpdateInterval=BootPublishDelay;   //This is used to set the first publish interval to 6 seconds..see a transmission after plugging in
  pinMode(RedLED, OUTPUT);
  digitalWrite(RedLED, LOW);
  //pinMode(LED_BUILTIN, OUTPUT);
  //digitalWrite(LED_BUILTIN, LOW);   //Low is LED ON 


//  pinMode(D1, INPUT);        //Used for Flood sens input #1 - ***!!!!EXTERNAL PULL UPs WILL BE REQUIRED on D1&D2!!!!!
//  pinMode(D2, INPUT);        //Used for Flood sens input #2
   
  //For DS18B20 temp sensor if required
 // sensors.begin();
  
  delay(400);
  digitalWrite(RedLED, HIGH);
 // digitalWrite(LED_BUILTIN, HIGH);   //Low is LED ON 
  delay(400);
  
 // sensors.setWaitForConversion(false);  // makes it async
 // sensors.requestTemperatures();
 // sensors.setWaitForConversion(true);
  
  LastPublishMillis=millis();
 // LastAlarmPublish=millis();
 // LastTempRead =millis();
  
  LastRxdMillis=millis();

  Serial.println("LoadMaster Ubidots Uploader - Release V5.0");   
  Serial.println("Setup Done");   
  
  SafetyIntervalStart=millis();

  
  }


    
//******* MAIN LOOP Starts Here *********************************************************************************************************

void loop() {
                                                                                                                                                 //Receive the Nextion serial data messages and extract variable data values
RxNextionData();           //Service the software serial Port, reads in Nextion format Data values, calls Parse routine if newdata Rx'd

//ReadTempSensor();

//If you wishto use an I/O alarm functions on D1 &D2, Un-comment the code below upto end of Alarm comment
//Manage Publishing of I/O Alarm status -  used for say flood Sensors / logic inputs etc

/*if(millis()-LastIOScan>IOScanInterval){    //Read IO inputs every 200mS
  if(AlarmStatusChanged()){      // Function to read sensor inputs (D1, D2 & Temp)ever 0.5S - Returns true if any sensor states changed  
    Serial.println("Alarm State Changed!!");
    PublishAlarm();    //publish new alarm state. 
  }  
  LastIOScan=millis();
}   

//Establish the update interval of publishing I/O Alarm Status:-
if(JustBooted){                                
    AlarmPublishInterval=BootPublishDelay;
  }
else if(AlarmStatus==0){
  AlarmPublishInterval=HourlyInterval;   // no alarm condition is present - i.e D1 or D2 pulled high
}
else {
  AlarmPublishInterval
  =SlowInterval;    // alarm condition active - i.e D1 or D2 pulled high, 30 min publishing
}


if(millis()-LastAlarmPublish > AlarmPublishInterval){    
      PublishAlarm();    //publish new alarm state 
      LastAlarmPublish=millis();
   }
 
 //End of Code to publish I/O Alarms
*/


// Check the MQTT connection and subscribing to the required topic(s) plus publishing appropriate data sets to the MQTT Broker:-
if(!client.connected()){
    client.reconnect();
    client.ubidotsSubscribe("loadmaster", "switch");  // Insert the dataSource and Variable's Labels
   }

//Determine the currrent logging rate:- following bootup it publishes after 10secs, then every 15min in daytime or 60mins at night   
 
  if(JustBooted){                                 
    ActiveUpdateInterval=BootPublishDelay;
    }
  else if (PVWatts>2){
    ActiveUpdateInterval = FastInterval;    //We have faster logging of data in daytime  - 10mins
    }
  else {
    ActiveUpdateInterval = SlowInterval;   
    }


//Is it time to send main data values to Ubidots via MQTT? 
 
if((millis()- LastPublishMillis)> ActiveUpdateInterval) {   //Publish main Data at required update interval ONLY during daytime
     JustBooted=false;
         
     PublishMainData();          //Function to Publish the regular data set - 15min interval during daytime, Hrly at night
     LastPublishMillis = millis();

     LastLMStatus = LMStatus;         //Remember the last published status, if it changes we publish again
     if(PVWatts>2 && WattHrs>10 ){    //when publishing data in any sunshine, update the daily max temperature which is logged at end of day data
        MaxDailyTemp=MaxTemp;
     }
  }



if (LossOfDatafromLM()&& LMStatusChanged()){      //Loss of LoadMaster serial data input?, Sets LMStatus to 99 to communicate a Loss of Loadmaster data input 
     Serial.println("No Serial Data from Loadmaster");
     PublishMainData();
    // PublishSwitch();
  }  


// Publish data if Loadmaster Status has just changed - publish changed status so we can quickly report errors etc
if(!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
   PublishMainData();
   PublishSwitch();
}


// Publish end of day 'Daily' values        
  if(EndOfDay()){                // Returns true when it sees LoadMasters PVWhrs value reset to zero at the end of a day (3 hrs of darkness)
      PublishDailyData();
      LastWattHrs=0;           // Clear values ready for the next day
     }
  else{
       LastWattHrs=WattHrs;     
     }
 
//Publish alarm IO status - usually only at slow interval, or fast interval if alarm state is present

 client.loop();                 // we must do this to check for subscribed data...or you only get it every 15min or 60min during publishes!

}


//******END OF MAIN LOOP ****************************************************************************************
/****************************************************************************************************************/
// * Subroutine Functions Below:-
/*--------------------------------------------------------------------------------------------------------------*/

//CallBack Subscribe function for Ubidots Library

void callback(char* topic, byte* payload, unsigned int length) {
  
 // To see subscribed message, un comment code below:
 //Serial.print("Msg arrived");
 //delay(250);
  
 // Serial.print(topic);
 // Serial.print("] ");
 // for (int i=0;i<length;i++) {
 // Serial.print((char)payload[i]);
 // }
 // Serial.println();

   if ((char)payload[0] == '1') {
    digitalWrite(16, HIGH);
       if(JustBooted==false){
     Serial.println("Switch.val=1");        //Nextion format command to turn System ON (same message as button press on LCD)
     espSerial.println("Switch.val=1");     // also send this to LoadMaster - for remote turn on / off
       }
   }
   else {
    digitalWrite(16, LOW);
   if(JustBooted==false){
      Serial.println("Switch.val=0");        //Nextion format command to turn System OFF
      espSerial.println("Switch.val=0");     // also send this to LoadMaster - for remote turn on / off
   }
  }
}


//*******************************************************************************************************

void RxNextionData  (){       //Function to receive Nextion data on Software Serial Port

  char RxdChar;
  static uint8_t charCount;
  static uint8_t ffCount;
  
  while (espSerial.available() > 0 && dataReady == false) {
    RxdChar = espSerial.read();
  // Serial.println(RxdChar);     // for testing - to see every rx'd character
   
    if (RxdChar == 0xff) {
      ++ffCount;
      if (ffCount >= 3) {                                    //Nextion display messages are terminated with 0xFF 0xFF 0xFF
        ffCount = 0;
        ReceivedSerialChars[BufferIndex] = '\0';        // terminate the string
        BufferIndex = 0;
        dataReady = true;
       }
     }
     else {
      ReceivedSerialChars[BufferIndex] = RxdChar;
      ++BufferIndex;
      if (BufferIndex >= bufferSize) {
        BufferIndex = bufferSize - 1;
        Overflow = true;        }        
      }
    }

 if (dataReady) {         
        if(!Overflow)
        ParseNextionData();     //parse messages and populate data variables 
        
        else{
          Serial.println("Overflow");
          Overflow=false;
        }
       dataReady = false; 
    }   
    
}

//***************************************************************************************************

void ParseNextionData () {              //Function to parse received nextion format messages and extract variable values     

  char * strtokIndx; // this is used by strtok()as an index

  //Serial.println(ReceivedSerialChars);
  strcpy(tempChars, ReceivedSerialChars);    // this temporary copy is necessary to protect the original data
                                             // because strtok() used in parseData() replaces the found token with \0 
                                         
  strtokIndx = strtok(tempChars,"=");    // get the first part get the first part of string before the '=' char
  
  if (strtokIndx == NULL){               // strtokIndex couldnt find the token - corrupt message so just return from function
      return; 
  }
  strcpy(VariableID, strtokIndx); 

  strtokIndx = strtok(NULL, "");         // get the remaining part of string after the "=" ....which is the variables int number
  
  if (strtokIndx == NULL){
  //  Serial.println("StrtoInx = NULL");
    return;
  }
    
  IsNumber=true;
     for (byte i = 0; i<=(strlen(strtokIndx)-1); i++) {
          if (!(isdigit(strtokIndx[i]))){
             IsNumber=false;
          }
     }
  
  if(IsNumber){
  RxdInt1 = atoi(strtokIndx);
  }
  else{
    return;
  }

  // Now lets try to match the received variable ID... 
  
  if (strcmp(VariableID, "TopC.val") == 0) {
   // Serial.print("Found TopC.val = ");
     TopTemp = RxdInt1/10.0;
   //  Serial.println(TopTemp);
  }
  else if (strcmp(VariableID, "MidC.val") == 0) {
    // Serial.print("Found MidC.val= ");
     MidTemp = RxdInt1/10.0;
    // Serial.println(MidTemp);
  }
  else if (strcmp(VariableID, "BotC.val") == 0) {
    //Serial.print("Found BotC.val= ");
    BottomTemp= RxdInt1/10.0;
    //Serial.println(BottomTemp);
  }
  else if (strcmp(VariableID, "MaxC.val") == 0) {
    //Serial.print("Found MaxC.val= ");
    MaxTemp= RxdInt1/10.0;
    //Serial.println(MaxTemp);
  }
  else if (strcmp(VariableID, "Whrs.val") == 0) {
   // Serial.print("Found Whrs.val= ");
    WattHrs = RxdInt1;
   // Serial.println(WattHrs);
  }
  else if (strcmp(VariableID, "Watts.val") == 0) {
  //  Serial.print("Found Watts.val= ");
    PVWatts = RxdInt1;
     //  Serial.println(PVWatts);
  }
  else if (strcmp(VariableID, "Status.val") == 0) {
   //Serial.print("Found Status.val= ");
    DataRxdMillis =millis();  
    LMStatus = RxdInt1;

      //  if(LMStatus!=1){
      //    Serial.print("RxdSerialChars= ");
      //    Serial.println(ReceivedSerialChars);
      //    Serial.print("RxdInt=");
      //    Serial.println(LMStatus);
      //  }
  }
  else{
    //Serial.print("Message not recognised");
    }
  
}

//*********************************************************************************


 bool EndOfDay (void)  {       //Function to detect the change to night time, triggers a sending of the daily value(s) 
                               //Loadmaster resets the WattHrs value a few hrs after darkness detected.
  
   if ((WattHrs == 0) && (LastWattHrs>10.0)){   //its the end of the day...Loadmaster just reset the WHrs value
     
      return true;
    }
  else{
      return false;
     }
 
  }
  
   
   //*******************************************************************************************************************


   void PublishDailyData (void){       // After darkness we send the days accumulated KWhrs energy value (any anything else of interests)

   if(PublishLimitOK()){    //Check the rate of publising has not been too high - say from repeated alarm triggers
       
       Serial.println("Publishing Daily");
      
       dtostrf(MaxDailyTemp,4, 1, outstr);                  // sprintf wont take in floats...ie  MaxTemp is a float  
       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
       // Serial.print(context);
    
       client.add("daykwhrs", LastWattHrs,context);
       client.ubidotsPublish("loadmaster");
     }
    else{
     Serial.println("Publish was blocked - limit exceeded");
    }
 }
   
//**************************************************************************************

void PublishMainData (void){     // Function publishes the main 15min data set to Ubidots MQTT broker 

if(PublishLimitOK()){    //Check the rate of publising has not been too high - say from repeated alarm triggers

  digitalWrite(RedLED, LOW);
//  digitalWrite(LED_BUILTIN, LOW);   //Low is LED ON 
  Serial.println("Publishing Main Data");
  
  LMStatustoText();

  client.add("power", PVWatts);
  client.add("kwhrs", WattHrs);
  client.add("status", LMStatus, context);  
  client.ubidotsPublish("loadmaster");
  
  //delay(200);
 
  client.add("bottemp", BottomTemp);
  client.add("midtemp", MidTemp);
  client.add("toptemp", TopTemp);
  client.ubidotsPublish("loadmaster");
 
  //  client.add("maxtemp", MaxTemp);
  //  client.ubidotsPublish("loadmaster");

  digitalWrite(RedLED, HIGH);
 // digitalWrite(LED_BUILTIN, HIGH);   //Low is LED ON 
  
  PublishCount++; 
}
else{
  Serial.println("Publish was blocked - limit exceeded");
}
}
//*********************************************************************************

void PublishSwitch (void) {

if(PublishLimitOK()){    //Check the rate of publising has not been too high - say from repeated alarm triggers
       
    if(LMStatus>=1 && LMStatus<5){
    client.add("switch", 1);
    }
    else{
    client.add("switch", 0);
    }
    client.ubidotsPublish("loadmaster");
    PublishCount++;
}
else{
  Serial.println("Publish was blocked - limit exceeded");
  }
}
//*********************************************************************************
void LMStatustoText(void){

 // 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/
 // sprintf(context, "\"Status\":\"%i - O.K\"", LMStatus);
 // strcpy(context,"\"Status\":\"Flood Alert\"");     //for adding context to a variable, see
 // sprintf(context, "\"Status\": All O.K");    //sprintf = string print formatted, https://www.programmingelectronics.com/sprintf-arduino/

switch (LMStatus) {


    case 0:
       sprintf(context, "\"Status\":\"%i - System OFF\"", LMStatus);
    break;
 
    case 1:
       sprintf(context, "\"Status\":\"%i - System ON - OK\"", LMStatus);  //Bottom Temp error
    break;
    
    case 2:
       sprintf(context, "\"Status\":\"%i - System ON - HOT !\"", LMStatus);  //Bottom Temp error
    break;

    case 3:
       sprintf(context, "\"Status\":\"%i - Aux Output Active\"", LMStatus);  //Bottom Temp error
    break;
    
    case 5:
       sprintf(context, "\"Status\":\"%i - Power Fail Reset\"", LMStatus);  //Bottom Temp error
    break;
        
    case 6:
       sprintf(context, "\"Status\":\"%i - Bottom Temp Err\"", LMStatus);  //Mid Temp error
    break;

    case 7:
       sprintf(context, "\"Status\":\"%i - Mid Temp Err\"", LMStatus);  //Mid Temp error
    break;
   
    case 8:
       sprintf(context, "\"Status\":\"%i - Top Temp Err\"", LMStatus);  //Top Temp error
    break;
   
    case 9:
       sprintf(context, "\"Status\":\"%i - Aux Temp error\"", LMStatus);  //Aux Temp error
    break;
         
    case 10:
       sprintf(context, "\"Status\":\"%i - FET Temp Err\"", LMStatus); //12V Error
    break;

    case 11:
       sprintf(context, "\"Status\":\"%i - 12V Supply Err\"", LMStatus); //12V Error
    break;

    case 12:
     sprintf(context, "\"Status\":\"%i - PWM Test Timeout\"", LMStatus); // Stereaming PWM tests timed out
    break;

    case 13:
     sprintf(context, "\"Status\":\"%i - PWM Sweep Complete\"", LMStatus); // Stereaming PWM tests timed out
    break;

    case 99:
     sprintf(context, "\"Status\":\"%i - Data Loss!\"", LMStatus); // Stereaming PWM tests timed out
    break;
    
    default:
    sprintf(context, "\"Status\":\"%i - Unknown Status I.D\"", LMStatus); // Stereaming PWM tests timed out
    break;
  }
 
}

//***************************************************************************************
bool LMStatusChanged (void){

  if (LMStatus != LastLMStatus){
    LastLMStatus = LMStatus;
    return true;
  }
  else{
    return false;
  }
}

// ************************************************************************************** 

bool LossOfDatafromLM(void){
  if(millis()-DataRxdMillis>15000){           //used to detect a loss of data being received from the LoadMaster
     LMStatus=99;
     LastRxdMillis=DataRxdMillis;
     return true;   
  }
  else{
    return false; 
  }
}

//*****************************************************************************************


bool PublishLimitOK(void){

  if ((millis()-SafetyIntervalStart) > SafetyIntervalDuration){
    SafetyIntervalStart=millis();
    PublishCount=0;
  }
   
  if(PublishCount<PublishLimit){    // used to indentify the start mS for a publishing safety timeout 
    return true;
    }
  else{
   return false; 
  }
}

// ************************************************************************************** 
/*

bool AlarmStatusChanged (void){
 
  //Determine the current Alarm status code BCD:- 
  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)
  bitWrite(AlarmStatus,1,!digitalRead(D2));
  bitWrite(AlarmStatus,2,((Temperature>MaxTempLimit) || (Temperature<MinTempLimit)));
   
 // Serial.print("Alm Status =");
 //Serial.println(AlarmStatus);
  
  if(JustBooted){
          LastAlarmStatus=AlarmStatus;  //Avoids an intitial status change at boot up - Alarm is always published at startup so state doesnt matter
        }
    
    // Serial.print("Alarm Status -");
    // Serial.println(AlarmStatus);
    // Serial.print("LastAlarm Status -");
    // Serial.println(LastAlarmStatus);
     
     if (AlarmStatus != LastAlarmStatus){
          LastAlarmStatus=AlarmStatus;
          return true;
        }

    else{
         return false;
        }
   
  }
 
 
// ***************************************************************************************

  void PublishAlarm (void){       // After darkness we send the days accumulated KWhrs energy value (any anything else of interests)
                                  //the variable includes a text 'context' field called "Alarm"
  if(PublishLimitOK()){    //Check the rate of publising has not been too high - say from repeated alarm triggers
       
          digitalWrite(LED_BUILTIN, LOW);   // flash Wemos D1 LED during publish to MQTT broker
          Serial.print("Publishing I/O Alarm -");
                  
          strcpy(IOAlarmStr1,"");
          strcpy(IOAlarmStr2,"");
          strcpy(TempAlarmStr3,"");
          dtostrf(Temperature,4, 1, outstr);      // sprintf wont take in floats...ie  Temperature is a float 
           
          if(AlarmStatus == 0) {
             sprintf(context, "\"Alarm\":\"%i: Alarms All O.K %sC\"",AlarmStatus,outstr);   // Alarm variable has text context field 'alarm' 
          }
          else{   
             if(bitRead(AlarmStatus,0)){       //if bit 0 is 1, i.e D1 is low in alarm state
               strcpy(IOAlarmStr1,"Cylinder leak,");
             }
             if(bitRead(AlarmStatus,1)){       //if bit 1 is 1, i.e D2 is low in alarm state
               strcpy(IOAlarmStr2,"Boiler leak,");
             }
              if(bitRead(AlarmStatus,2)){       //if bit 2 is 1, i.e temperature is high or low
               strcpy(TempAlarmStr3,"Temp!"); 
              }
             
             sprintf(context, "\"Alarm\":\"%i:%s%s%s%sC\"",AlarmStatus,IOAlarmStr1,IOAlarmStr2,TempAlarmStr3,outstr);   // Alarm variable has text context field 'alarm' 
          }
          Serial.println(context);
          
          client.add("alarms", AlarmStatus,context);
          client.ubidotsPublish("loadmaster");
          digitalWrite(LED_BUILTIN, HIGH);
          PublishCount++;
      }
  else{
     Serial.println("Publish was blocked - limit exceeded"); 
      }
}
   
//**************************************************************************************

void ReadTempSensor(void){
  
  if(millis()-LastTempRead>TempUpdateInterval){
      Temperature=sensors.getTempCByIndex(0);   //Request temperature reading from the first sensor only.
    //  Serial.println("in temp read");  
  
  sensors.setWaitForConversion(false);  // makes it async
  sensors.requestTemperatures();
  sensors.setWaitForConversion(true);
  
  LastTempRead=millis();
  
  }
}
*/

Credits

stevetearle
3 projects • 43 followers
A semi retired R&D Design Engineer now living on the Isle of Wight, South Coast of the UK
Contact

Comments

Please log in or sign up to comment.