Displays the current weather, date, and time

Dependencies:   mbed MbedJSONValue mbed-rtos 4DGL-uLCD-SE ESP8266NodeMCUInterface

Welcome to the Smart Weather Clock, which uses WiFi and Bluetooth to give the user a clear date, time, and weather for the day.

This wiki serves to document

  • What components you'll need
  • How these components will be connected
  • How the code gets all the information it needs

Components

LCD Screen

Components / 4D Systems 128 by 128 Smart Color LCD uLCD-144-G2
128 by 128 Color Smart LCD with serial interface and SD card slot

The LCD screen is a 128x128 pixel full color LCD by 4D Systems. A wonderful introduction can be found here.

In the simplest case, we'll only use one screen, but we can (and perhaps should) augment the design to include two.

Import library4DGL-uLCD-SE

Fork of 4DGL lib for uLCD-144-G2. Different command values needed. See https://mbed.org/users/4180_1/notebook/ulcd-144-g2-128-by-128-color-lcd/ for instructions and demo code.

You can buy it from sparkfun.

5V Adapter

The adapter allows us to feed much more power to the MBED and, critically, decouples us from a computer. It's important to remember that on the barrel jack adapter (i.e., the part that goes in the breadboard), the pin closest to the jack is 5V, and the back pin is Ground.

You can get the adapter here, and the barrel jack adapter here

Bluetooth UART Module

This module allows us to interface with the mbed via bluetooth and the ever-helpful AdaFruit Bluetooth App. A great introduction can be found here.

We'll use it to allow the user to set some defaults and API keys. This is stored in persistent flash storage on the LPC 1768 (See the Local File System, but you'll need an SD card if you're using a different MBED device.

You can get the Bluetooth module here.

WiFi Module

The WiFi module is also from AdaFruit, like the Bluetooth module. This allows us to interface with different WiFi networks for internet connectivity. A nice introduction is here.

You can get the WiFi module here.

WiFi Interface!

The current WiFi interface (found here) has some major problems - we're using an augmented version in our code!

Connections

5V Input for MBED

Before you connect the MBED to 5V from the wall, Make sure you have connected it correctly! If you don't, you could brick the MBED.

Thankfully, this is easy to test - when you think you have hooked up the 5V Jack correctly, try lighting a single LED (with a 10K resistor in series). If it lights up - you're good!

Alternatively, you could just plug in the MBED via USB, and just not have the MBED run on the +5V. You'll still need the Wall Adapter, however.

WiFi Module

The WiFi Module has two Grounds - you must connect both!

MBED5V Barrel Jack
Vin+5V (back pin)
GndGnd (pin closest to jack)
MBEDuLCD Cable
5V5V
GndGnd
P09TX
P10RX
P11Reset
MBEDBluetooth UART
5VVin
GndGnd
GndCTS
P27TXO
P28RXI
MBEDWiFi Module
5VV+
GndGnd
GndGnd
P13RX
P14TX
P15Reset

Code

The code works in a fairly logical order:

  1. Connect to the given WiFi, and check that we have all of our API keys
  2. Get the current location via the IP API
  3. Get the current time via the TimeZoneDB
  4. Get the current weather via the OpenWeatherMap API
  5. Continually update the weather, once per minute

Some caveats:

  • Memory seems to be an issue. If I had to guess, it would be the MbedJSONValue JSON parser - instantiating a third one seems to always lead to an MBED OS Fault or an MBED Memory Allocation fault. More insight is needed here.
  • The off-the-shelf ESP8226 Interface doesn't handle receiving correctly - I had to augment the library with recv and recv2. It works in most simple practical use cases.
Committer:
alexhrao
Date:
Mon Apr 01 17:00:17 2019 +0000
Revision:
8:d323c6406b47
Parent:
6:ec7829f7cd38
Child:
9:299eb69af04e
Update ESP8226 link

Who changed what in which revision?

UserRevisionLine numberNew contents of line
alexhrao 0:4ffa136585a2 1 #include "mbed.h"
alexhrao 1:0620ba35d2e8 2 #include "uLCD_4DGL.h"
alexhrao 1:0620ba35d2e8 3 #include "ESP8266Interface.h"
alexhrao 1:0620ba35d2e8 4 #include "TCPSocketConnection.h"
alexhrao 1:0620ba35d2e8 5 #include "rtos.h"
alexhrao 3:7bf41989ff8f 6 #include "MbedJSONValue.h"
alexhrao 3:7bf41989ff8f 7 #include <string>
alexhrao 3:7bf41989ff8f 8
alexhrao 3:7bf41989ff8f 9 #define BUF_SIZE 4096
alexhrao 1:0620ba35d2e8 10
alexhrao 1:0620ba35d2e8 11 // We need this for being able to reset the MBED (similar to watch dogs)
alexhrao 1:0620ba35d2e8 12 extern "C" void mbed_reset();
alexhrao 1:0620ba35d2e8 13
alexhrao 1:0620ba35d2e8 14 // LCD Screen
alexhrao 1:0620ba35d2e8 15 uLCD_4DGL uLCD(p9, p10, p11);
alexhrao 1:0620ba35d2e8 16 Mutex lcd_lock;
alexhrao 1:0620ba35d2e8 17
alexhrao 1:0620ba35d2e8 18 // File System
alexhrao 1:0620ba35d2e8 19 LocalFileSystem fs("local");
alexhrao 1:0620ba35d2e8 20
alexhrao 1:0620ba35d2e8 21 // Bluetooth
alexhrao 1:0620ba35d2e8 22 RawSerial pc(USBTX, USBRX);
alexhrao 1:0620ba35d2e8 23 RawSerial dev(p28,p27);
alexhrao 1:0620ba35d2e8 24
alexhrao 1:0620ba35d2e8 25 // Error LED
alexhrao 1:0620ba35d2e8 26 DigitalOut err_led(LED1);
alexhrao 1:0620ba35d2e8 27
alexhrao 1:0620ba35d2e8 28 // WiFi
alexhrao 1:0620ba35d2e8 29 ESP8266Interface wifi(p13, p14, p15, 9600, 10000);
alexhrao 1:0620ba35d2e8 30
alexhrao 1:0620ba35d2e8 31 // Time
alexhrao 1:0620ba35d2e8 32 Thread time_thread;
alexhrao 1:0620ba35d2e8 33
alexhrao 3:7bf41989ff8f 34 // Location
alexhrao 3:7bf41989ff8f 35 double latitude = 0;
alexhrao 3:7bf41989ff8f 36 double longitude = 0;
alexhrao 0:4ffa136585a2 37
alexhrao 4:55f0c303f56a 38 // Credentials
alexhrao 4:55f0c303f56a 39 char ssid[256];
alexhrao 4:55f0c303f56a 40 char pass[256];
alexhrao 4:55f0c303f56a 41 char ip_api_key[256];
alexhrao 4:55f0c303f56a 42 char time_api_key[256];
alexhrao 4:55f0c303f56a 43 char weather_api_key[256];
alexhrao 4:55f0c303f56a 44
alexhrao 8:d323c6406b47 45 void time_updater()
alexhrao 8:d323c6406b47 46 {
alexhrao 1:0620ba35d2e8 47 // We're not an interrupt, so take as much time as we need. Infinite loop
alexhrao 1:0620ba35d2e8 48 // but wait 1 second between each loop
alexhrao 1:0620ba35d2e8 49 struct tm* ltm;
alexhrao 1:0620ba35d2e8 50 time_t now;
alexhrao 8:d323c6406b47 51
alexhrao 1:0620ba35d2e8 52 now = time(NULL);
alexhrao 1:0620ba35d2e8 53 ltm = localtime(&now);
alexhrao 8:d323c6406b47 54
alexhrao 1:0620ba35d2e8 55 // Buffer for time string. Max length is 23:59 + \0
alexhrao 4:55f0c303f56a 56 int max_time_len = 8;
alexhrao 1:0620ba35d2e8 57 char ftime[max_time_len];
alexhrao 4:55f0c303f56a 58 ftime[0] = ' ';
alexhrao 4:55f0c303f56a 59 ftime[1] = ' ';
alexhrao 1:0620ba35d2e8 60 int min = -1;
alexhrao 8:d323c6406b47 61
alexhrao 1:0620ba35d2e8 62 while (true) {
alexhrao 1:0620ba35d2e8 63 // if the minute has changed, update.
alexhrao 1:0620ba35d2e8 64 now = time(NULL);
alexhrao 1:0620ba35d2e8 65 ltm = localtime(&now);
alexhrao 1:0620ba35d2e8 66 if(ltm->tm_min != min) {
alexhrao 1:0620ba35d2e8 67 // Get the new time
alexhrao 8:d323c6406b47 68 strftime(ftime + 2, max_time_len, "%H:%M", ltm);
alexhrao 1:0620ba35d2e8 69 // Update time! Lock the lcd mutex
alexhrao 1:0620ba35d2e8 70 lcd_lock.lock();
alexhrao 1:0620ba35d2e8 71 uLCD.text_width(2);
alexhrao 1:0620ba35d2e8 72 uLCD.text_height(2);
alexhrao 1:0620ba35d2e8 73 uLCD.text_string(ftime, 0, 2, FONT_8X8, GREEN);
alexhrao 1:0620ba35d2e8 74 // Done updating - unlock!
alexhrao 1:0620ba35d2e8 75 lcd_lock.unlock();
alexhrao 1:0620ba35d2e8 76 min = ltm->tm_min;
alexhrao 1:0620ba35d2e8 77 }
alexhrao 1:0620ba35d2e8 78 // Wait 1 second
alexhrao 1:0620ba35d2e8 79 Thread::wait(1.0f);
alexhrao 8:d323c6406b47 80 }
alexhrao 1:0620ba35d2e8 81 }
alexhrao 1:0620ba35d2e8 82
alexhrao 8:d323c6406b47 83 void dev_recv()
alexhrao 8:d323c6406b47 84 {
alexhrao 1:0620ba35d2e8 85 // Continually check if we have stuff...
alexhrao 1:0620ba35d2e8 86 char buf[1024];
alexhrao 1:0620ba35d2e8 87 int ind = 0;
alexhrao 1:0620ba35d2e8 88 while (true) {
alexhrao 1:0620ba35d2e8 89 while (true) {
alexhrao 1:0620ba35d2e8 90 // get stuff. If we encounter \r or \n, that's a complete command!
alexhrao 1:0620ba35d2e8 91 char tmp = dev.getc();
alexhrao 1:0620ba35d2e8 92 if (tmp == '\n' || tmp == '\r') {
alexhrao 1:0620ba35d2e8 93 break;
alexhrao 1:0620ba35d2e8 94 }
alexhrao 1:0620ba35d2e8 95 buf[ind++] = tmp;
alexhrao 1:0620ba35d2e8 96 Thread::wait(0.01);
alexhrao 1:0620ba35d2e8 97 }
alexhrao 1:0620ba35d2e8 98 buf[ind] = '\0';
alexhrao 1:0620ba35d2e8 99 // read command and respond
alexhrao 1:0620ba35d2e8 100 if (strcmp(buf, "reset") == 0) {
alexhrao 1:0620ba35d2e8 101 dev.printf("Are you sure? y/[n]\n");
alexhrao 1:0620ba35d2e8 102 }
alexhrao 1:0620ba35d2e8 103 buf[0] = '\0';
alexhrao 1:0620ba35d2e8 104 ind = 0;
alexhrao 1:0620ba35d2e8 105 //if (strcmp(buf, "reset") != 0) {
alexhrao 1:0620ba35d2e8 106 Thread::wait(0.01);
alexhrao 1:0620ba35d2e8 107 }
alexhrao 2:f7d19812bdc5 108 }
alexhrao 0:4ffa136585a2 109
alexhrao 8:d323c6406b47 110 int kelvin2farenheit(int temp)
alexhrao 8:d323c6406b47 111 {
alexhrao 8:d323c6406b47 112 return (int)((((temp - 273.15f) * 9.0f) / 5.0f) + 32.0f);
alexhrao 4:55f0c303f56a 113 }
alexhrao 4:55f0c303f56a 114
alexhrao 8:d323c6406b47 115 void clock_init()
alexhrao 8:d323c6406b47 116 {
alexhrao 1:0620ba35d2e8 117 // Set up bluetooth
alexhrao 1:0620ba35d2e8 118 dev.baud(9600);
alexhrao 1:0620ba35d2e8 119 pc.baud(9600);
alexhrao 8:d323c6406b47 120
alexhrao 1:0620ba35d2e8 121 // Tell user we're initializing...
alexhrao 1:0620ba35d2e8 122 lcd_lock.lock();
alexhrao 1:0620ba35d2e8 123 uLCD.cls();
alexhrao 1:0620ba35d2e8 124 uLCD.text_height(2);
alexhrao 6:ec7829f7cd38 125 uLCD.text_width(2);
alexhrao 6:ec7829f7cd38 126 uLCD.text_string("PLEASE", 0, 2, FONT_7X8, WHITE);
alexhrao 6:ec7829f7cd38 127 uLCD.text_string("WAIT", 0, 5, FONT_7X8, WHITE);
alexhrao 1:0620ba35d2e8 128 lcd_lock.unlock();
alexhrao 8:d323c6406b47 129
alexhrao 1:0620ba35d2e8 130 // Need to get wifi settings. If we don't have local file, then ask!
alexhrao 4:55f0c303f56a 131 FILE* fid = fopen("/local/settings.txt", "r");
alexhrao 8:d323c6406b47 132
alexhrao 4:55f0c303f56a 133 if (fid != NULL) {
alexhrao 2:f7d19812bdc5 134 // Read WiFi Settings
alexhrao 2:f7d19812bdc5 135 char settings_buf[1024];
alexhrao 4:55f0c303f56a 136 // Guaranteed to be 5 lines
alexhrao 8:d323c6406b47 137 //
alexhrao 2:f7d19812bdc5 138 fgets(settings_buf, 1024, fid);
alexhrao 2:f7d19812bdc5 139 // find \n
alexhrao 2:f7d19812bdc5 140 int settings_ind = 0;
alexhrao 2:f7d19812bdc5 141 int counter = 0;
alexhrao 2:f7d19812bdc5 142 while (settings_buf[counter] != '\n') {
alexhrao 2:f7d19812bdc5 143 ssid[settings_ind++] = settings_buf[counter++];
alexhrao 2:f7d19812bdc5 144 }
alexhrao 2:f7d19812bdc5 145 ssid[settings_ind] = '\0';
alexhrao 2:f7d19812bdc5 146 settings_ind = 0;
alexhrao 4:55f0c303f56a 147 fgets(settings_buf, 1024, fid);
alexhrao 4:55f0c303f56a 148 counter = 0;
alexhrao 2:f7d19812bdc5 149 while (settings_buf[counter] != '\n') {
alexhrao 2:f7d19812bdc5 150 pass[settings_ind++] = settings_buf[counter++];
alexhrao 2:f7d19812bdc5 151 }
alexhrao 2:f7d19812bdc5 152 pass[settings_ind] = '\0';
alexhrao 2:f7d19812bdc5 153 settings_ind = 0;
alexhrao 4:55f0c303f56a 154 fgets(settings_buf, 1024, fid);
alexhrao 4:55f0c303f56a 155 counter = 0;
alexhrao 4:55f0c303f56a 156 while (settings_buf[counter] != '\n') {
alexhrao 4:55f0c303f56a 157 ip_api_key[settings_ind++] = settings_buf[counter++];
alexhrao 4:55f0c303f56a 158 }
alexhrao 4:55f0c303f56a 159 ip_api_key[settings_ind] = '\0';
alexhrao 4:55f0c303f56a 160 settings_ind = 0;
alexhrao 4:55f0c303f56a 161 fgets(settings_buf, 1024, fid);
alexhrao 4:55f0c303f56a 162 counter = 0;
alexhrao 2:f7d19812bdc5 163 while (settings_buf[counter] != '\n') {
alexhrao 4:55f0c303f56a 164 time_api_key[settings_ind++] = settings_buf[counter++];
alexhrao 2:f7d19812bdc5 165 }
alexhrao 4:55f0c303f56a 166 time_api_key[settings_ind] = '\0';
alexhrao 4:55f0c303f56a 167 settings_ind = 0;
alexhrao 4:55f0c303f56a 168 fgets(settings_buf, 1024, fid);
alexhrao 4:55f0c303f56a 169 counter = 0;
alexhrao 4:55f0c303f56a 170 while (settings_buf[counter] != '\n') {
alexhrao 4:55f0c303f56a 171 weather_api_key[settings_ind++] = settings_buf[counter++];
alexhrao 4:55f0c303f56a 172 }
alexhrao 4:55f0c303f56a 173 weather_api_key[settings_ind] = '\0';
alexhrao 2:f7d19812bdc5 174 fclose(fid);
alexhrao 1:0620ba35d2e8 175 } else {
alexhrao 1:0620ba35d2e8 176 lcd_lock.lock();
alexhrao 1:0620ba35d2e8 177 uLCD.cls();
alexhrao 1:0620ba35d2e8 178 uLCD.text_height(2);
alexhrao 1:0620ba35d2e8 179 uLCD.text_width(2);
alexhrao 1:0620ba35d2e8 180 uLCD.text_string("SEE", 0, 2, FONT_7X8, RED);
alexhrao 1:0620ba35d2e8 181 uLCD.text_string("DEVICE", 0, 5, FONT_7X8, RED);
alexhrao 1:0620ba35d2e8 182 lcd_lock.unlock();
alexhrao 8:d323c6406b47 183
alexhrao 1:0620ba35d2e8 184 // Ask!
alexhrao 1:0620ba35d2e8 185 dev.printf("Please provide the name of a WiFi Network\n");
alexhrao 8:d323c6406b47 186
alexhrao 1:0620ba35d2e8 187 // Wait for them to respond
alexhrao 1:0620ba35d2e8 188 while (!dev.readable()) {
alexhrao 1:0620ba35d2e8 189 wait(0.001);
alexhrao 1:0620ba35d2e8 190 }
alexhrao 1:0620ba35d2e8 191 int ind = 0;
alexhrao 8:d323c6406b47 192
alexhrao 1:0620ba35d2e8 193 // Read response
alexhrao 1:0620ba35d2e8 194 while (ind < 255) {
alexhrao 1:0620ba35d2e8 195 char tmp = dev.getc();
alexhrao 1:0620ba35d2e8 196 if (tmp == '\n' || tmp == '\r') {
alexhrao 1:0620ba35d2e8 197 break;
alexhrao 1:0620ba35d2e8 198 }
alexhrao 1:0620ba35d2e8 199 ssid[ind++] = tmp;
alexhrao 1:0620ba35d2e8 200 wait(0.01);
alexhrao 1:0620ba35d2e8 201 }
alexhrao 1:0620ba35d2e8 202 ssid[ind] = '\0';
alexhrao 8:d323c6406b47 203
alexhrao 1:0620ba35d2e8 204 // flush device
alexhrao 1:0620ba35d2e8 205 while (dev.readable()) {
alexhrao 1:0620ba35d2e8 206 dev.getc();
alexhrao 1:0620ba35d2e8 207 wait(0.01);
alexhrao 1:0620ba35d2e8 208 }
alexhrao 8:d323c6406b47 209
alexhrao 2:f7d19812bdc5 210 // Get the password
alexhrao 1:0620ba35d2e8 211 dev.printf("Please provide the password\n");
alexhrao 1:0620ba35d2e8 212 while (!dev.readable()) {
alexhrao 1:0620ba35d2e8 213 wait(0.001);
alexhrao 1:0620ba35d2e8 214 }
alexhrao 1:0620ba35d2e8 215 ind = 0;
alexhrao 1:0620ba35d2e8 216 while (ind < 255) {
alexhrao 1:0620ba35d2e8 217 char tmp = dev.getc();
alexhrao 1:0620ba35d2e8 218 if (tmp == '\n' || tmp == '\r') {
alexhrao 1:0620ba35d2e8 219 break;
alexhrao 1:0620ba35d2e8 220 }
alexhrao 1:0620ba35d2e8 221 pass[ind++] = tmp;
alexhrao 1:0620ba35d2e8 222 wait(0.01);
alexhrao 1:0620ba35d2e8 223 }
alexhrao 1:0620ba35d2e8 224 pass[ind] = '\0';
alexhrao 8:d323c6406b47 225
alexhrao 2:f7d19812bdc5 226 // Get the API key
alexhrao 4:55f0c303f56a 227 dev.printf("Please provide the IP Stack API key\n");
alexhrao 2:f7d19812bdc5 228 while (!dev.readable()) {
alexhrao 2:f7d19812bdc5 229 wait(0.001);
alexhrao 2:f7d19812bdc5 230 }
alexhrao 2:f7d19812bdc5 231 ind = 0;
alexhrao 2:f7d19812bdc5 232 while (ind < 255) {
alexhrao 2:f7d19812bdc5 233 char tmp = dev.getc();
alexhrao 2:f7d19812bdc5 234 if (tmp == '\n' || tmp == '\r') {
alexhrao 2:f7d19812bdc5 235 break;
alexhrao 2:f7d19812bdc5 236 }
alexhrao 4:55f0c303f56a 237 ip_api_key[ind++] = tmp;
alexhrao 4:55f0c303f56a 238 wait(0.01);
alexhrao 4:55f0c303f56a 239 }
alexhrao 4:55f0c303f56a 240
alexhrao 4:55f0c303f56a 241 ip_api_key[ind] = '\0';
alexhrao 8:d323c6406b47 242
alexhrao 4:55f0c303f56a 243 dev.printf("Please provide the TimeZoneDB API key\n");
alexhrao 4:55f0c303f56a 244 while (!dev.readable()) {
alexhrao 4:55f0c303f56a 245 wait(0.001);
alexhrao 4:55f0c303f56a 246 }
alexhrao 4:55f0c303f56a 247 ind = 0;
alexhrao 4:55f0c303f56a 248 while (ind < 255) {
alexhrao 4:55f0c303f56a 249 char tmp = dev.getc();
alexhrao 4:55f0c303f56a 250 if (tmp == '\r' || tmp == '\n') {
alexhrao 4:55f0c303f56a 251 break;
alexhrao 4:55f0c303f56a 252 }
alexhrao 4:55f0c303f56a 253 time_api_key[ind++] = tmp;
alexhrao 2:f7d19812bdc5 254 wait(0.01);
alexhrao 2:f7d19812bdc5 255 }
alexhrao 4:55f0c303f56a 256 time_api_key[ind] = '\0';
alexhrao 8:d323c6406b47 257
alexhrao 4:55f0c303f56a 258 dev.printf("Please provide the OpenWeather API key\n");
alexhrao 4:55f0c303f56a 259 while (!dev.readable()) {
alexhrao 4:55f0c303f56a 260 wait(0.001);
alexhrao 4:55f0c303f56a 261 }
alexhrao 4:55f0c303f56a 262 ind = 0;
alexhrao 4:55f0c303f56a 263 while (ind < 255) {
alexhrao 4:55f0c303f56a 264 char tmp = dev.getc();
alexhrao 4:55f0c303f56a 265 if (tmp == '\r' || tmp == '\n') {
alexhrao 4:55f0c303f56a 266 break;
alexhrao 4:55f0c303f56a 267 }
alexhrao 4:55f0c303f56a 268 weather_api_key[ind++] = tmp;
alexhrao 4:55f0c303f56a 269 wait(0.01);
alexhrao 4:55f0c303f56a 270 }
alexhrao 4:55f0c303f56a 271 weather_api_key[ind] = '\0';
alexhrao 4:55f0c303f56a 272
alexhrao 8:d323c6406b47 273
alexhrao 8:d323c6406b47 274
alexhrao 8:d323c6406b47 275 // Because this is a simple proof of concept, we store the password in
alexhrao 8:d323c6406b47 276 // plaintext. It should be noted, however, that you **should never do
alexhrao 1:0620ba35d2e8 277 // this in "real life"**
alexhrao 4:55f0c303f56a 278 fid = fopen("/local/settings.txt", "w");
alexhrao 4:55f0c303f56a 279 fprintf(fid, "%s\n%s\n%s\n%s\n%s\n", ssid, pass, ip_api_key, time_api_key, weather_api_key);
alexhrao 4:55f0c303f56a 280 fclose(fid);
alexhrao 1:0620ba35d2e8 281 }
alexhrao 6:ec7829f7cd38 282 /*
alexhrao 4:55f0c303f56a 283 dev.printf("\r\n** CREDENTIALS **\r\n");
alexhrao 4:55f0c303f56a 284 dev.printf("SSID: **%s** (%d)\r\n", ssid, strlen(ssid));
alexhrao 4:55f0c303f56a 285 dev.printf("PASS: **%s** (%d)\r\n", pass, strlen(pass));
alexhrao 4:55f0c303f56a 286 dev.printf("IP STACK: **%s**\r\n", ip_api_key);
alexhrao 4:55f0c303f56a 287 dev.printf("TIMEZONEDB: **%s**\r\n", time_api_key);
alexhrao 4:55f0c303f56a 288 dev.printf("WEATHERMAP: **%s**\r\n", weather_api_key);
alexhrao 6:ec7829f7cd38 289 */
alexhrao 1:0620ba35d2e8 290 bool res = wifi.init();
alexhrao 4:55f0c303f56a 291
alexhrao 1:0620ba35d2e8 292 // Set up the WiFi Access Point
alexhrao 1:0620ba35d2e8 293 dev.printf("Connecting to WiFi %s with Password %s\n", ssid, pass);
alexhrao 8:d323c6406b47 294
alexhrao 5:b77a717feada 295 res = wifi.connect(ssid, pass);
alexhrao 2:f7d19812bdc5 296 if (!res) {
alexhrao 2:f7d19812bdc5 297 dev.printf("Connection Failed... Resetting Device\n");
alexhrao 2:f7d19812bdc5 298 err_led = 1;
alexhrao 2:f7d19812bdc5 299 mbed_reset();
alexhrao 2:f7d19812bdc5 300 }
alexhrao 8:d323c6406b47 301
alexhrao 2:f7d19812bdc5 302 dev.printf("Connected with IP Address: %s\n", wifi.getIPAddress());
alexhrao 8:d323c6406b47 303
alexhrao 4:55f0c303f56a 304 /** API REQUESTS **/
alexhrao 8:d323c6406b47 305
alexhrao 4:55f0c303f56a 306 int header_ind = 0;
alexhrao 4:55f0c303f56a 307 int footer_ind = 0;
alexhrao 4:55f0c303f56a 308 int read_len = 0;
alexhrao 4:55f0c303f56a 309 char buffer[BUF_SIZE];
alexhrao 4:55f0c303f56a 310 char cmd[512];
alexhrao 4:55f0c303f56a 311
alexhrao 3:7bf41989ff8f 312 TCPSocketConnection tcp;
alexhrao 3:7bf41989ff8f 313 tcp.connect("api.ipstack.com", 80);
alexhrao 8:d323c6406b47 314
alexhrao 8:d323c6406b47 315 sprintf(cmd,
alexhrao 8:d323c6406b47 316 "GET /check?access_key=%s HTTP/1.1\r\nHost: api.ipstack.com\r\n\r\n",
alexhrao 8:d323c6406b47 317 ip_api_key);
alexhrao 4:55f0c303f56a 318 tcp.send_all(cmd, strlen(cmd));
alexhrao 8:d323c6406b47 319
alexhrao 4:55f0c303f56a 320 wait(5);
alexhrao 8:d323c6406b47 321
alexhrao 4:55f0c303f56a 322 read_len = wifi.recv(buffer, BUF_SIZE - 1, 0);
alexhrao 3:7bf41989ff8f 323 buffer[read_len] = '\0';
alexhrao 8:d323c6406b47 324
alexhrao 4:55f0c303f56a 325 // Cleanup
alexhrao 8:d323c6406b47 326
alexhrao 4:55f0c303f56a 327 while (header_ind < read_len) {
alexhrao 4:55f0c303f56a 328 // if we are \r, look ahead to see \n\r\n:
alexhrao 4:55f0c303f56a 329 if(buffer[header_ind] == '\r' &&
alexhrao 8:d323c6406b47 330 buffer[header_ind+1] == '\n' &&
alexhrao 8:d323c6406b47 331 buffer[header_ind+2] == '\r' &&
alexhrao 8:d323c6406b47 332 buffer[header_ind+3] == '\n') {
alexhrao 4:55f0c303f56a 333 // Increment header_ind, look for JSON
alexhrao 4:55f0c303f56a 334 // Now just look for {
alexhrao 4:55f0c303f56a 335 header_ind += 4;
alexhrao 4:55f0c303f56a 336 while (header_ind < read_len) {
alexhrao 4:55f0c303f56a 337 if (buffer[header_ind] == '{') {
alexhrao 4:55f0c303f56a 338 // we got it!
alexhrao 4:55f0c303f56a 339 break;
alexhrao 4:55f0c303f56a 340 }
alexhrao 4:55f0c303f56a 341 header_ind++;
alexhrao 4:55f0c303f56a 342 }
alexhrao 4:55f0c303f56a 343 break;
alexhrao 4:55f0c303f56a 344 }
alexhrao 4:55f0c303f56a 345 header_ind++;
alexhrao 4:55f0c303f56a 346 }
alexhrao 4:55f0c303f56a 347 for (footer_ind = read_len - 1; footer_ind > header_ind; footer_ind--) {
alexhrao 4:55f0c303f56a 348 if(buffer[footer_ind] == '}') {
alexhrao 4:55f0c303f56a 349 break;
alexhrao 4:55f0c303f56a 350 }
alexhrao 4:55f0c303f56a 351 }
alexhrao 4:55f0c303f56a 352 buffer[footer_ind + 1] = '\0';
alexhrao 6:ec7829f7cd38 353
alexhrao 3:7bf41989ff8f 354 MbedJSONValue parser;
alexhrao 4:55f0c303f56a 355 parse(parser, buffer + header_ind);
alexhrao 8:d323c6406b47 356
alexhrao 4:55f0c303f56a 357 latitude = parser["latitude"].get<double>();
alexhrao 3:7bf41989ff8f 358 longitude = parser["longitude"].get<double>();
alexhrao 3:7bf41989ff8f 359
alexhrao 4:55f0c303f56a 360 // Get the Time
alexhrao 4:55f0c303f56a 361 TCPSocketConnection time_tcp;
alexhrao 4:55f0c303f56a 362
alexhrao 4:55f0c303f56a 363 time_tcp.connect("api.timezonedb.com", 80);
alexhrao 6:ec7829f7cd38 364
alexhrao 4:55f0c303f56a 365 sprintf(cmd,
alexhrao 8:d323c6406b47 366 "GET /v2.1/get-time-zone?key=%s&format=json&by=position&lat=%0.4f&lng=%0.4f HTTP/1.1\r\nHost: api.timezonedb.com\r\n\r\n",
alexhrao 8:d323c6406b47 367 time_api_key,
alexhrao 8:d323c6406b47 368 latitude,
alexhrao 8:d323c6406b47 369 longitude);
alexhrao 4:55f0c303f56a 370
alexhrao 4:55f0c303f56a 371 time_tcp.send_all(cmd, strlen(cmd));
alexhrao 6:ec7829f7cd38 372
alexhrao 4:55f0c303f56a 373 wait(5);
alexhrao 6:ec7829f7cd38 374
alexhrao 4:55f0c303f56a 375 read_len = wifi.recv(buffer, BUF_SIZE - 1, 0);
alexhrao 3:7bf41989ff8f 376 buffer[read_len] = '\0';
alexhrao 8:d323c6406b47 377
alexhrao 4:55f0c303f56a 378 // Cleanup
alexhrao 8:d323c6406b47 379
alexhrao 4:55f0c303f56a 380 // Clean up front
alexhrao 4:55f0c303f56a 381 // Read through headers (\r\n\r\n)
alexhrao 4:55f0c303f56a 382 header_ind = 0;
alexhrao 4:55f0c303f56a 383 while (header_ind < read_len) {
alexhrao 4:55f0c303f56a 384 // if we are \r, look ahead to see \n\r\n:
alexhrao 4:55f0c303f56a 385 if(buffer[header_ind] == '\r' &&
alexhrao 8:d323c6406b47 386 buffer[header_ind+1] == '\n' &&
alexhrao 8:d323c6406b47 387 buffer[header_ind+2] == '\r' &&
alexhrao 8:d323c6406b47 388 buffer[header_ind+3] == '\n') {
alexhrao 4:55f0c303f56a 389 // Increment header_ind, look for JSON
alexhrao 4:55f0c303f56a 390 // Now just look for {
alexhrao 4:55f0c303f56a 391 header_ind += 4;
alexhrao 4:55f0c303f56a 392 while (header_ind < read_len) {
alexhrao 4:55f0c303f56a 393 if (buffer[header_ind] == '{') {
alexhrao 4:55f0c303f56a 394 // we got it!
alexhrao 4:55f0c303f56a 395 break;
alexhrao 4:55f0c303f56a 396 }
alexhrao 4:55f0c303f56a 397 header_ind++;
alexhrao 4:55f0c303f56a 398 }
alexhrao 4:55f0c303f56a 399 break;
alexhrao 4:55f0c303f56a 400 }
alexhrao 4:55f0c303f56a 401 header_ind++;
alexhrao 4:55f0c303f56a 402 }
alexhrao 4:55f0c303f56a 403
alexhrao 4:55f0c303f56a 404 for (footer_ind = read_len - 1; footer_ind > header_ind; footer_ind--) {
alexhrao 4:55f0c303f56a 405 if(buffer[footer_ind] == '}') {
alexhrao 4:55f0c303f56a 406 break;
alexhrao 4:55f0c303f56a 407 }
alexhrao 4:55f0c303f56a 408 }
alexhrao 4:55f0c303f56a 409 buffer[footer_ind + 1] = '\0';
alexhrao 8:d323c6406b47 410
alexhrao 4:55f0c303f56a 411 MbedJSONValue time_parser;
alexhrao 4:55f0c303f56a 412 parse(time_parser, buffer + header_ind);
alexhrao 4:55f0c303f56a 413
alexhrao 4:55f0c303f56a 414 // Add 5 so that we make up for the wait(5)
alexhrao 6:ec7829f7cd38 415 // Add 3 so that we make up for TCP request - empirically...
alexhrao 6:ec7829f7cd38 416 set_time(time_parser["timestamp"].get<int>() + 5 + 3);
alexhrao 4:55f0c303f56a 417 // Now that we know what time it is, set up our Time Thread
alexhrao 4:55f0c303f56a 418 time_thread.start(time_updater);
alexhrao 8:d323c6406b47 419
alexhrao 4:55f0c303f56a 420 TCPSocketConnection forecast_sck;
alexhrao 6:ec7829f7cd38 421
alexhrao 4:55f0c303f56a 422 forecast_sck.connect("api.openweathermap.org", 80);
alexhrao 6:ec7829f7cd38 423
alexhrao 4:55f0c303f56a 424 sprintf(cmd,
alexhrao 8:d323c6406b47 425 "GET /data/2.5/weather?lat=%0.4f&lon=%0.4f&APPID=%s&cnt=8\r\nHost: api.openweathermap.org\r\n\r\n",
alexhrao 8:d323c6406b47 426 latitude, longitude, weather_api_key);
alexhrao 4:55f0c303f56a 427 forecast_sck.send_all(cmd, strlen(cmd));
alexhrao 6:ec7829f7cd38 428
alexhrao 4:55f0c303f56a 429 wait(5);
alexhrao 4:55f0c303f56a 430
alexhrao 6:ec7829f7cd38 431 read_len wifi.recv(buffer, BUF_SIZE - 1, 0);
alexhrao 6:ec7829f7cd38 432 buffer[read_len] = '\0';
alexhrao 8:d323c6406b47 433
alexhrao 6:ec7829f7cd38 434 // We don't have enough memory for another parser (why?), so just
alexhrao 6:ec7829f7cd38 435 // look for the word "temp" 0 hopefully won't have a city named "temp"!
alexhrao 4:55f0c303f56a 436 char* ind = strstr(buffer, "temp");
alexhrao 4:55f0c303f56a 437 char num_buf[16];
alexhrao 4:55f0c303f56a 438 int num_ind = 0;
alexhrao 4:55f0c303f56a 439 // go until we find numbers
alexhrao 4:55f0c303f56a 440 while (char tmp = *ind++) {
alexhrao 4:55f0c303f56a 441 if (tmp > '0' && tmp < '9') {
alexhrao 4:55f0c303f56a 442 num_buf[num_ind++] = tmp;
alexhrao 4:55f0c303f56a 443 break;
alexhrao 4:55f0c303f56a 444 }
alexhrao 4:55f0c303f56a 445 }
alexhrao 4:55f0c303f56a 446 // Keep moving until no more numbers
alexhrao 4:55f0c303f56a 447 while (char tmp = *ind++) {
alexhrao 4:55f0c303f56a 448 if (tmp > '9' || tmp < '0') {
alexhrao 4:55f0c303f56a 449 num_buf[num_ind] = '\0';
alexhrao 4:55f0c303f56a 450 break;
alexhrao 4:55f0c303f56a 451 } else {
alexhrao 4:55f0c303f56a 452 num_buf[num_ind++] = tmp;
alexhrao 4:55f0c303f56a 453 }
alexhrao 4:55f0c303f56a 454 }
alexhrao 4:55f0c303f56a 455 int temp = atoi(num_buf);
alexhrao 4:55f0c303f56a 456 // Convert
alexhrao 6:ec7829f7cd38 457 temp = kelvin2farenheit(temp);
alexhrao 4:55f0c303f56a 458 char temp_buf[12];
alexhrao 4:55f0c303f56a 459 sprintf(temp_buf, " %dF", temp);
alexhrao 8:d323c6406b47 460
alexhrao 2:f7d19812bdc5 461 lcd_lock.lock();
alexhrao 4:55f0c303f56a 462 uLCD.text_width(2);
alexhrao 4:55f0c303f56a 463 uLCD.text_height(2);
alexhrao 4:55f0c303f56a 464 uLCD.text_string(temp_buf, 0, 5, FONT_8X8, WHITE);
alexhrao 2:f7d19812bdc5 465 lcd_lock.unlock();
alexhrao 6:ec7829f7cd38 466
alexhrao 6:ec7829f7cd38 467 time_t prev_time = time(NULL);
alexhrao 1:0620ba35d2e8 468 while(true) {
alexhrao 3:7bf41989ff8f 469 time_t curr_time = time(NULL);
alexhrao 6:ec7829f7cd38 470 // Wait for 60 seconds
alexhrao 6:ec7829f7cd38 471 if ((prev_time + 60) < curr_time) {
alexhrao 4:55f0c303f56a 472 sprintf(cmd,
alexhrao 8:d323c6406b47 473 "GET /data/2.5/weather?lat=%0.4f&lon=%0.4f&APPID=%s\r\nHost: api.openweathermap.org\r\n\r\n",
alexhrao 8:d323c6406b47 474 latitude, longitude, weather_api_key);
alexhrao 4:55f0c303f56a 475 forecast_sck.connect("api.openweathermap.org", 80);
alexhrao 4:55f0c303f56a 476 wait(10);
alexhrao 4:55f0c303f56a 477 forecast_sck.send_all(cmd, strlen(cmd));
alexhrao 4:55f0c303f56a 478 wait(5);
alexhrao 4:55f0c303f56a 479
alexhrao 6:ec7829f7cd38 480 read_len = wifi.recv(buffer, BUF_SIZE - 1, 0);
alexhrao 4:55f0c303f56a 481
alexhrao 6:ec7829f7cd38 482 buffer[read_len] = '\0';
alexhrao 4:55f0c303f56a 483
alexhrao 4:55f0c303f56a 484 ind = strstr(buffer, "temp");
alexhrao 4:55f0c303f56a 485 num_ind = 0;
alexhrao 4:55f0c303f56a 486 // go until we find numbers
alexhrao 4:55f0c303f56a 487 while (char tmp = *ind++) {
alexhrao 4:55f0c303f56a 488 if (tmp > '0' && tmp < '9') {
alexhrao 4:55f0c303f56a 489 num_buf[num_ind++] = tmp;
alexhrao 4:55f0c303f56a 490 break;
alexhrao 4:55f0c303f56a 491 }
alexhrao 4:55f0c303f56a 492 }
alexhrao 4:55f0c303f56a 493 // Keep moving until no more numbers
alexhrao 4:55f0c303f56a 494 while (char tmp = *ind++) {
alexhrao 4:55f0c303f56a 495 if (tmp > '9' || tmp < '0') {
alexhrao 4:55f0c303f56a 496 num_buf[num_ind] = '\0';
alexhrao 4:55f0c303f56a 497 break;
alexhrao 4:55f0c303f56a 498 } else {
alexhrao 4:55f0c303f56a 499 num_buf[num_ind++] = tmp;
alexhrao 4:55f0c303f56a 500 }
alexhrao 4:55f0c303f56a 501 }
alexhrao 4:55f0c303f56a 502 temp = atoi(num_buf);
alexhrao 6:ec7829f7cd38 503
alexhrao 4:55f0c303f56a 504 // Convert
alexhrao 6:ec7829f7cd38 505 temp = kelvin2farenheit(temp);
alexhrao 4:55f0c303f56a 506 sprintf(temp_buf, " %dF", temp);
alexhrao 4:55f0c303f56a 507 lcd_lock.lock();
alexhrao 4:55f0c303f56a 508 uLCD.text_width(2);
alexhrao 4:55f0c303f56a 509 uLCD.text_height(2);
alexhrao 4:55f0c303f56a 510 uLCD.text_string(temp_buf, 0, 5, FONT_8X8, WHITE);
alexhrao 4:55f0c303f56a 511 lcd_lock.unlock();
alexhrao 3:7bf41989ff8f 512 }
alexhrao 0:4ffa136585a2 513 }
alexhrao 0:4ffa136585a2 514 }
alexhrao 4:55f0c303f56a 515
alexhrao 8:d323c6406b47 516 int main()
alexhrao 8:d323c6406b47 517 {
alexhrao 4:55f0c303f56a 518 clock_init();
alexhrao 4:55f0c303f56a 519 }