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

Files at this revision

API Documentation at this revision

Comitter:
Bobty
Date:
Tue Feb 17 21:33:39 2015 +0000
Parent:
4:0d3a207680b0
Child:
6:b7064d33e402
Commit message:
Tidied up - but is unstable - web server crashes after some time

Changed in this revision

GasUseCounter.cpp Show annotated file Show diff for this revision Revisions of this file
GasUseCounter.h Show annotated file Show diff for this revision Revisions of this file
NTPClient.lib Show annotated file Show diff for this revision Revisions of this file
PulsePin.cpp Show annotated file Show diff for this revision Revisions of this file
PulsePin.h Show annotated file Show diff for this revision Revisions of this file
RdWebServer.lib Show annotated file Show diff for this revision Revisions of this file
SDFileSystem-RTOS.lib Show annotated file Show diff for this revision Revisions of this file
SDFileSystem.lib Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
mbed-rtos.lib Show annotated file Show diff for this revision Revisions of this file
mbed-src.lib Show annotated file Show diff for this revision Revisions of this file
mbed.bld Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/GasUseCounter.cpp	Tue Feb 17 21:33:39 2015 +0000
@@ -0,0 +1,71 @@
+#include "GasUseCounter.h"
+
+// Callback from web server to handle getting current gas count
+char* GasUseCounter::getGasUseCallback(char* cmdStr, char* argStr)
+{
+    sprintf(_gasCountStr, "{\"gasUseCount\":\"%d\"}", GetCount());
+    return _gasCountStr;
+}
+
+// Init
+void GasUseCounter::Init()
+{
+    GetGasCountFromSD();
+}
+    
+// Service function
+bool GasUseCounter::Service()
+{
+    // Check for an edge
+    bool edgeDetected = _pulseDetector->Service();
+    if (edgeDetected)
+    {
+        // Check if we need to store in non-volatile storage
+        if (GetCount() >= _lastWrittenGasCount + MAX_PULSES_BEFORE_STORE_NV)
+        {
+            WriteGasCountToSD();
+            _lastWrittenGasCount = GetCount();
+        }
+            
+        // Show count
+        _pc.printf("Count %d Rate(ms) %d\r\n", _pulseDetector->GetPulseCount(), _pulseDetector->GetPulseRateMs());
+    }   
+    return edgeDetected;
+}
+    
+// Get the current usage count from SD card
+void GasUseCounter::GetGasCountFromSD()
+{
+    FILE* fp = fopen(_gasUseFilename, "r");
+    if (fp == NULL)
+    {
+        _pc.printf ("Read Gas ... Filename %s not found\r\n", _gasUseFilename);
+    }
+    else
+    {
+        int curCount = 0;
+        int retVal = fscanf(fp, "%d", &curCount);
+        fclose(fp);
+        if (retVal == 1)
+            _pc.printf ("Read from SD last gas count = %d\r\n", curCount);
+        else
+            _pc.printf ("Failed to read gas count from SD card\r\n");
+        _lastWrittenGasCount = curCount;
+        _pulseDetector->SetPulseCount(curCount);
+    }
+}
+
+void GasUseCounter::WriteGasCountToSD()
+{
+    FILE* fp = fopen(_gasUseFilename, "w");
+    if (fp == NULL)
+    {
+        _pc.printf ("WriteGas ... Filename %s not found\r\n", _gasUseFilename);
+    }
+    else
+    {
+        fprintf(fp, "%d", GetCount());
+        _pc.printf ("Written to SD last gas count = %d\r\n", GetCount());
+        fclose(fp);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/GasUseCounter.h	Tue Feb 17 21:33:39 2015 +0000
@@ -0,0 +1,69 @@
+#ifndef __GASUSECOUNTER__H
+#define __GASUSECOUNTER__H
+#include "mbed.h"
+#include "PulsePin.h"
+#include "SDFileSystem.h"
+#include <RawSerial.h>
+
+const int MAX_GAS_COUNT_STR_LEN = 50;
+const int MAX_PULSES_BEFORE_STORE_NV = 1; // Store at each pulse
+
+class GasUseCounter
+{
+    public:
+        // Constructor
+        GasUseCounter(const char* gasUseFilename, DigitalIn& gasPulsePin, RawSerial &pc) :
+                _gasPulsePin(gasPulsePin), _pc(pc)
+        {
+            _gasUseFilename = gasUseFilename;
+            _lastWrittenGasCount = 0;
+            _pulseDetector = new PulsePin(_gasPulsePin, false, 200);
+        }
+        
+        // Init (get count from NV)
+        void Init();
+        
+        // Callback from web server to handle getting current gas count
+        char* getGasUseCallback(char* cmdStr, char* argStr);
+
+        // Service function to detect pulses
+        bool Service();
+        
+        // Read/Write current gas count
+        void GetGasCountFromSD();
+        void WriteGasCountToSD();
+        
+        // Get Count
+        int GetCount()
+        {
+            return _pulseDetector->GetPulseCount();
+        }
+        
+        // Set Count
+        void SetCount(int gasUseCount)
+        {
+            _pulseDetector->SetPulseCount(gasUseCount);
+            WriteGasCountToSD();
+        }
+        
+        // Get inter-pulse time
+        int GetPulseRateMs()
+        {
+            return _pulseDetector->GetPulseRateMs();
+        }
+        
+    private:
+        // Gas use filename for non-volatile
+        const char* _gasUseFilename;
+        int _curGasCount;
+        int _lastWrittenGasCount;
+        char _gasCountStr [MAX_GAS_COUNT_STR_LEN];
+        DigitalIn& _gasPulsePin;
+        PulsePin* _pulseDetector;
+        RawSerial& _pc;
+};
+
+
+
+
+#endif
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/NTPClient.lib	Tue Feb 17 21:33:39 2015 +0000
@@ -0,0 +1,1 @@
+http://developer.mbed.org/users/donatien/code/NTPClient/#881559865a93
--- a/PulsePin.cpp	Mon Feb 02 16:24:30 2015 +0000
+++ b/PulsePin.cpp	Tue Feb 17 21:33:39 2015 +0000
@@ -13,12 +13,27 @@
     _lastStableTimeMs = _pinTimer.read_ms();
     _firstEdgeDetected = false;
     _timeBetweenEdgesMs = 0;
+    _pulseCount = 0;
+    _pinTimerMinutes = 0;
 }
 
 bool PulsePin::Service()
 {
     // Check time since last edge - looking for stability
     int timeNowMs = _pinTimer.read_ms();
+    
+    // Check if over 1 minute (as the timer wraps around after 30 mins)
+    if (timeNowMs > 60000)
+    {
+        _pinTimerMinutes++;
+        _pinTimer.reset();
+        timeNowMs -= 60000;
+    }
+    
+    // Get the real time elapsed (still wraps but now only after about 500 hours)
+    timeNowMs = _pinTimerMinutes*60000 + timeNowMs;
+    
+    // Check for pin stabilization    
     if (timeNowMs < _lastStableTimeMs + _waitForPinStabilisationMs)
         return false;
 
@@ -36,6 +51,7 @@
         
     // Reset the timer to avoid wrap around problems
     bool firstEdgeDetected = _firstEdgeDetected;
+    _pinTimerMinutes = 0;
     _pinTimer.reset();
     _firstEdgeDetected = true;
     _lastStableTimeMs = 0;
@@ -44,10 +60,21 @@
     if (!firstEdgeDetected)
         return false;
     _timeBetweenEdgesMs = timeNowMs;
+    _pulseCount++;
     return true;
 }
 
-int PulsePin::GetLastCycleTimeMs()
+int PulsePin::GetPulseRateMs()
 {
     return _timeBetweenEdgesMs;
 }
+
+int PulsePin::GetPulseCount()
+{
+    return _pulseCount;
+}
+
+void PulsePin::SetPulseCount(int pulseCount)
+{
+    _pulseCount = pulseCount;
+}
--- a/PulsePin.h	Mon Feb 02 16:24:30 2015 +0000
+++ b/PulsePin.h	Tue Feb 17 21:33:39 2015 +0000
@@ -7,8 +7,10 @@
     public:
         PulsePin(DigitalIn& pin, bool risingEdge, int pinStableTimeMs);
         bool Service();
-        int GetLastCycleTimeMs();
-    
+        int GetPulseRateMs();
+        int GetPulseCount();
+        void SetPulseCount(int pulseCount);
+
     private:
         DigitalIn& _pin;
         Timer _pinTimer;
@@ -18,6 +20,8 @@
         int _waitForPinStabilisationMs;
         bool _detectRisingEdge;
         int _timeBetweenEdgesMs;
+        int _pulseCount;
+        int _pinTimerMinutes;
 };
 
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/RdWebServer.lib	Tue Feb 17 21:33:39 2015 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/Bobty/code/RdWebServer/#fe7c33f7fbb8
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/SDFileSystem-RTOS.lib	Tue Feb 17 21:33:39 2015 +0000
@@ -0,0 +1,1 @@
+http://developer.mbed.org/users/Sissors/code/SDFileSystem-RTOS/#da69a01b8096
--- a/SDFileSystem.lib	Mon Feb 02 16:24:30 2015 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-http://developer.mbed.org/users/mbed_official/code/SDFileSystem/#7b35d1709458
--- a/main.cpp	Mon Feb 02 16:24:30 2015 +0000
+++ b/main.cpp	Tue Feb 17 21:33:39 2015 +0000
@@ -1,93 +1,189 @@
 #include "mbed.h"
 #include "EthernetInterface.h"
-#include "PulsePin.h"
-#include "SDFileSystem.h"
- 
+#include "NTPClient.h"
+#include "RdWebServer.h"
+#include "GasUseCounter.h"
+#include <stdarg.h>
+
+// Web and UDB ports 
+const int WEBPORT = 80; // Port for web server
+const int BROADCAST_PORT = 42853; // Arbitrarily chosen port number
+
+// Ticker collects data
+Ticker ticker;
+const int TICK_MS = 250;
+
+// Debugging and status
+RawSerial pc(USBTX, USBRX);
+DigitalOut led1(LED1); //ticking (flashes)
+DigitalOut led2(LED2); //server listning status (flashes)
+DigitalOut led3(LED3); //socket connecting status
+DigitalOut led4(LED4); //server status
+
+// Web server
+EthernetInterface eth;
+NTPClient ntp;
+UDPSocket sendUDPSocket;
+Endpoint broadcastEndpoint;
+
+// File system for SD card
 SDFileSystem sd(p5, p6, p7, p8, "sd");
-DigitalIn gpPin(p21);
-PulsePin pulsePin(gpPin, false, 200);
-DigitalOut led(LED1);
+
+// Gas use counter
+DigitalIn gasPulsePin(p21);
+const char* gasPulseFileName = "/sd/curPulse.txt";
+const char* logFilename = "/sd/log.txt";
+GasUseCounter gasUseCounter(gasPulseFileName, gasPulsePin, pc);
+
+void LogData(const char* format, ...)
+{
+    FILE* fp = fopen(logFilename, "a");
+    if (fp == NULL)
+    {
+        pc.printf ("Log ... Filename %s not found\r\n", logFilename);
+    }
+    else
+    {
+        va_list argptr;
+        va_start(argptr, format);
+        vfprintf(fp, format, argptr);
+        va_end(argptr);
+        fclose(fp);
+    }
+}
+
+void SendInfoBroadcast()
+{
+    led3 = true;
+    // Init the sending socket
+    sendUDPSocket.init();
+    sendUDPSocket.set_broadcasting();
+    broadcastEndpoint.set_address("255.255.255.255", BROADCAST_PORT);
+    
+    // Format message
+    char outBuf[200];
+    sprintf(outBuf, "{\"e\":[{\"n\":\"gasCount\",\"v\":%d},{\"n\":\"gasPulseRateMs\",\"v\":%d,\"u\":\"ms\"}]}", 
+                        gasUseCounter.GetCount(), gasUseCounter.GetPulseRateMs());
+    
+    // Send
+    int bytesToSend = strlen(outBuf);
+    int rslt = sendUDPSocket.sendTo(broadcastEndpoint, outBuf, bytesToSend);
+    if (rslt == bytesToSend)
+    {
+        pc.printf("Broadcast Sent ok %s\n", outBuf);
+    }
+    else if (rslt == -1)
+    {
+        pc.printf("Broadcast Failed to send %s\n", outBuf);
+    }
+    else
+    {
+        pc.printf("Broadcast Didn't send all of %s\n", outBuf);
+    }
+    
+    // Log
+    char timeBuf[32];
+    time_t seconds = time(NULL);
+    strftime(timeBuf, 32, "%Y-%m-%d %H:%M:%S", localtime(&seconds));
+    LogData("%s\t%d\t%d ms\n", timeBuf, gasUseCounter.GetCount(), gasUseCounter.GetPulseRateMs());
+    
+    led3 = false;
+}
 
-const int BROADCAST_PORT = 42853; // Arbitrarily chosen port number
-Serial pc(USBTX, USBRX);
+// Ticker's tick function
+void TickFunction()
+{
+}
+
+char* getGasUseCallback(int method, char* cmdStr, char* argStr)
+{
+    char* pResp = gasUseCounter.getGasUseCallback(cmdStr, argStr);
+    pc.printf("Returning gas use %s\r\n", pResp);
+    return pResp;
+}
+
+char* setGasUseCallback(int method, char* cmdStr, char* argStr)
+{
+    pc.printf("Setting gas use count %s\n\r", argStr);
+    int newGasUse = 0;
+    char* eqStr = strchr(argStr, '=');
+    if (eqStr == NULL)
+        return "SetGasValue FAILED";
+    sscanf(eqStr+1, "%d", &newGasUse);
+    gasUseCounter.SetCount(newGasUse);
+    return "SetGasValue OK";
+}
+
+void http_thread(void const* arg)
+{
+    char* baseWebFolder = "/sd/";
+
+    RdWebServer webServer;
+    webServer.addCommand("", RdWebServerCmdDef::CMD_SDORUSBFILE, NULL, "index.htm", false);
+    webServer.addCommand("gear-gr.png", RdWebServerCmdDef::CMD_SDORUSBFILE, NULL, NULL, true);
+    webServer.addCommand("getgascount", RdWebServerCmdDef::CMD_CALLBACK, &getGasUseCallback);
+    webServer.addCommand("setgascount", RdWebServerCmdDef::CMD_CALLBACK, &setGasUseCallback);
 
+    webServer.init(WEBPORT, &led4, baseWebFolder);
+
+    webServer.run();
+}
+
+void ntp_thread(void const* arg)
+{
+    while (1)
+    {
+        pc.printf("Trying to update time...\r\n");
+        if (ntp.setTime("0.pool.ntp.org") == 0)
+        {
+          printf("Set time successfully\r\n");
+          time_t ctTime;
+          ctTime = time(NULL);
+          printf("Time is set to (UTC): %s\r\n", ctime(&ctTime));
+        }
+        else
+        {
+          printf("Cannot set from NTP\r\n");
+        } 
+        // 1 hour
+        for (int i = 0; i < 60; i++)
+        {
+            for (int j = 0; j < 60; j++)
+            {
+                osDelay(1000);
+            }
+            pc.printf("Waited %d mins\r\n", i);
+        }
+    }
+}
+    
 int main()
 {
     pc.baud(115200);
-    printf("Gas Monitor - Rob Dobson 2014\n");
+    pc.printf("Gas Monitor V2 - Rob Dobson 2014\r\n");
 
-    EthernetInterface eth;
-    eth.init(); //Use DHCP
-    UDPSocket sendSocket;
-    Endpoint broadcast;
+    ticker.attach(&TickFunction,TICK_MS / 1000.0);
+
+    // Get the current count from the SD Card
+    gasUseCounter.Init();
     
-    // Connection establishment/re-establishment
-    Timer connectRetryTimer;
-    connectRetryTimer.start();
-    bool isConnected = false;
+    // setup ethernet interface
+    eth.init(); //Use DHCP
+    eth.connect();
     
-    // Count of gas pulses
-    int gasCount = 0;
+    pc.printf("IP Address is %s\n\r", eth.getIPAddress());
+
+    Thread ntpTimeSetter(&ntp_thread);
     
-    // Forever    
-    while (true)
+    Thread httpServer(&http_thread, NULL, osPriorityNormal, (DEFAULT_STACK_SIZE * 2.25));
+    
+    while(true)
     {
-        // Check if already connected to ethernet
-        if (!isConnected)
-        {
-            if (connectRetryTimer.read_ms() > 1000)
-            {
-                isConnected = eth.connect() == 0;
-                connectRetryTimer.reset();
-                if (isConnected)
-                {
-                    printf("Eth Connected - IP Address is %s - MAC is %s\n", eth.getIPAddress(), eth.getMACAddress());
-                    sendSocket.init();
-                    sendSocket.set_broadcasting();
-                    broadcast.set_address("255.255.255.255", BROADCAST_PORT);
-                    }
-                else
-                {
-                    printf("Eth Connect Attempt Failed\n");
-                }
-            }
-        }
-        else
-        {
-            led = gpPin;
-            // Check for an edge
-            bool edgeDetected = pulsePin.Service();
-            if (edgeDetected)
-            {
-                gasCount++;
-                char outBuf[200];
-                sprintf(outBuf, "{\"e\":[{\"n\":\"gasCount\",\"v\":%d},{\"n\":\"gasInterPulse\",\"v\":%d,\"u\":\"ms\"}]}", 
-                                    gasCount, pulsePin.GetLastCycleTimeMs());
-                int bytesToSend = strlen(outBuf);
-                int rslt = sendSocket.sendTo(broadcast, outBuf, bytesToSend);
-                if (rslt == bytesToSend)
-                {
-                    printf("Sent ok %s\n", outBuf);
-                }
-                else if (rslt == -1)
-                {
-                    printf("Failed to send %s\n", outBuf);
-                    isConnected = false;
-                }
-                else
-                {
-                    printf("Didn't send all of %s\n", outBuf);
-                    isConnected = false;
-                }
-            }
-            
-            // See if anything has failed
-            if (!isConnected)
-            {
-                sendSocket.close();
-                eth.disconnect();
-                Thread::wait(1000);
-            }
-        }
+        osDelay(250);
+        led1 = !led1;
+
+        // Service gas count
+        if (gasUseCounter.Service())
+            SendInfoBroadcast();
     }
-}
\ No newline at end of file
+}
--- a/mbed-rtos.lib	Mon Feb 02 16:24:30 2015 +0000
+++ b/mbed-rtos.lib	Tue Feb 17 21:33:39 2015 +0000
@@ -1,1 +1,1 @@
-http://mbed.org/users/mbed_official/code/mbed-rtos/#db1fc233faa9
+http://mbed.org/users/mbed_official/code/mbed-rtos/#5448826aa700
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-src.lib	Tue Feb 17 21:33:39 2015 +0000
@@ -0,0 +1,1 @@
+http://developer.mbed.org/users/mbed_official/code/mbed-src/#e03396e14338
--- a/mbed.bld	Mon Feb 02 16:24:30 2015 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-http://mbed.org/users/mbed_official/code/mbed/builds/7e6c9f46b3bd
\ No newline at end of file