Dreamforce Heroku Sample mbed application for the FRDM-K64F. This application uses SocketIO to connect and communicate with Heroku.
Dependencies: BufferedSerial C12832 EthernetInterface HTTPClient-SSL LM75B MMA7660 SocketIO-k64f WebSocketClient-ThermostatDemo mbed-rtos mbed picojson
Fork of df-2013-minihack-thermostat-complete by
Revision 0:26c48388f725, committed 2013-11-05
- Comitter:
- ansond
- Date:
- Tue Nov 05 21:31:01 2013 +0000
- Child:
- 1:3faa003ad6e6
- Commit message:
- initial checkin
Changed in this revision
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/C12832_lcd.lib Tue Nov 05 21:31:01 2013 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/dreschpe/code/C12832_lcd/#c9afe58d786a
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/EthernetInterface.lib Tue Nov 05 21:31:01 2013 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/mbed_official/code/EthernetInterface/#cba86db5ab96
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/HTTPClient.lib Tue Nov 05 21:31:01 2013 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/donatien/code/HTTPClient/#be61104f4e91
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/LM75B.lib Tue Nov 05 21:31:01 2013 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/chris/code/LM75B/#6a70c9303bbe
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/MMA7660.lib Tue Nov 05 21:31:01 2013 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/Sissors/code/MMA7660/#a8e20db7901e
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/README.txt Tue Nov 05 21:31:01 2013 +0000 @@ -0,0 +1,25 @@ +Instructions: + +1). Complete the “hands-on” exercises first + - Required to get setup with an mbed account and the compiler environment + +2). Import the “df-2013-minihack-thermostat” project into your mbed project workspace + - Be sure to add and make current the “mbed LPC1768” board as the current board + to compile to. You can modify the GPS coords and devie name in the same manner + that you did in the hands-on session - this will enable you to quickly and easily + identify your device on the map + +3). Examine Thermostat.cpp in your project + - In the top of the file, examine the Mini-hack challenge statement + - Follow those instructions to modify the code to create a way to write text from the + Heroku webservice + +A successful implementation will: + - Enable you to see your mbed device on the map + - Clicking on the device name (its a URL link) you should be able to go to the Devices + - page on the website and enter "text" for the message name followed by a text message + - after a brief delay, the text message should pop up briefly on the mbed device LCD + +References: + - Project Source: http://mbed.org/teams/MBED_DEMOS/code/df-2013-minihack-thermostat/ + - Completed Code: http://mbed.org/teams/MBED_DEMOS/code/df-2013-minihack-thermostat-complete/
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/SocketIO.lib Tue Nov 05 21:31:01 2013 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/ansond/code/SocketIO/#997b8c5d2d46
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Thermostat-BaseUtils.h Tue Nov 05 21:31:01 2013 +0000 @@ -0,0 +1,68 @@ +/* Thermostat-BaseUtils.h */ +/* Copyright (C) 2013 mbed.org, MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING + * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef THERMOSTAT_BASEUTILS_H_ +#define THERMOSTAT_BASEUTILS_H_ + +// AppBoard LCD Support +#include "C12832_lcd.h" +C12832_LCD lcd; + +// Serial Console Support (main.cpp) +extern Serial pc; + +// log messages to appropriate outputs +void Thermostat::logMessage(bool do_lcd) { + // print to LCD panel + if (do_lcd) { + lcd.cls(); + lcd.locate(0,0); + lcd.printf(this->m_display_message); + } + else { + // print to serial console + pc.printf(this->m_display_message); + pc.printf("\r\n"); + } + + // wait a bit so that the message can be read + wait(0.5); +} + +// display output +void Thermostat::display(const char *format, ...) { + memset(this->m_display_message,'\0',MAX_MESSAGE_LENGTH+1); + va_list args; + va_start(args, format); + vsprintf(this->m_display_message, format, args); + va_end(args); + this->logMessage(false); +} + +// display output +void Thermostat::display_lcd(const char *format, ...) { + memset(this->m_display_message,'\0',MAX_MESSAGE_LENGTH+1); + va_list args; + va_start(args, format); + vsprintf(this->m_display_message, format, args); + va_end(args); + this->logMessage(true); +} + +#endif // THERMOSTAT_BASEUTILS_H_
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Thermostat-LEDUtils.h Tue Nov 05 21:31:01 2013 +0000 @@ -0,0 +1,183 @@ +/* Thermostat-LEDUtils.h */ +/* Copyright (C) 2013 mbed.org, MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING + * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef THERMOSTAT_LEDUTILS_H_ +#define THERMOSTAT_LEDUTILS_H_ + +// LEDs to toggle with control messages +DigitalOut led1(LED1); +DigitalOut led2(LED2); +DigitalOut led3(LED3); +DigitalOut led4(LED4); + +// Joystick button (to create an error condition) +DigitalIn joystick_pressed(p14); +DigitalIn joystick(p15); + +// Pot 1 for dialing up and down the temperature +AnalogIn Pot1(p19); + +// Pot 2 for dialing up and down the battery level +AnalogIn Pot2(p20); + +// the led's are connected to vcc, so a PwmOut of 100% will shut off the led and 0% will let it shine +PwmOut r (p23); +PwmOut g (p24); +PwmOut b (p25); + +// get the int value of the joystick state +int Thermostat::getErrorState() { + if (this->m_error_state) + return 1; + else + return 0; +} + +// function to convert hue , saturation and value to RGB - then update the RGB LED +// see http://en.wikipedia.org/wiki/HSL_and_HSV +void Thermostat::updateRGBLED(float H, float S, float V) { + float f,h,p,q,t; + int i; + if( S == 0.0) { + r = 1.0 - V; // invert pwm ! + g = 1.0 - V; + b = 1.0 - V; + return; + } + if(H > 360.0) H = 0.0; // check values + if(S > 1.0) S = 1.0; + if(S < 0.0) S = 0.0; + if(V > 1.0) V = 1.0; + if(V < 0.0) V = 0.0; + h = H / 60.0; + i = (int) h; + f = h - i; + p = V * (1.0 - S); + q = V * (1.0 - (S * f)); + t = V * (1.0 - (S * (1.0 - f))); + + switch(i) { + case 0: + r = 1.0 - V; // invert pwm ! + g = 1.0 - t; + b = 1.0 - p; + break; + case 1: + r = 1.0 - q; + g = 1.0 - V; + b = 1.0 - p; + break; + case 2: + r = 1.0 - p; + g = 1.0 - V; + b = 1.0 - t; + break; + case 3: + r = 1.0 - p; + g = 1.0 - q; + b = 1.0 - V; + break; + case 4: + r = 1.0 - t; + g = 1.0 - p; + b = 1.0 - V; + break; + case 5: + default: + r = 1.0 - V; + g = 1.0 - p; + b = 1.0 - q; + break; + } +} + +// set all the LEDs +void Thermostat::setAllLEDs(int state) { + led1.write(state); + led2.write(state); + led3.write(state); + led4.write(state); +} + +// set all the LEDs +void Thermostat::resetAllLEDs() { + this->setAllLEDs(0); +} + +// set all the LEDs +void Thermostat::blinkAllLEDs() { + for(int i=0;i<4;++i) { + wait(1.0); + this->setAllLEDs(1); + this->display("Blinking on..."); + wait(1.0); + this->setAllLEDs(0); + this->display("Blinking off..."); + } +} + +// set the RGB LED color and brightness +void Thermostat::setRGBLED(double color, double bright) { + // set the RGB LED value + this->updateRGBLED(color,1.0,bright); +} + +// turn the RGB LED Red +void Thermostat::turnRGBLEDRed() { + this->m_rgbLEDColor = 0.0; + this->m_rgbLEDBright = 0.2; + this->setRGBLED(this->m_rgbLEDColor,this->m_rgbLEDBright); + this->m_error_state = true; +} + +// turn the RGB LED Green +void Thermostat::turnRGBLEDGreen() { + this->m_rgbLEDColor = 120.0; + this->m_rgbLEDBright = 0.2; + this->setRGBLED(this->m_rgbLEDColor,this->m_rgbLEDBright); + this->m_error_state = false; +} + +// turn the RGB LED Blue (initializing state) +void Thermostat::turnRGBLEDBlue() { + this->m_rgbLEDColor = 200.0; + this->m_rgbLEDBright = 0.2; + this->setRGBLED(this->m_rgbLEDColor,this->m_rgbLEDBright); + this->m_error_state = false; +} + +// blink an LED +void Thermostat::blinkLED(DigitalOut led) { + led = 1; + wait(0.2); + led = 0; +} + +// blink the Transport TX LED +void Thermostat::blinkTransportTxLED() { + this->blinkLED(led1); +} + +// blink the Transport RX LED +void Thermostat::blinkTransportRxLED() { + this->blinkLED(led2); +} + + +#endif // THERMOSTAT_LEDUTILS_H_ \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Thermostat-Location.h Tue Nov 05 21:31:01 2013 +0000 @@ -0,0 +1,36 @@ +/* Thermostat-Location.h */ +/* Copyright (C) 2013 mbed.org, MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING + * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef THERMOSTAT_LOCATION_H_ +#define THERMOSTAT_LOCATION_H_ + +// initialize our location +void Thermostat::initLocation() { +} + +// update our location coordinates +void Thermostat::updateCoordinates() { + this->m_latitude = DEFAULT_LATITUDE; + this->m_longitude = DEFAULT_LONGITUDE; + + this->display("Location: Latitude:%2.4f Longitude:%2.4f",this->m_latitude,this->m_longitude); + this->display_lcd("Location Coordinates\r\nLatitude: %2.4f\r\nLongitude: %2.4f",this->m_latitude,this->m_longitude); +} + +#endif // THERMOSTAT_LOCATION_H_ \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Thermostat.cpp Tue Nov 05 21:31:01 2013 +0000 @@ -0,0 +1,458 @@ +/* Thermostat.cpp */ +/* Copyright (C) 2013 mbed.org, MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING + * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +// +// 2013 DreamForce MiniHack - +// Look for the method: Thermostat::parseAndActOnControlMessage(char *json) +// From there, add code to look for a "text" message - send its contents to the LCD panel +// using the this->display(char *) method. You can use the other messages as a reference. +// + + /* + * Operation: with the MBED appboard - the following is available: + * 1. connect/disconnect: push and hold the joystick forward (towards potentiometer) until a connect/disconnect message is seen + * 2. control messages + * "led1" --> "on" or "off" (led1 is also used as the TX status...) + * "led2" --> "on" or "off" (led2 is also used as the RX status...) + * "led3" --> "on" or "off" + * "led4" --> "on" or "off" + * "blink" --> <dont care> should blink all 4 LEDs a few times + * "reset" --> <dont care> will reset the simulated error state for the device + * 3. simulated error state: depress and hold the joystick until the RGB LED turns red + * 4. rotate the potentiometer closest to the LCD panel to manipulate the battery level (0 - 100%) + * 5. rotate the potentiometer nearest the RGB LED to add/subtract 10 degrees from the current ambient temperature + */ + +// Primary include +#include "Thermostat.h" + +// DreamForce 2013 Tunables START + +// +// Our default Latitude and Longitude +// +#define DEFAULT_LATITUDE 37.7842 +#define DEFAULT_LONGITUDE -122.4016 + +// +// Name our endpoint something unique +// +#define DEFAULT_ENDPOINT_NAME "DreamForce Thermostat" + +// DreamForce 2013 Tunables END + +// Wait Loop default sleep per iteration +#define DEFAULT_MAIN_LOOP_WAIT 2.0 // 2 seconds + +// JSON parsing support +#include "picojson.h" + +// +// Accelerometer Support +// +#include "MMA7660.h" +MMA7660 acc(p28, p27); + +// +// Temperature Sensor Support +// +#include "LM75B.h" +LM75B temp_sensor(p28,p27); + +// +// Ethernet support +// +#include "EthernetInterface.h" +EthernetInterface ethernet; + +// +// Thermostat SocketIO Support +// +#include "ThermostatSocketIO.h" +ThermostatSocketIO socketio(DEFAULT_ENDPOINT_NAME); + +// Include LED Utils +#include "Thermostat-LEDUtils.h" + +// Include Base Utils +#include "Thermostat-BaseUtils.h" + +// Include Location Stubs +#include "Thermostat-Location.h" + +// Default constructor +Thermostat::Thermostat() { + this->m_temperature = 0.0; + this->m_battery = 50.0; + this->m_status = "OK"; +} + +// Destructor +Thermostat::~Thermostat() { + // close down connections + socketio.close(); + ethernet.disconnect(); + this->turnRGBLEDBlue(); +} + +// get the temp +float Thermostat::getTemperature() { + // get Pot 2 an additive/subtractive value to the ambient temp + float scale = Pot2.read(); + scale = scale * 20.0; // scale to 0 - 20 + scale = scale - 10.0; // scale -10 to +10 + + // Get the Temperature (in C) + float c = temp_sensor.read(); + float f = ((9/5) * c ) + 32; + + // now get the ambient temp and scale it + this->m_temperature = c + scale; + this->display("Temp %.1f C (%.1f F)",this->m_temperature,f); + this->display_lcd("Temp: %.1f C (%.1f F)",this->m_temperature,f); + + // return the temperature + return this->m_temperature; +} + +// get the current battery level +float Thermostat::getBatteryLevel() { + // get Pot 1 an additive/subtractive value to simulate battery level + this->m_battery = Pot1.read(); + this->m_battery = this->m_battery * 100.0; // scale to 0 - 100; + + // return the battery level + return this->m_battery; +} + +// receive from the heroku SocketIO web service +char *Thermostat::receiveFromWSService(char *buffer) { + bool success = socketio.read(buffer); + if (success == true) + this->display("SocketIO: Read success"); + else + this->display("SocketIO: Read failure"); + + return buffer; +} + +// translate the LED status +int Thermostat::translateLEDStatus(const char *status, int current) { + int i_status = current; + + if (status != NULL && strlen(status) > 0) { + if (strcmp(status,"on") == 0 || strcmp(status,"ON") == 0 || strcmp(status,"On") == 0 || strcmp(status,"1") == 0 || strcmp(status,"oN") == 0) + i_status = 1; + if (strcmp(status,"off") == 0 || strcmp(status,"OFF") == 0 || strcmp(status,"Off") == 0 || strcmp(status,"0") == 0 || strcmp(status,"oFF") == 0 || strcmp(status,"oF") == 0 || strcmp(status,"ofF") == 0) + i_status = 0; + } + + // return the status + return i_status; +} + +// reset the device status to OK +void Thermostat::resetDeviceStatus() { + this->turnRGBLEDGreen(); + this->m_status = "OK"; + socketio.resetMessageCounter(); + this->resetAllLEDs(); +} + +// basic parsing and processing of the control message +// +// Control Message Format: 5:::{"name":"control-device","args":[{"hello":"world"}]} +// +void Thermostat::parseAndActOnControlMessage(char *json) { + picojson::value v; + + if (json != NULL && strlen(json) > 0 && strstr(json,"{") != NULL) { + // move past the socket.io header + char *json_proper = strstr(json,"{"); + + // parse the packet + string err = picojson::parse(v, json_proper, json_proper + strlen(json_proper)); + + // the args value is an array of json values + picojson::array list = v.get("args").get<picojson::array>(); + + // loop through the array and parse/process each element + for (picojson::array::iterator iter = list.begin(); iter != list.end(); ++iter) { + // Toggle LEDs + if ((*iter).get("led1") != NULL) led1.write(this->translateLEDStatus((*iter).get("led1").get<string>().c_str(),(int)led1)); + if ((*iter).get("led2") != NULL) led2.write(this->translateLEDStatus((*iter).get("led2").get<string>().c_str(),(int)led2)); + if ((*iter).get("led3") != NULL) led3.write(this->translateLEDStatus((*iter).get("led3").get<string>().c_str(),(int)led3)); + if ((*iter).get("led4") != NULL) led4.write(this->translateLEDStatus((*iter).get("led4").get<string>().c_str(),(int)led4)); + if ((*iter).get("reset") != NULL) this->resetDeviceStatus(); + if ((*iter).get("text") != NULL) this->display((*iter).get("text").get<string>().c_str()); + if ((*iter).get("blink") != NULL) this->blinkAllLEDs(); + + // + // 2013 DreamForce MiniHack - add code to look for a "text" message - send its contents to the LCD panel + // using the this->display(char *) method + // + // Answer: + // + if ((*iter).get("text") != NULL) this->display((*iter).get("text").get<string>().c_str()); + } + } +} + +// recv and process a control message +void Thermostat::processControlMessage() { + + if (socketio.is_connected()) { + char message[SOCKETIO_MESSAGE_LENGTH]; + if (socketio.read(message)) { + // log the message + this->display("Received control message: %s",message); + + // process the message + this->parseAndActOnControlMessage(message); + + // blink the RX led + this->blinkTransportRxLED(); + } + else { + // no messages received - log + this->display("No control message received. OK"); + } + } +} + +// send status (no params) to the service +void Thermostat::sendStatus() { + // send the status + this->sendStatus(this->getTemperature(),this->getBatteryLevel()); +} + +// send status (temp & battery) to the service +void Thermostat::sendStatus(float temp, int bat) { + // incorporate location coordinates + this->sendStatus(temp,this->m_latitude,this->m_longitude,bat); +} + +// send status (temp, lat/long, battery) to the service +void Thermostat::sendStatus(float temp, float latitude, float longitude, float bat) { + // Announce + this->display("Send: status..."); + this->display_lcd("Sending status..."); + + // now send... + int sent = socketio.emit(temp,latitude,longitude,bat,this->getErrorState(),this->m_status); + + // Log + if (sent > 0) { + this->display("Send success. Ready..."); + this->display_lcd("Send status: OK.\r\nSleeping..."); + } + else { + this->display("Send Failed: sent=%d",sent); + this->display_lcd("Send status: FAILED.\r\nSleeping..."); + } + + // blink the TX led + this->blinkTransportTxLED(); +} + +// connect to the heroku WebService +bool Thermostat::connectWebSocketService() { + // Log + this->display("Connecting to SocketIO..."); + this->display_lcd("SocketIO connecting..."); + + // only connect if we are not already so + if (!socketio.is_connected()) socketio.connect(); + + // check connection status + bool connected = socketio.is_connected(); + + // log + if (connected == true) { + this->display("SocketIO: Connected!"); + this->display_lcd("SocketIO: Connected."); + } + else { + this->display("SocketIO: Not connected!"); + this->display_lcd("SocketIO: Connect FAILED."); + } + + // return the status + return connected; +} + +// Connect up Ethernet +bool Thermostat::connectEthernet() { + bool connected = false; + char *ipAddr = NULL; + + // Use DHCP + this->display("Initializing Ethernet..."); + this->display_lcd("Ethernet: Initializing..."); + ethernet.init(); + + // attempt connection + this->display("Connecting Ethernet..."); + this->display_lcd("Ethernet: Connecting..."); + if (ethernet.connect() == 0) connected = true; + + // check connection status + if (connected) { + ipAddr = ethernet.getIPAddress(); + if (ipAddr != NULL && strlen(ipAddr) > 0) + connected = true; + } + + // log + if (connected == true) { + this->display("Ethernet: Connected.\r\nIP: %s", ipAddr); + this->display_lcd("Ethernet: Connected\r\nIP: %s",ipAddr); + } + else { + this->display("Ethernet: Not connected"); + this->display_lcd("Ethernet: Connect FAILED."); + } + + // return the status + return connected; +} + +// gracefully de-register and close down the WS connection +void Thermostat::gracefullyDisconnect() { + // disconnect + if (socketio.is_connected()) socketio.close(); + + // announce + this->display("Disconnected."); + this->display_lcd("Disconnected."); + this->turnRGBLEDBlue(); + + // reset any status + this->m_status = "OK"; + socketio.resetMessageCounter(); +} + +// external function in main() to check for the CTRL-C key press to exit the application gracefully +extern void checkForExit(); + +// main loop +void Thermostat::mainLoop() { + // initialize our location + this->initLocation(); + + // begin the main loop + while(true) { + // sleep for a bit + checkForExit(); + wait(DEFAULT_MAIN_LOOP_WAIT); + + // announce our position + this->updateCoordinates(); + + // check and react to the joystick button press + if (joystick_pressed) { + if (this->m_rgbLEDColor > 1) { + this->turnRGBLEDRed(); + this->m_status = "FAIL"; + } + else { + this->turnRGBLEDGreen(); + this->m_status = "OK"; + } + } + else if (socketio.is_connected() && this->m_rgbLEDColor > 121) { + this->turnRGBLEDGreen(); + } + + // check the status of the joystick + if (joystick) { + if (socketio.is_connected()) { + // announce + this->display("Disconnecting..."); + this->display_lcd("Disconnecting..."); + + // disconnect + this->gracefullyDisconnect(); + } + else if (!socketio.is_connected()){ + // announce + this->display("Re-connecting..."); + this->display_lcd("Re-connecting..."); + + // re-connect + if (this->connectWebSocketService()) { + // announce + this->display("Reconnect success"); + this->display_lcd("Reconnect: SUCCESS"); + this->turnRGBLEDGreen(); + this->resetAllLEDs(); + } + else { + // announce + this->display("Reconnect failure"); + this->display_lcd("Reconnect: FAILED"); + this->gracefullyDisconnect(); + this->turnRGBLEDRed(); + } + } + } + + // if we are connected, send our status + if (socketio.is_connected()) { + // send status + this->sendStatus(); + checkForExit(); + } + + // if we are connected, read any control we may receive + if (socketio.is_connected()) { + // process control messages + this->processControlMessage(); + checkForExit(); + } + } +} + +// Run the Demo +void Thermostat::runDemo() { + // Announce + this->display("Thermostat Hands-On Demo v1.0"); + this->display_lcd("Thermostat Hands-On\r\nDemo v1.0"); + + // init the RGB LED + this->display("Initializing LEDs..."); + this->turnRGBLEDBlue(); + + // Log + this->display("Connecting..."); + this->display_lcd("Connecting..."); + + // connect and send the initial status + if (this->connectEthernet() == true && this->connectWebSocketService() == true) { + this->sendStatus(); + this->mainLoop(); + } + else { + this->display("Connection failure. Application exiting..."); + this->display_lcd("Connect: FAILURE.\r\nApplication Exiting"); + } + + // exit the application if we get here + exit(1); +} \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Thermostat.h Tue Nov 05 21:31:01 2013 +0000 @@ -0,0 +1,104 @@ +/* Thermostat.h */ +/* Copyright (C) 2013 mbed.org, MIT License + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of this software + * and associated documentation files (the "Software"), to deal in the Software without restriction, + * including without limitation the rights to use, copy, modify, merge, publish, distribute, + * sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all copies or + * substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING + * BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef THERMOSTAT_H_ +#define THERMOSTAT_H_ + +// platform support +#include "mbed.h" + +// Support for std args +#include <stdarg.h> + +// maximum size of a displayed message +#define MAX_MESSAGE_LENGTH 100 + +class Thermostat { + public: + // Default Constructor + Thermostat(); + + // Destructor + ~Thermostat(); + + // invoke the demo + void runDemo(); + + private: + int getErrorState(); + char *createDeregisterJSON(char *buffer); + char *createJSON(char *buffer, float temp, float latitude, float longitude, float bat); + + float getTemperature(); + float getBatteryLevel(); + + void resetDeviceStatus(); + int translateLEDStatus(const char *status, int current); + void parseAndActOnControlMessage(char *json); + void processControlMessage(); + void sendDeregisterMessage(); + void sendStatus(); + void sendStatus(float temp, int battery); + void sendStatus(float temp, float latitude, float longitude, float bat); + + char *receiveFromWSService(char *buffer); + + void parseSessionKey(char *response, char *sessionkey); + char *performSocketIOHandshake(char *sessionkey); + bool connectWebSocketService(); + bool connectEthernet(); + + void gracefullyDisconnect(); + void mainLoop(); + + // Thermostat-LEDUtils.cpp + void setAllLEDs(int state); + void resetAllLEDs(); + void blinkAllLEDs(); + void updateRGBLED(float H,float S, float V); + void setRGBLED(double color, double bright); + void turnRGBLEDRed(); + void turnRGBLEDGreen(); + void turnRGBLEDBlue(); + void blinkLED(DigitalOut led); + void blinkTransportTxLED(); + void blinkTransportRxLED(); + + // Thermostat-BaseUtils.cpp + void logMessage(bool do_lcd); + void display(const char *format, ...); + void display_lcd(const char *format, ...); + + // Stubs + void updateCoordinates(); + void initLocation(); + + // private members + float m_latitude; + float m_longitude; + float m_temperature; + float m_battery; + char *m_status; + bool m_error_state; + double m_rgbLEDColor; + double m_rgbLEDBright; + char m_display_message[MAX_MESSAGE_LENGTH+1]; +}; + +#endif /* THERMOSTAT_H_ */ \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ThermostatSocketIO.cpp Tue Nov 05 21:31:01 2013 +0000 @@ -0,0 +1,89 @@ +#include "ThermostatSocketIO.h" + +// Default SocketIO URL +#define DEFAULT_URL "mc-control-1.herokuapp.com" + +// message counter +int counter = 1; + +// constructor +ThermostatSocketIO::ThermostatSocketIO(char *devname) : SocketIO(DEFAULT_URL) { + this->device_name = devname; +} + +// constructor +ThermostatSocketIO::ThermostatSocketIO(char * myurl, char *devname) : SocketIO(myurl) { + this->device_name = devname; +} + +// reset the message counter +void ThermostatSocketIO::resetMessageCounter() { + counter = 1; +} + +// emit a message (broadcast) to the SocketIO server +int ThermostatSocketIO::emit(float temp, float latitude, float longitude, float bat, int errorState, char *t_status) { + // create json string with acc/tmp data + char send[256]; + char *json = this->createJSON(send,temp,latitude,longitude,bat,errorState,t_status); + + // handle the message name + char message_name[32]; + if (counter == 1) + // we need to register the device + sprintf(message_name,"register-device"); + else + // we are simply issuing readings... + sprintf(message_name,"readings"); + + // increment our counter + ++counter; + + // emit this json + return ((SocketIO *)this)->emit(message_name,json); +} + +// Close the thermostat socket.io +bool ThermostatSocketIO::close() { + char buf[256]; + char message_name[32]; + + // we need to register the device + sprintf(message_name,"disconnect"); + + // create the deregister JSON message + char *json = this->createDeregisterJSON(buf); + + // now send... + int sent = ((SocketIO *)this)->emit(message_name,json); + + // now close + return ((SocketIO *)this)->close(); +} + +// create the JSON to deregister the device +char *ThermostatSocketIO::createDeregisterJSON(char *buffer) { + // create the JSON to just register the device + sprintf(buffer,"[{ \"device_id\": \"%s\" } }]",this->device_name); + + // return the JSON + return buffer; +} + +// Create the JSON that is consumable by the demo webservice +char *ThermostatSocketIO::createJSON(char *buffer, float temp, float latitude, float longitude, float bat, int errorState, char *t_status) { + // create the message name + if (counter == 1) { + // create the JSON to just register the device + sprintf(buffer,"[\"%s\",{\"battery\": %d, \"city\": \"Austin\", \"country\": \"US\", \"device_id\": \"%s\", \"lat\": %4.6f, \"long\": %4.6f, \"status\": \"%s\", \"temp\": %4.1f, \"switch\": %d}]", + device_name, (int)bat, this->device_name, latitude, longitude, t_status, temp, errorState); + } + else { + // create the JSON + sprintf(buffer,"[{\"battery\": %d, \"city\": \"Austin\", \"country\": \"US\", \"device_id\": \"%s\", \"lat\": %4.6f, \"long\": %4.6f, \"status\": \"%s\", \"temp\": %4.1f, \"switch\": %d}]", + (int)bat, this->device_name, latitude, longitude, t_status, temp, errorState); + } + + // return the JSON + return buffer; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ThermostatSocketIO.h Tue Nov 05 21:31:01 2013 +0000 @@ -0,0 +1,94 @@ +/** +* @author Doug Anson +* +* @section LICENSE +* +* Copyright (c) 2013 mbed +* +* Permission is hereby granted, free of charge, to any person obtaining a copy +* of this software and associated documentation files (the "Software"), to deal +* in the Software without restriction, including without limitation the rights +* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +* copies of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be included in +* all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +* THE SOFTWARE. +* +* @section DESCRIPTION +* SocketIO derivation client library for the Thermostat Demo +* +*/ + +#ifndef THERMOSTATSOCKETIO_H +#define THERMOSTATSOCKETIO_H + +#include "SocketIO.h" + +/** + * ThermostatSocketIO client class. + * Derived class from SocketIO library specifically for the ThermostatDemo app + */ + +class ThermostatSocketIO : public SocketIO +{ + public: + /** + * Constructor + * + * @param devname The device's devname for display in the console + */ + ThermostatSocketIO(char *devname); + + /** + * Constructor + * + * @param url The SocketIO url in the form "www.example.com:[port]" (by default: port = 80) - i.e. just the endpoint name + * @param devname The device's devname for display in the console + */ + ThermostatSocketIO(char * url, char *devname); + + /** + * Emit (Broadcast) a socket.io message to the SocketIO server - specific to the ThermostatDemo app + * + * @param temp - temperature + * @param latitude - the device latitude + * @param longitude - the device longitude + * @param bat - the battery level + * @param errorState - the devices current error state + * @param t_status - the devices current error state (string - either OK or FAIL) + * + * @returns the number of bytes sent + */ + int emit(float temp, float latitude, float longitude, float bat, int errorState, char *t_status); + + /** + * Reset the message counter + */ + void resetMessageCounter(); + + /** + * Close the SocketIO connection + * + * @return true if the connection has been closed, false otherwise + */ + bool close(); + + private: + // variables + char *device_name; + + // methods + char *createDeregisterJSON(char *buffer); + char *createJSON(char *buffer, float temp, float latitude, float longitude, float bat, int errorState, char *t_status); +}; + +#endif // THERMOSTATSOCKETIO_H \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/WebSocketClient.lib Tue Nov 05 21:31:01 2013 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/ansond/code/WebSocketClient-ThermostatDemo/#8ee61b912743
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/main.cpp Tue Nov 05 21:31:01 2013 +0000 @@ -0,0 +1,24 @@ +#include "mbed.h" + +#include "Thermostat.h" + +Serial pc(USBTX, USBRX); +Thermostat *thermostat = NULL; + +// check for exit +void checkForExit() { + if (pc.readable()) { + char c = pc.getc(); + if (c == 0x03) { // CTRL-C ASCII + pc.printf("ctrl-c: closing down thermostat...\r\n"); + if (thermostat != NULL) delete thermostat; + pc.printf("app exiting...\r\n"); + exit(1); + } + } +} + +int main() { + thermostat = new Thermostat(); + if (thermostat != NULL) thermostat->runDemo(); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed-rtos.lib Tue Nov 05 21:31:01 2013 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/mbed_official/code/mbed-rtos/#ee87e782d34f
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/mbed.bld Tue Nov 05 21:31:01 2013 +0000 @@ -0,0 +1,1 @@ +http://mbed.org/users/mbed_official/code/mbed/builds/a9913a65894f \ No newline at end of file
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/picojson.lib Tue Nov 05 21:31:01 2013 +0000 @@ -0,0 +1,1 @@ +https://mbed.org/users/mimil/code/picojson/#2bb500b021e2