![](/media/cache/img/default_profile.jpg.50x50_q85.jpg)
Fork from Alex
Dependencies: mbed MbedJSONValue mbed-rtos 4DGL-uLCD-SE ESP8266NodeMCUInterface
main.cpp
- Committer:
- alexhrao
- Date:
- 2019-05-18
- Revision:
- 10:16356570821e
- Parent:
- 9:299eb69af04e
File content as of revision 10:16356570821e:
#include "mbed.h" #include "uLCD_4DGL.h" #include "ESP8266Interface.h" #include "TCPSocketConnection.h" #include "rtos.h" #include "MbedJSONValue.h" #include <string> #define BUF_SIZE 4096 // We need this for being able to reset the MBED (similar to watch dogs) extern "C" void mbed_reset(); // LCD Screen uLCD_4DGL uLCD(p9, p10, p11); Mutex lcd_lock; // File System LocalFileSystem fs("local"); // Bluetooth RawSerial pc(USBTX, USBRX); RawSerial dev(p28,p27); // Error LED DigitalOut err_led(LED1); // WiFi ESP8266Interface wifi(p13, p14, p15, 9600, 10000); // Time Thread time_thread; // Location double latitude = 0; double longitude = 0; // Credentials char ssid[256]; char pass[256]; char ip_api_key[256]; char time_api_key[256]; char weather_api_key[256]; void time_updater() { // We're not an interrupt, so take as much time as we need. Infinite loop // but wait 1 second between each loop struct tm* ltm; time_t now; now = time(NULL); ltm = localtime(&now); // Buffer for time string. Max length is 23:59 + \0 int max_time_len = 8; char ftime[max_time_len]; ftime[0] = ' '; ftime[1] = ' '; int min = -1; while (true) { // if the minute has changed, update. now = time(NULL); ltm = localtime(&now); if(ltm->tm_min != min) { // Get the new time strftime(ftime + 2, max_time_len, "%H:%M", ltm); // Update time! Lock the lcd mutex lcd_lock.lock(); uLCD.text_width(2); uLCD.text_height(2); uLCD.text_string(ftime, 0, 2, FONT_8X8, GREEN); // Done updating - unlock! lcd_lock.unlock(); min = ltm->tm_min; } // Wait 1 second Thread::wait(1.0f); } } void dev_recv() { // Continually check if we have stuff... char buf[1024]; int ind = 0; while (true) { while (ind < 1023) { // get stuff. If we encounter \r or \n, that's a complete command! char tmp = dev.getc(); if (tmp == '\n' || tmp == '\r') { break; } buf[ind++] = tmp; Thread::wait(0.01); } buf[ind] = '\0'; // read command and respond if (strcmp(buf, "reset wifi") == 0) { dev.printf("Are you sure? y/[n]\n"); if (dev.getc() == 'y') { // Remove the WIFI.TXT file remove("/local/wifi.txt"); mbed_reset(); } } else if (strcmp(buf, "reset api") == 0) { dev.printf("Are you sure? y/[n]\n"); if (dev.getc() == 'y') { // Remove api_keys.txt remove("/local/api_keys.txt"); mbed_reset(); } } else if (strcmp(buf, "info") == 0) { // Print basic info dev.printf("WiFi Connected with Address %s\r\n", wifi.getIPAddress()); time_t curr_time = time(NULL); dev.printf("Current Time: %s\r\n", ctime(&curr_time)); } buf[0] = '\0'; ind = 0; Thread::wait(0.01); } } int kelvin2farenheit(int temp) { return (int)((((temp - 273.15f) * 9.0f) / 5.0f) + 32.0f); } void clock_init() { // Set up bluetooth dev.baud(9600); pc.baud(9600); // Tell user we're initializing... lcd_lock.lock(); uLCD.cls(); uLCD.text_height(2); uLCD.text_width(2); uLCD.text_string("PLEASE", 0, 2, FONT_7X8, WHITE); uLCD.text_string("WAIT", 0, 5, FONT_7X8, WHITE); lcd_lock.unlock(); // Need to get wifi settings. If we don't have local file, then ask! FILE* fid = fopen("/local/api_keys.txt", "r"); char settings_buf[1024]; int settings_ind = 0; int counter = 0; if (fid == NULL) { lcd_lock.lock(); uLCD.cls(); uLCD.text_height(2); uLCD.text_width(2); uLCD.text_string("SEE", 0, 2, FONT_7X8, RED); uLCD.text_string("DEVICE", 0, 5, FONT_7X8, RED); lcd_lock.unlock(); // Ask // Get the API key dev.printf("Please provide the IP Stack API key\n"); while (!dev.readable()) { wait(0.001); } int ind = 0; while (ind < 255) { char tmp = dev.getc(); if (tmp == '\n' || tmp == '\r') { break; } ip_api_key[ind++] = tmp; wait(0.01); } ip_api_key[ind] = '\0'; dev.printf("Please provide the TimeZoneDB API key\n"); while (!dev.readable()) { wait(0.001); } ind = 0; while (ind < 255) { char tmp = dev.getc(); if (tmp == '\r' || tmp == '\n') { break; } time_api_key[ind++] = tmp; wait(0.01); } time_api_key[ind] = '\0'; dev.printf("Please provide the OpenWeather API key\n"); while (!dev.readable()) { wait(0.001); } ind = 0; while (ind < 255) { char tmp = dev.getc(); if (tmp == '\r' || tmp == '\n') { break; } weather_api_key[ind++] = tmp; wait(0.01); } weather_api_key[ind] = '\0'; // Create file fid = fopen("/local/api_keys.txt", "w"); fprintf(fid, "%s\n%s\n%s\n", ip_api_key, time_api_key, weather_api_key); fclose(fid); } else { // Read from file fgets(settings_buf, 1024, fid); counter = 0; while (settings_buf[counter] != '\n') { ip_api_key[settings_ind++] = settings_buf[counter++]; } ip_api_key[settings_ind] = '\0'; settings_ind = 0; fgets(settings_buf, 1024, fid); counter = 0; while (settings_buf[counter] != '\n') { time_api_key[settings_ind++] = settings_buf[counter++]; } time_api_key[settings_ind] = '\0'; settings_ind = 0; fgets(settings_buf, 1024, fid); counter = 0; while (settings_buf[counter] != '\n') { weather_api_key[settings_ind++] = settings_buf[counter++]; } weather_api_key[settings_ind] = '\0'; fclose(fid); } fid = fopen("/local/wifi.txt", "r"); if (fid != NULL) { // Read WiFi Settings // Guaranteed to be 2 lines // fgets(settings_buf, 1024, fid); // find \n settings_ind = 0; counter = 0; while (settings_buf[counter] != '\n') { ssid[settings_ind++] = settings_buf[counter++]; } ssid[settings_ind] = '\0'; settings_ind = 0; fgets(settings_buf, 1024, fid); counter = 0; while (settings_buf[counter] != '\n') { pass[settings_ind++] = settings_buf[counter++]; } pass[settings_ind] = '\0'; fclose(fid); } else { lcd_lock.lock(); uLCD.cls(); uLCD.text_height(2); uLCD.text_width(2); uLCD.text_string("SEE", 0, 2, FONT_7X8, RED); uLCD.text_string("DEVICE", 0, 5, FONT_7X8, RED); lcd_lock.unlock(); // Ask! dev.printf("Please provide the name of a WiFi Network\n"); // Wait for them to respond while (!dev.readable()) { wait(0.001); } int ind = 0; // Read response while (ind < 255) { char tmp = dev.getc(); if (tmp == '\n' || tmp == '\r') { break; } ssid[ind++] = tmp; wait(0.01); } ssid[ind] = '\0'; // flush device while (dev.readable()) { dev.getc(); wait(0.01); } // Get the password dev.printf("Please provide the password\n"); while (!dev.readable()) { wait(0.001); } ind = 0; while (ind < 255) { char tmp = dev.getc(); if (tmp == '\n' || tmp == '\r') { break; } pass[ind++] = tmp; wait(0.01); } pass[ind] = '\0'; // Because this is a simple proof of concept, we store the password in // plaintext. It should be noted, however, that you **should never do // this in "real life"** fid = fopen("/local/wifi.txt", "w"); fprintf(fid, "%s\n%s\n", ssid, pass); fclose(fid); } /* dev.printf("\r\n** CREDENTIALS **\r\n"); dev.printf("SSID: **%s** (%d)\r\n", ssid, strlen(ssid)); dev.printf("PASS: **%s** (%d)\r\n", pass, strlen(pass)); dev.printf("IP STACK: **%s**\r\n", ip_api_key); dev.printf("TIMEZONEDB: **%s**\r\n", time_api_key); dev.printf("WEATHERMAP: **%s**\r\n", weather_api_key); */ bool res = wifi.init(); // Set up the WiFi Access Point dev.printf("Connecting to WiFi %s with Password %s\n", ssid, pass); res = wifi.connect(ssid, pass); if (!res) { dev.printf("Connection Failed... Resetting Device\n"); err_led = 1; mbed_reset(); } dev.printf("Connected with IP Address: %s\n", wifi.getIPAddress()); /** API REQUESTS **/ int header_ind = 0; int footer_ind = 0; int read_len = 0; char buffer[BUF_SIZE]; char cmd[512]; TCPSocketConnection tcp; tcp.connect("api.ipstack.com", 80); sprintf(cmd, "GET /check?access_key=%s HTTP/1.1\r\nHost: api.ipstack.com\r\n\r\n", ip_api_key); tcp.send_all(cmd, strlen(cmd)); wait(5); read_len = wifi.recv(buffer, BUF_SIZE - 1, 0); buffer[read_len] = '\0'; // Cleanup while (header_ind < read_len) { // if we are \r, look ahead to see \n\r\n: if(buffer[header_ind] == '\r' && buffer[header_ind+1] == '\n' && buffer[header_ind+2] == '\r' && buffer[header_ind+3] == '\n') { // Increment header_ind, look for JSON // Now just look for { header_ind += 4; while (header_ind < read_len) { if (buffer[header_ind] == '{') { // we got it! break; } header_ind++; } break; } header_ind++; } for (footer_ind = read_len - 1; footer_ind > header_ind; footer_ind--) { if(buffer[footer_ind] == '}') { break; } } buffer[footer_ind + 1] = '\0'; MbedJSONValue* parser = new MbedJSONValue(); parse(*parser, buffer + header_ind); latitude = (*parser)["latitude"].get<double>(); longitude = (*parser)["longitude"].get<double>(); delete(parser); // Get the Time TCPSocketConnection time_tcp; time_tcp.connect("api.timezonedb.com", 80); sprintf(cmd, "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", time_api_key, latitude, longitude); time_tcp.send_all(cmd, strlen(cmd)); wait(5); read_len = wifi.recv(buffer, BUF_SIZE - 1, 0); buffer[read_len] = '\0'; // Cleanup // Clean up front // Read through headers (\r\n\r\n) header_ind = 0; while (header_ind < read_len) { // if we are \r, look ahead to see \n\r\n: if(buffer[header_ind] == '\r' && buffer[header_ind+1] == '\n' && buffer[header_ind+2] == '\r' && buffer[header_ind+3] == '\n') { // Increment header_ind, look for JSON // Now just look for { header_ind += 4; while (header_ind < read_len) { if (buffer[header_ind] == '{') { // we got it! break; } header_ind++; } break; } header_ind++; } for (footer_ind = read_len - 1; footer_ind > header_ind; footer_ind--) { if(buffer[footer_ind] == '}') { break; } } buffer[footer_ind + 1] = '\0'; parser = new MbedJSONValue(); parse(*parser, buffer + header_ind); // Add 5 so that we make up for the wait(5) // Add 3 so that we make up for TCP request - empirically... set_time((*parser)["timestamp"].get<int>() + 5 + 3); delete(parser); lcd_lock.lock(); uLCD.cls(); lcd_lock.unlock(); // Now that we know what time it is, set up our Time Thread time_thread.start(time_updater); TCPSocketConnection forecast_sck; forecast_sck.connect("api.openweathermap.org", 80); sprintf(cmd, "GET /data/2.5/forecast?lat=%0.4f&lon=%0.4f&APPID=%s&cnt=1\r\nHost: api.openweathermap.org\r\n\r\n", latitude, longitude, weather_api_key); forecast_sck.send_all(cmd, strlen(cmd)); wait(5); read_len = wifi.recv(buffer, BUF_SIZE - 1, 0); buffer[read_len] = '\0'; // We don't have enough memory for another parser (why?), so just // look for the word "temp" 0 hopefully won't have a city named "temp"! char* ind = strstr(buffer, "temp"); char num_buf[16]; int num_ind = 0; // go until we find numbers while (char tmp = *ind++) { if (tmp > '0' && tmp < '9') { num_buf[num_ind++] = tmp; break; } } // Keep moving until no more numbers while (char tmp = *ind++) { if (tmp > '9' || tmp < '0') { num_buf[num_ind] = '\0'; break; } else { num_buf[num_ind++] = tmp; } } int temp = atoi(num_buf); // Convert temp = kelvin2farenheit(temp); char temp_buf[12]; sprintf(temp_buf, " %dF", temp); lcd_lock.lock(); uLCD.text_width(2); uLCD.text_height(2); uLCD.text_string(temp_buf, 0, 5, FONT_8X8, WHITE); lcd_lock.unlock(); time_t prev_time = time(NULL); while(true) { time_t curr_time = time(NULL); // Wait for 60 seconds if ((prev_time + 60) < curr_time) { sprintf(cmd, "GET /data/2.5/weather?lat=%0.4f&lon=%0.4f&APPID=%s\r\nHost: api.openweathermap.org\r\n\r\n", latitude, longitude, weather_api_key); forecast_sck.connect("api.openweathermap.org", 80); wait(10); forecast_sck.send_all(cmd, strlen(cmd)); wait(5); read_len = wifi.recv(buffer, BUF_SIZE - 1, 0); buffer[read_len] = '\0'; ind = strstr(buffer, "temp"); num_ind = 0; // go until we find numbers while (char tmp = *ind++) { if (tmp > '0' && tmp < '9') { num_buf[num_ind++] = tmp; break; } } // Keep moving until no more numbers while (char tmp = *ind++) { if (tmp > '9' || tmp < '0') { num_buf[num_ind] = '\0'; break; } else { num_buf[num_ind++] = tmp; } } temp = atoi(num_buf); // Convert temp = kelvin2farenheit(temp); sprintf(temp_buf, " %dF", temp); lcd_lock.lock(); uLCD.text_width(2); uLCD.text_height(2); uLCD.text_string(temp_buf, 0, 5, FONT_8X8, WHITE); lcd_lock.unlock(); } } } int main() { clock_init(); }