implement API upload

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

31
api.h

@ -1,31 +1,40 @@
#pragma once
#include <WiFiClientSecure.h>
#include "config.h"
#include "streampipe.h"
class OsemApi {
protected:
WiFiClientSecure client;
public:
bool postMeasurement(String m, String sensorID) {
bool postMeasurement(String measurement, String sensorID) {
//telnet.print("Connecting to API.. ");
if (!client.connect(API_ENDPOINT, 443)) {
//telnet.println("connection failed");
//Serial.println("connection failed");
return false;
}
if (!client.verify(API_FINGERPRINT, API_ENDPOINT)) {
Serial.println("certificate doesn't match");
//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");
client << String("POST ") << "/boxes/" << ID_BOX << "/" << sensorID << " HTTP/1.1" << EOL;
client << "Host: " << API_ENDPOINT << EOL;
client << "X-APIKey: " << API_KEY << EOL;
client << "Content-Type: application/json" << EOL;
client << "Connection: close" << EOL;
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;
}
};

@ -1,19 +1,22 @@
/* WiFi (ESP8266) */
#pragma once
static const char* WIFI_SSID = "Elmo";
static const char* WIFI_PASS = "FreiBier123";
/* WiFi (ESP8266) */
#define WIFI_SSID "Penaten"
#define WIFI_PASS "XXXXXX"
/* GPS reciever (uBloc NEO-7M) */
static const int GPS_RX_PIN = 4;
static const int GPS_TX_PIN = 3;
static const int GPS_BAUD = 9600;
static const int GPS_INTERVAL = 1000; // update interval of the gps device
#define GPS_RX_PIN 4
#define GPS_TX_PIN 3
#define GPS_BAUD 9600
#define GPS_INTERVAL 1000 // update interval of the gps device
/* API (openSenseMap) */
static const char* API_ENDPOINT = "api.opensensemap.org";
#define API_ENDPOINT "api.osem.vo1d.space"
// 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";
static const char* API_KEY = "...";
static const char* ID_BOX = "57308b2c566b8d3c11114a9f";
static const char* ID_SENSOR_WIFI = "...";
#define API_FINGERPRINT "A2 38 74 C7 B0 71 07 D4 2A 1C A5 6D 0D 05 3E 0A 90 68 A5 CB"
#define API_KEY_LENGTH 24
#define API_KEY "XXXXXXXXXXX"
#define ID_BOX "57c7f3291421551100bf13c8"
#define ID_SENSOR_WIFI "57c7f3291421551100bf13ca"

@ -3,6 +3,8 @@
#include <Time.h>
#include "config.h"
// TODO: refactor updateXXX members to be protected and called by getXXX ?
class Gps {
protected:
TinyGPSPlus gps;
@ -59,8 +61,12 @@ class Gps {
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() {
// 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"
#define DEBUG_OUT Serial
//#define DEBUG_OUT telnet
//TelnetPrint telnet = TelnetPrint();
Storage storage = Storage();
@ -23,15 +24,15 @@ void printState(WifiState wifiState) {
DEBUG_OUT.println(wifiState.numUnencrypted);
DEBUG_OUT.print("lat: ");
//DEBUG_OUT.print(gps.location.lat(), 6);
//DEBUG_OUT.print(gps.getLocation().lat(), 6);
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("");
}
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;
m.lat = lat;
m.lng = lng;
@ -51,7 +52,7 @@ void setup() {
//gps.begin();
wifi.begin();
//connectWifi(WIFI_SSID, WIFI_PASS);
wifi.connect(WIFI_SSID, WIFI_PASS);
//delay(5000); // DEBUG oportunity to connect to network logger
@ -76,7 +77,7 @@ void setup() {
void loop() {
//pollGPS();
//DEBUG_OUT.pollClients();
WifiState wifiState = wifi.scanWifi(WIFI_SSID);
WifiState wifiState = wifi.scan(WIFI_SSID);
char* dateString = gps.getISODate();
// TODO: take other measurements (average them?)
@ -86,7 +87,7 @@ void loop() {
*/
// 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: ");
} else {
DEBUG_OUT.print("measurement store failed! storage size: ");
@ -94,17 +95,14 @@ void loop() {
DEBUG_OUT.println(storage.size());
// TODO: connect to wifi, if available & not connected yet
// then upload local data, remove from storage
// DEBUG: recall all previous measurements
// then upload local data, remove from storage
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
api.postMeasurement(measure.substring(API_KEY_LENGTH + 1), measure.substring(0, API_KEY_LENGTH));
}
printState(wifiState);
delay(5000);
}

@ -2,45 +2,36 @@
#include <FS.h>
#include <ESP8266TrueRandom.h>
#include <ArduinoJson.h>
#include "api.h"
#include "config.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 {
char timeStamp[20];
float lat;
float lng;
float value;
char sensorID[32];
char sensorID[API_KEY_LENGTH];
};
class Storage {
protected:
// not needed, as we post the data as json string?
/*Measurement deserializeMeasurement(char* s) {
Measurement m;
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;
}*/
void serializeMeasurement(Measurement& m, Print& f) {
// prepend the sensor ID to the json
f << m.sensorID << EOL;
bool serializeMeasurement(Measurement& m, Print& f) {
f.println(m.sensorID);
StaticJsonBuffer<MEASUREMENT_JSON_SIZE> jsonBuffer;
JsonObject& root = jsonBuffer.createObject();
// TODO: replace temporary data model
root["createdAt"] = m.timeStamp;
root["lat"] = m.lat;
root["lng"] = m.lng;
root["value"] = m.value;
root.printTo(f);
return root.success();
// convert floats to strings
char val[10], lat[10], lng[10];
dtostrf(m.value, 5, 6, val);
dtostrf(m.lat, 5, 6, lat);
dtostrf(m.lng, 5, 6, lng);
f << "{\"value\":" << val
<< ",\"createdAt\":\"" << m.timeStamp
<< "\",\"lat\":" << lat
<< ",\"lng\":" << lng
<< "}" << EOL;
}
public:
@ -60,9 +51,9 @@ class Storage {
String fileName = directory + ESP8266TrueRandom.uuidToString(uuid).substring(26);
if (File f = SPIFFS.open(fileName, "w") ) {
bool success = serializeMeasurement(m, f);
serializeMeasurement(m, f);
f.close();
return success;
return true;
}
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);
}
WifiState scanWifi(String homeSSID) {
WifiState scan(String homeSSID) {
// TODO: filter duplicate SSIDs!
WifiState state;
state.homeAvailable = false;
@ -32,7 +32,7 @@ class Wifi {
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
unsigned long start = millis();

Loading…
Cancel
Save