add hardware switches for modes
This commit is contained in:
parent
ac8d10bb49
commit
e61cec10a1
4 changed files with 120 additions and 101 deletions
|
@ -8,7 +8,7 @@
|
||||||
|
|
||||||
# pragma once
|
# pragma once
|
||||||
#include <ESP8266WiFi.h>
|
#include <ESP8266WiFi.h>
|
||||||
#define MAX_TELNET_CLIENTS 3
|
#define MAX_TELNET_CLIENTS 3 // more
|
||||||
|
|
||||||
class TelnetPrint : public Print {
|
class TelnetPrint : public Print {
|
||||||
protected:
|
protected:
|
||||||
|
@ -47,7 +47,7 @@ class TelnetPrint : public Print {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: find more efficient method than sending byte by byte
|
// TODO: find more efficient method than sending byte by byte (!)
|
||||||
virtual size_t write(uint8_t s) {
|
virtual size_t write(uint8_t s) {
|
||||||
for(uint8_t i = 0; i < MAX_TELNET_CLIENTS; i++){
|
for(uint8_t i = 0; i < MAX_TELNET_CLIENTS; i++){
|
||||||
if (clients[i] && clients[i].connected()){
|
if (clients[i] && clients[i].connected()){
|
||||||
|
@ -58,13 +58,13 @@ class TelnetPrint : public Print {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Is only called for Strings, not char arrays
|
// Is only called for Strings, not char arrays
|
||||||
virtual size_t write(const char *buffer, size_t size) {
|
/*virtual size_t write(const char *buffer, size_t size) {
|
||||||
for(uint8_t i = 0; i < MAX_TELNET_CLIENTS; i++){
|
for(uint8_t i = 0; i < MAX_TELNET_CLIENTS; i++){
|
||||||
if (clients[i] && clients[i].connected()){
|
if (clients[i] && clients[i].connected()){
|
||||||
clients[i].write(buffer, size);
|
clients[i].write(buffer, size);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return size;
|
return size;
|
||||||
}
|
}*/
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
1
api.h
1
api.h
|
@ -9,7 +9,6 @@ class OsemApi {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
bool postMeasurement(String measurement, String sensorID) {
|
bool postMeasurement(String measurement, String sensorID) {
|
||||||
//telnet.print("Connecting to API.. ");
|
|
||||||
if (!client.connect(API_ENDPOINT, 443)) {
|
if (!client.connect(API_ENDPOINT, 443)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
29
config.h
29
config.h
|
@ -1,28 +1,35 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
/* GENERAL */
|
||||||
|
// interval of the measurements in ms. 0 for "as fast as possible"
|
||||||
|
#define MEASUREMENT_INTERVAL 10000
|
||||||
|
// pull this pin down to disable measurements (eg for quickly bulk uploading stored measurements)
|
||||||
|
#define PIN_MEASURE_MODE D14
|
||||||
|
// pull this pin down to disable uploads (eg for higher measurement rates when no realtime data is required)
|
||||||
|
#define PIN_UPLOAD_MODE D15
|
||||||
|
// should be higher than the number of sensors to avoid storage overflowing. tradeoff with the measurement interval
|
||||||
|
#define MAX_UPLOADS_PER_CYCLE 4
|
||||||
|
|
||||||
/* WiFi (ESP8266) */
|
/* WiFi (ESP8266) */
|
||||||
|
#define WIFI_SSID "Elmo"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#define WIFI_SSID "FRITZ!Box 7490"
|
|
||||||
#define WIFI_PASS "XXXXXX"
|
#define WIFI_PASS "XXXXXX"
|
||||||
|
|
||||||
/* GPS reciever (uBloc NEO-7M) */
|
|
||||||
#define GPS_RX_PIN 4
|
|
||||||
#define GPS_TX_PIN 3
|
|
||||||
|
|
||||||
|
/* GPS reciever (uBloc NEO-7M) connected to hardware serial (SoftwareSerial does not work well!!) */
|
||||||
#define GPS_BAUD 9600
|
#define GPS_BAUD 9600
|
||||||
#define GPS_INTERVAL 1000 // update interval of the gps device
|
#define GPS_INTERVAL 1000 // update interval of the gps device in ms
|
||||||
|
|
||||||
/* API (openSenseMap) */
|
/* API (openSenseMap) */
|
||||||
#define API_ENDPOINT "api.osem.vo1d.space"
|
#define API_ENDPOINT "api.osem.vo1d.space"
|
||||||
// SHA1 of the API SSL cert
|
// SHA1 of the API SSL cert
|
||||||
#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_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_LENGTH 24 // length of the keys
|
||||||
#define API_KEY "XXXXXXXXXXX"
|
#define API_KEY "XXXXXXXXXXX"
|
||||||
#define ID_BOX "57c7f3291421551100bf13c8"
|
#define ID_BOX "57c7f3291421551100bf13c8"
|
||||||
#define ID_SENSOR_WIFI_APS "57c7f3291421551100bf13ca"
|
#define ID_SENSOR_WIFI_APS "57c7f3291421551100bf13ca"
|
||||||
#define ID_SENSOR_WIFI_NET "57cdd4ce1421551100bf17c5"
|
#define ID_SENSOR_WIFI_NET "57cdd4ce1421551100bf17c5"
|
||||||
#define ID_SENSOR_WIFI_OPEN "57cdd4ce1421551100bf17c6"
|
#define ID_SENSOR_WIFI_OPEN "57cdd4ce1421551100bf17c6"
|
||||||
|
|
||||||
#define MEASUREMENT_INTERVAL 20000
|
|
||||||
|
|
|
@ -21,24 +21,80 @@ bool storeMeasurement(float lat, float lng, float value, const char* timeStamp,
|
||||||
m.value = value;
|
m.value = value;
|
||||||
strcpy(m.timeStamp, timeStamp);
|
strcpy(m.timeStamp, timeStamp);
|
||||||
strcpy(m.sensorID, sensorID);
|
strcpy(m.sensorID, sensorID);
|
||||||
|
|
||||||
return storage.add(m);
|
return storage.add(m);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool uploadMeasurements(const uint16_t maxUploads = 5) {
|
void measure(WifiState& wifiState) {
|
||||||
|
char dateString[20];
|
||||||
|
|
||||||
|
// measure WiFi
|
||||||
|
wifiState = wifi.scan(WIFI_SSID);
|
||||||
|
|
||||||
|
// update gps position
|
||||||
|
// TODO: how to handle lost GPS fix?
|
||||||
|
// TODO: check if is data is valid?
|
||||||
|
if(!gps.updateLocation() || !gps.updateTime()) {
|
||||||
|
DEBUG_OUT << "GPS timed out" << EOL;
|
||||||
|
digitalWrite(BUILTIN_LED, LOW);
|
||||||
|
} else {
|
||||||
|
digitalWrite(BUILTIN_LED, HIGH);
|
||||||
|
}
|
||||||
|
TinyGPSLocation loc = gps.getLocation();
|
||||||
|
gps.getISODate(dateString);
|
||||||
|
|
||||||
|
// print state
|
||||||
|
DEBUG_OUT << "homeAvailable: " << wifiState.homeAvailable << EOL;
|
||||||
|
DEBUG_OUT << "numAPs: " << wifiState.numAccessPoints << EOL;
|
||||||
|
DEBUG_OUT << "numNetworks: " << wifiState.numNetworks << EOL;
|
||||||
|
DEBUG_OUT << "numUnencrypted: " << wifiState.numUnencrypted << EOL;
|
||||||
|
DEBUG_OUT.print("lat: ");
|
||||||
|
DEBUG_OUT.print(loc.lat(), 6);
|
||||||
|
DEBUG_OUT.print(" lng: ");
|
||||||
|
DEBUG_OUT.println(loc.lng(), 6);
|
||||||
|
DEBUG_OUT << dateString << EOL;
|
||||||
|
|
||||||
|
// IDEA: write location update to separate file?
|
||||||
|
|
||||||
|
// write measurements to file
|
||||||
|
if (!storeMeasurement(loc.lat(), loc.lng(), wifiState.numAccessPoints, dateString, ID_SENSOR_WIFI_APS))
|
||||||
|
DEBUG_OUT << "measurement (wifi aps) store failed!" << EOL;
|
||||||
|
|
||||||
|
if (!storeMeasurement(loc.lat(), loc.lng(), wifiState.numNetworks, dateString, ID_SENSOR_WIFI_NET))
|
||||||
|
DEBUG_OUT << "measurement (wifi nets) store failed!" << EOL;
|
||||||
|
|
||||||
|
if (!storeMeasurement(loc.lat(), loc.lng(), wifiState.numUnencrypted, dateString, ID_SENSOR_WIFI_OPEN))
|
||||||
|
DEBUG_OUT << "measurement (wifi open) store failed!" << EOL;
|
||||||
|
|
||||||
|
DEBUG_OUT << EOL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void upload(WifiState& wifiState) {
|
||||||
|
size_t numMeasures = storage.size();
|
||||||
|
DEBUG_OUT << numMeasures << " measurements stored." << EOL;
|
||||||
|
if (!numMeasures) return;
|
||||||
|
|
||||||
|
// in case we are not measuring, scan manually to detect the home network
|
||||||
|
if (digitalRead(PIN_MEASURE_MODE) == LOW)
|
||||||
|
wifiState = wifi.scan(WIFI_SSID);
|
||||||
|
|
||||||
|
// connect to wifi, if available & not connected yet
|
||||||
|
// once we are connected, upload (max) 5 stored measurements & free the storage
|
||||||
|
if (wifi.isConnected() || (wifiState.homeAvailable && wifi.connect(WIFI_SSID, WIFI_PASS)) ) {
|
||||||
uint16_t uploadCount = 0;
|
uint16_t uploadCount = 0;
|
||||||
String measure;
|
String measure;
|
||||||
// only upload limited measures per cycle, to avoid long gaps in measurements
|
// only upload limited measures per cycle, to avoid long gaps in measurements
|
||||||
while (storage.size() && uploadCount++ < maxUploads) {
|
while (storage.size() && uploadCount++ < MAX_UPLOADS_PER_CYCLE) {
|
||||||
measure = storage.pop();
|
measure = storage.pop();
|
||||||
DEBUG_OUT << "Uploading measurement for " << measure;
|
DEBUG_OUT << "Uploading measurement for " << measure;
|
||||||
if(!api.postMeasurement(measure.substring(API_KEY_LENGTH + 1), measure.substring(0, API_KEY_LENGTH))) {
|
if (api.postMeasurement(measure.substring(API_KEY_LENGTH + 1), measure.substring(0, API_KEY_LENGTH)))
|
||||||
DEBUG_OUT << "upload failed!" << EOL;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
DEBUG_OUT << "success!" << EOL;
|
DEBUG_OUT << "success!" << EOL;
|
||||||
|
else
|
||||||
|
DEBUG_OUT << "upload failed!" << EOL;
|
||||||
}
|
}
|
||||||
return true;
|
} else {
|
||||||
|
DEBUG_OUT << "wifi connection to " << WIFI_SSID << " failed" << EOL;
|
||||||
|
}
|
||||||
|
DEBUG_OUT << EOL;
|
||||||
}
|
}
|
||||||
|
|
||||||
// delay for a given duration (ms), rollover-safe implementation
|
// delay for a given duration (ms), rollover-safe implementation
|
||||||
|
@ -54,13 +110,18 @@ void adaptiveDelay(unsigned long ms, unsigned long offset = 0) {
|
||||||
|
|
||||||
unsigned long now = millis();
|
unsigned long now = millis();
|
||||||
unsigned long elapsed = now - start + offset;
|
unsigned long elapsed = now - start + offset;
|
||||||
//DEBUG_OUT << elapsed << EOL;
|
|
||||||
if (elapsed >= ms) return;
|
if (elapsed >= ms) return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* MAIN ENTRY POINTS */
|
/* MAIN ENTRY POINTS */
|
||||||
void setup() {
|
void setup() {
|
||||||
|
pinMode(BUILTIN_LED, OUTPUT); // status indicator LED: on = no GPS fix
|
||||||
|
digitalWrite(BUILTIN_LED, LOW);
|
||||||
|
pinMode(PIN_MEASURE_MODE, INPUT_PULLUP); // switch for measurements (pull it down to disable)
|
||||||
|
pinMode(PIN_UPLOAD_MODE, INPUT_PULLUP); // switch for API uploads (pull it down to disable)
|
||||||
|
|
||||||
size_t bytesFree = storage.begin();
|
size_t bytesFree = storage.begin();
|
||||||
gps.begin();
|
gps.begin();
|
||||||
wifi.begin();
|
wifi.begin();
|
||||||
|
@ -68,89 +129,41 @@ void setup() {
|
||||||
// DEBUG: just for connection to telnet printer
|
// DEBUG: just for connection to telnet printer
|
||||||
wifi.connect(WIFI_SSID, WIFI_PASS);
|
wifi.connect(WIFI_SSID, WIFI_PASS);
|
||||||
DEBUG_OUT.begin();
|
DEBUG_OUT.begin();
|
||||||
delay(5000);
|
delay(3000);
|
||||||
telnet.pollClients();
|
telnet.pollClients();
|
||||||
|
|
||||||
// wait until we got a first fix from GPS, and thus an initial time
|
// wait until we got a first fix from GPS, and thus an initial time
|
||||||
DEBUG_OUT.print("Getting GPS fix..");
|
DEBUG_OUT << "Getting GPS fix..";
|
||||||
while (!gps.updateLocation()) { DEBUG_OUT.print("."); }
|
while (!gps.updateLocation()) { DEBUG_OUT << "."; }
|
||||||
DEBUG_OUT.println(" done! ");
|
DEBUG_OUT << " done!" << EOL;
|
||||||
|
digitalWrite(BUILTIN_LED, HIGH);
|
||||||
|
|
||||||
DEBUG_OUT.println("WiFi MAC WiFi IP");
|
DEBUG_OUT << "Setup done!" << EOL;
|
||||||
DEBUG_OUT.print(WiFi.macAddress());
|
DEBUG_OUT << "WiFi MAC WiFi IP" << EOL;
|
||||||
DEBUG_OUT.print(" ");
|
DEBUG_OUT << WiFi.macAddress() << " " << WiFi.localIP() << EOL;
|
||||||
DEBUG_OUT.println(WiFi.localIP());
|
DEBUG_OUT << "SPIFF bytes free: " << bytesFree << EOL << EOL;
|
||||||
|
|
||||||
DEBUG_OUT.print("SPIFF bytes free: ");
|
|
||||||
DEBUG_OUT.println(bytesFree);
|
|
||||||
|
|
||||||
DEBUG_OUT.println("Setup done!\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unsigned long cycleStart;
|
unsigned long cycleStart;
|
||||||
TinyGPSLocation loc;
|
WifiState wifiState; // global, as both measure and upload need the state
|
||||||
char dateString[20];
|
|
||||||
|
|
||||||
void loop() {
|
void loop() {
|
||||||
cycleStart = millis();
|
cycleStart = millis();
|
||||||
|
|
||||||
//gps.pollGPS();
|
if (digitalRead(PIN_MEASURE_MODE) == HIGH)
|
||||||
//telnet.pollClients();
|
measure(wifiState);
|
||||||
|
|
||||||
// measure WiFi
|
if (digitalRead(PIN_UPLOAD_MODE) == HIGH)
|
||||||
WifiState wifiState = wifi.scan(WIFI_SSID);
|
upload(wifiState);
|
||||||
|
|
||||||
// measure GPS
|
if (digitalRead(PIN_MEASURE_MODE) == HIGH) {
|
||||||
if(!gps.updateLocation()) DEBUG_OUT.println("GPS timed out (location)");
|
// run the measurements in a fixed interval, using an adaptive delay
|
||||||
if(!gps.updateTime()) DEBUG_OUT.println("GPS timed out (time)");
|
|
||||||
loc = gps.getLocation();
|
|
||||||
gps.getISODate(dateString);
|
|
||||||
|
|
||||||
// print state
|
|
||||||
DEBUG_OUT << "homeAvailable: " << wifiState.homeAvailable << EOL;
|
|
||||||
DEBUG_OUT << "numAPs: " << wifiState.numAccessPoints << EOL;
|
|
||||||
DEBUG_OUT << "numNetworks: " << wifiState.numNetworks << EOL;
|
|
||||||
DEBUG_OUT << "numUnencrypted: " << wifiState.numUnencrypted << EOL;
|
|
||||||
DEBUG_OUT.print("lat: ");
|
|
||||||
DEBUG_OUT.print(loc.lat(), 6);
|
|
||||||
DEBUG_OUT.print(" lng: ");
|
|
||||||
DEBUG_OUT.println(loc.lng(), 6);
|
|
||||||
DEBUG_OUT << dateString << EOL;
|
|
||||||
|
|
||||||
// TODO. write location update to file
|
|
||||||
|
|
||||||
// write measurements to file
|
|
||||||
if (storeMeasurement(loc.lat(), loc.lng(), wifiState.numAccessPoints, dateString, ID_SENSOR_WIFI_APS)) {
|
|
||||||
DEBUG_OUT.print("measurement (wifi aps) stored! storage size: ");
|
|
||||||
} else {
|
|
||||||
DEBUG_OUT.print("measurement (wifi aps) store failed! storage size: ");
|
|
||||||
}
|
|
||||||
DEBUG_OUT.println(storage.size());
|
|
||||||
if (storeMeasurement(loc.lat(), loc.lng(), wifiState.numNetworks, dateString, ID_SENSOR_WIFI_NET)) {
|
|
||||||
DEBUG_OUT.print("measurement (wifi nets) stored! storage size: ");
|
|
||||||
} else {
|
|
||||||
DEBUG_OUT.print("measurement (wifi nets) store failed! storage size: ");
|
|
||||||
}
|
|
||||||
DEBUG_OUT.println(storage.size());
|
|
||||||
if (storeMeasurement(loc.lat(), loc.lng(), wifiState.numUnencrypted, dateString, ID_SENSOR_WIFI_OPEN)) {
|
|
||||||
DEBUG_OUT.print("measurement (wifi open) stored! storage size: ");
|
|
||||||
} else {
|
|
||||||
DEBUG_OUT.print("measurement (wifi open) store failed! storage size: ");
|
|
||||||
}
|
|
||||||
DEBUG_OUT.println(storage.size());
|
|
||||||
|
|
||||||
// connect to wifi, if available & not connected yet
|
|
||||||
// once we are connected, upload (max) 4 stored measurements & free the storage
|
|
||||||
if (wifi.isConnected() || (wifiState.homeAvailable && wifi.connect(WIFI_SSID, WIFI_PASS)) ) {
|
|
||||||
uploadMeasurements(4);
|
|
||||||
}
|
|
||||||
|
|
||||||
DEBUG_OUT << EOL;
|
|
||||||
|
|
||||||
// the measurement & upload cycle takes ~4 seconds, so lets we wait measure
|
|
||||||
// every 10secs in total
|
|
||||||
// run the loop every 10secs. using an adaptive delay
|
|
||||||
// IDEA: dont use time but distance interval? -> TinyGPSPlus::distanceBetween()
|
// IDEA: dont use time but distance interval? -> TinyGPSPlus::distanceBetween()
|
||||||
adaptiveDelay(MEASUREMENT_INTERVAL, millis() - cycleStart);
|
adaptiveDelay(MEASUREMENT_INTERVAL, millis() - cycleStart);
|
||||||
|
} else {
|
||||||
|
// run as fast as possible when not measuring.
|
||||||
|
// adaptiveDelay has to be called anyway, as some polling functions are run within
|
||||||
|
adaptiveDelay(0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Reference in a new issue