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:
Sun Jul 27 17:47:58 2014 +0000
Revision:
1:04ab0a3d07f1
Parent:
0:a4887b672ac6
Child:
2:649d91b93824
Minor adjustment to scheduling of the web transaction.

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 1:04ab0a3d07f1 294 case ' ':
WiredHome 1:04ab0a3d07f1 295 case '\r':
WiredHome 1:04ab0a3d07f1 296 case '\n':
WiredHome 0:a4887b672ac6 297 pc.printf("Commands:\r\n"
WiredHome 0:a4887b672ac6 298 " r = reset\r\n"
WiredHome 0:a4887b672ac6 299 " s = software update check\r\n"
WiredHome 0:a4887b672ac6 300 " t = time sync to NTP server\r\n"
WiredHome 0:a4887b672ac6 301 );
WiredHome 0:a4887b672ac6 302 ShowIPAddress();
WiredHome 0:a4887b672ac6 303
WiredHome 0:a4887b672ac6 304 break;
WiredHome 0:a4887b672ac6 305 }
WiredHome 0:a4887b672ac6 306 }
WiredHome 0:a4887b672ac6 307 }
WiredHome 0:a4887b672ac6 308
WiredHome 0:a4887b672ac6 309 bool NetworkIsConnected(void)
WiredHome 0:a4887b672ac6 310 {
WiredHome 0:a4887b672ac6 311 #ifdef WIFLY
WiredHome 0:a4887b672ac6 312 return eth.is_connected();
WiredHome 0:a4887b672ac6 313 #else
WiredHome 0:a4887b672ac6 314 return get_link_status();
WiredHome 0:a4887b672ac6 315 #endif
WiredHome 0:a4887b672ac6 316 }
WiredHome 0:a4887b672ac6 317
WiredHome 0:a4887b672ac6 318 void PulseRisingISR(void)
WiredHome 0:a4887b672ac6 319 {
WiredHome 0:a4887b672ac6 320 uint64_t tNow = timer.read_us();
WiredHome 0:a4887b672ac6 321
WiredHome 0:a4887b672ac6 322 __disable_irq();
WiredHome 0:a4887b672ac6 323 if (!RawPowerSample.init) {
WiredHome 0:a4887b672ac6 324 RawPowerSample.init = true;
WiredHome 0:a4887b672ac6 325 RawPowerSample.cycles = (uint32_t)-1;
WiredHome 0:a4887b672ac6 326 RawPowerSample.tStart = tNow;
WiredHome 0:a4887b672ac6 327 RawPowerSample.tLastRise = tNow;
WiredHome 0:a4887b672ac6 328 RawPowerSample.startTimestamp = ntp.time();
WiredHome 0:a4887b672ac6 329 }
WiredHome 0:a4887b672ac6 330 RawPowerSample.cycles++;
WiredHome 0:a4887b672ac6 331 RawPowerSample.tStartSample = RawPowerSample.tLastRise;
WiredHome 0:a4887b672ac6 332 RawPowerSample.tLastRise = tNow;
WiredHome 0:a4887b672ac6 333 __enable_irq();
WiredHome 0:a4887b672ac6 334 PulseIndicator = 1;
WiredHome 0:a4887b672ac6 335 flash.attach_us(&LedOff, 25000);
WiredHome 0:a4887b672ac6 336 }
WiredHome 0:a4887b672ac6 337
WiredHome 0:a4887b672ac6 338 void RunPulseTask(void)
WiredHome 0:a4887b672ac6 339 {
WiredHome 0:a4887b672ac6 340 static time_t timeFor5s = 0;
WiredHome 0:a4887b672ac6 341 static time_t timeFor5m = 0;
WiredHome 0:a4887b672ac6 342 static uint32_t lastCount = 0;
WiredHome 0:a4887b672ac6 343 time_t timenow = ntp.time();
WiredHome 0:a4887b672ac6 344 float iKW = 0.0f;
WiredHome 0:a4887b672ac6 345 bool sendToWeb = false;
WiredHome 0:a4887b672ac6 346
WiredHome 0:a4887b672ac6 347 __disable_irq();
WiredHome 0:a4887b672ac6 348 uint32_t elapsed = RawPowerSample.tLastRise - RawPowerSample.tStartSample;
WiredHome 0:a4887b672ac6 349 uint32_t count = RawPowerSample.cycles;
WiredHome 0:a4887b672ac6 350 __enable_irq();
WiredHome 0:a4887b672ac6 351
WiredHome 0:a4887b672ac6 352 if (elapsed) {
WiredHome 0:a4887b672ac6 353 // instantaneous, from this exact sample
WiredHome 0:a4887b672ac6 354 iKW = (float)3600 * 1000 / elapsed;
WiredHome 0:a4887b672ac6 355 }
WiredHome 0:a4887b672ac6 356 if (timeFor5s == 0 || timenow < timeFor5s) // startup or if something goes really bad
WiredHome 0:a4887b672ac6 357 timeFor5s = timenow;
WiredHome 0:a4887b672ac6 358 if (timeFor5m == 0 || timenow < timeFor5m) // startup or if something goes really bad
WiredHome 0:a4887b672ac6 359 timeFor5m = timenow;
WiredHome 0:a4887b672ac6 360
WiredHome 0:a4887b672ac6 361 if ((timenow - timeFor5m) >= 60) { // 300) {
WiredHome 0:a4887b672ac6 362 pc.printf(" tnow: %d, t5m: %d\r\n", timenow, timeFor5m);
WiredHome 0:a4887b672ac6 363 sendToWeb = true;
WiredHome 1:04ab0a3d07f1 364 timeFor5s = timeFor5m = timenow;
WiredHome 1:04ab0a3d07f1 365 stats5s.EnterItem(iKW);
WiredHome 0:a4887b672ac6 366 stats5m.EnterItem(stats5s.Average());
WiredHome 1:04ab0a3d07f1 367 TransmitEnergy(true, iKW, stats5s.Min(), stats5s.Average(), stats5s.Max(),
WiredHome 1:04ab0a3d07f1 368 stats5m.Min(), stats5m.Average(), stats5m.Max());
WiredHome 1:04ab0a3d07f1 369 } else if ((timenow - timeFor5s) >= 5) {
WiredHome 0:a4887b672ac6 370 timeFor5s = timenow;
WiredHome 0:a4887b672ac6 371 stats5s.EnterItem(iKW);
WiredHome 1:04ab0a3d07f1 372 TransmitEnergy(false, iKW, stats5s.Min(), stats5s.Average(), stats5s.Max(),
WiredHome 0:a4887b672ac6 373 stats5m.Min(), stats5m.Average(), stats5m.Max());
WiredHome 0:a4887b672ac6 374 }
WiredHome 0:a4887b672ac6 375 if (count != lastCount) {
WiredHome 0:a4887b672ac6 376 lastCount = count;
WiredHome 0:a4887b672ac6 377 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 378 (float)elapsed/1000000,
WiredHome 0:a4887b672ac6 379 iKW,
WiredHome 0:a4887b672ac6 380 stats5s.Min(), stats5s.Average(), stats5s.Max(),
WiredHome 0:a4887b672ac6 381 stats5m.Min(), stats5m.Average(), stats5m.Max());
WiredHome 0:a4887b672ac6 382 }
WiredHome 0:a4887b672ac6 383 }
WiredHome 0:a4887b672ac6 384
WiredHome 0:a4887b672ac6 385 /// SimplyDynamicPage1
WiredHome 0:a4887b672ac6 386 ///
WiredHome 0:a4887b672ac6 387 /// This web page is generated dynamically as a kind of "bare minimum".
WiredHome 0:a4887b672ac6 388 /// It doesn't do much.
WiredHome 0:a4887b672ac6 389 ///
WiredHome 0:a4887b672ac6 390 /// You can see in main how this page was registered.
WiredHome 0:a4887b672ac6 391 ///
WiredHome 0:a4887b672ac6 392 HTTPServer::CallBackResults SuperSimpleDynamicPage(HTTPServer *svr, HTTPServer::CallBackType type,
WiredHome 0:a4887b672ac6 393 const char * path, const HTTPServer::namevalue *params, int paramcount)
WiredHome 0:a4887b672ac6 394 {
WiredHome 0:a4887b672ac6 395 HTTPServer::CallBackResults ret = HTTPServer::ACCEPT_ERROR;
WiredHome 0:a4887b672ac6 396 char contentlen[30];
WiredHome 0:a4887b672ac6 397 char buf[500];
WiredHome 0:a4887b672ac6 398 char linebuf[100];
WiredHome 0:a4887b672ac6 399
WiredHome 0:a4887b672ac6 400 switch (type) {
WiredHome 0:a4887b672ac6 401 case HTTPServer::SEND_PAGE:
WiredHome 0:a4887b672ac6 402 // This sample drops it all into a local buffer, computes the length,
WiredHome 0:a4887b672ac6 403 // and passes that along as well. This can help the other end with efficiency.
WiredHome 0:a4887b672ac6 404 strcpy(buf, "<html><head><title>Smart WattEye/title></head>\r\n");
WiredHome 0:a4887b672ac6 405 strcat(buf, "<body>\r\n");
WiredHome 0:a4887b672ac6 406 strcat(buf, "<h1>Smart WattEye</h1>\r\n");
WiredHome 0:a4887b672ac6 407 strcat(buf, "<table>");
WiredHome 0:a4887b672ac6 408 snprintf(linebuf, sizeof(linebuf), "<tr><td>Instantaneous</td><td align='right'>%5.3f.</td></tr>\r\n",
WiredHome 0:a4887b672ac6 409 PowerSnapshot.instantKW);
WiredHome 0:a4887b672ac6 410 strcat(buf, linebuf);
WiredHome 0:a4887b672ac6 411 snprintf(linebuf, sizeof(linebuf), "<tr><td>Average</td><td align='right'>%5.3f</td></tr>\r\n",
WiredHome 0:a4887b672ac6 412 PowerSnapshot.averageKW);
WiredHome 0:a4887b672ac6 413 strcat(buf, linebuf);
WiredHome 0:a4887b672ac6 414 snprintf(linebuf, sizeof(linebuf), "<tr><td>Total Cycles</td><td align='right'>%10u</td></tr>\r\n",
WiredHome 0:a4887b672ac6 415 PowerSnapshot.measuredCycles);
WiredHome 0:a4887b672ac6 416 strcat(buf, linebuf);
WiredHome 0:a4887b672ac6 417 strcat(buf, "</table>");
WiredHome 0:a4887b672ac6 418 strcat(buf, "<a href='/'>back to main</a></body></html>\r\n");
WiredHome 0:a4887b672ac6 419 sprintf(contentlen, "Content-Length: %d\r\n", strlen(buf));
WiredHome 0:a4887b672ac6 420 // Now the actual header response
WiredHome 0:a4887b672ac6 421 svr->header(200, "OK", "Content-Type: text/html\r\n", contentlen);
WiredHome 0:a4887b672ac6 422 // and data are sent
WiredHome 0:a4887b672ac6 423 svr->send(buf);
WiredHome 0:a4887b672ac6 424 ret = HTTPServer::ACCEPT_COMPLETE;
WiredHome 0:a4887b672ac6 425 break;
WiredHome 0:a4887b672ac6 426 case HTTPServer::CONTENT_LENGTH_REQUEST:
WiredHome 0:a4887b672ac6 427 ret = HTTPServer::ACCEPT_COMPLETE;
WiredHome 0:a4887b672ac6 428 break;
WiredHome 0:a4887b672ac6 429 case HTTPServer::DATA_TRANSFER:
WiredHome 0:a4887b672ac6 430 ret = HTTPServer::ACCEPT_COMPLETE;
WiredHome 0:a4887b672ac6 431 break;
WiredHome 0:a4887b672ac6 432 default:
WiredHome 0:a4887b672ac6 433 ret = HTTPServer::ACCEPT_ERROR;
WiredHome 0:a4887b672ac6 434 break;
WiredHome 0:a4887b672ac6 435 }
WiredHome 0:a4887b672ac6 436 return ret;
WiredHome 0:a4887b672ac6 437 }
WiredHome 0:a4887b672ac6 438
WiredHome 0:a4887b672ac6 439
WiredHome 0:a4887b672ac6 440 int main()
WiredHome 0:a4887b672ac6 441 {
WiredHome 0:a4887b672ac6 442 bool SensorStarted = false;
WiredHome 0:a4887b672ac6 443 pc.baud(460800);
WiredHome 0:a4887b672ac6 444 pc.printf("\r\n%s\r\n", PROG_INFO);
WiredHome 0:a4887b672ac6 445
WiredHome 0:a4887b672ac6 446 if (wd.WatchdogCausedReset()) {
WiredHome 0:a4887b672ac6 447 pc.printf("**** Watchdog Event caused reset ****\r\n");
WiredHome 0:a4887b672ac6 448 }
WiredHome 0:a4887b672ac6 449 wd.Configure(30.0); // nothing should take more than 30 s we hope.
WiredHome 0:a4887b672ac6 450 ini.SetFile(iniFile);
WiredHome 0:a4887b672ac6 451 // Thread bcThread(Scheduler_thread, NULL, osPriorityHigh);
WiredHome 0:a4887b672ac6 452
WiredHome 0:a4887b672ac6 453 // Now let's instantiate the web server - along with a few settings:
WiredHome 0:a4887b672ac6 454 // the Wifly object, the port of interest (typically 80),
WiredHome 0:a4887b672ac6 455 // file system path to the static pages,
WiredHome 0:a4887b672ac6 456 // the maximum parameters per transaction (in the query string),
WiredHome 0:a4887b672ac6 457 // the maximum number of dynamic pages that can be registered,
WiredHome 0:a4887b672ac6 458 // the serial port back thru USB (for development/logging)
WiredHome 0:a4887b672ac6 459 //HTTPServer svr(NULL, 80, "/Local/", 15, 30, 10, &pc);
WiredHome 0:a4887b672ac6 460
WiredHome 0:a4887b672ac6 461 // But for even more fun, I'm registering a few dynamic pages
WiredHome 0:a4887b672ac6 462 // You see the handlers for in DynamicPages.cpp.
WiredHome 0:a4887b672ac6 463 // Here you can see the path to place on the URL.
WiredHome 0:a4887b672ac6 464 // ex. http://192.168.1.140/dyn
WiredHome 0:a4887b672ac6 465 //svr.RegisterHandler("/dyn", SuperSimpleDynamicPage);
WiredHome 0:a4887b672ac6 466
WiredHome 0:a4887b672ac6 467
WiredHome 0:a4887b672ac6 468 pc.printf("***\r\n");
WiredHome 0:a4887b672ac6 469 pc.printf("Initializing network interface...\r\n");
WiredHome 0:a4887b672ac6 470
WiredHome 0:a4887b672ac6 471 int res;
WiredHome 0:a4887b672ac6 472 char ip[20], mask[20], gw[20];
WiredHome 0:a4887b672ac6 473 bool bIP, bMask, bGW;
WiredHome 0:a4887b672ac6 474 bIP = ini.ReadString("Network", "addr", ip, 20, "");
WiredHome 0:a4887b672ac6 475 bMask = ini.ReadString("Network", "mask", mask, 20, "");
WiredHome 0:a4887b672ac6 476 bGW = ini.ReadString("Network", "gate", gw, 20, "");
WiredHome 0:a4887b672ac6 477
WiredHome 0:a4887b672ac6 478 if (bIP && bMask && bGW) {
WiredHome 0:a4887b672ac6 479 res = eth.init(ip,mask,gw);
WiredHome 0:a4887b672ac6 480 } else {
WiredHome 0:a4887b672ac6 481 res = eth.init();
WiredHome 0:a4887b672ac6 482 }
WiredHome 0:a4887b672ac6 483 if (0 == res) { // Interface set
WiredHome 0:a4887b672ac6 484 do {
WiredHome 0:a4887b672ac6 485 pc.printf("Connecting to network...\r\n");
WiredHome 0:a4887b672ac6 486 if (0 == eth.connect()) {
WiredHome 0:a4887b672ac6 487 linkup = true;
WiredHome 0:a4887b672ac6 488 ShowIPAddress(true);
WiredHome 0:a4887b672ac6 489 #ifdef WIFLY
WiredHome 0:a4887b672ac6 490 #else
WiredHome 0:a4887b672ac6 491 int speed = get_connection_speed();
WiredHome 0:a4887b672ac6 492 pc.printf("Connected at %d Mb/s\r\n", speed);
WiredHome 0:a4887b672ac6 493 #endif
WiredHome 0:a4887b672ac6 494 SoftwareUpdateCheck(true);
WiredHome 0:a4887b672ac6 495 SyncToNTPServer(); // we hope to have the right time of day now
WiredHome 0:a4887b672ac6 496 wait(5);
WiredHome 0:a4887b672ac6 497 if (!SensorStarted) {
WiredHome 0:a4887b672ac6 498 timer.start();
WiredHome 0:a4887b672ac6 499 timer.reset();
WiredHome 0:a4887b672ac6 500 event.rise(&PulseRisingISR);
WiredHome 0:a4887b672ac6 501 SensorStarted = true;
WiredHome 0:a4887b672ac6 502 }
WiredHome 0:a4887b672ac6 503 while (NetworkIsConnected()) {
WiredHome 0:a4887b672ac6 504 Thread::wait(5);
WiredHome 0:a4887b672ac6 505 linkdata = !linkdata;
WiredHome 0:a4887b672ac6 506 // Here's the real core of the main loop
WiredHome 0:a4887b672ac6 507 RunPulseTask();
WiredHome 0:a4887b672ac6 508 //svr.Poll();
WiredHome 0:a4887b672ac6 509 CheckConsoleInput();
WiredHome 0:a4887b672ac6 510 ShowSignOfLife();
WiredHome 0:a4887b672ac6 511 SoftwareUpdateCheck();
WiredHome 0:a4887b672ac6 512 wd.Service();
WiredHome 0:a4887b672ac6 513 }
WiredHome 0:a4887b672ac6 514 linkup = false;
WiredHome 0:a4887b672ac6 515 pc.printf("lost connection.\r\n");
WiredHome 0:a4887b672ac6 516 ShowIPAddress(false);
WiredHome 0:a4887b672ac6 517 eth.disconnect();
WiredHome 0:a4887b672ac6 518 }
WiredHome 0:a4887b672ac6 519 else {
WiredHome 0:a4887b672ac6 520 pc.printf(" ... failed to connect.\r\n");
WiredHome 0:a4887b672ac6 521 }
WiredHome 0:a4887b672ac6 522 CheckConsoleInput();
WiredHome 0:a4887b672ac6 523 }
WiredHome 0:a4887b672ac6 524 while (1);
WiredHome 0:a4887b672ac6 525 }
WiredHome 0:a4887b672ac6 526 else {
WiredHome 0:a4887b672ac6 527 pc.printf(" ... failed to initialize, rebooting...\r\n");
WiredHome 0:a4887b672ac6 528 mbed_reset();
WiredHome 0:a4887b672ac6 529 }
WiredHome 0:a4887b672ac6 530
WiredHome 0:a4887b672ac6 531 }