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:36:49 2019 +0000
Revision:
13:65946a58123e
Parent:
12:513a0fd7c426
Make new node off by default

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