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:
Sun Mar 31 15:39:50 2019 +0000
Revision:
4:55f0c303f56a
Parent:
3:7bf41989ff8f
Child:
5:b77a717feada
Add credentials

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