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 21:ccf053bab795, committed 2015-10-16
- Comitter:
- Bobty
- Date:
- Fri Oct 16 08:37:30 2015 +0000
- Parent:
- 20:7933076df5af
- Child:
- 22:14b4060dd027
- Commit message:
- Added names to thermometers and pumps; Added file upload and delete
Changed in this revision
--- a/Onewire.lib Tue Oct 13 18:35:20 2015 +0000 +++ b/Onewire.lib Fri Oct 16 08:37:30 2015 +0000 @@ -1,1 +1,1 @@ -https://developer.mbed.org/users/Bobty/code/Onewire/#d2452e9b169b +https://developer.mbed.org/users/Bobty/code/Onewire/#5d0bd95b586f
--- a/RdDS18B20.cpp Tue Oct 13 18:35:20 2015 +0000
+++ b/RdDS18B20.cpp Fri Oct 16 08:37:30 2015 +0000
@@ -172,7 +172,8 @@
if (rslt != ONEWIRE_OK)
{
#ifdef SHOW_18B20_DEBUGGING
- _logger.LogDebug("Search returned %s", (rslt == ONEWIRE_SEARCH_INIT_FAIL) ? "InitFail" : ((rslt == ONEWIRE_SEARCH_NOT_FOUND) ? "NotFound" : "UnknownError"));
+// _logger.LogDebug("Search returned %s", _oneWire.GetErrorStr(rslt));
+ _logger.LogDebug("Search returned %d", rslt);
#endif
break;
}
@@ -206,11 +207,11 @@
switch (val)
{
case 0x10:
- return("Chip = DS18S20\r\n"); // or old DS1820
+ return("Chip = DS18S20"); // or old DS1820
case 0x28:
- return("Chip = DS18B20\r\n");
+ return("Chip = DS18B20");
case 0x22:
- return("Chip = DS1822\r\n");
+ return("Chip = DS1822");
}
- return("Chip NOT DS18x20 FAMILY\r\n");
+ return("Chip NOT DS18x20 FAMILY");
}
--- a/Thermometers.cpp Tue Oct 13 18:35:20 2015 +0000
+++ b/Thermometers.cpp Fri Oct 16 08:37:30 2015 +0000
@@ -122,11 +122,11 @@
double tempValue = pThermBus->GetLatestTemperature(addrIdx, timeOfReading);
int ageInSecs = time(NULL) - timeOfReading;
if (tempValue == DS18B20::INVALID_TEMPERATURE)
- sprintf(tempStrBuf+strlen(tempStrBuf), "%.2fC (INVALID) ", tempValue);
- else if (ageInSecs == 0)
- sprintf(tempStrBuf+strlen(tempStrBuf), "%.2fC ", tempValue);
+ sprintf(tempStrBuf+strlen(tempStrBuf), "%.1fC (INVALID) ", tempValue);
+ else if (ageInSecs <= 2)
+ sprintf(tempStrBuf+strlen(tempStrBuf), "%.1fC ", tempValue);
else
- sprintf(tempStrBuf+strlen(tempStrBuf), "%.2fC (%dS ago) ", tempValue, ageInSecs);
+ sprintf(tempStrBuf+strlen(tempStrBuf), "%.1fC (%dS ago) ", tempValue, ageInSecs);
}
}
_logger.LogDebug("Therm %s", tempStrBuf);
--- a/main.cpp Tue Oct 13 18:35:20 2015 +0000
+++ b/main.cpp Fri Oct 16 08:37:30 2015 +0000
@@ -46,6 +46,9 @@
// File system for SD card
SDFileSystem sd(p5, p6, p7, p8, "sd");
+// Base folder for web file system
+char* baseWebFolder = "/sd/";
+
// Log file names
const char* gasPulseFileName1 = "/sd/curPulse.txt";
const char* gasPulseFileName2 = "/sd/curPulse2.txt";
@@ -87,19 +90,68 @@
// }
const char broadcastMsgPrefix[] = "{\"e\":[";
const char broadcastMsgGasFormat[] = "{\"n\":\"gasCount\",\"v\":%d,\"u\":\"count\"},{\"n\":\"gasPulseRateMs\",\"v\":%d,\"u\":\"ms\"}";
-const char broadcastTemperatureFormat[] = "{\"n\":\"temp_%s\",\"v\":%0.1f,\"u\":\"degC\"}";
-const char broadcastVoltAlerterFormat[] = "{\"n\":\"pump_%d\",\"bv\":%d}";
+const char broadcastTemperatureFormat[] = "{\"n\":\"temp_%s_%s\",\"v\":%0.1f,\"u\":\"degC\"}";
+const char broadcastVoltAlerterFormat[] = "{\"n\":\"pump_%d_%s\",\"bv\":%d}";
const char broadcastMsgSuffix[] = "],\"bt\":%d}";
// Broadcast message length and buffer
+const int MAX_DEVICE_NAME_LEN = 20;
const int broadcastMsgLen = sizeof(broadcastMsgPrefix) +
sizeof(broadcastMsgGasFormat) +
- (sizeof(broadcastTemperatureFormat)*Thermometers::MAX_THERMOMETERS) +
- (sizeof(broadcastVoltAlerterFormat)*NUM_VOLT_ALERTERS) +
+ ((sizeof(broadcastTemperatureFormat)+MAX_DEVICE_NAME_LEN)*Thermometers::MAX_THERMOMETERS) +
+ ((sizeof(broadcastVoltAlerterFormat)+MAX_DEVICE_NAME_LEN)*NUM_VOLT_ALERTERS) +
sizeof(broadcastMsgSuffix) +
60;
char broadcastMsgBuffer[broadcastMsgLen];
-
+
+// Handling of SD card file delete and file upload commands
+const int MAX_FNAME_LENGTH = 127;
+char fileNameForWrite[MAX_FNAME_LENGTH+1] = "";
+int fileRemainingForWrite = 0;
+
+// Thermometer and pump names
+char thermometerAddrs[][MAX_DEVICE_NAME_LEN] =
+{
+ "28b1b1e0050000d0",
+ "289dd7c705000060",
+ "28b3b0c60500000a"
+};
+char thermometerNames[][MAX_DEVICE_NAME_LEN] =
+{
+ "HWCylinder",
+ "Inflow2",
+ "Outflow2"
+};
+int numNamedThermometers = 3;
+
+char voltAlerterNames[][MAX_DEVICE_NAME_LEN] =
+{
+ "PumpUpper",
+ "PumpLower",
+ "PumpHW"
+};
+
+// Get names of thermometers
+char* getThermometerName(char* thermAddr)
+{
+ for (int i = 0; i < numNamedThermometers; i++)
+ {
+ if (strcmp(thermometerAddrs[i], thermAddr) == 0)
+ return thermometerNames[i];
+ }
+ return "Unknown";
+}
+
+// Get names of volt alerters
+char* getVoltAlerterName(int idx)
+{
+ if (idx >= 0 && idx < NUM_VOLT_ALERTERS)
+ {
+ return voltAlerterNames[idx];
+ }
+ return "Unknown";
+}
+
// Format broadcast message
void GenBroadcastMessage()
{
@@ -118,14 +170,16 @@
strcpy(broadcastMsgBuffer+strlen(broadcastMsgBuffer), ",");
for (int tempIdx = 0; tempIdx < numTempValues; tempIdx++)
{
- sprintf(broadcastMsgBuffer+strlen(broadcastMsgBuffer), broadcastTemperatureFormat, tempValues[tempIdx].address, tempValues[tempIdx].tempInCentigrade);
+ sprintf(broadcastMsgBuffer+strlen(broadcastMsgBuffer), broadcastTemperatureFormat, tempValues[tempIdx].address,
+ getThermometerName(tempValues[tempIdx].address),
+ tempValues[tempIdx].tempInCentigrade);
strcpy(broadcastMsgBuffer+strlen(broadcastMsgBuffer), ",");
}
- sprintf(broadcastMsgBuffer+strlen(broadcastMsgBuffer), broadcastVoltAlerterFormat, 1, voltAlerter1.GetState());
+ sprintf(broadcastMsgBuffer+strlen(broadcastMsgBuffer), broadcastVoltAlerterFormat, 1, getVoltAlerterName(0), voltAlerter1.GetState());
strcpy(broadcastMsgBuffer+strlen(broadcastMsgBuffer), ",");
- sprintf(broadcastMsgBuffer+strlen(broadcastMsgBuffer), broadcastVoltAlerterFormat, 2, voltAlerter2.GetState());
+ sprintf(broadcastMsgBuffer+strlen(broadcastMsgBuffer), broadcastVoltAlerterFormat, 2, getVoltAlerterName(1), voltAlerter2.GetState());
strcpy(broadcastMsgBuffer+strlen(broadcastMsgBuffer), ",");
- sprintf(broadcastMsgBuffer+strlen(broadcastMsgBuffer), broadcastVoltAlerterFormat, 3, voltAlerter3.GetState());
+ sprintf(broadcastMsgBuffer+strlen(broadcastMsgBuffer), broadcastVoltAlerterFormat, 3, getVoltAlerterName(2), voltAlerter3.GetState());
sprintf(broadcastMsgBuffer+strlen(broadcastMsgBuffer), broadcastMsgSuffix, timeNow);
}
@@ -185,16 +239,192 @@
return "SetGasValue OK";
}
+// Handle SD Card File Delete
+char* sdCardDelete(int method, char* cmdStr, char* argStr, char* msgBuffer, int msgLen,
+ int contentLen, unsigned char* pPayload, int payloadLen, int splitPayloadPos)
+{
+ printf("Delete file %s\r\n", argStr);
+ sdCardMutex.lock();
+ char* baseWebFolder = "/sd/";
+ char filename[MAX_FNAME_LENGTH+1];
+ sprintf(filename, "%s%s", baseWebFolder, argStr);
+ printf("Full filename for delete is %s\r\n", filename);
+ bool delOk = (remove(filename) == 0);
+ sdCardMutex.unlock();
+ if (delOk)
+ return "Delete OK";
+ return "Delete Failed";
+}
+
+// Handle SD Card File Upload
+char* sdCardUpload(int method, char* cmdStr, char* argStr, char* msgBuffer, int msgLen,
+ int contentLen, unsigned char* pPayload, int payloadLen, int splitPayloadPos)
+{
+ printf("Upload file %s PayloadLen %d ContentLen %d MsgLen %d\r\n", argStr, payloadLen, contentLen, msgLen);
+ if (payloadLen == 0)
+ {
+ printf("Upload file - payload len == 0 - quitting\r\n");
+ return "OK";
+ }
+
+ bool writeSuccess = false;
+ if (splitPayloadPos == 0)
+ {
+ // Get the filename
+ fileNameForWrite[0] = '\0';
+ fileRemainingForWrite = 0;
+ char* filenameText = " filename=\"";
+ char* pFilename = strstr((char*)pPayload, filenameText);
+ if ((pFilename != NULL) && (pFilename - ((char*)pPayload) < 200))
+ {
+ pFilename += strlen(filenameText);
+ char* pEndFileName = strstr(pFilename, "\"");
+ if (pEndFileName != NULL)
+ {
+ int fileNameLen = pEndFileName - pFilename;
+ if (fileNameLen + strlen(baseWebFolder) < MAX_FNAME_LENGTH)
+ {
+ strcpy(fileNameForWrite, baseWebFolder);
+ strncpy(fileNameForWrite+strlen(baseWebFolder), pFilename, fileNameLen);
+ fileNameForWrite[fileNameLen+strlen(baseWebFolder)] = '\0';
+ printf("Upload file - filename %s\r\n", fileNameForWrite);
+ }
+ else
+ {
+ printf("Upload file - filename too long - quitting\r\n");
+ }
+ }
+ else
+ {
+ printf("Upload file - end of filename not found - quitting\r\n");
+ }
+ }
+ else
+ {
+ printf("Upload file - filename not found (or not near start of message) - quitting\r\n");
+ }
+ // Write first chunk to file
+ if (strlen(fileNameForWrite) > 0)
+ {
+ // Find the chunk start
+ char* chunkStartText = "\r\n\r\n";
+ char* pChunk = strstr((char*)pPayload, chunkStartText);
+ if ((pChunk != NULL) && (pChunk - ((char*)pPayload) < 300))
+ {
+ pChunk += strlen(chunkStartText);
+ // Find chunk len
+ int headerLen = pChunk - ((char*)pPayload);
+ int chunkLen = payloadLen - headerLen;
+ fileRemainingForWrite = contentLen - headerLen;
+ int numBytesToWrite = chunkLen;
+ if (fileRemainingForWrite > 0)
+ {
+ // Check for end boundary of data
+ if ((fileRemainingForWrite - chunkLen < 100) && (payloadLen > 50))
+ {
+ char* pEndForm = strstr(((char*)pPayload) + payloadLen - 50, "\r\n------");
+ if (pEndForm != NULL)
+ {
+ numBytesToWrite = pEndForm - pChunk;
+ printf("Upload file - payload end found writing %d bytes\r\n", numBytesToWrite);
+ }
+ }
+ // Write chunk to file
+ sdCardMutex.lock();
+ FILE* fp = fopen(fileNameForWrite, "w+");
+ if (fp == NULL)
+ {
+ printf("Upload file - Failed to open output file\r\n");
+ }
+ else
+ {
+ fwrite(pChunk, sizeof(char), numBytesToWrite, fp);
+ fclose(fp);
+ printf("Upload file - written %d bytes\r\n", numBytesToWrite);
+ writeSuccess = true;
+ }
+ sdCardMutex.unlock();
+ // Reduce remaining bytes
+ fileRemainingForWrite -= chunkLen;
+ }
+ else
+ {
+ printf("Upload file - file remaining for write <= 0 - quitting\r\n");
+ }
+ }
+ else
+ {
+ printf("Upload file - can't find chunk start - quitting\r\n");
+ }
+ }
+ else
+ {
+ printf("Upload file - filename blank - quitting\r\n");
+ }
+
+ }
+ else
+ {
+ if (strlen(fileNameForWrite) != 0)
+ {
+ if (fileRemainingForWrite > 0)
+ {
+ int numBytesToWrite = payloadLen;
+ // Check for end boundary of data
+ if ((fileRemainingForWrite - payloadLen < 100) && (payloadLen > 50))
+ {
+ char* pEndForm = strstr(((char*)pPayload) + payloadLen - 50, "\r\n------");
+ if (pEndForm != NULL)
+ {
+ numBytesToWrite = pEndForm - ((char*)pPayload);
+ printf("Upload file - payload end found writing %d bytes\r\n", numBytesToWrite);
+ }
+ }
+ sdCardMutex.lock();
+ FILE* fp = fopen(fileNameForWrite, "a");
+ if (fp == NULL)
+ {
+ printf("Failed to open output file\r\n");
+ }
+ else
+ {
+ fwrite(pPayload, sizeof(char), numBytesToWrite, fp);
+ fclose(fp);
+ writeSuccess = true;
+ printf("Upload file - written %d bytes\r\n", numBytesToWrite);
+ }
+ sdCardMutex.unlock();
+ // Reduce remaining bytes
+ fileRemainingForWrite -= payloadLen;
+ }
+ else
+ {
+ printf("Upload file - file remaining for write <= 0 - quitting\r\n");
+ }
+ }
+ else
+ {
+ printf("Upload file - filename blank - quitting\r\n");
+ }
+ }
+
+ // Return results
+ if (writeSuccess)
+ return "Write OK";
+ return "Write Failed";
+}
+
// Create, configure and run the web server
void http_thread(void const* arg)
{
- char* baseWebFolder = "/sd/";
RdWebServer webServer(&sdCardMutex);
webServer.addCommand("", RdWebServerCmdDef::CMD_SDORUSBFILE, NULL, "index.htm", false);
webServer.addCommand("gear-gr.png", RdWebServerCmdDef::CMD_SDORUSBFILE, NULL, NULL, true);
webServer.addCommand("listfiles", RdWebServerCmdDef::CMD_SDORUSBFILE, NULL, "/", false);
webServer.addCommand("getcurdata", RdWebServerCmdDef::CMD_CALLBACK, &getCurDataCallback);
webServer.addCommand("setgascount", RdWebServerCmdDef::CMD_CALLBACK, &setGasUseCallback);
+ webServer.addCommand("delete", RdWebServerCmdDef::CMD_CALLBACK, &sdCardDelete);
+ webServer.addCommand("upload", RdWebServerCmdDef::CMD_CALLBACK, &sdCardUpload);
webServer.init(WEBPORT, &led4, baseWebFolder);
webServer.run();
}
@@ -280,7 +510,7 @@
bool restartCauseRecorded = false;
// Setup the watchdog for reset
- watchdog.SetTimeoutSecs(60);
+ watchdog.SetTimeoutSecs(300);
// Time of last broadcast
time_t timeOfLastBroadcast = time(NULL);