Watt Eye has a simple purpose - monitor pulses that comes from the home electric meter, measure the interval between the pulses and compute the real-time energy being consumed, broadcast that onto the network using UDP packets so that CouchCalendar has something to do and display, and publish the data to a web server, where it can be used (graphed or placed into a db).

Dependencies:   IniManager mbed HTTPClient SWUpdate StatisticQueue mbed-rtos NTPClient Watchdog SW_HTTPServer EthernetInterface TimeInterface

Features:

  • Reads the time between pulses (which the home electric meter emits as IR for each Watt consumed).
  • Once every 5 seconds, it broadcasts this via UDP to the network, so other nodes can listen to this real-time data.
  • Once every 5 minutes, it posts statistics to a web server for logging.
  • Once a day, it checks the web server to see if there is a SW update (and if so it downloads, installs, and activates it).
  • It syncs to a configured NTP server, but doesn't actually use this information for anything.
  • It hosts a web server, but this is not being used at this time.

So, this is a rather expensive piece of hardware to monitor a single pulse, and yet it is easy to imagine enhancing this:

  • Read the water meter in a similar manner.
  • Read the gas meter in a similar manner.

And even then, there will be many left-over port pins for other uses.

Committer:
WiredHome
Date:
Sat Jul 26 19:51:33 2014 +0000
Revision:
0:a4887b672ac6
Child:
1:04ab0a3d07f1
Made it more robust for timing to push data to the web server. ; Also increased the frequency that it checks for software updates from once per day to once per hour since most development is "remote".

Who changed what in which revision?

UserRevisionLine numberNew contents of line
WiredHome 0:a4887b672ac6 1 #include "mbed.h" // v83, RTOS 38
WiredHome 0:a4887b672ac6 2 #include "RawSerial.h" // ?
WiredHome 0:a4887b672ac6 3
WiredHome 0:a4887b672ac6 4 // My libs
WiredHome 0:a4887b672ac6 5 #include "TimeInterface.h" // ver 3
WiredHome 0:a4887b672ac6 6 #include "HTTPClient.h" // ver 0
WiredHome 0:a4887b672ac6 7 #include "IniManager.h" // ver 9
WiredHome 0:a4887b672ac6 8 #include "SWUpdate.h" // ver 17
WiredHome 0:a4887b672ac6 9 #include "Watchdog.h" // ver 2
WiredHome 0:a4887b672ac6 10 #include "StatisticQueue.h"
WiredHome 0:a4887b672ac6 11
WiredHome 0:a4887b672ac6 12 //#define WIFLY
WiredHome 0:a4887b672ac6 13 #define HW_ADAPTER SMART_BOARD /* Which board are we compiling against? */
WiredHome 0:a4887b672ac6 14
WiredHome 0:a4887b672ac6 15 #ifdef WIFLY
WiredHome 0:a4887b672ac6 16 #include "WiflyInterface.h"
WiredHome 0:a4887b672ac6 17 #else
WiredHome 0:a4887b672ac6 18 #include "EthernetInterface.h" // ver 41
WiredHome 0:a4887b672ac6 19 #endif
WiredHome 0:a4887b672ac6 20 #include "EthStatus.h"
WiredHome 0:a4887b672ac6 21
WiredHome 0:a4887b672ac6 22 #include "SW_HTTPServer.h"
WiredHome 0:a4887b672ac6 23
WiredHome 0:a4887b672ac6 24 extern "C" void mbed_reset();
WiredHome 0:a4887b672ac6 25
WiredHome 0:a4887b672ac6 26 //#define DEBUG "MAIN"
WiredHome 0:a4887b672ac6 27 #include <cstdio>
WiredHome 0:a4887b672ac6 28 #if (defined(DEBUG) && !defined(TARGET_LPC11U24))
WiredHome 0:a4887b672ac6 29 #define DBG(x, ...) std::printf("[DBG %s %3d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__);
WiredHome 0:a4887b672ac6 30 #define WARN(x, ...) std::printf("[WRN %s %3d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__);
WiredHome 0:a4887b672ac6 31 #define ERR(x, ...) std::printf("[ERR %s %3d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__);
WiredHome 0:a4887b672ac6 32 #define INFO(x, ...) std::printf("[INF %s %3d] "x"\r\n", DEBUG, __LINE__, ##__VA_ARGS__);
WiredHome 0:a4887b672ac6 33 #else
WiredHome 0:a4887b672ac6 34 #define DBG(x, ...)
WiredHome 0:a4887b672ac6 35 #define WARN(x, ...)
WiredHome 0:a4887b672ac6 36 #define ERR(x, ...)
WiredHome 0:a4887b672ac6 37 #define INFO(x, ...)
WiredHome 0:a4887b672ac6 38 #endif
WiredHome 0:a4887b672ac6 39
WiredHome 0:a4887b672ac6 40 #define TIME_TO_CHECK_SW_UPDATE (60*60) /* once per hour */
WiredHome 0:a4887b672ac6 41
WiredHome 0:a4887b672ac6 42 EthernetInterface eth;
WiredHome 0:a4887b672ac6 43 Mutex eth_mutex;
WiredHome 0:a4887b672ac6 44
WiredHome 0:a4887b672ac6 45 Watchdog wd;
WiredHome 0:a4887b672ac6 46
WiredHome 0:a4887b672ac6 47 RawSerial pc(USBTX, USBRX);
WiredHome 0:a4887b672ac6 48 LocalFileSystem local("local");
WiredHome 0:a4887b672ac6 49 INI ini;
WiredHome 0:a4887b672ac6 50
WiredHome 0:a4887b672ac6 51 DigitalOut linkup(p26);
WiredHome 0:a4887b672ac6 52 DigitalOut linkdata(p25);
WiredHome 0:a4887b672ac6 53
WiredHome 0:a4887b672ac6 54 TimeInterface ntp;
WiredHome 0:a4887b672ac6 55 HTTPClient http;
WiredHome 0:a4887b672ac6 56
WiredHome 0:a4887b672ac6 57 // Keep a sample every 5 s for 5 minutes
WiredHome 0:a4887b672ac6 58 // 12 samples / min * 5 min => 60 samples
WiredHome 0:a4887b672ac6 59 #define SampleInterval_Sec 5
WiredHome 0:a4887b672ac6 60 #define SampleHistory_5m (60)
WiredHome 0:a4887b672ac6 61 StatisticQueue stats5s(SampleHistory_5m);
WiredHome 0:a4887b672ac6 62
WiredHome 0:a4887b672ac6 63 // Keep 5 minute data for 1 day
WiredHome 0:a4887b672ac6 64 // 12 samples / hour * 24 hours => 288
WiredHome 0:a4887b672ac6 65 #define SampleInterval_Min 5
WiredHome 0:a4887b672ac6 66 #define SampleHistory_1d 288
WiredHome 0:a4887b672ac6 67 StatisticQueue stats5m(SampleHistory_1d);
WiredHome 0:a4887b672ac6 68
WiredHome 0:a4887b672ac6 69 const char * PROG_INFO = "Watt Eye: " __DATE__ ", " __TIME__;
WiredHome 0:a4887b672ac6 70 const char * iniFile = "/local/WattEye.ini";
WiredHome 0:a4887b672ac6 71
WiredHome 0:a4887b672ac6 72
WiredHome 0:a4887b672ac6 73 DigitalOut PulseIndicator(LED1);
WiredHome 0:a4887b672ac6 74 DigitalOut UDPSendIndicator(LED2);
WiredHome 0:a4887b672ac6 75 DigitalOut URLSendIndicator(LED3);
WiredHome 0:a4887b672ac6 76 PwmOut signOfLife(LED4);
WiredHome 0:a4887b672ac6 77
WiredHome 0:a4887b672ac6 78 InterruptIn event(p15);
WiredHome 0:a4887b672ac6 79 Timer timer;
WiredHome 0:a4887b672ac6 80 Timeout flash;
WiredHome 0:a4887b672ac6 81
WiredHome 0:a4887b672ac6 82 typedef struct
WiredHome 0:a4887b672ac6 83 {
WiredHome 0:a4887b672ac6 84 time_t todClock;
WiredHome 0:a4887b672ac6 85 uint32_t tLastStart;
WiredHome 0:a4887b672ac6 86 uint32_t tLastRise;
WiredHome 0:a4887b672ac6 87 uint16_t Samples10s[30]; // Every 10s for 5 min
WiredHome 0:a4887b672ac6 88 uint16_t Samples10sIndex;
WiredHome 0:a4887b672ac6 89 uint16_t Samples5m[12*24]; // Every 5m for 1 day
WiredHome 0:a4887b672ac6 90 uint16_t Samples5mIndex;
WiredHome 0:a4887b672ac6 91 uint16_t Samples1d[365]; // Every
WiredHome 0:a4887b672ac6 92 uint16_t Samples1dIndex;
WiredHome 0:a4887b672ac6 93 } WattData;
WiredHome 0:a4887b672ac6 94
WiredHome 0:a4887b672ac6 95 typedef struct
WiredHome 0:a4887b672ac6 96 {
WiredHome 0:a4887b672ac6 97 float instantKW;
WiredHome 0:a4887b672ac6 98 float averageKW;
WiredHome 0:a4887b672ac6 99 uint32_t measuredCycles;
WiredHome 0:a4887b672ac6 100 } Atomic_t;
WiredHome 0:a4887b672ac6 101
WiredHome 0:a4887b672ac6 102 Atomic_t PowerSnapshot;
WiredHome 0:a4887b672ac6 103
WiredHome 0:a4887b672ac6 104 typedef struct
WiredHome 0:a4887b672ac6 105 {
WiredHome 0:a4887b672ac6 106 bool init;
WiredHome 0:a4887b672ac6 107 time_t startTimestamp;
WiredHome 0:a4887b672ac6 108 uint64_t tStart;
WiredHome 0:a4887b672ac6 109 uint64_t tLastRise;
WiredHome 0:a4887b672ac6 110 uint64_t tStartSample;
WiredHome 0:a4887b672ac6 111 uint32_t cycles;
WiredHome 0:a4887b672ac6 112 } RawSample_t;
WiredHome 0:a4887b672ac6 113
WiredHome 0:a4887b672ac6 114 RawSample_t RawPowerSample;
WiredHome 0:a4887b672ac6 115
WiredHome 0:a4887b672ac6 116 //uint64_t tElapsedFive;
WiredHome 0:a4887b672ac6 117 //uint32_t cycleFive;
WiredHome 0:a4887b672ac6 118
WiredHome 0:a4887b672ac6 119
WiredHome 0:a4887b672ac6 120
WiredHome 0:a4887b672ac6 121 void SoftwareUpdateCheck(bool force = false)
WiredHome 0:a4887b672ac6 122 {
WiredHome 0:a4887b672ac6 123 static time_t tLastCheck;
WiredHome 0:a4887b672ac6 124 char url[100], name[10];
WiredHome 0:a4887b672ac6 125 time_t tCheck = ntp.time();
WiredHome 0:a4887b672ac6 126
WiredHome 0:a4887b672ac6 127 if (tCheck < tLastCheck)
WiredHome 0:a4887b672ac6 128 force = true; // guard against bad stuff that would prevent updates
WiredHome 0:a4887b672ac6 129
WiredHome 0:a4887b672ac6 130 if ((tCheck - tLastCheck > TIME_TO_CHECK_SW_UPDATE) || force) {
WiredHome 0:a4887b672ac6 131 tLastCheck = tCheck;
WiredHome 0:a4887b672ac6 132 eth_mutex.lock();
WiredHome 0:a4887b672ac6 133 pc.printf("SoftwareUpdateCheck\r\n");
WiredHome 0:a4887b672ac6 134 if (ini.ReadString("SWUpdate", "url", url, sizeof(url))
WiredHome 0:a4887b672ac6 135 && ini.ReadString("SWUpdate", "name", name, sizeof(name))) {
WiredHome 0:a4887b672ac6 136 //pc.printf("SW Check(%s,%s)\r\n", url, name);
WiredHome 0:a4887b672ac6 137 SWUpdate_T su = SoftwareUpdate(url, name, DEFER_REBOOT);
WiredHome 0:a4887b672ac6 138 if (SWUP_OK == su) {
WiredHome 0:a4887b672ac6 139 eth_mutex.unlock();
WiredHome 0:a4887b672ac6 140 pc.printf(" new software installed, restarting...\r\n");
WiredHome 0:a4887b672ac6 141 Thread::wait(3000);
WiredHome 0:a4887b672ac6 142 mbed_reset();
WiredHome 0:a4887b672ac6 143 } else if (SWUP_SAME_VER == su) {
WiredHome 0:a4887b672ac6 144 pc.printf(" no update available.\r\n");
WiredHome 0:a4887b672ac6 145 } else {
WiredHome 0:a4887b672ac6 146 pc.printf(" update failed %04X, http %d\r\n", su, SoftwareUpdateGetHTTPErrorCode());
WiredHome 0:a4887b672ac6 147 }
WiredHome 0:a4887b672ac6 148 } else {
WiredHome 0:a4887b672ac6 149 pc.printf(" can't get info from ini file.\r\n");
WiredHome 0:a4887b672ac6 150 eth_mutex.unlock();
WiredHome 0:a4887b672ac6 151 }
WiredHome 0:a4887b672ac6 152 }
WiredHome 0:a4887b672ac6 153 }
WiredHome 0:a4887b672ac6 154
WiredHome 0:a4887b672ac6 155 void ShowIPAddress(bool show = true)
WiredHome 0:a4887b672ac6 156 {
WiredHome 0:a4887b672ac6 157 char buf[16];
WiredHome 0:a4887b672ac6 158
WiredHome 0:a4887b672ac6 159 if (show)
WiredHome 0:a4887b672ac6 160 sprintf(buf, "%15s", eth.getIPAddress());
WiredHome 0:a4887b672ac6 161 else
WiredHome 0:a4887b672ac6 162 sprintf(buf, "%15s", "---.---.---.---");
WiredHome 0:a4887b672ac6 163 pc.printf("Ethernet connected as %s\r\n", buf);
WiredHome 0:a4887b672ac6 164 }
WiredHome 0:a4887b672ac6 165
WiredHome 0:a4887b672ac6 166
WiredHome 0:a4887b672ac6 167
WiredHome 0:a4887b672ac6 168 bool SyncToNTPServer(void)
WiredHome 0:a4887b672ac6 169 {
WiredHome 0:a4887b672ac6 170 char url[100];
WiredHome 0:a4887b672ac6 171 char tzone[10];
WiredHome 0:a4887b672ac6 172
WiredHome 0:a4887b672ac6 173 if (ini.ReadString("Clock", "timeserver", url, sizeof(url))) {
WiredHome 0:a4887b672ac6 174 ini.ReadString("Clock", "tzoffsetmin", tzone, sizeof(tzone), "0");
WiredHome 0:a4887b672ac6 175
WiredHome 0:a4887b672ac6 176 time_t tls = ntp.get_timelastset();
WiredHome 0:a4887b672ac6 177 //time_t tnow = ntp.time();
WiredHome 0:a4887b672ac6 178 //int32_t tcr = ntp.get_cal();
WiredHome 0:a4887b672ac6 179 eth_mutex.lock();
WiredHome 0:a4887b672ac6 180 pc.printf("NTP update time from (%s)\r\n", url);
WiredHome 0:a4887b672ac6 181 linkdata = true;
WiredHome 0:a4887b672ac6 182 int32_t tzo_min = atoi(tzone);
WiredHome 0:a4887b672ac6 183 ntp.set_tzo_min(tzo_min);
WiredHome 0:a4887b672ac6 184 int res = ntp.setTime(url);
WiredHome 0:a4887b672ac6 185 eth_mutex.unlock();
WiredHome 0:a4887b672ac6 186 linkdata = false;
WiredHome 0:a4887b672ac6 187 if (res == 0) {
WiredHome 0:a4887b672ac6 188 time_t ctTime;
WiredHome 0:a4887b672ac6 189 ctTime = ntp.timelocal();
WiredHome 0:a4887b672ac6 190 pc.printf(" Time set to (UTC): %s\r\n", ntp.ctime(&ctTime));
WiredHome 0:a4887b672ac6 191 return true;
WiredHome 0:a4887b672ac6 192 } else {
WiredHome 0:a4887b672ac6 193 pc.printf("Error %d\r\n", res);
WiredHome 0:a4887b672ac6 194 }
WiredHome 0:a4887b672ac6 195 } else {
WiredHome 0:a4887b672ac6 196 pc.printf("no time server was set\r\n");
WiredHome 0:a4887b672ac6 197 }
WiredHome 0:a4887b672ac6 198 return false;
WiredHome 0:a4887b672ac6 199 }
WiredHome 0:a4887b672ac6 200
WiredHome 0:a4887b672ac6 201 void TransmitEnergy(bool sendNow, float iKW, float min5s, float avg5s, float max5s, float min5m, float avg5m, float max5m)
WiredHome 0:a4887b672ac6 202 {
WiredHome 0:a4887b672ac6 203 char url[100], dest[20], port[8];
WiredHome 0:a4887b672ac6 204 char data[150];
WiredHome 0:a4887b672ac6 205 char myID[50];
WiredHome 0:a4887b672ac6 206 char fullurl[250];
WiredHome 0:a4887b672ac6 207 bool bEU = ini.ReadString("Energy", "url", url, sizeof(url));
WiredHome 0:a4887b672ac6 208 bool bDS = ini.ReadString("Energy", "dest", dest, sizeof(dest));
WiredHome 0:a4887b672ac6 209 bool bPO = ini.ReadString("Energy", "port", port, sizeof(port));
WiredHome 0:a4887b672ac6 210 bool bID = ini.ReadString("Node", "id", myID, sizeof(myID));
WiredHome 0:a4887b672ac6 211
WiredHome 0:a4887b672ac6 212 if (bEU && bDS && bPO && bID) {
WiredHome 0:a4887b672ac6 213 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 0:a4887b672ac6 214 myID, iKW, min5s, avg5s, max5s, min5m, avg5m, max5m);
WiredHome 0:a4887b672ac6 215 eth_mutex.lock();
WiredHome 0:a4887b672ac6 216 // Send the UDP Broadcast, picked up by a listener
WiredHome 0:a4887b672ac6 217 UDPSendIndicator = true;
WiredHome 0:a4887b672ac6 218 UDPSocket bcast;
WiredHome 0:a4887b672ac6 219 Endpoint ep;
WiredHome 0:a4887b672ac6 220 int h = ep.set_address(dest, atoi(port));
WiredHome 0:a4887b672ac6 221 int i = bcast.bind(atoi(port));
WiredHome 0:a4887b672ac6 222 int j = bcast.set_broadcasting(true);
WiredHome 0:a4887b672ac6 223 int k = bcast.sendTo(ep, data, strlen(data));
WiredHome 0:a4887b672ac6 224 bcast.close();
WiredHome 0:a4887b672ac6 225 UDPSendIndicator = false;
WiredHome 0:a4887b672ac6 226 // On the 5-minute interval, post the data to a specified web server
WiredHome 0:a4887b672ac6 227 if (sendNow && *url) {
WiredHome 0:a4887b672ac6 228 //HTTPClient http;
WiredHome 0:a4887b672ac6 229 char buf[50];
WiredHome 0:a4887b672ac6 230 URLSendIndicator = true;
WiredHome 0:a4887b672ac6 231 snprintf(fullurl, 250, "%s?%s", url, data);
WiredHome 0:a4887b672ac6 232 pc.printf("Contacting %s\r\n", fullurl);
WiredHome 0:a4887b672ac6 233 http.setMaxRedirections(3);
WiredHome 0:a4887b672ac6 234 int x = http.get(fullurl, buf, sizeof(buf));
WiredHome 0:a4887b672ac6 235 URLSendIndicator = false;
WiredHome 0:a4887b672ac6 236 pc.printf(" return: %d\r\n", x);
WiredHome 0:a4887b672ac6 237 }
WiredHome 0:a4887b672ac6 238 eth_mutex.unlock();
WiredHome 0:a4887b672ac6 239 }
WiredHome 0:a4887b672ac6 240 }
WiredHome 0:a4887b672ac6 241
WiredHome 0:a4887b672ac6 242
WiredHome 0:a4887b672ac6 243 /// ShowSignOfLife
WiredHome 0:a4887b672ac6 244 ///
WiredHome 0:a4887b672ac6 245 /// Pulse an LED to indicate a sign of life of the program.
WiredHome 0:a4887b672ac6 246 /// This also has some moderate entertainment value.
WiredHome 0:a4887b672ac6 247 ///
WiredHome 0:a4887b672ac6 248 void ShowSignOfLife()
WiredHome 0:a4887b672ac6 249 {
WiredHome 0:a4887b672ac6 250 #define PI 3.14159265359
WiredHome 0:a4887b672ac6 251 static Timer activityTimer;
WiredHome 0:a4887b672ac6 252 static unsigned int activityStart;
WiredHome 0:a4887b672ac6 253 static bool init;
WiredHome 0:a4887b672ac6 254 static int degrees = 0;
WiredHome 0:a4887b672ac6 255 float v;
WiredHome 0:a4887b672ac6 256
WiredHome 0:a4887b672ac6 257 if (!init) {
WiredHome 0:a4887b672ac6 258 activityTimer.start();
WiredHome 0:a4887b672ac6 259 activityStart = (unsigned int) activityTimer.read_ms();
WiredHome 0:a4887b672ac6 260 init = true;
WiredHome 0:a4887b672ac6 261 }
WiredHome 0:a4887b672ac6 262 if ((unsigned int)activityTimer.read_ms() - activityStart > 20) {
WiredHome 0:a4887b672ac6 263
WiredHome 0:a4887b672ac6 264 v = sin(degrees * PI / 180);
WiredHome 0:a4887b672ac6 265 if (v < 0)
WiredHome 0:a4887b672ac6 266 v = 0;
WiredHome 0:a4887b672ac6 267 signOfLife = v;
WiredHome 0:a4887b672ac6 268 degrees += 5;
WiredHome 0:a4887b672ac6 269 activityStart = (unsigned int) activityTimer.read_ms();
WiredHome 0:a4887b672ac6 270 }
WiredHome 0:a4887b672ac6 271 }
WiredHome 0:a4887b672ac6 272
WiredHome 0:a4887b672ac6 273 void LedOff(void)
WiredHome 0:a4887b672ac6 274 {
WiredHome 0:a4887b672ac6 275 PulseIndicator = 0;
WiredHome 0:a4887b672ac6 276 }
WiredHome 0:a4887b672ac6 277
WiredHome 0:a4887b672ac6 278 void CheckConsoleInput(void)
WiredHome 0:a4887b672ac6 279 {
WiredHome 0:a4887b672ac6 280 if (pc.readable()) {
WiredHome 0:a4887b672ac6 281 int c = pc.getc();
WiredHome 0:a4887b672ac6 282 switch (c) {
WiredHome 0:a4887b672ac6 283 case 'r':
WiredHome 0:a4887b672ac6 284 mbed_reset();
WiredHome 0:a4887b672ac6 285 break;
WiredHome 0:a4887b672ac6 286 case 's':
WiredHome 0:a4887b672ac6 287 SoftwareUpdateCheck(true);
WiredHome 0:a4887b672ac6 288 break;
WiredHome 0:a4887b672ac6 289 case 't':
WiredHome 0:a4887b672ac6 290 SyncToNTPServer();
WiredHome 0:a4887b672ac6 291 break;
WiredHome 0:a4887b672ac6 292 default:
WiredHome 0:a4887b672ac6 293 pc.printf("unknown command '%c'\r\n", c);
WiredHome 0:a4887b672ac6 294 pc.printf("Commands:\r\n"
WiredHome 0:a4887b672ac6 295 " r = reset\r\n"
WiredHome 0:a4887b672ac6 296 " s = software update check\r\n"
WiredHome 0:a4887b672ac6 297 " t = time sync to NTP server\r\n"
WiredHome 0:a4887b672ac6 298 );
WiredHome 0:a4887b672ac6 299 ShowIPAddress();
WiredHome 0:a4887b672ac6 300
WiredHome 0:a4887b672ac6 301 break;
WiredHome 0:a4887b672ac6 302 }
WiredHome 0:a4887b672ac6 303 }
WiredHome 0:a4887b672ac6 304 }
WiredHome 0:a4887b672ac6 305
WiredHome 0:a4887b672ac6 306 bool NetworkIsConnected(void)
WiredHome 0:a4887b672ac6 307 {
WiredHome 0:a4887b672ac6 308 #ifdef WIFLY
WiredHome 0:a4887b672ac6 309 return eth.is_connected();
WiredHome 0:a4887b672ac6 310 #else
WiredHome 0:a4887b672ac6 311 return get_link_status();
WiredHome 0:a4887b672ac6 312 #endif
WiredHome 0:a4887b672ac6 313 }
WiredHome 0:a4887b672ac6 314
WiredHome 0:a4887b672ac6 315 void PulseRisingISR(void)
WiredHome 0:a4887b672ac6 316 {
WiredHome 0:a4887b672ac6 317 uint64_t tNow = timer.read_us();
WiredHome 0:a4887b672ac6 318
WiredHome 0:a4887b672ac6 319 __disable_irq();
WiredHome 0:a4887b672ac6 320 if (!RawPowerSample.init) {
WiredHome 0:a4887b672ac6 321 RawPowerSample.init = true;
WiredHome 0:a4887b672ac6 322 RawPowerSample.cycles = (uint32_t)-1;
WiredHome 0:a4887b672ac6 323 RawPowerSample.tStart = tNow;
WiredHome 0:a4887b672ac6 324 RawPowerSample.tLastRise = tNow;
WiredHome 0:a4887b672ac6 325 RawPowerSample.startTimestamp = ntp.time();
WiredHome 0:a4887b672ac6 326 }
WiredHome 0:a4887b672ac6 327 RawPowerSample.cycles++;
WiredHome 0:a4887b672ac6 328 RawPowerSample.tStartSample = RawPowerSample.tLastRise;
WiredHome 0:a4887b672ac6 329 RawPowerSample.tLastRise = tNow;
WiredHome 0:a4887b672ac6 330 __enable_irq();
WiredHome 0:a4887b672ac6 331 PulseIndicator = 1;
WiredHome 0:a4887b672ac6 332 flash.attach_us(&LedOff, 25000);
WiredHome 0:a4887b672ac6 333 }
WiredHome 0:a4887b672ac6 334
WiredHome 0:a4887b672ac6 335 void RunPulseTask(void)
WiredHome 0:a4887b672ac6 336 {
WiredHome 0:a4887b672ac6 337 static time_t timeFor5s = 0;
WiredHome 0:a4887b672ac6 338 static time_t timeFor5m = 0;
WiredHome 0:a4887b672ac6 339 static uint32_t lastCount = 0;
WiredHome 0:a4887b672ac6 340 time_t timenow = ntp.time();
WiredHome 0:a4887b672ac6 341 float iKW = 0.0f;
WiredHome 0:a4887b672ac6 342 bool sendToWeb = false;
WiredHome 0:a4887b672ac6 343
WiredHome 0:a4887b672ac6 344 __disable_irq();
WiredHome 0:a4887b672ac6 345 uint32_t elapsed = RawPowerSample.tLastRise - RawPowerSample.tStartSample;
WiredHome 0:a4887b672ac6 346 uint32_t count = RawPowerSample.cycles;
WiredHome 0:a4887b672ac6 347 __enable_irq();
WiredHome 0:a4887b672ac6 348
WiredHome 0:a4887b672ac6 349 if (elapsed) {
WiredHome 0:a4887b672ac6 350 // instantaneous, from this exact sample
WiredHome 0:a4887b672ac6 351 iKW = (float)3600 * 1000 / elapsed;
WiredHome 0:a4887b672ac6 352 }
WiredHome 0:a4887b672ac6 353 if (timeFor5s == 0 || timenow < timeFor5s) // startup or if something goes really bad
WiredHome 0:a4887b672ac6 354 timeFor5s = timenow;
WiredHome 0:a4887b672ac6 355 if (timeFor5m == 0 || timenow < timeFor5m) // startup or if something goes really bad
WiredHome 0:a4887b672ac6 356 timeFor5m = timenow;
WiredHome 0:a4887b672ac6 357
WiredHome 0:a4887b672ac6 358 if ((timenow - timeFor5m) >= 60) { // 300) {
WiredHome 0:a4887b672ac6 359 pc.printf(" tnow: %d, t5m: %d\r\n", timenow, timeFor5m);
WiredHome 0:a4887b672ac6 360 sendToWeb = true;
WiredHome 0:a4887b672ac6 361 timeFor5m = timenow;
WiredHome 0:a4887b672ac6 362 stats5m.EnterItem(stats5s.Average());
WiredHome 0:a4887b672ac6 363 }
WiredHome 0:a4887b672ac6 364 if ((timenow - timeFor5s) >= 5) {
WiredHome 0:a4887b672ac6 365 timeFor5s = timenow;
WiredHome 0:a4887b672ac6 366 stats5s.EnterItem(iKW);
WiredHome 0:a4887b672ac6 367 TransmitEnergy(sendToWeb, iKW, stats5s.Min(), stats5s.Average(), stats5s.Max(),
WiredHome 0:a4887b672ac6 368 stats5m.Min(), stats5m.Average(), stats5m.Max());
WiredHome 0:a4887b672ac6 369 }
WiredHome 0:a4887b672ac6 370 if (count != lastCount) {
WiredHome 0:a4887b672ac6 371 lastCount = count;
WiredHome 0:a4887b672ac6 372 pc.printf("%8.3fs => %4.3f (%4.3f,%4.3f,%4.3f) iKW, (%4.3f,%4.3f,%4.3f) KW 5m\r\n",
WiredHome 0:a4887b672ac6 373 (float)elapsed/1000000,
WiredHome 0:a4887b672ac6 374 iKW,
WiredHome 0:a4887b672ac6 375 stats5s.Min(), stats5s.Average(), stats5s.Max(),
WiredHome 0:a4887b672ac6 376 stats5m.Min(), stats5m.Average(), stats5m.Max());
WiredHome 0:a4887b672ac6 377 }
WiredHome 0:a4887b672ac6 378 }
WiredHome 0:a4887b672ac6 379
WiredHome 0:a4887b672ac6 380 /// SimplyDynamicPage1
WiredHome 0:a4887b672ac6 381 ///
WiredHome 0:a4887b672ac6 382 /// This web page is generated dynamically as a kind of "bare minimum".
WiredHome 0:a4887b672ac6 383 /// It doesn't do much.
WiredHome 0:a4887b672ac6 384 ///
WiredHome 0:a4887b672ac6 385 /// You can see in main how this page was registered.
WiredHome 0:a4887b672ac6 386 ///
WiredHome 0:a4887b672ac6 387 HTTPServer::CallBackResults SuperSimpleDynamicPage(HTTPServer *svr, HTTPServer::CallBackType type,
WiredHome 0:a4887b672ac6 388 const char * path, const HTTPServer::namevalue *params, int paramcount)
WiredHome 0:a4887b672ac6 389 {
WiredHome 0:a4887b672ac6 390 HTTPServer::CallBackResults ret = HTTPServer::ACCEPT_ERROR;
WiredHome 0:a4887b672ac6 391 char contentlen[30];
WiredHome 0:a4887b672ac6 392 char buf[500];
WiredHome 0:a4887b672ac6 393 char linebuf[100];
WiredHome 0:a4887b672ac6 394
WiredHome 0:a4887b672ac6 395 switch (type) {
WiredHome 0:a4887b672ac6 396 case HTTPServer::SEND_PAGE:
WiredHome 0:a4887b672ac6 397 // This sample drops it all into a local buffer, computes the length,
WiredHome 0:a4887b672ac6 398 // and passes that along as well. This can help the other end with efficiency.
WiredHome 0:a4887b672ac6 399 strcpy(buf, "<html><head><title>Smart WattEye/title></head>\r\n");
WiredHome 0:a4887b672ac6 400 strcat(buf, "<body>\r\n");
WiredHome 0:a4887b672ac6 401 strcat(buf, "<h1>Smart WattEye</h1>\r\n");
WiredHome 0:a4887b672ac6 402 strcat(buf, "<table>");
WiredHome 0:a4887b672ac6 403 snprintf(linebuf, sizeof(linebuf), "<tr><td>Instantaneous</td><td align='right'>%5.3f.</td></tr>\r\n",
WiredHome 0:a4887b672ac6 404 PowerSnapshot.instantKW);
WiredHome 0:a4887b672ac6 405 strcat(buf, linebuf);
WiredHome 0:a4887b672ac6 406 snprintf(linebuf, sizeof(linebuf), "<tr><td>Average</td><td align='right'>%5.3f</td></tr>\r\n",
WiredHome 0:a4887b672ac6 407 PowerSnapshot.averageKW);
WiredHome 0:a4887b672ac6 408 strcat(buf, linebuf);
WiredHome 0:a4887b672ac6 409 snprintf(linebuf, sizeof(linebuf), "<tr><td>Total Cycles</td><td align='right'>%10u</td></tr>\r\n",
WiredHome 0:a4887b672ac6 410 PowerSnapshot.measuredCycles);
WiredHome 0:a4887b672ac6 411 strcat(buf, linebuf);
WiredHome 0:a4887b672ac6 412 strcat(buf, "</table>");
WiredHome 0:a4887b672ac6 413 strcat(buf, "<a href='/'>back to main</a></body></html>\r\n");
WiredHome 0:a4887b672ac6 414 sprintf(contentlen, "Content-Length: %d\r\n", strlen(buf));
WiredHome 0:a4887b672ac6 415 // Now the actual header response
WiredHome 0:a4887b672ac6 416 svr->header(200, "OK", "Content-Type: text/html\r\n", contentlen);
WiredHome 0:a4887b672ac6 417 // and data are sent
WiredHome 0:a4887b672ac6 418 svr->send(buf);
WiredHome 0:a4887b672ac6 419 ret = HTTPServer::ACCEPT_COMPLETE;
WiredHome 0:a4887b672ac6 420 break;
WiredHome 0:a4887b672ac6 421 case HTTPServer::CONTENT_LENGTH_REQUEST:
WiredHome 0:a4887b672ac6 422 ret = HTTPServer::ACCEPT_COMPLETE;
WiredHome 0:a4887b672ac6 423 break;
WiredHome 0:a4887b672ac6 424 case HTTPServer::DATA_TRANSFER:
WiredHome 0:a4887b672ac6 425 ret = HTTPServer::ACCEPT_COMPLETE;
WiredHome 0:a4887b672ac6 426 break;
WiredHome 0:a4887b672ac6 427 default:
WiredHome 0:a4887b672ac6 428 ret = HTTPServer::ACCEPT_ERROR;
WiredHome 0:a4887b672ac6 429 break;
WiredHome 0:a4887b672ac6 430 }
WiredHome 0:a4887b672ac6 431 return ret;
WiredHome 0:a4887b672ac6 432 }
WiredHome 0:a4887b672ac6 433
WiredHome 0:a4887b672ac6 434
WiredHome 0:a4887b672ac6 435 int main()
WiredHome 0:a4887b672ac6 436 {
WiredHome 0:a4887b672ac6 437 bool SensorStarted = false;
WiredHome 0:a4887b672ac6 438 pc.baud(460800);
WiredHome 0:a4887b672ac6 439 pc.printf("\r\n%s\r\n", PROG_INFO);
WiredHome 0:a4887b672ac6 440
WiredHome 0:a4887b672ac6 441 if (wd.WatchdogCausedReset()) {
WiredHome 0:a4887b672ac6 442 pc.printf("**** Watchdog Event caused reset ****\r\n");
WiredHome 0:a4887b672ac6 443 }
WiredHome 0:a4887b672ac6 444 wd.Configure(30.0); // nothing should take more than 30 s we hope.
WiredHome 0:a4887b672ac6 445 ini.SetFile(iniFile);
WiredHome 0:a4887b672ac6 446 // Thread bcThread(Scheduler_thread, NULL, osPriorityHigh);
WiredHome 0:a4887b672ac6 447
WiredHome 0:a4887b672ac6 448 // Now let's instantiate the web server - along with a few settings:
WiredHome 0:a4887b672ac6 449 // the Wifly object, the port of interest (typically 80),
WiredHome 0:a4887b672ac6 450 // file system path to the static pages,
WiredHome 0:a4887b672ac6 451 // the maximum parameters per transaction (in the query string),
WiredHome 0:a4887b672ac6 452 // the maximum number of dynamic pages that can be registered,
WiredHome 0:a4887b672ac6 453 // the serial port back thru USB (for development/logging)
WiredHome 0:a4887b672ac6 454 //HTTPServer svr(NULL, 80, "/Local/", 15, 30, 10, &pc);
WiredHome 0:a4887b672ac6 455
WiredHome 0:a4887b672ac6 456 // But for even more fun, I'm registering a few dynamic pages
WiredHome 0:a4887b672ac6 457 // You see the handlers for in DynamicPages.cpp.
WiredHome 0:a4887b672ac6 458 // Here you can see the path to place on the URL.
WiredHome 0:a4887b672ac6 459 // ex. http://192.168.1.140/dyn
WiredHome 0:a4887b672ac6 460 //svr.RegisterHandler("/dyn", SuperSimpleDynamicPage);
WiredHome 0:a4887b672ac6 461
WiredHome 0:a4887b672ac6 462
WiredHome 0:a4887b672ac6 463 pc.printf("***\r\n");
WiredHome 0:a4887b672ac6 464 pc.printf("Initializing network interface...\r\n");
WiredHome 0:a4887b672ac6 465
WiredHome 0:a4887b672ac6 466 int res;
WiredHome 0:a4887b672ac6 467 char ip[20], mask[20], gw[20];
WiredHome 0:a4887b672ac6 468 bool bIP, bMask, bGW;
WiredHome 0:a4887b672ac6 469 bIP = ini.ReadString("Network", "addr", ip, 20, "");
WiredHome 0:a4887b672ac6 470 bMask = ini.ReadString("Network", "mask", mask, 20, "");
WiredHome 0:a4887b672ac6 471 bGW = ini.ReadString("Network", "gate", gw, 20, "");
WiredHome 0:a4887b672ac6 472
WiredHome 0:a4887b672ac6 473 if (bIP && bMask && bGW) {
WiredHome 0:a4887b672ac6 474 res = eth.init(ip,mask,gw);
WiredHome 0:a4887b672ac6 475 } else {
WiredHome 0:a4887b672ac6 476 res = eth.init();
WiredHome 0:a4887b672ac6 477 }
WiredHome 0:a4887b672ac6 478 if (0 == res) { // Interface set
WiredHome 0:a4887b672ac6 479 do {
WiredHome 0:a4887b672ac6 480 pc.printf("Connecting to network...\r\n");
WiredHome 0:a4887b672ac6 481 if (0 == eth.connect()) {
WiredHome 0:a4887b672ac6 482 linkup = true;
WiredHome 0:a4887b672ac6 483 ShowIPAddress(true);
WiredHome 0:a4887b672ac6 484 #ifdef WIFLY
WiredHome 0:a4887b672ac6 485 #else
WiredHome 0:a4887b672ac6 486 int speed = get_connection_speed();
WiredHome 0:a4887b672ac6 487 pc.printf("Connected at %d Mb/s\r\n", speed);
WiredHome 0:a4887b672ac6 488 #endif
WiredHome 0:a4887b672ac6 489 SoftwareUpdateCheck(true);
WiredHome 0:a4887b672ac6 490 SyncToNTPServer(); // we hope to have the right time of day now
WiredHome 0:a4887b672ac6 491 wait(5);
WiredHome 0:a4887b672ac6 492 if (!SensorStarted) {
WiredHome 0:a4887b672ac6 493 timer.start();
WiredHome 0:a4887b672ac6 494 timer.reset();
WiredHome 0:a4887b672ac6 495 event.rise(&PulseRisingISR);
WiredHome 0:a4887b672ac6 496 SensorStarted = true;
WiredHome 0:a4887b672ac6 497 }
WiredHome 0:a4887b672ac6 498 while (NetworkIsConnected()) {
WiredHome 0:a4887b672ac6 499 Thread::wait(5);
WiredHome 0:a4887b672ac6 500 linkdata = !linkdata;
WiredHome 0:a4887b672ac6 501 // Here's the real core of the main loop
WiredHome 0:a4887b672ac6 502 RunPulseTask();
WiredHome 0:a4887b672ac6 503 //svr.Poll();
WiredHome 0:a4887b672ac6 504 CheckConsoleInput();
WiredHome 0:a4887b672ac6 505 ShowSignOfLife();
WiredHome 0:a4887b672ac6 506 SoftwareUpdateCheck();
WiredHome 0:a4887b672ac6 507 wd.Service();
WiredHome 0:a4887b672ac6 508 }
WiredHome 0:a4887b672ac6 509 linkup = false;
WiredHome 0:a4887b672ac6 510 pc.printf("lost connection.\r\n");
WiredHome 0:a4887b672ac6 511 ShowIPAddress(false);
WiredHome 0:a4887b672ac6 512 eth.disconnect();
WiredHome 0:a4887b672ac6 513 }
WiredHome 0:a4887b672ac6 514 else {
WiredHome 0:a4887b672ac6 515 pc.printf(" ... failed to connect.\r\n");
WiredHome 0:a4887b672ac6 516 }
WiredHome 0:a4887b672ac6 517 CheckConsoleInput();
WiredHome 0:a4887b672ac6 518 }
WiredHome 0:a4887b672ac6 519 while (1);
WiredHome 0:a4887b672ac6 520 }
WiredHome 0:a4887b672ac6 521 else {
WiredHome 0:a4887b672ac6 522 pc.printf(" ... failed to initialize, rebooting...\r\n");
WiredHome 0:a4887b672ac6 523 mbed_reset();
WiredHome 0:a4887b672ac6 524 }
WiredHome 0:a4887b672ac6 525
WiredHome 0:a4887b672ac6 526 }