Web enabled thermostat demo using the Mission Cognition baseboard.

Dependencies:   NetServices mbed AvailableMemory

Committer:
jt
Date:
Mon Oct 03 21:45:56 2011 +0000
Revision:
0:2e82bfc9dc19
1.0

Who changed what in which revision?

UserRevisionLine numberNew contents of line
jt 0:2e82bfc9dc19 1 /*
jt 0:2e82bfc9dc19 2 Copyright (c) 2011 Jim Thomas, jt@missioncognition.net
jt 0:2e82bfc9dc19 3
jt 0:2e82bfc9dc19 4 Permission is hereby granted, free of charge, to any person obtaining a copy
jt 0:2e82bfc9dc19 5 of this software and associated documentation files (the "Software"), to deal
jt 0:2e82bfc9dc19 6 in the Software without restriction, including without limitation the rights
jt 0:2e82bfc9dc19 7 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
jt 0:2e82bfc9dc19 8 copies of the Software, and to permit persons to whom the Software is
jt 0:2e82bfc9dc19 9 furnished to do so, subject to the following conditions:
jt 0:2e82bfc9dc19 10
jt 0:2e82bfc9dc19 11 The above copyright notice and this permission notice shall be included in
jt 0:2e82bfc9dc19 12 all copies or substantial portions of the Software.
jt 0:2e82bfc9dc19 13
jt 0:2e82bfc9dc19 14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
jt 0:2e82bfc9dc19 15 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
jt 0:2e82bfc9dc19 16 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
jt 0:2e82bfc9dc19 17 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
jt 0:2e82bfc9dc19 18 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
jt 0:2e82bfc9dc19 19 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
jt 0:2e82bfc9dc19 20 THE SOFTWARE.
jt 0:2e82bfc9dc19 21 */
jt 0:2e82bfc9dc19 22
jt 0:2e82bfc9dc19 23 #include "mbed.h"
jt 0:2e82bfc9dc19 24 #include "SDHCFileSystem.h"
jt 0:2e82bfc9dc19 25 #include "EthernetNetIf.h"
jt 0:2e82bfc9dc19 26 #include "HTTPClient.h"
jt 0:2e82bfc9dc19 27 #include "NTPClient.h"
jt 0:2e82bfc9dc19 28 #include "HTTPServer.h"
jt 0:2e82bfc9dc19 29 #include "RPCFunction.h"
jt 0:2e82bfc9dc19 30 #include "RPCVariable.h"
jt 0:2e82bfc9dc19 31 #include "AvailableMemory.h"
jt 0:2e82bfc9dc19 32
jt 0:2e82bfc9dc19 33
jt 0:2e82bfc9dc19 34 #define HOSTNAME "mbedSE"
jt 0:2e82bfc9dc19 35 #define PORT 80
jt 0:2e82bfc9dc19 36
jt 0:2e82bfc9dc19 37 // Setup the SD card file system on the /sd path
jt 0:2e82bfc9dc19 38 SDFileSystem sd(p5, p6, p7, p8, "sd");
jt 0:2e82bfc9dc19 39
jt 0:2e82bfc9dc19 40 EthernetNetIf eth(HOSTNAME);
jt 0:2e82bfc9dc19 41 HTTPClient http;
jt 0:2e82bfc9dc19 42 NTPClient ntp;
jt 0:2e82bfc9dc19 43 HTTPServer svr;
jt 0:2e82bfc9dc19 44
jt 0:2e82bfc9dc19 45 // Setup an analog input
jt 0:2e82bfc9dc19 46 AnalogIn rawtemp(p15, "temp"); // "AIN1"
jt 0:2e82bfc9dc19 47
jt 0:2e82bfc9dc19 48 // Setup Relay outputs
jt 0:2e82bfc9dc19 49 DigitalOut relay1(p26, "relay1"); // "PWM1"
jt 0:2e82bfc9dc19 50 DigitalOut relay2(p25, "relay2"); // "PWM2"
jt 0:2e82bfc9dc19 51
jt 0:2e82bfc9dc19 52 // Setup some variables for a thermostat (degress F)
jt 0:2e82bfc9dc19 53 float stat_heat_setpoint = 68.0;
jt 0:2e82bfc9dc19 54 float stat_hysteresis = 1.0;
jt 0:2e82bfc9dc19 55 float stat_cool_setpoint = 74.0;
jt 0:2e82bfc9dc19 56 float stat_current_temp = 0.0; // Will be updated from the temp sensor reading
jt 0:2e82bfc9dc19 57
jt 0:2e82bfc9dc19 58 // Make the variables RPC accessible individually
jt 0:2e82bfc9dc19 59 RPCVariable<float> rpc_stat_heat_setpoint(&stat_heat_setpoint, "stat_heat_setpoint");
jt 0:2e82bfc9dc19 60 RPCVariable<float> rpc_stat_hysteresis(&stat_hysteresis, "stat_hysteresis");
jt 0:2e82bfc9dc19 61 RPCVariable<float> rpc_stat_cool_setpoint(&stat_cool_setpoint, "stat_cool_setpoint");
jt 0:2e82bfc9dc19 62 RPCVariable<float> rpc_stat_current_temp(&stat_current_temp, "stat_current_temp");
jt 0:2e82bfc9dc19 63
jt 0:2e82bfc9dc19 64 // Make the whole state readable all at once as a JSON dict
jt 0:2e82bfc9dc19 65 void DoGetThermostat(char * input, char* output);
jt 0:2e82bfc9dc19 66 RPCFunction GetThermostat(&DoGetThermostat, "GetThermostat");
jt 0:2e82bfc9dc19 67
jt 0:2e82bfc9dc19 68 void DoGetThermostat(char * input, char* output) {
jt 0:2e82bfc9dc19 69 // Input is ignored
jt 0:2e82bfc9dc19 70 printf("Thermostat: %0.1f %0.1f %0.1f %0.1f\n", stat_heat_setpoint, stat_hysteresis, stat_cool_setpoint, stat_current_temp);
jt 0:2e82bfc9dc19 71 printf("Relays: %d %d\n", relay1.read(), relay2.read());
jt 0:2e82bfc9dc19 72
jt 0:2e82bfc9dc19 73 sprintf(output, "{\"hs\":%0.1f,\"hy\":%0.1f,\"cs\":%0.1f,\"ct\":%0.1f,\"rh\":%d,\"rc\":%d}",
jt 0:2e82bfc9dc19 74 stat_heat_setpoint, stat_hysteresis, stat_cool_setpoint, stat_current_temp,
jt 0:2e82bfc9dc19 75 relay1.read(), relay2.read());
jt 0:2e82bfc9dc19 76 }
jt 0:2e82bfc9dc19 77
jt 0:2e82bfc9dc19 78 // Setup the status LED
jt 0:2e82bfc9dc19 79 DigitalOut led1(LED1, "led1");
jt 0:2e82bfc9dc19 80
jt 0:2e82bfc9dc19 81 int main() {
jt 0:2e82bfc9dc19 82 float aval;
jt 0:2e82bfc9dc19 83 float res;
jt 0:2e82bfc9dc19 84 int counter = 0;
jt 0:2e82bfc9dc19 85
jt 0:2e82bfc9dc19 86 EthernetErr ethErr;
jt 0:2e82bfc9dc19 87 int count = 0;
jt 0:2e82bfc9dc19 88 do {
jt 0:2e82bfc9dc19 89 printf("Setting up %d...\n", ++count);
jt 0:2e82bfc9dc19 90 ethErr = eth.setup();
jt 0:2e82bfc9dc19 91 if (ethErr) printf("Timeout\n", ethErr);
jt 0:2e82bfc9dc19 92 } while (ethErr != ETH_OK);
jt 0:2e82bfc9dc19 93
jt 0:2e82bfc9dc19 94 printf("Connected OK\n");
jt 0:2e82bfc9dc19 95 const char* hwAddr = eth.getHwAddr();
jt 0:2e82bfc9dc19 96 printf("HW address : %02x:%02x:%02x:%02x:%02x:%02x\n",
jt 0:2e82bfc9dc19 97 hwAddr[0], hwAddr[1], hwAddr[2],
jt 0:2e82bfc9dc19 98 hwAddr[3], hwAddr[4], hwAddr[5]);
jt 0:2e82bfc9dc19 99
jt 0:2e82bfc9dc19 100 IpAddr ethIp = eth.getIp();
jt 0:2e82bfc9dc19 101 printf("IP address : %d.%d.%d.%d\n", ethIp[0], ethIp[1], ethIp[2], ethIp[3]);
jt 0:2e82bfc9dc19 102 printf("Check router DHCP table for name : %s\n", eth.getHostname());
jt 0:2e82bfc9dc19 103
jt 0:2e82bfc9dc19 104 time_t ctTime;
jt 0:2e82bfc9dc19 105 ctTime = time(NULL);
jt 0:2e82bfc9dc19 106 printf("\nCurrent time is (UTC): %d %s\n", ctTime, ctime(&ctTime));
jt 0:2e82bfc9dc19 107 printf("NTP setTime...\n");
jt 0:2e82bfc9dc19 108 Host server(IpAddr(), 123, "pool.ntp.org");
jt 0:2e82bfc9dc19 109 printf("Result : %d\n", ntp.setTime(server));
jt 0:2e82bfc9dc19 110
jt 0:2e82bfc9dc19 111 ctTime = time(NULL);
jt 0:2e82bfc9dc19 112 printf("\nTime is now (UTC): %d %s\n", ctTime, ctime(&ctTime));
jt 0:2e82bfc9dc19 113
jt 0:2e82bfc9dc19 114 char ip[16];
jt 0:2e82bfc9dc19 115 sprintf(ip, "%d.%d.%d.%d", ethIp[0], ethIp[1], ethIp[2], ethIp[3]);
jt 0:2e82bfc9dc19 116
jt 0:2e82bfc9dc19 117 FSHandler::mount("/sd/www", "/"); //Mount uSD www path on web root path
jt 0:2e82bfc9dc19 118
jt 0:2e82bfc9dc19 119 svr.addHandler<RPCHandler>("/rpc"); // Enable RPC functionality under the /rpc path
jt 0:2e82bfc9dc19 120 svr.addHandler<FSHandler>("/"); // Add the file handler at the root
jt 0:2e82bfc9dc19 121
jt 0:2e82bfc9dc19 122 svr.bind(PORT);
jt 0:2e82bfc9dc19 123 printf("Server listening (port %d)\n", PORT);
jt 0:2e82bfc9dc19 124 printf("- LED1 flashes server heartbeat\n");
jt 0:2e82bfc9dc19 125 printf("- URL for RPC commands: %s/rpc \n", ip);
jt 0:2e82bfc9dc19 126
jt 0:2e82bfc9dc19 127 Timer tm;
jt 0:2e82bfc9dc19 128 tm.start();
jt 0:2e82bfc9dc19 129
jt 0:2e82bfc9dc19 130 while (true) {
jt 0:2e82bfc9dc19 131 Net::poll();
jt 0:2e82bfc9dc19 132 if (tm.read() > 0.5) {
jt 0:2e82bfc9dc19 133 tm.start();
jt 0:2e82bfc9dc19 134
jt 0:2e82bfc9dc19 135 if (counter % 128 == 0) printf("Available memory (exact bytes) : %d\n", AvailableMemory(1));
jt 0:2e82bfc9dc19 136
jt 0:2e82bfc9dc19 137 // Keep a loop counter
jt 0:2e82bfc9dc19 138 counter++;
jt 0:2e82bfc9dc19 139
jt 0:2e82bfc9dc19 140 // Toggle the LED
jt 0:2e82bfc9dc19 141 led1 = !led1;
jt 0:2e82bfc9dc19 142
jt 0:2e82bfc9dc19 143 // Read our rawtemp sensor and convert to degrees F
jt 0:2e82bfc9dc19 144 // ref http://www.seeedstudio.com/wiki/index.php?title=Project_Seven_-_rawtemp
jt 0:2e82bfc9dc19 145 // ref http://www.seeedstudio.com/wiki/index.php?title=GROVE_-_Starter_Bundle_V1.0b#rawtemp_Sensor_Twig
jt 0:2e82bfc9dc19 146 aval = rawtemp.read();
jt 0:2e82bfc9dc19 147 res = (10000.0 / aval) - 10000.0; // Reference resistor is 10k ohm
jt 0:2e82bfc9dc19 148 stat_current_temp = (1.0 / ((log(res / 10000.0) / 3975.0) + 1 / 298.15) - 273.15) * 9.0 / 5.0 + 32.0;
jt 0:2e82bfc9dc19 149
jt 0:2e82bfc9dc19 150 // Make sure that the setpoints don't cross
jt 0:2e82bfc9dc19 151 if (stat_cool_setpoint < stat_heat_setpoint + 2 * stat_hysteresis)
jt 0:2e82bfc9dc19 152 stat_cool_setpoint = stat_heat_setpoint + 2 * stat_hysteresis;
jt 0:2e82bfc9dc19 153
jt 0:2e82bfc9dc19 154 // Update relays once every 8 loops (~ 4 seconds)
jt 0:2e82bfc9dc19 155 // ref http://www.seeedstudio.com/wiki/index.php?title=Project_Five_%E2%80%93_Relay_Control
jt 0:2e82bfc9dc19 156 if (counter % 8 == 0) {
jt 0:2e82bfc9dc19 157 printf("Thermostat: %0.1f %0.1f %0.1f %0.1f\n", stat_heat_setpoint, stat_hysteresis, stat_cool_setpoint, stat_current_temp);
jt 0:2e82bfc9dc19 158
jt 0:2e82bfc9dc19 159 if ((stat_current_temp < stat_heat_setpoint - stat_hysteresis) && !relay1) {
jt 0:2e82bfc9dc19 160 relay1 = 1;
jt 0:2e82bfc9dc19 161 printf("Turning Relay 1 On\n");
jt 0:2e82bfc9dc19 162 }
jt 0:2e82bfc9dc19 163 if ((stat_current_temp > stat_heat_setpoint + stat_hysteresis) && relay1) {
jt 0:2e82bfc9dc19 164 relay1 = 0;
jt 0:2e82bfc9dc19 165 printf("Turning Relay 1 Off\n");
jt 0:2e82bfc9dc19 166 }
jt 0:2e82bfc9dc19 167 if ((stat_current_temp < stat_cool_setpoint - stat_hysteresis) && relay2) {
jt 0:2e82bfc9dc19 168 relay2 = 0;
jt 0:2e82bfc9dc19 169 printf("Turning Relay 2 Off\n");
jt 0:2e82bfc9dc19 170 }
jt 0:2e82bfc9dc19 171 if ((stat_current_temp > stat_cool_setpoint + stat_hysteresis) && !relay2) {
jt 0:2e82bfc9dc19 172 relay2 = 1;
jt 0:2e82bfc9dc19 173 printf("Turning Relay 2 On\n");
jt 0:2e82bfc9dc19 174 }
jt 0:2e82bfc9dc19 175 }
jt 0:2e82bfc9dc19 176 }
jt 0:2e82bfc9dc19 177 }
jt 0:2e82bfc9dc19 178 }