Selaa lähdekoodia

Set prevalue using MQTT + set prevalue to RAW value (REST+MQTT) (#2252)

* Use double instead of float

* Error handling + set to RAW if newvalue < 0

* REST SetPrevalue: Set to RAW if newvalue < 0

* set prevalue with MQTT
Slider0007 2 vuotta sitten
vanhempi
sitoutus
b6bfeea936

+ 23 - 20
code/components/jomjol_flowcontroll/ClassFlowControll.cpp

@@ -470,10 +470,10 @@ string ClassFlowControll::getReadoutAll(int _type)
 }	
 
 
-string ClassFlowControll::getReadout(bool _rawvalue = false, bool _noerror = false)
+string ClassFlowControll::getReadout(bool _rawvalue = false, bool _noerror = false, int _number = 0)
 {
     if (flowpostprocessing)
-        return flowpostprocessing->getReadoutParam(_rawvalue, _noerror);
+        return flowpostprocessing->getReadoutParam(_rawvalue, _noerror, _number);
 
     string zw = "";
     string result = "";
@@ -501,37 +501,40 @@ string ClassFlowControll::GetPrevalue(std::string _number)
         return flowpostprocessing->GetPreValue(_number);   
     }
 
+
     return std::string("");    
 }
 
 
-std::string ClassFlowControll::UpdatePrevalue(std::string _newvalue, std::string _numbers, bool _extern)
+bool ClassFlowControll::UpdatePrevalue(std::string _newvalue, std::string _numbers, bool _extern)
 {
-    float zw;
+    double newvalueAsDouble;
     char* p;
 
     _newvalue = trim(_newvalue);
-//    ESP_LOGD(TAG, "Input UpdatePreValue: %s", _newvalue.c_str());
+    //ESP_LOGD(TAG, "Input UpdatePreValue: %s", _newvalue.c_str());
 
-    if (_newvalue.compare("0.0") == 0)
-    {
-        zw = 0;
+    if (_newvalue.substr(0,8).compare("0.000000") == 0 || _newvalue.compare("0.0") == 0 || _newvalue.compare("0") == 0) {
+        newvalueAsDouble = 0;   // preset to value = 0
     }
-    else
-    {
-        zw = strtof(_newvalue.c_str(), &p);
-        if (zw == 0)
-            return "- Error in String to Value Conversion!!! Must be of format value=123.456";
+    else {
+        newvalueAsDouble = strtod(_newvalue.c_str(), &p);
+        if (newvalueAsDouble == 0) {
+            LogFile.WriteToFile(ESP_LOG_WARN, TAG, "UpdatePrevalue: No valid value for processing: " + _newvalue);
+            return false;
+        }
     }
     
-
-    if (flowpostprocessing)
-    {
-        flowpostprocessing->SetPreValue(zw, _numbers, _extern);
-        return _newvalue;    
+    if (flowpostprocessing) {
+        if (flowpostprocessing->SetPreValue(newvalueAsDouble, _numbers, _extern))
+            return true;
+        else
+            return false;
+    }
+    else {
+        LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "UpdatePrevalue: ERROR - Class Post-Processing not initialized");
+        return false;
     }
-
-    return std::string();
 }
 
 

+ 2 - 2
code/components/jomjol_flowcontroll/ClassFlowControll.h

@@ -46,9 +46,9 @@ public:
 	bool doFlow(string time);
 	void doFlowTakeImageOnly(string time);
 	bool getStatusSetupModus(){return SetupModeActive;};
-	string getReadout(bool _rawvalue, bool _noerror);
+	string getReadout(bool _rawvalue, bool _noerror, int _number);
 	string getReadoutAll(int _type);	
-	string UpdatePrevalue(std::string _newvalue, std::string _numbers, bool _extern);
+	bool UpdatePrevalue(std::string _newvalue, std::string _numbers, bool _extern);
 	string GetPrevalue(std::string _number = "");	
 	bool ReadParameter(FILE* pfile, string& aktparamgraph);	
 	string getJSON();

+ 34 - 12
code/components/jomjol_flowcontroll/ClassFlowPostProcessing.cpp

@@ -96,27 +96,49 @@ string ClassFlowPostProcessing::GetPreValue(std::string _number)
     return result;
 }
 
-void ClassFlowPostProcessing::SetPreValue(double zw, string _numbers, bool _extern)
+
+bool ClassFlowPostProcessing::SetPreValue(double _newvalue, string _numbers, bool _extern)
 {
-    ESP_LOGD(TAG, "SetPrevalue: %f, %s", zw, _numbers.c_str());
-    for (int j = 0; j < NUMBERS.size(); ++j)
-    {
-//        ESP_LOGD(TAG, "Number %d, %s", j, NUMBERS[j]->name.c_str());
-        if (NUMBERS[j]->name == _numbers)
-        {
-            NUMBERS[j]->PreValue = zw;
-            NUMBERS[j]->ReturnPreValue = std::to_string(zw);
+    //ESP_LOGD(TAG, "SetPrevalue: %f, %s", zw, _numbers.c_str());
+
+    for (int j = 0; j < NUMBERS.size(); ++j) {
+        //ESP_LOGD(TAG, "Number %d, %s", j, NUMBERS[j]->name.c_str());
+        if (NUMBERS[j]->name == _numbers) {
+            if (_newvalue >= 0) {  // if new value posivive, use provided value to preset PreValue
+                NUMBERS[j]->PreValue = _newvalue;
+            }
+            else {          // if new value negative, use last raw value to preset PreValue
+                char* p;
+                double ReturnRawValueAsDouble = strtod(NUMBERS[j]->ReturnRawValue.c_str(), &p);
+                if (ReturnRawValueAsDouble == 0) {
+                    LogFile.WriteToFile(ESP_LOG_WARN, TAG, "SetPreValue: RawValue not a valid value for further processing: "
+                                                            + NUMBERS[j]->ReturnRawValue);
+                    return false;
+                }
+                NUMBERS[j]->PreValue = ReturnRawValueAsDouble;
+            }
+
+            NUMBERS[j]->ReturnPreValue = std::to_string(NUMBERS[j]->PreValue);
             NUMBERS[j]->PreValueOkay = true;
+
             if (_extern)
             {
                 time(&(NUMBERS[j]->lastvalue));
                 localtime(&(NUMBERS[j]->lastvalue));
             }
-//            ESP_LOGD(TAG, "Found %d! - set to %f", j,  NUMBERS[j]->PreValue);
+            //ESP_LOGD(TAG, "Found %d! - set to %.8f", j,  NUMBERS[j]->PreValue);
+            
+            UpdatePreValueINI = true;   // Only update prevalue file if a new value is set
+            SavePreValue();
+
+            LogFile.WriteToFile(ESP_LOG_INFO, TAG, "SetPreValue: PreValue for " + NUMBERS[j]->name + " set to " + 
+                                                     std::to_string(NUMBERS[j]->PreValue));
+            return true;
         }
     }
-    UpdatePreValueINI = true;
-    SavePreValue();
+    
+    LogFile.WriteToFile(ESP_LOG_WARN, TAG, "SetPreValue: Numbersname not found or not valid");
+    return false;   // No new value was set (e.g. wrong numbersname, no numbers at all)
 }
 
 

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

@@ -68,7 +68,7 @@ public:
     void SavePreValue();
     string getJsonFromNumber(int i, std::string _lineend);
     string GetPreValue(std::string _number = "");
-    void SetPreValue(double zw, string _numbers, bool _extern = false);
+    bool SetPreValue(double zw, string _numbers, bool _extern = false);
 
     std::string GetJSON(std::string _lineend = "\n");
     std::string getNumbersName();

+ 1 - 1
code/components/jomjol_mqtt/CMakeLists.txt

@@ -2,4 +2,4 @@ FILE(GLOB_RECURSE app_sources ${CMAKE_CURRENT_SOURCE_DIR}/*.*)
 
 idf_component_register(SRCS ${app_sources}
                     INCLUDE_DIRS "."
-                    REQUIRES tflite-lib mqtt jomjol_tfliteclass jomjol_helper jomjol_mqtt jomjol_wlan)
+                    REQUIRES tflite-lib mqtt jomjol_tfliteclass jomjol_helper jomjol_mqtt jomjol_wlan json)

+ 47 - 4
code/components/jomjol_mqtt/interface_mqtt.cpp

@@ -6,6 +6,7 @@
 #include "mqtt_client.h"
 #include "ClassLogFile.h"
 #include "server_tflite.h"
+#include "cJSON.h"
 #include "../../include/defines.h"
 
 static const char *TAG = "MQTT IF";
@@ -336,17 +337,54 @@ bool getMQTTisConnected() {
 }
 
 
-bool mqtt_handler_flow_start(std::string _topic, char* _data, int _data_len) {
+bool mqtt_handler_flow_start(std::string _topic, char* _data, int _data_len) 
+{
     ESP_LOGD(TAG, "Handler called: topic %s, data %.*s", _topic.c_str(), _data_len, _data);
 
     if (_data_len > 0) {
         MQTTCtrlFlowStart(_topic);
     }
+    else {
+        LogFile.WriteToFile(ESP_LOG_WARN, TAG, "handler_flow_start: handler called, but no data");
+    }
 
     return ESP_OK;
 }
 
 
+bool mqtt_handler_set_prevalue(std::string _topic, char* _data, int _data_len) 
+{
+    //ESP_LOGD(TAG, "Handler called: topic %s, data %.*s", _topic.c_str(), _data_len, _data);
+    //example: {"numbersname": "main", "value": 12345.1234567}
+
+    if (_data_len > 0) {    // Check if data length > 0
+        cJSON *jsonData = cJSON_Parse(_data);
+        cJSON *numbersname = cJSON_GetObjectItemCaseSensitive(jsonData, "numbersname");
+        cJSON *value = cJSON_GetObjectItemCaseSensitive(jsonData, "value");
+
+        if (cJSON_IsString(numbersname) && (numbersname->valuestring != NULL)) {    // Check if numbersname is valid
+            if (cJSON_IsNumber(value)) {   // Check if value is a number
+                LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "handler_set_prevalue called: numbersname: " + std::string(numbersname->valuestring) + 
+                                                                                         ", value: " + std::to_string(value->valuedouble));
+                if (tfliteflow.UpdatePrevalue(std::to_string(value->valuedouble), std::string(numbersname->valuestring), true))
+                    return ESP_OK;
+            }
+            else {
+                LogFile.WriteToFile(ESP_LOG_WARN, TAG, "handler_set_prevalue: value not a valid number (\"value\": 12345.12345)");
+            }
+        }
+        else {
+            LogFile.WriteToFile(ESP_LOG_WARN, TAG, "handler_set_prevalue: numbersname not a valid string (\"numbersname\": \"main\")");
+        }
+    }
+    else {
+        LogFile.WriteToFile(ESP_LOG_WARN, TAG, "handler_set_prevalue: handler called, but no data received");
+    }
+
+    return ESP_FAIL;
+}
+
+
 void MQTTconnected(){
     if (mqtt_connected) {
         LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Connected to broker");
@@ -358,9 +396,14 @@ void MQTTconnected(){
             }
         }
 
-        /* Subcribe to topics */
-        std::function<bool(std::string topic, char* data, int data_len)> subHandler = mqtt_handler_flow_start;     
-        MQTTregisterSubscribeFunction(maintopic + "/ctrl/flow_start", subHandler);        // subcribe to maintopic/ctrl/flow_start
+        // Subcribe to topics
+        // Note: Further subsriptions are handled in GPIO class
+        //*****************************************
+        std::function<bool(std::string topic, char* data, int data_len)> subHandler1 = mqtt_handler_flow_start;     
+        MQTTregisterSubscribeFunction(maintopic + "/ctrl/flow_start", subHandler1);        // subcribe to maintopic/ctrl/flow_start
+
+        std::function<bool(std::string topic, char* data, int data_len)> subHandler2 = mqtt_handler_set_prevalue;     
+        MQTTregisterSubscribeFunction(maintopic + "/ctrl/set_prevalue", subHandler2);      // subcribe to maintopic/ctrl/set_prevalue
 
        if (subscribeFunktionMap != NULL) {
             for(std::map<std::string, std::function<bool(std::string, char*, int)>>::iterator it = subscribeFunktionMap->begin(); it != subscribeFunktionMap->end(); ++it) {

+ 61 - 30
code/components/jomjol_tfliteclass/server_tflite.cpp

@@ -399,7 +399,7 @@ esp_err_t handler_wasserzaehler(httpd_req_t *req)
         }
 
 
-        zw = tfliteflow.getReadout(_rawValue, _noerror);
+        zw = tfliteflow.getReadout(_rawValue, _noerror, 0);
         if (zw.length() > 0)
             httpd_resp_sendstr_chunk(req, zw.c_str()); 
 
@@ -706,7 +706,7 @@ esp_err_t handler_editflow(httpd_req_t *req)
 esp_err_t handler_statusflow(httpd_req_t *req)
 {
     #ifdef DEBUG_DETAIL_ON       
-        LogFile.WriteHeapInfo("handler_prevalue - Start");       
+        LogFile.WriteHeapInfo("handler_statusflow - Start");       
     #endif
 
     const char* resp_str;
@@ -715,7 +715,7 @@ esp_err_t handler_statusflow(httpd_req_t *req)
     if (bTaskAutoFlowCreated) 
     {
         #ifdef DEBUG_DETAIL_ON       
-            ESP_LOGD(TAG, "handler_prevalue: %s", req->uri);
+            ESP_LOGD(TAG, "handler_statusflow: %s", req->uri);
         #endif
 
         string* zw = tfliteflow.getActStatusWithTime();
@@ -730,7 +730,7 @@ esp_err_t handler_statusflow(httpd_req_t *req)
     }
 
     #ifdef DEBUG_DETAIL_ON       
-        LogFile.WriteHeapInfo("handler_prevalue - Done");       
+        LogFile.WriteHeapInfo("handler_statusflow - Done");       
     #endif
 
     return ESP_OK;
@@ -802,50 +802,81 @@ esp_err_t handler_uptime(httpd_req_t *req)
 esp_err_t handler_prevalue(httpd_req_t *req)
 {
     #ifdef DEBUG_DETAIL_ON       
-        LogFile.WriteHeapInfo("handler_prevalue - Start");       
+        LogFile.WriteHeapInfo("handler_prevalue - Start");          
+        ESP_LOGD(TAG, "handler_prevalue: %s", req->uri);
     #endif
 
-    const char* resp_str;
-    string zw;
+    // Default usage message when handler gets called without any parameter
+    const std::string RESTUsageInfo = 
+        "00: Handler usage:<br>"
+        "- To retrieve actual PreValue, please provide only a numbersname, e.g. /setPreValue?numbers=main<br>"
+        "- To set PreValue to a new value, please provide a numbersname and a value, e.g. /setPreValue?numbers=main&value=1234.5678<br>"
+        "NOTE:<br>"
+        "value >= 0.0: Set PreValue to provided value<br>"
+        "value <  0.0: Set PreValue to actual RAW value (as long RAW value is a valid number, without N)";
 
-    #ifdef DEBUG_DETAIL_ON       
-        ESP_LOGD(TAG, "handler_prevalue: %s", req->uri);
-    #endif
+    // Default return error message when no return is programmed
+    std::string sReturnMessage = "E90: Uninitialized";
 
     char _query[100];
-    char _size[10] = "";
-    char _numbers[50] = "default";
+    char _numbersname[50] = "default";
+    char _value[20] = "";
 
-    if (httpd_req_get_url_query_str(req, _query, 100) == ESP_OK)
-    {
+    httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
+
+    if (httpd_req_get_url_query_str(req, _query, 100) == ESP_OK) {
         #ifdef DEBUG_DETAIL_ON       
             ESP_LOGD(TAG, "Query: %s", _query);
         #endif
 
-        if (httpd_query_key_value(_query, "value", _size, 10) == ESP_OK)
-        {
+        if (httpd_query_key_value(_query, "numbers", _numbersname, 50) != ESP_OK) { // If request is incomplete
+            sReturnMessage = "E91: Query parameter incomplete or not valid!<br> "
+                             "Call /setPreValue to show REST API usage info and/or check documentation";
+            httpd_resp_send(req, sReturnMessage.c_str(), sReturnMessage.length());
+            return ESP_FAIL; 
+        }
+
+        if (httpd_query_key_value(_query, "value", _value, 20) == ESP_OK) {
             #ifdef DEBUG_DETAIL_ON       
                 ESP_LOGD(TAG, "Value: %s", _size);
             #endif
         }
+    }
+    else {  // if no parameter is provided, print handler usage
+        httpd_resp_send(req, RESTUsageInfo.c_str(), RESTUsageInfo.length());
+        return ESP_OK; 
+    }   
+
+    if (strlen(_value) == 0) { // If no value is povided --> return actual PreValue
+        sReturnMessage = tfliteflow.GetPrevalue(std::string(_numbersname));
+
+        if (sReturnMessage.empty()) {
+            sReturnMessage = "E92: Numbers name not found";
+            httpd_resp_send(req, sReturnMessage.c_str(), sReturnMessage.length());
+            return ESP_FAIL;
+        }
+    }
+    else {
+        // New value is positive: Set PreValue to provided value and return value
+        // New value is negative and actual RAW value is a valid number: Set PreValue to RAW value and return value
+        LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "REST API handler_prevalue called: numbersname: " + std::string(_numbersname) + 
+                                                                                      ", value: " + std::string(_value));
+        if (!tfliteflow.UpdatePrevalue(_value, _numbersname, true)) {
+            sReturnMessage = "E93: Update request rejected. Please check device logs for more details";
+            httpd_resp_send(req, sReturnMessage.c_str(), sReturnMessage.length());  
+            return ESP_FAIL;
+        }
 
-        httpd_query_key_value(_query, "numbers", _numbers, 50);
-    }      
+        sReturnMessage = tfliteflow.GetPrevalue(std::string(_numbersname));
 
-    if (strlen(_size) == 0)
-    {
-        zw = tfliteflow.GetPrevalue(std::string(_numbers));
-    }
-    else
-    {
-        zw = "SetPrevalue to " + tfliteflow.UpdatePrevalue(_size, _numbers, true);
+        if (sReturnMessage.empty()) {
+            sReturnMessage = "E94: Numbers name not found";
+            httpd_resp_send(req, sReturnMessage.c_str(), sReturnMessage.length());
+            return ESP_FAIL;
+        }
     }
-    
-    resp_str = zw.c_str();
 
-    httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
-    
-    httpd_resp_send(req, resp_str, HTTPD_RESP_USE_STRLEN);  
+    httpd_resp_send(req, sReturnMessage.c_str(), sReturnMessage.length());  
 
     #ifdef DEBUG_DETAIL_ON       
         LogFile.WriteHeapInfo("handler_prevalue - End");