diff --git a/bin/config.min.htm b/bin/config.min.htm index 99fd1df..2ae55b0 100644 --- a/bin/config.min.htm +++ b/bin/config.min.htm @@ -1 +1 @@ -Beer Gravity Monitor

Temperature Format:


(C) Copyright 2021 Magnus Persson
\ No newline at end of file +Beer Gravity Monitor

Temperature Format:




(C) Copyright 2021 Magnus Persson
\ No newline at end of file diff --git a/bin/firmware-debug.bin b/bin/firmware-debug.bin index af786e7..cb169be 100644 Binary files a/bin/firmware-debug.bin and b/bin/firmware-debug.bin differ diff --git a/data/config.htm b/data/config.htm index acfd5af..8250204 100644 --- a/data/config.htm +++ b/data/config.htm @@ -119,6 +119,8 @@ +
+
@@ -147,19 +149,49 @@
- +
- +
+ +
+
- + +
+
+ +
+ +
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+ +
+
+
+ +
+
@@ -319,6 +351,10 @@ $("#http-push").val(cfg["http-push"]); $("#http-push2").val(cfg["http-push2"]); $("#brewfather-push").val(cfg["brewfather-push"]); + $("#influxdb2-push").val(cfg["influxdb2-push"]); + $("#influxdb2-org").val(cfg["influxdb2-org"]); + $("#influxdb2-bucket").val(cfg["influxdb2-bucket"]); + $("#influxdb2-auth").val(cfg["influxdb2-auth"]); $("#sleep-interval").val(cfg["sleep-interval"]); $("#voltage-factor").val(cfg["voltage-factor"]); $("#gravity-formula").val(cfg["gravity-formula"]); diff --git a/data/config.min.htm b/data/config.min.htm index 99fd1df..2ae55b0 100644 --- a/data/config.min.htm +++ b/data/config.min.htm @@ -1 +1 @@ -Beer Gravity Monitor

Temperature Format:


(C) Copyright 2021 Magnus Persson
\ No newline at end of file +Beer Gravity Monitor

Temperature Format:




(C) Copyright 2021 Magnus Persson
\ No newline at end of file diff --git a/data/device.htm b/data/device.htm index d41c105..c654e6e 100644 --- a/data/device.htm +++ b/data/device.htm @@ -118,7 +118,7 @@ $('#spinner').show(); $.getJSON(url, function (cfg) { console.log( cfg ); - $("#app-ver").text(cfg["app-ver"] + " (html 0.3.2)"); + $("#app-ver").text(cfg["app-ver"] + " (html 0.3.5)"); $("#mdns").text(cfg["mdns"]); $("#id").text(cfg["id"]); }) diff --git a/data/device.min.htm b/data/device.min.htm index dbff1be..2f5c2c3 100644 --- a/data/device.min.htm +++ b/data/device.min.htm @@ -14,4 +14,4 @@
- -->
(C) Copyright 2021 Magnus Persson
\ No newline at end of file + -->
(C) Copyright 2021 Magnus Persson
\ No newline at end of file diff --git a/platformio.ini b/platformio.ini index 4bf1b64..6d2626f 100644 --- a/platformio.ini +++ b/platformio.ini @@ -23,12 +23,11 @@ build_flags = #-O0 -Wl,-Map,output.map -D BAUD=${common_env_data.monitor_speed} -D ACTIVATE_OTA #-D SKIP_SLEEPMODE - -D COLLECT_PERFDATA -D USE_LITTLEFS=true -D EMBED_HTML -D USER_SSID=\""\"" # =\""myssid\"" -D USER_SSID_PWD=\""\"" # =\""mypwd\"" - -D CFG_APPVER="\"0.3.2\"" + -D CFG_APPVER="\"0.3.5\"" lib_deps = # https://github.com/jrowberg/i2cdevlib.git # Using local copy of this library https://github.com/codeplea/tinyexpr @@ -51,7 +50,8 @@ extra_scripts = build_unflags = ${common_env_data.build_unflags} build_flags = ${common_env_data.build_flags} - -D LOG_LEVEL=6 + -D COLLECT_PERFDATA # This option will collect runtime data for a few defined methods to measure time, dumped to serial or influxdb + -D LOG_LEVEL=6 # Maximum log level for the debug build. lib_deps = ${common_env_data.lib_deps} board = ${common_env_data.board} diff --git a/src/config.cpp b/src/config.cpp index 645bc5f..4848eb1 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -51,20 +51,24 @@ Config::Config() { // Populate the json document with all configuration parameters (used in both web and saving to file) // void Config::createJson(DynamicJsonDocument& doc) { - doc[ CFG_PARAM_MDNS ] = getMDNS(); - doc[ CFG_PARAM_ID ] = getID(); - doc[ CFG_PARAM_OTA ] = getOtaURL(); - doc[ CFG_PARAM_TEMPFORMAT ] = String( getTempFormat() ); - doc[ CFG_PARAM_PUSH_BREWFATHER ] = getBrewfatherPushTarget(); - doc[ CFG_PARAM_PUSH_HTTP ] = getHttpPushTarget(); - doc[ CFG_PARAM_PUSH_HTTP2 ] = getHttpPushTarget2(); - doc[ CFG_PARAM_SLEEP_INTERVAL ] = getSleepInterval(); -// doc[ CFG_PARAM_PUSH_INTERVAL ] = getSleepInterval(); // TODO: @deprecated - doc[ CFG_PARAM_VOLTAGEFACTOR ] = getVoltageFactor(); - doc[ CFG_PARAM_GRAVITY_FORMULA ] = getGravityFormula(); - doc[ CFG_PARAM_GRAVITY_FORMAT ] = String(getGravityFormat()); - doc[ CFG_PARAM_TEMP_ADJ ] = getTempSensorAdj(); - doc[ CFG_PARAM_GRAVITY_TEMP_ADJ ] = isGravityTempAdj(); + doc[ CFG_PARAM_MDNS ] = getMDNS(); + doc[ CFG_PARAM_ID ] = getID(); + doc[ CFG_PARAM_OTA ] = getOtaURL(); + doc[ CFG_PARAM_TEMPFORMAT ] = String( getTempFormat() ); + doc[ CFG_PARAM_PUSH_BREWFATHER ] = getBrewfatherPushUrl(); + doc[ CFG_PARAM_PUSH_HTTP ] = getHttpPushUrl(); + doc[ CFG_PARAM_PUSH_HTTP2 ] = getHttpPushUrl2(); + doc[ CFG_PARAM_PUSH_INFLUXDB2 ] = getInfluxDb2PushUrl(); + doc[ CFG_PARAM_PUSH_INFLUXDB2_ORG ] = getInfluxDb2PushOrg(); + doc[ CFG_PARAM_PUSH_INFLUXDB2_BUCKET ] = getInfluxDb2PushBucket(); + doc[ CFG_PARAM_PUSH_INFLUXDB2_AUTH ] = getInfluxDb2PushToken(); + doc[ CFG_PARAM_SLEEP_INTERVAL ] = getSleepInterval(); +// doc[ CFG_PARAM_PUSH_INTERVAL ] = getSleepInterval(); // TODO: @deprecated + doc[ CFG_PARAM_VOLTAGEFACTOR ] = getVoltageFactor(); + doc[ CFG_PARAM_GRAVITY_FORMULA ] = getGravityFormula(); + doc[ CFG_PARAM_GRAVITY_FORMAT ] = String(getGravityFormat()); + doc[ CFG_PARAM_TEMP_ADJ ] = getTempSensorAdj(); + doc[ CFG_PARAM_GRAVITY_TEMP_ADJ ] = isGravityTempAdj(); JsonObject cal = doc.createNestedObject( CFG_PARAM_GYRO_CALIBRATION ); cal["ax"] = gyroCalibration.ax; @@ -133,6 +137,8 @@ bool Config::loadFile() { return false; } + Log.notice(F("CFG : Size of configuration %d bytes." CR), configFile.size() ); + DynamicJsonDocument doc(CFG_JSON_BUFSIZE); DeserializationError err = deserializeJson(doc, configFile); #if LOG_LEVEL==6 @@ -158,11 +164,19 @@ bool Config::loadFile() { setTempFormat( s.charAt(0) ); } if( !doc[ CFG_PARAM_PUSH_BREWFATHER ].isNull() ) - setBrewfatherPushTarget( doc[ CFG_PARAM_PUSH_BREWFATHER ] ); + setBrewfatherPushUrl( doc[ CFG_PARAM_PUSH_BREWFATHER ] ); if( !doc[ CFG_PARAM_PUSH_HTTP ].isNull() ) - setHttpPushTarget( doc[ CFG_PARAM_PUSH_HTTP ] ); + setHttpPushUrl( doc[ CFG_PARAM_PUSH_HTTP ] ); if( !doc[ CFG_PARAM_PUSH_HTTP2 ].isNull() ) - setHttpPushTarget2( doc[ CFG_PARAM_PUSH_HTTP2 ] ); + setHttpPushUrl2( doc[ CFG_PARAM_PUSH_HTTP2 ] ); + if( !doc[ CFG_PARAM_PUSH_INFLUXDB2 ].isNull() ) + setInfluxDb2PushUrl( doc[ CFG_PARAM_PUSH_INFLUXDB2 ] ); + if( !doc[ CFG_PARAM_PUSH_INFLUXDB2_ORG ].isNull() ) + setInfluxDb2PushOrg( doc[ CFG_PARAM_PUSH_INFLUXDB2_ORG ] ); + if( !doc[ CFG_PARAM_PUSH_INFLUXDB2_BUCKET ].isNull() ) + setInfluxDb2PushBucket( doc[ CFG_PARAM_PUSH_INFLUXDB2_BUCKET ] ); + if( !doc[ CFG_PARAM_PUSH_INFLUXDB2_AUTH ].isNull() ) + setInfluxDb2PushToken( doc[ CFG_PARAM_PUSH_INFLUXDB2_AUTH ] ); if( !doc[ CFG_PARAM_SLEEP_INTERVAL ].isNull() ) setSleepInterval( doc[ CFG_PARAM_SLEEP_INTERVAL ].as() ); if( !doc[ CFG_PARAM_PUSH_INTERVAL ].isNull() ) // TODO: @deprecated @@ -231,16 +245,18 @@ void Config::debug() { Log.verbose(F("CFG : Dumping configration " CFG_FILENAME "." CR)); Log.verbose(F("CFG : ID; '%s'." CR), getID()); Log.verbose(F("CFG : mDNS; '%s'." CR), getMDNS() ); + Log.verbose(F("CFG : Sleep interval; %d." CR), getSleepInterval() ); Log.verbose(F("CFG : OTA; '%s'." CR), getOtaURL() ); Log.verbose(F("CFG : Temp; %c." CR), getTempFormat() ); Log.verbose(F("CFG : Temp Adj; %F." CR), getTempSensorAdj() ); Log.verbose(F("CFG : VoltageFactor; %F." CR), getVoltageFactor() ); Log.verbose(F("CFG : Gravity formula; '%s'." CR), getGravityFormula() ); Log.verbose(F("CFG : Gravity format; '%c'." CR), getGravityFormat() ); - Log.verbose(F("CFG : Push brewfather; '%s'." CR), getBrewfatherPushTarget() ); - Log.verbose(F("CFG : Push http; '%s'." CR), getHttpPushTarget() ); - Log.verbose(F("CFG : Push http2; '%s'." CR), getHttpPushTarget2() ); - Log.verbose(F("CFG : Sleep interval; %d." CR), getSleepInterval() ); + Log.verbose(F("CFG : Push brewfather; '%s'." CR), getBrewfatherPushUrl() ); + Log.verbose(F("CFG : Push http; '%s'." CR), getHttpPushUrl() ); + Log.verbose(F("CFG : Push http2; '%s'." CR), getHttpPushUrl2() ); + Log.verbose(F("CFG : InfluxDb2; '%s', '%s', '%s', '%s'." CR), getInfluxDb2PushUrl(), getInfluxDb2PushOrg(), + getInfluxDb2PushBucket(), getInfluxDb2PushToken() ); // Log.verbose(F("CFG : Accel offset\t%d\t%d\t%d" CR), gyroCalibration.ax, gyroCalibration.ay, gyroCalibration.az ); // Log.verbose(F("CFG : Gyro offset \t%d\t%d\t%d" CR), gyroCalibration.gx, gyroCalibration.gy, gyroCalibration.gz ); #endif diff --git a/src/config.h b/src/config.h index 8d24dce..cc9dd18 100644 --- a/src/config.h +++ b/src/config.h @@ -31,7 +31,7 @@ SOFTWARE. #include // defintions -#define CFG_JSON_BUFSIZE 1000 +#define CFG_JSON_BUFSIZE 2000 #define CFG_APPNAME "GravityMon " // Name of firmware #define CFG_FILENAME "/gravitymon.json" // Name of config file @@ -42,22 +42,26 @@ SOFTWARE. #define WIFI_PORTAL_TIMEOUT 120 // Number of seconds until the config portal is closed // These are used in API + Savefile -#define CFG_PARAM_ID "id" -#define CFG_PARAM_MDNS "mdns" // Device name -#define CFG_PARAM_OTA "ota-url" // Base URL for OTA -#define CFG_PARAM_PUSH_BREWFATHER "brewfather-push" // URL (brewfather format) -#define CFG_PARAM_PUSH_HTTP "http-push" // URL (iSpindle format) -#define CFG_PARAM_PUSH_HTTP2 "http-push2" // URL (iSpindle format) -#define CFG_PARAM_SLEEP_INTERVAL "sleep-interval" // Sleep interval +#define CFG_PARAM_ID "id" +#define CFG_PARAM_MDNS "mdns" // Device name +#define CFG_PARAM_OTA "ota-url" // Base URL for OTA +#define CFG_PARAM_PUSH_BREWFATHER "brewfather-push" // URL (brewfather format) +#define CFG_PARAM_PUSH_HTTP "http-push" // URL (iSpindle format) +#define CFG_PARAM_PUSH_HTTP2 "http-push2" // URL (iSpindle format) +#define CFG_PARAM_PUSH_INFLUXDB2 "influxdb2-push" // URL (iSpindle format) +#define CFG_PARAM_PUSH_INFLUXDB2_ORG "influxdb2-org" // URL (iSpindle format) +#define CFG_PARAM_PUSH_INFLUXDB2_BUCKET "influxdb2-bucket" // URL (iSpindle format) +#define CFG_PARAM_PUSH_INFLUXDB2_AUTH "influxdb2-auth" // URL (iSpindle format) +#define CFG_PARAM_SLEEP_INTERVAL "sleep-interval" // Sleep interval // TODO: @deprecated setting -#define CFG_PARAM_PUSH_INTERVAL "push-interval" // Time between push -#define CFG_PARAM_TEMPFORMAT "temp-format" // C or F -#define CFG_PARAM_VOLTAGEFACTOR "voltage-factor" // Factor to calculate the battery voltage -#define CFG_PARAM_GRAVITY_FORMULA "gravity-formula" // Formula for calculating gravity -#define CFG_PARAM_GRAVITY_FORMAT "gravity-format" // Gravity format G or P -#define CFG_PARAM_GRAVITY_TEMP_ADJ "gravity-temp-adjustment" // True/False. Adjust gravity for temperature -#define CFG_PARAM_TEMP_ADJ "temp-adjustment-value" // Correction value for temp sensor -#define CFG_PARAM_GYRO_CALIBRATION "gyro-calibration-data" // READ ONLY +#define CFG_PARAM_PUSH_INTERVAL "push-interval" // Time between push +#define CFG_PARAM_TEMPFORMAT "temp-format" // C or F +#define CFG_PARAM_VOLTAGEFACTOR "voltage-factor" // Factor to calculate the battery voltage +#define CFG_PARAM_GRAVITY_FORMULA "gravity-formula" // Formula for calculating gravity +#define CFG_PARAM_GRAVITY_FORMAT "gravity-format" // Gravity format G or P +#define CFG_PARAM_GRAVITY_TEMP_ADJ "gravity-temp-adjustment" // True/False. Adjust gravity for temperature +#define CFG_PARAM_TEMP_ADJ "temp-adjustment-value" // Correction value for temp sensor +#define CFG_PARAM_GYRO_CALIBRATION "gyro-calibration-data" // READ ONLY // These are used in API's #define CFG_PARAM_APP_NAME "app-name" @@ -98,9 +102,15 @@ class Config { int sleepInterval; // Push target settings - String brewfatherPushTarget; - String httpPushTarget; - String httpPushTarget2; + String brewfatherPushUrl; // URL For brewfather + + String httpPushUrl; // URL 1 for standard http + String httpPushUrl2; // URL 2 for standard http + + String influxDb2Url; // URL for InfluxDB v2 + String influxDb2Org; // Organisation for InfluxDB v2 + String influxDb2Bucket; // Bucket for InfluxDB v2 + String influxDb2Token; // Auth Token for InfluxDB v2 // Gravity and temperature calculations String gravityFormula; @@ -122,19 +132,31 @@ class Config { const char* getOtaURL() { return otaURL.c_str(); } void setOtaURL( String s ) { otaURL = s; saveNeeded = true; } - bool isOtaActive() { return otaURL.length()>0?true:false; } + bool isOtaActive() { return otaURL.length()?true:false; } - const char* getBrewfatherPushTarget() { return brewfatherPushTarget.c_str(); } - void setBrewfatherPushTarget( String s ) { brewfatherPushTarget = s; saveNeeded = true; } - bool isBrewfatherActive() { return brewfatherPushTarget.length()>0?true:false; } + // Brewfather + const char* getBrewfatherPushUrl() { return brewfatherPushUrl.c_str(); } + void setBrewfatherPushUrl( String s ) { brewfatherPushUrl = s; saveNeeded = true; } + bool isBrewfatherActive() { return brewfatherPushUrl.length()?true:false; } - const char* getHttpPushTarget() { return httpPushTarget.c_str(); } - void setHttpPushTarget( String s ) { httpPushTarget = s; saveNeeded = true; } - bool isHttpActive() { return httpPushTarget.length()>0?true:false; } + // Standard HTTP + const char* getHttpPushUrl() { return httpPushUrl.c_str(); } + void setHttpPushUrl( String s ) { httpPushUrl = s; saveNeeded = true; } + bool isHttpActive() { return httpPushUrl.length()?true:false; } + const char* getHttpPushUrl2() { return httpPushUrl2.c_str(); } + void setHttpPushUrl2( String s ) { httpPushUrl2 = s; saveNeeded = true; } + bool isHttpActive2() { return httpPushUrl2.length()?true:false; } - const char* getHttpPushTarget2() { return httpPushTarget2.c_str(); } - void setHttpPushTarget2( String s ) { httpPushTarget2 = s; saveNeeded = true; } - bool isHttpActive2() { return httpPushTarget2.length()>0?true:false; } + // InfluxDB2 + const char* getInfluxDb2PushUrl() { return influxDb2Url.c_str(); } + void setInfluxDb2PushUrl( String s ) { influxDb2Url = s; saveNeeded = true; } + bool isInfluxDb2Active() { return influxDb2Url.length()?true:false; } + const char* getInfluxDb2PushOrg() { return influxDb2Org.c_str(); } + void setInfluxDb2PushOrg( String s ) { influxDb2Org = s; saveNeeded = true; } + const char* getInfluxDb2PushBucket() { return influxDb2Bucket.c_str(); } + void setInfluxDb2PushBucket( String s ) { influxDb2Bucket = s; saveNeeded = true; } + const char* getInfluxDb2PushToken() { return influxDb2Token.c_str(); } + void setInfluxDb2PushToken( String s ) { influxDb2Token = s; saveNeeded = true; } int getSleepInterval() { return sleepInterval; } void setSleepInterval( int v ) { sleepInterval = v; saveNeeded = true; } diff --git a/src/helper.cpp b/src/helper.cpp index 08c1e2b..5f046cd 100644 --- a/src/helper.cpp +++ b/src/helper.cpp @@ -23,9 +23,10 @@ SOFTWARE. */ #include "helper.h" #include "config.h" +#include +#include SerialDebug mySerial; -PerfLogging myPerfLogging; BatteryVoltage myBatteryVoltage; // @@ -94,6 +95,115 @@ void BatteryVoltage::read() { #endif } + +#if defined( COLLECT_PERFDATA ) + +PerfLogging myPerfLogging; + +// +// Clear the current cache +// +void PerfLogging::clear() { + if( first == 0 ) + return; + + PerfEntry* pe = first; + + do { + PerfEntry* p = pe; + pe = pe->next; + delete p; + } while( pe != 0 ); + + first = 0; +} + +// +// Start measuring this performance point +// +void PerfLogging::start( const char* key ) { + PerfEntry* pe = add( key ); + pe->start = millis(); +} + +// +// Finalize measuring of this performance point +// +void PerfLogging::stop( const char* key ) { + PerfEntry* pe = find( key ); + + if( pe != 0 ) { + pe->end = millis(); + + unsigned long t = pe->end - pe->start; + + if( t > pe->max ) + pe->max = t; + } +} + +// +// Print the collected performance data +// +void PerfLogging::print() { + PerfEntry* pe = first; + + while( pe != 0 ) { + //Log.notice( F("PERF: %s=%l ms (%l, %l)" CR), pe->key, (pe->end - pe->start), pe->start, pe->end ); + Log.notice( F("PERF: %s %lms" CR), pe->key, pe->max ); + pe = pe->next; + } +} + +// +// Push collected performance data to influx (use influx configuration) +// +void PerfLogging::pushInflux() { + if( !myConfig.isInfluxDb2Active() ) + return; + + WiFiClient client; + HTTPClient http; + String serverPath = String(myConfig.getInfluxDb2PushUrl()) + "/api/v2/write?org=" + + String(myConfig.getInfluxDb2PushOrg()) + "&bucket=" + + String(myConfig.getInfluxDb2PushBucket()); + + http.begin( client, serverPath); + + // Create body for influxdb2, format used + // key,host=mdns value=0.0 + String body; + + PerfEntry* pe = first; + + while( pe != 0 ) { + char buf[100]; + sprintf( &buf[0], "%s,host=%s,device=%s value=%ld\n", pe->key, myConfig.getMDNS(), myConfig.getID(), pe->max); + body += &buf[0]; + pe = pe->next; + } + +#if LOG_LEVEL==6 + Log.verbose(F("PERF: url %s." CR), serverPath.c_str()); + Log.verbose(F("PERF: data %s." CR), body.c_str() ); +#endif + + // Send HTTP POST request + String auth = "Token " + String( myConfig.getInfluxDb2PushToken() ); + http.addHeader(F("Authorization"), auth.c_str() ); + int httpResponseCode = http.POST(body); + + if (httpResponseCode==204) { + Log.notice(F("PUSH: InfluxDB2 HTTP Response code %d" CR), httpResponseCode); + } else { + Log.error(F("PUSH: InfluxDB2 HTTP Response code %d" CR), httpResponseCode); + } + + http.end(); +} + +#endif // COLLECT_PERFDATA + // // Convert float to formatted string with n decimals. Buffer should be at least 10 chars. // diff --git a/src/helper.h b/src/helper.h index 4b70982..683f9e0 100644 --- a/src/helper.h +++ b/src/helper.h @@ -58,18 +58,6 @@ class BatteryVoltage { }; #if defined( COLLECT_PERFDATA ) -// Use these to collect performance data from various parts of the code -#define LOG_PERF_START(s) myPerfLogging.start(s) -#define LOG_PERF_STOP(s) myPerfLogging.stop(s) -#define LOG_PERF_PRINT() myPerfLogging.print() -#define LOG_PERF_CLEAR() myPerfLogging.clear() -#else -// These will disable the performance collection -#define LOG_PERF_START(s) -#define LOG_PERF_STOP(s) -#define LOG_PERF_PRINT() -#define LOG_PERF_CLEAR() -#endif class PerfLogging { private: @@ -124,67 +112,36 @@ class PerfLogging { return pe; }; - public: - // - // Clear the current cache - // - void clear() { - if( first == 0 ) - return; - - PerfEntry* pe = first; - - do { - PerfEntry* p = pe; - pe = pe->next; - delete p; - } while( pe != 0 ); - - first = 0; - } - - // - // Start measuring this performance point - // - void start( const char* key ) { - PerfEntry* pe = add( key ); - pe->start = millis(); - } - - // - // Finalize measuring of this performance point - // - void stop( const char* key ) { - PerfEntry* pe = find( key ); - - if( pe != 0 ) { - pe->end = millis(); - - unsigned long t = pe->end - pe->start; - - if( t > pe->max ) - pe->max = t; - } - } - - // - // Print the collected performance data - // - void print() { - PerfEntry* pe = first; - - while( pe != 0 ) { - //Log.notice( F("PERF: %s=%l ms (%l, %l)" CR), pe->key, (pe->end - pe->start), pe->start, pe->end ); - Log.notice( F("PERF: %s %lms" CR), pe->key, pe->max ); - pe = pe->next; - } - } + void clear(); + void start( const char* key ); + void stop( const char* key ); + void print(); + void pushInflux(); }; +extern PerfLogging myPerfLogging; + +// Use these to collect performance data from various parts of the code +#define LOG_PERF_START(s) myPerfLogging.start(s) +#define LOG_PERF_STOP(s) myPerfLogging.stop(s) +#define LOG_PERF_PRINT() myPerfLogging.print() +#define LOG_PERF_CLEAR() myPerfLogging.clear() +#define LOG_PERF_PUSH() myPerfLogging.pushInflux() + +#else + +// These will disable the performance collection +#define LOG_PERF_START(s) +#define LOG_PERF_STOP(s) +#define LOG_PERF_PRINT() +#define LOG_PERF_CLEAR() +#define LOG_PERF_PUSH() + +#endif // COLLECT_PERFDATA + // Global instance created extern SerialDebug mySerial; -extern PerfLogging myPerfLogging; extern BatteryVoltage myBatteryVoltage; #endif // _HELPER_H diff --git a/src/main.cpp b/src/main.cpp index 10b2c1a..73c627f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -91,6 +91,7 @@ void checkSleepMode( float angle, float volt ) { // Setup // void setup() { + LOG_PERF_START("run-time"); LOG_PERF_START("main-setup"); startMillis = millis(); @@ -160,8 +161,8 @@ void setup() { } LOG_PERF_STOP("main-setup"); - LOG_PERF_PRINT(); - LOG_PERF_CLEAR(); + LOG_PERF_PRINT(); // Dump data to serial + LOG_PERF_PUSH(); // Dump data to influx } // @@ -227,6 +228,8 @@ void loop() { LittleFS.end(); myGyro.enterSleep(); drd->stop(); + LOG_PERF_STOP("run-time"); + LOG_PERF_PUSH(); LOG_PERF_PRINT(); delay(100); deepSleep( myConfig.getSleepInterval() ); diff --git a/src/pushtarget.cpp b/src/pushtarget.cpp index 8dd7222..3d2f937 100644 --- a/src/pushtarget.cpp +++ b/src/pushtarget.cpp @@ -53,15 +53,67 @@ void PushTarget::send(float angle, float gravity, float temp, float runTime, boo if( myConfig.isHttpActive() ) { LOG_PERF_START("push-http"); - sendHttp( myConfig.getHttpPushTarget(), angle, gravity, temp, runTime ); + sendHttp( myConfig.getHttpPushUrl(), angle, gravity, temp, runTime ); LOG_PERF_STOP("push-http"); } if( myConfig.isHttpActive2() ) { LOG_PERF_START("push-http2"); - sendHttp( myConfig.getHttpPushTarget2(), angle, gravity, temp, runTime ); + sendHttp( myConfig.getHttpPushUrl2(), angle, gravity, temp, runTime ); LOG_PERF_STOP("push-http2"); } + + if( myConfig.isInfluxDb2Active() ) { + LOG_PERF_START("push-influxdb2"); + sendInfluxDb2( angle, gravity, temp, runTime ); + LOG_PERF_STOP("push-influxdb2"); + } +} + +// +// Send to influx db v2 +// +void PushTarget::sendInfluxDb2(float angle, float gravity, float temp, float runTime) { + Log.notice(F("PUSH: Sending values to influxdb2 angle=%F, gravity=%F, temp=%F." CR), angle, gravity, temp ); + + WiFiClient client; + HTTPClient http; + String serverPath = String(myConfig.getInfluxDb2PushUrl()) + "/api/v2/write?org=" + + String(myConfig.getInfluxDb2PushOrg()) + "&bucket=" + + String(myConfig.getInfluxDb2PushBucket()); + + http.begin( client, serverPath); + + // Create body for influxdb2 + char buf[1024]; + sprintf( &buf[0], "gravity,host=%s,device=%s,format=%s value=%.4f\n" + "temp,host=%s,device=%s,format=%c value=%.1f\n" + "battery,host=%s,device=%s value=%.2f\n" + "rssi,host=%s,device=%s value=%d\n", + // TODO: Add support for plato format + myConfig.getMDNS(), myConfig.getID(), "SG", gravity, + myConfig.getMDNS(), myConfig.getID(), myConfig.getTempFormat(), temp, + myConfig.getMDNS(), myConfig.getID(), myBatteryVoltage.getVoltage(), + myConfig.getMDNS(), myConfig.getID(), WiFi.RSSI() ); + +#if LOG_LEVEL==6 + Log.verbose(F("PUSH: url %s." CR), serverPath.c_str()); + Log.verbose(F("PUSH: data %s." CR), &buf[0] ); +#endif + + // Send HTTP POST request + String auth = "Token " + String( myConfig.getInfluxDb2PushToken() ); + http.addHeader(F("Authorization"), auth.c_str() ); + int httpResponseCode = http.POST(&buf[0]); + + if (httpResponseCode==204) { + Log.notice(F("PUSH: InfluxDB2 HTTP Response code %d" CR), httpResponseCode); + } else { + Log.error(F("PUSH: InfluxDB2 HTTP Response code %d" CR), httpResponseCode); + } + + http.end(); + } // @@ -91,22 +143,15 @@ void PushTarget::sendBrewfather(float angle, float gravity, float temp ) { // doc["name"] = myConfig.getMDNS(); doc["temp"] = reduceFloatPrecision( temp, 1); - //doc["aux_temp"] = 0; - //doc["ext_temp"] = 0; doc["temp_unit"] = String( myConfig.getTempFormat() ); - //doc["pressure"] = ; - //doc["pressure_unit"] = ; doc["battery"] = reduceFloatPrecision( myBatteryVoltage.getVoltage(), 2 ); + // TODO: Add support for plato format doc["gravity"] = reduceFloatPrecision( gravity, 4 ); doc["gravity_unit"] = myConfig.isGravitySG()?"G":"P"; - //doc["ph"] = 0; - //doc["bpm"] = 0; - //doc["comment"] = ""; - //doc["beer"] = ""; WiFiClient client; HTTPClient http; - String serverPath = myConfig.getBrewfatherPushTarget(); + String serverPath = myConfig.getBrewfatherPushUrl(); // Your Domain name with URL path or IP address with path http.begin( client, serverPath); @@ -122,9 +167,9 @@ void PushTarget::sendBrewfather(float angle, float gravity, float temp ) { int httpResponseCode = http.POST(json); if (httpResponseCode==200) { - Log.notice(F("PUSH: HTTP Response code %d" CR), httpResponseCode); + Log.notice(F("PUSH: Brewfather HTTP Response code %d" CR), httpResponseCode); } else { - Log.error(F("PUSH: HTTP Response code %d" CR), httpResponseCode); + Log.error(F("PUSH: Brewfather HTTP Response code %d" CR), httpResponseCode); } http.end(); @@ -139,19 +184,21 @@ void PushTarget::sendHttp( String serverPath, float angle, float gravity, float DynamicJsonDocument doc(256); // Use iSpindle format for compatibility - doc["name"] = myConfig.getMDNS(); - doc["ID"] = myConfig.getID(); - doc["token"] = "gravmon"; - doc["interval"] = myConfig.getSleepInterval(); - doc["temperature"] = reduceFloatPrecision( temp, 1 ); - doc["temp-units"] = String( myConfig.getTempFormat() ); - doc["gravity"] = reduceFloatPrecision( gravity, 4 ); - doc["angle"] = reduceFloatPrecision( angle, 2); - doc["battery"] = reduceFloatPrecision( myBatteryVoltage.getVoltage(), 2 ); - doc["rssi"] = WiFi.RSSI(); + doc["name"] = myConfig.getMDNS(); + doc["ID"] = myConfig.getID(); + doc["token"] = "gravmon"; + doc["interval"] = myConfig.getSleepInterval(); + doc["temperature"] = reduceFloatPrecision( temp, 1 ); + doc["temp-units"] = String( myConfig.getTempFormat() ); + // TODO: Add support for plato format + doc["gravity"] = reduceFloatPrecision( gravity, 4 ); + doc["angle"] = reduceFloatPrecision( angle, 2); + doc["battery"] = reduceFloatPrecision( myBatteryVoltage.getVoltage(), 2 ); + doc["rssi"] = WiFi.RSSI(); // Some additional information - doc["run-time"] = reduceFloatPrecision( runTime, 2 ); + doc["gravity-units"] = "SG"; + doc["run-time"] = reduceFloatPrecision( runTime, 2 ); WiFiClient client; HTTPClient http; diff --git a/src/pushtarget.h b/src/pushtarget.h index 2a897d2..66d2835 100644 --- a/src/pushtarget.h +++ b/src/pushtarget.h @@ -39,6 +39,7 @@ class PushTarget { void sendBrewfather(float angle, float gravity, float temp ); void sendHttp(String serverPath, float angle, float gravity, float temp, float runTime); + void sendInfluxDb2(float angle, float gravity, float temp, float runTime); public: PushTarget() { ms = millis(); } diff --git a/src/resources.cpp b/src/resources.cpp index 7fb48d0..b62e9a3 100644 --- a/src/resources.cpp +++ b/src/resources.cpp @@ -36,7 +36,6 @@ INCBIN(AboutHtm, "data/about.min.htm" ); // Minium web interface for uploading htm files INCBIN(UploadHtm, "data/upload.min.htm" ); - #endif // EOF \ No newline at end of file diff --git a/src/webserver.cpp b/src/webserver.cpp index 6e7f38a..062cde2 100644 --- a/src/webserver.cpp +++ b/src/webserver.cpp @@ -56,6 +56,7 @@ extern bool sleepModeAlwaysSkip; // Callback from webServer when / has been accessed. // void webHandleDevice() { + LOG_PERF_START("webserver-api-device"); #if LOG_LEVEL==6 Log.verbose(F("WEB : webServer callback for /api/config." CR)); #endif @@ -71,12 +72,14 @@ void webHandleDevice() { String out; serializeJson(doc, out); server.send(200, "application/json", out.c_str() ); + LOG_PERF_STOP("webserver-api-device"); } // // Callback from webServer when / has been accessed. // void webHandleConfig() { + LOG_PERF_START("webserver-api-config"); #if LOG_LEVEL==6 Log.verbose(F("WEB : webServer callback for /api/config." CR)); #endif @@ -98,12 +101,14 @@ void webHandleConfig() { String out; serializeJson(doc, out); server.send(200, "application/json", out.c_str() ); + LOG_PERF_STOP("webserver-api-config"); } // // Callback from webServer when / has been accessed. // void webHandleUpload() { + LOG_PERF_START("webserver-api-upload"); #if LOG_LEVEL==6 Log.verbose(F("WEB : webServer callback for /api/upload." CR)); #endif @@ -122,6 +127,7 @@ void webHandleUpload() { String out; serializeJson(doc, out); server.send(200, "application/json", out.c_str() ); + LOG_PERF_STOP("webserver-api-upload"); } // @@ -130,7 +136,7 @@ void webHandleUpload() { File uploadFile; void webHandleUploadFile() { - Log.notice(F("WEB : webServer callback for /api/upload/file." CR)); + LOG_PERF_START("webserver-api-upload-file"); #if LOG_LEVEL==6 Log.verbose(F("WEB : webServer callback for /api/upload/file." CR)); #endif @@ -164,12 +170,14 @@ void webHandleUploadFile() { } else { server.send(500, "text/plain", "Couldn't create file."); } + LOG_PERF_STOP("webserver-api-upload-file"); } // // Callback from webServer when / has been accessed. // void webHandleCalibrate() { + LOG_PERF_START("webserver-api-calibrate"); String id = server.arg( CFG_PARAM_ID ); #if LOG_LEVEL==6 Log.verbose(F("WEB : webServer callback for /api/calibrate." CR)); @@ -177,10 +185,12 @@ void webHandleCalibrate() { if( !id.equalsIgnoreCase( myConfig.getID() ) ) { Log.error(F("WEB : Wrong ID received %s, expected %s" CR), id.c_str(), myConfig.getID()); server.send(400, "text/plain", "Invalid ID."); + LOG_PERF_STOP("webserver-api-calibrate"); return; } myGyro.calibrateSensor(); server.send(200, "text/plain", "Device calibrated" ); + LOG_PERF_STOP("webserver-api-calibrate"); } // @@ -206,6 +216,7 @@ void webHandleFactoryReset() { // Callback from webServer when / has been accessed. // void webHandleStatus() { + LOG_PERF_START("webserver-api-status"); #if LOG_LEVEL==6 Log.verbose(F("WEB : webServer callback for /api/status." CR)); #endif @@ -231,6 +242,7 @@ void webHandleStatus() { String out; serializeJson(doc, out); server.send(200, "application/json", out.c_str() ); + LOG_PERF_STOP("webserver-api-status"); } // @@ -255,6 +267,7 @@ void webHandleClearWIFI() { // Used to force the device to never sleep. // void webHandleStatusSleepmode() { + LOG_PERF_START("webserver-api-sleepmode"); String id = server.arg( CFG_PARAM_ID ); #if LOG_LEVEL==6 Log.verbose(F("WEB : webServer callback for /api/status/sleepmode." CR) ); @@ -262,6 +275,7 @@ void webHandleStatusSleepmode() { if( !id.equalsIgnoreCase( myConfig.getID() ) ) { Log.error(F("WEB : Wrong ID received %s, expected %s" CR), id.c_str(), myConfig.getID()); server.send(400, "text/plain", "Invalid ID."); + LOG_PERF_STOP("webserver-api-sleepmode"); return; } #if LOG_LEVEL==6 @@ -272,12 +286,14 @@ void webHandleStatusSleepmode() { else sleepModeAlwaysSkip = false; server.send(200, "text/plain", "Sleep mode updated" ); + LOG_PERF_STOP("webserver-api-sleepmode"); } // // Update device settings. // void webHandleConfigDevice() { + LOG_PERF_START("webserver-api-config-device"); String id = server.arg( CFG_PARAM_ID ); #if LOG_LEVEL==6 Log.verbose(F("WEB : webServer callback for /api/config/device." CR) ); @@ -285,6 +301,7 @@ void webHandleConfigDevice() { if( !id.equalsIgnoreCase( myConfig.getID() ) ) { Log.error(F("WEB : Wrong ID received %s, expected %s" CR), id.c_str(), myConfig.getID()); server.send(400, "text/plain", "Invalid ID."); + LOG_PERF_STOP("webserver-api-config-device"); return; } #if LOG_LEVEL==6 @@ -296,12 +313,14 @@ void webHandleConfigDevice() { myConfig.saveFile(); server.sendHeader("Location", "/config.htm#collapseOne", true); server.send(302, "text/plain", "Device config updated" ); + LOG_PERF_STOP("webserver-api-config-device"); } // // Update push settings. // void webHandleConfigPush() { + LOG_PERF_START("webserver-api-config-push"); String id = server.arg( CFG_PARAM_ID ); #if LOG_LEVEL==6 Log.verbose(F("WEB : webServer callback for /api/config/push." CR) ); @@ -309,23 +328,34 @@ void webHandleConfigPush() { if( !id.equalsIgnoreCase( myConfig.getID() ) ) { Log.error(F("WEB : Wrong ID received %s, expected %s" CR), id.c_str(), myConfig.getID()); server.send(400, "text/plain", "Invalid ID."); + LOG_PERF_STOP("webserver-api-config-push"); return; } #if LOG_LEVEL==6 - Log.verbose(F("WEB : http=%s, bf=%s interval=%s." CR), server.arg( CFG_PARAM_PUSH_HTTP ).c_str(), server.arg( CFG_PARAM_PUSH_BREWFATHER ).c_str(), server.arg( CFG_PARAM_PUSH_INTERVAL ).c_str() ); + Log.verbose(F("WEB : http=%s,%s, bf=%s influx2=%s, %s, %s, %s." CR), server.arg( CFG_PARAM_PUSH_HTTP ).c_str(), + server.arg( CFG_PARAM_PUSH_HTTP2 ).c_str(), server.arg( CFG_PARAM_PUSH_BREWFATHER ).c_str(), + server.arg( CFG_PARAM_PUSH_INFLUXDB2 ).c_str(), server.arg( CFG_PARAM_PUSH_INFLUXDB2_ORG ).c_str(), + server.arg( CFG_PARAM_PUSH_INFLUXDB2_BUCKET ).c_str(), server.arg( CFG_PARAM_PUSH_INFLUXDB2_AUTH ).c_str() + ); #endif - myConfig.setHttpPushTarget( server.arg( CFG_PARAM_PUSH_HTTP ).c_str() ); - myConfig.setHttpPushTarget2( server.arg( CFG_PARAM_PUSH_HTTP2 ).c_str() ); - myConfig.setBrewfatherPushTarget( server.arg( CFG_PARAM_PUSH_BREWFATHER ).c_str() ); + myConfig.setHttpPushUrl( server.arg( CFG_PARAM_PUSH_HTTP ).c_str() ); + myConfig.setHttpPushUrl2( server.arg( CFG_PARAM_PUSH_HTTP2 ).c_str() ); + myConfig.setBrewfatherPushUrl( server.arg( CFG_PARAM_PUSH_BREWFATHER ).c_str() ); + myConfig.setInfluxDb2PushUrl( server.arg( CFG_PARAM_PUSH_INFLUXDB2 ).c_str() ); + myConfig.setInfluxDb2PushOrg( server.arg( CFG_PARAM_PUSH_INFLUXDB2_ORG ).c_str() ); + myConfig.setInfluxDb2PushBucket( server.arg( CFG_PARAM_PUSH_INFLUXDB2_BUCKET ).c_str() ); + myConfig.setInfluxDb2PushToken( server.arg( CFG_PARAM_PUSH_INFLUXDB2_AUTH ).c_str() ); myConfig.saveFile(); server.sendHeader("Location", "/config.htm#collapseTwo", true); server.send(302, "text/plain", "Push config updated" ); + LOG_PERF_STOP("webserver-api-config-push"); } // // Update gravity settings. // void webHandleConfigGravity() { + LOG_PERF_START("webserver-api-config-gravity"); String id = server.arg( CFG_PARAM_ID ); #if LOG_LEVEL==6 Log.verbose(F("WEB : webServer callback for /api/config/gravity." CR) ); @@ -333,6 +363,7 @@ void webHandleConfigGravity() { if( !id.equalsIgnoreCase( myConfig.getID() ) ) { Log.error(F("WEB : Wrong ID received %s, expected %s" CR), id.c_str(), myConfig.getID()); server.send(400, "text/plain", "Invalid ID."); + LOG_PERF_STOP("webserver-api-config-gravity"); return; } #if LOG_LEVEL==6 @@ -343,12 +374,14 @@ void webHandleConfigGravity() { myConfig.saveFile(); server.sendHeader("Location", "/config.htm#collapseThree", true); server.send(302, "text/plain", "Gravity config updated" ); + LOG_PERF_STOP("webserver-api-config-gravity"); } // // Update hardware settings. // void webHandleConfigHardware() { + LOG_PERF_START("webserver-api-config-hardware"); String id = server.arg( CFG_PARAM_ID ); #if LOG_LEVEL==6 Log.verbose(F("WEB : webServer callback for /api/config/hardware." CR) ); @@ -356,6 +389,7 @@ void webHandleConfigHardware() { if( !id.equalsIgnoreCase( myConfig.getID() ) ) { Log.error(F("WEB : Wrong ID received %s, expected %s" CR), id.c_str(), myConfig.getID()); server.send(400, "text/plain", "Invalid ID."); + LOG_PERF_STOP("webserver-api-config-hardware"); return; } #if LOG_LEVEL==6 @@ -367,6 +401,7 @@ void webHandleConfigHardware() { myConfig.saveFile(); server.sendHeader("Location", "/config.htm#collapseFour", true); server.send(302, "text/plain", "Hardware config updated" ); + LOG_PERF_STOP("webserver-api-config-hardware"); } // diff --git a/test/config.json b/test/config.json index fbeb053..8e94072 100644 --- a/test/config.json +++ b/test/config.json @@ -1,26 +1,30 @@ { - "mdns": "gravitymon2", - "id": "ee1bfc", - "ota-url": "", + "mdns": "gravmon3", + "id": "7376ef", + "ota-url": "http://192.168.1.100:80/firmware/gravmon/", "temp-format": "C", - "brewfather-push": "", - "http-push": "http://192.168.1.16:9090/api/v1/V7s7vRXLqnsW3HdxxRuD/telemetry", - "http-push2": "http://192.168.1.16:9090/test", + "brewfather-push": "http://log.brewfather.net/stream?id=KfkJU43jUFfj", + "http-push": "http://192.168.1.10:9090/api/v1/ZYfjlUNeiuyu9N/telemetry", + "http-push2": "http://192.168.1.10/ispindel", + "influxdb2-push": "http://192.168.1.10:8086", + "influxdb2-org": "hello", + "influxdb2-bucket": "spann", + "influxdb2-auth": "OijkU((jhfkh", "sleep-interval": 30, - "push-interval": 30, "voltage-factor": 1.59, "gravity-formula": "0.0*tilt^3+0.0*tilt^2+0.0017978*tilt+0.9436", + "gravity-format": "G", "temp-adjustment-value": 0, "gravity-temp-adjustment": false, "gyro-calibration-data": { - "ax": -4814, - "ay": 1143, - "az": 2270, - "gx": 47, - "gy": -25, - "gz": 47 + "ax": -330, + "ay": -2249, + "az": 1170, + "gx": 99, + "gy": -6, + "gz": 4 }, - "angle": 90.38, - "gravity": 1.1106, - "battery": 4.24 + "angle": 90.93, + "gravity": 1.105, + "battery": 0.04 } \ No newline at end of file