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 9:0e103c2f869a, committed 2015-02-22
- 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
--- 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);
}
}
}
+