implement API upload

esp8266-bme280
noerw 8 years ago
parent e3581f3088
commit 8ef77fcc97

31
api.h

@ -1,31 +1,40 @@
#pragma once #pragma once
#include <WiFiClientSecure.h> #include <WiFiClientSecure.h>
#include "config.h" #include "config.h"
#include "streampipe.h"
class OsemApi { class OsemApi {
protected: protected:
WiFiClientSecure client; WiFiClientSecure client;
public: public:
bool postMeasurement(String m, String sensorID) { bool postMeasurement(String measurement, String sensorID) {
//telnet.print("Connecting to API.. "); //telnet.print("Connecting to API.. ");
if (!client.connect(API_ENDPOINT, 443)) { if (!client.connect(API_ENDPOINT, 443)) {
//telnet.println("connection failed"); //Serial.println("connection failed");
return false; return false;
} }
if (!client.verify(API_FINGERPRINT, API_ENDPOINT)) { if (!client.verify(API_FINGERPRINT, API_ENDPOINT)) {
Serial.println("certificate doesn't match"); //Serial.println("certificate doesn't match");
return false; return false;
} }
String url = "/boxes/" + String(ID_BOX) + "/" + sensorID; client << String("POST ") << "/boxes/" << ID_BOX << "/" << sensorID << " HTTP/1.1" << EOL;
// TODO: add actual measurement to post client << "Host: " << API_ENDPOINT << EOL;
client.print(String("POST ") + url + " HTTP/1.1\r\n" + client << "X-APIKey: " << API_KEY << EOL;
"Host: " + API_ENDPOINT + "\r\n" + client << "Content-Type: application/json" << EOL;
"User-Agent: mobile-sensebox-esp8266\r\n" + client << "Connection: close" << EOL;
"Connection: close\r\n\r\n"); client << "Content-Length: " << measurement.length() << EOL << EOL;
client << measurement;
// read response
while (client.connected()) {
String line = client.readStringUntil('\n');
if (line == "\r") break;
}
Serial << "API-Server response: " << client.readString() << EOL;
return true; return true;
} }
}; };

@ -1,19 +1,22 @@
/* WiFi (ESP8266) */
#pragma once #pragma once
static const char* WIFI_SSID = "Elmo"; /* WiFi (ESP8266) */
static const char* WIFI_PASS = "FreiBier123";
#define WIFI_SSID "Penaten"
#define WIFI_PASS "XXXXXX"
/* GPS reciever (uBloc NEO-7M) */ /* GPS reciever (uBloc NEO-7M) */
static const int GPS_RX_PIN = 4; #define GPS_RX_PIN 4
static const int GPS_TX_PIN = 3; #define GPS_TX_PIN 3
static const int GPS_BAUD = 9600; #define GPS_BAUD 9600
static const int GPS_INTERVAL = 1000; // update interval of the gps device #define GPS_INTERVAL 1000 // update interval of the gps device
/* API (openSenseMap) */ /* API (openSenseMap) */
static const char* API_ENDPOINT = "api.opensensemap.org"; #define API_ENDPOINT "api.osem.vo1d.space"
// SHA1 of the API SSL cert // SHA1 of the API SSL cert
static const char* API_FINGERPRINT = "0F B0 0C E0 FD 18 C2 0B 07 1C 21 AB A0 FF EF CC 09 62 57 A9"; #define API_FINGERPRINT "A2 38 74 C7 B0 71 07 D4 2A 1C A5 6D 0D 05 3E 0A 90 68 A5 CB"
static const char* API_KEY = "..."; #define API_KEY_LENGTH 24
static const char* ID_BOX = "57308b2c566b8d3c11114a9f"; #define API_KEY "XXXXXXXXXXX"
static const char* ID_SENSOR_WIFI = "..."; #define ID_BOX "57c7f3291421551100bf13c8"
#define ID_SENSOR_WIFI "57c7f3291421551100bf13ca"

@ -3,6 +3,8 @@
#include <Time.h> #include <Time.h>
#include "config.h" #include "config.h"
// TODO: refactor updateXXX members to be protected and called by getXXX ?
class Gps { class Gps {
protected: protected:
TinyGPSPlus gps; TinyGPSPlus gps;
@ -59,8 +61,12 @@ class Gps {
return true; return true;
} }
TinyGPSLocation& getLocation() {
return gps.location;
}
/** /**
* return an iso8266 formatted datestring with the current time * return an iso8601 formatted datestring with the current time
*/ */
static char* getISODate() { static char* getISODate() {
// TODO: check why we need to allocate that much storage for a 20 character string for Serial printing?? // TODO: check why we need to allocate that much storage for a 20 character string for Serial printing??

@ -6,6 +6,7 @@
#include "TelnetPrint.h" #include "TelnetPrint.h"
#define DEBUG_OUT Serial #define DEBUG_OUT Serial
//#define DEBUG_OUT telnet
//TelnetPrint telnet = TelnetPrint(); //TelnetPrint telnet = TelnetPrint();
Storage storage = Storage(); Storage storage = Storage();
@ -23,15 +24,15 @@ void printState(WifiState wifiState) {
DEBUG_OUT.println(wifiState.numUnencrypted); DEBUG_OUT.println(wifiState.numUnencrypted);
DEBUG_OUT.print("lat: "); DEBUG_OUT.print("lat: ");
//DEBUG_OUT.print(gps.location.lat(), 6); //DEBUG_OUT.print(gps.getLocation().lat(), 6);
DEBUG_OUT.print(" lng: "); DEBUG_OUT.print(" lng: ");
//DEBUG_OUT.println(gps.location.lng(), 6); //DEBUG_OUT.println(gps.getLocation().lng(), 6);
DEBUG_OUT.println(gps.getISODate()); DEBUG_OUT.println(gps.getISODate());
DEBUG_OUT.println(""); DEBUG_OUT.println("");
} }
bool storeMeasurement(float lat, float lng, float value, char* timeStamp, char* sensorID) { bool storeMeasurement(float lat, float lng, float value, const char* timeStamp, const char* sensorID) {
Measurement m; Measurement m;
m.lat = lat; m.lat = lat;
m.lng = lng; m.lng = lng;
@ -51,7 +52,7 @@ void setup() {
//gps.begin(); //gps.begin();
wifi.begin(); wifi.begin();
//connectWifi(WIFI_SSID, WIFI_PASS); wifi.connect(WIFI_SSID, WIFI_PASS);
//delay(5000); // DEBUG oportunity to connect to network logger //delay(5000); // DEBUG oportunity to connect to network logger
@ -76,7 +77,7 @@ void setup() {
void loop() { void loop() {
//pollGPS(); //pollGPS();
//DEBUG_OUT.pollClients(); //DEBUG_OUT.pollClients();
WifiState wifiState = wifi.scanWifi(WIFI_SSID); WifiState wifiState = wifi.scan(WIFI_SSID);
char* dateString = gps.getISODate(); char* dateString = gps.getISODate();
// TODO: take other measurements (average them?) // TODO: take other measurements (average them?)
@ -86,7 +87,7 @@ void loop() {
*/ */
// write measurements to file // write measurements to file
if (storeMeasurement(51.2, 7.89, wifiState.numNetworks, dateString, "12341234123412341234123412341234")) { if (storeMeasurement(51.25345345, 7.89, wifiState.numNetworks, "2016-08-31T00:03:10Z", ID_SENSOR_WIFI)) {
DEBUG_OUT.print("measurement stored! storage size: "); DEBUG_OUT.print("measurement stored! storage size: ");
} else { } else {
DEBUG_OUT.print("measurement store failed! storage size: "); DEBUG_OUT.print("measurement store failed! storage size: ");
@ -94,17 +95,14 @@ void loop() {
DEBUG_OUT.println(storage.size()); DEBUG_OUT.println(storage.size());
// TODO: connect to wifi, if available & not connected yet // TODO: connect to wifi, if available & not connected yet
// then upload local data, remove from storage
// then upload local data, remove from storage
// DEBUG: recall all previous measurements
while (storage.size()) { while (storage.size()) {
String measure = storage.pop(); String measure = storage.pop();
//api.postMeasurement(measure.substring(0, 31), measure.substring(32)); api.postMeasurement(measure.substring(API_KEY_LENGTH + 1), measure.substring(0, API_KEY_LENGTH));
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
} }
printState(wifiState); printState(wifiState);
delay(5000);
} }

@ -2,45 +2,36 @@
#include <FS.h> #include <FS.h>
#include <ESP8266TrueRandom.h> #include <ESP8266TrueRandom.h>
#include <ArduinoJson.h> #include "config.h"
#include "api.h" #include "streampipe.h"
#define MEASUREMENT_JSON_SIZE (JSON_OBJECT_SIZE(5)) #define MEASUREMENT_JSON_SIZE (JSON_OBJECT_SIZE(4)) // 4 properties (sensorID is excluded)
struct Measurement { struct Measurement {
char timeStamp[20]; char timeStamp[20];
float lat; float lat;
float lng; float lng;
float value; float value;
char sensorID[32]; char sensorID[API_KEY_LENGTH];
}; };
class Storage { class Storage {
protected: protected:
// not needed, as we post the data as json string? void serializeMeasurement(Measurement& m, Print& f) {
/*Measurement deserializeMeasurement(char* s) { // prepend the sensor ID to the json
Measurement m; f << m.sensorID << EOL;
StaticJsonBuffer<MEASUREMENT_JSON_SIZE> jsonBuffer;
JsonObject& root = jsonBuffer.parseObject(s);
m.timeStamp = (const char[sizeof Measurement.timeStamp])jsonBuffer.strdup(root["date"]);
m.lat = root["lat"];
m.lng = root["lng"];
m.value = root["value"];
m.sensorID = root["sensorId"];
return m;
}*/
bool serializeMeasurement(Measurement& m, Print& f) { // convert floats to strings
f.println(m.sensorID); char val[10], lat[10], lng[10];
StaticJsonBuffer<MEASUREMENT_JSON_SIZE> jsonBuffer; dtostrf(m.value, 5, 6, val);
JsonObject& root = jsonBuffer.createObject(); dtostrf(m.lat, 5, 6, lat);
// TODO: replace temporary data model dtostrf(m.lng, 5, 6, lng);
root["createdAt"] = m.timeStamp;
root["lat"] = m.lat; f << "{\"value\":" << val
root["lng"] = m.lng; << ",\"createdAt\":\"" << m.timeStamp
root["value"] = m.value; << "\",\"lat\":" << lat
root.printTo(f); << ",\"lng\":" << lng
return root.success(); << "}" << EOL;
} }
public: public:
@ -60,9 +51,9 @@ class Storage {
String fileName = directory + ESP8266TrueRandom.uuidToString(uuid).substring(26); String fileName = directory + ESP8266TrueRandom.uuidToString(uuid).substring(26);
if (File f = SPIFFS.open(fileName, "w") ) { if (File f = SPIFFS.open(fileName, "w") ) {
bool success = serializeMeasurement(m, f); serializeMeasurement(m, f);
f.close(); f.close();
return success; return true;
} }
return false; return false;
} }

@ -0,0 +1,6 @@
// add classic C stream pipe operator to arduino C
#pragma once
#define EOL "\r\n"
template<class T> inline Print &operator <<(Print &obj, T arg) { obj.print(arg); return obj; }

@ -14,7 +14,7 @@ class Wifi {
WiFi.mode(WIFI_STA); WiFi.mode(WIFI_STA);
} }
WifiState scanWifi(String homeSSID) { WifiState scan(String homeSSID) {
// TODO: filter duplicate SSIDs! // TODO: filter duplicate SSIDs!
WifiState state; WifiState state;
state.homeAvailable = false; state.homeAvailable = false;
@ -32,7 +32,7 @@ class Wifi {
return state; return state;
} }
bool connectWifi(const char* ssid, const char* pass) { bool connect(const char* ssid, const char* pass) {
static const unsigned int timeout = 10000; // abort after 10 secs static const unsigned int timeout = 10000; // abort after 10 secs
unsigned long start = millis(); unsigned long start = millis();

Loading…
Cancel
Save