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