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:
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

Onewire.lib Show annotated file Show diff for this revision Revisions of this file
RdDS18B20.cpp 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
main.cpp Show annotated file Show diff for this revision Revisions of this file
--- 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);