Monitor for central heating system (e.g. 2zones+hw) Supports up to 15 temp probes (DS18B20/DS18S20) 3 valve monitors Gas pulse meter recording Use stand-alone or with nodeEnergyServer See http://robdobson.com/2015/09/central-heating-monitor

Dependencies:   EthernetInterfacePlusHostname NTPClient Onewire RdWebServer SDFileSystem-RTOS mbed-rtos mbed-src

Revision:
10:72eb217def1f
Parent:
9:0e103c2f869a
Child:
11:30182b9aa833
--- a/main.cpp	Sun Feb 22 11:57:12 2015 +0000
+++ b/main.cpp	Sun Feb 22 20:23:43 2015 +0000
@@ -4,6 +4,7 @@
 #include "RdWebServer.h"
 #include "GasUseCounter.h"
 #include "Thermometers.h"
+#include "VoltAlerter.h"
 #include <stdarg.h>
 
 // Web and UDB ports 
@@ -12,22 +13,25 @@
 
 // Ticker collects data
 //Ticker ticker;
-//const int TICK_MS = 250;
+//const int TICK_MS = 50;
 const int LOOP_DELAY_IN_MS = 250;
 
 // Debugging and status
 RawSerial pc(USBTX, USBRX);
 DigitalOut led1(LED1); //ticking (flashes)
-DigitalOut led2(LED2); //server listning status (flashes)
+DigitalOut led2(LED2); //
 DigitalOut led3(LED3); //socket connecting status
 DigitalOut led4(LED4); //server status
 
 // Web server
 EthernetInterface eth;
-NTPClient ntp;
 UDPSocket sendUDPSocket;
 Endpoint broadcastEndpoint;
 
+// Network Time Protocol (NTP)
+NTPClient ntp;
+const int NTP_REFRESH_INTERVAL_HOURS = 1;
+
 // File system for SD card
 SDFileSystem sd(p5, p6, p7, p8, "sd");
 
@@ -41,6 +45,28 @@
 const PinName tempSensorPins[] = { p22 };
 Thermometers thermometers(sizeof(tempSensorPins)/sizeof(PinName), tempSensorPins, LOOP_DELAY_IN_MS);
 
+// Voltage Sensors / Alerters
+const int NUM_VOLT_ALERTERS = 3;
+VoltAlerter voltAlerter1(p23);
+VoltAlerter voltAlerter2(p24);
+VoltAlerter voltAlerter3(p25);
+
+// Broadcast message
+const char broadcastMsgPrefix[] = "{\"e\":[";
+const char broadcastMsgGasFormat[] = "{\"n\":\"gasCount\",\"v\":%d},{\"n\":\"gasPulseRateMs\",\"v\":%d,\"u\":\"ms\"}";
+const char broadcastTemperatureFormat[] = "{\"n\":\"temp_%s\",\"v\":%0.1f,\"u\":\"degC\"}";
+const char broadcastVoltAlerterFormat[] = "{\"n\":\"pump_%d\",\"v\":%d}";
+const char broadcastMsgSuffix[] = "],\"bt\":%d}";
+
+// Format message
+const int broadcastMsgLen = sizeof(broadcastMsgPrefix) + 
+            sizeof(broadcastMsgGasFormat) + 
+            (sizeof(broadcastTemperatureFormat)*Thermometers::MAX_THERMOMETERS) + 
+            (sizeof(broadcastVoltAlerterFormat)*NUM_VOLT_ALERTERS) + 
+            sizeof(broadcastMsgSuffix) + 
+            60;
+char broadcastMsgBuffer[broadcastMsgLen];
+    
 // Utility function to log data
 void LogData(const char* format, ...)
 {
@@ -71,31 +97,54 @@
     // Get temperature values
     TemperatureValue tempValues[Thermometers::MAX_THERMOMETERS];
     int numTempValues = thermometers.GetTemperatureValues(Thermometers::MAX_THERMOMETERS, tempValues, 100);
-    char tempStr[200];
     for (int tempIdx = 0; tempIdx < numTempValues; tempIdx++)
     {
         printf("Temp: %.1f, Addr: %s, Time: %d\r\n", tempValues[tempIdx].tempInCentigrade, tempValues[tempIdx].address, tempValues[tempIdx].timeStamp);
     }
     
-    // Format message
-    char outBuf[200];
-    sprintf(outBuf, "{\"e\":[{\"n\":\"gasCount\",\"v\":%d},{\"n\":\"gasPulseRateMs\",\"v\":%d,\"u\":\"ms\"}]}", 
-                        gasUseCounter.GetCount(), gasUseCounter.GetPulseRateMs());
-    
+    // Data format of the message - senml - https://tools.ietf.org/html/draft-jennings-senml-08
+    // {
+    //     "e": [
+    //              {"n":"gasCount","v":%d}, 
+    //              {"n":"gasPulseRateMs","v":%d,"u":"ms"},
+    //              {"n":"temp_%s","v":%0.1f,"u":"degC"},
+    //              ...
+    //              {"n":"pump_%d","v":%d},
+    //              ...
+    //          ],
+    //      "bt": %d
+    // }
+
+    time_t timeNow = time(NULL);
+    strcpy(broadcastMsgBuffer, broadcastMsgPrefix);
+    sprintf(broadcastMsgBuffer+strlen(broadcastMsgBuffer), broadcastMsgGasFormat, gasUseCounter.GetCount(), gasUseCounter.GetPulseRateMs());
+    strcpy(broadcastMsgBuffer+strlen(broadcastMsgBuffer), ",");
+    for (int tempIdx = 0; tempIdx < numTempValues; tempIdx++)
+    {
+        sprintf(broadcastMsgBuffer+strlen(broadcastMsgBuffer), broadcastTemperatureFormat, tempValues[tempIdx].address, tempValues[tempIdx].tempInCentigrade);
+        strcpy(broadcastMsgBuffer+strlen(broadcastMsgBuffer), ",");
+    }
+    sprintf(broadcastMsgBuffer+strlen(broadcastMsgBuffer), broadcastVoltAlerterFormat, 1, voltAlerter1.GetState());
+    strcpy(broadcastMsgBuffer+strlen(broadcastMsgBuffer), ",");
+    sprintf(broadcastMsgBuffer+strlen(broadcastMsgBuffer), broadcastVoltAlerterFormat, 2, voltAlerter2.GetState());
+    strcpy(broadcastMsgBuffer+strlen(broadcastMsgBuffer), ",");
+    sprintf(broadcastMsgBuffer+strlen(broadcastMsgBuffer), broadcastVoltAlerterFormat, 3, voltAlerter3.GetState());
+    sprintf(broadcastMsgBuffer+strlen(broadcastMsgBuffer), broadcastMsgSuffix, timeNow);
+        
     // Send
-    int bytesToSend = strlen(outBuf);
-    int rslt = sendUDPSocket.sendTo(broadcastEndpoint, outBuf, bytesToSend);
+    int bytesToSend = strlen(broadcastMsgBuffer);
+    int rslt = sendUDPSocket.sendTo(broadcastEndpoint, broadcastMsgBuffer, bytesToSend);
     if (rslt == bytesToSend)
     {
-        pc.printf("Broadcast Sent ok %s\n", outBuf);
+        pc.printf("Broadcast (len %d) Sent ok %s\r\n", bytesToSend, broadcastMsgBuffer);
     }
     else if (rslt == -1)
     {
-        pc.printf("Broadcast Failed to send %s\n", outBuf);
+        pc.printf("Broadcast Failed to send %s\r\n", broadcastMsgBuffer);
     }
     else
     {
-        pc.printf("Broadcast Didn't send all of %s\n", outBuf);
+        pc.printf("Broadcast Didn't send all of %s\r\n", broadcastMsgBuffer);
     }
     
     // Log
@@ -161,17 +210,21 @@
         else
         {
           printf("Cannot set from NTP\r\n");
-        } 
-        // 1 hour
-        for (int i = 0; i < 60; i++)
+        }
+        
+        // Refresh time every K hours
+        for (int k = 0; k < NTP_REFRESH_INTERVAL_HOURS; k++)
         {
-            for (int j = 0; j < 60; j++)
+            // 1 hour
+            for (int i = 0; i < 60; i++)
             {
-                osDelay(1000);
+                for (int j = 0; j < 60; j++)
+                {
+                    osDelay(1000);
+                }
+                pc.printf("%d mins to next NTP time refresh\r\n", (NTP_REFRESH_INTERVAL_HOURS-k-1)*60 + (59-i));
             }
-            pc.printf("%d mins since NTP\r\n", i);
         }
-        break;
     }
 }
 
@@ -180,6 +233,8 @@
     pc.baud(115200);
     pc.printf("Gas Monitor V2 - Rob Dobson 2014\r\n");
 
+    printf("Broadcast Msg Len %d\r\n", broadcastMsgLen);
+
 //    ticker.attach(&TickFunction,TICK_MS / 1000.0);
 
     // Initialise thermometers
@@ -224,6 +279,12 @@
             SendInfoBroadcast();
             timeOfLastBroadcast = time(NULL);
         }
+        
+        // Service volt alerters
+        voltAlerter1.Service();
+        voltAlerter2.Service();
+        voltAlerter3.Service();
+        led2 = voltAlerter1.GetState();
     }
 }