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

Committer:
Bobty
Date:
Fri Oct 16 09:07:04 2015 +0000
Revision:
23:fd5a5a9f30bc
Parent:
21:ccf053bab795
Added index.html file to project for completeness

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Bobty 19:0367cb46d003 1 // Gas usage monitor
Bobty 19:0367cb46d003 2 // Counts pulses from a gas meter
Bobty 19:0367cb46d003 3 // Monitors temperature sensors
Bobty 19:0367cb46d003 4 // Monitors valve/pump activity
Bobty 19:0367cb46d003 5 // Web interface and UDP broadcast
Bobty 19:0367cb46d003 6 // Rob Dobson 2015
Bobty 19:0367cb46d003 7
Bobty 0:f6611c8f453c 8 #include "mbed.h"
Bobty 0:f6611c8f453c 9 #include "EthernetInterface.h"
Bobty 5:5bccf48799d4 10 #include "NTPClient.h"
Bobty 5:5bccf48799d4 11 #include "RdWebServer.h"
Bobty 5:5bccf48799d4 12 #include "GasUseCounter.h"
Bobty 9:0e103c2f869a 13 #include "Thermometers.h"
Bobty 10:72eb217def1f 14 #include "VoltAlerter.h"
Bobty 12:a52996515063 15 #include "Watchdog.h"
Bobty 12:a52996515063 16 #include "Logger.h"
Bobty 5:5bccf48799d4 17
Bobty 18:d419ccebc666 18 // System name (used for hostname)
Bobty 18:d419ccebc666 19 char systemName[20] = "RdGasUseMonitor";
Bobty 18:d419ccebc666 20
Bobty 5:5bccf48799d4 21 // Web and UDB ports
Bobty 5:5bccf48799d4 22 const int WEBPORT = 80; // Port for web server
Bobty 5:5bccf48799d4 23 const int BROADCAST_PORT = 42853; // Arbitrarily chosen port number
Bobty 5:5bccf48799d4 24
Bobty 11:30182b9aa833 25 // Main loop delay between data collection passes
Bobty 9:0e103c2f869a 26 const int LOOP_DELAY_IN_MS = 250;
Bobty 5:5bccf48799d4 27
Bobty 5:5bccf48799d4 28 // Debugging and status
Bobty 5:5bccf48799d4 29 RawSerial pc(USBTX, USBRX);
Bobty 5:5bccf48799d4 30 DigitalOut led1(LED1); //ticking (flashes)
Bobty 11:30182b9aa833 31 DigitalOut led2(LED2); //state of the 1st voltage alerter
Bobty 5:5bccf48799d4 32 DigitalOut led3(LED3); //socket connecting status
Bobty 5:5bccf48799d4 33 DigitalOut led4(LED4); //server status
Bobty 5:5bccf48799d4 34
Bobty 5:5bccf48799d4 35 // Web server
Bobty 5:5bccf48799d4 36 UDPSocket sendUDPSocket;
Bobty 5:5bccf48799d4 37 Endpoint broadcastEndpoint;
Bobty 5:5bccf48799d4 38
Bobty 10:72eb217def1f 39 // Network Time Protocol (NTP)
Bobty 10:72eb217def1f 40 NTPClient ntp;
Bobty 10:72eb217def1f 41 const int NTP_REFRESH_INTERVAL_HOURS = 1;
Bobty 10:72eb217def1f 42
Bobty 20:7933076df5af 43 // Mutex for SD card access
Bobty 20:7933076df5af 44 Mutex sdCardMutex;
Bobty 20:7933076df5af 45
Bobty 5:5bccf48799d4 46 // File system for SD card
Bobty 4:0d3a207680b0 47 SDFileSystem sd(p5, p6, p7, p8, "sd");
Bobty 5:5bccf48799d4 48
Bobty 21:ccf053bab795 49 // Base folder for web file system
Bobty 21:ccf053bab795 50 char* baseWebFolder = "/sd/";
Bobty 21:ccf053bab795 51
Bobty 12:a52996515063 52 // Log file names
Bobty 19:0367cb46d003 53 const char* gasPulseFileName1 = "/sd/curPulse.txt";
Bobty 19:0367cb46d003 54 const char* gasPulseFileName2 = "/sd/curPulse2.txt";
Bobty 12:a52996515063 55 const char* eventLogFileName = "/sd/log.txt";
Bobty 12:a52996515063 56 const char* dataLogFileBase = "/sd/";
Bobty 12:a52996515063 57
Bobty 12:a52996515063 58 // Logger
Bobty 20:7933076df5af 59 Logger logger(eventLogFileName, dataLogFileBase, sdCardMutex);
Bobty 12:a52996515063 60
Bobty 5:5bccf48799d4 61 // Gas use counter
Bobty 5:5bccf48799d4 62 DigitalIn gasPulsePin(p21);
Bobty 20:7933076df5af 63 GasUseCounter gasUseCounter(gasPulseFileName1, gasPulseFileName2, gasPulsePin, logger, sdCardMutex);
Bobty 5:5bccf48799d4 64
Bobty 8:5980547ae71c 65 // Thermometers - DS18B20 OneWire Thermometer connections
Bobty 8:5980547ae71c 66 const PinName tempSensorPins[] = { p22 };
Bobty 20:7933076df5af 67 Thermometers thermometers(sizeof(tempSensorPins)/sizeof(PinName), tempSensorPins, LOOP_DELAY_IN_MS, logger);
Bobty 8:5980547ae71c 68
Bobty 10:72eb217def1f 69 // Voltage Sensors / Alerters
Bobty 10:72eb217def1f 70 const int NUM_VOLT_ALERTERS = 3;
Bobty 10:72eb217def1f 71 VoltAlerter voltAlerter1(p23);
Bobty 10:72eb217def1f 72 VoltAlerter voltAlerter2(p24);
Bobty 10:72eb217def1f 73 VoltAlerter voltAlerter3(p25);
Bobty 10:72eb217def1f 74
Bobty 12:a52996515063 75 // Watchdog
Bobty 12:a52996515063 76 Watchdog watchdog;
Bobty 12:a52996515063 77
Bobty 11:30182b9aa833 78 // Broadcast message format
Bobty 11:30182b9aa833 79 // Data format of the broadcast message - senml - https://tools.ietf.org/html/draft-jennings-senml-08
Bobty 11:30182b9aa833 80 // {
Bobty 11:30182b9aa833 81 // "e": [
Bobty 11:30182b9aa833 82 // {"n":"gasCount","v":%d},
Bobty 11:30182b9aa833 83 // {"n":"gasPulseRateMs","v":%d,"u":"ms"},
Bobty 11:30182b9aa833 84 // {"n":"temp_%s","v":%0.1f,"u":"degC"},
Bobty 11:30182b9aa833 85 // ...
Bobty 11:30182b9aa833 86 // {"n":"pump_%d","v":%d},
Bobty 11:30182b9aa833 87 // ...
Bobty 11:30182b9aa833 88 // ],
Bobty 11:30182b9aa833 89 // "bt": %d
Bobty 11:30182b9aa833 90 // }
Bobty 10:72eb217def1f 91 const char broadcastMsgPrefix[] = "{\"e\":[";
Bobty 14:3c3aa4fd7e1a 92 const char broadcastMsgGasFormat[] = "{\"n\":\"gasCount\",\"v\":%d,\"u\":\"count\"},{\"n\":\"gasPulseRateMs\",\"v\":%d,\"u\":\"ms\"}";
Bobty 21:ccf053bab795 93 const char broadcastTemperatureFormat[] = "{\"n\":\"temp_%s_%s\",\"v\":%0.1f,\"u\":\"degC\"}";
Bobty 21:ccf053bab795 94 const char broadcastVoltAlerterFormat[] = "{\"n\":\"pump_%d_%s\",\"bv\":%d}";
Bobty 10:72eb217def1f 95 const char broadcastMsgSuffix[] = "],\"bt\":%d}";
Bobty 10:72eb217def1f 96
Bobty 11:30182b9aa833 97 // Broadcast message length and buffer
Bobty 21:ccf053bab795 98 const int MAX_DEVICE_NAME_LEN = 20;
Bobty 10:72eb217def1f 99 const int broadcastMsgLen = sizeof(broadcastMsgPrefix) +
Bobty 10:72eb217def1f 100 sizeof(broadcastMsgGasFormat) +
Bobty 21:ccf053bab795 101 ((sizeof(broadcastTemperatureFormat)+MAX_DEVICE_NAME_LEN)*Thermometers::MAX_THERMOMETERS) +
Bobty 21:ccf053bab795 102 ((sizeof(broadcastVoltAlerterFormat)+MAX_DEVICE_NAME_LEN)*NUM_VOLT_ALERTERS) +
Bobty 10:72eb217def1f 103 sizeof(broadcastMsgSuffix) +
Bobty 10:72eb217def1f 104 60;
Bobty 10:72eb217def1f 105 char broadcastMsgBuffer[broadcastMsgLen];
Bobty 21:ccf053bab795 106
Bobty 21:ccf053bab795 107 // Handling of SD card file delete and file upload commands
Bobty 21:ccf053bab795 108 const int MAX_FNAME_LENGTH = 127;
Bobty 21:ccf053bab795 109 char fileNameForWrite[MAX_FNAME_LENGTH+1] = "";
Bobty 21:ccf053bab795 110 int fileRemainingForWrite = 0;
Bobty 21:ccf053bab795 111
Bobty 21:ccf053bab795 112 // Thermometer and pump names
Bobty 21:ccf053bab795 113 char thermometerAddrs[][MAX_DEVICE_NAME_LEN] =
Bobty 21:ccf053bab795 114 {
Bobty 21:ccf053bab795 115 "28b1b1e0050000d0",
Bobty 21:ccf053bab795 116 "289dd7c705000060",
Bobty 21:ccf053bab795 117 "28b3b0c60500000a"
Bobty 21:ccf053bab795 118 };
Bobty 21:ccf053bab795 119 char thermometerNames[][MAX_DEVICE_NAME_LEN] =
Bobty 21:ccf053bab795 120 {
Bobty 21:ccf053bab795 121 "HWCylinder",
Bobty 21:ccf053bab795 122 "Inflow2",
Bobty 21:ccf053bab795 123 "Outflow2"
Bobty 21:ccf053bab795 124 };
Bobty 21:ccf053bab795 125 int numNamedThermometers = 3;
Bobty 21:ccf053bab795 126
Bobty 21:ccf053bab795 127 char voltAlerterNames[][MAX_DEVICE_NAME_LEN] =
Bobty 21:ccf053bab795 128 {
Bobty 21:ccf053bab795 129 "PumpUpper",
Bobty 21:ccf053bab795 130 "PumpLower",
Bobty 21:ccf053bab795 131 "PumpHW"
Bobty 21:ccf053bab795 132 };
Bobty 21:ccf053bab795 133
Bobty 21:ccf053bab795 134 // Get names of thermometers
Bobty 21:ccf053bab795 135 char* getThermometerName(char* thermAddr)
Bobty 21:ccf053bab795 136 {
Bobty 21:ccf053bab795 137 for (int i = 0; i < numNamedThermometers; i++)
Bobty 21:ccf053bab795 138 {
Bobty 21:ccf053bab795 139 if (strcmp(thermometerAddrs[i], thermAddr) == 0)
Bobty 21:ccf053bab795 140 return thermometerNames[i];
Bobty 21:ccf053bab795 141 }
Bobty 21:ccf053bab795 142 return "Unknown";
Bobty 21:ccf053bab795 143 }
Bobty 21:ccf053bab795 144
Bobty 21:ccf053bab795 145 // Get names of volt alerters
Bobty 21:ccf053bab795 146 char* getVoltAlerterName(int idx)
Bobty 21:ccf053bab795 147 {
Bobty 21:ccf053bab795 148 if (idx >= 0 && idx < NUM_VOLT_ALERTERS)
Bobty 21:ccf053bab795 149 {
Bobty 21:ccf053bab795 150 return voltAlerterNames[idx];
Bobty 21:ccf053bab795 151 }
Bobty 21:ccf053bab795 152 return "Unknown";
Bobty 21:ccf053bab795 153 }
Bobty 21:ccf053bab795 154
Bobty 14:3c3aa4fd7e1a 155 // Format broadcast message
Bobty 14:3c3aa4fd7e1a 156 void GenBroadcastMessage()
Bobty 5:5bccf48799d4 157 {
Bobty 9:0e103c2f869a 158 // Get temperature values
Bobty 9:0e103c2f869a 159 TemperatureValue tempValues[Thermometers::MAX_THERMOMETERS];
Bobty 9:0e103c2f869a 160 int numTempValues = thermometers.GetTemperatureValues(Thermometers::MAX_THERMOMETERS, tempValues, 100);
Bobty 11:30182b9aa833 161 // for (int tempIdx = 0; tempIdx < numTempValues; tempIdx++)
Bobty 11:30182b9aa833 162 // {
Bobty 11:30182b9aa833 163 // printf("Temp: %.1f, Addr: %s, Time: %d\r\n", tempValues[tempIdx].tempInCentigrade, tempValues[tempIdx].address, tempValues[tempIdx].timeStamp);
Bobty 11:30182b9aa833 164 // }
Bobty 14:3c3aa4fd7e1a 165
Bobty 12:a52996515063 166 // Format the broadcast message
Bobty 10:72eb217def1f 167 time_t timeNow = time(NULL);
Bobty 10:72eb217def1f 168 strcpy(broadcastMsgBuffer, broadcastMsgPrefix);
Bobty 10:72eb217def1f 169 sprintf(broadcastMsgBuffer+strlen(broadcastMsgBuffer), broadcastMsgGasFormat, gasUseCounter.GetCount(), gasUseCounter.GetPulseRateMs());
Bobty 10:72eb217def1f 170 strcpy(broadcastMsgBuffer+strlen(broadcastMsgBuffer), ",");
Bobty 10:72eb217def1f 171 for (int tempIdx = 0; tempIdx < numTempValues; tempIdx++)
Bobty 10:72eb217def1f 172 {
Bobty 21:ccf053bab795 173 sprintf(broadcastMsgBuffer+strlen(broadcastMsgBuffer), broadcastTemperatureFormat, tempValues[tempIdx].address,
Bobty 21:ccf053bab795 174 getThermometerName(tempValues[tempIdx].address),
Bobty 21:ccf053bab795 175 tempValues[tempIdx].tempInCentigrade);
Bobty 10:72eb217def1f 176 strcpy(broadcastMsgBuffer+strlen(broadcastMsgBuffer), ",");
Bobty 10:72eb217def1f 177 }
Bobty 21:ccf053bab795 178 sprintf(broadcastMsgBuffer+strlen(broadcastMsgBuffer), broadcastVoltAlerterFormat, 1, getVoltAlerterName(0), voltAlerter1.GetState());
Bobty 10:72eb217def1f 179 strcpy(broadcastMsgBuffer+strlen(broadcastMsgBuffer), ",");
Bobty 21:ccf053bab795 180 sprintf(broadcastMsgBuffer+strlen(broadcastMsgBuffer), broadcastVoltAlerterFormat, 2, getVoltAlerterName(1), voltAlerter2.GetState());
Bobty 10:72eb217def1f 181 strcpy(broadcastMsgBuffer+strlen(broadcastMsgBuffer), ",");
Bobty 21:ccf053bab795 182 sprintf(broadcastMsgBuffer+strlen(broadcastMsgBuffer), broadcastVoltAlerterFormat, 3, getVoltAlerterName(2), voltAlerter3.GetState());
Bobty 10:72eb217def1f 183 sprintf(broadcastMsgBuffer+strlen(broadcastMsgBuffer), broadcastMsgSuffix, timeNow);
Bobty 14:3c3aa4fd7e1a 184 }
Bobty 14:3c3aa4fd7e1a 185
Bobty 14:3c3aa4fd7e1a 186 // Send broadcast message with current data
Bobty 14:3c3aa4fd7e1a 187 void SendInfoBroadcast()
Bobty 14:3c3aa4fd7e1a 188 {
Bobty 14:3c3aa4fd7e1a 189 led3 = true;
Bobty 14:3c3aa4fd7e1a 190
Bobty 14:3c3aa4fd7e1a 191 // Init the sending socket
Bobty 14:3c3aa4fd7e1a 192 sendUDPSocket.init();
Bobty 14:3c3aa4fd7e1a 193 sendUDPSocket.set_broadcasting();
Bobty 14:3c3aa4fd7e1a 194 broadcastEndpoint.set_address("255.255.255.255", BROADCAST_PORT);
Bobty 10:72eb217def1f 195
Bobty 14:3c3aa4fd7e1a 196 // Format the message
Bobty 14:3c3aa4fd7e1a 197 GenBroadcastMessage();
Bobty 14:3c3aa4fd7e1a 198
Bobty 5:5bccf48799d4 199 // Send
Bobty 10:72eb217def1f 200 int bytesToSend = strlen(broadcastMsgBuffer);
Bobty 10:72eb217def1f 201 int rslt = sendUDPSocket.sendTo(broadcastEndpoint, broadcastMsgBuffer, bytesToSend);
Bobty 5:5bccf48799d4 202 if (rslt == bytesToSend)
Bobty 5:5bccf48799d4 203 {
Bobty 20:7933076df5af 204 logger.LogDebug("Broadcast (len %d) Sent ok %s", bytesToSend, broadcastMsgBuffer);
Bobty 5:5bccf48799d4 205 }
Bobty 5:5bccf48799d4 206 else if (rslt == -1)
Bobty 5:5bccf48799d4 207 {
Bobty 20:7933076df5af 208 logger.LogDebug("Broadcast Failed to send %s", broadcastMsgBuffer);
Bobty 5:5bccf48799d4 209 }
Bobty 5:5bccf48799d4 210 else
Bobty 5:5bccf48799d4 211 {
Bobty 20:7933076df5af 212 logger.LogDebug("Broadcast Didn't send all of %s", broadcastMsgBuffer);
Bobty 5:5bccf48799d4 213 }
Bobty 5:5bccf48799d4 214
Bobty 12:a52996515063 215 // Log the data
Bobty 12:a52996515063 216 logger.LogData(broadcastMsgBuffer);
Bobty 5:5bccf48799d4 217
Bobty 5:5bccf48799d4 218 led3 = false;
Bobty 5:5bccf48799d4 219 }
Bobty 0:f6611c8f453c 220
Bobty 16:89778849e9f7 221 char* getCurDataCallback(int method, char* cmdStr, char* argStr, char* msgBuffer, int msgLen,
Bobty 16:89778849e9f7 222 int contentLen, unsigned char* pPayload, int payloadLen, int splitPayloadPos)
Bobty 5:5bccf48799d4 223 {
Bobty 14:3c3aa4fd7e1a 224 // Format message
Bobty 14:3c3aa4fd7e1a 225 GenBroadcastMessage();
Bobty 14:3c3aa4fd7e1a 226 return broadcastMsgBuffer;
Bobty 5:5bccf48799d4 227 }
Bobty 5:5bccf48799d4 228
Bobty 16:89778849e9f7 229 char* setGasUseCallback(int method, char* cmdStr, char* argStr, char* msgBuffer, int msgLen,
Bobty 16:89778849e9f7 230 int contentLen, unsigned char* pPayload, int payloadLen, int splitPayloadPos)
Bobty 5:5bccf48799d4 231 {
Bobty 20:7933076df5af 232 logger.LogDebug("Setting gas use count %s", argStr);
Bobty 5:5bccf48799d4 233 int newGasUse = 0;
Bobty 5:5bccf48799d4 234 char* eqStr = strchr(argStr, '=');
Bobty 5:5bccf48799d4 235 if (eqStr == NULL)
Bobty 5:5bccf48799d4 236 return "SetGasValue FAILED";
Bobty 5:5bccf48799d4 237 sscanf(eqStr+1, "%d", &newGasUse);
Bobty 5:5bccf48799d4 238 gasUseCounter.SetCount(newGasUse);
Bobty 5:5bccf48799d4 239 return "SetGasValue OK";
Bobty 5:5bccf48799d4 240 }
Bobty 5:5bccf48799d4 241
Bobty 21:ccf053bab795 242 // Handle SD Card File Delete
Bobty 21:ccf053bab795 243 char* sdCardDelete(int method, char* cmdStr, char* argStr, char* msgBuffer, int msgLen,
Bobty 21:ccf053bab795 244 int contentLen, unsigned char* pPayload, int payloadLen, int splitPayloadPos)
Bobty 21:ccf053bab795 245 {
Bobty 21:ccf053bab795 246 printf("Delete file %s\r\n", argStr);
Bobty 21:ccf053bab795 247 sdCardMutex.lock();
Bobty 21:ccf053bab795 248 char* baseWebFolder = "/sd/";
Bobty 21:ccf053bab795 249 char filename[MAX_FNAME_LENGTH+1];
Bobty 21:ccf053bab795 250 sprintf(filename, "%s%s", baseWebFolder, argStr);
Bobty 21:ccf053bab795 251 printf("Full filename for delete is %s\r\n", filename);
Bobty 21:ccf053bab795 252 bool delOk = (remove(filename) == 0);
Bobty 21:ccf053bab795 253 sdCardMutex.unlock();
Bobty 21:ccf053bab795 254 if (delOk)
Bobty 21:ccf053bab795 255 return "Delete OK";
Bobty 21:ccf053bab795 256 return "Delete Failed";
Bobty 21:ccf053bab795 257 }
Bobty 21:ccf053bab795 258
Bobty 21:ccf053bab795 259 // Handle SD Card File Upload
Bobty 21:ccf053bab795 260 char* sdCardUpload(int method, char* cmdStr, char* argStr, char* msgBuffer, int msgLen,
Bobty 21:ccf053bab795 261 int contentLen, unsigned char* pPayload, int payloadLen, int splitPayloadPos)
Bobty 21:ccf053bab795 262 {
Bobty 21:ccf053bab795 263 printf("Upload file %s PayloadLen %d ContentLen %d MsgLen %d\r\n", argStr, payloadLen, contentLen, msgLen);
Bobty 21:ccf053bab795 264 if (payloadLen == 0)
Bobty 21:ccf053bab795 265 {
Bobty 21:ccf053bab795 266 printf("Upload file - payload len == 0 - quitting\r\n");
Bobty 21:ccf053bab795 267 return "OK";
Bobty 21:ccf053bab795 268 }
Bobty 21:ccf053bab795 269
Bobty 21:ccf053bab795 270 bool writeSuccess = false;
Bobty 21:ccf053bab795 271 if (splitPayloadPos == 0)
Bobty 21:ccf053bab795 272 {
Bobty 21:ccf053bab795 273 // Get the filename
Bobty 21:ccf053bab795 274 fileNameForWrite[0] = '\0';
Bobty 21:ccf053bab795 275 fileRemainingForWrite = 0;
Bobty 21:ccf053bab795 276 char* filenameText = " filename=\"";
Bobty 21:ccf053bab795 277 char* pFilename = strstr((char*)pPayload, filenameText);
Bobty 21:ccf053bab795 278 if ((pFilename != NULL) && (pFilename - ((char*)pPayload) < 200))
Bobty 21:ccf053bab795 279 {
Bobty 21:ccf053bab795 280 pFilename += strlen(filenameText);
Bobty 21:ccf053bab795 281 char* pEndFileName = strstr(pFilename, "\"");
Bobty 21:ccf053bab795 282 if (pEndFileName != NULL)
Bobty 21:ccf053bab795 283 {
Bobty 21:ccf053bab795 284 int fileNameLen = pEndFileName - pFilename;
Bobty 21:ccf053bab795 285 if (fileNameLen + strlen(baseWebFolder) < MAX_FNAME_LENGTH)
Bobty 21:ccf053bab795 286 {
Bobty 21:ccf053bab795 287 strcpy(fileNameForWrite, baseWebFolder);
Bobty 21:ccf053bab795 288 strncpy(fileNameForWrite+strlen(baseWebFolder), pFilename, fileNameLen);
Bobty 21:ccf053bab795 289 fileNameForWrite[fileNameLen+strlen(baseWebFolder)] = '\0';
Bobty 21:ccf053bab795 290 printf("Upload file - filename %s\r\n", fileNameForWrite);
Bobty 21:ccf053bab795 291 }
Bobty 21:ccf053bab795 292 else
Bobty 21:ccf053bab795 293 {
Bobty 21:ccf053bab795 294 printf("Upload file - filename too long - quitting\r\n");
Bobty 21:ccf053bab795 295 }
Bobty 21:ccf053bab795 296 }
Bobty 21:ccf053bab795 297 else
Bobty 21:ccf053bab795 298 {
Bobty 21:ccf053bab795 299 printf("Upload file - end of filename not found - quitting\r\n");
Bobty 21:ccf053bab795 300 }
Bobty 21:ccf053bab795 301 }
Bobty 21:ccf053bab795 302 else
Bobty 21:ccf053bab795 303 {
Bobty 21:ccf053bab795 304 printf("Upload file - filename not found (or not near start of message) - quitting\r\n");
Bobty 21:ccf053bab795 305 }
Bobty 21:ccf053bab795 306 // Write first chunk to file
Bobty 21:ccf053bab795 307 if (strlen(fileNameForWrite) > 0)
Bobty 21:ccf053bab795 308 {
Bobty 21:ccf053bab795 309 // Find the chunk start
Bobty 21:ccf053bab795 310 char* chunkStartText = "\r\n\r\n";
Bobty 21:ccf053bab795 311 char* pChunk = strstr((char*)pPayload, chunkStartText);
Bobty 21:ccf053bab795 312 if ((pChunk != NULL) && (pChunk - ((char*)pPayload) < 300))
Bobty 21:ccf053bab795 313 {
Bobty 21:ccf053bab795 314 pChunk += strlen(chunkStartText);
Bobty 21:ccf053bab795 315 // Find chunk len
Bobty 21:ccf053bab795 316 int headerLen = pChunk - ((char*)pPayload);
Bobty 21:ccf053bab795 317 int chunkLen = payloadLen - headerLen;
Bobty 21:ccf053bab795 318 fileRemainingForWrite = contentLen - headerLen;
Bobty 21:ccf053bab795 319 int numBytesToWrite = chunkLen;
Bobty 21:ccf053bab795 320 if (fileRemainingForWrite > 0)
Bobty 21:ccf053bab795 321 {
Bobty 21:ccf053bab795 322 // Check for end boundary of data
Bobty 21:ccf053bab795 323 if ((fileRemainingForWrite - chunkLen < 100) && (payloadLen > 50))
Bobty 21:ccf053bab795 324 {
Bobty 21:ccf053bab795 325 char* pEndForm = strstr(((char*)pPayload) + payloadLen - 50, "\r\n------");
Bobty 21:ccf053bab795 326 if (pEndForm != NULL)
Bobty 21:ccf053bab795 327 {
Bobty 21:ccf053bab795 328 numBytesToWrite = pEndForm - pChunk;
Bobty 21:ccf053bab795 329 printf("Upload file - payload end found writing %d bytes\r\n", numBytesToWrite);
Bobty 21:ccf053bab795 330 }
Bobty 21:ccf053bab795 331 }
Bobty 21:ccf053bab795 332 // Write chunk to file
Bobty 21:ccf053bab795 333 sdCardMutex.lock();
Bobty 21:ccf053bab795 334 FILE* fp = fopen(fileNameForWrite, "w+");
Bobty 21:ccf053bab795 335 if (fp == NULL)
Bobty 21:ccf053bab795 336 {
Bobty 21:ccf053bab795 337 printf("Upload file - Failed to open output file\r\n");
Bobty 21:ccf053bab795 338 }
Bobty 21:ccf053bab795 339 else
Bobty 21:ccf053bab795 340 {
Bobty 21:ccf053bab795 341 fwrite(pChunk, sizeof(char), numBytesToWrite, fp);
Bobty 21:ccf053bab795 342 fclose(fp);
Bobty 21:ccf053bab795 343 printf("Upload file - written %d bytes\r\n", numBytesToWrite);
Bobty 21:ccf053bab795 344 writeSuccess = true;
Bobty 21:ccf053bab795 345 }
Bobty 21:ccf053bab795 346 sdCardMutex.unlock();
Bobty 21:ccf053bab795 347 // Reduce remaining bytes
Bobty 21:ccf053bab795 348 fileRemainingForWrite -= chunkLen;
Bobty 21:ccf053bab795 349 }
Bobty 21:ccf053bab795 350 else
Bobty 21:ccf053bab795 351 {
Bobty 21:ccf053bab795 352 printf("Upload file - file remaining for write <= 0 - quitting\r\n");
Bobty 21:ccf053bab795 353 }
Bobty 21:ccf053bab795 354 }
Bobty 21:ccf053bab795 355 else
Bobty 21:ccf053bab795 356 {
Bobty 21:ccf053bab795 357 printf("Upload file - can't find chunk start - quitting\r\n");
Bobty 21:ccf053bab795 358 }
Bobty 21:ccf053bab795 359 }
Bobty 21:ccf053bab795 360 else
Bobty 21:ccf053bab795 361 {
Bobty 21:ccf053bab795 362 printf("Upload file - filename blank - quitting\r\n");
Bobty 21:ccf053bab795 363 }
Bobty 21:ccf053bab795 364
Bobty 21:ccf053bab795 365 }
Bobty 21:ccf053bab795 366 else
Bobty 21:ccf053bab795 367 {
Bobty 21:ccf053bab795 368 if (strlen(fileNameForWrite) != 0)
Bobty 21:ccf053bab795 369 {
Bobty 21:ccf053bab795 370 if (fileRemainingForWrite > 0)
Bobty 21:ccf053bab795 371 {
Bobty 21:ccf053bab795 372 int numBytesToWrite = payloadLen;
Bobty 21:ccf053bab795 373 // Check for end boundary of data
Bobty 21:ccf053bab795 374 if ((fileRemainingForWrite - payloadLen < 100) && (payloadLen > 50))
Bobty 21:ccf053bab795 375 {
Bobty 21:ccf053bab795 376 char* pEndForm = strstr(((char*)pPayload) + payloadLen - 50, "\r\n------");
Bobty 21:ccf053bab795 377 if (pEndForm != NULL)
Bobty 21:ccf053bab795 378 {
Bobty 21:ccf053bab795 379 numBytesToWrite = pEndForm - ((char*)pPayload);
Bobty 21:ccf053bab795 380 printf("Upload file - payload end found writing %d bytes\r\n", numBytesToWrite);
Bobty 21:ccf053bab795 381 }
Bobty 21:ccf053bab795 382 }
Bobty 21:ccf053bab795 383 sdCardMutex.lock();
Bobty 21:ccf053bab795 384 FILE* fp = fopen(fileNameForWrite, "a");
Bobty 21:ccf053bab795 385 if (fp == NULL)
Bobty 21:ccf053bab795 386 {
Bobty 21:ccf053bab795 387 printf("Failed to open output file\r\n");
Bobty 21:ccf053bab795 388 }
Bobty 21:ccf053bab795 389 else
Bobty 21:ccf053bab795 390 {
Bobty 21:ccf053bab795 391 fwrite(pPayload, sizeof(char), numBytesToWrite, fp);
Bobty 21:ccf053bab795 392 fclose(fp);
Bobty 21:ccf053bab795 393 writeSuccess = true;
Bobty 21:ccf053bab795 394 printf("Upload file - written %d bytes\r\n", numBytesToWrite);
Bobty 21:ccf053bab795 395 }
Bobty 21:ccf053bab795 396 sdCardMutex.unlock();
Bobty 21:ccf053bab795 397 // Reduce remaining bytes
Bobty 21:ccf053bab795 398 fileRemainingForWrite -= payloadLen;
Bobty 21:ccf053bab795 399 }
Bobty 21:ccf053bab795 400 else
Bobty 21:ccf053bab795 401 {
Bobty 21:ccf053bab795 402 printf("Upload file - file remaining for write <= 0 - quitting\r\n");
Bobty 21:ccf053bab795 403 }
Bobty 21:ccf053bab795 404 }
Bobty 21:ccf053bab795 405 else
Bobty 21:ccf053bab795 406 {
Bobty 21:ccf053bab795 407 printf("Upload file - filename blank - quitting\r\n");
Bobty 21:ccf053bab795 408 }
Bobty 21:ccf053bab795 409 }
Bobty 21:ccf053bab795 410
Bobty 21:ccf053bab795 411 // Return results
Bobty 21:ccf053bab795 412 if (writeSuccess)
Bobty 21:ccf053bab795 413 return "Write OK";
Bobty 21:ccf053bab795 414 return "Write Failed";
Bobty 21:ccf053bab795 415 }
Bobty 21:ccf053bab795 416
Bobty 11:30182b9aa833 417 // Create, configure and run the web server
Bobty 5:5bccf48799d4 418 void http_thread(void const* arg)
Bobty 5:5bccf48799d4 419 {
Bobty 20:7933076df5af 420 RdWebServer webServer(&sdCardMutex);
Bobty 5:5bccf48799d4 421 webServer.addCommand("", RdWebServerCmdDef::CMD_SDORUSBFILE, NULL, "index.htm", false);
Bobty 5:5bccf48799d4 422 webServer.addCommand("gear-gr.png", RdWebServerCmdDef::CMD_SDORUSBFILE, NULL, NULL, true);
Bobty 12:a52996515063 423 webServer.addCommand("listfiles", RdWebServerCmdDef::CMD_SDORUSBFILE, NULL, "/", false);
Bobty 14:3c3aa4fd7e1a 424 webServer.addCommand("getcurdata", RdWebServerCmdDef::CMD_CALLBACK, &getCurDataCallback);
Bobty 5:5bccf48799d4 425 webServer.addCommand("setgascount", RdWebServerCmdDef::CMD_CALLBACK, &setGasUseCallback);
Bobty 21:ccf053bab795 426 webServer.addCommand("delete", RdWebServerCmdDef::CMD_CALLBACK, &sdCardDelete);
Bobty 21:ccf053bab795 427 webServer.addCommand("upload", RdWebServerCmdDef::CMD_CALLBACK, &sdCardUpload);
Bobty 5:5bccf48799d4 428 webServer.init(WEBPORT, &led4, baseWebFolder);
Bobty 5:5bccf48799d4 429 webServer.run();
Bobty 5:5bccf48799d4 430 }
Bobty 5:5bccf48799d4 431
Bobty 11:30182b9aa833 432 // Network time protocol (NTP) thread to get time from internet
Bobty 5:5bccf48799d4 433 void ntp_thread(void const* arg)
Bobty 5:5bccf48799d4 434 {
Bobty 5:5bccf48799d4 435 while (1)
Bobty 5:5bccf48799d4 436 {
Bobty 20:7933076df5af 437 logger.LogDebug("Trying to update time...");
Bobty 14:3c3aa4fd7e1a 438 if (ntp.setTime("0.pool.ntp.org") == NTP_OK)
Bobty 5:5bccf48799d4 439 {
Bobty 19:0367cb46d003 440 osDelay(1000); // This delay is simply to try to improve printf output
Bobty 20:7933076df5af 441 logger.LogDebug("Set time successfully");
Bobty 19:0367cb46d003 442 time_t ctTime;
Bobty 19:0367cb46d003 443 ctTime = time(NULL);
Bobty 20:7933076df5af 444 logger.LogDebug("Time is set to (UTC): %s", ctime(&ctTime));
Bobty 5:5bccf48799d4 445 }
Bobty 5:5bccf48799d4 446 else
Bobty 5:5bccf48799d4 447 {
Bobty 20:7933076df5af 448 logger.LogDebug("Cannot set from NTP");
Bobty 10:72eb217def1f 449 }
Bobty 10:72eb217def1f 450
Bobty 10:72eb217def1f 451 // Refresh time every K hours
Bobty 10:72eb217def1f 452 for (int k = 0; k < NTP_REFRESH_INTERVAL_HOURS; k++)
Bobty 5:5bccf48799d4 453 {
Bobty 10:72eb217def1f 454 // 1 hour
Bobty 10:72eb217def1f 455 for (int i = 0; i < 60; i++)
Bobty 5:5bccf48799d4 456 {
Bobty 10:72eb217def1f 457 for (int j = 0; j < 60; j++)
Bobty 10:72eb217def1f 458 {
Bobty 10:72eb217def1f 459 osDelay(1000);
Bobty 10:72eb217def1f 460 }
Bobty 20:7933076df5af 461 logger.LogDebug("%d mins to next NTP time refresh", (NTP_REFRESH_INTERVAL_HOURS-k-1)*60 + (59-i));
Bobty 5:5bccf48799d4 462 }
Bobty 5:5bccf48799d4 463 }
Bobty 5:5bccf48799d4 464 }
Bobty 5:5bccf48799d4 465 }
Bobty 9:0e103c2f869a 466
Bobty 12:a52996515063 467 // #define TEST_WATCHDOG 1
Bobty 12:a52996515063 468 #ifdef TEST_WATCHDOG
Bobty 12:a52996515063 469 int watchdogTestLoopCount = 0;
Bobty 12:a52996515063 470 #endif
Bobty 12:a52996515063 471
Bobty 11:30182b9aa833 472 // Main
Bobty 0:f6611c8f453c 473 int main()
Bobty 0:f6611c8f453c 474 {
Bobty 0:f6611c8f453c 475 pc.baud(115200);
Bobty 20:7933076df5af 476 logger.SetDebugDest(true, true);
Bobty 20:7933076df5af 477 logger.LogDebug("\r\n\r\nGas Monitor V2 - Rob Dobson 2015");
Bobty 0:f6611c8f453c 478
Bobty 9:0e103c2f869a 479 // Initialise thermometers
Bobty 9:0e103c2f869a 480 thermometers.Init();
Bobty 9:0e103c2f869a 481
Bobty 5:5bccf48799d4 482 // Get the current count from the SD Card
Bobty 5:5bccf48799d4 483 gasUseCounter.Init();
Bobty 0:f6611c8f453c 484
Bobty 18:d419ccebc666 485 // Setup ethernet interface
Bobty 18:d419ccebc666 486 char macAddr[6];
Bobty 18:d419ccebc666 487 mbed_mac_address(macAddr);
Bobty 20:7933076df5af 488 logger.LogDebug("Ethernet MAC address: %02x:%02x:%02x:%02x:%02x:%02x", macAddr[0], macAddr[1], macAddr[2], macAddr[3], macAddr[4], macAddr[5]);
Bobty 20:7933076df5af 489 logger.LogDebug("Connecting to ethernet ...");
Bobty 18:d419ccebc666 490
Bobty 18:d419ccebc666 491 // Init ethernet
Bobty 18:d419ccebc666 492 EthernetInterface::init();
Bobty 18:d419ccebc666 493
Bobty 18:d419ccebc666 494 // Using code described here https://developer.mbed.org/questions/1602/How-to-set-the-TCPIP-stack-s-hostname-pr/
Bobty 18:d419ccebc666 495 // to setName on the ethernet interface
Bobty 18:d419ccebc666 496 EthernetInterface::setName(systemName);
Bobty 18:d419ccebc666 497
Bobty 18:d419ccebc666 498 // Connect ethernet
Bobty 18:d419ccebc666 499 EthernetInterface::connect();
Bobty 20:7933076df5af 500 logger.LogDebug("IP Address: %s HostName %s", EthernetInterface::getIPAddress(), EthernetInterface::getName());
Bobty 8:5980547ae71c 501
Bobty 8:5980547ae71c 502 // NTP Time setter
Bobty 5:5bccf48799d4 503 Thread ntpTimeSetter(&ntp_thread);
Bobty 0:f6611c8f453c 504
Bobty 8:5980547ae71c 505 // Web Server
Bobty 6:b7064d33e402 506 Thread httpServer(&http_thread, NULL, osPriorityNormal, (DEFAULT_STACK_SIZE * 3));
Bobty 14:3c3aa4fd7e1a 507
Bobty 14:3c3aa4fd7e1a 508 // Store reason for restart
Bobty 14:3c3aa4fd7e1a 509 bool watchdogCausedRestart = watchdog.WatchdogCausedRestart();
Bobty 14:3c3aa4fd7e1a 510 bool restartCauseRecorded = false;
Bobty 5:5bccf48799d4 511
Bobty 20:7933076df5af 512 // Setup the watchdog for reset
Bobty 21:ccf053bab795 513 watchdog.SetTimeoutSecs(300);
Bobty 12:a52996515063 514
Bobty 9:0e103c2f869a 515 // Time of last broadcast
Bobty 9:0e103c2f869a 516 time_t timeOfLastBroadcast = time(NULL);
Bobty 9:0e103c2f869a 517 const int TIME_BETWEEN_BROADCASTS_IN_SECS = 60;
Bobty 5:5bccf48799d4 518 while(true)
Bobty 0:f6611c8f453c 519 {
Bobty 14:3c3aa4fd7e1a 520 // Check if we can record the reason for restart (i.e. if time is now set)
Bobty 14:3c3aa4fd7e1a 521 if (!restartCauseRecorded)
Bobty 14:3c3aa4fd7e1a 522 {
Bobty 14:3c3aa4fd7e1a 523 time_t nowTime = time(NULL);
Bobty 14:3c3aa4fd7e1a 524 if (nowTime > 1000000000)
Bobty 14:3c3aa4fd7e1a 525 {
Bobty 14:3c3aa4fd7e1a 526 // Record the reason for restarting in the log file
Bobty 14:3c3aa4fd7e1a 527 if (watchdogCausedRestart)
Bobty 19:0367cb46d003 528 {
Bobty 14:3c3aa4fd7e1a 529 logger.LogEvent("Watchdog Restart");
Bobty 20:7933076df5af 530 logger.LogDebug("Watchdog Restart");
Bobty 19:0367cb46d003 531 }
Bobty 14:3c3aa4fd7e1a 532 else
Bobty 19:0367cb46d003 533 {
Bobty 14:3c3aa4fd7e1a 534 logger.LogEvent("Normal Restart");
Bobty 20:7933076df5af 535 logger.LogDebug("Normal Restart");
Bobty 19:0367cb46d003 536 }
Bobty 14:3c3aa4fd7e1a 537 restartCauseRecorded = true;
Bobty 14:3c3aa4fd7e1a 538 }
Bobty 14:3c3aa4fd7e1a 539 }
Bobty 14:3c3aa4fd7e1a 540
Bobty 14:3c3aa4fd7e1a 541 // Loop delay
Bobty 9:0e103c2f869a 542 osDelay(LOOP_DELAY_IN_MS);
Bobty 14:3c3aa4fd7e1a 543
Bobty 14:3c3aa4fd7e1a 544 // Feed the watchdog and show the flashing LED
Bobty 5:5bccf48799d4 545 led1 = !led1;
Bobty 12:a52996515063 546 watchdog.Feed();
Bobty 5:5bccf48799d4 547
Bobty 5:5bccf48799d4 548 // Service gas count
Bobty 5:5bccf48799d4 549 if (gasUseCounter.Service())
Bobty 8:5980547ae71c 550 {
Bobty 9:0e103c2f869a 551 SendInfoBroadcast();
Bobty 9:0e103c2f869a 552 timeOfLastBroadcast = time(NULL);
Bobty 9:0e103c2f869a 553 }
Bobty 8:5980547ae71c 554
Bobty 9:0e103c2f869a 555 // Service thermometers
Bobty 9:0e103c2f869a 556 thermometers.Service();
Bobty 9:0e103c2f869a 557
Bobty 9:0e103c2f869a 558 // Check if ready for a broadcast
Bobty 9:0e103c2f869a 559 if ((time(NULL) - timeOfLastBroadcast) >= TIME_BETWEEN_BROADCASTS_IN_SECS)
Bobty 9:0e103c2f869a 560 {
Bobty 9:0e103c2f869a 561 SendInfoBroadcast();
Bobty 9:0e103c2f869a 562 timeOfLastBroadcast = time(NULL);
Bobty 8:5980547ae71c 563 }
Bobty 10:72eb217def1f 564
Bobty 10:72eb217def1f 565 // Service volt alerters
Bobty 10:72eb217def1f 566 voltAlerter1.Service();
Bobty 10:72eb217def1f 567 voltAlerter2.Service();
Bobty 10:72eb217def1f 568 voltAlerter3.Service();
Bobty 11:30182b9aa833 569
Bobty 11:30182b9aa833 570 // Set LED2 to the state of the first volt alerter
Bobty 10:72eb217def1f 571 led2 = voltAlerter1.GetState();
Bobty 12:a52996515063 572
Bobty 12:a52996515063 573 #ifdef TEST_WATCHDOG
Bobty 12:a52996515063 574 // After about 20 seconds of operation we'll hang to test the watchdog
Bobty 12:a52996515063 575 if (watchdogTestLoopCount++ > 80)
Bobty 12:a52996515063 576 {
Bobty 12:a52996515063 577 // This should cause watchdog to kick in and reset
Bobty 12:a52996515063 578 osDelay(20000);
Bobty 12:a52996515063 579 }
Bobty 12:a52996515063 580 #endif
Bobty 0:f6611c8f453c 581 }
Bobty 5:5bccf48799d4 582 }
Bobty 9:0e103c2f869a 583