A weather station that uses GPS and WiFi to get the weather where you are. Almost better than actually going outside!
Dependencies: 4DGL-uLCD-SE ESP8266NodeMCUInterface GPS MbedJSONValue mbed-rtos mbed-src
main.cpp@1:fc07d1430053, 2016-03-14 (annotated)
- Committer:
- krbng4180
- Date:
- Mon Mar 14 03:04:19 2016 +0000
- Revision:
- 1:fc07d1430053
- Parent:
- 0:c4da54879553
publish
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
krbng4180 | 0:c4da54879553 | 1 | #include "mbed.h" |
krbng4180 | 0:c4da54879553 | 2 | #include "GPS.h" |
krbng4180 | 0:c4da54879553 | 3 | #include "ESP8266Interface.h" |
krbng4180 | 0:c4da54879553 | 4 | #include "MbedJSONValue.h" |
krbng4180 | 0:c4da54879553 | 5 | #include "uLCD_4DGL.h" |
krbng4180 | 0:c4da54879553 | 6 | |
krbng4180 | 1:fc07d1430053 | 7 | #define DEBUG_MODE |
krbng4180 | 1:fc07d1430053 | 8 | |
krbng4180 | 1:fc07d1430053 | 9 | #ifdef DEBUG_MODE |
krbng4180 | 1:fc07d1430053 | 10 | # define DEBUG(msg) pc.printf(msg) |
krbng4180 | 1:fc07d1430053 | 11 | # define DEBUGF(msgf) pc.printf msgf |
krbng4180 | 1:fc07d1430053 | 12 | #else |
krbng4180 | 1:fc07d1430053 | 13 | # define DEBUG(msg) |
krbng4180 | 1:fc07d1430053 | 14 | # define DEBUGF(msgf) |
krbng4180 | 1:fc07d1430053 | 15 | #endif |
krbng4180 | 0:c4da54879553 | 16 | |
krbng4180 | 0:c4da54879553 | 17 | /* Lua code comes from here: |
krbng4180 | 0:c4da54879553 | 18 | * https://learn.adafruit.com/adafruit-huzzah-esp8266-breakout/using-nodemcu-lua |
krbng4180 | 0:c4da54879553 | 19 | */ |
krbng4180 | 0:c4da54879553 | 20 | #define LUA(x) #x |
krbng4180 | 0:c4da54879553 | 21 | |
krbng4180 | 0:c4da54879553 | 22 | #define SSID "ThisIsWiFi" |
krbng4180 | 0:c4da54879553 | 23 | #define PWD "benandjerrys101" |
krbng4180 | 0:c4da54879553 | 24 | #define API_KEY "f99ab4720b04e9a5" |
krbng4180 | 1:fc07d1430053 | 25 | #define FORECAST_API_KEY "9cfbfbf425552305838467b4b838b426" |
krbng4180 | 1:fc07d1430053 | 26 | #define WWO_API_KEY "43911d834dc04583b4e221235161303" |
krbng4180 | 0:c4da54879553 | 27 | |
krbng4180 | 0:c4da54879553 | 28 | /* |
krbng4180 | 0:c4da54879553 | 29 | * The GPS unit continuously transmits data over serial in standard ASCII text. |
krbng4180 | 0:c4da54879553 | 30 | * Using this API, we call `gps.sample()` to get the most recent longitude and |
krbng4180 | 0:c4da54879553 | 31 | * latitude. To then read those values, we call `gps.longitude` and `gps.latitude`. |
krbng4180 | 0:c4da54879553 | 32 | * |
krbng4180 | 0:c4da54879553 | 33 | * Important: |
krbng4180 | 0:c4da54879553 | 34 | * It is worth noting that `gps.sample()` is synchronous and blocking; because |
krbng4180 | 0:c4da54879553 | 35 | * the GPS continously transmits data, `gps.sample()` can take a varying amount |
krbng4180 | 0:c4da54879553 | 36 | * of time. The worst case scenario is that the GPS unit *just* transmitted the |
krbng4180 | 0:c4da54879553 | 37 | * relevant information right before we call `gps.sample()`. If we needed GPS |
krbng4180 | 0:c4da54879553 | 38 | * information frequently, it would be prudent to move this to a separate thread |
krbng4180 | 0:c4da54879553 | 39 | * and interface with that thread via mutex-protected global variables for |
krbng4180 | 0:c4da54879553 | 40 | * latitude and longitude. |
krbng4180 | 0:c4da54879553 | 41 | */ |
krbng4180 | 0:c4da54879553 | 42 | GPS gps(p13, p14); |
krbng4180 | 0:c4da54879553 | 43 | |
krbng4180 | 0:c4da54879553 | 44 | /* |
krbng4180 | 0:c4da54879553 | 45 | * Serial communications with the computer. Used for debugging. |
krbng4180 | 0:c4da54879553 | 46 | */ |
krbng4180 | 0:c4da54879553 | 47 | Serial pc(USBTX, USBRX); |
krbng4180 | 0:c4da54879553 | 48 | |
krbng4180 | 0:c4da54879553 | 49 | /* |
krbng4180 | 0:c4da54879553 | 50 | * We communicate with the wifi firmware over serial. The firmware accepts |
krbng4180 | 0:c4da54879553 | 51 | * Lua commands, so we send those over serial. |
krbng4180 | 0:c4da54879553 | 52 | */ |
krbng4180 | 0:c4da54879553 | 53 | //Serial wifi(p9, p10); |
krbng4180 | 0:c4da54879553 | 54 | ESP8266Interface esp(p9, p10, p8, 9600, 7000); |
krbng4180 | 0:c4da54879553 | 55 | |
krbng4180 | 0:c4da54879553 | 56 | uLCD_4DGL uLCD(p28,p27,p30); |
krbng4180 | 0:c4da54879553 | 57 | |
krbng4180 | 1:fc07d1430053 | 58 | #define REQ_TEMPLATE_WWO "GET /free/v2/weather.ashx?key=%s&format=json&cc=yes&fx=no&q=%f,%f HTTP/1.1\r\nHost: api.worldweatheronline.com\r\nConnection: keep-alive\r\nAccept: */*\r\n\r\n" |
krbng4180 | 1:fc07d1430053 | 59 | #define REQ_TEMPLATE_WU "GET /api/%s/geolookup/q/%f,%f.json HTTP/1.1\r\nHost: api.wunderground.com\r\nConnection: keep-alive\r\nAccept: */*\r\n\r\n" |
krbng4180 | 1:fc07d1430053 | 60 | #define REQ_TEMPLATE "GET /forecast/%s/%f,%f?exclude=minutely,hourly,daily,alerts,flags HTTP/1.1\r\nHost: api.forecast.io\r\nConnection: keep-alive\r\nAccept: */*\r\n\r\n" |
krbng4180 | 0:c4da54879553 | 61 | static char http_request_buf[512] = { 0 }; |
krbng4180 | 0:c4da54879553 | 62 | |
krbng4180 | 1:fc07d1430053 | 63 | #define RESP_LEN 2048 |
krbng4180 | 0:c4da54879553 | 64 | static char http_response_buf[RESP_LEN] = { 0 }; |
krbng4180 | 0:c4da54879553 | 65 | static int http_response_len = RESP_LEN; |
krbng4180 | 0:c4da54879553 | 66 | |
krbng4180 | 1:fc07d1430053 | 67 | /* |
krbng4180 | 1:fc07d1430053 | 68 | * Prints to LCD, theoretically. It's not very pretty. |
krbng4180 | 1:fc07d1430053 | 69 | */ |
krbng4180 | 1:fc07d1430053 | 70 | |
krbng4180 | 1:fc07d1430053 | 71 | void draw_values (const char * weather, const char * temp) { |
krbng4180 | 1:fc07d1430053 | 72 | uLCD.printf("\n Current Conditions:"); |
krbng4180 | 1:fc07d1430053 | 73 | uLCD.text_width(2); |
krbng4180 | 1:fc07d1430053 | 74 | uLCD.text_height(2); |
krbng4180 | 1:fc07d1430053 | 75 | uLCD.printf(temp); |
krbng4180 | 1:fc07d1430053 | 76 | uLCD.printf(" F\n"); |
krbng4180 | 1:fc07d1430053 | 77 | uLCD.text_width(1); |
krbng4180 | 1:fc07d1430053 | 78 | uLCD.text_height(1); |
krbng4180 | 1:fc07d1430053 | 79 | uLCD.printf(weather); |
krbng4180 | 1:fc07d1430053 | 80 | } |
krbng4180 | 1:fc07d1430053 | 81 | |
krbng4180 | 1:fc07d1430053 | 82 | /* |
krbng4180 | 1:fc07d1430053 | 83 | * Parse location from geolocation response. |
krbng4180 | 1:fc07d1430053 | 84 | */ |
krbng4180 | 1:fc07d1430053 | 85 | |
krbng4180 | 1:fc07d1430053 | 86 | void parse_response (char * resp_buff) { |
krbng4180 | 0:c4da54879553 | 87 | MbedJSONValue parsed; |
krbng4180 | 0:c4da54879553 | 88 | parse(parsed, resp_buff); |
krbng4180 | 1:fc07d1430053 | 89 | MbedJSONValue &inst = parsed["data"]["current_condition"][0]; |
krbng4180 | 0:c4da54879553 | 90 | // const string &citystate = inst["city"].get<string>() + ", " + inst["state"].get<string>(); |
krbng4180 | 0:c4da54879553 | 91 | // string[2] ar; |
krbng4180 | 1:fc07d1430053 | 92 | const char* weather = inst["wetherDesc"][0]["value"].get<string>().c_str(); |
krbng4180 | 1:fc07d1430053 | 93 | const char* temp = inst["temp_f"].get<string>().c_str(); |
krbng4180 | 1:fc07d1430053 | 94 | //if we want an icon, inst["weatherIconUrl"][0]["value"].get<string>(); gets the URL |
krbng4180 | 1:fc07d1430053 | 95 | draw_values(weather, temp); |
krbng4180 | 0:c4da54879553 | 96 | } |
krbng4180 | 0:c4da54879553 | 97 | |
krbng4180 | 1:fc07d1430053 | 98 | static char * get_weather_json(double latitude, double longitude) |
krbng4180 | 1:fc07d1430053 | 99 | { |
krbng4180 | 1:fc07d1430053 | 100 | int http_request_len = sprintf(http_request_buf, REQ_TEMPLATE_WWO, WWO_API_KEY, latitude, longitude); |
krbng4180 | 1:fc07d1430053 | 101 | /* Send HTTP request */ |
krbng4180 | 1:fc07d1430053 | 102 | bool sent = false; |
krbng4180 | 1:fc07d1430053 | 103 | do { |
krbng4180 | 1:fc07d1430053 | 104 | sent = esp.send(http_request_buf, http_request_len); |
krbng4180 | 1:fc07d1430053 | 105 | DEBUGF(("Request sent: %d\n\r", sent)); |
krbng4180 | 1:fc07d1430053 | 106 | } while (!sent); |
krbng4180 | 1:fc07d1430053 | 107 | |
krbng4180 | 1:fc07d1430053 | 108 | DEBUGF(("%s", http_request_buf)); |
krbng4180 | 0:c4da54879553 | 109 | |
krbng4180 | 1:fc07d1430053 | 110 | wait(3); |
krbng4180 | 1:fc07d1430053 | 111 | |
krbng4180 | 1:fc07d1430053 | 112 | bool recv = false; |
krbng4180 | 1:fc07d1430053 | 113 | do { |
krbng4180 | 1:fc07d1430053 | 114 | http_response_len = RESP_LEN; |
krbng4180 | 1:fc07d1430053 | 115 | recv = esp.recv(http_response_buf, &http_response_len); |
krbng4180 | 1:fc07d1430053 | 116 | DEBUGF(("Request recv: %d\n\r", recv)); |
krbng4180 | 1:fc07d1430053 | 117 | DEBUGF(("Response: %s\n\r", http_response_buf)); |
krbng4180 | 1:fc07d1430053 | 118 | DEBUGF(("Response Length: %d\n\r", http_response_len)); |
krbng4180 | 1:fc07d1430053 | 119 | wait(2); |
krbng4180 | 1:fc07d1430053 | 120 | } while (!recv); |
krbng4180 | 1:fc07d1430053 | 121 | |
krbng4180 | 1:fc07d1430053 | 122 | return http_response_buf; |
krbng4180 | 0:c4da54879553 | 123 | } |
krbng4180 | 0:c4da54879553 | 124 | |
krbng4180 | 0:c4da54879553 | 125 | int main() { |
krbng4180 | 0:c4da54879553 | 126 | |
krbng4180 | 0:c4da54879553 | 127 | //wifi.attach(&wifi_rx_handler, Serial::RxIrq); |
krbng4180 | 0:c4da54879553 | 128 | //wifi.attach(&wifi_tx_handler, Serial::TxIrq); |
krbng4180 | 0:c4da54879553 | 129 | |
krbng4180 | 0:c4da54879553 | 130 | //wifi.baud(9600); |
krbng4180 | 0:c4da54879553 | 131 | pc.baud(9600); |
krbng4180 | 0:c4da54879553 | 132 | pc.printf("HELLO WORLD\n\r"); |
krbng4180 | 0:c4da54879553 | 133 | /* |
krbng4180 | 0:c4da54879553 | 134 | * Intialize connection to AP. |
krbng4180 | 0:c4da54879553 | 135 | */ |
krbng4180 | 0:c4da54879553 | 136 | esp.init(); |
krbng4180 | 0:c4da54879553 | 137 | |
krbng4180 | 0:c4da54879553 | 138 | bool connected = false; |
krbng4180 | 0:c4da54879553 | 139 | do { |
krbng4180 | 0:c4da54879553 | 140 | connected = esp.connect(SSID, PWD); |
krbng4180 | 0:c4da54879553 | 141 | DEBUGF(("Connected to AP: %d\n\r", connected)); |
krbng4180 | 0:c4da54879553 | 142 | } while (!connected); |
krbng4180 | 0:c4da54879553 | 143 | |
krbng4180 | 0:c4da54879553 | 144 | /* Perform DNS lookup */ |
krbng4180 | 0:c4da54879553 | 145 | |
krbng4180 | 0:c4da54879553 | 146 | char ip[12] = { 0 }; |
krbng4180 | 0:c4da54879553 | 147 | bool dns_success = false; |
krbng4180 | 0:c4da54879553 | 148 | do { |
krbng4180 | 1:fc07d1430053 | 149 | dns_success = esp.getHostByName("api.worldweatheronline.com", ip); |
krbng4180 | 0:c4da54879553 | 150 | DEBUGF(("IP: %s\n\r", ip)); |
krbng4180 | 0:c4da54879553 | 151 | } while (!dns_success); |
krbng4180 | 0:c4da54879553 | 152 | |
krbng4180 | 0:c4da54879553 | 153 | /* Open connection */ |
krbng4180 | 0:c4da54879553 | 154 | |
krbng4180 | 0:c4da54879553 | 155 | bool opened = false; |
krbng4180 | 0:c4da54879553 | 156 | do { |
krbng4180 | 0:c4da54879553 | 157 | opened = esp.open(1, ip, 80); |
krbng4180 | 0:c4da54879553 | 158 | DEBUGF(("Connection opened: %d\n\r", opened)); |
krbng4180 | 0:c4da54879553 | 159 | } while (!opened); |
krbng4180 | 0:c4da54879553 | 160 | |
krbng4180 | 0:c4da54879553 | 161 | /* Generate HTTP request */ |
krbng4180 | 0:c4da54879553 | 162 | gps.sample(); |
krbng4180 | 1:fc07d1430053 | 163 | get_weather_json(gps.latitude, gps.longitude + 56); |
krbng4180 | 1:fc07d1430053 | 164 | //int http_request_len = sprintf(http_request_buf, REQ_TEMPLATE_WWO, WWO_API_KEY, gps.latitude, gps.longitude + 56); |
krbng4180 | 1:fc07d1430053 | 165 | // /* Send HTTP request */ |
krbng4180 | 1:fc07d1430053 | 166 | // bool sent = false; |
krbng4180 | 1:fc07d1430053 | 167 | // do { |
krbng4180 | 1:fc07d1430053 | 168 | // sent = esp.send(http_request_buf, http_request_len); |
krbng4180 | 1:fc07d1430053 | 169 | // DEBUGF(("Request sent: %d\n\r", sent)); |
krbng4180 | 1:fc07d1430053 | 170 | // } while (!sent); |
krbng4180 | 1:fc07d1430053 | 171 | // |
krbng4180 | 1:fc07d1430053 | 172 | // DEBUGF(("%s", http_request_buf)); |
krbng4180 | 1:fc07d1430053 | 173 | // |
krbng4180 | 1:fc07d1430053 | 174 | // wait(3); |
krbng4180 | 1:fc07d1430053 | 175 | // |
krbng4180 | 1:fc07d1430053 | 176 | // bool recv = false; |
krbng4180 | 1:fc07d1430053 | 177 | // do { |
krbng4180 | 1:fc07d1430053 | 178 | // http_response_len = RESP_LEN; |
krbng4180 | 1:fc07d1430053 | 179 | // recv = esp.recv(http_response_buf, &http_response_len); |
krbng4180 | 1:fc07d1430053 | 180 | // DEBUGF(("Request recv: %d\n\r", recv)); |
krbng4180 | 1:fc07d1430053 | 181 | // DEBUGF(("Response: %s\n\r", http_response_buf)); |
krbng4180 | 1:fc07d1430053 | 182 | // DEBUGF(("Response Length: %d\n\r", http_response_len)); |
krbng4180 | 1:fc07d1430053 | 183 | // wait(2); |
krbng4180 | 1:fc07d1430053 | 184 | // } while (!recv); |
krbng4180 | 0:c4da54879553 | 185 | |
krbng4180 | 0:c4da54879553 | 186 | while (1) { |
krbng4180 | 0:c4da54879553 | 187 | } |
krbng4180 | 0:c4da54879553 | 188 | |
krbng4180 | 0:c4da54879553 | 189 | } |