Fork from Alex

Dependencies:   mbed MbedJSONValue mbed-rtos 4DGL-uLCD-SE ESP8266NodeMCUInterface

main.cpp

Committer:
alexhrao
Date:
2019-03-31
Revision:
4:55f0c303f56a
Parent:
3:7bf41989ff8f
Child:
5:b77a717feada

File content as of revision 4:55f0c303f56a:

#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);
Thread dev_thread;

// 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 weather_updater() {
    // get the weather
    // first get the current weather
    // Weather data is _long_
    dev.printf("Hello, World!\n");

    char forecast_buf[4096];
    TCPSocketConnection forecast_sck;
    // http://api.openweathermap.org/data/2.5/forecast?lat=33.7485&lon=-84.3871&appid=6971e1ebfcc60f29c8dcc617c532b1b6&cnt=8
    forecast_sck.connect("api.openweathermap.org", 80);
    char cmd[256];
    sprintf(cmd,
        "GET /data/2.5/weather?lat=%0.4f&lon=%0.4f&APPID=6971e1ebfcc60f29c8dcc617c532b1b6&cnt=8\r\nHost: api.openweathermap.org\r\n\r\n",
        latitude, longitude);
    forecast_sck.send_all(cmd, strlen(cmd));
    wait(10);
    int len_read = wifi.recv(forecast_buf, 4096 - 1, 0);
    forecast_buf[len_read] = '\0';
    dev.printf(forecast_buf);
    return;
    // http://api.openweathermap.org/data/2.5/forecast?lat=33.7485&lon=-84.3871&appid=6971e1ebfcc60f29c8dcc617c532b1b6
    // Get current weather
    char current_buf[4096];
    sprintf(cmd,
        "GET /data/2.5/forecast?lat=%0.4f&lon=%0.4f&APPID=%s\r\nHost: api.openweathermap.org\r\n\r\n",
        latitude, longitude, weather_api_key);
    sck.send_all(cmd, strlen(cmd));
    wait(10);
    int buf_len = wifi.recv(current_buf, 4096 - 1, 0);
    current_buf[buf_len] = '\0';
    // we'll always want to update the LCD - don't worry about the previous
    // weather
    int curr_temp = 0;
    int high_temp = 0;
    int low_temp = 0;
    char buf[12];
    sprintf(buf, "%d %d/%d", curr_temp, high_temp, low_temp);
    // lock
    lcd_lock.lock();
    uLCD.text_width(2);
    uLCD.text_height(2);
    // include null!
    uLCD.text_string(buf, 0, 5, FONT_7X8, WHITE);
    // done! unlock
    lcd_lock.unlock();
}
*/

void dev_recv() {
    // Continually check if we have stuff...
    char buf[1024];
    int ind = 0;
    while (true) {
        while (true) {
            // 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") == 0) {
            dev.printf("Are you sure? y/[n]\n");
        }
        buf[0] = '\0';
        ind = 0;
        //if (strcmp(buf, "reset") != 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_string("PLEASE WAIT", 0, 2, FONT_7X8, WHITE);
    lcd_lock.unlock();
    
    // Need to get wifi settings. If we don't have local file, then ask!
    FILE* fid = fopen("/local/settings.txt", "r");
    
    if (fid != NULL) {
        // Read WiFi Settings
        char settings_buf[1024];
        // Guaranteed to be 5 lines
        // 
        fgets(settings_buf, 1024, fid);
        // find \n
        int settings_ind = 0;
        int 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';
        settings_ind = 0;
        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);
    } 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';
        
        // Get the API key
        dev.printf("Please provide the IP Stack API key\n");
        while (!dev.readable()) {
            wait(0.001);
        }
        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';

        
        
        // 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/settings.txt", "w");
        fprintf(fid, "%s\n%s\n%s\n%s\n%s\n", ssid, pass, ip_api_key, time_api_key, weather_api_key);
        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("Alex's iPhone", "mbedlookhere");
    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];

    dev.printf("Getting the current location...\n");
    TCPSocketConnection tcp;
    tcp.connect("api.ipstack.com", 80);
    //af9319bf6435ddd9bb640f763ff64d34
    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';
    dev.printf(buffer);
    MbedJSONValue parser;
    parse(parser, buffer + header_ind);
    
    latitude =  parser["latitude"].get<double>();
    longitude = parser["longitude"].get<double>();

    // Get the Time
    TCPSocketConnection time_tcp;

    //http://api.timezonedb.com/v2.1/get-time-zone?key=YOUR_API_KEY&format=json&by=zone&zone=America/Chicago
    time_tcp.connect("api.timezonedb.com", 80);
    //VFHNS0FSUJVN
    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';
    
    MbedJSONValue time_parser;
    parse(time_parser, buffer + header_ind);

    // Add 5 so that we make up for the wait(5)
    set_time(time_parser["timestamp"].get<int>() + 5);
    // Now that we know what time it is, set up our Time Thread
    time_thread.start(time_updater);
    TCPSocketConnection forecast_sck;
    // http://api.openweathermap.org/data/2.5/forecast?lat=33.7485&lon=-84.3871&appid=6971e1ebfcc60f29c8dcc617c532b1b6&cnt=8
    forecast_sck.connect("api.openweathermap.org", 80);
    //6971e1ebfcc60f29c8dcc617c532b1b6
    sprintf(cmd,
        "GET /data/2.5/weather?lat=%0.4f&lon=%0.4f&APPID=%s&cnt=8\r\nHost: api.openweathermap.org\r\n\r\n",
        latitude, longitude, weather_api_key);
    forecast_sck.send_all(cmd, strlen(cmd));
    wait(5);
    int len_read = wifi.recv(buffer, BUF_SIZE - 1, 0);
    buffer[len_read] = '\0';
    

    //buffer[footer_ind + 1] = '\0';
    char* ind = strstr(buffer, "temp");
    for (int m = 0; m < 15; m++) {
        dev.putc(ind[m]);
    }
    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 = (((temp - 273.15f) * 9.0f) / 5.0f) + 32.0f;
    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);
    // done! unlock
    lcd_lock.unlock();
    
    
    // Start up weather service!
    //weather_thread.start(weather_updater);
    
    // Listen on bluetooth.
    //dev_thread.start(dev_recv);
    while(true) {
        time_t curr_time = time(NULL);
        if (true) {
            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);

            len_read = wifi.recv(buffer, BUF_SIZE - 1, 0);

            buffer[len_read] = '\0';

    
            dev.printf(buffer);

            ind = strstr(buffer, "temp");
            for (int m = 0; m < 15; m++) {
                dev.putc(ind[m]);
            }
            num_ind = 0;
            // go until we find numbers
            while (char tmp = *ind++) {
                dev.printf("CHAR: %c\r\n", tmp);
                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);
            dev.printf("Temperature: %s (%d)\r\n", num_buf, temp);
            // Convert
            temp = (((temp - 273.15f) * 9.0f) / 5.0f) + 32.0f;
            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);
            // done! unlock
            lcd_lock.unlock();
        }

        err_led = !err_led;
    }
}

int main() {
    clock_init();
}