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

Committer:
krbng4180
Date:
Mon Mar 14 03:04:19 2016 +0000
Revision:
1:fc07d1430053
Parent:
0:c4da54879553
publish

Who changed what in which revision?

UserRevisionLine numberNew 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 }