Skip to content

Commit cc4bdac

Browse files
committed
Use ArduinoSTL in main Open Hive firmware to improve data collection
1 parent 6649cf0 commit cc4bdac

File tree

1 file changed

+118
-15
lines changed

1 file changed

+118
-15
lines changed

node-gprs-http/node-gprs-http.ino

Lines changed: 118 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
2016-06-20 Clemens Gruber | Modularization of upload URL
2121
2016-09-17 Clemens Gruber | Modularization of sensors and debugging
2222
2017-01-09 Clemens Gruber | Add support for HX711 and ESP8266
23+
2017-01-10 Andreas Motl | Improve sensor data collection
2324
2425
2526
GNU GPL v3 License
@@ -51,6 +52,22 @@
5152
A7 battery voltage
5253
*/
5354

55+
56+
// Standard C++ (STL) for Arduino for dynamic data structures like vector and map.
57+
// Required for AVR only, STL already seems to be included in Espressif SDK.
58+
#ifndef ARDUINO_ARCH_ESP8266
59+
#include <ArduinoSTL.h>
60+
#endif
61+
62+
63+
// TerkinData - flexible data collection for sensor readings
64+
// to decouple measurement from telemetry domain.
65+
#include <TerkinData.h>
66+
using namespace TerkinData;
67+
using namespace TerkinUtil;
68+
using std::string;
69+
70+
5471
// -------------------------+------
5572
// variables you can modify | START
5673
// -------------------------+------
@@ -207,7 +224,44 @@ unsigned long updateInterval = 60UL * 60UL; // s*m*h*d // seems it take 11 sec
207224
// do not use spaces before or after an comma
208225
//const char datasetHeader[] = "Date/Time,Weight,Outside Temp,Outside Humid,Inside Temp,Inside Humid,H1 Temp,H2 Temp,H3 Temp,H4 Temp,H5 Temp,Voltage";
209226
//const char datasetHeader[] = "Date/Time,Weight,Outside Temp,Outside Humid,Inside Temp,Voltage";
210-
const char datasetHeader[] = "Datum/Zeit,Gewicht,Aussen-Temperatur,Aussen-Feuchtigkeit,Brut-Temperatur,Spannung";
227+
//const char datasetHeader[] = "Datum/Zeit,Gewicht,Aussen-Temperatur,Aussen-Feuchtigkeit,Brut-Temperatur,Spannung";
228+
229+
230+
// ---------------------------------------
231+
// ** dynamic dataset (v2): infrastructure
232+
// ---------------------------------------
233+
234+
// Moved to "TerkinData" library.
235+
236+
237+
// ------------------------------
238+
// ** dynamic dataset (v2): setup
239+
// ------------------------------
240+
241+
void DataManager::setup() {
242+
243+
// List of field names
244+
this->field_names = new DataHeader({"time", "weight", "temp-outside", "humidity-outside", "temp-brood", "voltage"});
245+
246+
// List of human readable field names for backward compatibility
247+
this->field_labels = new DataHeader({"Datum/Zeit", "Gewicht", "Aussen-Temperatur", "Aussen-Feuchtigkeit", "Brut-Temperatur", "Spannung"});
248+
249+
// Optionally prefix header line with string
250+
//this->csv_header_prefix = "";
251+
252+
// Map names of lowlevel sensor values to highlevel telemetry data fields
253+
(*this->sensor_field_mapping)[string("dht.0.temp")] = string("temp-outside");
254+
(*this->sensor_field_mapping)[string("dht.0.hum")] = string("humidity-outside");
255+
(*this->sensor_field_mapping)[string("ds18b20.0")] = string("temp-brood");
256+
257+
}
258+
259+
DataManager *datamgr = new DataManager();
260+
261+
262+
// static dataset (v1) backward compatibility: Make opaque CSV header string from list of field name elements
263+
const char *datasetHeader = join(*datamgr->field_labels, ',').c_str();
264+
211265

212266
// -------------------------+----
213267
// variables you can modify | END
@@ -355,7 +409,7 @@ const char datasetHeader[] = "Datum/Zeit,Gewicht,Aussen-Temperatur,Aussen-Feucht
355409
#endif
356410

357411

358-
void setup () {
412+
void setup() {
359413
// debug and GSM
360414
Serial.begin(9600);
361415
#ifdef isDebug
@@ -443,6 +497,7 @@ void setup () {
443497
// some simplificatiion for your convenience
444498
// build uploadPath and upload header
445499
#if defined (isGSM) || defined (isWifi) || defined (isEthernet)
500+
446501
// build uploadPath
447502
snprintf(uploadPath, sizeof(uploadPath), uploadScheme,
448503
uploadDomain,
@@ -585,7 +640,7 @@ void setup () {
585640
// timestamp
586641
#ifdef isRTC
587642
#ifdef isWifi
588-
void getTimestamp() {
643+
void getTimestamp(Measurement& measurement) {
589644
// set timestamp later by server
590645
memcpy(timestampChar, "timestamp-by-server", sizeof("timestamp-by-server"));
591646
/*
@@ -646,14 +701,16 @@ void setup () {
646701
*/
647702
}
648703
#else
649-
void getTimestamp() {
704+
void getTimestamp(Measurement& measurement) {
650705

651706
// Get the current datetime
652707
DateTime currentTime = RTC.now();
653708

654709
// Write to char array
655710
snprintf(timestampChar, sizeof(timestampChar), "%d/%02d/%02d %02d:%02d:%02d", currentTime.year(), currentTime.month(), currentTime.date(), currentTime.hour(), currentTime.minute(), currentTime.second()); // write to char array
656711

712+
// Write to data container
713+
measurement.time = timestampChar;
657714
}
658715
#endif
659716
#endif
@@ -692,7 +749,7 @@ void setup () {
692749

693750
// weight
694751
#ifdef isScale
695-
void getWeight() {
752+
void getWeight(Measurement& measurement) {
696753
// clear running median samples
697754
weightSamples.clear();
698755

@@ -753,12 +810,14 @@ void setup () {
753810
// Write to char array
754811
dtostrf(weight, 8, 3, weightMedianChar);
755812

813+
// Write to data container
814+
measurement.data["weight"] = weight;
756815
}
757816
#endif
758817

759818
// temperature array / DS18B20
760819
#ifdef isTemperatureArray
761-
void getTemperature() {
820+
void getTemperature(Measurement& measurement) {
762821
// request temperature on all devices on the bus
763822
temperatureSensors.setWaitForConversion(false); // makes it async
764823
// initiatie temperature retrieval
@@ -783,13 +842,16 @@ void setup () {
783842
// Write to char array
784843
dtostrf(temperatureC, 5, 1, temperatureArrayChar[i]);
785844

845+
// Write to data container
846+
String key = "ds18b20." + String(i); // e.g. ds18b20.0, ds18b20.1, etc.
847+
measurement.data[key.c_str()] = temperatureC;
786848
}
787849
}
788850
#endif
789851

790852
// humidity and temperature / DHTxx
791853
#ifdef isHumidityTemperature
792-
void getHumidityTemperature() {
854+
void getHumidityTemperature(Measurement& measurement) {
793855
// read humidity and temperature data
794856
// loop through all devices
795857
for (int i=0; i<humidityNumDevices; i++) {
@@ -812,6 +874,10 @@ void setup () {
812874
// Read sensor the second time, this should deliver the appropriate values
813875
int chk = DHT.readHumidityType(humidityPins[i]);
814876

877+
// Prepare keys for data container, e.g. dht.0.temp, dht.0.hum, dht.1.temp, dht.1.hum, etc.
878+
String key_temp = "dht." + String(i) + ".temp";
879+
String key_hum = "dht." + String(i) + ".hum";
880+
815881
switch (chk) {
816882
// this is the normal case, all is working smoothly
817883
case DHTLIB_OK:
@@ -821,6 +887,9 @@ void setup () {
821887
dtostrf(DHT.temperature, 5, 1, temperatureChar[i]);
822888
dtostrf(DHT.humidity, 5, 1, humidityChar[i]);
823889

890+
// Write to data container
891+
measurement.data[key_temp.c_str()] = DHT.temperature;
892+
measurement.data[key_hum.c_str()] = DHT.humidity;
824893

825894
break;
826895

@@ -865,7 +934,7 @@ void setup () {
865934
// read value should be 411 (3.14V / 0.402V) and the max analog
866935
// read value should be 785 (6V / 0.767V).
867936
#ifdef isBattery
868-
void getVoltage() {
937+
void getVoltage(Measurement& measurement) {
869938
int batteryValue = analogRead(batteryPin); // read battery as analog value
870939

871940
// Compute voltage based on voltage divider resistors
@@ -874,6 +943,8 @@ void setup () {
874943
// Write to char array
875944
dtostrf(voltage,5,2,voltageChar); // write to char array
876945

946+
// Write to data container
947+
measurement.data["voltage"] = voltage;
877948

878949
}
879950
#endif
@@ -895,28 +966,32 @@ void setup () {
895966
// Main program
896967
// ------------
897968

898-
void loop () {
969+
void loop() {
970+
971+
// Data container to collect one reading
972+
Measurement *measurement = new Measurement();
973+
899974
// update data
900975
//
901976
// update timestamp
902977
#ifdef isRTC
903-
getTimestamp();
978+
getTimestamp(*measurement);
904979
#endif
905980
// update weight
906981
#ifdef isScale
907-
getWeight();
982+
getWeight(*measurement);
908983
#endif
909984
// update humidity and temperature, DHTxx
910985
#ifdef isHumidityTemperature
911-
getHumidityTemperature();
986+
getHumidityTemperature(*measurement);
912987
#endif
913988
// update temperature array
914989
#ifdef isTemperatureArray
915-
getTemperature();
990+
getTemperature(*measurement);
916991
#endif
917992
// update battery voltage
918993
#ifdef isBattery
919-
getVoltage();
994+
getVoltage(*measurement);
920995
#endif
921996

922997
/*
@@ -949,7 +1024,10 @@ void loop () {
9491024
Serial.println(voltageChar);
9501025
*/
9511026

952-
// build dataset
1027+
// ----------------------------
1028+
// ** static dataset (v1): data
1029+
// ----------------------------
1030+
9531031
// calculate size of dataset
9541032
char dataset[0
9551033
#ifdef isRTC
@@ -997,11 +1075,36 @@ void loop () {
9971075
strcat(dataset, ",");
9981076
strcat(dataset, voltageChar);
9991077
#endif
1078+
10001079
// debug
10011080
#ifdef isDebug
1081+
Serial.println("static dataset (v1)");
10021082
Serial.println(dataset);
10031083
#endif
10041084

1085+
1086+
// -----------------------------
1087+
// ** dynamic dataset (v2): data
1088+
// -----------------------------
1089+
1090+
std::string data_header = datamgr->csv_header();
1091+
std::string data_record = datamgr->csv_data(*measurement);
1092+
1093+
// debug
1094+
#ifdef isDebug
1095+
Serial.println("static dataset (v2)");
1096+
//Serial.println(data_record);
1097+
#endif
1098+
1099+
1100+
// ---------------
1101+
// ** Telemetry **
1102+
// ---------------
1103+
1104+
// TODO: Use HTTP POST
1105+
// TODO: Use MQTT
1106+
// TODO: Use SSL if possible
1107+
10051108
#if defined (isGSM) || defined (isWifi) || defined (isEthernet)
10061109
// replace spaces with plus for proper URL
10071110
for (int i = 0; dataset[i] != 0; i++) {

0 commit comments

Comments
 (0)