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
main.cpp
- Committer:
- Bobty
- Date:
- 2015-02-21
- Revision:
- 8:5980547ae71c
- Parent:
- 7:113c68639d10
- Child:
- 9:0e103c2f869a
File content as of revision 8:5980547ae71c:
#include "mbed.h" #include "EthernetInterface.h" #include "NTPClient.h" #include "RdWebServer.h" #include "GasUseCounter.h" #include "RdDS18B20.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"); // Gas use counter DigitalIn gasPulsePin(p21); const char* gasPulseFileName = "/sd/curPulse.txt"; const char* logFilename = "/sd/log.txt"; GasUseCounter gasUseCounter(gasPulseFileName, gasPulsePin, pc); // Thermometers - DS18B20 OneWire Thermometer connections const PinName tempSensorPins[] = { p22 }; const int NUM_THERM_BUSES = sizeof(tempSensorPins)/sizeof(int); DS18B20* thermometerBuses[NUM_THERM_BUSES]; 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; } // 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); } break; } } int main() { pc.baud(115200); pc.printf("Gas Monitor V2 - Rob Dobson 2014\r\n"); // 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(); } // Get the current count from the SD Card gasUseCounter.Init(); // setup ethernet interface eth.init(); //Use DHCP eth.connect(); pc.printf("IP Address is %s\n\r", eth.getIPAddress()); // NTP Time setter Thread ntpTimeSetter(&ntp_thread); // 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; while(true) { osDelay(loopDelayInMs); 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(); } } // 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"); } } } } } }