Final Project for 4180 Nixie Tube IoT Clock

Dependencies:   4DGL-uLCD-SE NixieTube MBed_Adafruit-GPS-Library NetServices wave_player mbed spxml

Final Project for ECE 4180

main.cpp

Committer:
fischk08
Date:
2016-12-15
Revision:
4:9651e706b36f
Parent:
3:d62bb9ee0aa0

File content as of revision 4:9651e706b36f:

// Notes https://developer.mbed.org/users/edodm85/notebook/HC-05-bluetooth/
// https://developer.mbed.org/cookbook/Bluetooth-Android-Controlled-MBED  
// https://developer.mbed.org/users/mlee350/notebook/adafruit-ultimate-gps-breakout-board/
// https://developer.mbed.org/users/4180_1/notebook/ulcd-144-g2-128-by-128-color-lcd/
// https://developer.mbed.org/handbook/LocalFileSystem
// Includes Files
#include "mbed.h"
#include <string>
#include "uLCD_4DGL.h"
#include "wave_player.h"
#include "MBed_Adafruit_GPS.h" // GPS Unit 
#include "spdomparser.hpp" /// Parseing Weather
#include "spxmlnode.hpp" /// Parseing Weather
#include "spxmlhandle.hpp" /// Parseing Weather
#include "EthernetNetIf.h"
#include "HTTPClient.h"
#include <string>
#include "NTPClient.h"
#include "NixieTube.h"
Serial pc(USBTX, USBRX);
NixieTube Ntube(p24,p23,p22,p21);
/////////////////////////
EthernetNetIf eth;
HTTPClient http;
HTTPResult result;
////////////////////////
NTPClient ntp; // Used for Clock
////////////////////////////////
LocalFileSystem local("local");         // Create the local filesystem under the name "local"
AnalogOut DACout(p18);                  // DAC for producing sound
wave_player waver(&DACout);             // wavplayer object
Serial * gps_Serial;                    // GPS Interface
uLCD_4DGL uLCD(p13,p14,p15);            // serial tx, serial rx, reset pin;
AnalogIn photocell(p19);
Serial bt(p28, p27);

// Bluetooth


//LCD Files Needs to be local to the ulcd screen
    
// Declarations 
bool completed = false;                 // Used for HTTP Request
bool pressPlay = false;                 // Default on pause (song select mode)
int volume = 0; 
volatile float lattitude = 33.7490;
volatile float longitude = -84.3880;
bool  gps_setup();
void display_screen_debug(),request_callback(),parseWeather(),system_setup(),display_weather(int),sound_alarm(float),ethernet_setup();

 // Used for obtaining weather Information
void request_callback(HTTPResult r){
    result = r;
    completed = true;
}

void display_weather(int code){
        uLCD.flush_media();
        uLCD.cls();
        uLCD.media_init();
        uLCD.set_sector_address(0x0000,(code*65));
        uLCD.display_control(3);
        uLCD.display_image(0,0);
    }    

void parseWeather(SP_XmlElementNode *node, string loc){
    //extracts current weather XML data fields for LCD
    SP_XmlHandle handle(node);
    SP_XmlElementNode * condition = handle.getChild( "item" ).getChild("yweather:condition").toElement();
    //display Weather conditions
    // Print the name of the city
    pc.printf("%s:", loc);
    //Print the weather conditions
    pc.printf("%s",condition->getAttrValue("text"));
    //Print the termperature (in degrees Celcius)
    pc.printf("%sF",condition->getAttrValue("temp"));
    display_weather(atoi(condition->getAttrValue("code")));
}

int weather(){ 
retryweather:
    completed = false;
    SP_XmlDomParser parser;
    HTTPStream stream;   
    char buffer3 [200];
    wait(1);
    pc.printf("%.6f:",lattitude);
    pc.printf("%.6f:",longitude);
    int n2;
    char post[] = "https://query.yahooapis.com/v1/public/yql?q=select+item.condition+from+weather.forecast+where+woeid+in+(SELECT+woeid+FROM+geo.places+WHERE+text='(";
    char msg[10] = ")')";
    n2 = sprintf(buffer3, "%.6f,%.6f", lattitude, longitude);
    char* temppostRequest = strcat(post,buffer3);
    char* postRequest = strcat(temppostRequest,msg);
     pc.printf(post);
     pc.printf(msg);
     pc.printf(temppostRequest);
    pc.printf("Reading\r\n");
    pc.printf(postRequest);
    wait(1);
    //n=sprintf(buffer, "https://query.yahooapis.com/v1/public/yql?q=select%20item.condition%20from%20weather.forecast%20where%20woeid%20in%20%28SELECT%20woeid%20FROM%20geo.places%20WHERE%20text%3D%22(%.6f%2C%.6f)%22)", lat, log);
    char BigBuf[512 + 1] = {0};
    wait(1);
    stream.readNext((byte*)BigBuf, 512); //Point to buffer for the first read
    //Yahoo! weather API for selected city - get XML document for parsing
    //HTTPResult r = http.get("https://query.yahooapis.com/v1/public/yql?q=select+item.condition+from+weather.forecast+where+woeid+in+(SELECT+woeid+FROM+geo.places+WHERE+text='(33.7490,-84.3880)')", &stream, request_callback);
    HTTPResult r = http.get(postRequest, &stream, request_callback); // This is wehre the http query for the local weather occurs 
    while (!completed) {
        Net::poll(); //Polls the Networking stack
        if (stream.readable()) {
            BigBuf[stream.readLen()] = 0; //Transform this buffer in a zero-terminated char* string
            parser.append( BigBuf, strlen(BigBuf)); // stream current buffer data to the XML parser
            stream.readNext((byte*)BigBuf, 512); //Buffer has been read, now we can put more data in it
        }
    }
    if (result == HTTP_OK) {
        pc.printf("Weather complete");
    } else {
        pc. printf("Weather Error %d", result);
        goto retryweather;
        return -1;
    }

    SP_XmlHandle rootHandle( parser.getDocument()->getRootElement() );
    SP_XmlElementNode * child2 = rootHandle.getChild( "results" ).getChild( "channel" ).toElement();

    //pc.printf(BigBuf);

    if ( child2 ) {
        parseWeather(child2, "Atlanta"); //parses XML "current-conditions" info
    }

    if ( NULL != parser.getError() ) {
        pc.printf( "\n error: %s\n", parser.getError() );
    }
    return 0;
}
// Need to update so that if it failes to get a GPS fix after say 10 tries it defaults lat and longitude values and time is found thought another method.
bool  gps_setup(){
    Timer refresh_Timer; //sets up a timer for use in loop; how often do we print GPS info?
    const int refresh_Time = 2000; //refresh time in ms
    bool gps_off = true;
    char c;  
    gps_Serial = new Serial(p9,p10); //serial object for use w/ GPS tx rx
    Adafruit_GPS myGPS(gps_Serial); //object of Adafruit's GPS class
    myGPS.begin(9600);  //sets baud rate for GPS communication; note this may be changed via Adafruit_GPS::sendCommand(char *)
    myGPS.sendCommand(PMTK_SET_NMEA_OUTPUT_RMCGGA); //these commands are defined in MBed_Adafruit_GPS.h; a link is provided there for command creation
    myGPS.sendCommand(PMTK_SET_NMEA_UPDATE_1HZ);
    myGPS.sendCommand(PGCMD_ANTENNA);
    refresh_Timer.start();  //starts the clock on the timer
    uLCD.text_width(1); //4X size text
    uLCD.text_height(1);
    uLCD.printf("Starting Up\n");
    while(gps_off){
        uLCD.cls();
        c = myGPS.read();   //queries the GPS
        if (c) { uLCD.printf("%c", c); } //this line will echo the GPS data if not paused
        //check if we recieved a new message from GPS, if so, attempt to parse it,
        if ( myGPS.newNMEAreceived() ) {
            if ( !myGPS.parse(myGPS.lastNMEA()) ) {
                continue;   
            }    
        }
        //check if enough time has passed to warrant printing GPS info to screen
        //note if refresh_Time is too low or pc.baud is too low, GPS data may be lost during printing
        if (refresh_Timer.read_ms() >= refresh_Time) {
            refresh_Timer.reset();
            uLCD.printf("Fix: %d\n", (int) myGPS.fix);
            uLCD.printf("Quality: %d\n", (int) myGPS.fixquality);
            if (myGPS.fix) {
                uLCD.printf("Time: %d:%d:%d.%u\n", myGPS.hour, myGPS.minute, myGPS.seconds, myGPS.milliseconds);   
                uLCD.printf("Date: %d/%d/20%d\n", myGPS.day, myGPS.month, myGPS.year);
                uLCD.printf("Location: %5.2f%c, %5.2f%c\n", myGPS.latitude, myGPS.lat, myGPS.longitude, myGPS.lon);
                uLCD.printf("Speed: %5.2f knots\n", myGPS.speed);
                uLCD.printf("Angle: %5.2f\n", myGPS.angle);
                uLCD.printf("Altitude: %5.2f\n", myGPS.altitude);
                uLCD.printf("Satellites: %d\n", myGPS.satellites);
                gps_off = false;
                lattitude = myGPS.latitude;
                longitude = myGPS.longitude;
            }
        }
    }
    return true;
}    

void sound_alarm() {
        pressPlay = true;
        FILE *wave_file = fopen("/local/alarm.wav","r");
        waver.play(wave_file); //play(FILE *wavefile,bool *pressPlay, int *volume);
        pressPlay = false;
        wait(10);
        fclose(wave_file); 
}


int main() {
    unsigned char rx;
    bt.baud(9600);
    char alarm[6] = "02:14";
    pc.baud(9600);
    pc.printf("\r\nintializing hardware,...v15\r\n");
    eth.init(); //Use DHCP
    int retry = 0;
sendGETRequest:
    EthernetErr ethErr = eth.setup(60000);
    
    if (ethErr) {
        pc.printf("Error in setup trying again %d",retry);
        retry++;
        goto sendGETRequest;
        }
    pc.printf("net ok testing weather\r\n");
    weather();
    weather();
    time_t ctTime;
    ctTime = time(NULL);  
    Host server(IpAddr(), 123, "0.us.pool.ntp.org");
    ntp.setTime(server);
    char hString[3];
    char mString[3];
    char alarmCompare[5];
    int offset = 5;
    int old_min2 = 0;
    int reset = 0;
    char ch;
    
    while(1) {
        int x = 0;
        if(bt.readable())
        {
            //pc.printf("device readable");
            ch=bt.getc();
            //alarm[x] = ch;
            pc.printf("%c",ch);
            bt.printf("%c",ch);
            //x++
        }
        
        //pc.printf("%f", photocell.read() );
        if (photocell < .3) {
            
            Ntube.set_dim(0.2);
        } else {
            Ntube.set_dim(0.5);
        }
        
        ctTime = time(NULL) - 3600 * offset;
        strftime(hString, 3, "%I", localtime(&ctTime));
        strftime(mString, 3, "%M", localtime(&ctTime));
        
        strftime(alarmCompare, 6, "%I:%M", localtime(&ctTime));
        
        if (strcmp(alarm, alarmCompare) == 0) {
            pc.printf("ALARM\r\n");
            sound_alarm();
            wait(10);
        }
        
        int hour = std::atoi(hString);
        int min = std::atoi(mString);
        
        int hour1 = hour / 10;
        int hour2 = hour % 10;
        
        int min1 = min / 10;
        int min2 = min % 10;
        
        if (min2!=old_min2) {
            old_min2=min2;
            pc. printf("\n %d, %d, %d, %d\r\n", hour1, hour2, min1, min2);
            Ntube.update_all_nixie_tube(hour1, hour2, min1, min2);
            reset++;
            
            }
        if (reset>14){
            reset = 0;
            weather();
            weather();
            }            
        wait(0.3);
        }   
}