diff --git a/api.h b/api.h index b6ee1f4..041181b 100644 --- a/api.h +++ b/api.h @@ -2,26 +2,31 @@ #include #include "config.h" -WiFiClientSecure api; +class OsemApi { + protected: + WiFiClientSecure client; -bool postMeasurement(String m, String sensorID) { - //telnet.print("Connecting to API.. "); - if (!api.connect(API_ENDPOINT, 443)) { - //telnet.println("connection failed"); - return false; + public: + bool postMeasurement(String m, String sensorID) { + //telnet.print("Connecting to API.. "); + if (!client.connect(API_ENDPOINT, 443)) { + //telnet.println("connection failed"); + return false; + } + + if (!client.verify(API_FINGERPRINT, API_ENDPOINT)) { + Serial.println("certificate doesn't match"); + return false; + } + + String url = "/boxes/" + String(ID_BOX) + "/" + sensorID; + // TODO: add actual measurement to post + client.print(String("POST ") + url + " HTTP/1.1\r\n" + + "Host: " + API_ENDPOINT + "\r\n" + + "User-Agent: mobile-sensebox-esp8266\r\n" + + "Connection: close\r\n\r\n"); + + return true; } - if (api.verify(API_FINGERPRINT, API_ENDPOINT)) { - //telnet.println("certificate matches"); - } else { - //telnet.println("certificate doesn't match"); - return false; - } - - String url = "/boxes/" + String(ID_BOX) + "/" + sensorID; - api.print(String("POST ") + url + " HTTP/1.1\r\n" + - "Host: " + API_ENDPOINT + "\r\n" + - "User-Agent: mobile-sensebox-esp8266\r\n" + - "Connection: close\r\n\r\n"); +}; - return true; -} diff --git a/gps.h b/gps.h index e5ddff9..70df806 100644 --- a/gps.h +++ b/gps.h @@ -3,51 +3,71 @@ #include #include "config.h" -/* GPS */ -TinyGPSPlus gps; -// allocate the maximum buffer size, so we can reduce the Serial polling interval to a minimum -//SoftwareSerial gpsSerial(GPS_RX_PIN, GPS_TX_PIN, false, 27*49); - -void pollGPS() { - while (Serial.available() > 0) - gps.encode(Serial.read()); -} - -bool updateLocation() { - // abort if the GPS device does not push valid data within one update cycle - static const unsigned int timeout = 2 * GPS_INTERVAL; - unsigned long start = millis(); +class Gps { + protected: + TinyGPSPlus gps; - do { - pollGPS(); - if (millis() - start > timeout) return false; - } while (!gps.location.isUpdated()); - return true; -} - -bool updateTime() { - // abort if the GPS device does not push valid data within one update cycle - static const unsigned int timeout = 2 * GPS_INTERVAL; - unsigned long start = millis(); + public: + void begin() { + Serial.begin(GPS_BAUD); + } - do { - pollGPS(); - if (millis() - start > timeout) return false; - } while ( !(gps.date.isUpdated() && gps.time.isUpdated()) ); + /** + * parse all available bytes from the Serial input + * should be called frequently to avoid buffer overflows + */ + void pollGPS() { + while (Serial.available() > 0) + gps.encode(Serial.read()); + } - // in case we didnt timeout, resync the local clock - setTime(gps.time.hour(), gps.time.minute(), gps.time.second(), - gps.date.day(), gps.date.month(), gps.date.year()); + /** + * poll until we have a valid location. + * retries at most once, returns success state + */ + bool updateLocation() { + // abort if the GPS device does not push valid data within one update cycle + static const unsigned int timeout = 2 * GPS_INTERVAL; + unsigned long start = millis(); + + do { + pollGPS(); + if (millis() - start > timeout) return false; + } while (!gps.location.isUpdated()); // TODO: check if is valid? + return true; + } + + /** + * poll until we have a valid date & time. + * retries at most once, returns success state + */ + bool updateTime() { + // abort if the GPS device does not push valid data within one update cycle + static const unsigned int timeout = 2 * GPS_INTERVAL; + unsigned long start = millis(); - return true; -} + // TODO: check if is valid? + do { + pollGPS(); + if (millis() - start > timeout) return false; + } while ( !(gps.date.isUpdated() && gps.time.isUpdated()) ); + + // in case we didnt timeout, resync the local clock (Time.h) + setTime(gps.time.hour(), gps.time.minute(), gps.time.second(), + gps.date.day(), gps.date.month(), gps.date.year()); + + return true; + } + /** + * return an iso8266 formatted datestring with the current time + */ + static char* getISODate() { + // TODO: check why we need to allocate that much storage for a 20 character string for Serial printing?? + char result[100] = { 0 }; + sprintf(result, "%04d-%02d-%02d-T%02d:%02d:%02dZ", + year(), month(), day(), hour(), minute(), second()); + return result; + } +}; -/* UTILS */ -static char* getISODate() { - // TODO: check why we need to allocate that much storage for a 20 character string for Serial printing?? - char result[100] = { 0 }; - sprintf(result, "%04d-%02d-%02d-T%02d:%02d:%02dZ", - year(), month(), day(), hour(), minute(), second()); - return result; -} diff --git a/mobile-sensebox.ino b/mobile-sensebox.ino index a882e92..d4b848d 100644 --- a/mobile-sensebox.ino +++ b/mobile-sensebox.ino @@ -9,41 +9,57 @@ //TelnetPrint telnet = TelnetPrint(); Storage storage = Storage(); +Wifi wifi = Wifi(); +OsemApi api = OsemApi(); +Gps gps = Gps(); /* UTILS */ -void printState(WifiState wifi) { +void printState(WifiState wifiState) { DEBUG_OUT.print("homeAvailable: "); - DEBUG_OUT.println(wifi.homeAvailable); + DEBUG_OUT.println(wifiState.homeAvailable); DEBUG_OUT.print("numNetworks: "); - DEBUG_OUT.println(wifi.numNetworks); + DEBUG_OUT.println(wifiState.numNetworks); DEBUG_OUT.print("numUnencrypted: "); - DEBUG_OUT.println(wifi.numUnencrypted); + DEBUG_OUT.println(wifiState.numUnencrypted); DEBUG_OUT.print("lat: "); //DEBUG_OUT.print(gps.location.lat(), 6); DEBUG_OUT.print(" lng: "); //DEBUG_OUT.println(gps.location.lng(), 6); - DEBUG_OUT.println(getISODate()); + DEBUG_OUT.println(gps.getISODate()); DEBUG_OUT.println(""); } +bool storeMeasurement(float lat, float lng, float value, char* timeStamp, char* sensorID) { + Measurement m; + m.lat = lat; + m.lng = lng; + m.value = value; + strcpy(m.timeStamp, timeStamp); + strcpy(m.sensorID, sensorID); + + return storage.add(m); +} + /* MAIN ENTRY POINTS */ void setup() { - //Serial.begin(9600); // GPS reciever DEBUG_OUT.begin(115200); - WiFi.mode(WIFI_STA); + size_t bytesFree = storage.begin(); + //gps.begin(); + wifi.begin(); + //connectWifi(WIFI_SSID, WIFI_PASS); - //delay(5000); // DEBUG: oportunity to connect to network logger + //delay(5000); // DEBUG oportunity to connect to network logger // wait until we got a first fix from GPS, and thus an initial time /*DEBUG_OUT.print("Getting GPS fix.."); - while (!updateLocation()) { DEBUG_OUT.print("."); } + while (!gps.updateLocation()) { DEBUG_OUT.print("."); } DEBUG_OUT.print(" done! ");*/ - DEBUG_OUT.println(getISODate()); + DEBUG_OUT.println(gps.getISODate()); DEBUG_OUT.println("Setup done!\n"); DEBUG_OUT.println("WiFi MAC WiFi IP"); @@ -52,50 +68,43 @@ void setup() { DEBUG_OUT.println(WiFi.localIP()); DEBUG_OUT.print("SPIFF bytes free: "); - DEBUG_OUT.println(storage.begin()); + DEBUG_OUT.println(bytesFree); - digitalWrite(D9, HIGH); // DEBUG: integrated led? doesnt work + digitalWrite(D9, HIGH); // DEBUG: integrated led? doesnt work } void loop() { //pollGPS(); //DEBUG_OUT.pollClients(); - WifiState wifi = scanWifi(WIFI_SSID); + WifiState wifiState = wifi.scanWifi(WIFI_SSID); + char* dateString = gps.getISODate(); // TODO: take other measurements (average them?) /* - if(!updateLocation()) DEBUG_OUT.println("GPS timed out (location)"); - if(!updateTime()) DEBUG_OUT.println("GPS timed out (time)"); + if(!gps.updateLocation()) DEBUG_OUT.println("GPS timed out (location)"); + if(!gps.updateTime()) DEBUG_OUT.println("GPS timed out (time)"); */ - // TODO: write measurements to file - - // TODO: connect to wifi, if available & not connected yet - // then upload local data, clean up - printState(wifi); + // write measurements to file + if (storeMeasurement(51.2, 7.89, wifiState.numNetworks, dateString, "12341234123412341234123412341234")) { + DEBUG_OUT.print("measurement stored! storage size: "); + } else { + DEBUG_OUT.print("measurement store failed! storage size: "); + } + DEBUG_OUT.println(storage.size()); - // recall all previous measurements + // TODO: connect to wifi, if available & not connected yet + // then upload local data, remove from storage + + // DEBUG: recall all previous measurements while (storage.size()) { String measure = storage.pop(); + //api.postMeasurement(measure.substring(0, 31), measure.substring(32)); DEBUG_OUT.println("popped a measurement: "); DEBUG_OUT.println(measure.substring(0, 31)); // size of sensorID DEBUG_OUT.println(measure.substring(32)); // skip the newline char } - // store new measurement - Measurement testMeasure; - testMeasure.lat = 51.2; - testMeasure.lng = 7.89; - testMeasure.value = wifi.numNetworks; - strcpy(testMeasure.timeStamp, getISODate()); - strcpy(testMeasure.sensorID, "123457812345678123456781234567"); - - if (storage.add(testMeasure)) { - DEBUG_OUT.print("measurement stored! storage size: "); - } else { - DEBUG_OUT.print("measurement store failed! storage size: "); - } - DEBUG_OUT.println(storage.size()); - - delay(2000); + printState(wifiState); } + diff --git a/wifi.h b/wifi.h index 3809689..fbc1524 100644 --- a/wifi.h +++ b/wifi.h @@ -2,46 +2,53 @@ #include #include "config.h" -/* WIFI */ struct WifiState { bool homeAvailable; unsigned int numNetworks; unsigned int numUnencrypted; }; -// TODO: filter duplicate SSIDs! -WifiState scanWifi(String homeSSID) { - WifiState state; - state.homeAvailable = false; - state.numNetworks = WiFi.scanNetworks(false, false); - state.numUnencrypted = 0; - - for (unsigned int i = 0; i < state.numNetworks; i++) { - if (WiFi.encryptionType(i) == ENC_TYPE_NONE) - ++state.numUnencrypted; - - if (WiFi.SSID(i) == homeSSID) - state.homeAvailable = true; +class Wifi { + public: + void begin() { + WiFi.mode(WIFI_STA); } - - return state; -} - -bool connectWifi(const char* ssid, const char* pass) { - static const unsigned int timeout = 10000; // abort after 10 secs - unsigned long start = millis(); - - WiFi.disconnect(); - WiFi.begin(ssid, pass); - //telnet.print("Connecting to WiFi."); - while (WiFi.status() != WL_CONNECTED && millis() - start < timeout) { - delay(200); - //telnet.print("."); + + WifiState scanWifi(String homeSSID) { + // TODO: filter duplicate SSIDs! + WifiState state; + state.homeAvailable = false; + state.numNetworks = WiFi.scanNetworks(false, false); + state.numUnencrypted = 0; + + for (unsigned int i = 0; i < state.numNetworks; i++) { + if (WiFi.encryptionType(i) == ENC_TYPE_NONE) + ++state.numUnencrypted; + + if (WiFi.SSID(i) == homeSSID) + state.homeAvailable = true; + } + + return state; } - if (WiFi.status() == WL_CONNECTED) { - //telnet.println("connected!"); - return true; + + bool connectWifi(const char* ssid, const char* pass) { + static const unsigned int timeout = 10000; // abort after 10 secs + unsigned long start = millis(); + + WiFi.disconnect(); + WiFi.begin(ssid, pass); + //telnet.print("Connecting to WiFi."); + while (WiFi.status() != WL_CONNECTED && millis() - start < timeout) { + delay(200); + //telnet.print("."); + } + if (WiFi.status() == WL_CONNECTED) { + //telnet.println("connected!"); + return true; + } + //telnet.println(" timeout"); + return false; } - //telnet.println(" timeout"); - return false; -} +}; +