X10 Server - IOT device to leverage a collection of old X10 devices for home automation and lighting control.
Dependencies: IniManager mbed HTTPClient SWUpdate mbed-rtos Watchdog X10 SW_HTTPServer SW_String EthernetInterface TimeInterface SSDP
X10 Server
See the X10 Server Nodebook page
main.cpp@10:ca0c1db6d933, 2019-03-03 (annotated)
- Committer:
- WiredHome
- Date:
- Sun Mar 03 23:41:27 2019 +0000
- Revision:
- 10:ca0c1db6d933
- Parent:
- 9:2c96e69b6035
Updated WattEye that has SSDP Discovery.;
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
WiredHome | 0:de1dfa2ab813 | 1 | // |
WiredHome | 10:ca0c1db6d933 | 2 | // WattEye - Version 2 |
WiredHome | 0:de1dfa2ab813 | 3 | // |
WiredHome | 10:ca0c1db6d933 | 4 | /// WattEye monitors a simple input pin, measures the time between pulses, and translates |
WiredHome | 10:ca0c1db6d933 | 5 | /// that into a unit of power. The pulses are generated by the whole-house electric meter |
WiredHome | 10:ca0c1db6d933 | 6 | /// and may be generated by an IR Emitter. |
WiredHome | 7:16129d213e6a | 7 | /// |
WiredHome | 7:16129d213e6a | 8 | |
WiredHome | 0:de1dfa2ab813 | 9 | #include "mbed.h" // ver 120; mbed-rtos ver 111 |
WiredHome | 7:16129d213e6a | 10 | #include "EthernetInterface.h" // ver 56 - https://os.mbed.com/users/WiredHome/code/EthernetInterface/ |
WiredHome | 7:16129d213e6a | 11 | #include "SW_HTTPServer.h" // ver 58 |
WiredHome | 7:16129d213e6a | 12 | #include "TimeInterface.h" // ver 25 |
WiredHome | 7:16129d213e6a | 13 | #include "SWUpdate.h" // ver 26 |
WiredHome | 7:16129d213e6a | 14 | #include "SW_String.h" // ver 2 |
WiredHome | 7:16129d213e6a | 15 | #include "SSDP.h" // ver 7 |
WiredHome | 0:de1dfa2ab813 | 16 | #include "Watchdog.h" // ver 6 |
WiredHome | 7:16129d213e6a | 17 | #include "IniManager.h" // v20 |
WiredHome | 10:ca0c1db6d933 | 18 | |
WiredHome | 10:ca0c1db6d933 | 19 | #include "StatisticQueue.h" |
WiredHome | 10:ca0c1db6d933 | 20 | #include "PowerData.h" |
WiredHome | 7:16129d213e6a | 21 | |
WiredHome | 0:de1dfa2ab813 | 22 | #include "WebPages.h" // Private handler for web queries |
WiredHome | 7:16129d213e6a | 23 | #include "SignOfLife.h" // LED effects |
WiredHome | 0:de1dfa2ab813 | 24 | |
WiredHome | 7:16129d213e6a | 25 | extern "C" void mbed_reset(); |
WiredHome | 7:16129d213e6a | 26 | |
WiredHome | 10:ca0c1db6d933 | 27 | //#define DEBUG "MAIN" |
WiredHome | 10:ca0c1db6d933 | 28 | #include <cstdio> |
WiredHome | 10:ca0c1db6d933 | 29 | #if (defined(DEBUG) && !defined(TARGET_LPC11U24)) |
WiredHome | 10:ca0c1db6d933 | 30 | #define DBG(x, ...) std::printf("[DBG %s %3d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__); |
WiredHome | 10:ca0c1db6d933 | 31 | #define WARN(x, ...) std::printf("[WRN %s %3d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__); |
WiredHome | 10:ca0c1db6d933 | 32 | #define ERR(x, ...) std::printf("[ERR %s %3d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__); |
WiredHome | 10:ca0c1db6d933 | 33 | #define INFO(x, ...) std::printf("[INF %s %3d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__); |
WiredHome | 10:ca0c1db6d933 | 34 | #else |
WiredHome | 10:ca0c1db6d933 | 35 | #define DBG(x, ...) |
WiredHome | 10:ca0c1db6d933 | 36 | #define WARN(x, ...) |
WiredHome | 10:ca0c1db6d933 | 37 | #define ERR(x, ...) |
WiredHome | 10:ca0c1db6d933 | 38 | #define INFO(x, ...) |
WiredHome | 10:ca0c1db6d933 | 39 | #endif |
WiredHome | 10:ca0c1db6d933 | 40 | |
WiredHome | 5:6244e237def1 | 41 | |
WiredHome | 0:de1dfa2ab813 | 42 | RawSerial pc(USBTX, USBRX); |
WiredHome | 0:de1dfa2ab813 | 43 | EthernetInterface eth; |
WiredHome | 7:16129d213e6a | 44 | DigitalOut linkup(p26); |
WiredHome | 7:16129d213e6a | 45 | DigitalOut linkdata(p25); |
WiredHome | 7:16129d213e6a | 46 | |
WiredHome | 0:de1dfa2ab813 | 47 | Watchdog wd; |
WiredHome | 7:16129d213e6a | 48 | bool WDEventOccurred = false; |
WiredHome | 0:de1dfa2ab813 | 49 | |
WiredHome | 7:16129d213e6a | 50 | TimeInterface ntp(ð); |
WiredHome | 7:16129d213e6a | 51 | time_t ntpSyncd; // time of the last sync |
WiredHome | 7:16129d213e6a | 52 | bool ntpUpdateCheck = true; // scheduled check on startup |
WiredHome | 4:5da66fab599c | 53 | |
WiredHome | 7:16129d213e6a | 54 | time_t lastboottime; |
WiredHome | 7:16129d213e6a | 55 | bool swUpdateCheck = true; // scheduled check on startup |
WiredHome | 7:16129d213e6a | 56 | |
WiredHome | 7:16129d213e6a | 57 | INI ini; |
WiredHome | 0:de1dfa2ab813 | 58 | LocalFileSystem local("local"); // some place to hold settings and maybe the static web pages |
WiredHome | 0:de1dfa2ab813 | 59 | const char * Server_Root = "/local"; |
WiredHome | 0:de1dfa2ab813 | 60 | |
WiredHome | 0:de1dfa2ab813 | 61 | // public for the WebPages handler to see |
WiredHome | 0:de1dfa2ab813 | 62 | // |
WiredHome | 0:de1dfa2ab813 | 63 | const char * BUILD_DATE = __DATE__ " " __TIME__; |
WiredHome | 10:ca0c1db6d933 | 64 | const char * PROG_NAME = "WattEye-2"; |
WiredHome | 10:ca0c1db6d933 | 65 | char * My_Name = "WattEye-2"; |
WiredHome | 10:ca0c1db6d933 | 66 | const char * PROG_INFO = "WattEye-2 Build " __DATE__ " " __TIME__; |
WiredHome | 0:de1dfa2ab813 | 67 | const char * My_SerialNum = "0000001"; |
WiredHome | 4:5da66fab599c | 68 | int Server_Port = 80; |
WiredHome | 0:de1dfa2ab813 | 69 | // end public information |
WiredHome | 0:de1dfa2ab813 | 70 | |
WiredHome | 10:ca0c1db6d933 | 71 | const char * iniFile = "/local/WattEye.ini"; |
WiredHome | 7:16129d213e6a | 72 | |
WiredHome | 10:ca0c1db6d933 | 73 | HTTPClient http; |
WiredHome | 10:ca0c1db6d933 | 74 | DigitalOut PulseIndicator(LED1); |
WiredHome | 10:ca0c1db6d933 | 75 | DigitalOut UDPSendIndicator(LED2); |
WiredHome | 10:ca0c1db6d933 | 76 | DigitalOut URLSendIndicator(LED3); |
WiredHome | 7:16129d213e6a | 77 | |
WiredHome | 7:16129d213e6a | 78 | |
WiredHome | 10:ca0c1db6d933 | 79 | // Keep a sample every 5 s for 5 minutes |
WiredHome | 10:ca0c1db6d933 | 80 | // 12 samples / min * 5 min => 60 samples |
WiredHome | 10:ca0c1db6d933 | 81 | #define SampleInterval_Sec 5 |
WiredHome | 10:ca0c1db6d933 | 82 | #define SampleHistory_5m (60) |
WiredHome | 10:ca0c1db6d933 | 83 | StatisticQueue stats5s(SampleHistory_5m); |
WiredHome | 10:ca0c1db6d933 | 84 | |
WiredHome | 10:ca0c1db6d933 | 85 | // Keep 5 minute data for 1 day |
WiredHome | 10:ca0c1db6d933 | 86 | // 12 samples / hour * 24 hours => 288 |
WiredHome | 10:ca0c1db6d933 | 87 | #define SampleInterval_Min 5 |
WiredHome | 10:ca0c1db6d933 | 88 | #define SampleHistory_1d 288 |
WiredHome | 10:ca0c1db6d933 | 89 | StatisticQueue stats5m(SampleHistory_1d); |
WiredHome | 10:ca0c1db6d933 | 90 | |
WiredHome | 10:ca0c1db6d933 | 91 | char url[100], dest[20], port[8]; |
WiredHome | 10:ca0c1db6d933 | 92 | char myID[50]; |
WiredHome | 10:ca0c1db6d933 | 93 | |
WiredHome | 10:ca0c1db6d933 | 94 | InterruptIn event(p15); |
WiredHome | 10:ca0c1db6d933 | 95 | Timer timer; |
WiredHome | 10:ca0c1db6d933 | 96 | Timeout flash; |
WiredHome | 10:ca0c1db6d933 | 97 | |
WiredHome | 10:ca0c1db6d933 | 98 | typedef struct { |
WiredHome | 10:ca0c1db6d933 | 99 | time_t todClock; |
WiredHome | 10:ca0c1db6d933 | 100 | uint32_t tLastStart; |
WiredHome | 10:ca0c1db6d933 | 101 | uint32_t tLastRise; |
WiredHome | 10:ca0c1db6d933 | 102 | uint16_t Samples10s[30]; // Every 10s for 5 min |
WiredHome | 10:ca0c1db6d933 | 103 | uint16_t Samples10sIndex; |
WiredHome | 10:ca0c1db6d933 | 104 | uint16_t Samples5m[12*24]; // Every 5m for 1 day |
WiredHome | 10:ca0c1db6d933 | 105 | uint16_t Samples5mIndex; |
WiredHome | 10:ca0c1db6d933 | 106 | uint16_t Samples1d[365]; // Every |
WiredHome | 10:ca0c1db6d933 | 107 | uint16_t Samples1dIndex; |
WiredHome | 10:ca0c1db6d933 | 108 | } WattData; |
WiredHome | 10:ca0c1db6d933 | 109 | |
WiredHome | 10:ca0c1db6d933 | 110 | Atomic_t PowerSnapshot; |
WiredHome | 10:ca0c1db6d933 | 111 | |
WiredHome | 10:ca0c1db6d933 | 112 | typedef struct { |
WiredHome | 10:ca0c1db6d933 | 113 | bool init; |
WiredHome | 10:ca0c1db6d933 | 114 | time_t startTimestamp; |
WiredHome | 10:ca0c1db6d933 | 115 | uint64_t tStart; |
WiredHome | 10:ca0c1db6d933 | 116 | uint64_t tLastRise; |
WiredHome | 10:ca0c1db6d933 | 117 | uint64_t tStartSample; |
WiredHome | 10:ca0c1db6d933 | 118 | uint32_t cycles; |
WiredHome | 10:ca0c1db6d933 | 119 | } RawSample_t; |
WiredHome | 10:ca0c1db6d933 | 120 | |
WiredHome | 10:ca0c1db6d933 | 121 | RawSample_t RawPowerSample; |
WiredHome | 10:ca0c1db6d933 | 122 | |
WiredHome | 10:ca0c1db6d933 | 123 | void PulseRisingISR(void); |
WiredHome | 10:ca0c1db6d933 | 124 | void RunPulseTask(void); |
WiredHome | 10:ca0c1db6d933 | 125 | void TransmitEnergy(bool sendNow, float iKW, float min5s, float avg5s, float max5s, float min5m, float avg5m, float max5m); |
WiredHome | 10:ca0c1db6d933 | 126 | void ShowRawSample(); |
WiredHome | 10:ca0c1db6d933 | 127 | |
WiredHome | 10:ca0c1db6d933 | 128 | void ShowRawSample() { |
WiredHome | 10:ca0c1db6d933 | 129 | printf("Sample:\r\n"); |
WiredHome | 10:ca0c1db6d933 | 130 | printf(" Sample Start: %s\r\n", ntp.ctime(&RawPowerSample.startTimestamp)); |
WiredHome | 10:ca0c1db6d933 | 131 | printf(" tStart: %llu\r\n", RawPowerSample.tStart); |
WiredHome | 10:ca0c1db6d933 | 132 | printf(" tLastRise: %llu\r\n", RawPowerSample.tLastRise); |
WiredHome | 10:ca0c1db6d933 | 133 | printf(" tStartSample: %llu\r\n", RawPowerSample.tStartSample); |
WiredHome | 10:ca0c1db6d933 | 134 | printf(" cycles: %ul\r\n", RawPowerSample.cycles); |
WiredHome | 10:ca0c1db6d933 | 135 | } |
WiredHome | 10:ca0c1db6d933 | 136 | |
WiredHome | 10:ca0c1db6d933 | 137 | |
WiredHome | 10:ca0c1db6d933 | 138 | void SoftwareUpdateCheck(bool force = false) |
WiredHome | 7:16129d213e6a | 139 | { |
WiredHome | 7:16129d213e6a | 140 | char url[100], name[10]; |
WiredHome | 10:ca0c1db6d933 | 141 | static time_t tstart = ntp.timelocal(); |
WiredHome | 10:ca0c1db6d933 | 142 | time_t tNow = ntp.timelocal(); |
WiredHome | 10:ca0c1db6d933 | 143 | |
WiredHome | 7:16129d213e6a | 144 | //eth_mutex.lock(); |
WiredHome | 10:ca0c1db6d933 | 145 | #define ONE_DAY (24 * 60 * 60) |
WiredHome | 7:16129d213e6a | 146 | if (force || (tNow - tstart) > ONE_DAY) { |
WiredHome | 10:ca0c1db6d933 | 147 | pc.printf(" SoftwareUpdateCheck: %s\r\n", ntp.ctime(&tNow)); |
WiredHome | 7:16129d213e6a | 148 | tstart = tNow; |
WiredHome | 7:16129d213e6a | 149 | swUpdateCheck = true; |
WiredHome | 7:16129d213e6a | 150 | if (INI::INI_SUCCESS == ini.ReadString("SWUpdate", "url", url, sizeof(url)) |
WiredHome | 7:16129d213e6a | 151 | && INI::INI_SUCCESS == ini.ReadString("SWUpdate", "name", name, sizeof(name))) { |
WiredHome | 7:16129d213e6a | 152 | linkdata = true; |
WiredHome | 7:16129d213e6a | 153 | pc.printf(" url: %s\r\n", url); |
WiredHome | 7:16129d213e6a | 154 | pc.printf(" name: %s\r\n", name); |
WiredHome | 7:16129d213e6a | 155 | SWUpdate_T su = SoftwareUpdate(url, name, DEFER_REBOOT); |
WiredHome | 7:16129d213e6a | 156 | if (SWUP_OK == su) { |
WiredHome | 7:16129d213e6a | 157 | pc.printf(" update installed, rebooting...\r\n"); |
WiredHome | 7:16129d213e6a | 158 | Thread::wait(3000); |
WiredHome | 7:16129d213e6a | 159 | mbed_reset(); |
WiredHome | 7:16129d213e6a | 160 | } else if (SWUP_SAME_VER == su) { |
WiredHome | 7:16129d213e6a | 161 | pc.printf(" no update available.\r\n"); |
WiredHome | 7:16129d213e6a | 162 | swUpdateCheck = false; |
WiredHome | 7:16129d213e6a | 163 | } else { |
WiredHome | 10:ca0c1db6d933 | 164 | pc.printf(" update failed %04X - %s\r\n", su, |
WiredHome | 10:ca0c1db6d933 | 165 | SoftwareUpdateGetHTTPErrorMsg(SoftwareUpdateGetHTTPErrorCode())); |
WiredHome | 7:16129d213e6a | 166 | Thread::wait(1000); |
WiredHome | 10:ca0c1db6d933 | 167 | swUpdateCheck = false; |
WiredHome | 7:16129d213e6a | 168 | } |
WiredHome | 7:16129d213e6a | 169 | linkdata = false; |
WiredHome | 7:16129d213e6a | 170 | } else { |
WiredHome | 7:16129d213e6a | 171 | pc.printf(" can't get info from ini file.\r\n"); |
WiredHome | 7:16129d213e6a | 172 | swUpdateCheck = false; |
WiredHome | 7:16129d213e6a | 173 | } |
WiredHome | 10:ca0c1db6d933 | 174 | //eth_mutex.unlock(); |
WiredHome | 7:16129d213e6a | 175 | } |
WiredHome | 7:16129d213e6a | 176 | } |
WiredHome | 7:16129d213e6a | 177 | |
WiredHome | 10:ca0c1db6d933 | 178 | void ShowIPAddress(bool show = true) |
WiredHome | 10:ca0c1db6d933 | 179 | { |
WiredHome | 10:ca0c1db6d933 | 180 | char buf[16]; |
WiredHome | 10:ca0c1db6d933 | 181 | |
WiredHome | 10:ca0c1db6d933 | 182 | if (show) |
WiredHome | 10:ca0c1db6d933 | 183 | sprintf(buf, "%15s", eth.getIPAddress()); |
WiredHome | 10:ca0c1db6d933 | 184 | else |
WiredHome | 10:ca0c1db6d933 | 185 | sprintf(buf, "%15s", "---.---.---.---"); |
WiredHome | 10:ca0c1db6d933 | 186 | pc.printf("Ethernet connected as %s\r\n", buf); |
WiredHome | 10:ca0c1db6d933 | 187 | } |
WiredHome | 10:ca0c1db6d933 | 188 | |
WiredHome | 10:ca0c1db6d933 | 189 | |
WiredHome | 7:16129d213e6a | 190 | |
WiredHome | 7:16129d213e6a | 191 | /// This function syncs the node to a timeserver, if one |
WiredHome | 7:16129d213e6a | 192 | /// is configured in the .ini file. |
WiredHome | 7:16129d213e6a | 193 | /// |
WiredHome | 7:16129d213e6a | 194 | void SyncToNTPServer(bool force) |
WiredHome | 7:16129d213e6a | 195 | { |
WiredHome | 7:16129d213e6a | 196 | char url[100]; |
WiredHome | 7:16129d213e6a | 197 | char tzone[10]; |
WiredHome | 7:16129d213e6a | 198 | char dstFlag[5]; // off,on,auto |
WiredHome | 7:16129d213e6a | 199 | char dstStart[12]; // mm/dd,hh:mm |
WiredHome | 7:16129d213e6a | 200 | char dstStop[12]; // mm/dd,hh:mm |
WiredHome | 7:16129d213e6a | 201 | static time_t tlast = 0; |
WiredHome | 10:ca0c1db6d933 | 202 | time_t tnow = ntp.timelocal(); |
WiredHome | 7:16129d213e6a | 203 | |
WiredHome | 7:16129d213e6a | 204 | if (((tnow - tlast) > (60*60*24)) || force) { |
WiredHome | 7:16129d213e6a | 205 | printf("SyncToNTPServer\r\n"); |
WiredHome | 7:16129d213e6a | 206 | if (INI::INI_SUCCESS == ini.ReadString("Clock", "timeserver", url, sizeof(url))) { |
WiredHome | 7:16129d213e6a | 207 | ini.ReadString("Clock", "tzoffsetmin", tzone, sizeof(tzone), "0"); |
WiredHome | 7:16129d213e6a | 208 | ini.ReadString("Clock", "dst", dstFlag, sizeof(dstFlag), "0"); |
WiredHome | 7:16129d213e6a | 209 | ini.ReadString("Clock", "dststart", dstStart, sizeof(dstStart), ""); |
WiredHome | 7:16129d213e6a | 210 | ini.ReadString("Clock", "dststop", dstStop, sizeof(dstStop), ""); |
WiredHome | 10:ca0c1db6d933 | 211 | |
WiredHome | 7:16129d213e6a | 212 | printf("NTP update time from (%s)\r\n", url); |
WiredHome | 7:16129d213e6a | 213 | int32_t tzo_min = atoi(tzone); |
WiredHome | 10:ca0c1db6d933 | 214 | |
WiredHome | 7:16129d213e6a | 215 | if (strcmp(dstFlag,"on") == 0) { |
WiredHome | 7:16129d213e6a | 216 | ntp.set_dst(1); |
WiredHome | 7:16129d213e6a | 217 | } else if (strcmp(dstFlag, "off") == 0) { |
WiredHome | 7:16129d213e6a | 218 | ntp.set_dst(0); |
WiredHome | 10:ca0c1db6d933 | 219 | } else { /* if (strcmp(dstFlag, "auto") == 0) */ |
WiredHome | 7:16129d213e6a | 220 | ntp.set_dst(dstStart,dstStop); |
WiredHome | 7:16129d213e6a | 221 | } |
WiredHome | 7:16129d213e6a | 222 | ntp.set_tzo_min(tzo_min); |
WiredHome | 8:a45fe77efcc5 | 223 | linkdata = true; |
WiredHome | 7:16129d213e6a | 224 | int res = ntp.setTime(url); |
WiredHome | 7:16129d213e6a | 225 | //printf(" NTP (release ethernet)\r\n"); |
WiredHome | 7:16129d213e6a | 226 | if (res == 0) { |
WiredHome | 7:16129d213e6a | 227 | time_t ctTime; |
WiredHome | 10:ca0c1db6d933 | 228 | ctTime = ntp.timelocal(); |
WiredHome | 7:16129d213e6a | 229 | ntpSyncd = ntp.get_timelastset();; |
WiredHome | 7:16129d213e6a | 230 | tlast = ctTime; |
WiredHome | 7:16129d213e6a | 231 | printf(" Time set to (UTC): %s\r\n", ntp.ctime(&ctTime)); |
WiredHome | 10:ca0c1db6d933 | 232 | printf(" ntpSyncd: %s (UTC)\r\n", ntp.ctime(&ntpSyncd)); |
WiredHome | 8:a45fe77efcc5 | 233 | ntpUpdateCheck = false; |
WiredHome | 7:16129d213e6a | 234 | } else { |
WiredHome | 7:16129d213e6a | 235 | ntpSyncd = 0; |
WiredHome | 7:16129d213e6a | 236 | printf("Error return from setTime(%s) %d\r\n", url, res); |
WiredHome | 7:16129d213e6a | 237 | } |
WiredHome | 8:a45fe77efcc5 | 238 | linkdata = false; |
WiredHome | 7:16129d213e6a | 239 | } else { |
WiredHome | 7:16129d213e6a | 240 | ntpSyncd = 0; |
WiredHome | 7:16129d213e6a | 241 | printf("no time server was set\r\n"); |
WiredHome | 7:16129d213e6a | 242 | } |
WiredHome | 7:16129d213e6a | 243 | } |
WiredHome | 7:16129d213e6a | 244 | } |
WiredHome | 7:16129d213e6a | 245 | |
WiredHome | 7:16129d213e6a | 246 | |
WiredHome | 7:16129d213e6a | 247 | /// This function monitors the USB serial interface for activity |
WiredHome | 7:16129d213e6a | 248 | /// from a connected user. |
WiredHome | 7:16129d213e6a | 249 | /// |
WiredHome | 7:16129d213e6a | 250 | /// It offers a tiny bit of help if an unrecognized command is entered. |
WiredHome | 7:16129d213e6a | 251 | /// |
WiredHome | 7:16129d213e6a | 252 | void CheckConsoleInput(void) |
WiredHome | 7:16129d213e6a | 253 | { |
WiredHome | 7:16129d213e6a | 254 | static Timer timer; |
WiredHome | 7:16129d213e6a | 255 | |
WiredHome | 7:16129d213e6a | 256 | if (pc.readable()) { |
WiredHome | 7:16129d213e6a | 257 | int c = pc.getc(); |
WiredHome | 7:16129d213e6a | 258 | switch (c) { |
WiredHome | 7:16129d213e6a | 259 | case 'r': |
WiredHome | 7:16129d213e6a | 260 | mbed_reset(); |
WiredHome | 7:16129d213e6a | 261 | break; |
WiredHome | 7:16129d213e6a | 262 | case 's': |
WiredHome | 7:16129d213e6a | 263 | swUpdateCheck = true; |
WiredHome | 7:16129d213e6a | 264 | break; |
WiredHome | 7:16129d213e6a | 265 | case 't': |
WiredHome | 7:16129d213e6a | 266 | ntpUpdateCheck = true; |
WiredHome | 7:16129d213e6a | 267 | break; |
WiredHome | 7:16129d213e6a | 268 | case '@': |
WiredHome | 7:16129d213e6a | 269 | pc.printf("Sample '%s' file.\r\n", iniFile); |
WiredHome | 7:16129d213e6a | 270 | pc.printf("[SWUpdate]\r\n"); |
WiredHome | 7:16129d213e6a | 271 | pc.printf("url=http://192.168.1.201/mbed/\r\n"); |
WiredHome | 10:ca0c1db6d933 | 272 | pc.printf("name=WattEye\r\n"); |
WiredHome | 7:16129d213e6a | 273 | pc.printf("[Clock]\r\n"); |
WiredHome | 7:16129d213e6a | 274 | pc.printf("timeserver=time.nist.gov\r\n"); |
WiredHome | 7:16129d213e6a | 275 | pc.printf("tzoffsetmin=-300\r\n"); |
WiredHome | 7:16129d213e6a | 276 | pc.printf("[IP]\r\n"); |
WiredHome | 10:ca0c1db6d933 | 277 | pc.printf("ip=192.168.1.204\r\n"); |
WiredHome | 7:16129d213e6a | 278 | pc.printf("nm=255.255.254.0\r\n"); |
WiredHome | 7:16129d213e6a | 279 | pc.printf("gw=192.168.1.1\r\n"); |
WiredHome | 7:16129d213e6a | 280 | pc.printf("[Node]\r\n"); |
WiredHome | 10:ca0c1db6d933 | 281 | pc.printf("id=WattEye-01\r\n"); |
WiredHome | 7:16129d213e6a | 282 | pc.printf(";hint: Use either the fixed IP or the Node\r\n"); |
WiredHome | 7:16129d213e6a | 283 | break; |
WiredHome | 7:16129d213e6a | 284 | case '?': |
WiredHome | 10:ca0c1db6d933 | 285 | ShowRawSample(); |
WiredHome | 10:ca0c1db6d933 | 286 | // break; |
WiredHome | 7:16129d213e6a | 287 | default: |
WiredHome | 7:16129d213e6a | 288 | pc.printf("\r\n\r\n"); |
WiredHome | 7:16129d213e6a | 289 | if (c > ' ' && c != '?') |
WiredHome | 7:16129d213e6a | 290 | pc.printf("unknown command '%c'\r\n", c); |
WiredHome | 10:ca0c1db6d933 | 291 | pc.printf("Commands:\r\n" |
WiredHome | 10:ca0c1db6d933 | 292 | " r = reset\r\n" |
WiredHome | 10:ca0c1db6d933 | 293 | " s = software update check\r\n" |
WiredHome | 10:ca0c1db6d933 | 294 | " t = time sync to NTP server\r\n" |
WiredHome | 10:ca0c1db6d933 | 295 | ); |
WiredHome | 10:ca0c1db6d933 | 296 | ShowIPAddress(); |
WiredHome | 10:ca0c1db6d933 | 297 | |
WiredHome | 7:16129d213e6a | 298 | break; |
WiredHome | 7:16129d213e6a | 299 | } |
WiredHome | 7:16129d213e6a | 300 | } |
WiredHome | 7:16129d213e6a | 301 | } |
WiredHome | 7:16129d213e6a | 302 | |
WiredHome | 7:16129d213e6a | 303 | |
WiredHome | 7:16129d213e6a | 304 | |
WiredHome | 5:6244e237def1 | 305 | int main() |
WiredHome | 4:5da66fab599c | 306 | { |
WiredHome | 7:16129d213e6a | 307 | char ip[20],nm[20],gw[20]; |
WiredHome | 10:ca0c1db6d933 | 308 | bool SensorStarted = false; |
WiredHome | 10:ca0c1db6d933 | 309 | |
WiredHome | 0:de1dfa2ab813 | 310 | pc.baud(460800); |
WiredHome | 0:de1dfa2ab813 | 311 | pc.printf("\r\n%s Build %s\r\n", PROG_NAME, BUILD_DATE); |
WiredHome | 4:5da66fab599c | 312 | lastboottime = ntp.timelocal(); |
WiredHome | 0:de1dfa2ab813 | 313 | if (wd.WatchdogCausedReset()) { |
WiredHome | 0:de1dfa2ab813 | 314 | pc.printf("**** Watchdog Event caused reset at %s ****\r\n", ntp.ctime(&lastboottime)); |
WiredHome | 7:16129d213e6a | 315 | WDEventOccurred = true; |
WiredHome | 0:de1dfa2ab813 | 316 | } |
WiredHome | 7:16129d213e6a | 317 | wd.Configure(25); // very generous, but this is a network appliance, so a bit less deterministic. |
WiredHome | 7:16129d213e6a | 318 | |
WiredHome | 7:16129d213e6a | 319 | ini.SetFile(iniFile, 2); |
WiredHome | 0:de1dfa2ab813 | 320 | |
WiredHome | 5:6244e237def1 | 321 | pc.printf("Initializing network interface...\r\n"); |
WiredHome | 7:16129d213e6a | 322 | int initResult; |
WiredHome | 10:ca0c1db6d933 | 323 | |
WiredHome | 7:16129d213e6a | 324 | if (INI::INI_SUCCESS == ini.ReadString("IP", "ip", ip, sizeof(ip)) |
WiredHome | 10:ca0c1db6d933 | 325 | && INI::INI_SUCCESS == ini.ReadString("IP", "nm", nm, sizeof(nm)) |
WiredHome | 10:ca0c1db6d933 | 326 | && INI::INI_SUCCESS == ini.ReadString("IP", "gw", gw, sizeof(gw))) { |
WiredHome | 7:16129d213e6a | 327 | initResult = eth.init(ip,nm,gw); // use Fixed |
WiredHome | 7:16129d213e6a | 328 | } else { |
WiredHome | 7:16129d213e6a | 329 | initResult = eth.init(); // use DHCP |
WiredHome | 7:16129d213e6a | 330 | } |
WiredHome | 7:16129d213e6a | 331 | if (initResult) { |
WiredHome | 7:16129d213e6a | 332 | // Failed to init ... |
WiredHome | 7:16129d213e6a | 333 | pc.printf(" ... failed to initialize, rebooting...\r\n"); |
WiredHome | 7:16129d213e6a | 334 | wait_ms(5000); |
WiredHome | 7:16129d213e6a | 335 | mbed_reset(); |
WiredHome | 7:16129d213e6a | 336 | } else { |
WiredHome | 10:ca0c1db6d933 | 337 | bool bEU = ini.ReadString("Energy", "url", url, sizeof(url)); |
WiredHome | 10:ca0c1db6d933 | 338 | bool bDS = ini.ReadString("Energy", "dest", dest, sizeof(dest)); |
WiredHome | 10:ca0c1db6d933 | 339 | bool bPO = ini.ReadString("Energy", "port", port, sizeof(port)); |
WiredHome | 10:ca0c1db6d933 | 340 | bool bID = ini.ReadString("Node", "id", myID, sizeof(myID)); |
WiredHome | 10:ca0c1db6d933 | 341 | if (INI::INI_SUCCESS == bEU && INI::INI_SUCCESS == bDS && INI::INI_SUCCESS == bPO && INI::INI_SUCCESS == bID) { |
WiredHome | 10:ca0c1db6d933 | 342 | pc.printf("Node %s\r\n", myID); |
WiredHome | 10:ca0c1db6d933 | 343 | pc.printf("URL %s\r\n", url); |
WiredHome | 10:ca0c1db6d933 | 344 | pc.printf("port %s\r\n", port); |
WiredHome | 10:ca0c1db6d933 | 345 | pc.printf("dest %s\r\n", dest); |
WiredHome | 10:ca0c1db6d933 | 346 | Server_Port = atoi(port); |
WiredHome | 10:ca0c1db6d933 | 347 | } |
WiredHome | 10:ca0c1db6d933 | 348 | eth.setName(myID); |
WiredHome | 4:5da66fab599c | 349 | |
WiredHome | 5:6244e237def1 | 350 | do { |
WiredHome | 5:6244e237def1 | 351 | pc.printf("Connecting to network...\r\n"); |
WiredHome | 5:6244e237def1 | 352 | if (0 == eth.connect()) { |
WiredHome | 7:16129d213e6a | 353 | wd.Service(); |
WiredHome | 7:16129d213e6a | 354 | linkup = true; |
WiredHome | 10:ca0c1db6d933 | 355 | time_t tstart = ntp.timelocal(); |
WiredHome | 5:6244e237def1 | 356 | int speed = eth.get_connection_speed(); |
WiredHome | 5:6244e237def1 | 357 | |
WiredHome | 7:16129d213e6a | 358 | pc.printf("Ethernet Connected at: %d Mb/s\r\n", speed); |
WiredHome | 7:16129d213e6a | 359 | pc.printf(" IP: %15s\r\n", eth.getIPAddress()); |
WiredHome | 5:6244e237def1 | 360 | |
WiredHome | 10:ca0c1db6d933 | 361 | HTTPServer svr(Server_Port, Server_Root); |
WiredHome | 5:6244e237def1 | 362 | svr.RegisterHandler("/", RootPage); |
WiredHome | 7:16129d213e6a | 363 | svr.RegisterHandler("/info", InfoPage); |
WiredHome | 7:16129d213e6a | 364 | svr.RegisterHandler("/software", SoftwarePage); |
WiredHome | 8:a45fe77efcc5 | 365 | svr.RegisterHandler("/reboot", RebootPage); |
WiredHome | 5:6244e237def1 | 366 | svr.RegisterHandler("/setup.xml", Setup_xml); |
WiredHome | 10:ca0c1db6d933 | 367 | SSDP ssdp(myID, eth.getMACAddress(), eth.getIPAddress(), Server_Port); |
WiredHome | 4:5da66fab599c | 368 | |
WiredHome | 10:ca0c1db6d933 | 369 | wait(5); |
WiredHome | 10:ca0c1db6d933 | 370 | if (!SensorStarted) { |
WiredHome | 10:ca0c1db6d933 | 371 | timer.start(); |
WiredHome | 10:ca0c1db6d933 | 372 | timer.reset(); |
WiredHome | 10:ca0c1db6d933 | 373 | event.rise(&PulseRisingISR); |
WiredHome | 10:ca0c1db6d933 | 374 | SensorStarted = true; |
WiredHome | 10:ca0c1db6d933 | 375 | printf("Sensor started\r\n"); |
WiredHome | 10:ca0c1db6d933 | 376 | } |
WiredHome | 5:6244e237def1 | 377 | while (eth.is_connected()) { |
WiredHome | 5:6244e237def1 | 378 | wd.Service(); |
WiredHome | 5:6244e237def1 | 379 | time_t tNow = ntp.timelocal(); |
WiredHome | 7:16129d213e6a | 380 | CheckConsoleInput(); |
WiredHome | 10:ca0c1db6d933 | 381 | RunPulseTask(); |
WiredHome | 7:16129d213e6a | 382 | svr.Poll(); // Web Server: non-blocking, but also not deterministic |
WiredHome | 10:ca0c1db6d933 | 383 | ShowSignOfLife(); |
WiredHome | 7:16129d213e6a | 384 | SyncToNTPServer(ntpUpdateCheck); |
WiredHome | 7:16129d213e6a | 385 | SoftwareUpdateCheck(swUpdateCheck); |
WiredHome | 5:6244e237def1 | 386 | // Any other work can happen here |
WiredHome | 7:16129d213e6a | 387 | // ... |
WiredHome | 5:6244e237def1 | 388 | Thread::yield(); |
WiredHome | 5:6244e237def1 | 389 | } |
WiredHome | 7:16129d213e6a | 390 | linkup = false; |
WiredHome | 7:16129d213e6a | 391 | linkdata = false; |
WiredHome | 5:6244e237def1 | 392 | pc.printf("lost connection.\r\n"); |
WiredHome | 10:ca0c1db6d933 | 393 | ShowIPAddress(false); |
WiredHome | 5:6244e237def1 | 394 | eth.disconnect(); |
WiredHome | 5:6244e237def1 | 395 | } else { |
WiredHome | 5:6244e237def1 | 396 | pc.printf(" ... failed to connect.\r\n"); |
WiredHome | 5:6244e237def1 | 397 | } |
WiredHome | 5:6244e237def1 | 398 | } while (1); |
WiredHome | 0:de1dfa2ab813 | 399 | } |
WiredHome | 0:de1dfa2ab813 | 400 | } |
WiredHome | 10:ca0c1db6d933 | 401 | |
WiredHome | 10:ca0c1db6d933 | 402 | |
WiredHome | 10:ca0c1db6d933 | 403 | void LedOff(void) |
WiredHome | 10:ca0c1db6d933 | 404 | { |
WiredHome | 10:ca0c1db6d933 | 405 | PulseIndicator = 0; |
WiredHome | 10:ca0c1db6d933 | 406 | } |
WiredHome | 10:ca0c1db6d933 | 407 | |
WiredHome | 10:ca0c1db6d933 | 408 | |
WiredHome | 10:ca0c1db6d933 | 409 | void PulseRisingISR(void) |
WiredHome | 10:ca0c1db6d933 | 410 | { |
WiredHome | 10:ca0c1db6d933 | 411 | uint64_t tNow = timer.read_us(); |
WiredHome | 10:ca0c1db6d933 | 412 | |
WiredHome | 10:ca0c1db6d933 | 413 | __disable_irq(); |
WiredHome | 10:ca0c1db6d933 | 414 | if (!RawPowerSample.init) { |
WiredHome | 10:ca0c1db6d933 | 415 | RawPowerSample.init = true; |
WiredHome | 10:ca0c1db6d933 | 416 | RawPowerSample.cycles = (uint32_t)-1; |
WiredHome | 10:ca0c1db6d933 | 417 | RawPowerSample.tStart = tNow; |
WiredHome | 10:ca0c1db6d933 | 418 | RawPowerSample.tLastRise = tNow; |
WiredHome | 10:ca0c1db6d933 | 419 | RawPowerSample.startTimestamp = ntp.timelocal(); |
WiredHome | 10:ca0c1db6d933 | 420 | } |
WiredHome | 10:ca0c1db6d933 | 421 | RawPowerSample.cycles++; |
WiredHome | 10:ca0c1db6d933 | 422 | RawPowerSample.tStartSample = RawPowerSample.tLastRise; |
WiredHome | 10:ca0c1db6d933 | 423 | RawPowerSample.tLastRise = tNow; |
WiredHome | 10:ca0c1db6d933 | 424 | __enable_irq(); |
WiredHome | 10:ca0c1db6d933 | 425 | PulseIndicator = 1; |
WiredHome | 10:ca0c1db6d933 | 426 | flash.attach_us(&LedOff, 25000); |
WiredHome | 10:ca0c1db6d933 | 427 | } |
WiredHome | 10:ca0c1db6d933 | 428 | |
WiredHome | 10:ca0c1db6d933 | 429 | |
WiredHome | 10:ca0c1db6d933 | 430 | void RunPulseTask(void) |
WiredHome | 10:ca0c1db6d933 | 431 | { |
WiredHome | 10:ca0c1db6d933 | 432 | static time_t timeFor5s = 0; |
WiredHome | 10:ca0c1db6d933 | 433 | static time_t timeFor5m = 0; |
WiredHome | 10:ca0c1db6d933 | 434 | //static uint32_t lastCount = 0; |
WiredHome | 10:ca0c1db6d933 | 435 | time_t timenow = ntp.timelocal(); |
WiredHome | 10:ca0c1db6d933 | 436 | float iKW = 0.0f; |
WiredHome | 10:ca0c1db6d933 | 437 | bool sendToWeb = false; |
WiredHome | 10:ca0c1db6d933 | 438 | |
WiredHome | 10:ca0c1db6d933 | 439 | __disable_irq(); |
WiredHome | 10:ca0c1db6d933 | 440 | uint32_t elapsed = RawPowerSample.tLastRise - RawPowerSample.tStartSample; |
WiredHome | 10:ca0c1db6d933 | 441 | //uint32_t count = RawPowerSample.cycles; |
WiredHome | 10:ca0c1db6d933 | 442 | __enable_irq(); |
WiredHome | 10:ca0c1db6d933 | 443 | |
WiredHome | 10:ca0c1db6d933 | 444 | if (elapsed) { |
WiredHome | 10:ca0c1db6d933 | 445 | // instantaneous, from this exact sample |
WiredHome | 10:ca0c1db6d933 | 446 | iKW = (float)3600 * 1000 / elapsed; |
WiredHome | 10:ca0c1db6d933 | 447 | } |
WiredHome | 10:ca0c1db6d933 | 448 | if (timeFor5s == 0 || timenow < timeFor5s) // startup or if something goes really bad |
WiredHome | 10:ca0c1db6d933 | 449 | timeFor5s = timenow; |
WiredHome | 10:ca0c1db6d933 | 450 | if (timeFor5m == 0 || timenow < timeFor5m) // startup or if something goes really bad |
WiredHome | 10:ca0c1db6d933 | 451 | timeFor5m = timenow; |
WiredHome | 10:ca0c1db6d933 | 452 | |
WiredHome | 10:ca0c1db6d933 | 453 | if ((timenow - timeFor5m) >= 60) { // 300) { |
WiredHome | 10:ca0c1db6d933 | 454 | //pc.printf(" tnow: %d, t5m: %d\r\n", timenow, timeFor5m); |
WiredHome | 10:ca0c1db6d933 | 455 | sendToWeb = true; |
WiredHome | 10:ca0c1db6d933 | 456 | timeFor5s = timeFor5m = timenow; |
WiredHome | 10:ca0c1db6d933 | 457 | stats5s.EnterItem(iKW); |
WiredHome | 10:ca0c1db6d933 | 458 | stats5m.EnterItem(stats5s.Average()); |
WiredHome | 10:ca0c1db6d933 | 459 | TransmitEnergy(true, iKW, stats5s.Min(), stats5s.Average(), stats5s.Max(), |
WiredHome | 10:ca0c1db6d933 | 460 | stats5m.Min(), stats5m.Average(), stats5m.Max()); |
WiredHome | 10:ca0c1db6d933 | 461 | } else if ((timenow - timeFor5s) >= 5) { |
WiredHome | 10:ca0c1db6d933 | 462 | sendToWeb = true; |
WiredHome | 10:ca0c1db6d933 | 463 | timeFor5s = timenow; |
WiredHome | 10:ca0c1db6d933 | 464 | stats5s.EnterItem(iKW); |
WiredHome | 10:ca0c1db6d933 | 465 | TransmitEnergy(false, iKW, stats5s.Min(), stats5s.Average(), stats5s.Max(), |
WiredHome | 10:ca0c1db6d933 | 466 | stats5m.Min(), stats5m.Average(), stats5m.Max()); |
WiredHome | 10:ca0c1db6d933 | 467 | } |
WiredHome | 10:ca0c1db6d933 | 468 | if (sendToWeb) { // count != lastCount) { |
WiredHome | 10:ca0c1db6d933 | 469 | //lastCount = count; |
WiredHome | 10:ca0c1db6d933 | 470 | pc.printf("%8.3fs => %4.3f (%4.3f,%4.3f,%4.3f) iKW, (%4.3f,%4.3f,%4.3f) KW 5m\r\n", |
WiredHome | 10:ca0c1db6d933 | 471 | (float)elapsed/1000000, |
WiredHome | 10:ca0c1db6d933 | 472 | iKW, |
WiredHome | 10:ca0c1db6d933 | 473 | stats5s.Min(), stats5s.Average(), stats5s.Max(), |
WiredHome | 10:ca0c1db6d933 | 474 | stats5m.Min(), stats5m.Average(), stats5m.Max()); |
WiredHome | 10:ca0c1db6d933 | 475 | } |
WiredHome | 10:ca0c1db6d933 | 476 | } |
WiredHome | 10:ca0c1db6d933 | 477 | |
WiredHome | 10:ca0c1db6d933 | 478 | void TransmitEnergy(bool sendNow, float iKW, float min5s, float avg5s, float max5s, float min5m, float avg5m, float max5m) |
WiredHome | 10:ca0c1db6d933 | 479 | { |
WiredHome | 10:ca0c1db6d933 | 480 | char data[150]; |
WiredHome | 10:ca0c1db6d933 | 481 | char fullurl[250]; |
WiredHome | 10:ca0c1db6d933 | 482 | |
WiredHome | 10:ca0c1db6d933 | 483 | if (*url) { |
WiredHome | 10:ca0c1db6d933 | 484 | snprintf(data, 150, "ID=%s&iKW=%5.3f&min5s=%5.3f&avg5s=%5.3f&max5s=%5.3f&min5m=%5.3f&avg5m=%5.3f&max5m=%5.3f", |
WiredHome | 10:ca0c1db6d933 | 485 | myID, iKW, min5s, avg5s, max5s, min5m, avg5m, max5m); |
WiredHome | 10:ca0c1db6d933 | 486 | //eth_mutex.lock(); |
WiredHome | 10:ca0c1db6d933 | 487 | linkdata = true; |
WiredHome | 10:ca0c1db6d933 | 488 | // Send the UDP Broadcast, picked up by a listener |
WiredHome | 10:ca0c1db6d933 | 489 | UDPSendIndicator = true; |
WiredHome | 10:ca0c1db6d933 | 490 | UDPSocket bcast; |
WiredHome | 10:ca0c1db6d933 | 491 | Endpoint ep; |
WiredHome | 10:ca0c1db6d933 | 492 | int h = ep.set_address(dest, Server_Port); |
WiredHome | 10:ca0c1db6d933 | 493 | int i = bcast.bind(Server_Port); |
WiredHome | 10:ca0c1db6d933 | 494 | int j = bcast.set_broadcasting(true); |
WiredHome | 10:ca0c1db6d933 | 495 | int k = bcast.sendTo(ep, data, strlen(data)); |
WiredHome | 10:ca0c1db6d933 | 496 | bcast.close(); |
WiredHome | 10:ca0c1db6d933 | 497 | UDPSendIndicator = false; |
WiredHome | 10:ca0c1db6d933 | 498 | // On the 5-minute interval, post the data to a specified web server |
WiredHome | 10:ca0c1db6d933 | 499 | if (sendNow && *url) { |
WiredHome | 10:ca0c1db6d933 | 500 | //HTTPClient http; |
WiredHome | 10:ca0c1db6d933 | 501 | char buf[50]; |
WiredHome | 10:ca0c1db6d933 | 502 | URLSendIndicator = true; |
WiredHome | 10:ca0c1db6d933 | 503 | snprintf(fullurl, 250, "%s?%s", url, data); |
WiredHome | 10:ca0c1db6d933 | 504 | pc.printf("Contacting %s\r\n", fullurl); |
WiredHome | 10:ca0c1db6d933 | 505 | http.setMaxRedirections(3); |
WiredHome | 10:ca0c1db6d933 | 506 | int x = http.get(fullurl, buf, sizeof(buf)); |
WiredHome | 10:ca0c1db6d933 | 507 | URLSendIndicator = false; |
WiredHome | 10:ca0c1db6d933 | 508 | pc.printf(" return: %d\r\n", x); |
WiredHome | 10:ca0c1db6d933 | 509 | } |
WiredHome | 10:ca0c1db6d933 | 510 | linkdata = false; |
WiredHome | 10:ca0c1db6d933 | 511 | //eth_mutex.unlock(); |
WiredHome | 10:ca0c1db6d933 | 512 | } |
WiredHome | 10:ca0c1db6d933 | 513 | } |