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:
Sun Feb 22 11:57:12 2015 +0000
Parent:
8:5980547ae71c
Child:
10:72eb217def1f
Commit message:
Moved thermometer code to separate class

Changed in this revision

RdDS18B20.cpp Show annotated file Show diff for this revision Revisions of this file
RdDS18B20.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
Thermometers.cpp Show annotated file Show diff for this revision Revisions of this file
Thermometers.h Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
--- a/RdDS18B20.cpp	Sat Feb 21 19:00:08 2015 +0000
+++ b/RdDS18B20.cpp	Sun Feb 22 11:57:12 2015 +0000
@@ -10,6 +10,11 @@
 DS18B20::DS18B20(PinName mbedPin) : _oneWire(mbedPin)
 {
     _numValidAddresses = 0;
+    for (int i = 0; i < MAX_BUS_DEVICES; i++)
+    {
+        _temperatureTable[i] = INVALID_TEMPERATURE;
+        _timeOfReadingTable[i] = 0;    
+    }
 }
 
 // Request conversion
@@ -22,11 +27,11 @@
 }
 
 // Get temperature
-double DS18B20::GetTemperature(int addrIdx)
+double DS18B20::ReadTemperature(int addrIdx)
 {
     // Check valid address
     if ((addrIdx >= _numValidAddresses) || (addrIdx < 0))
-        return -1000.0;
+        return INVALID_TEMPERATURE;
     
     // Init the bus and req reading
     _oneWire.init();
@@ -49,14 +54,22 @@
     
     // Convert temperature
     double temperature = ((temperatureVals[1] * 256) + temperatureVals[0])*0.0625;
+    _temperatureTable[addrIdx] = temperature;
+    _timeOfReadingTable[addrIdx] = time(NULL);
     return temperature; 
 }
 
 // Get address for a device
-uint8_t* DS18B20::GetAddress(int addrIdx)
+uint8_t* DS18B20::GetAddress(int addrIdx, uint8_t* addrBufPtr)
 {
     if ((addrIdx >= _numValidAddresses) || (addrIdx < 0))
         return _addrTable[0];
+    // Make a copy if non-null pointer passed in
+    if (addrBufPtr != NULL)
+    {
+        for( int i = 0; i < ONEWIRE_ADDR_BYTES; i++) 
+            addrBufPtr[i] = _addrTable[addrIdx][i];
+    }
     return _addrTable[addrIdx];
 }
 
@@ -85,6 +98,14 @@
     printf(GetAddressStr(addrIdx));
 }
 
+double DS18B20::GetLatestTemperature(int addrIdx, time_t& timeOfReading)
+{
+    if ((addrIdx >= _numValidAddresses) || (addrIdx < 0))
+        return INVALID_TEMPERATURE;
+    timeOfReading = _timeOfReadingTable[addrIdx];
+    return _temperatureTable[addrIdx];
+}
+
 void DS18B20::SearchToGetAddresses()
 {
     _numValidAddresses = 0;
@@ -104,7 +125,7 @@
 #ifdef SHOW_18B20_DEBUGGING
         printf("Found device addr (ROM) =");
 #endif
-        for( int i = 0; i < 8; i++) 
+        for( int i = 0; i < ONEWIRE_ADDR_BYTES; i++) 
         {
             // Copy to table
             _addrTable[_numValidAddresses][i] = addr[i];
--- a/RdDS18B20.h	Sat Feb 21 19:00:08 2015 +0000
+++ b/RdDS18B20.h	Sun Feb 22 11:57:12 2015 +0000
@@ -8,28 +8,34 @@
 #include "mbed.h"
 #include "Onewire.h"
 
-#define MAX_BUS_DEVICES 8
-
 class DS18B20
 {
 public:
     DS18B20(PinName mbedPin);
     void ReqConvert();
-    double GetTemperature(int addrIdx);
+    double ReadTemperature(int addrIdx);
     void DebugPrintAddress(int addrIdx);
     void SearchToGetAddresses();
     int GetNumAddresses()
     {
         return _numValidAddresses;
     }
-    uint8_t* GetAddress(int addrIdx);
+    uint8_t* GetAddress(int addrIdx, uint8_t* addrBufPtr);
     char* GetAddressStr(int addrIdx);
+    double GetLatestTemperature(int addrIdx, time_t& timeOfReading);
+    
+    static const int ONEWIRE_ADDR_STRLEN = 3 * ONEWIRE_ADDR_BYTES + 1;
+    static const int MAX_BUS_DEVICES = 8;
+    
+    static const int INVALID_TEMPERATURE = -1000.0;
     
 private:
     int _numValidAddresses;
     uint8_t _addrTable[MAX_BUS_DEVICES][ONEWIRE_ADDR_BYTES];
+    double _temperatureTable[MAX_BUS_DEVICES];
+    time_t _timeOfReadingTable[MAX_BUS_DEVICES];
     Onewire _oneWire;
-    char _addrStr[3 * ONEWIRE_ADDR_BYTES + 1];
+    char _addrStr[ONEWIRE_ADDR_STRLEN];
 };
 
 #endif
\ No newline at end of file
--- a/RdWebServer.lib	Sat Feb 21 19:00:08 2015 +0000
+++ b/RdWebServer.lib	Sun Feb 22 11:57:12 2015 +0000
@@ -1,1 +1,1 @@
-http://mbed.org/users/Bobty/code/RdWebServer/#de915bd70ec1
+http://mbed.org/users/Bobty/code/RdWebServer/#35668248199b
--- a/Thermometers.cpp	Sat Feb 21 19:00:08 2015 +0000
+++ b/Thermometers.cpp	Sun Feb 22 11:57:12 2015 +0000
@@ -0,0 +1,127 @@
+// Handles temperature collection from a number of DS18B20 devices
+// Rob Dobson, 2015
+
+#include "Thermometers.h"
+
+// #define SHOW_THERMOMETER_DEBUGGING 1
+
+Thermometers::Thermometers(int numTempSensorPins, const PinName tempSensorPins[], int serviceIntervalInMs)
+{
+    _numTempSensorPins = numTempSensorPins;
+    _tempSensorPins = tempSensorPins;
+    _serviceIntervalInMs = serviceIntervalInMs;
+    _numThermometerBuses = 0;
+}
+
+void Thermometers::Init()
+{
+    // Setup the thermometers
+    for (int busIdx = 0; busIdx < _numTempSensorPins; busIdx++)
+    {
+        if (busIdx >= MAX_ONEWIRE_BUSES)
+            break;
+        _thermometerBuses[busIdx] = new DS18B20(_tempSensorPins[busIdx]);
+        DS18B20* pThermBus = _thermometerBuses[busIdx];
+        pThermBus->SearchToGetAddresses();
+        pThermBus->ReqConvert();
+        _numThermometerBuses++;
+    }
+}
+
+void Thermometers::Service()
+{
+    int numLoopsPerThermReading = numSecondsBetweenThermReadings*1000/_serviceIntervalInMs;
+    int loopCountForRequestingThermReading = numLoopsPerThermReading - (timeForThermReadingInSecs*1000/_serviceIntervalInMs);
+
+    // Check if thermometer addresses need to be got
+    if (_countForThermReadings++ == 0)
+    {
+        if (_countForGetThermometerAddresses++ == 0)
+        {
+#ifdef SHOW_THERMOMETER_DEBUGGING
+            printf("Requested Addresses\r\n");
+#endif
+            for (int busIdx = 0; busIdx < _numThermometerBuses; busIdx++)
+            {
+                DS18B20* pThermBus = _thermometerBuses[busIdx];
+                pThermBus->SearchToGetAddresses();
+            }
+        }
+        else if (_countForGetThermometerAddresses > reGetThermometerAddressesAfterNumReadings)
+        {
+            _countForGetThermometerAddresses = 0;
+        }
+    }
+    else
+    {
+        // Check if time to request thermometer readings
+        if (_countForThermReadings == loopCountForRequestingThermReading)
+        {
+#ifdef SHOW_THERMOMETER_DEBUGGING
+            printf("Requested Conversion\r\n");
+#endif
+            for (int busIdx = 0; busIdx < _numThermometerBuses; busIdx++)
+            {
+                DS18B20* pThermBus = _thermometerBuses[busIdx];
+#ifdef SHOW_THERMOMETER_DEBUGGING
+                printf("Bus %d Num therms %d\r\n", busIdx, pThermBus->GetNumAddresses());
+#endif
+                pThermBus->ReqConvert();
+            }                
+        }
+    
+        // Read thermometers
+        if (_countForThermReadings > numLoopsPerThermReading)
+        {
+            _countForThermReadings = 0;
+#ifdef SHOW_THERMOMETER_DEBUGGING
+            printf("Reading Temp\r\n");
+#endif
+            for (int busIdx = 0; busIdx < _numThermometerBuses; busIdx++)
+            {
+                DS18B20* pThermBus = _thermometerBuses[busIdx];
+                for (int addrIdx = 0; addrIdx < pThermBus->GetNumAddresses(); addrIdx++)
+                {
+                    double tempValue = pThermBus->ReadTemperature(addrIdx);
+#ifdef SHOW_THERMOMETER_DEBUGGING                    
+                    printf("Bus %d Therm %d === %.2fC ... Addr = ", busIdx, addrIdx, tempValue);
+                    pThermBus->DebugPrintAddress(addrIdx);
+                    printf("\r\n");
+#endif
+                }
+            }                
+        }
+    }
+}
+
+int Thermometers::GetTemperatureValues(int maxTempValues, TemperatureValue* tempValues, int maxAgeInSecs)
+{
+    // Go through available values
+    int curTempValueIdx = 0;
+    for (int busIdx = 0; busIdx < _numThermometerBuses; busIdx++)
+    {
+        DS18B20* pThermBus = _thermometerBuses[busIdx];
+        for (int addrIdx = 0; addrIdx < pThermBus->GetNumAddresses(); addrIdx++)
+        {
+            time_t timeOfReading = 0;
+            double tempValue = pThermBus->GetLatestTemperature(addrIdx, timeOfReading);
+            if (tempValue != DS18B20::INVALID_TEMPERATURE)
+            {
+                if ((time(NULL) - timeOfReading) < maxAgeInSecs)
+                {
+                    tempValues[curTempValueIdx].timeStamp = timeOfReading;
+                    strncpy(tempValues[curTempValueIdx].address, pThermBus->GetAddressStr(addrIdx), DS18B20::ONEWIRE_ADDR_STRLEN-1);
+                    tempValues[curTempValueIdx].tempInCentigrade = tempValue;
+                    curTempValueIdx++;
+                    if (curTempValueIdx >= maxTempValues)
+                        break;
+                }
+            }
+        }
+        if (curTempValueIdx >= maxTempValues)
+            break;
+    }
+    return curTempValueIdx;
+}
+
+    
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Thermometers.h	Sun Feb 22 11:57:12 2015 +0000
@@ -0,0 +1,42 @@
+// Handles Thermometers
+// Rob Dobson, 2015
+
+#ifndef Thermometers__H
+#define Thermometers__H
+
+#include "RdDS18B20.h"
+
+struct TemperatureValue
+{
+    time_t timeStamp;
+    char address[DS18B20::ONEWIRE_ADDR_STRLEN];
+    double tempInCentigrade;
+};
+
+class Thermometers
+{
+public:
+    Thermometers(int numTempSensorPins, const PinName tempSensorPins[], int serviceIntervalInMs);
+    void Init();
+    void Service();
+    int GetTemperatureValues(int maxTempValues, TemperatureValue* tempValues, int maxAgeInSecs);
+    static const int numSecondsBetweenThermReadings = 10;
+    static const int timeForThermReadingInSecs = 2;
+    static const int reGetThermometerAddressesAfterNumReadings = 100;
+    static const int MAX_ONEWIRE_BUSES = 1;
+    static const int MAX_THERMOMETERS = 8;
+    
+private:
+    // Thermometer info
+    int _numTempSensorPins;
+    const PinName* _tempSensorPins;
+    int _numThermometerBuses;
+    DS18B20* _thermometerBuses[MAX_ONEWIRE_BUSES];
+    int _serviceIntervalInMs;
+
+    // Counters for state machine
+    int _countForThermReadings;
+    int _countForGetThermometerAddresses;
+};
+
+#endif
--- a/main.cpp	Sat Feb 21 19:00:08 2015 +0000
+++ b/main.cpp	Sun Feb 22 11:57:12 2015 +0000
@@ -3,7 +3,7 @@
 #include "NTPClient.h"
 #include "RdWebServer.h"
 #include "GasUseCounter.h"
-#include "RdDS18B20.h"
+#include "Thermometers.h"
 #include <stdarg.h>
 
 // Web and UDB ports 
@@ -13,6 +13,7 @@
 // Ticker collects data
 //Ticker ticker;
 //const int TICK_MS = 250;
+const int LOOP_DELAY_IN_MS = 250;
 
 // Debugging and status
 RawSerial pc(USBTX, USBRX);
@@ -38,9 +39,9 @@
 
 // Thermometers - DS18B20 OneWire Thermometer connections
 const PinName tempSensorPins[] = { p22 };
-const int NUM_THERM_BUSES = sizeof(tempSensorPins)/sizeof(int);
-DS18B20* thermometerBuses[NUM_THERM_BUSES];
+Thermometers thermometers(sizeof(tempSensorPins)/sizeof(PinName), tempSensorPins, LOOP_DELAY_IN_MS);
 
+// Utility function to log data
 void LogData(const char* format, ...)
 {
     FILE* fp = fopen(logFilename, "a");
@@ -58,6 +59,7 @@
     }
 }
 
+// Send broadcast message with current data
 void SendInfoBroadcast()
 {
     led3 = true;
@@ -66,6 +68,15 @@
     sendUDPSocket.set_broadcasting();
     broadcastEndpoint.set_address("255.255.255.255", BROADCAST_PORT);
     
+    // 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\"}]}", 
@@ -110,7 +121,7 @@
 
 char* setGasUseCallback(int method, char* cmdStr, char* argStr)
 {
-    pc.printf("Setting gas use count %s\n\r", argStr);
+    pc.printf("Setting gas use count %s\r\n", argStr);
     int newGasUse = 0;
     char* eqStr = strchr(argStr, '=');
     if (eqStr == NULL)
@@ -158,12 +169,12 @@
             {
                 osDelay(1000);
             }
-            pc.printf("Waited %d mins\r\n", i);
+            pc.printf("%d mins since NTP\r\n", i);
         }
         break;
     }
 }
-    
+
 int main()
 {
     pc.baud(115200);
@@ -171,18 +182,9 @@
 
 //    ticker.attach(&TickFunction,TICK_MS / 1000.0);
 
-    // Setup the thermometers
-    for (int thermIdx = 0; thermIdx < NUM_THERM_BUSES; thermIdx++)
-        thermometerBuses[thermIdx] = new DS18B20(tempSensorPins[thermIdx]);
-        
-    // Initialise thermometers   
-    for (int thermIdx = 0; thermIdx < NUM_THERM_BUSES; thermIdx++)
-    {
-        DS18B20* pThermBus = thermometerBuses[thermIdx];
-        pThermBus->SearchToGetAddresses();
-        pThermBus->ReqConvert();
-    }
-
+    // Initialise thermometers
+    thermometers.Init();
+    
     // Get the current count from the SD Card
     gasUseCounter.Init();
     
@@ -190,7 +192,7 @@
     eth.init(); //Use DHCP
     eth.connect();
     
-    pc.printf("IP Address is %s\n\r", eth.getIPAddress());
+    pc.printf("IP Address is %s\r\n", eth.getIPAddress());
     
     // NTP Time setter
     Thread ntpTimeSetter(&ntp_thread);
@@ -198,70 +200,30 @@
     // Web Server
     Thread httpServer(&http_thread, NULL, osPriorityNormal, (DEFAULT_STACK_SIZE * 3));
     
-    const int loopDelayInMs = 250;
-    const int numSecondsBetweenThermReadings = 10;
-    const int numLoopsPerThermReading = numSecondsBetweenThermReadings*1000/loopDelayInMs;
-    const int timeForThermReadingInSecs = 2;
-    const int loopCountForRequestingThermReading = numLoopsPerThermReading - (timeForThermReadingInSecs*1000/loopDelayInMs);
-    int countForThermReadings = 0;
-    const int reGetThermometerAddressesAfterNumReadings = 100;
-    int countForGetThermometerAddresses = 0;
+    // Time of last broadcast
+    time_t timeOfLastBroadcast = time(NULL);
+    const int TIME_BETWEEN_BROADCASTS_IN_SECS = 60;
     while(true)
     {
-        osDelay(loopDelayInMs);
+        osDelay(LOOP_DELAY_IN_MS);
         led1 = !led1;
 
         // Service gas count
         if (gasUseCounter.Service())
-            SendInfoBroadcast();
-        
-        // Check if thermometer addresses need to be got
-        if (countForThermReadings++ == 0)
-        {
-            if (countForGetThermometerAddresses++ == 0)
-            {
-                printf("Requested Addresses\n\r");
-                for (int thermIdx = 0; thermIdx < NUM_THERM_BUSES; thermIdx++)
-                {
-                    DS18B20* pThermBus = thermometerBuses[thermIdx];
-                    pThermBus->SearchToGetAddresses();
-                }
-            }
-            else if (countForGetThermometerAddresses > reGetThermometerAddressesAfterNumReadings)
-            {
-                countForGetThermometerAddresses = 0;
-            }
-        }
-        else
         {
-            // Check if time to request thermometer readings
-            if (countForThermReadings == loopCountForRequestingThermReading)
-            {
-                printf("Requested Convert\n\r");
-                for (int thermIdx = 0; thermIdx < NUM_THERM_BUSES; thermIdx++)
-                {
-                    DS18B20* pThermBus = thermometerBuses[thermIdx];
-                    printf("Bus %d Num therms %d\n\r", thermIdx, pThermBus->GetNumAddresses());
-                    pThermBus->ReqConvert();
-                }                
-            }
+            SendInfoBroadcast();
+            timeOfLastBroadcast = time(NULL);
+        }
         
-            // Read thermometers
-            if (countForThermReadings > numLoopsPerThermReading)
-            {
-                countForThermReadings = 0;
-                printf("Reading Temp\n\r");
-                for (int thermIdx = 0; thermIdx < NUM_THERM_BUSES; thermIdx++)
-                {
-                    DS18B20* pThermBus = thermometerBuses[thermIdx];
-                    for (int addrIdx = 0; addrIdx < pThermBus->GetNumAddresses(); addrIdx++)
-                    {
-                        printf("Bus %d Therm %d === %.2fC ... Addr = ", thermIdx, addrIdx, pThermBus->GetTemperature(addrIdx));
-                        pThermBus->DebugPrintAddress(addrIdx);
-                        printf("\r\n");
-                    }
-                }                
-            }
+        // Service thermometers
+        thermometers.Service();
+        
+        // Check if ready for a broadcast
+        if ((time(NULL) - timeOfLastBroadcast) >= TIME_BETWEEN_BROADCASTS_IN_SECS)
+        {
+            SendInfoBroadcast();
+            timeOfLastBroadcast = time(NULL);
         }
     }
 }
+