Просмотр исходного кода

Implement InfluxDB v2 (#2004)

* Implement InfluxDBv2 Innitial

* Update incl. UI

* Correct UI

* Update UI - Indiv. Param.

* Update edit_config_param.html

* Correct Timeshift

* Update Fieldname
jomjol 3 лет назад
Родитель
Сommit
1acd72d33e

+ 8 - 0
code/components/jomjol_flowcontroll/ClassFlowControll.cpp

@@ -60,6 +60,9 @@ std::string ClassFlowControll::doSingleStep(std::string _stepname, std::string _
     if ((_stepname.compare("[InfluxDB]") == 0) || (_stepname.compare(";[InfluxDB]") == 0)){
         _classname = "ClassFlowInfluxDB";
     }
+    if ((_stepname.compare("[InfluxDBv2]") == 0) || (_stepname.compare(";[InfluxDBv2]") == 0)){
+        _classname = "ClassFlowInfluxDBv2";
+    }
     #endif //ENABLE_INFLUXDB
 
     for (int i = 0; i < FlowControll.size(); ++i)
@@ -90,6 +93,8 @@ std::string ClassFlowControll::TranslateAktstatus(std::string _input)
     #ifdef ENABLE_INFLUXDB
         if (_input.compare("ClassFlowInfluxDB") == 0)
             return ("Sending InfluxDB");
+        if (_input.compare("ClassFlowInfluxDBv2") == 0)
+            return ("Sending InfluxDBv2");
     #endif //ENABLE_INFLUXDB
     if (_input.compare("ClassFlowPostProcessing") == 0)
         return ("Post-Processing");
@@ -233,6 +238,8 @@ ClassFlow* ClassFlowControll::CreateClassFlow(std::string _type)
     #ifdef ENABLE_INFLUXDB
     if (toUpper(_type).compare("[INFLUXDB]") == 0)
         cfc = new ClassFlowInfluxDB(&FlowControll);
+    if (toUpper(_type).compare("[INFLUXDBV2]") == 0)
+        cfc = new ClassFlowInfluxDBv2(&FlowControll);
     #endif //ENABLE_INFLUXDB  
     if (toUpper(_type).compare("[WRITELIST]") == 0)
         cfc = new ClassFlowWriteList(&FlowControll);
@@ -290,6 +297,7 @@ void ClassFlowControll::InitFlow(std::string config)
     while ((line.size() > 0) && !(feof(pFile)))
     {
         cfc = CreateClassFlow(line);
+//        printf("Name: %s\n", cfc->name().c_str());
         if (cfc)
         {
             ESP_LOGD(TAG, "Start ReadParameter (%s)", line.c_str());

+ 1 - 0
code/components/jomjol_flowcontroll/ClassFlowControll.h

@@ -15,6 +15,7 @@
 #endif //ENABLE_MQTT
 #ifdef ENABLE_INFLUXDB
 	#include "ClassFlowInfluxDB.h"
+	#include "ClassFlowInfluxDBv2.h"
 #endif //ENABLE_INFLUXDB
 #include "ClassFlowCNNGeneral.h"
 #include "ClassFlowWriteList.h"

+ 1 - 0
code/components/jomjol_flowcontroll/ClassFlowDefineTypes.h

@@ -50,6 +50,7 @@ struct NumberPost {
     int DecimalShiftInitial;
     float AnalogDigitalTransitionStart; // When is the digit > x.1, i.e. when does it start to tilt?
     int Nachkomma;
+    string Fieldname; // Fieldname in InfluxDB2  
 
     bool isExtendedResolution;
 

+ 219 - 0
code/components/jomjol_flowcontroll/ClassFlowInfluxDBv2.cpp

@@ -0,0 +1,219 @@
+#ifdef ENABLE_INFLUXDB
+#include <sstream>
+#include "ClassFlowInfluxDBv2.h"
+#include "Helper.h"
+#include "connect_wlan.h"
+
+#include "time_sntp.h"
+#include "interface_influxdb.h"
+
+#include "ClassFlowPostProcessing.h"
+#include "esp_log.h"
+#include "../../include/defines.h"
+
+#include "ClassLogFile.h"
+
+#include <time.h>
+
+static const char* TAG = "class_flow_influxDbv2";
+
+void ClassFlowInfluxDBv2::SetInitialParameter(void)
+{
+    uri = "";
+    database = "";
+    measurement = "";
+    dborg = "";  
+    dbtoken = "";  
+//    dbfield = "";
+
+    OldValue = "";
+    flowpostprocessing = NULL;  
+    previousElement = NULL;
+    ListFlowControll = NULL; 
+    disabled = false;
+    InfluxDBenable = false;
+}       
+
+ClassFlowInfluxDBv2::ClassFlowInfluxDBv2()
+{
+    SetInitialParameter();
+}
+
+ClassFlowInfluxDBv2::ClassFlowInfluxDBv2(std::vector<ClassFlow*>* lfc)
+{
+    SetInitialParameter();
+
+    ListFlowControll = lfc;
+    for (int i = 0; i < ListFlowControll->size(); ++i)
+    {
+        if (((*ListFlowControll)[i])->name().compare("ClassFlowPostProcessing") == 0)
+        {
+            flowpostprocessing = (ClassFlowPostProcessing*) (*ListFlowControll)[i];
+        }
+    }
+}
+
+ClassFlowInfluxDBv2::ClassFlowInfluxDBv2(std::vector<ClassFlow*>* lfc, ClassFlow *_prev)
+{
+    SetInitialParameter();
+
+    previousElement = _prev;
+    ListFlowControll = lfc;
+
+    for (int i = 0; i < ListFlowControll->size(); ++i)
+    {
+        if (((*ListFlowControll)[i])->name().compare("ClassFlowPostProcessing") == 0)
+        {
+            flowpostprocessing = (ClassFlowPostProcessing*) (*ListFlowControll)[i];
+        }
+    }
+}
+
+
+bool ClassFlowInfluxDBv2::ReadParameter(FILE* pfile, string& aktparamgraph)
+{
+    std::vector<string> splitted;
+
+    aktparamgraph = trim(aktparamgraph);
+    printf("akt param: %s\n", aktparamgraph.c_str());
+
+    if (aktparamgraph.size() == 0)
+        if (!this->GetNextParagraph(pfile, aktparamgraph))
+            return false;
+
+    if (toUpper(aktparamgraph).compare("[INFLUXDBV2]") != 0) 
+        return false;
+
+    while (this->getNextLine(pfile, &aktparamgraph) && !this->isNewParagraph(aktparamgraph))
+    {
+//        ESP_LOGD(TAG, "while loop reading line: %s", aktparamgraph.c_str());
+        splitted = ZerlegeZeile(aktparamgraph);
+        std::string _param = GetParameterName(splitted[0]);
+
+        if ((toUpper(_param) == "ORG") && (splitted.size() > 1))
+        {
+            this->dborg = splitted[1];
+        }  
+        if ((toUpper(_param) == "TOKEN") && (splitted.size() > 1))
+        {
+            this->dbtoken = splitted[1];
+        }               
+        if ((toUpper(_param) == "URI") && (splitted.size() > 1))
+        {
+            this->uri = splitted[1];
+        }
+        if (((toUpper(_param) == "MEASUREMENT")) && (splitted.size() > 1))
+        {
+            this->measurement = splitted[1];
+        }
+        if (((toUpper(_param) == "FIELDNAME")) && (splitted.size() > 1))
+        {
+            handleFieldname(splitted[0], splitted[1]);
+        }
+        if (((toUpper(splitted[0]) == "DATABASE")) && (splitted.size() > 1))
+        {
+            this->database = splitted[1];
+        }
+    }
+
+    printf("uri:         %s\n", uri.c_str());
+    printf("measurement: %s\n", measurement.c_str());
+    printf("org:         %s\n", dborg.c_str());
+    printf("token:       %s\n", dbtoken.c_str());
+
+    if ((uri.length() > 0) && (database.length() > 0) && (measurement.length() > 0) && (dbtoken.length() > 0) && (dborg.length() > 0)) 
+    { 
+        LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Init InfluxDB with uri: " + uri + ", measurement: " + measurement + ", org: " + dborg + ", token: *****");
+//        printf("vor V2 Init\n");
+        InfluxDB_V2_Init(uri, database, measurement, dborg, dbtoken); 
+//        printf("nach V2 Init\n");
+        InfluxDBenable = true;
+    } else {
+        LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "InfluxDBv2 (Verion2 !!!) init skipped as we are missing some parameters");
+    }
+   
+    return true;
+}
+
+
+string ClassFlowInfluxDBv2::GetInfluxDBMeasurement()
+{
+    return measurement;
+}
+
+void ClassFlowInfluxDBv2::handleFieldname(string _decsep, string _value)
+{
+    string _digit, _decpos;
+    int _pospunkt = _decsep.find_first_of(".");
+//    ESP_LOGD(TAG, "Name: %s, Pospunkt: %d", _decsep.c_str(), _pospunkt);
+    if (_pospunkt > -1)
+        _digit = _decsep.substr(0, _pospunkt);
+    else
+        _digit = "default";
+    for (int j = 0; j < flowpostprocessing->NUMBERS.size(); ++j)
+    {
+        if (_digit == "default")                        //  Set to default first (if nothing else is set)
+        {
+            flowpostprocessing->NUMBERS[j]->Fieldname = _value;
+        }
+        if (flowpostprocessing->NUMBERS[j]->name == _digit)
+        {
+            flowpostprocessing->NUMBERS[j]->Fieldname = _value;
+        }
+    }
+}
+
+
+
+bool ClassFlowInfluxDBv2::doFlow(string zwtime)
+{
+    if (!InfluxDBenable)
+        return true;
+
+    std::string result;
+    std::string resulterror = "";
+    std::string resultraw = "";
+    std::string resultrate = "";
+    std::string resulttimestamp = "";
+    string zw = "";
+    string namenumber = "";
+
+    if (flowpostprocessing)
+    {
+        std::vector<NumberPost*>* NUMBERS = flowpostprocessing->GetNumbers();
+
+        for (int i = 0; i < (*NUMBERS).size(); ++i)
+        {
+            result =  (*NUMBERS)[i]->ReturnValue;
+            resultraw =  (*NUMBERS)[i]->ReturnRawValue;
+            resulterror = (*NUMBERS)[i]->ErrorMessageText;
+            resultrate = (*NUMBERS)[i]->ReturnRateValue;
+            resulttimestamp = (*NUMBERS)[i]->timeStamp;
+
+            if ((*NUMBERS)[i]->Fieldname.length() > 0)
+            {
+                namenumber = (*NUMBERS)[i]->Fieldname;
+            }
+            else
+            {
+                namenumber = (*NUMBERS)[i]->name;
+                if (namenumber == "default")
+                    namenumber = "value";
+                else
+                    namenumber = namenumber + "/value";
+            }
+            
+            printf("vor sende Influx_DB_V2 - namenumber. %s, result: %s, timestampt: %s", namenumber.c_str(), result.c_str(), resulttimestamp.c_str());
+
+            if (result.length() > 0)   
+                InfluxDB_V2_Publish(namenumber, result, resulttimestamp);
+//                InfluxDB_V2_Publish(namenumber, result, resulttimestamp);
+        }
+    }
+   
+    OldValue = result;
+    
+    return true;
+}
+
+#endif //ENABLE_INFLUXDB

+ 41 - 0
code/components/jomjol_flowcontroll/ClassFlowInfluxDBv2.h

@@ -0,0 +1,41 @@
+#ifdef ENABLE_INFLUXDB
+
+#pragma once
+
+#ifndef CLASSFINFLUXDBv2_H
+#define CLASSFINFLUXDBv2_H
+
+#include "ClassFlow.h"
+
+#include "ClassFlowPostProcessing.h"
+
+#include <string>
+
+class ClassFlowInfluxDBv2 :
+    public ClassFlow
+{
+protected:
+    std::string uri, database, measurement;
+    std::string dborg, dbtoken, dbfield;
+    std::string OldValue;
+	ClassFlowPostProcessing* flowpostprocessing;  
+    bool InfluxDBenable;
+
+    void SetInitialParameter(void);     
+
+    void handleFieldname(string _decsep, string _value);   
+
+public:
+    ClassFlowInfluxDBv2();
+    ClassFlowInfluxDBv2(std::vector<ClassFlow*>* lfc);
+    ClassFlowInfluxDBv2(std::vector<ClassFlow*>* lfc, ClassFlow *_prev);
+
+    string GetInfluxDBMeasurement();
+
+    bool ReadParameter(FILE* pfile, string& aktparamgraph);
+    bool doFlow(string time);
+    string name(){return "ClassFlowInfluxDBv2";};
+};
+
+#endif //CLASSFINFLUXDBv2_H
+#endif //ENABLE_INFLUXDB

+ 2 - 1
code/components/jomjol_flowcontroll/ClassFlowPostProcessing.h

@@ -15,7 +15,6 @@ class ClassFlowPostProcessing :
     public ClassFlow
 {
 protected:
-    std::vector<NumberPost*> NUMBERS;
     bool UpdatePreValueINI;
 
     int PreValueAgeStartup; 
@@ -54,6 +53,8 @@ protected:
 
 public:
     bool PreValueUse;
+    std::vector<NumberPost*> NUMBERS;
+
 
     ClassFlowPostProcessing(std::vector<ClassFlow*>* lfc, ClassFlowCNNGeneral *_analog, ClassFlowCNNGeneral *_digit);
     virtual ~ClassFlowPostProcessing(){};

+ 2 - 4
code/components/jomjol_helper/Helper.cpp

@@ -576,9 +576,6 @@ std::vector<string> HelperZerlegeZeile(std::string input, std::string _delimiter
 std::vector<string> ZerlegeZeile(std::string input, std::string delimiter)
 {
 	std::vector<string> Output;
-
-	input = trim(input, delimiter);
-
 	/* The input can have multiple formats: 
 	 *  - key = value
      *  - key = value1 value2 value3 ...
@@ -593,12 +590,13 @@ std::vector<string> ZerlegeZeile(std::string input, std::string delimiter)
 	 * As a workaround and to not break any legacy usage, we enforce to only use the
 	 * equal sign, if the key is "password"
 	*/
-	if (input.find("password") != string::npos) { // Line contains a password, use the equal sign as the only delimiter and only split on first occurrence
+	if ((input.find("password") != string::npos) || (input.find("Token") != string::npos)) { // Line contains a password, use the equal sign as the only delimiter and only split on first occurrence
 		size_t pos = input.find("=");
 		Output.push_back(trim(input.substr(0, pos), ""));
 		Output.push_back(trim(input.substr(pos +1, string::npos), ""));
 	}
 	else { // Legacy Mode
+		input = trim(input, delimiter);							// sonst werden delimiter am Ende (z.B. == im Token) gelöscht)
 		size_t pos = findDelimiterPos(input, delimiter);
 		std::string token;
 		while (pos != std::string::npos) {

+ 114 - 15
code/components/jomjol_influxdb/interface_influxdb.cpp

@@ -16,6 +16,101 @@ std::string _influxDBMeasurement;
 std::string _influxDBUser;
 std::string _influxDBPassword;
 
+std::string _influxDB_V2_URI;
+std::string _influxDB_V2_Database;
+std::string _influxDB_V2_Measurement;
+std::string _influxDB_V2_Token;
+std::string _influxDB_V2_Org;
+
+static esp_err_t http_event_handler(esp_http_client_event_t *evt);
+
+void InfluxDB_V2_Init(std::string _uri, std::string _database, std::string _measurement, std::string _org, std::string _token)
+{
+    _influxDB_V2_URI = _uri;
+    _influxDB_V2_Database = _database;
+    _influxDB_V2_Measurement = _measurement;
+    _influxDB_V2_Org = _org;
+    _influxDB_V2_Token = _token;
+}
+
+void InfluxDB_V2_Publish(std::string _key, std::string _content, std::string _timestamp) 
+{
+    char response_buffer[MAX_HTTP_OUTPUT_BUFFER] = {0};
+    esp_http_client_config_t http_config = {
+       .user_agent = "ESP32 Meter reader",
+       .method = HTTP_METHOD_POST,
+       .event_handler = http_event_handler,
+       .buffer_size = MAX_HTTP_OUTPUT_BUFFER,
+       .user_data = response_buffer
+    };
+
+    LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "InfluxDB_V2_Publish - Key: " + _key + ", Content: " + _content + ", Timestamp: " + _timestamp);
+
+    // Format:     #define PREVALUE_TIME_FORMAT_OUTPUT "%Y-%m-%dT%H:%M:%S%z"
+
+    char nowTimestamp[21];
+    std::string payload;
+
+    if (_timestamp.length() > 0)
+    {
+        struct tm tm;
+        strptime(_timestamp.c_str(), PREVALUE_TIME_FORMAT_OUTPUT, &tm);
+        time_t t = mktime(&tm); // Time in Localtime (looks like timezone is not used by strptime)
+
+        struct tm * ptm;
+        ptm = gmtime ( &t );
+        time_t utc = mktime(ptm);
+        utc = 2*t - utc;        // Take care of timezone (looks difficult, but is easy: t = t + (t - utc), weil t-utc = timezone)
+
+        sprintf(nowTimestamp,"%ld000000000", (long) utc);           // UTC
+
+        payload = _influxDB_V2_Measurement + " " + _key + "=" + _content + " " + nowTimestamp;
+//        payload = _influxDB_V2_Measurement + " " + _key + "=774 " + nowTimestamp;
+    }
+    else
+    {
+        payload = _influxDB_V2_Measurement + " " + _key + "=" + _content;
+//        payload = _influxDB_V2_Measurement + " " + _key + "=774";
+    }
+
+    payload.shrink_to_fit();
+
+    LogFile.WriteToFile(ESP_LOG_INFO, TAG, "sending line to influxdb:" + payload);
+
+    std::string apiURI = _influxDB_V2_URI + "/api/v2/write?org=" + _influxDB_V2_Org + "&bucket=" + _influxDB_V2_Database;
+    apiURI.shrink_to_fit();
+    http_config.url = apiURI.c_str();
+    ESP_LOGI(TAG, "http_config: %s", http_config.url); // Add mark on log to see when it restarted
+
+    LogFile.WriteToFile(ESP_LOG_INFO, TAG, "API URI: " + apiURI);
+
+    esp_http_client_handle_t http_client = esp_http_client_init(&http_config);
+    LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "client is initialized");
+
+    esp_http_client_set_header(http_client, "Content-Type", "text/plain");
+    std::string _zw = "Token " + _influxDB_V2_Token;
+    //    LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Tokenheader: %s\n", _zw.c_str());
+    esp_http_client_set_header(http_client, "Authorization", _zw.c_str());
+
+    LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "header is set");
+
+    ESP_ERROR_CHECK(esp_http_client_set_post_field(http_client, payload.c_str(), payload.length()));
+    LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "post payload is set");
+
+    esp_err_t err = ESP_ERROR_CHECK_WITHOUT_ABORT(esp_http_client_perform(http_client));
+
+    if( err == ESP_OK ) {
+      LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "HTTP request was performed");
+      int status_code = esp_http_client_get_status_code(http_client);
+      LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "HTTP status code" + std::to_string(status_code));
+    } else {
+      LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "HTTP request failed");
+    }
+    esp_http_client_cleanup(http_client);
+}
+
+
+
 static esp_err_t http_event_handler(esp_http_client_event_t *evt)
 {
     switch(evt->event_id)
@@ -64,26 +159,30 @@ void InfluxDBPublish(std::string _key, std::string _content, std::string _timest
 
     LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "InfluxDBPublish - Key: " + _key + ", Content: " + _content + ", Timestamp: " + _timestamp);
 
-    // Format:     #define PREVALUE_TIME_FORMAT_OUTPUT "%Y-%m-%dT%H:%M:%S%z"
-    struct tm tm;
-    strptime(_timestamp.c_str(), PREVALUE_TIME_FORMAT_OUTPUT, &tm);
-
-    time_t t = mktime(&tm); // Time in Localtime (looks like timezone is not used by strptime)
-
-    struct tm * ptm;
-    ptm = gmtime ( &t );
-
-    time_t utc = mktime(ptm);
-    utc = 2*t - utc;
-
     char nowTimestamp[21];
+    std::string payload;
+
+    if (_timestamp.length() > 0)
+    {
+        struct tm tm;
+        strptime(_timestamp.c_str(), PREVALUE_TIME_FORMAT_OUTPUT, &tm);
+        time_t t = mktime(&tm); // Time in Localtime (looks like timezone is not used by strptime)
 
-    sprintf(nowTimestamp,"%ld000000000", (long) utc);           // UTC
+        struct tm * ptm;
+        ptm = gmtime ( &t );
+        time_t utc = mktime(ptm);
+        utc = 2*t - utc;        // Take care of timezone (looks difficult, but is easy: t = t + (t - utc), weil t-utc = timezone)
 
+        sprintf(nowTimestamp,"%ld000000000", (long) utc);           // UTC
 
-//    LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Test Time Conversion - t: " + std::to_string(t) + ", utc: " + std::to_string(utc) + ", now: " + std::to_string(now) + ", utc_local: " + std::to_string(utc_local));
+        payload = _influxDB_V2_Measurement + " " + _key + "=" + _content + " " + nowTimestamp;
+//        payload = _influxDB_V2_Measurement + " " + _key + "=774 " + nowTimestamp;
+    }
+    else
+    {
+        payload = _influxDBMeasurement + " " + _key + "=" + _content;
+    }
 
-    std::string payload = _influxDBMeasurement + " " + _key + "=" + _content + " " + nowTimestamp;
     payload.shrink_to_fit();
 
     LogFile.WriteToFile(ESP_LOG_INFO, TAG, "sending line to influxdb:" + payload);

+ 9 - 2
code/components/jomjol_influxdb/interface_influxdb.h

@@ -8,10 +8,17 @@
 #include <map>
 #include <functional>
 
+// Interface to InfluxDB v1.x
 void InfluxDBInit(std::string _influxDBURI, std::string _database, std::string _measurement, std::string _user, std::string _password);
-void InfluxDBdestroy();
-
 void InfluxDBPublish(std::string _key, std::string _content, std::string _timestamp);
 
+// Interface to InfluxDB v2.x
+void InfluxDB_V2_Init(std::string _uri, std::string _database, std::string _measurement, std::string _org, std::string _token);
+void InfluxDB_V2_Publish(std::string _key, std::string _content, std::string _timestamp);
+
+
+
+void InfluxDBdestroy();
+
 #endif //INTERFACE_INFLUXDB_H
 #endif //ENABLE_INFLUXDB

+ 165 - 15
sd-card/html/edit_config_param.html

@@ -456,7 +456,7 @@ textarea {
 			</td>
 		</tr>
 		<tr>
-			<td class="indent1">
+			<td class="indent1" style="padding-left: 75px;">
 				<input type="checkbox" id="PostProcessing_AllowNegativeRates_enabled" value="1"  onclick = 'InvertEnableItem("PostProcessing", "AllowNegativeRates")' unchecked >
 				<label for=PostProcessing_AllowNegativeRates_enabled><class id="PostProcessing_AllowNegativeRates_text" style="color:black;">AllowNegativeRates</class></label>
 			</td>
@@ -471,7 +471,7 @@ textarea {
 			</td>
 		</tr>
 		<tr>
-			<td class="indent1">
+			<td class="indent1" style="padding-left: 75px;">
 				<input type="checkbox" id="PostProcessing_DecimalShift_enabled" value="1"  onclick = 'InvertEnableItem("PostProcessing", "DecimalShift")' unchecked >
 				<label for=PostProcessing_DecimalShift_enabled><class id="PostProcessing_DecimalShift_text" style="color:black;">DecimalShift</class></label>
 			</td>
@@ -484,7 +484,7 @@ textarea {
 			</td>
 		</tr>
 		<tr>
-			<td class="indent1">
+			<td class="indent1" style="padding-left: 75px;">
 				<input type="checkbox" id="PostProcessing_AnalogDigitalTransitionStart_enabled" value="1"  onclick = 'InvertEnableItem("PostProcessing", "AnalogDigitalTransitionStart")' unchecked >
 				<label for=PostProcessing_AnalogDigitalTransitionStart_enabled><class id="PostProcessing_AnalogDigitalTransitionStart_text" style="color:black;">AnalogDigitalTransitionStart</class></label>
 			</td>
@@ -498,7 +498,7 @@ textarea {
 		</tr>
 
 		<tr>
-			<td class="indent1">
+			<td class="indent1" style="padding-left: 75px;">
 				<input type="checkbox" id="PostProcessing_MaxRateValue_enabled" value="1"  onclick = 'InvertEnableItem("PostProcessing", "MaxRateValue")' unchecked >
 				<label for=PostProcessing_MaxRateValue_enabled><class id="PostProcessing_MaxRateValue_text" style="color:black;">MaxRateValue</class></label>
 			</td>
@@ -510,7 +510,7 @@ textarea {
 			</td>
 		</tr>
 		<tr>
-			<td class="indent1">
+			<td class="indent1" style="padding-left: 75px;">
 				<input type="checkbox" id="PostProcessing_MaxRateType_enabled" value="1"  onclick = 'InvertEnableItem("PostProcessing", "MaxRateType")' unchecked >
 				<label for=PostProcessing_MaxRateType_enabled><class id="PostProcessing_MaxRateType_text" style="color:black;">MaxRateType</class></label>
 			</td>
@@ -525,7 +525,7 @@ textarea {
 			</td>
 		</tr>
 		<tr>
-			<td class="indent1">
+			<td class="indent1" style="padding-left: 75px;">
 				<input type="checkbox" id="PostProcessing_ExtendedResolution_enabled" value="1"  onclick = 'InvertEnableItem("PostProcessing", "ExtendedResolution")' unchecked >
 			<label for=PostProcessing_ExtendedResolution_enabled><class id="PostProcessing_ExtendedResolution_text" style="color:black;">ExtendedResolution</class></label>
 			</td>
@@ -541,7 +541,7 @@ textarea {
 		</tr>
 		
 		<tr>
-			<td id="ex121" class="indent1">
+			<td id="ex121" class="indent1" style="padding-left: 75px;">
 				<input type="checkbox" id="PostProcessing_IgnoreLeadingNaN_enabled" value="1"  onclick = 'InvertEnableItem("PostProcessing", "IgnoreLeadingNaN")' unchecked >
 			<label for=PostProcessing_IgnoreLeadingNaN_enabled><class id="PostProcessing_IgnoreLeadingNaN_text" style="color:black;">IgnoreLeadingNaN</class></label>
 			</td>
@@ -701,7 +701,7 @@ textarea {
 			<td colspan="3" style="padding-left: 20px;">
 			    <h4>
 				<input type="checkbox" id="Category_InfluxDB_enabled" value="1"  onclick = 'UpdateAfterCategoryCheck()' unchecked >
-				<label for=Category_InfluxDB_enabled>InfluxDB</h4><h5>Only InfluxDB v1.x is supported, v2.x has a changed interface</h5></label>				
+				<label for=Category_InfluxDB_enabled>InfluxDB</h4><h5>Only InfluxDB v1.x is configured here - v2.x see below [InfluxDBv2]</h5></label>				
 			</td>
 		</tr> 		
 		<tr>
@@ -765,6 +765,109 @@ textarea {
 			</td>
 		</tr>
 
+
+
+		<tr>
+			<td colspan="3" style="padding-left: 20px;">
+			    <h4>
+				<input type="checkbox" id="Category_InfluxDBv2_enabled" value="1"  onclick = 'UpdateAfterCategoryCheck()' unchecked >
+				<label for=Category_InfluxDBv2_enabled>InfluxDBv2</h4><h5>Only InfluxDB v2.x is configured here, v1.x see above [InfluxDB]</h5></label>				
+			</td>
+		</tr> 		
+		<tr>
+			<td class="indent1">
+				<input type="checkbox" id="InfluxDBv2_Uri_enabled" value="1"  onclick = 'InvertEnableItem("InfluxDBv2", "Uri")' unchecked >
+				<label for=InfluxDBv2_Uri_enabled><class id="InfluxDBv2_Uri_text" style="color:black;">Uri</class></label>
+			</td>
+			<td>
+				<input type="text" id="InfluxDBv2_Uri_value1">
+			</td>
+			<td style="font-size: 80%;">
+				URI of the HTTP interface to InfluxDB (Version2), without traililing slash, e.g. http://IP-Address:Port
+			</td>
+		</tr>
+                <tr>
+			<td class="indent1">
+				<input type="checkbox" id="InfluxDBv2_Database_enabled" value="1"  onclick = 'InvertEnableItem("InfluxDBv2", "Database")' unchecked >
+				<label for=InfluxDBv2_Database_enabled><class id="InfluxDBv2_Database_text" style="color:black;">Database</class></label>
+			</td>
+			<td>
+				<input type="text" id="InfluxDBv2_Database_value1">
+			</td>
+			<td style="font-size: 80%;">
+                                Database name in which to publish the read value.
+			</td>
+		</tr>
+		<tr>
+			<td class="indent1">
+				<input type="checkbox" id="InfluxDBv2_Measurement_enabled" value="1"  onclick = 'InvertEnableItem("InfluxDBv2", "Measurement")' unchecked >
+				<label for=InfluxDBv2_Measurement_enabled><class id="InfluxDBv2_Measurement_text" style="color:black;">Measurement</class></label>
+			</td>
+			<td>
+				<input type="text" id="InfluxDBv2_Measurement_value1">
+			</td>
+			<td style="font-size: 80%;">
+                                Measurement name to use to publish the read value.
+			</td>
+		</tr>
+		<tr>
+			<td class="indent1">
+				<input type="checkbox" id="InfluxDBv2_Org_enabled" value="1"  onclick = 'InvertEnableItem("InfluxDBv2", "Org")' unchecked >
+				<label for=InfluxDBv2_Org_enabled><class id="InfluxDBv2_Org_text" style="color:black;">Org</class></label>
+			</td>
+			<td>
+				<input type="text" id="InfluxDBv2_Org_value1">
+			</td>
+			<td style="font-size: 80%;">
+				Organisation (Org) for InfluxDBv2 authentication
+			</td>
+		</tr>
+		<tr>
+			<td class="indent1">
+				<input type="checkbox" id="InfluxDBv2_Token_enabled" value="1"  onclick = 'InvertEnableItem("InfluxDBv2", "Token")' unchecked >
+				<label for=InfluxDBv2_Token_enabled><class id="InfluxDBv2_Token_text" style="color:black;">Token</class></label>
+			</td>
+			<td>
+				<input type="text" id="InfluxDBv2_Token_value1">
+			</td>
+			<td style="font-size: 80%;">
+				Token for InfluxDB authentication
+			</td>
+		</tr>
+		<tr>
+			<td class="indent1" colspan="3">
+				<br>
+				<b>Postprocessing Individual Parameters: 
+                <select id="NumbersInfluxDB_value1" onchange="numberInfluxDBChanged()">
+                    <option value="0" selected>default</option>
+                    <option value="1" >NT</option>
+                    <option value="2" >HT</option>
+                </select></b>
+			</td>
+		</tr>
+		<tr>
+			<td class="indent1" style="padding-left: 75px;">
+				<input type="checkbox" id="InfluxDBv2_Fieldname_enabled" value="1"  onclick = 'InvertEnableItem("InfluxDBv2", "Fieldname")' unchecked >
+				<label for=InfluxDBv2_Fieldname_enabled><class id="InfluxDBv2_Fieldname_text" style="color:black;">Fieldname</class></label>
+			</td>
+			<td>
+				<input type="text" id="InfluxDBv2_Fieldname_value1">
+			</td>
+			<td style="font-size: 80%;">
+                                Fieldname to use for saving.
+			</td>
+		</tr>
+
+
+
+
+
+
+
+
+
+
+
 		<tr>
 			<td colspan="3" style="padding-left: 20px;">
 				<h4><input type="checkbox" id="Category_GPIO_enabled" value="1"  onclick='UpdateAfterCategoryCheck()' unchecked > 
@@ -1464,7 +1567,8 @@ function LoadConfigNeu() {
 	InitIndivParameter();
 
 	UpdateInput();
-	UpdateInputIndividual();
+	var sel = document.getElementById("Numbers_value1");
+	UpdateInputIndividual(sel);
 	UpdateExpertModus();
 	document.getElementById("divall").style.display = ''; 
 }
@@ -1476,14 +1580,23 @@ function InitIndivParameter()
     var _index = document.getElementById("Numbers_value1");
     while (_index.length)
         _index.remove(0);
+	var _indexInflux = document.getElementById("NumbersInfluxDB_value1");
+    while (_indexInflux.length)
+		_indexInflux.remove(0);
 
     for (var i = 0; i < NUMBERS.length; ++i){
         var option = document.createElement("option");
         option.text = NUMBERS[i]["name"];
         option.value = i;
         _index.add(option);
+
+		var optionInflux = document.createElement("option");
+        optionInflux.text = NUMBERS[i]["name"];
+        optionInflux.value = i;
+		_indexInflux.add(optionInflux);
         }
     _index.selectedIndex = 0; 
+	_indexInflux.selectedIndex = 0; 
 }
 
 
@@ -1768,7 +1881,7 @@ function ReadParameter(_param, _cat, _name, _optional, _number = -1){
 	}
 }
 
-function UpdateInputIndividual()
+function UpdateInputIndividual(sel)
 {
 	if (NUNBERSAkt != -1)
 	{
@@ -1779,9 +1892,10 @@ function UpdateInputIndividual()
 		ReadParameter(param, "PostProcessing", "ExtendedResolution", true, NUNBERSAkt)		
 		ReadParameter(param, "PostProcessing", "IgnoreLeadingNaN", true, NUNBERSAkt)		
 		ReadParameter(param, "PostProcessing", "AllowNegativeRates", true, NUNBERSAkt)		
+		ReadParameter(param, "InfluxDBv2", "Fieldname", true, NUNBERSAkt)		
 	}
 
-	var sel = document.getElementById("Numbers_value1");
+//	var sel = document.getElementById("Numbers_value1");
 	NUNBERSAkt = sel.selectedIndex;
 	WriteParameter(param, category, "PostProcessing", "DecimalShift", true, NUNBERSAkt);
 	WriteParameter(param, category, "PostProcessing", "AnalogDigitalTransitionStart", true, NUNBERSAkt);
@@ -1790,6 +1904,7 @@ function UpdateInputIndividual()
 	WriteParameter(param, category, "PostProcessing", "ExtendedResolution", true, NUNBERSAkt);
 	WriteParameter(param, category, "PostProcessing", "IgnoreLeadingNaN", true, NUNBERSAkt);
 	WriteParameter(param, category, "PostProcessing", "AllowNegativeRates", true, NUNBERSAkt);
+	WriteParameter(param, category, "InfluxDBv2", "Fieldname", true, NUNBERSAkt);
 }
 
 function UpdateInput() {
@@ -1798,6 +1913,7 @@ function UpdateInput() {
 	document.getElementById("Category_MQTT_enabled").checked = category["MQTT"]["enabled"];
 	document.getElementById("Category_GPIO_enabled").checked = category["GPIO"]["enabled"];
 	document.getElementById("Category_InfluxDB_enabled").checked = category["InfluxDB"]["enabled"];
+	document.getElementById("Category_InfluxDBv2_enabled").checked = category["InfluxDBv2"]["enabled"];
 	setVisible("GPIO_item", category["GPIO"]["enabled"]);
 
 	WriteParameter(param, category, "MakeImage", "LogImageLocation", true);
@@ -1844,6 +1960,13 @@ function UpdateInput() {
 	WriteParameter(param, category, "InfluxDB", "user", true);	
 	WriteParameter(param, category, "InfluxDB", "password", true);	
 
+	WriteParameter(param, category, "InfluxDBv2", "Uri", true);	
+	WriteParameter(param, category, "InfluxDBv2", "Database", true);	
+	WriteParameter(param, category, "InfluxDBv2", "Measurement", true);	
+	WriteParameter(param, category, "InfluxDBv2", "Org", true);	
+	WriteParameter(param, category, "InfluxDBv2", "Token", true);	
+	WriteParameter(param, category, "InfluxDBv2", "Fieldname", true);
+
 	WriteParameter(param, category, "GPIO", "IO0", true);
 	WriteParameter(param, category, "GPIO", "IO1", true);
 	WriteParameter(param, category, "GPIO", "IO3", true);
@@ -1919,6 +2042,7 @@ function ReadParameterAll()
 	category["Digits"]["enabled"] = document.getElementById("Category_Digits_enabled").checked;
 	category["MQTT"]["enabled"] = document.getElementById("Category_MQTT_enabled").checked;
 	category["InfluxDB"]["enabled"] = document.getElementById("Category_InfluxDB_enabled").checked;
+	category["InfluxDBv2"]["enabled"] = document.getElementById("Category_InfluxDBv2_enabled").checked;
 	category["GPIO"]["enabled"] = document.getElementById("Category_GPIO_enabled").checked;
 	
 	ReadParameter(param, "MakeImage", "LogImageLocation", true);
@@ -1948,7 +2072,6 @@ function ReadParameterAll()
 
 	ReadParameter(param, "PostProcessing", "PreValueUse", true);		
 	ReadParameter(param, "PostProcessing", "PreValueAgeStartup", true);		
-//	ReadParameter(param, "PostProcessing", "AllowNegativeRates", true);
 	ReadParameter(param, "PostProcessing", "ErrorMessage", true);
 	ReadParameter(param, "PostProcessing", "CheckDigitIncreaseConsistency", true);
 
@@ -1967,6 +2090,13 @@ function ReadParameterAll()
 	ReadParameter(param, "InfluxDB", "user", true);	
 	ReadParameter(param, "InfluxDB", "password", true);	
 
+	ReadParameter(param, "InfluxDBv2", "Uri", true);	
+	ReadParameter(param, "InfluxDBv2", "Database", true);	
+	ReadParameter(param, "InfluxDBv2", "Measurement", true);	
+	ReadParameter(param, "InfluxDBv2", "Org", true);	
+	ReadParameter(param, "InfluxDBv2", "Token", true);	
+//	ReadParameter(param, "InfluxDB", "Fieldname", true);	
+
 	ReadParameter(param, "GPIO", "IO0", true);
 	ReadParameter(param, "GPIO", "IO1", true);
 	ReadParameter(param, "GPIO", "IO3", true);
@@ -1998,7 +2128,8 @@ function ReadParameterAll()
 	ReadParameter(param, "System", "TimeServer", true);	
 	ReadParameter(param, "System", "RSSIThreashold", true);	
 
-	UpdateInputIndividual();
+	var sel = document.getElementById("Numbers_value1");	
+	UpdateInputIndividual(sel);
 	
 //	FormatDecimalValue(param, "PostProcessing", "MaxRateValue");
 }
@@ -2018,10 +2149,12 @@ function UpdateAfterCategoryCheck() {
 	category["Digits"]["enabled"] = document.getElementById("Category_Digits_enabled").checked;
 	category["MQTT"]["enabled"] = document.getElementById("Category_MQTT_enabled").checked;
 	category["InfluxDB"]["enabled"] = document.getElementById("Category_InfluxDB_enabled").checked;
+	category["InfluxDBv2"]["enabled"] = document.getElementById("Category_InfluxDBv2_enabled").checked;
 	category["GPIO"]["enabled"] = document.getElementById("Category_GPIO_enabled").checked;
 
 	UpdateInput();
-	UpdateInputIndividual();
+	var sel = document.getElementById("Numbers_value1");
+	UpdateInputIndividual(sel);
 }
 
 function UpdateExpertModus()
@@ -2098,9 +2231,26 @@ function editConfigDirect() {
 
 function numberChanged()
 {
-	UpdateInputIndividual();
+	var sel = document.getElementById("Numbers_value1");
+	_neu = sel.selectedIndex;
+	UpdateInputIndividual(sel);
+
+	var _selInflux = document.getElementById("NumbersInfluxDB_value1");
+	if (_selInflux.selectedIndex != _neu)
+		_selInflux.selectedIndex = _neu
 }
  
+function numberInfluxDBChanged()
+{
+	var sel = document.getElementById("NumbersInfluxDB_value1");
+	_neu = sel.selectedIndex;
+	UpdateInputIndividual(sel);
+
+	var _sel2 = document.getElementById("Numbers_value1");
+	if (_sel2.selectedIndex != _neu)
+	_sel2.selectedIndex = _neu
+}
+
 LoadConfigNeu();
  
 </script>

+ 1 - 1
sd-card/html/gethost.js

@@ -13,7 +13,7 @@ function getbasepath(){
     {
 //        host = "http://192.168.2.219";          // jomjol interner test
 //        host = "http://192.168.178.46";          // jomjol interner test
-        host = "http://192.168.178.62";          // jomjol interner Real
+        host = "http://192.168.178.44";          // jomjol interner Real
 //        host = "http://192.168.43.191";
 //        host = ".";                           // jomjol interner localhost   
 

+ 3 - 2
sd-card/html/readconfigcommon.js

@@ -45,7 +45,6 @@ function ZerlegeZeile(input, delimiter = " =\t\r")
           var Output = Array(0);
 //          delimiter = " =,\t";
      
-          input = trim(input, delimiter);
 
           /* The input can have multiple formats: 
            *  - key = value
@@ -61,12 +60,14 @@ function ZerlegeZeile(input, delimiter = " =\t\r")
            * As a workaround and to not break any legacy usage, we enforce to only use the
            * equal sign, if the key is "password"
            */
-          if (input.includes("password")) { // Line contains a password, use the equal sign as the only delimiter and only split on first occurrence
+          if (input.includes("password") || input.includes("Token")) { // Line contains a password, use the equal sign as the only delimiter and only split on first occurrence
                var pos = input.indexOf("=");
+               delimiter = " \t\r"
                Output.push(trim(input.substr(0, pos), delimiter));
                Output.push(trim(input.substr(pos +1, input.length), delimiter));
           }
           else { // Legacy Mode
+               input = trim(input, delimiter);
                var pos = findDelimiterPos(input, delimiter);
                var token;
                while (pos > -1) {

+ 12 - 0
sd-card/html/readconfigparam.js

@@ -196,6 +196,18 @@ function ParseConfig() {
      ParamAddValue(param, catname, "user");
      ParamAddValue(param, catname, "password");
     
+     var catname = "InfluxDBv2";
+     category[catname] = new Object(); 
+     category[catname]["enabled"] = false;
+     category[catname]["found"] = false;
+     param[catname] = new Object();
+     ParamAddValue(param, catname, "Uri");
+     ParamAddValue(param, catname, "Database");
+     ParamAddValue(param, catname, "Measurement");
+     ParamAddValue(param, catname, "Org");
+     ParamAddValue(param, catname, "Token");
+     ParamAddValue(param, catname, "Fieldname", 1, true);
+
      var catname = "GPIO";
      category[catname] = new Object(); 
      category[catname]["enabled"] = false;