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:
Sat May 18 17:57:20 2019 +0000
Revision:
10:16356570821e
Parent:
9:299eb69af04e
Child:
11:643f66b447b8
Cleanup

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 10:16356570821e 89 while (ind < 1023) {
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 10:16356570821e 100 if (strcmp(buf, "reset wifi") == 0) {
alexhrao 10:16356570821e 101 dev.printf("Are you sure? y/[n]\n");
alexhrao 10:16356570821e 102 if (dev.getc() == 'y') {
alexhrao 10:16356570821e 103 // Remove the WIFI.TXT file
alexhrao 10:16356570821e 104 remove("/local/wifi.txt");
alexhrao 10:16356570821e 105 mbed_reset();
alexhrao 10:16356570821e 106 }
alexhrao 10:16356570821e 107 } else if (strcmp(buf, "reset api") == 0) {
alexhrao 1:0620ba35d2e8 108 dev.printf("Are you sure? y/[n]\n");
alexhrao 10:16356570821e 109 if (dev.getc() == 'y') {
alexhrao 10:16356570821e 110 // Remove api_keys.txt
alexhrao 10:16356570821e 111 remove("/local/api_keys.txt");
alexhrao 10:16356570821e 112 mbed_reset();
alexhrao 10:16356570821e 113 }
alexhrao 10:16356570821e 114 } else if (strcmp(buf, "info") == 0) {
alexhrao 10:16356570821e 115 // Print basic info
alexhrao 10:16356570821e 116 dev.printf("WiFi Connected with Address %s\r\n",
alexhrao 10:16356570821e 117 wifi.getIPAddress());
alexhrao 10:16356570821e 118 time_t curr_time = time(NULL);
alexhrao 10:16356570821e 119 dev.printf("Current Time: %s\r\n", ctime(&curr_time));
alexhrao 1:0620ba35d2e8 120 }
alexhrao 1:0620ba35d2e8 121 buf[0] = '\0';
alexhrao 1:0620ba35d2e8 122 ind = 0;
alexhrao 1:0620ba35d2e8 123 Thread::wait(0.01);
alexhrao 1:0620ba35d2e8 124 }
alexhrao 2:f7d19812bdc5 125 }
alexhrao 0:4ffa136585a2 126
alexhrao 8:d323c6406b47 127 int kelvin2farenheit(int temp)
alexhrao 8:d323c6406b47 128 {
alexhrao 8:d323c6406b47 129 return (int)((((temp - 273.15f) * 9.0f) / 5.0f) + 32.0f);
alexhrao 4:55f0c303f56a 130 }
alexhrao 4:55f0c303f56a 131
alexhrao 8:d323c6406b47 132 void clock_init()
alexhrao 8:d323c6406b47 133 {
alexhrao 1:0620ba35d2e8 134 // Set up bluetooth
alexhrao 1:0620ba35d2e8 135 dev.baud(9600);
alexhrao 1:0620ba35d2e8 136 pc.baud(9600);
alexhrao 8:d323c6406b47 137
alexhrao 1:0620ba35d2e8 138 // Tell user we're initializing...
alexhrao 1:0620ba35d2e8 139 lcd_lock.lock();
alexhrao 1:0620ba35d2e8 140 uLCD.cls();
alexhrao 1:0620ba35d2e8 141 uLCD.text_height(2);
alexhrao 6:ec7829f7cd38 142 uLCD.text_width(2);
alexhrao 6:ec7829f7cd38 143 uLCD.text_string("PLEASE", 0, 2, FONT_7X8, WHITE);
alexhrao 6:ec7829f7cd38 144 uLCD.text_string("WAIT", 0, 5, FONT_7X8, WHITE);
alexhrao 1:0620ba35d2e8 145 lcd_lock.unlock();
alexhrao 8:d323c6406b47 146
alexhrao 1:0620ba35d2e8 147 // Need to get wifi settings. If we don't have local file, then ask!
alexhrao 10:16356570821e 148 FILE* fid = fopen("/local/api_keys.txt", "r");
alexhrao 10:16356570821e 149 char settings_buf[1024];
alexhrao 10:16356570821e 150 int settings_ind = 0;
alexhrao 10:16356570821e 151 int counter = 0;
alexhrao 10:16356570821e 152 if (fid == NULL) {
alexhrao 10:16356570821e 153 lcd_lock.lock();
alexhrao 10:16356570821e 154 uLCD.cls();
alexhrao 10:16356570821e 155 uLCD.text_height(2);
alexhrao 10:16356570821e 156 uLCD.text_width(2);
alexhrao 10:16356570821e 157 uLCD.text_string("SEE", 0, 2, FONT_7X8, RED);
alexhrao 10:16356570821e 158 uLCD.text_string("DEVICE", 0, 5, FONT_7X8, RED);
alexhrao 10:16356570821e 159 lcd_lock.unlock();
alexhrao 10:16356570821e 160 // Ask
alexhrao 10:16356570821e 161 // Get the API key
alexhrao 10:16356570821e 162 dev.printf("Please provide the IP Stack API key\n");
alexhrao 10:16356570821e 163 while (!dev.readable()) {
alexhrao 10:16356570821e 164 wait(0.001);
alexhrao 10:16356570821e 165 }
alexhrao 10:16356570821e 166 int ind = 0;
alexhrao 10:16356570821e 167 while (ind < 255) {
alexhrao 10:16356570821e 168 char tmp = dev.getc();
alexhrao 10:16356570821e 169 if (tmp == '\n' || tmp == '\r') {
alexhrao 10:16356570821e 170 break;
alexhrao 10:16356570821e 171 }
alexhrao 10:16356570821e 172 ip_api_key[ind++] = tmp;
alexhrao 10:16356570821e 173 wait(0.01);
alexhrao 10:16356570821e 174 }
alexhrao 10:16356570821e 175
alexhrao 10:16356570821e 176 ip_api_key[ind] = '\0';
alexhrao 8:d323c6406b47 177
alexhrao 10:16356570821e 178 dev.printf("Please provide the TimeZoneDB API key\n");
alexhrao 10:16356570821e 179 while (!dev.readable()) {
alexhrao 10:16356570821e 180 wait(0.001);
alexhrao 10:16356570821e 181 }
alexhrao 10:16356570821e 182 ind = 0;
alexhrao 10:16356570821e 183 while (ind < 255) {
alexhrao 10:16356570821e 184 char tmp = dev.getc();
alexhrao 10:16356570821e 185 if (tmp == '\r' || tmp == '\n') {
alexhrao 10:16356570821e 186 break;
alexhrao 10:16356570821e 187 }
alexhrao 10:16356570821e 188 time_api_key[ind++] = tmp;
alexhrao 10:16356570821e 189 wait(0.01);
alexhrao 2:f7d19812bdc5 190 }
alexhrao 10:16356570821e 191 time_api_key[ind] = '\0';
alexhrao 10:16356570821e 192
alexhrao 10:16356570821e 193 dev.printf("Please provide the OpenWeather API key\n");
alexhrao 10:16356570821e 194 while (!dev.readable()) {
alexhrao 10:16356570821e 195 wait(0.001);
alexhrao 2:f7d19812bdc5 196 }
alexhrao 10:16356570821e 197 ind = 0;
alexhrao 10:16356570821e 198 while (ind < 255) {
alexhrao 10:16356570821e 199 char tmp = dev.getc();
alexhrao 10:16356570821e 200 if (tmp == '\r' || tmp == '\n') {
alexhrao 10:16356570821e 201 break;
alexhrao 10:16356570821e 202 }
alexhrao 10:16356570821e 203 weather_api_key[ind++] = tmp;
alexhrao 10:16356570821e 204 wait(0.01);
alexhrao 10:16356570821e 205 }
alexhrao 10:16356570821e 206 weather_api_key[ind] = '\0';
alexhrao 10:16356570821e 207 // Create file
alexhrao 10:16356570821e 208 fid = fopen("/local/api_keys.txt", "w");
alexhrao 10:16356570821e 209 fprintf(fid, "%s\n%s\n%s\n", ip_api_key, time_api_key, weather_api_key);
alexhrao 10:16356570821e 210 fclose(fid);
alexhrao 10:16356570821e 211 } else {
alexhrao 10:16356570821e 212 // Read from file
alexhrao 4:55f0c303f56a 213 fgets(settings_buf, 1024, fid);
alexhrao 4:55f0c303f56a 214 counter = 0;
alexhrao 4:55f0c303f56a 215 while (settings_buf[counter] != '\n') {
alexhrao 4:55f0c303f56a 216 ip_api_key[settings_ind++] = settings_buf[counter++];
alexhrao 4:55f0c303f56a 217 }
alexhrao 4:55f0c303f56a 218 ip_api_key[settings_ind] = '\0';
alexhrao 4:55f0c303f56a 219 settings_ind = 0;
alexhrao 4:55f0c303f56a 220 fgets(settings_buf, 1024, fid);
alexhrao 4:55f0c303f56a 221 counter = 0;
alexhrao 2:f7d19812bdc5 222 while (settings_buf[counter] != '\n') {
alexhrao 4:55f0c303f56a 223 time_api_key[settings_ind++] = settings_buf[counter++];
alexhrao 2:f7d19812bdc5 224 }
alexhrao 4:55f0c303f56a 225 time_api_key[settings_ind] = '\0';
alexhrao 4:55f0c303f56a 226 settings_ind = 0;
alexhrao 4:55f0c303f56a 227 fgets(settings_buf, 1024, fid);
alexhrao 4:55f0c303f56a 228 counter = 0;
alexhrao 4:55f0c303f56a 229 while (settings_buf[counter] != '\n') {
alexhrao 4:55f0c303f56a 230 weather_api_key[settings_ind++] = settings_buf[counter++];
alexhrao 4:55f0c303f56a 231 }
alexhrao 4:55f0c303f56a 232 weather_api_key[settings_ind] = '\0';
alexhrao 2:f7d19812bdc5 233 fclose(fid);
alexhrao 10:16356570821e 234 }
alexhrao 10:16356570821e 235
alexhrao 10:16356570821e 236 fid = fopen("/local/wifi.txt", "r");
alexhrao 10:16356570821e 237
alexhrao 10:16356570821e 238 if (fid != NULL) {
alexhrao 10:16356570821e 239 // Read WiFi Settings
alexhrao 10:16356570821e 240 // Guaranteed to be 2 lines
alexhrao 10:16356570821e 241 //
alexhrao 10:16356570821e 242 fgets(settings_buf, 1024, fid);
alexhrao 10:16356570821e 243 // find \n
alexhrao 10:16356570821e 244 settings_ind = 0;
alexhrao 10:16356570821e 245 counter = 0;
alexhrao 10:16356570821e 246 while (settings_buf[counter] != '\n') {
alexhrao 10:16356570821e 247 ssid[settings_ind++] = settings_buf[counter++];
alexhrao 10:16356570821e 248 }
alexhrao 10:16356570821e 249 ssid[settings_ind] = '\0';
alexhrao 10:16356570821e 250 settings_ind = 0;
alexhrao 10:16356570821e 251 fgets(settings_buf, 1024, fid);
alexhrao 10:16356570821e 252 counter = 0;
alexhrao 10:16356570821e 253 while (settings_buf[counter] != '\n') {
alexhrao 10:16356570821e 254 pass[settings_ind++] = settings_buf[counter++];
alexhrao 10:16356570821e 255 }
alexhrao 10:16356570821e 256 pass[settings_ind] = '\0';
alexhrao 10:16356570821e 257 fclose(fid);
alexhrao 1:0620ba35d2e8 258 } else {
alexhrao 1:0620ba35d2e8 259 lcd_lock.lock();
alexhrao 1:0620ba35d2e8 260 uLCD.cls();
alexhrao 1:0620ba35d2e8 261 uLCD.text_height(2);
alexhrao 1:0620ba35d2e8 262 uLCD.text_width(2);
alexhrao 1:0620ba35d2e8 263 uLCD.text_string("SEE", 0, 2, FONT_7X8, RED);
alexhrao 1:0620ba35d2e8 264 uLCD.text_string("DEVICE", 0, 5, FONT_7X8, RED);
alexhrao 1:0620ba35d2e8 265 lcd_lock.unlock();
alexhrao 8:d323c6406b47 266
alexhrao 1:0620ba35d2e8 267 // Ask!
alexhrao 1:0620ba35d2e8 268 dev.printf("Please provide the name of a WiFi Network\n");
alexhrao 8:d323c6406b47 269
alexhrao 1:0620ba35d2e8 270 // Wait for them to respond
alexhrao 1:0620ba35d2e8 271 while (!dev.readable()) {
alexhrao 1:0620ba35d2e8 272 wait(0.001);
alexhrao 1:0620ba35d2e8 273 }
alexhrao 1:0620ba35d2e8 274 int ind = 0;
alexhrao 8:d323c6406b47 275
alexhrao 1:0620ba35d2e8 276 // Read response
alexhrao 1:0620ba35d2e8 277 while (ind < 255) {
alexhrao 1:0620ba35d2e8 278 char tmp = dev.getc();
alexhrao 1:0620ba35d2e8 279 if (tmp == '\n' || tmp == '\r') {
alexhrao 1:0620ba35d2e8 280 break;
alexhrao 1:0620ba35d2e8 281 }
alexhrao 1:0620ba35d2e8 282 ssid[ind++] = tmp;
alexhrao 1:0620ba35d2e8 283 wait(0.01);
alexhrao 1:0620ba35d2e8 284 }
alexhrao 1:0620ba35d2e8 285 ssid[ind] = '\0';
alexhrao 8:d323c6406b47 286
alexhrao 1:0620ba35d2e8 287 // flush device
alexhrao 1:0620ba35d2e8 288 while (dev.readable()) {
alexhrao 1:0620ba35d2e8 289 dev.getc();
alexhrao 1:0620ba35d2e8 290 wait(0.01);
alexhrao 1:0620ba35d2e8 291 }
alexhrao 8:d323c6406b47 292
alexhrao 2:f7d19812bdc5 293 // Get the password
alexhrao 1:0620ba35d2e8 294 dev.printf("Please provide the password\n");
alexhrao 1:0620ba35d2e8 295 while (!dev.readable()) {
alexhrao 1:0620ba35d2e8 296 wait(0.001);
alexhrao 1:0620ba35d2e8 297 }
alexhrao 1:0620ba35d2e8 298 ind = 0;
alexhrao 1:0620ba35d2e8 299 while (ind < 255) {
alexhrao 1:0620ba35d2e8 300 char tmp = dev.getc();
alexhrao 1:0620ba35d2e8 301 if (tmp == '\n' || tmp == '\r') {
alexhrao 1:0620ba35d2e8 302 break;
alexhrao 1:0620ba35d2e8 303 }
alexhrao 1:0620ba35d2e8 304 pass[ind++] = tmp;
alexhrao 1:0620ba35d2e8 305 wait(0.01);
alexhrao 1:0620ba35d2e8 306 }
alexhrao 1:0620ba35d2e8 307 pass[ind] = '\0';
alexhrao 8:d323c6406b47 308 // Because this is a simple proof of concept, we store the password in
alexhrao 8:d323c6406b47 309 // plaintext. It should be noted, however, that you **should never do
alexhrao 1:0620ba35d2e8 310 // this in "real life"**
alexhrao 10:16356570821e 311 fid = fopen("/local/wifi.txt", "w");
alexhrao 10:16356570821e 312 fprintf(fid, "%s\n%s\n", ssid, pass);
alexhrao 4:55f0c303f56a 313 fclose(fid);
alexhrao 1:0620ba35d2e8 314 }
alexhrao 6:ec7829f7cd38 315 /*
alexhrao 4:55f0c303f56a 316 dev.printf("\r\n** CREDENTIALS **\r\n");
alexhrao 4:55f0c303f56a 317 dev.printf("SSID: **%s** (%d)\r\n", ssid, strlen(ssid));
alexhrao 4:55f0c303f56a 318 dev.printf("PASS: **%s** (%d)\r\n", pass, strlen(pass));
alexhrao 4:55f0c303f56a 319 dev.printf("IP STACK: **%s**\r\n", ip_api_key);
alexhrao 4:55f0c303f56a 320 dev.printf("TIMEZONEDB: **%s**\r\n", time_api_key);
alexhrao 4:55f0c303f56a 321 dev.printf("WEATHERMAP: **%s**\r\n", weather_api_key);
alexhrao 6:ec7829f7cd38 322 */
alexhrao 1:0620ba35d2e8 323 bool res = wifi.init();
alexhrao 4:55f0c303f56a 324
alexhrao 1:0620ba35d2e8 325 // Set up the WiFi Access Point
alexhrao 1:0620ba35d2e8 326 dev.printf("Connecting to WiFi %s with Password %s\n", ssid, pass);
alexhrao 8:d323c6406b47 327
alexhrao 5:b77a717feada 328 res = wifi.connect(ssid, pass);
alexhrao 2:f7d19812bdc5 329 if (!res) {
alexhrao 2:f7d19812bdc5 330 dev.printf("Connection Failed... Resetting Device\n");
alexhrao 2:f7d19812bdc5 331 err_led = 1;
alexhrao 2:f7d19812bdc5 332 mbed_reset();
alexhrao 2:f7d19812bdc5 333 }
alexhrao 8:d323c6406b47 334
alexhrao 2:f7d19812bdc5 335 dev.printf("Connected with IP Address: %s\n", wifi.getIPAddress());
alexhrao 8:d323c6406b47 336
alexhrao 4:55f0c303f56a 337 /** API REQUESTS **/
alexhrao 8:d323c6406b47 338
alexhrao 4:55f0c303f56a 339 int header_ind = 0;
alexhrao 4:55f0c303f56a 340 int footer_ind = 0;
alexhrao 4:55f0c303f56a 341 int read_len = 0;
alexhrao 4:55f0c303f56a 342 char buffer[BUF_SIZE];
alexhrao 4:55f0c303f56a 343 char cmd[512];
alexhrao 4:55f0c303f56a 344
alexhrao 3:7bf41989ff8f 345 TCPSocketConnection tcp;
alexhrao 3:7bf41989ff8f 346 tcp.connect("api.ipstack.com", 80);
alexhrao 8:d323c6406b47 347
alexhrao 8:d323c6406b47 348 sprintf(cmd,
alexhrao 8:d323c6406b47 349 "GET /check?access_key=%s HTTP/1.1\r\nHost: api.ipstack.com\r\n\r\n",
alexhrao 8:d323c6406b47 350 ip_api_key);
alexhrao 4:55f0c303f56a 351 tcp.send_all(cmd, strlen(cmd));
alexhrao 8:d323c6406b47 352
alexhrao 4:55f0c303f56a 353 wait(5);
alexhrao 8:d323c6406b47 354
alexhrao 4:55f0c303f56a 355 read_len = wifi.recv(buffer, BUF_SIZE - 1, 0);
alexhrao 3:7bf41989ff8f 356 buffer[read_len] = '\0';
alexhrao 8:d323c6406b47 357
alexhrao 4:55f0c303f56a 358 // Cleanup
alexhrao 8:d323c6406b47 359
alexhrao 4:55f0c303f56a 360 while (header_ind < read_len) {
alexhrao 4:55f0c303f56a 361 // if we are \r, look ahead to see \n\r\n:
alexhrao 4:55f0c303f56a 362 if(buffer[header_ind] == '\r' &&
alexhrao 8:d323c6406b47 363 buffer[header_ind+1] == '\n' &&
alexhrao 8:d323c6406b47 364 buffer[header_ind+2] == '\r' &&
alexhrao 8:d323c6406b47 365 buffer[header_ind+3] == '\n') {
alexhrao 4:55f0c303f56a 366 // Increment header_ind, look for JSON
alexhrao 4:55f0c303f56a 367 // Now just look for {
alexhrao 4:55f0c303f56a 368 header_ind += 4;
alexhrao 4:55f0c303f56a 369 while (header_ind < read_len) {
alexhrao 4:55f0c303f56a 370 if (buffer[header_ind] == '{') {
alexhrao 4:55f0c303f56a 371 // we got it!
alexhrao 4:55f0c303f56a 372 break;
alexhrao 4:55f0c303f56a 373 }
alexhrao 4:55f0c303f56a 374 header_ind++;
alexhrao 4:55f0c303f56a 375 }
alexhrao 4:55f0c303f56a 376 break;
alexhrao 4:55f0c303f56a 377 }
alexhrao 4:55f0c303f56a 378 header_ind++;
alexhrao 4:55f0c303f56a 379 }
alexhrao 4:55f0c303f56a 380 for (footer_ind = read_len - 1; footer_ind > header_ind; footer_ind--) {
alexhrao 4:55f0c303f56a 381 if(buffer[footer_ind] == '}') {
alexhrao 4:55f0c303f56a 382 break;
alexhrao 4:55f0c303f56a 383 }
alexhrao 4:55f0c303f56a 384 }
alexhrao 4:55f0c303f56a 385 buffer[footer_ind + 1] = '\0';
alexhrao 6:ec7829f7cd38 386
alexhrao 9:299eb69af04e 387 MbedJSONValue* parser = new MbedJSONValue();
alexhrao 9:299eb69af04e 388 parse(*parser, buffer + header_ind);
alexhrao 8:d323c6406b47 389
alexhrao 9:299eb69af04e 390 latitude = (*parser)["latitude"].get<double>();
alexhrao 9:299eb69af04e 391 longitude = (*parser)["longitude"].get<double>();
alexhrao 9:299eb69af04e 392 delete(parser);
alexhrao 4:55f0c303f56a 393 // Get the Time
alexhrao 4:55f0c303f56a 394 TCPSocketConnection time_tcp;
alexhrao 4:55f0c303f56a 395
alexhrao 4:55f0c303f56a 396 time_tcp.connect("api.timezonedb.com", 80);
alexhrao 6:ec7829f7cd38 397
alexhrao 4:55f0c303f56a 398 sprintf(cmd,
alexhrao 8:d323c6406b47 399 "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 400 time_api_key,
alexhrao 8:d323c6406b47 401 latitude,
alexhrao 8:d323c6406b47 402 longitude);
alexhrao 4:55f0c303f56a 403
alexhrao 4:55f0c303f56a 404 time_tcp.send_all(cmd, strlen(cmd));
alexhrao 6:ec7829f7cd38 405
alexhrao 4:55f0c303f56a 406 wait(5);
alexhrao 6:ec7829f7cd38 407
alexhrao 4:55f0c303f56a 408 read_len = wifi.recv(buffer, BUF_SIZE - 1, 0);
alexhrao 3:7bf41989ff8f 409 buffer[read_len] = '\0';
alexhrao 8:d323c6406b47 410
alexhrao 4:55f0c303f56a 411 // Cleanup
alexhrao 8:d323c6406b47 412
alexhrao 4:55f0c303f56a 413 // Clean up front
alexhrao 4:55f0c303f56a 414 // Read through headers (\r\n\r\n)
alexhrao 4:55f0c303f56a 415 header_ind = 0;
alexhrao 4:55f0c303f56a 416 while (header_ind < read_len) {
alexhrao 4:55f0c303f56a 417 // if we are \r, look ahead to see \n\r\n:
alexhrao 4:55f0c303f56a 418 if(buffer[header_ind] == '\r' &&
alexhrao 8:d323c6406b47 419 buffer[header_ind+1] == '\n' &&
alexhrao 8:d323c6406b47 420 buffer[header_ind+2] == '\r' &&
alexhrao 8:d323c6406b47 421 buffer[header_ind+3] == '\n') {
alexhrao 4:55f0c303f56a 422 // Increment header_ind, look for JSON
alexhrao 4:55f0c303f56a 423 // Now just look for {
alexhrao 4:55f0c303f56a 424 header_ind += 4;
alexhrao 4:55f0c303f56a 425 while (header_ind < read_len) {
alexhrao 4:55f0c303f56a 426 if (buffer[header_ind] == '{') {
alexhrao 4:55f0c303f56a 427 // we got it!
alexhrao 4:55f0c303f56a 428 break;
alexhrao 4:55f0c303f56a 429 }
alexhrao 4:55f0c303f56a 430 header_ind++;
alexhrao 4:55f0c303f56a 431 }
alexhrao 4:55f0c303f56a 432 break;
alexhrao 4:55f0c303f56a 433 }
alexhrao 4:55f0c303f56a 434 header_ind++;
alexhrao 4:55f0c303f56a 435 }
alexhrao 4:55f0c303f56a 436
alexhrao 4:55f0c303f56a 437 for (footer_ind = read_len - 1; footer_ind > header_ind; footer_ind--) {
alexhrao 4:55f0c303f56a 438 if(buffer[footer_ind] == '}') {
alexhrao 4:55f0c303f56a 439 break;
alexhrao 4:55f0c303f56a 440 }
alexhrao 4:55f0c303f56a 441 }
alexhrao 4:55f0c303f56a 442 buffer[footer_ind + 1] = '\0';
alexhrao 9:299eb69af04e 443 parser = new MbedJSONValue();
alexhrao 9:299eb69af04e 444 parse(*parser, buffer + header_ind);
alexhrao 4:55f0c303f56a 445
alexhrao 4:55f0c303f56a 446 // Add 5 so that we make up for the wait(5)
alexhrao 6:ec7829f7cd38 447 // Add 3 so that we make up for TCP request - empirically...
alexhrao 9:299eb69af04e 448 set_time((*parser)["timestamp"].get<int>() + 5 + 3);
alexhrao 9:299eb69af04e 449 delete(parser);
alexhrao 9:299eb69af04e 450 lcd_lock.lock();
alexhrao 9:299eb69af04e 451 uLCD.cls();
alexhrao 9:299eb69af04e 452 lcd_lock.unlock();
alexhrao 4:55f0c303f56a 453 // Now that we know what time it is, set up our Time Thread
alexhrao 4:55f0c303f56a 454 time_thread.start(time_updater);
alexhrao 8:d323c6406b47 455
alexhrao 4:55f0c303f56a 456 TCPSocketConnection forecast_sck;
alexhrao 6:ec7829f7cd38 457
alexhrao 4:55f0c303f56a 458 forecast_sck.connect("api.openweathermap.org", 80);
alexhrao 6:ec7829f7cd38 459
alexhrao 4:55f0c303f56a 460 sprintf(cmd,
alexhrao 9:299eb69af04e 461 "GET /data/2.5/forecast?lat=%0.4f&lon=%0.4f&APPID=%s&cnt=1\r\nHost: api.openweathermap.org\r\n\r\n",
alexhrao 8:d323c6406b47 462 latitude, longitude, weather_api_key);
alexhrao 4:55f0c303f56a 463 forecast_sck.send_all(cmd, strlen(cmd));
alexhrao 6:ec7829f7cd38 464
alexhrao 4:55f0c303f56a 465 wait(5);
alexhrao 4:55f0c303f56a 466
alexhrao 9:299eb69af04e 467 read_len = wifi.recv(buffer, BUF_SIZE - 1, 0);
alexhrao 6:ec7829f7cd38 468 buffer[read_len] = '\0';
alexhrao 8:d323c6406b47 469
alexhrao 6:ec7829f7cd38 470 // We don't have enough memory for another parser (why?), so just
alexhrao 6:ec7829f7cd38 471 // look for the word "temp" 0 hopefully won't have a city named "temp"!
alexhrao 4:55f0c303f56a 472 char* ind = strstr(buffer, "temp");
alexhrao 4:55f0c303f56a 473 char num_buf[16];
alexhrao 4:55f0c303f56a 474 int num_ind = 0;
alexhrao 4:55f0c303f56a 475 // go until we find numbers
alexhrao 4:55f0c303f56a 476 while (char tmp = *ind++) {
alexhrao 4:55f0c303f56a 477 if (tmp > '0' && tmp < '9') {
alexhrao 4:55f0c303f56a 478 num_buf[num_ind++] = tmp;
alexhrao 4:55f0c303f56a 479 break;
alexhrao 4:55f0c303f56a 480 }
alexhrao 4:55f0c303f56a 481 }
alexhrao 4:55f0c303f56a 482 // Keep moving until no more numbers
alexhrao 4:55f0c303f56a 483 while (char tmp = *ind++) {
alexhrao 4:55f0c303f56a 484 if (tmp > '9' || tmp < '0') {
alexhrao 4:55f0c303f56a 485 num_buf[num_ind] = '\0';
alexhrao 4:55f0c303f56a 486 break;
alexhrao 4:55f0c303f56a 487 } else {
alexhrao 4:55f0c303f56a 488 num_buf[num_ind++] = tmp;
alexhrao 4:55f0c303f56a 489 }
alexhrao 4:55f0c303f56a 490 }
alexhrao 4:55f0c303f56a 491 int temp = atoi(num_buf);
alexhrao 9:299eb69af04e 492
alexhrao 4:55f0c303f56a 493 // Convert
alexhrao 6:ec7829f7cd38 494 temp = kelvin2farenheit(temp);
alexhrao 4:55f0c303f56a 495 char temp_buf[12];
alexhrao 4:55f0c303f56a 496 sprintf(temp_buf, " %dF", temp);
alexhrao 8:d323c6406b47 497
alexhrao 2:f7d19812bdc5 498 lcd_lock.lock();
alexhrao 4:55f0c303f56a 499 uLCD.text_width(2);
alexhrao 4:55f0c303f56a 500 uLCD.text_height(2);
alexhrao 4:55f0c303f56a 501 uLCD.text_string(temp_buf, 0, 5, FONT_8X8, WHITE);
alexhrao 2:f7d19812bdc5 502 lcd_lock.unlock();
alexhrao 6:ec7829f7cd38 503
alexhrao 6:ec7829f7cd38 504 time_t prev_time = time(NULL);
alexhrao 1:0620ba35d2e8 505 while(true) {
alexhrao 3:7bf41989ff8f 506 time_t curr_time = time(NULL);
alexhrao 6:ec7829f7cd38 507 // Wait for 60 seconds
alexhrao 6:ec7829f7cd38 508 if ((prev_time + 60) < curr_time) {
alexhrao 4:55f0c303f56a 509 sprintf(cmd,
alexhrao 8:d323c6406b47 510 "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 511 latitude, longitude, weather_api_key);
alexhrao 4:55f0c303f56a 512 forecast_sck.connect("api.openweathermap.org", 80);
alexhrao 4:55f0c303f56a 513 wait(10);
alexhrao 4:55f0c303f56a 514 forecast_sck.send_all(cmd, strlen(cmd));
alexhrao 4:55f0c303f56a 515 wait(5);
alexhrao 4:55f0c303f56a 516
alexhrao 6:ec7829f7cd38 517 read_len = wifi.recv(buffer, BUF_SIZE - 1, 0);
alexhrao 4:55f0c303f56a 518
alexhrao 6:ec7829f7cd38 519 buffer[read_len] = '\0';
alexhrao 4:55f0c303f56a 520
alexhrao 4:55f0c303f56a 521 ind = strstr(buffer, "temp");
alexhrao 4:55f0c303f56a 522 num_ind = 0;
alexhrao 4:55f0c303f56a 523 // go until we find numbers
alexhrao 4:55f0c303f56a 524 while (char tmp = *ind++) {
alexhrao 4:55f0c303f56a 525 if (tmp > '0' && tmp < '9') {
alexhrao 4:55f0c303f56a 526 num_buf[num_ind++] = tmp;
alexhrao 4:55f0c303f56a 527 break;
alexhrao 4:55f0c303f56a 528 }
alexhrao 4:55f0c303f56a 529 }
alexhrao 4:55f0c303f56a 530 // Keep moving until no more numbers
alexhrao 4:55f0c303f56a 531 while (char tmp = *ind++) {
alexhrao 4:55f0c303f56a 532 if (tmp > '9' || tmp < '0') {
alexhrao 4:55f0c303f56a 533 num_buf[num_ind] = '\0';
alexhrao 4:55f0c303f56a 534 break;
alexhrao 4:55f0c303f56a 535 } else {
alexhrao 4:55f0c303f56a 536 num_buf[num_ind++] = tmp;
alexhrao 4:55f0c303f56a 537 }
alexhrao 4:55f0c303f56a 538 }
alexhrao 4:55f0c303f56a 539 temp = atoi(num_buf);
alexhrao 6:ec7829f7cd38 540
alexhrao 4:55f0c303f56a 541 // Convert
alexhrao 6:ec7829f7cd38 542 temp = kelvin2farenheit(temp);
alexhrao 4:55f0c303f56a 543 sprintf(temp_buf, " %dF", temp);
alexhrao 4:55f0c303f56a 544 lcd_lock.lock();
alexhrao 4:55f0c303f56a 545 uLCD.text_width(2);
alexhrao 4:55f0c303f56a 546 uLCD.text_height(2);
alexhrao 4:55f0c303f56a 547 uLCD.text_string(temp_buf, 0, 5, FONT_8X8, WHITE);
alexhrao 4:55f0c303f56a 548 lcd_lock.unlock();
alexhrao 3:7bf41989ff8f 549 }
alexhrao 0:4ffa136585a2 550 }
alexhrao 0:4ffa136585a2 551 }
alexhrao 4:55f0c303f56a 552
alexhrao 8:d323c6406b47 553 int main()
alexhrao 8:d323c6406b47 554 {
alexhrao 4:55f0c303f56a 555 clock_init();
alexhrao 4:55f0c303f56a 556 }