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:
Fri May 24 23:19:29 2019 +0000
Revision:
11:643f66b447b8
Parent:
10:16356570821e
Child:
12:513a0fd7c426
Add limited support for the new lua interpreter

Who changed what in which revision?

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