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

Merge remote-tracking branch 'upstream/rolling' into rolling

Zwer2k 4 лет назад
Родитель
Сommit
5414a4c3f1
51 измененных файлов с 3037 добавлено и 1320 удалено
  1. 16 0
      FeatureRequest.md
  2. 44 2
      README.md
  3. BIN
      code/components/connect_wlan.zip
  4. 4 0
      code/components/jomjol_controlcamera/ClassControllCamera.cpp
  5. 20 3
      code/components/jomjol_flowcontroll/ClassFlow.cpp
  6. 2 0
      code/components/jomjol_flowcontroll/ClassFlow.h
  7. 350 0
      code/components/jomjol_flowcontroll/ClassFlowAnalog._c_p_p_
  8. 48 0
      code/components/jomjol_flowcontroll/ClassFlowAnalog._h_
  9. 200 66
      code/components/jomjol_flowcontroll/ClassFlowAnalog.cpp
  10. 21 4
      code/components/jomjol_flowcontroll/ClassFlowAnalog.h
  11. 37 4
      code/components/jomjol_flowcontroll/ClassFlowControll.cpp
  12. 9 2
      code/components/jomjol_flowcontroll/ClassFlowControll.h
  13. 175 51
      code/components/jomjol_flowcontroll/ClassFlowDigit.cpp
  14. 20 2
      code/components/jomjol_flowcontroll/ClassFlowDigit.h
  15. 49 39
      code/components/jomjol_flowcontroll/ClassFlowMQTT.cpp
  16. 4 1
      code/components/jomjol_flowcontroll/ClassFlowMQTT.h
  17. 412 244
      code/components/jomjol_flowcontroll/ClassFlowPostProcessing.cpp
  18. 60 24
      code/components/jomjol_flowcontroll/ClassFlowPostProcessing.h
  19. 28 0
      code/components/jomjol_helper/Helper.cpp
  20. 3 0
      code/components/jomjol_helper/Helper.h
  21. 54 3
      code/components/jomjol_tfliteclass/server_tflite.cpp
  22. 1 1
      code/components/jomjol_wlan/read_wlanini.cpp
  23. 2 2
      code/main/server_main.cpp
  24. 4 4
      code/main/version.cpp
  25. 2 0
      code/platformio.ini
  26. 174 5
      code/sdkconfig.old
  27. 4 4
      code/version.cpp
  28. BIN
      firmware/html.zip
  29. BIN
      images/numbers.jpg
  30. BIN
      images/powermeter.jpg
  31. 29 31
      sd-card/config/config.ini
  32. BIN
      sd-card/config/dig0870s3q.tflite
  33. BIN
      sd-card/config/dig1030s1q.tflite
  34. 14 16
      sd-card/html/edit_alignment.html
  35. 168 53
      sd-card/html/edit_analog.html
  36. 0 1
      sd-card/html/edit_config.html
  37. 171 114
      sd-card/html/edit_config_param.html
  38. 170 55
      sd-card/html/edit_digits.html
  39. 1 2
      sd-card/html/edit_reference.html
  40. 4 3
      sd-card/html/gethost.js
  41. 17 0
      sd-card/html/info.html
  42. 0 1
      sd-card/html/jquery-3.5.1.min.js
  43. 1 0
      sd-card/html/jquery-3.6.0.min.js
  44. 103 23
      sd-card/html/prevalue_set.html
  45. 0 427
      sd-card/html/readconfig.js
  46. 58 61
      sd-card/html/readconfigcommon.js
  47. 418 14
      sd-card/html/readconfigparam.js
  48. BIN
      sd-card/html/sd-card - Verknüpfung.lnk
  49. 32 0
      sd-card/html/test.html
  50. 1 1
      sd-card/html/version.txt
  51. 107 57
      sd-card/html/wasserzaehler_roi.html

+ 16 - 0
FeatureRequest.md

@@ -11,6 +11,22 @@
 
 ____
 
+#### #8 MQTT configurable readout intervall
+
+Make the readout intervall configurable via MQTT.
+
+* Change the mqtt part to receive and process input and not only sending
+
+#### #7 Extended Error Handling
+
+Check different types of error (e.g. tflite not availabe) and generate an error on the html page.
+
+To do:
+
+* Make a list of "important" errors
+* Implement a checking algo
+* Extend the firmware and html page for the error handling
+
 #### #6 Check for double ROI names
 
 Check during configuration, that ROI names are unique.

+ 44 - 2
README.md

@@ -12,6 +12,8 @@ respectively ESP32-Cam housing only: https://www.thingiverse.com/thing:4571627
 
 <img src="https://raw.githubusercontent.com/jomjol/AI-on-the-edge-device/master/images/watermeter.jpg" width="600"> 
 
+<img src="https://raw.githubusercontent.com/jomjol/AI-on-the-edge-device/master/images/powermeter.jpg" width="600"> 
+
 
 
 
@@ -45,15 +47,55 @@ In other cases you can contact the developer via email: <img src="https://raw.gi
 
 
 
+##### Rolling - (2021-07-05)
+
+* Update jquery, inital config.ini
+
+Rolling - (2021-07-03)
+
+* Parameter `MaxRateValue` individual for each number
+* BugFix: MQTT server tried to connect even in case it was disabled
+
+Rolling - (2021-07-01)
 
-##### 7.1.1 MQTT-Update - (2021-05-30)
+* NEW FEATURE: adding support for more than 1 number on a meter (e.g. two different power readings)
+  Therefore the concept of "Numbers" is implemented - a bunch of digits and analog counters are combined to one number. You can define them during setup of digital and analog ROIs:
+  <img src="https://raw.githubusercontent.com/jomjol/AI-on-the-edge-device/master/images/numbers.jpg" width="300"> 
+  
+* MQTT: standardization of the naming - only the main topic needs to be specified. The subtopics will be named automatically. This is necessary to handle the multi number option.
+  **ATTENTION**: the parameter `maintopic` needs to be set
+  
+* Remark: 
+  
+  * This is an early stage - do only use it on a test system and make a backup of your configuration. 
+  * The documentation is not updated yet.
 
-* NEW: 7.1.1: bug fix wlan password with "="  (again)
+* <span style="color: red;">**ATTENTION: the configuration and prevalue files are modified automatically and will not be backward compatible!**</span> 
+
+  
+
+Rolling - (2021-06-17)
+
+* bug fix setting hostname, Flash-LED not off during reboot
+
+Rolling - (2021-06-11)
+
+* Restructuring for multi number counters
+  * Major internal and html changes 
+    (html and firmware)
+*  **ATTENTION: the configuration and prevalue files are modified automatically and will not be backward compatible!**
+
+
+
+##### 7.1.2 MQTT-Update - (2021-06-17)
+
+* NEW: 7.1.2: bug fix setting hostname, Flash-LED not off during rebootNEW: 7.1.1: bug fix wlan password with "="  (again)
 * MQTT error message: changes "no error", send retain flag
 * Update wlan handling to esp-idf 4.1
 * Upgrade digital CNN to v8.7.0  (added new images)
 * Bug fix: MQTT, WLAN, LED-Controll, GPIO usage, fixed IP, calculation flow rate
 
+  
 
 ##### 7.0.1 MQTT-Update - (2021-05-13)
 

BIN
code/components/connect_wlan.zip


+ 4 - 0
code/components/jomjol_controlcamera/ClassControllCamera.cpp

@@ -230,6 +230,8 @@ void CCamera::EnableAutoExposure(int flashdauer)
     camera_fb_t * fb = esp_camera_fb_get();
     if (!fb) {
         ESP_LOGE(TAGCAMERACLASS, "Camera Capture Failed");
+        LEDOnOff(false);
+        LightOnOff(false);
         doReboot();
     }
     esp_camera_fb_return(fb);        
@@ -275,6 +277,7 @@ esp_err_t CCamera::CaptureToBasisImage(CImageBasis *_Image, int delay)
     if (!fb) {
         ESP_LOGE(TAGCAMERACLASS, "Camera Capture Failed");
         LEDOnOff(false);
+        LightOnOff(false);
         doReboot();
 
         return ESP_FAIL;
@@ -453,6 +456,7 @@ esp_err_t CCamera::CaptureToHTTP(httpd_req_t *req, int delay)
     fb = esp_camera_fb_get();
     if (!fb) {
         ESP_LOGE(TAGCAMERACLASS, "Camera capture failed");
+        LEDOnOff(false);
         LightOnOff(false);
         httpd_resp_send_500(req);
 //        doReboot();

+ 20 - 3
code/components/jomjol_flowcontroll/ClassFlow.cpp

@@ -94,6 +94,23 @@ string ClassFlow::getReadout()
 	return string();
 }
 
+std::string ClassFlow::GetParameterName(std::string _input)
+{
+    string _param;
+    int _pospunkt = _input.find_first_of(".");
+    if (_pospunkt > -1)
+    {
+        _param = _input.substr(_pospunkt+1, _input.length() - _pospunkt - 1);
+    }
+    else
+    {
+        _param = _input;
+    }
+//    printf("Parameter: %s, Pospunkt: %d\n", _param.c_str(), _pospunkt);
+	return _param;
+}
+
+
 bool ClassFlow::getNextLine(FILE* pfile, string *rt)
 {
 	char zw[1024];
@@ -102,13 +119,13 @@ bool ClassFlow::getNextLine(FILE* pfile, string *rt)
 		*rt = "";
 		return false;
 	}
-	fgets(zw, 1024, pfile);
-	printf("%s", zw);
-	if ((strlen(zw) == 0) && feof(pfile))
+	if (!fgets(zw, 1024, pfile))
 	{
 		*rt = "";
+		printf("END OF FILE\n");
 		return false;
 	}
+	printf("%s", zw);
 	*rt = zw;
 	*rt = trim(*rt);
 	while ((zw[0] == ';' || zw[0] == '#' || (rt->size() == 0)) && !(zw[1] == '['))			// Kommentarzeilen (; oder #) und Leerzeilen überspringen, es sei denn es ist ein neuer auskommentierter Paragraph

+ 2 - 0
code/components/jomjol_flowcontroll/ClassFlow.h

@@ -37,6 +37,8 @@ protected:
 
 	virtual void SetInitialParameter(void);
 
+	std::string GetParameterName(std::string _input);
+
 	bool disabled;
 
 public:

+ 350 - 0
code/components/jomjol_flowcontroll/ClassFlowAnalog._c_p_p_

@@ -0,0 +1,350 @@
+#include "ClassFlowAnalog.h"
+
+#include <math.h>
+#include <iomanip> 
+#include <sys/types.h>
+#include <sstream>      // std::stringstream
+
+  
+// #define OHNETFLITE
+
+#ifndef OHNETFLITE
+#include "CTfLiteClass.h"
+#endif
+
+#include "ClassLogFile.h"
+
+static const char* TAG = "flow_analog";
+
+bool debugdetailanalog = false;
+
+void ClassFlowAnalog::SetInitialParameter(void)
+{
+    string cnnmodelfile = "";
+    modelxsize = 1;
+    modelysize = 1;
+    ListFlowControll = NULL;
+    previousElement = NULL;   
+    SaveAllFiles = false; 
+    disabled = false;
+    extendedResolution = false;
+}   
+
+ClassFlowAnalog::ClassFlowAnalog(std::vector<ClassFlow*>* lfc) : ClassFlowImage(lfc, TAG)
+{
+    SetInitialParameter();
+    ListFlowControll = lfc;
+
+    for (int i = 0; i < ListFlowControll->size(); ++i)
+    {
+        if (((*ListFlowControll)[i])->name().compare("ClassFlowAlignment") == 0)
+        {
+            flowpostalignment = (ClassFlowAlignment*) (*ListFlowControll)[i];
+        }
+    }
+
+}
+
+
+int ClassFlowAnalog::AnzahlROIs()
+{
+    int zw = ROI.size();
+    if (extendedResolution)
+        zw++;
+    
+    return zw;
+} 
+
+
+string ClassFlowAnalog::getReadout()
+{
+    string result = "";    
+    if (ROI.size() == 0)
+        return result;
+
+
+    float zahl = ROI[ROI.size() - 1]->result;
+    int ergebnis_nachkomma = ((int) floor(zahl * 10)) % 10;
+
+    int prev = -1;
+
+    prev = ZeigerEval(ROI[ROI.size() - 1]->result, prev);
+    result = std::to_string(prev);
+
+    if (extendedResolution)
+        result = result + std::to_string(ergebnis_nachkomma);
+
+    for (int i = ROI.size() - 2; i >= 0; --i)
+    {
+        prev = ZeigerEval(ROI[i]->result, prev);
+        result = std::to_string(prev) + result;
+    }
+
+    return result;
+}
+
+int ClassFlowAnalog::ZeigerEval(float zahl, int ziffer_vorgaenger)
+{
+    int ergebnis_nachkomma = ((int) floor(zahl * 10)) % 10;
+    int ergebnis_vorkomma = ((int) floor(zahl)) % 10;
+    int ergebnis, ergebnis_rating;
+
+    if (ziffer_vorgaenger == -1)
+        return ergebnis_vorkomma % 10;
+
+    ergebnis_rating = ergebnis_nachkomma - ziffer_vorgaenger;
+    if (ergebnis_nachkomma >= 5)
+        ergebnis_rating-=5;
+    else
+        ergebnis_rating+=5;
+    ergebnis = (int) round(zahl);
+    if (ergebnis_rating < 0)
+        ergebnis-=1;
+    if (ergebnis == -1)
+        ergebnis+=10;
+
+    ergebnis = ergebnis % 10;
+    return ergebnis;
+}
+
+bool ClassFlowAnalog::ReadParameter(FILE* pfile, string& aktparamgraph)
+{
+    std::vector<string> zerlegt;
+
+    aktparamgraph = trim(aktparamgraph);
+
+    if (aktparamgraph.size() == 0)
+        if (!this->GetNextParagraph(pfile, aktparamgraph))
+            return false;
+
+
+    if ((aktparamgraph.compare("[Analog]") != 0) && (aktparamgraph.compare(";[Analog]") != 0))       // Paragraph passt nich zu MakeImage
+        return false;
+
+    if (aktparamgraph[0] == ';')
+    {
+        disabled = true;
+        while (getNextLine(pfile, &aktparamgraph) && !isNewParagraph(aktparamgraph));
+        printf("[Analog] is disabled !!!\n");
+        return true;
+    }
+
+
+    while (this->getNextLine(pfile, &aktparamgraph) && !this->isNewParagraph(aktparamgraph))
+    {
+        zerlegt = this->ZerlegeZeile(aktparamgraph);
+        if ((zerlegt[0] == "LogImageLocation") && (zerlegt.size() > 1))
+        {
+            this->LogImageLocation = "/sdcard" + zerlegt[1];
+            this->isLogImage = true;
+        }
+        if ((toUpper(zerlegt[0]) == "LOGFILERETENTIONINDAYS") && (zerlegt.size() > 1))
+        {
+            this->logfileRetentionInDays = std::stoi(zerlegt[1]);
+        }
+        if ((zerlegt[0] == "Model") && (zerlegt.size() > 1))
+        {
+            this->cnnmodelfile = zerlegt[1];
+        }
+        if ((zerlegt[0] == "ModelInputSize") && (zerlegt.size() > 2))
+        {
+            this->modelxsize = std::stoi(zerlegt[1]);
+            this->modelysize = std::stoi(zerlegt[2]);
+        }
+        if (zerlegt.size() >= 5)
+        {
+            roianalog* neuroi = new roianalog;
+            neuroi->name = zerlegt[0];
+            neuroi->posx = std::stoi(zerlegt[1]);
+            neuroi->posy = std::stoi(zerlegt[2]);
+            neuroi->deltax = std::stoi(zerlegt[3]);
+            neuroi->deltay = std::stoi(zerlegt[4]);
+            neuroi->result = -1;
+            neuroi->image = NULL;
+            neuroi->image_org = NULL;
+            ROI.push_back(neuroi);
+        }
+
+        if ((toUpper(zerlegt[0]) == "SAVEALLFILES") && (zerlegt.size() > 1))
+        {
+            if (toUpper(zerlegt[1]) == "TRUE")
+                SaveAllFiles = true;
+        }
+
+        if ((toUpper(zerlegt[0]) == "EXTENDEDRESOLUTION") && (zerlegt.size() > 1))
+        {
+            if (toUpper(zerlegt[1]) == "TRUE")
+                extendedResolution = true;
+        }
+    }
+
+    for (int i = 0; i < ROI.size(); ++i)
+    {
+        ROI[i]->image = new CImageBasis(modelxsize, modelysize, 3);
+        ROI[i]->image_org = new CImageBasis(ROI[i]->deltax, ROI[i]->deltay, 3);
+    }
+
+    return true;
+}
+
+
+string ClassFlowAnalog::getHTMLSingleStep(string host)
+{
+    string result, zw;
+    std::vector<HTMLInfo*> htmlinfo;
+
+    result = "<p>Found ROIs: </p> <p><img src=\"" + host + "/img_tmp/alg_roi.jpg\"></p>\n";
+    result = result + "Analog Pointers: <p> ";
+
+    htmlinfo = GetHTMLInfo();
+    for (int i = 0; i < htmlinfo.size(); ++i)
+    {
+        std::stringstream stream;
+        stream << std::fixed << std::setprecision(1) << htmlinfo[i]->val;
+        zw = stream.str();
+
+        result = result + "<img src=\"" + host + "/img_tmp/" +  htmlinfo[i]->filename + "\"> " + zw;
+        delete htmlinfo[i];
+    }
+    htmlinfo.clear();         
+
+    return result;
+}
+
+
+
+bool ClassFlowAnalog::doFlow(string time)
+{
+    if (disabled)
+      return true;
+
+    if (!doAlignAndCut(time)){
+        return false;
+    };
+
+    if (debugdetailanalog) LogFile.WriteToFile("ClassFlowAnalog::doFlow nach Alignment");
+
+    doNeuralNetwork(time);
+
+    RemoveOldLogs();
+
+    return true;
+}
+
+bool ClassFlowAnalog::doAlignAndCut(string time)
+{
+    if (disabled)
+        return true;
+
+    CAlignAndCutImage *caic = flowpostalignment->GetAlignAndCutImage();    
+
+    for (int i = 0; i < ROI.size(); ++i)
+    {
+        printf("Analog %d - Align&Cut\n", i);
+        
+        caic->CutAndSave(ROI[i]->posx, ROI[i]->posy, ROI[i]->deltax, ROI[i]->deltay, ROI[i]->image_org);
+        if (SaveAllFiles) ROI[i]->image_org->SaveToFile(FormatFileName("/sdcard/img_tmp/" + ROI[i]->name + ".jpg"));
+
+        ROI[i]->image_org->Resize(modelxsize, modelysize, ROI[i]->image);
+        if (SaveAllFiles) ROI[i]->image->SaveToFile(FormatFileName("/sdcard/img_tmp/" + ROI[i]->name + ".bmp"));
+    }
+
+    return true;
+} 
+
+void ClassFlowAnalog::DrawROI(CImageBasis *_zw)
+{
+    int r = 0;
+    int g = 255;
+    int b = 0;
+
+    for (int i = 0; i < ROI.size(); ++i)
+    {
+        _zw->drawRect(ROI[i]->posx, ROI[i]->posy, ROI[i]->deltax, ROI[i]->deltay, r, g, b, 1);
+        _zw->drawCircle((int) (ROI[i]->posx + ROI[i]->deltax/2), (int)  (ROI[i]->posy + ROI[i]->deltay/2), (int) (ROI[i]->deltax/2), r, g, b, 2);
+        _zw->drawLine((int) (ROI[i]->posx + ROI[i]->deltax/2), (int) ROI[i]->posy, (int) (ROI[i]->posx + ROI[i]->deltax/2), (int) (ROI[i]->posy + ROI[i]->deltay), r, g, b, 2);
+        _zw->drawLine((int) ROI[i]->posx, (int) (ROI[i]->posy + ROI[i]->deltay/2), (int) ROI[i]->posx + ROI[i]->deltax, (int) (ROI[i]->posy + ROI[i]->deltay/2), r, g, b, 2);
+    }
+} 
+
+bool ClassFlowAnalog::doNeuralNetwork(string time)
+{
+    if (disabled)
+        return true;
+
+    string logPath = CreateLogFolder(time);
+    
+    string input = "/sdcard/img_tmp/alg.jpg";
+    string ioresize = "/sdcard/img_tmp/resize.bmp";
+    string output;
+    input = FormatFileName(input);
+
+#ifndef OHNETFLITE
+    CTfLiteClass *tflite = new CTfLiteClass;  
+    string zwcnn = "/sdcard" + cnnmodelfile;
+    zwcnn = FormatFileName(zwcnn);
+    printf(zwcnn.c_str());printf("\n");
+    tflite->LoadModel(zwcnn); 
+    tflite->MakeAllocate();
+#endif
+
+    for (int i = 0; i < ROI.size(); ++i)
+    {
+        printf("Analog %d - TfLite\n", i);
+        ioresize = "/sdcard/img_tmp/ra" + std::to_string(i) + ".bmp";
+        ioresize = FormatFileName(ioresize);
+
+
+        float f1, f2;
+        f1 = 0; f2 = 0;
+
+#ifndef OHNETFLITE
+//        LogFile.WriteToFile("ClassFlowAnalog::doNeuralNetwork vor CNN tflite->LoadInputImage(ioresize)");
+//        tflite->LoadInputImage(ioresize);
+        tflite->LoadInputImageBasis(ROI[i]->image);        
+        tflite->Invoke();
+        if (debugdetailanalog) LogFile.WriteToFile("Nach Invoke");
+
+
+        f1 = tflite->GetOutputValue(0);
+        f2 = tflite->GetOutputValue(1);
+#endif
+
+        float result = fmod(atan2(f1, f2) / (M_PI * 2) + 2, 1);
+//        printf("Result sin, cos, ziffer: %f, %f, %f\n", f1, f2, result);  
+        ROI[i]->result = result * 10;
+
+        printf("Result Analog%i: %f\n", i, ROI[i]->result); 
+
+        if (isLogImage)
+        {
+            LogImage(logPath, ROI[i]->name, &ROI[i]->result, NULL, time, ROI[i]->image_org);
+        }
+    }
+#ifndef OHNETFLITE
+        delete tflite;
+#endif    
+
+    return true;
+}
+
+
+std::vector<HTMLInfo*> ClassFlowAnalog::GetHTMLInfo()
+{
+    std::vector<HTMLInfo*> result;
+
+    for (int i = 0; i < ROI.size(); ++i)
+    {
+        HTMLInfo *zw = new HTMLInfo;
+        zw->filename = ROI[i]->name + ".bmp";
+        zw->filename_org = ROI[i]->name + ".jpg";
+        zw->val = ROI[i]->result;
+        zw->image = ROI[i]->image;
+        zw->image_org = ROI[i]->image_org;
+        result.push_back(zw);
+    }
+
+    return result;
+}
+
+

+ 48 - 0
code/components/jomjol_flowcontroll/ClassFlowAnalog._h_

@@ -0,0 +1,48 @@
+#pragma once
+#include "ClassFlowImage.h"
+#include "ClassFlowAlignment.h"
+// #include "CTfLiteClass.h"
+
+struct roianalog {
+    int posx, posy, deltax, deltay;
+    float result;
+    CImageBasis *image, *image_org;
+    string name;
+};
+
+
+class ClassFlowAnalog :
+    public ClassFlowImage
+{
+protected:
+    std::vector<roianalog*> ROI;
+    string cnnmodelfile;
+    int modelxsize, modelysize;
+    int ZeigerEval(float zahl, int ziffer_vorgaenger);
+    bool SaveAllFiles;    
+
+
+    ClassFlowAlignment* flowpostalignment;
+
+	void SetInitialParameter(void);        
+
+public:
+    bool extendedResolution;
+
+    ClassFlowAnalog(std::vector<ClassFlow*>* lfc);
+
+    bool ReadParameter(FILE* pfile, string& aktparamgraph);
+    bool doFlow(string time);
+    string getHTMLSingleStep(string host);
+    string getReadout();   
+
+    void DrawROI(CImageBasis *_zw); 
+
+    bool doNeuralNetwork(string time); 
+    bool doAlignAndCut(string time);
+   	std::vector<HTMLInfo*> GetHTMLInfo();   
+    int AnzahlROIs(); 
+
+    string name(){return "ClassFlowAnalog";}; 
+};
+

+ 200 - 66
code/components/jomjol_flowcontroll/ClassFlowAnalog.cpp

@@ -1,7 +1,7 @@
 #include "ClassFlowAnalog.h"
 
 #include <math.h>
-#include <iomanip>
+#include <iomanip> 
 #include <sys/types.h>
 #include <sstream>      // std::stringstream
 
@@ -46,9 +46,9 @@ ClassFlowAnalog::ClassFlowAnalog(std::vector<ClassFlow*>* lfc) : ClassFlowImage(
 }
 
 
-int ClassFlowAnalog::AnzahlROIs()
+int ClassFlowAnalog::AnzahlROIs(int _analog = 0)
 {
-    int zw = ROI.size();
+    int zw = ANALOG[_analog]->ROI.size();
     if (extendedResolution)
         zw++;
     
@@ -56,27 +56,27 @@ int ClassFlowAnalog::AnzahlROIs()
 } 
 
 
-string ClassFlowAnalog::getReadout()
+string ClassFlowAnalog::getReadout(int _analog = 0)
 {
     string result = "";    
-    if (ROI.size() == 0)
+    if (ANALOG[_analog]->ROI.size() == 0)
         return result;
 
 
-    float zahl = ROI[ROI.size() - 1]->result;
+    float zahl = ANALOG[_analog]->ROI[ANALOG[_analog]->ROI.size() - 1]->result;
     int ergebnis_nachkomma = ((int) floor(zahl * 10)) % 10;
 
     int prev = -1;
 
-    prev = ZeigerEval(ROI[ROI.size() - 1]->result, prev);
+    prev = ZeigerEval(ANALOG[_analog]->ROI[ANALOG[_analog]->ROI.size() - 1]->result, prev);
     result = std::to_string(prev);
 
     if (extendedResolution)
         result = result + std::to_string(ergebnis_nachkomma);
 
-    for (int i = ROI.size() - 2; i >= 0; --i)
+    for (int i = ANALOG[_analog]->ROI.size() - 2; i >= 0; --i)
     {
-        prev = ZeigerEval(ROI[i]->result, prev);
+        prev = ZeigerEval(ANALOG[_analog]->ROI[i]->result, prev);
         result = std::to_string(prev) + result;
     }
 
@@ -153,8 +153,8 @@ bool ClassFlowAnalog::ReadParameter(FILE* pfile, string& aktparamgraph)
         }
         if (zerlegt.size() >= 5)
         {
-            roianalog* neuroi = new roianalog;
-            neuroi->name = zerlegt[0];
+            analog* _analog = GetANALOG(zerlegt[0], true);
+            roianalog* neuroi = _analog->ROI[_analog->ROI.size()-1];
             neuroi->posx = std::stoi(zerlegt[1]);
             neuroi->posy = std::stoi(zerlegt[2]);
             neuroi->deltax = std::stoi(zerlegt[3]);
@@ -162,7 +162,7 @@ bool ClassFlowAnalog::ReadParameter(FILE* pfile, string& aktparamgraph)
             neuroi->result = -1;
             neuroi->image = NULL;
             neuroi->image_org = NULL;
-            ROI.push_back(neuroi);
+//            ROI.push_back(neuroi);
         }
 
         if ((toUpper(zerlegt[0]) == "SAVEALLFILES") && (zerlegt.size() > 1))
@@ -178,16 +178,77 @@ bool ClassFlowAnalog::ReadParameter(FILE* pfile, string& aktparamgraph)
         }
     }
 
-    for (int i = 0; i < ROI.size(); ++i)
+   for (int _ana = 0; _ana < ANALOG.size(); ++_ana)
+        for (int i = 0; i < ANALOG[_ana]->ROI.size(); ++i)
+        {
+            ANALOG[_ana]->ROI[i]->image = new CImageBasis(modelxsize, modelysize, 3);
+            ANALOG[_ana]->ROI[i]->image_org = new CImageBasis(ANALOG[_ana]->ROI[i]->deltax, ANALOG[_ana]->ROI[i]->deltay, 3);
+        }
+
+    return true;
+}
+
+analog* ClassFlowAnalog::FindANALOG(string _name_number)
+{
+    analog *_ret = NULL;
+
+    for (int i = 0; i < ANALOG.size(); ++i)
     {
-        ROI[i]->image = new CImageBasis(modelxsize, modelysize, 3);
-        ROI[i]->image_org = new CImageBasis(ROI[i]->deltax, ROI[i]->deltay, 3);
+        if (ANALOG[i]->name == _name_number)
+            return ANALOG[i];
     }
 
-    return true;
+    return NULL;
+}
+
+
+
+analog* ClassFlowAnalog::GetANALOG(string _name, bool _create = true)
+{
+    string _analog, _roi;
+    int _pospunkt = _name.find_first_of(".");
+//    printf("Name: %s, Pospunkt: %d\n", _name.c_str(), _pospunkt);
+    if (_pospunkt > -1)
+    {
+        _analog = _name.substr(0, _pospunkt);
+        _roi = _name.substr(_pospunkt+1, _name.length() - _pospunkt - 1);
+    }
+    else
+    {
+        _analog = "default";
+        _roi = _name;
+    }
+
+    analog *_ret = NULL;
+
+    for (int i = 0; i < ANALOG.size(); ++i)
+    {
+        if (ANALOG[i]->name == _analog)
+            _ret = ANALOG[i];
+    }
+
+    if (!_create)         // nicht gefunden und soll auch nicht erzeugt werden
+        return _ret;
+
+
+    if (_ret == NULL)
+    {
+        _ret = new analog;
+        _ret->name = _analog;
+        ANALOG.push_back(_ret);
+    }
+
+    roianalog* neuroi = new roianalog;
+    neuroi->name = _roi;
+    _ret->ROI.push_back(neuroi);
+
+    printf("GetANALOG - ANALOG %s - roi %s\n", _analog.c_str(), _roi.c_str());
+
+    return _ret;
 }
 
 
+
 string ClassFlowAnalog::getHTMLSingleStep(string host)
 {
     string result, zw;
@@ -238,16 +299,29 @@ bool ClassFlowAnalog::doAlignAndCut(string time)
 
     CAlignAndCutImage *caic = flowpostalignment->GetAlignAndCutImage();    
 
-    for (int i = 0; i < ROI.size(); ++i)
-    {
-        printf("Analog %d - Align&Cut\n", i);
-        
-        caic->CutAndSave(ROI[i]->posx, ROI[i]->posy, ROI[i]->deltax, ROI[i]->deltay, ROI[i]->image_org);
-        if (SaveAllFiles) ROI[i]->image_org->SaveToFile(FormatFileName("/sdcard/img_tmp/" + ROI[i]->name + ".jpg"));
-
-        ROI[i]->image_org->Resize(modelxsize, modelysize, ROI[i]->image);
-        if (SaveAllFiles) ROI[i]->image->SaveToFile(FormatFileName("/sdcard/img_tmp/" + ROI[i]->name + ".bmp"));
-    }
+    for (int _ana = 0; _ana < ANALOG.size(); ++_ana)
+        for (int i = 0; i < ANALOG[_ana]->ROI.size(); ++i)
+        {
+            printf("Analog %d - Align&Cut\n", i);
+            
+            caic->CutAndSave(ANALOG[_ana]->ROI[i]->posx, ANALOG[_ana]->ROI[i]->posy, ANALOG[_ana]->ROI[i]->deltax, ANALOG[_ana]->ROI[i]->deltay, ANALOG[_ana]->ROI[i]->image_org);
+            if (SaveAllFiles)
+            {
+                if (ANALOG[_ana]->name == "default")
+                    ANALOG[_ana]->ROI[i]->image_org->SaveToFile(FormatFileName("/sdcard/img_tmp/" + ANALOG[_ana]->ROI[i]->name + ".jpg"));
+                else
+                    ANALOG[_ana]->ROI[i]->image_org->SaveToFile(FormatFileName("/sdcard/img_tmp/" + ANALOG[_ana]->name + "_" + ANALOG[_ana]->ROI[i]->name + ".jpg"));
+            } 
+
+            ANALOG[_ana]->ROI[i]->image_org->Resize(modelxsize, modelysize, ANALOG[_ana]->ROI[i]->image);
+            if (SaveAllFiles)
+            {
+                if (ANALOG[_ana]->name == "default")
+                    ANALOG[_ana]->ROI[i]->image->SaveToFile(FormatFileName("/sdcard/img_tmp/" + ANALOG[_ana]->ROI[i]->name + ".bmp"));
+                else
+                    ANALOG[_ana]->ROI[i]->image->SaveToFile(FormatFileName("/sdcard/img_tmp/" + ANALOG[_ana]->name + "_" + ANALOG[_ana]->ROI[i]->name + ".bmp"));
+            } 
+        }
 
     return true;
 } 
@@ -258,13 +332,14 @@ void ClassFlowAnalog::DrawROI(CImageBasis *_zw)
     int g = 255;
     int b = 0;
 
-    for (int i = 0; i < ROI.size(); ++i)
-    {
-        _zw->drawRect(ROI[i]->posx, ROI[i]->posy, ROI[i]->deltax, ROI[i]->deltay, r, g, b, 1);
-        _zw->drawCircle((int) (ROI[i]->posx + ROI[i]->deltax/2), (int)  (ROI[i]->posy + ROI[i]->deltay/2), (int) (ROI[i]->deltax/2), r, g, b, 2);
-        _zw->drawLine((int) (ROI[i]->posx + ROI[i]->deltax/2), (int) ROI[i]->posy, (int) (ROI[i]->posx + ROI[i]->deltax/2), (int) (ROI[i]->posy + ROI[i]->deltay), r, g, b, 2);
-        _zw->drawLine((int) ROI[i]->posx, (int) (ROI[i]->posy + ROI[i]->deltay/2), (int) ROI[i]->posx + ROI[i]->deltax, (int) (ROI[i]->posy + ROI[i]->deltay/2), r, g, b, 2);
-    }
+    for (int _ana = 0; _ana < ANALOG.size(); ++_ana)
+        for (int i = 0; i < ANALOG[_ana]->ROI.size(); ++i)
+        {
+            _zw->drawRect(ANALOG[_ana]->ROI[i]->posx, ANALOG[_ana]->ROI[i]->posy, ANALOG[_ana]->ROI[i]->deltax, ANALOG[_ana]->ROI[i]->deltay, r, g, b, 1);
+            _zw->drawCircle((int) (ANALOG[_ana]->ROI[i]->posx + ANALOG[_ana]->ROI[i]->deltax/2), (int)  (ANALOG[_ana]->ROI[i]->posy + ANALOG[_ana]->ROI[i]->deltay/2), (int) (ANALOG[_ana]->ROI[i]->deltax/2), r, g, b, 2);
+            _zw->drawLine((int) (ANALOG[_ana]->ROI[i]->posx + ANALOG[_ana]->ROI[i]->deltax/2), (int) ANALOG[_ana]->ROI[i]->posy, (int) (ANALOG[_ana]->ROI[i]->posx + ANALOG[_ana]->ROI[i]->deltax/2), (int) (ANALOG[_ana]->ROI[i]->posy + ANALOG[_ana]->ROI[i]->deltay), r, g, b, 2);
+            _zw->drawLine((int) ANALOG[_ana]->ROI[i]->posx, (int) (ANALOG[_ana]->ROI[i]->posy + ANALOG[_ana]->ROI[i]->deltay/2), (int) ANALOG[_ana]->ROI[i]->posx + ANALOG[_ana]->ROI[i]->deltax, (int) (ANALOG[_ana]->ROI[i]->posy + ANALOG[_ana]->ROI[i]->deltay/2), r, g, b, 2);
+        }
 } 
 
 bool ClassFlowAnalog::doNeuralNetwork(string time)
@@ -288,39 +363,38 @@ bool ClassFlowAnalog::doNeuralNetwork(string time)
     tflite->MakeAllocate();
 #endif
 
-    for (int i = 0; i < ROI.size(); ++i)
+    for (int _ana = 0; _ana < ANALOG.size(); ++_ana)
     {
-        printf("Analog %d - TfLite\n", i);
-        ioresize = "/sdcard/img_tmp/ra" + std::to_string(i) + ".bmp";
-        ioresize = FormatFileName(ioresize);
-
+        for (int i = 0; i < ANALOG[_ana]->ROI.size(); ++i)
+        {
+            printf("Analog %d - TfLite\n", i);
 
-        float f1, f2;
-        f1 = 0; f2 = 0;
+            float f1, f2;
+            f1 = 0; f2 = 0;
 
-#ifndef OHNETFLITE
-//        LogFile.WriteToFile("ClassFlowAnalog::doNeuralNetwork vor CNN tflite->LoadInputImage(ioresize)");
-//        tflite->LoadInputImage(ioresize);
-        tflite->LoadInputImageBasis(ROI[i]->image);        
-        tflite->Invoke();
-        if (debugdetailanalog) LogFile.WriteToFile("Nach Invoke");
+    #ifndef OHNETFLITE
+            tflite->LoadInputImageBasis(ANALOG[_ana]->ROI[i]->image);        
+            tflite->Invoke();
+            if (debugdetailanalog) LogFile.WriteToFile("Nach Invoke");
 
 
-        f1 = tflite->GetOutputValue(0);
-        f2 = tflite->GetOutputValue(1);
-#endif
+            f1 = tflite->GetOutputValue(0);
+            f2 = tflite->GetOutputValue(1);
+    #endif
 
-        float result = fmod(atan2(f1, f2) / (M_PI * 2) + 2, 1);
-//        printf("Result sin, cos, ziffer: %f, %f, %f\n", f1, f2, result);  
-        ROI[i]->result = result * 10;
+            float result = fmod(atan2(f1, f2) / (M_PI * 2) + 2, 1);
+    //        printf("Result sin, cos, ziffer: %f, %f, %f\n", f1, f2, result);  
+            ANALOG[_ana]->ROI[i]->result = result * 10;
 
-        printf("Result Analog%i: %f\n", i, ROI[i]->result); 
+            printf("Result Analog%i: %f\n", i, ANALOG[_ana]->ROI[i]->result); 
 
-        if (isLogImage)
-        {
-            LogImage(logPath, ROI[i]->name, &ROI[i]->result, NULL, time, ROI[i]->image_org);
+            if (isLogImage)
+            {
+                LogImage(logPath, ANALOG[_ana]->ROI[i]->name, &ANALOG[_ana]->ROI[i]->result, NULL, time, ANALOG[_ana]->ROI[i]->image_org);
+            }
         }
     }
+
 #ifndef OHNETFLITE
         delete tflite;
 #endif    
@@ -333,18 +407,78 @@ std::vector<HTMLInfo*> ClassFlowAnalog::GetHTMLInfo()
 {
     std::vector<HTMLInfo*> result;
 
-    for (int i = 0; i < ROI.size(); ++i)
-    {
-        HTMLInfo *zw = new HTMLInfo;
-        zw->filename = ROI[i]->name + ".bmp";
-        zw->filename_org = ROI[i]->name + ".jpg";
-        zw->val = ROI[i]->result;
-        zw->image = ROI[i]->image;
-        zw->image_org = ROI[i]->image_org;
-        result.push_back(zw);
-    }
+    for (int _ana = 0; _ana < ANALOG.size(); ++_ana)
+        for (int i = 0; i < ANALOG[_ana]->ROI.size(); ++i)
+        {
+                if (ANALOG[_ana]->name == "default")
+                    ANALOG[_ana]->ROI[i]->image->SaveToFile(FormatFileName("/sdcard/img_tmp/" + ANALOG[_ana]->ROI[i]->name + ".bmp"));
+                else
+                    ANALOG[_ana]->ROI[i]->image->SaveToFile(FormatFileName("/sdcard/img_tmp/" + ANALOG[_ana]->name + "_" + ANALOG[_ana]->ROI[i]->name + ".bmp"));
+
+
+            HTMLInfo *zw = new HTMLInfo;
+            if (ANALOG[_ana]->name == "default")
+            {
+                zw->filename = ANALOG[_ana]->ROI[i]->name + ".bmp";
+                zw->filename_org = ANALOG[_ana]->ROI[i]->name + ".jpg";
+            }
+            else
+            {
+                zw->filename = ANALOG[_ana]->name + "_" + ANALOG[_ana]->ROI[i]->name + ".bmp";
+                zw->filename_org = ANALOG[_ana]->name + "_" + ANALOG[_ana]->ROI[i]->name + ".jpg";
+            }
+
+            zw->val = ANALOG[_ana]->ROI[i]->result;
+            zw->image = ANALOG[_ana]->ROI[i]->image;
+            zw->image_org = ANALOG[_ana]->ROI[i]->image_org;
+
+            result.push_back(zw);
+        }
 
     return result;
 }
 
 
+
+int ClassFlowAnalog::getAnzahlANALOG()
+{
+    return ANALOG.size();
+}
+
+string ClassFlowAnalog::getNameANALOG(int _analog)
+{
+    if (_analog < ANALOG.size())
+        return ANALOG[_analog]->name;
+
+    return "ANALOG DOES NOT EXIST";
+}
+
+analog* ClassFlowAnalog::GetANALOG(int _analog)
+{
+    if (_analog < ANALOG.size())
+        return ANALOG[_analog];
+
+    return NULL;
+}
+
+
+
+void ClassFlowAnalog::UpdateNameNumbers(std::vector<std::string> *_name_numbers)
+{
+    for (int _dig = 0; _dig < ANALOG.size(); _dig++)
+    {
+        std::string _name = ANALOG[_dig]->name;
+        bool found = false;
+        for (int i = 0; i < (*_name_numbers).size(); ++i)
+        {
+            if ((*_name_numbers)[i] == _name)
+                found = true;
+        }
+        if (!found)
+            (*_name_numbers).push_back(_name);
+    }
+}
+
+
+
+

+ 21 - 4
code/components/jomjol_flowcontroll/ClassFlowAnalog.h

@@ -10,12 +10,19 @@ struct roianalog {
     string name;
 };
 
+struct analog {
+    string name;
+    std::vector<roianalog*> ROI;
+};
+
 
 class ClassFlowAnalog :
     public ClassFlowImage
 {
 protected:
-    std::vector<roianalog*> ROI;
+//    std::vector<roianalog*> ROI;
+    std::vector<analog*> ANALOG;
+
     string cnnmodelfile;
     int modelxsize, modelysize;
     int ZeigerEval(float zahl, int ziffer_vorgaenger);
@@ -24,7 +31,8 @@ protected:
 
     ClassFlowAlignment* flowpostalignment;
 
-	void SetInitialParameter(void);        
+	void SetInitialParameter(void);   
+
 
 public:
     bool extendedResolution;
@@ -34,14 +42,23 @@ public:
     bool ReadParameter(FILE* pfile, string& aktparamgraph);
     bool doFlow(string time);
     string getHTMLSingleStep(string host);
-    string getReadout();   
+    string getReadout(int _analog);   
 
     void DrawROI(CImageBasis *_zw); 
 
     bool doNeuralNetwork(string time); 
     bool doAlignAndCut(string time);
    	std::vector<HTMLInfo*> GetHTMLInfo();   
-    int AnzahlROIs(); 
+    int AnzahlROIs(int _analog);
+
+    int getAnzahlANALOG();
+    analog* GetANALOG(int _analog);
+    analog* GetANALOG(string _name, bool _create);
+    analog* FindANALOG(string _name_number);    
+    string getNameANALOG(int _analog);     
+
+    void UpdateNameNumbers(std::vector<std::string> *_name_numbers);
+
 
     string name(){return "ClassFlowAnalog";}; 
 };

+ 37 - 4
code/components/jomjol_flowcontroll/ClassFlowControll.cpp

@@ -120,6 +120,7 @@ ClassFlow* ClassFlowControll::CreateClassFlow(std::string _type)
     }
     if (toUpper(_type).compare("[MQTT]") == 0)
         cfc = new ClassFlowMQTT(&FlowControll);
+        
     if (toUpper(_type).compare("[POSTPROCESSING]") == 0)
     {
         cfc = new ClassFlowPostProcessing(&FlowControll); 
@@ -262,6 +263,38 @@ void ClassFlowControll::UpdateAktStatus(std::string _flow)
 }
 
 
+string ClassFlowControll::getReadoutAll(int _type)
+{
+    std::vector<NumberPost*> numbers = flowpostprocessing->GetNumbers();
+    std::string out = "";
+
+    for (int i = 0; i < numbers.size(); ++i)
+    {
+        out = out + numbers[i]->name + "\t";
+        switch (_type) {
+            case READOUT_TYPE_VALUE:
+                out = out + numbers[i]->ReturnValue;
+                break;
+            case READOUT_TYPE_PREVALUE:
+                out = out + numbers[i]->ReturnPreValue;
+                break;
+            case READOUT_TYPE_RAWVALUE:
+                out = out + numbers[i]->ReturnRawValue;
+                break;
+            case READOUT_TYPE_ERROR:
+                out = out + numbers[i]->ErrorMessageText;
+                break;
+        }
+        if (i < numbers.size()-1)
+            out = out + "\r\n";
+    }
+
+//    printf("OUT: %s", out.c_str());
+
+    return out;
+}	
+
+
 string ClassFlowControll::getReadout(bool _rawvalue = false, bool _noerror = false)
 {
     if (flowpostprocessing)
@@ -285,17 +318,17 @@ string ClassFlowControll::getReadout(bool _rawvalue = false, bool _noerror = fal
     return result;
 }
 
-string ClassFlowControll::GetPrevalue()	
+string ClassFlowControll::GetPrevalue(std::string _number)	
 {
     if (flowpostprocessing)
     {
-        return flowpostprocessing->GetPreValue();   
+        return flowpostprocessing->GetPreValue(_number);   
     }
 
     return std::string();    
 }
 
-std::string ClassFlowControll::UpdatePrevalue(std::string _newvalue)
+std::string ClassFlowControll::UpdatePrevalue(std::string _newvalue, std::string _numbers)
 {
     float zw;
     char* p;
@@ -317,7 +350,7 @@ std::string ClassFlowControll::UpdatePrevalue(std::string _newvalue)
 
     if (flowpostprocessing)
     {
-        flowpostprocessing->SavePreValue(zw);
+        flowpostprocessing->SetPreValue(zw, _numbers);
         return _newvalue;    
     }
 

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

@@ -11,6 +11,12 @@
 #include "ClassFlowMQTT.h"
 
 
+#define READOUT_TYPE_VALUE 0
+#define READOUT_TYPE_PREVALUE 1
+#define READOUT_TYPE_RAWVALUE 2
+#define READOUT_TYPE_ERROR 3
+
+
 class ClassFlowControll :
     public ClassFlow
 {
@@ -38,8 +44,9 @@ public:
 	void doFlowMakeImageOnly(string time);
 	bool getStatusSetupModus(){return SetupModeActive;};
 	string getReadout(bool _rawvalue, bool _noerror);
-	string UpdatePrevalue(std::string _newvalue);
-	string GetPrevalue();	
+	string getReadoutAll(int _type);	
+	string UpdatePrevalue(std::string _newvalue, std::string _numbers);
+	string GetPrevalue(std::string _number = "");	
 	bool ReadParameter(FILE* pfile, string& aktparamgraph);	
 
 	esp_err_t GetJPGStream(std::string _fn, httpd_req_t *req);

+ 175 - 51
code/components/jomjol_flowcontroll/ClassFlowDigit.cpp

@@ -64,16 +64,16 @@ ClassFlowDigit::ClassFlowDigit(std::vector<ClassFlow*>* lfc, ClassFlow *_prev) :
     }    
 }
 
-string ClassFlowDigit::getReadout()
+string ClassFlowDigit::getReadout(int _digit = 0)
 {
     string rst = "";
 
-    for (int i = 0; i < ROI.size(); ++i)
+    for (int i = 0; i < DIGIT[_digit]->ROI.size(); ++i)
     {
-        if (ROI[i]->resultklasse == 10)
+        if (DIGIT[_digit]->ROI[i]->resultklasse == 10)
             rst = rst + "N";
         else
-            rst = rst + std::to_string(ROI[i]->resultklasse);
+            rst = rst + std::to_string(DIGIT[_digit]->ROI[i]->resultklasse);
     }
 
     return rst;
@@ -91,18 +91,11 @@ bool ClassFlowDigit::ReadParameter(FILE* pfile, string& aktparamgraph)
 
     printf("aktparamgraph: %s\n", aktparamgraph.c_str());
 
-
-/*
-    if ((aktparamgraph.compare("[Digits]") != 0) && (aktparamgraph.compare(";[Digits]") != 0))       // Paragraph passt nich zu MakeImage
-        return false;
-*/
-
     if ((aktparamgraph.compare(0, 7, "[Digits") != 0) && (aktparamgraph.compare(0, 8, ";[Digits") != 0))       // Paragraph passt nich zu MakeImage
         return false;
 
     int _pospkt = aktparamgraph.find_first_of(".");
     int _posklammerzu = aktparamgraph.find_first_of("]");
-//    printf("Pos: %d, %d\n", _pospkt, _posklammerzu);
     if (_pospkt > -1)
         NameDigit = aktparamgraph.substr(_pospkt+1, _posklammerzu - _pospkt-1);
     else
@@ -137,8 +130,8 @@ bool ClassFlowDigit::ReadParameter(FILE* pfile, string& aktparamgraph)
         }
         if (zerlegt.size() >= 5)
         {
-            roi* neuroi = new roi;
-            neuroi->name = zerlegt[0];
+            digit* _digit = GetDIGIT(zerlegt[0], true);
+            roi* neuroi = _digit->ROI[_digit->ROI.size()-1];
             neuroi->posx = std::stoi(zerlegt[1]);
             neuroi->posy = std::stoi(zerlegt[2]);
             neuroi->deltax = std::stoi(zerlegt[3]);
@@ -146,7 +139,6 @@ bool ClassFlowDigit::ReadParameter(FILE* pfile, string& aktparamgraph)
             neuroi->resultklasse = -1;
             neuroi->image = NULL;
             neuroi->image_org = NULL;            
-            ROI.push_back(neuroi);
         }
 
         if ((toUpper(zerlegt[0]) == "SAVEALLFILES") && (zerlegt.size() > 1))
@@ -157,16 +149,75 @@ bool ClassFlowDigit::ReadParameter(FILE* pfile, string& aktparamgraph)
 
     }
 
-    for (int i = 0; i < ROI.size(); ++i)
+   for (int _dig = 0; _dig < DIGIT.size(); ++_dig)
+        for (int i = 0; i < DIGIT[_dig]->ROI.size(); ++i)
+        {
+            DIGIT[_dig]->ROI[i]->image = new CImageBasis(modelxsize, modelysize, 3);
+            DIGIT[_dig]->ROI[i]->image_org = new CImageBasis(DIGIT[_dig]->ROI[i]->deltax, DIGIT[_dig]->ROI[i]->deltay, 3);
+        }
+
+    return true;
+}
+
+digit* ClassFlowDigit::FindDIGIT(string _name_number)
+{
+    digit *_ret = NULL;
+
+    for (int i = 0; i < DIGIT.size(); ++i)
     {
-        ROI[i]->image = new CImageBasis(modelxsize, modelysize, 3);
-        ROI[i]->image_org = new CImageBasis(ROI[i]->deltax, ROI[i]->deltay, 3);
+        if (DIGIT[i]->name == _name_number)
+            return DIGIT[i];
     }
 
-    return true;
+    return NULL;
 }
 
 
+digit* ClassFlowDigit::GetDIGIT(string _name, bool _create = true)
+{
+    string _digit, _roi;
+    int _pospunkt = _name.find_first_of(".");
+//    printf("Name: %s, Pospunkt: %d\n", _name.c_str(), _pospunkt);
+    if (_pospunkt > -1)
+    {
+        _digit = _name.substr(0, _pospunkt);
+        _roi = _name.substr(_pospunkt+1, _name.length() - _pospunkt - 1);
+    }
+    else
+    {
+        _digit = "default";
+        _roi = _name;
+    }
+
+    digit *_ret = NULL;
+
+    for (int i = 0; i < DIGIT.size(); ++i)
+    {
+        if (DIGIT[i]->name == _digit)
+            _ret = DIGIT[i];
+    }
+
+    if (!_create)         // nicht gefunden und soll auch nicht erzeugt werden, ggf. geht eine NULL zurück
+        return _ret;
+
+    if (_ret == NULL)
+    {
+        _ret = new digit;
+        _ret->name = _digit;
+        DIGIT.push_back(_ret);
+    }
+
+    roi* neuroi = new roi;
+    neuroi->name = _roi;
+    _ret->ROI.push_back(neuroi);
+
+    printf("GetDIGIT - digit %s - roi %s\n", _digit.c_str(), _roi.c_str());
+
+    return _ret;
+}
+
+
+
 string ClassFlowDigit::getHTMLSingleStep(string host)
 {
     string result, zw;
@@ -216,17 +267,32 @@ bool ClassFlowDigit::doAlignAndCut(string time)
 
     CAlignAndCutImage *caic = flowpostalignment->GetAlignAndCutImage();
 
-    for (int i = 0; i < ROI.size(); ++i)
+    for (int _dig = 0; _dig < DIGIT.size(); ++_dig)
     {
-        printf("DigitalDigit %d - Align&Cut\n", i);
-        
-        caic->CutAndSave(ROI[i]->posx, ROI[i]->posy, ROI[i]->deltax, ROI[i]->deltay, ROI[i]->image_org);
-        if (SaveAllFiles) ROI[i]->image_org->SaveToFile(FormatFileName("/sdcard/img_tmp/" + ROI[i]->name + ".jpg"));
-
-        ROI[i]->image_org->Resize(modelxsize, modelysize, ROI[i]->image);
-        if (SaveAllFiles) ROI[i]->image->SaveToFile(FormatFileName("/sdcard/img_tmp/" + ROI[i]->name + ".bmp"));
+        printf("DIGIT[_dig]->ROI.size() %d\n", DIGIT[_dig]->ROI.size());
+        for (int i = 0; i < DIGIT[_dig]->ROI.size(); ++i)
+        {
+            printf("DigitalDigit %d - Align&Cut\n", i);
+            
+            caic->CutAndSave(DIGIT[_dig]->ROI[i]->posx, DIGIT[_dig]->ROI[i]->posy, DIGIT[_dig]->ROI[i]->deltax, DIGIT[_dig]->ROI[i]->deltay, DIGIT[_dig]->ROI[i]->image_org);
+            if (SaveAllFiles)
+            {
+                if (DIGIT[_dig]->name == "default")
+                    DIGIT[_dig]->ROI[i]->image_org->SaveToFile(FormatFileName("/sdcard/img_tmp/" + DIGIT[_dig]->ROI[i]->name + ".jpg"));
+                else
+                    DIGIT[_dig]->ROI[i]->image_org->SaveToFile(FormatFileName("/sdcard/img_tmp/" + DIGIT[_dig]->name + "_" + DIGIT[_dig]->ROI[i]->name + ".jpg"));
+            } 
+
+            DIGIT[_dig]->ROI[i]->image_org->Resize(modelxsize, modelysize, DIGIT[_dig]->ROI[i]->image);
+            if (SaveAllFiles)
+            {
+                if (DIGIT[_dig]->name == "default")
+                    DIGIT[_dig]->ROI[i]->image->SaveToFile(FormatFileName("/sdcard/img_tmp/" + DIGIT[_dig]->ROI[i]->name + ".bmp"));
+                else
+                    DIGIT[_dig]->ROI[i]->image->SaveToFile(FormatFileName("/sdcard/img_tmp/" + DIGIT[_dig]->name + "_" + DIGIT[_dig]->ROI[i]->name + ".bmp"));
+            } 
+        }
     }
-
     return true;
 } 
 
@@ -245,22 +311,23 @@ bool ClassFlowDigit::doNeuralNetwork(string time)
     tflite->MakeAllocate();
 #endif
 
-    for (int i = 0; i < ROI.size(); ++i)
-    {
-        printf("DigitalDigit %d - TfLite\n", i);
+    for (int _dig = 0; _dig < DIGIT.size(); ++_dig)
+        for (int i = 0; i < DIGIT[_dig]->ROI.size(); ++i)
+        {
+            printf("DigitalDigit %d - TfLite\n", i);
 
-        ROI[i]->resultklasse = 0;
-#ifndef OHNETFLITE
-        ROI[i]->resultklasse = tflite->GetClassFromImageBasis(ROI[i]->image);
+            DIGIT[_dig]->ROI[i]->resultklasse = 0;
+    #ifndef OHNETFLITE
+            DIGIT[_dig]->ROI[i]->resultklasse = tflite->GetClassFromImageBasis(DIGIT[_dig]->ROI[i]->image);
 
-#endif
-        printf("Result Digit%i: %d\n", i, ROI[i]->resultklasse);
+    #endif
+            printf("Result Digit%i: %d\n", i, DIGIT[_dig]->ROI[i]->resultklasse);
 
-        if (isLogImage)
-        {
-            LogImage(logPath, ROI[i]->name, NULL, &ROI[i]->resultklasse, time, ROI[i]->image_org);
+            if (isLogImage)
+            {
+                LogImage(logPath, DIGIT[_dig]->ROI[i]->name, NULL, &DIGIT[_dig]->ROI[i]->resultklasse, time, DIGIT[_dig]->ROI[i]->image_org);
+            }
         }
-    }
 #ifndef OHNETFLITE
         delete tflite;
 #endif
@@ -269,25 +336,82 @@ bool ClassFlowDigit::doNeuralNetwork(string time)
 
 void ClassFlowDigit::DrawROI(CImageBasis *_zw)
 {
-    for (int i = 0; i < ROI.size(); ++i)
-        _zw->drawRect(ROI[i]->posx, ROI[i]->posy, ROI[i]->deltax, ROI[i]->deltay, 0, 0, 255, 2);
+    for (int _dig = 0; _dig < DIGIT.size(); ++_dig)
+        for (int i = 0; i < DIGIT[_dig]->ROI.size(); ++i)
+            _zw->drawRect(DIGIT[_dig]->ROI[i]->posx, DIGIT[_dig]->ROI[i]->posy, DIGIT[_dig]->ROI[i]->deltax, DIGIT[_dig]->ROI[i]->deltay, 0, 0, (255 - _dig*100), 2);
 }     
 
 std::vector<HTMLInfo*> ClassFlowDigit::GetHTMLInfo()
 {
     std::vector<HTMLInfo*> result;
 
-    for (int i = 0; i < ROI.size(); ++i)
-    {
-        HTMLInfo *zw = new HTMLInfo;
-        zw->filename = ROI[i]->name + ".bmp";
-        zw->filename_org = ROI[i]->name + ".jpg";
-        zw->val = ROI[i]->resultklasse;
-        zw->image = ROI[i]->image;
-        zw->image_org = ROI[i]->image_org;
-        result.push_back(zw);
-    }
+    for (int _dig = 0; _dig < DIGIT.size(); ++_dig)
+        for (int i = 0; i < DIGIT[_dig]->ROI.size(); ++i)
+        {
+                if (DIGIT[_dig]->name == "default")
+                    DIGIT[_dig]->ROI[i]->image->SaveToFile(FormatFileName("/sdcard/img_tmp/" + DIGIT[_dig]->ROI[i]->name + ".bmp"));
+                else
+                    DIGIT[_dig]->ROI[i]->image->SaveToFile(FormatFileName("/sdcard/img_tmp/" + DIGIT[_dig]->name + "_" + DIGIT[_dig]->ROI[i]->name + ".bmp"));
+
+
+            HTMLInfo *zw = new HTMLInfo;
+            if (DIGIT[_dig]->name == "default")
+            {
+                zw->filename = DIGIT[_dig]->ROI[i]->name + ".bmp";
+                zw->filename_org = DIGIT[_dig]->ROI[i]->name + ".jpg";
+            }
+            else
+            {
+                zw->filename = DIGIT[_dig]->name + "_" + DIGIT[_dig]->ROI[i]->name + ".bmp";
+                zw->filename_org = DIGIT[_dig]->name + "_" + DIGIT[_dig]->ROI[i]->name + ".jpg";
+            }
+
+            zw->val = DIGIT[_dig]->ROI[i]->resultklasse;
+            zw->image = DIGIT[_dig]->ROI[i]->image;
+            zw->image_org = DIGIT[_dig]->ROI[i]->image_org;
+            result.push_back(zw);
+        }
 
     return result;
 }
 
+int ClassFlowDigit::getAnzahlDIGIT()
+{
+    return DIGIT.size();
+}
+
+string ClassFlowDigit::getNameDIGIT(int _digit)
+{
+    if (_digit < DIGIT.size())
+        return DIGIT[_digit]->name;
+
+    return "DIGIT DOES NOT EXIST";
+}
+
+digit* ClassFlowDigit::GetDIGIT(int _digit)
+{
+    if (_digit < DIGIT.size())
+        return DIGIT[_digit];
+
+    return NULL;
+}
+
+void ClassFlowDigit::UpdateNameNumbers(std::vector<std::string> *_name_numbers)
+{
+    for (int _dig = 0; _dig < DIGIT.size(); _dig++)
+    {
+        std::string _name = DIGIT[_dig]->name;
+        bool found = false;
+        for (int i = 0; i < (*_name_numbers).size(); ++i)
+        {
+            if ((*_name_numbers)[i] == _name)
+                found = true;
+        }
+        if (!found)
+            (*_name_numbers).push_back(_name);
+    }
+}
+
+
+
+

+ 20 - 2
code/components/jomjol_flowcontroll/ClassFlowDigit.h

@@ -5,6 +5,8 @@
 
 #include <string>
 
+
+
 struct roi {
     int posx, posy, deltax, deltay;
     int resultklasse;
@@ -13,11 +15,17 @@ struct roi {
     roi* next;
 };
 
+struct digit {
+    string name;
+    std::vector<roi*> ROI;
+};
+
 class ClassFlowDigit :
     public ClassFlowImage
 {
 protected:
-    std::vector<roi*> ROI;
+//    std::vector<roi*> ROI;
+    std::vector<digit*> DIGIT;
     string cnnmodelfile;
     int modelxsize, modelysize;
     bool SaveAllFiles;
@@ -31,6 +39,7 @@ protected:
     bool doNeuralNetwork(string time); 
     bool doAlignAndCut(string time); 
 
+
 	void SetInitialParameter(void);    
 
 public:
@@ -40,9 +49,18 @@ public:
     bool ReadParameter(FILE* pfile, string& aktparamgraph);
     bool doFlow(string time);
     string getHTMLSingleStep(string host); 
-    string getReadout();
+    string getReadout(int _digit);
    	std::vector<HTMLInfo*> GetHTMLInfo();
 
+    int getAnzahlDIGIT();
+    digit* GetDIGIT(int _digit);
+    digit* GetDIGIT(string _name, bool _create);
+    digit* FindDIGIT(string _name_number);
+
+    string getNameDIGIT(int _digit);
+
+    void UpdateNameNumbers(std::vector<std::string> *_name_numbers);
+
     void DrawROI(CImageBasis *_zw);        
 
     string name(){return "ClassFlowDigit";};

+ 49 - 39
code/components/jomjol_flowcontroll/ClassFlowMQTT.cpp

@@ -13,6 +13,9 @@ void ClassFlowMQTT::SetInitialParameter(void)
     topicError = "";
     topicRate = "";
     topicTimeStamp = "";
+    maintopic = "";
+    mainerrortopic = ""; 
+
     clientname = "watermeter";
     OldValue = "";
     flowpostprocessing = NULL;  
@@ -21,6 +24,9 @@ void ClassFlowMQTT::SetInitialParameter(void)
     previousElement = NULL;
     ListFlowControll = NULL; 
     disabled = false;
+    MQTTenable = false;
+    
+    
 
 }       
 
@@ -88,33 +94,24 @@ bool ClassFlowMQTT::ReadParameter(FILE* pfile, string& aktparamgraph)
         {
             this->uri = zerlegt[1];
         }
-        if ((toUpper(zerlegt[0]) == "TOPIC") && (zerlegt.size() > 1))
-        {
-            this->topic = zerlegt[1];
-        }
-        if ((toUpper(zerlegt[0]) == "TOPICERROR") && (zerlegt.size() > 1))
-        {
-            this->topicError = zerlegt[1];
-        }
-        if ((toUpper(zerlegt[0]) == "TOPICRATE") && (zerlegt.size() > 1))
-        {
-            this->topicRate  = zerlegt[1];
-        }
-        if ((toUpper(zerlegt[0]) == "TOPICTIMESTAMP") && (zerlegt.size() > 1))
-        {
-            this->topicTimeStamp  = zerlegt[1];
-        }
 
         if ((toUpper(zerlegt[0]) == "CLIENTID") && (zerlegt.size() > 1))
         {
             this->clientname = zerlegt[1];
         }
 
+        if (((toUpper(zerlegt[0]) == "TOPIC") || (toUpper(zerlegt[0]) == "MAINTOPIC")) && (zerlegt.size() > 1))
+        {
+            maintopic = zerlegt[1];
+        }
     }
 
-    if ((uri.length() > 0) && (topic.length() > 0)) 
+    if ((uri.length() > 0) && (maintopic.length() > 0)) 
     {
-        MQTTInit(uri, clientname, user, password, topicError, 60);
+        mainerrortopic = maintopic + "/connection";
+        MQTTInit(uri, clientname, user, password, mainerrortopic, 60); 
+        MQTTPublish(mainerrortopic, "connected");
+        MQTTenable = true;
     }
    
     return true;
@@ -123,18 +120,47 @@ bool ClassFlowMQTT::ReadParameter(FILE* pfile, string& aktparamgraph)
 
 bool ClassFlowMQTT::doFlow(string zwtime)
 {
+    if (!MQTTenable)
+        return true;
+
     std::string result;
     std::string resulterror = "";
     std::string resultrate = "";
     std::string resulttimestamp = "";
     string zw = "";
+    string namenumber = "";
+
+    MQTTPublish(mainerrortopic, "connected");
     
     if (flowpostprocessing)
     {
-        result =  flowpostprocessing->getReadoutParam(false, true);
-        resulterror = flowpostprocessing->getReadoutError();
-        resultrate = flowpostprocessing->getReadoutRate();
-        resulttimestamp = flowpostprocessing->getReadoutTimeStamp();
+        std::vector<NumberPost*> NUMBERS = flowpostprocessing->GetNumbers();
+
+        for (int i = 0; i < NUMBERS.size(); ++i)
+        {
+            result =  NUMBERS[i]->ReturnValueNoError;
+            resulterror = NUMBERS[i]->ErrorMessageText;
+            resultrate = std::to_string(NUMBERS[i]->FlowRateAct);
+            resulttimestamp = NUMBERS[i]->timeStamp;
+
+            namenumber = NUMBERS[i]->name;
+            if (namenumber == "default")
+                namenumber = maintopic + "/";
+            else
+                namenumber = maintopic + "/" + namenumber + "/";
+
+            zw = namenumber + "value";    
+            MQTTPublish(zw, result);
+
+            zw = namenumber + "error";    
+            MQTTPublish(zw, resulterror, 1);
+
+            zw = namenumber + "rate";    
+            MQTTPublish(zw, resultrate);
+
+            zw = namenumber + "timestamp";    
+            MQTTPublish(zw, resulttimestamp);
+        }
     }
     else
     {
@@ -149,25 +175,9 @@ bool ClassFlowMQTT::doFlow(string zwtime)
                     result = result + "\t" + zw;
             }
         }
+        MQTTPublish(topic, result);
     }
     
-    MQTTPublish(topic, result);
-
-    if (topicError.length() > 0) {
-        if (resulterror.length() == 0)
-        {
-            resulterror = " ";
-        }
-        MQTTPublish(topicError, resulterror, 1);
-    }
-
-    if (topicRate.length() > 0) {
-        MQTTPublish(topicRate, resultrate);
-    }
-
-    if (topicTimeStamp.length() > 0) {
-        MQTTPublish(topicTimeStamp, resulttimestamp);
-    }
 
     OldValue = result;
     

+ 4 - 1
code/components/jomjol_flowcontroll/ClassFlowMQTT.h

@@ -12,7 +12,10 @@ protected:
     std::string uri, topic, topicError, clientname, topicRate, topicTimeStamp;
     std::string OldValue;
 	ClassFlowPostProcessing* flowpostprocessing;  
-    std::string user, password;  
+    std::string user, password; 
+    bool MQTTenable;
+
+    std::string maintopic, mainerrortopic; 
 	void SetInitialParameter(void);        
 
 public:

+ 412 - 244
code/components/jomjol_flowcontroll/ClassFlowPostProcessing.cpp

@@ -1,8 +1,6 @@
 #include "ClassFlowPostProcessing.h"
 
 #include "Helper.h"
-#include "ClassFlowAnalog.h"
-#include "ClassFlowDigit.h"
 #include "ClassFlowMakeImage.h"
 #include "ClassLogFile.h"
 
@@ -18,130 +16,205 @@
 #define PREVALUE_TIME_FORMAT_INPUT "%d-%d-%dT%d:%d:%d"
 
 
-string ClassFlowPostProcessing::GetPreValue()
+string ClassFlowPostProcessing::GetPreValue(std::string _number)
 {
     std::string result;
-    bool isAnalog = false;
-    bool isDigit = false;
+    int index = -1;
 
-    int AnzahlAnalog = 0;
-    result = RundeOutput(PreValue, -DecimalShift);
+    if (_number == "")
+        _number = "default";
 
-    for (int i = 0; i < ListFlowControll->size(); ++i)
-    {
-        if (((*ListFlowControll)[i])->name().compare("ClassFlowAnalog") == 0)
-        {
-            isAnalog = true;
-            AnzahlAnalog = ((ClassFlowAnalog*)(*ListFlowControll)[i])->AnzahlROIs();
-        }
-        if (((*ListFlowControll)[i])->name().compare("ClassFlowDigit") == 0)
-        {
-            isDigit = true;
-        }
-    }
+    for (int i = 0; i < NUMBERS.size(); ++i)
+        if (NUMBERS[i]->name == _number)
+            index = i;
+
+//    result = RundeOutput(NUMBERS[index]->PreValue, -NUMBERS[index]->DecimalShift);
+    result = RundeOutput(NUMBERS[index]->PreValue, NUMBERS[index]->Nachkomma);
 
-    if (isDigit && isAnalog)
-        result = RundeOutput(PreValue, AnzahlAnalog - DecimalShift);
+//    if (NUMBERS[index]->digit_roi && NUMBERS[index]->analog_roi)
+//        result = RundeOutput(NUMBERS[index]->PreValue, NUMBERS[index]->AnzahlAnalog - NUMBERS[index]->DecimalShift);
 
     return result;
 }
 
+void ClassFlowPostProcessing::SetPreValue(float zw, string _numbers)
+{
+    for (int j = 0; j < NUMBERS.size(); ++j)
+    {
+        if (NUMBERS[j]->name == _numbers)
+            NUMBERS[j]->PreValue = zw;
+    }
+    UpdatePreValueINI = true;
+    SavePreValue();
+}
+
+
 bool ClassFlowPostProcessing::LoadPreValue(void)
 {
+    std::vector<string> zerlegt;
     FILE* pFile;
     char zw[1024];
-    string zwtime, zwvalue;
+    string zwtime, zwvalue, name;
+    bool _done = false;
+
+    UpdatePreValueINI = false;       // Konvertierung ins neue Format
+
 
     pFile = fopen(FilePreValue.c_str(), "r");
     if (pFile == NULL)
         return false;
 
     fgets(zw, 1024, pFile);
-    printf("%s", zw);
+    printf("Read Zeile Prevalue.ini: %s", zw);
     zwtime = trim(std::string(zw));
-
-    fgets(zw, 1024, pFile);
-    fclose(pFile);
-    printf("%s", zw);
-    zwvalue = trim(std::string(zw));
-    PreValue = stof(zwvalue.c_str());
-
-    time_t tStart;
-    int yy, month, dd, hh, mm, ss;
-    struct tm whenStart;
-
-    sscanf(zwtime.c_str(), PREVALUE_TIME_FORMAT_INPUT, &yy, &month, &dd, &hh, &mm, &ss);
-    whenStart.tm_year = yy - 1900;
-    whenStart.tm_mon = month - 1;
-    whenStart.tm_mday = dd;
-    whenStart.tm_hour = hh;
-    whenStart.tm_min = mm;
-    whenStart.tm_sec = ss;
-    whenStart.tm_isdst = -1;
-
-    lastvalue = mktime(&whenStart);
-
-    time(&tStart);
-    localtime(&tStart);
-    double difference = difftime(tStart, lastvalue);
-    difference /= 60;
-    if (difference > PreValueAgeStartup)
+    if (zwtime.length() == 0)
         return false;
 
-    Value = PreValue;
-    ReturnValue = to_string(Value);
-    ReturnValueNoError = ReturnValue; 
+    zerlegt = HelperZerlegeZeile(zwtime, "\t");
+    if (zerlegt.size() > 1)     // neues Format
+    {
+        while ((zerlegt.size() > 1) && !_done)
+        {
+            name = trim(zerlegt[0]);
+            zwtime = trim(zerlegt[1]);
+            zwvalue = trim(zerlegt[2]);
 
-    bool isAnalog = false;
-    bool isDigit = false;
-    int AnzahlAnalog = 0;
+            for (int j = 0; j < NUMBERS.size(); ++j)
+            {
+                if (NUMBERS[j]->name == name)
+                {
+                    NUMBERS[j]->PreValue = stof(zwvalue.c_str());
+                    NUMBERS[j]->ReturnPreValue = RundeOutput(NUMBERS[j]->PreValue, NUMBERS[j]->Nachkomma);
+
+                    time_t tStart;
+                    int yy, month, dd, hh, mm, ss;
+                    struct tm whenStart;
+
+                    sscanf(zwtime.c_str(), PREVALUE_TIME_FORMAT_INPUT, &yy, &month, &dd, &hh, &mm, &ss);
+                    whenStart.tm_year = yy - 1900;
+                    whenStart.tm_mon = month - 1;
+                    whenStart.tm_mday = dd;
+                    whenStart.tm_hour = hh;
+                    whenStart.tm_min = mm;
+                    whenStart.tm_sec = ss;
+                    whenStart.tm_isdst = -1;
+
+                    NUMBERS[j]->lastvalue = mktime(&whenStart);
+
+                    time(&tStart);
+                    localtime(&tStart);
+                    double difference = difftime(tStart, NUMBERS[j]->lastvalue);
+                    difference /= 60;
+                    if (difference > PreValueAgeStartup)
+                    {
+                        NUMBERS[j]->PreValueOkay = false;
+                    }
+                    else
+                    {
+                        NUMBERS[j]->PreValueOkay = true;
+                        NUMBERS[j]->Value = NUMBERS[j]->PreValue;
+                        NUMBERS[j]->ReturnValue = to_string(NUMBERS[j]->Value);
+                        NUMBERS[j]->ReturnValueNoError = NUMBERS[j]->ReturnValue; 
+
+                        if (NUMBERS[j]->digit_roi || NUMBERS[j]->analog_roi)
+                        {
+                            NUMBERS[j]->ReturnValue = RundeOutput(NUMBERS[j]->Value, NUMBERS[j]->AnzahlAnalog - NUMBERS[j]->DecimalShift);
+                            NUMBERS[j]->ReturnValueNoError = NUMBERS[j]->ReturnValue;
+                        }
+                    }
+
+                }
+            }
 
-    for (int i = 0; i < ListFlowControll->size(); ++i)
+            if (!fgets(zw, 1024, pFile))
+                _done = true;
+            else
+            {
+                printf("Read Zeile Prevalue.ini: %s", zw);
+                zerlegt = HelperZerlegeZeile(trim(std::string(zw)), "\t");
+                if (zerlegt.size() > 1)
+                {
+                    name = trim(zerlegt[0]);
+                    zwtime = trim(zerlegt[1]);
+                    zwvalue = trim(zerlegt[2]);
+                }
+            }
+        }
+        fclose(pFile);
+    }   
+    else        // altes Format
     {
-        if (((*ListFlowControll)[i])->name().compare("ClassFlowAnalog") == 0)
-            isAnalog = true;
-        if (((*ListFlowControll)[i])->name().compare("ClassFlowDigit") == 0)
-            isDigit = true;
-    }
+        fgets(zw, 1024, pFile);
+        fclose(pFile);
+        printf("%s", zw);
+        zwvalue = trim(std::string(zw));
+        NUMBERS[0]->PreValue = stof(zwvalue.c_str());
+
+        time_t tStart;
+        int yy, month, dd, hh, mm, ss;
+        struct tm whenStart;
+
+        sscanf(zwtime.c_str(), PREVALUE_TIME_FORMAT_INPUT, &yy, &month, &dd, &hh, &mm, &ss);
+        whenStart.tm_year = yy - 1900;
+        whenStart.tm_mon = month - 1;
+        whenStart.tm_mday = dd;
+        whenStart.tm_hour = hh;
+        whenStart.tm_min = mm;
+        whenStart.tm_sec = ss;
+        whenStart.tm_isdst = -1;
+
+        printf("TIME: %d, %d, %d, %d, %d, %d\n", whenStart.tm_year, whenStart.tm_mon, whenStart.tm_wday, whenStart.tm_hour, whenStart.tm_min, whenStart.tm_sec);
+
+        NUMBERS[0]->lastvalue = mktime(&whenStart);
+
+        time(&tStart);
+        localtime(&tStart);
+        double difference = difftime(tStart, NUMBERS[0]->lastvalue);
+        difference /= 60;
+        if (difference > PreValueAgeStartup)
+            return false;
+
+        NUMBERS[0]->Value = NUMBERS[0]->PreValue;
+        NUMBERS[0]->ReturnValue = to_string(NUMBERS[0]->Value);
+        NUMBERS[0]->ReturnValueNoError = NUMBERS[0]->ReturnValue; 
+
+        if (NUMBERS[0]->digit_roi || NUMBERS[0]->analog_roi)
+        {
+            NUMBERS[0]->ReturnValue = RundeOutput(NUMBERS[0]->Value, NUMBERS[0]->AnzahlAnalog - NUMBERS[0]->DecimalShift);
+            NUMBERS[0]->ReturnValueNoError = NUMBERS[0]->ReturnValue;
+        }
+
+        UpdatePreValueINI = true;       // Konvertierung ins neue Format
+        SavePreValue();
+    } 
 
-    if (isDigit || isAnalog)
-    {
-        ReturnValue = RundeOutput(Value, AnzahlAnalog - DecimalShift);
-        ReturnValueNoError = ReturnValue;
-    }
-   
     return true;
 }
 
-void ClassFlowPostProcessing::SavePreValue(float value, string zwtime)
+void ClassFlowPostProcessing::SavePreValue()
 {
     FILE* pFile;
+    string _zw;
+
+    if (!UpdatePreValueINI)         // PreValues unverändert --> File muss nicht neu geschrieben werden
+        return;
 
     pFile = fopen(FilePreValue.c_str(), "w");
 
-    if (strlen(zwtime.c_str()) == 0)
+    for (int j = 0; j < NUMBERS.size(); ++j)
     {
-        time_t rawtime;
-        struct tm* timeinfo;
         char buffer[80];
+        struct tm* timeinfo = localtime(&NUMBERS[j]->lastvalue);
+        strftime(buffer, 80, PREVALUE_TIME_FORMAT_OUTPUT, timeinfo);
+        NUMBERS[j]->timeStamp = std::string(buffer);
 
-        time(&rawtime);
-        timeinfo = localtime(&rawtime);
+        _zw = NUMBERS[j]->name + "\t" + NUMBERS[j]->timeStamp + "\t" + to_string(NUMBERS[j]->PreValue) + "\n";
+        printf("Write PreValue Zeile: %s\n", _zw.c_str());
 
-        strftime(buffer, 80, PREVALUE_TIME_FORMAT_OUTPUT, timeinfo);
-        timeStamp = std::string(buffer);
+        fputs(_zw.c_str(), pFile);
     }
-    else
-    {
-        timeStamp = zwtime;
-    }
-
-    PreValue = value;
 
-    fputs(timeStamp.c_str(), pFile);
-    fputs("\n", pFile);
-    fputs(to_string(value).c_str(), pFile);
-    fputs("\n", pFile);
+    UpdatePreValueINI = false;
 
     fclose(pFile);
 }
@@ -149,22 +222,19 @@ void ClassFlowPostProcessing::SavePreValue(float value, string zwtime)
 
 ClassFlowPostProcessing::ClassFlowPostProcessing(std::vector<ClassFlow*>* lfc)
 {
-    FlowRateAct = 0;
+//    FlowRateAct = 0;
     PreValueUse = false;
     PreValueAgeStartup = 30;
-    AllowNegativeRates = false;
-    MaxRateValue = 0.1;
     ErrorMessage = false;
     ListFlowControll = NULL;
-    PreValueOkay = false;
-    useMaxRateValue = false;
-    checkDigitIncreaseConsistency = false;
-    DecimalShift = 0;    
-    ErrorMessageText = "";
-    timeStamp = "";
+//    PreValueOkay = false;
+//    DecimalShift = 0;    
+//    ErrorMessageText = "";
+//    timeStamp = "";
     FilePreValue = FormatFileName("/sdcard/config/prevalue.ini");
     ListFlowControll = lfc;
     flowMakeImage = NULL;
+    UpdatePreValueINI = false;
 
     for (int i = 0; i < ListFlowControll->size(); ++i)
     {
@@ -175,10 +245,59 @@ ClassFlowPostProcessing::ClassFlowPostProcessing(std::vector<ClassFlow*>* lfc)
     }
 }
 
+void ClassFlowPostProcessing::handleDecimalSeparator(string _decsep, string _value)
+{
+    string _digit, _decpos;
+    int _pospunkt = _decsep.find_first_of(".");
+//    printf("Name: %s, Pospunkt: %d\n", _decsep.c_str(), _pospunkt);
+    if (_pospunkt > -1)
+        _digit = _decsep.substr(0, _pospunkt);
+    else
+        _digit = "default";
+
+    for (int j = 0; j < NUMBERS.size(); ++j)
+    {
+        if (_digit == "default")                        // erstmal auf default setzen (falls sonst nichts gesetzt)
+            NUMBERS[j]->DecimalShift = stoi(_value);
+
+        if (NUMBERS[j]->name == _digit)
+            NUMBERS[j]->DecimalShift = stoi(_value);
+
+        NUMBERS[j]->Nachkomma = NUMBERS[j]->AnzahlAnalog - NUMBERS[j]->DecimalShift;
+    }
+}
+
+void ClassFlowPostProcessing::handleMaxRateValue(string _decsep, string _value)
+{
+    string _digit, _decpos;
+    int _pospunkt = _decsep.find_first_of(".");
+//    printf("Name: %s, Pospunkt: %d\n", _decsep.c_str(), _pospunkt);
+    if (_pospunkt > -1)
+        _digit = _decsep.substr(0, _pospunkt);
+    else
+        _digit = "default";
+
+    for (int j = 0; j < NUMBERS.size(); ++j)
+    {
+        if (_digit == "default")                        // erstmal auf default setzen (falls sonst nichts gesetzt)
+        {
+            NUMBERS[j]->useMaxRateValue = true;
+            NUMBERS[j]->MaxRateValue = stof(_value);
+        }
+
+        if (NUMBERS[j]->name == _digit)
+        {
+            NUMBERS[j]->useMaxRateValue = true;
+            NUMBERS[j]->MaxRateValue = stof(_value);
+        }
+    }
+}
+
 
 bool ClassFlowPostProcessing::ReadParameter(FILE* pfile, string& aktparamgraph)
 {
     std::vector<string> zerlegt;
+    int _n;
 
     aktparamgraph = trim(aktparamgraph);
 
@@ -190,53 +309,148 @@ bool ClassFlowPostProcessing::ReadParameter(FILE* pfile, string& aktparamgraph)
     if (aktparamgraph.compare("[PostProcessing]") != 0)       // Paragraph passt nich zu MakeImage
         return false;
 
+    InitNUMBERS();
+
+
     while (this->getNextLine(pfile, &aktparamgraph) && !this->isNewParagraph(aktparamgraph))
     {
         zerlegt = this->ZerlegeZeile(aktparamgraph);
-        if ((toUpper(zerlegt[0]) == "DECIMALSHIFT") && (zerlegt.size() > 1))
+        std::string _param = GetParameterName(zerlegt[0]);
+
+        if ((toUpper(_param) == "DECIMALSHIFT") && (zerlegt.size() > 1))
         {
-            DecimalShift = stoi(zerlegt[1]);
+            handleDecimalSeparator(zerlegt[0], zerlegt[1]);
+        }
+        if ((toUpper(_param) == "MAXRATEVALUE") && (zerlegt.size() > 1))
+        {
+            handleMaxRateValue(zerlegt[0], zerlegt[1]);
         }
 
-        if ((toUpper(zerlegt[0]) == "PREVALUEUSE") && (zerlegt.size() > 1))
+        if ((toUpper(_param) == "PREVALUEUSE") && (zerlegt.size() > 1))
         {
             if (toUpper(zerlegt[1]) == "TRUE")
             {
                 PreValueUse = true;
             }
         }
-        if ((toUpper(zerlegt[0]) == "CHECKDIGITINCREASECONSISTENCY") && (zerlegt.size() > 1))
+        if ((toUpper(_param) == "CHECKDIGITINCREASECONSISTENCY") && (zerlegt.size() > 1))
         {
             if (toUpper(zerlegt[1]) == "TRUE")
-                checkDigitIncreaseConsistency = true;
+                for (_n = 0; _n < NUMBERS.size(); ++_n)
+                    NUMBERS[_n]->checkDigitIncreaseConsistency = true;
         }        
-        if ((toUpper(zerlegt[0]) == "ALLOWNEGATIVERATES") && (zerlegt.size() > 1))
+        if ((toUpper(_param) == "ALLOWNEGATIVERATES") && (zerlegt.size() > 1))
         {
             if (toUpper(zerlegt[1]) == "TRUE")
-                AllowNegativeRates = true;
+                for (_n = 0; _n < NUMBERS.size(); ++_n)
+                    NUMBERS[_n]->AllowNegativeRates = true;
         }
-        if ((toUpper(zerlegt[0]) == "ERRORMESSAGE") && (zerlegt.size() > 1))
+        if ((toUpper(_param) == "ERRORMESSAGE") && (zerlegt.size() > 1))
         {
             if (toUpper(zerlegt[1]) == "TRUE")
                 ErrorMessage = true;
         }
-        if ((toUpper(zerlegt[0]) == "PREVALUEAGESTARTUP") && (zerlegt.size() > 1))
+        if ((toUpper(_param) == "PREVALUEAGESTARTUP") && (zerlegt.size() > 1))
         {
             PreValueAgeStartup = std::stoi(zerlegt[1]);
         }
-        if ((toUpper(zerlegt[0]) == "MAXRATEVALUE") && (zerlegt.size() > 1))
-        {
-            useMaxRateValue = true;
-            MaxRateValue = std::stof(zerlegt[1]);
-        }
     }
 
     if (PreValueUse) {
-        PreValueOkay = LoadPreValue();
+        LoadPreValue();
     }
+
     return true;
 }
 
+void ClassFlowPostProcessing::InitNUMBERS()
+{
+//    ClassFlowDigit* _cdigit = NULL;
+//    ClassFlowAnalog* _canalog = NULL;
+    int anzDIGIT = 0;
+    int anzANALOG = 0;
+    std::vector<std::string> name_numbers;
+
+    flowAnalog = NULL;
+    flowDigit = NULL;
+
+    for (int i = 0; i < ListFlowControll->size(); ++i)
+    {
+        if (((*ListFlowControll)[i])->name().compare("ClassFlowDigit") == 0)
+        {
+            flowDigit = (ClassFlowDigit*) (*ListFlowControll)[i];
+            anzDIGIT = flowDigit->getAnzahlDIGIT();
+        }
+        if (((*ListFlowControll)[i])->name().compare("ClassFlowAnalog") == 0)
+        {
+            flowAnalog = (ClassFlowAnalog*)(*ListFlowControll)[i];
+            anzANALOG = flowAnalog->getAnzahlANALOG();
+        }
+    }
+
+    if (flowDigit)
+        flowDigit->UpdateNameNumbers(&name_numbers);
+    if (flowAnalog)
+        flowAnalog->UpdateNameNumbers(&name_numbers);
+
+    printf("Anzahl NUMBERS: %d - DIGITS: %d, ANALOG: %d\n", name_numbers.size(), anzDIGIT, anzANALOG);
+
+    for (int _num = 0; _num < name_numbers.size(); ++_num)
+    {
+        NumberPost *_number = new NumberPost;
+
+        _number->name = name_numbers[_num];
+        
+        _number->digit_roi = NULL;
+        if (flowDigit)
+            _number->digit_roi = flowDigit->FindDIGIT(name_numbers[_num]);
+        
+        if (_number->digit_roi)
+            _number->AnzahlDigital = _number->digit_roi->ROI.size();
+        else
+            _number->AnzahlDigital = 0;
+
+        _number->analog_roi = NULL;
+        if (flowAnalog)
+            _number->analog_roi = flowAnalog->FindANALOG(name_numbers[_num]);
+
+
+        if (_number->analog_roi)
+            _number->AnzahlAnalog = _number->analog_roi->ROI.size();
+        else
+            _number->AnzahlAnalog = 0;
+
+        _number->ReturnRawValue = "";      // Rohwert (mit N & führenden 0)    
+        _number->ReturnValue = "";         // korrigierter Rückgabewert, ggf. mit Fehlermeldung
+        _number->ReturnValueNoError = "";  // korrigierter Rückgabewert ohne Fehlermeldung
+        _number->ErrorMessageText = "";        // Fehlermeldung bei Consistency Check
+        _number->ReturnPreValue = "";
+        _number->PreValueOkay = false;
+        _number->AllowNegativeRates = false;
+        _number->MaxRateValue = 0.1;
+        _number->useMaxRateValue = false;
+        _number->checkDigitIncreaseConsistency = false;
+        _number->PreValueOkay = false;
+        _number->useMaxRateValue = false;
+        _number->DecimalShift = 0;
+
+        _number->FlowRateAct = 0;          // m3 / min
+        _number->PreValue = 0;             // letzter Wert, der gut ausgelesen wurde
+        _number->Value = 0;                // letzer ausgelesener Wert, inkl. Korrekturen
+        _number->ReturnRawValue = "";      // Rohwert (mit N & führenden 0)    
+        _number->ReturnValue = "";         // korrigierter Rückgabewert, ggf. mit Fehlermeldung
+        _number->ReturnValueNoError = "";  // korrigierter Rückgabewert ohne Fehlermeldung
+        _number->ErrorMessageText = "";        // Fehlermeldung bei Consistency Check
+
+        _number->Nachkomma = _number->AnzahlAnalog;
+
+        NUMBERS.push_back(_number);
+    }
+
+    for (int i = 0; i < NUMBERS.size(); ++i)
+        printf("Number %s, Anz DIG: %d, Anz ANA %d\n", NUMBERS[i]->name.c_str(), NUMBERS[i]->AnzahlDigital, NUMBERS[i]->AnzahlAnalog);
+}
+
 string ClassFlowPostProcessing::ShiftDecimal(string in, int _decShift){
 
     if (_decShift == 0){
@@ -285,173 +499,127 @@ bool ClassFlowPostProcessing::doFlow(string zwtime)
     string digit = "";
     string analog = "";
     string zwvalue;
-    bool isdigit = false;
-    bool isanalog = false;
-    int AnzahlAnalog = 0;
     string zw;
     time_t imagetime = 0;
     string rohwert;
 
-    ErrorMessageText = "";
-
-
-    for (int i = 0; i < ListFlowControll->size(); ++i)
-    {
-        if (((*ListFlowControll)[i])->name().compare("ClassFlowMakeImage") == 0)
-        {
-            imagetime = ((ClassFlowMakeImage*)(*ListFlowControll)[i])->getTimeImageTaken();
-        }
-        if (((*ListFlowControll)[i])->name().compare("ClassFlowDigit") == 0)
-        {
-            isdigit = true;
-            digit = (*ListFlowControll)[i]->getReadout();
-        }
-        if (((*ListFlowControll)[i])->name().compare("ClassFlowAnalog") == 0)
-        {
-            isanalog = true;
-            analog = (*ListFlowControll)[i]->getReadout();
-            AnzahlAnalog = ((ClassFlowAnalog*)(*ListFlowControll)[i])->AnzahlROIs();
-        }
-    }
+//    ErrorMessageText = "";
 
+    imagetime = flowMakeImage->getTimeImageTaken();
     if (imagetime == 0)
         time(&imagetime);
 
     struct tm* timeinfo;
     timeinfo = localtime(&imagetime);
-
     char strftime_buf[64];
     strftime(strftime_buf, sizeof(strftime_buf), "%Y-%m-%dT%H:%M:%S", timeinfo);
     zwtime = std::string(strftime_buf);
 
+    printf("Anzahl NUMBERS: %d\n", NUMBERS.size());
 
-    //    // TESTING ONLY////////////////////
-    //    isdigit = true; digit = "12N";
-    //    isanalog = true; analog = "456";
-
-    ReturnRawValue = "";
-
-    if (isdigit)
-        ReturnRawValue = digit;
-    if (isdigit && isanalog)
-        ReturnRawValue = ReturnRawValue + ".";
-    if (isanalog)
-        ReturnRawValue = ReturnRawValue + analog; 
-
-
-    if (!isdigit)
+    for (int j = 0; j < NUMBERS.size(); ++j)
     {
-        AnzahlAnalog = 0;
-    }
+        NUMBERS[j]->ReturnRawValue = "";
+        NUMBERS[j]->ErrorMessageText = "";
 
-    ReturnRawValue = ShiftDecimal(ReturnRawValue, DecimalShift);   
+        if (NUMBERS[j]->digit_roi)
+            NUMBERS[j]->ReturnRawValue = flowDigit->getReadout(j);
+        if (NUMBERS[j]->digit_roi && NUMBERS[j]->analog_roi)
+            NUMBERS[j]->ReturnRawValue = NUMBERS[j]->ReturnRawValue + ".";
+        if (NUMBERS[j]->analog_roi)
+            NUMBERS[j]->ReturnRawValue = NUMBERS[j]->ReturnRawValue + flowAnalog->getReadout(j); 
 
-    rohwert = ReturnRawValue;
+        NUMBERS[j]->ReturnRawValue = ShiftDecimal(NUMBERS[j]->ReturnRawValue, NUMBERS[j]->DecimalShift);   
 
-    if (!PreValueUse || !PreValueOkay)
-    {
-        ReturnValue = ReturnRawValue;
-        ReturnValueNoError = ReturnRawValue;
+        rohwert = NUMBERS[j]->ReturnRawValue;
 
-        if ((findDelimiterPos(ReturnValue, "N") == std::string::npos) && (ReturnValue.length() > 0))
+        if (!PreValueUse || !NUMBERS[j]->PreValueOkay)
         {
-            while ((ReturnValue.length() > 1) && (ReturnValue[0] == '0'))
-            {
-                ReturnValue.erase(0, 1);
-            }
-            Value = std::stof(ReturnValue);
-            ReturnValueNoError = ReturnValue;
+            NUMBERS[j]->ReturnValue = NUMBERS[j]->ReturnRawValue;
+            NUMBERS[j]->ReturnValueNoError = NUMBERS[j]->ReturnRawValue;
 
-            PreValueOkay = true;
-            PreValue = Value;
-            if (flowMakeImage) 
-            {
-                lastvalue = flowMakeImage->getTimeImageTaken();
-                zwtime = ConvertTimeToString(lastvalue, PREVALUE_TIME_FORMAT_OUTPUT);
-            }
-            else
+            if ((findDelimiterPos(NUMBERS[j]->ReturnValue, "N") == std::string::npos) && (NUMBERS[j]->ReturnValue.length() > 0))
             {
-                time(&lastvalue);
-                localtime(&lastvalue);
+                while ((NUMBERS[j]->ReturnValue.length() > 1) && (NUMBERS[j]->ReturnValue[0] == '0'))
+                {
+                    NUMBERS[j]->ReturnValue.erase(0, 1);
+                }
+                NUMBERS[j]->Value = std::stof(NUMBERS[j]->ReturnValue);
+                NUMBERS[j]->ReturnValueNoError = NUMBERS[j]->ReturnValue;
+
+                NUMBERS[j]->PreValueOkay = true;
+                NUMBERS[j]->PreValue = NUMBERS[j]->Value;
+                NUMBERS[j]->ReturnPreValue = RundeOutput(NUMBERS[j]->PreValue, NUMBERS[j]->Nachkomma);
+                NUMBERS[j]->lastvalue = flowMakeImage->getTimeImageTaken();
+                zwtime = ConvertTimeToString(NUMBERS[j]->lastvalue, PREVALUE_TIME_FORMAT_OUTPUT);
+
+                UpdatePreValueINI = true;
+                SavePreValue();
             }
-
-            SavePreValue(Value, zwtime);
         }
-        return true;
-    }
+        else
+        {
+            zw = ErsetzteN(NUMBERS[j]->ReturnRawValue, NUMBERS[j]->PreValue); 
 
+            NUMBERS[j]->Value = std::stof(zw);
+            if (NUMBERS[j]->checkDigitIncreaseConsistency)
+            {
+                NUMBERS[j]->Value = checkDigitConsistency(NUMBERS[j]->Value, NUMBERS[j]->DecimalShift, NUMBERS[j]->analog_roi != NULL, NUMBERS[j]->PreValue);
+            }
 
-    zw = ErsetzteN(ReturnRawValue); 
+            zwvalue = RundeOutput(NUMBERS[j]->Value, NUMBERS[j]->AnzahlAnalog - NUMBERS[j]->DecimalShift);
 
-    Value = std::stof(zw);
-    if (checkDigitIncreaseConsistency)
-    {
-        Value = checkDigitConsistency(Value, DecimalShift, isanalog);
-    }
-
-    zwvalue = RundeOutput(Value, AnzahlAnalog - DecimalShift);
+            if ((!NUMBERS[j]->AllowNegativeRates) && (NUMBERS[j]->Value < NUMBERS[j]->PreValue))
+            {
+                NUMBERS[j]->ErrorMessageText = NUMBERS[j]->ErrorMessageText + "Neg. Rate - Read: " + zwvalue + " - Raw: " + NUMBERS[j]->ReturnRawValue + " - Pre: " + std::to_string(NUMBERS[j]->Value) + " "; 
+                NUMBERS[j]->Value = NUMBERS[j]->PreValue;
+                zwvalue = RundeOutput(NUMBERS[j]->Value, NUMBERS[j]->AnzahlAnalog - NUMBERS[j]->DecimalShift);
+            }
 
-    if ((!AllowNegativeRates) && (Value < PreValue))
-    {
-        ErrorMessageText = ErrorMessageText + "Negative Rate - Returned old value - read value: " + zwvalue + " - raw value: " + ReturnRawValue + " - checked value: " + std::to_string(Value) + " "; 
-        Value = PreValue;
-        zwvalue = RundeOutput(Value, AnzahlAnalog - DecimalShift);
-    }
+            if (NUMBERS[j]->useMaxRateValue && (abs(NUMBERS[j]->Value - NUMBERS[j]->PreValue) > NUMBERS[j]->MaxRateValue))
+            {
+                NUMBERS[j]->ErrorMessageText = NUMBERS[j]->ErrorMessageText + "Rate too high - Read: " + RundeOutput(NUMBERS[j]->Value, NUMBERS[j]->Nachkomma) + " - Pre: " + RundeOutput(NUMBERS[j]->PreValue, NUMBERS[j]->Nachkomma) + " ";
+                NUMBERS[j]->Value = NUMBERS[j]->PreValue;
+                zwvalue = RundeOutput(NUMBERS[j]->Value, NUMBERS[j]->Nachkomma);
+            }
 
-    if (useMaxRateValue && (abs(Value - PreValue) > MaxRateValue))
-    {
-        ErrorMessageText = ErrorMessageText + "Rate too high - Returned old value - read value: " + zwvalue + " - checked value: " + RundeOutput(Value, AnzahlAnalog - DecimalShift) + " ";
-        Value = PreValue;
-        zwvalue = RundeOutput(Value, AnzahlAnalog - DecimalShift);
-    }
+            NUMBERS[j]->ReturnValueNoError = zwvalue;
+            NUMBERS[j]->ReturnValue = zwvalue;
+            if (NUMBERS[j]->ErrorMessage && (NUMBERS[j]->ErrorMessageText.length() > 0))
+                NUMBERS[j]->ReturnValue = NUMBERS[j]->ReturnValue + "\t" + NUMBERS[j]->ErrorMessageText;
 
 
-    ReturnValueNoError = zwvalue;
-    ReturnValue = zwvalue;
-    if (ErrorMessage && (ErrorMessageText.length() > 0))
-        ReturnValue = ReturnValue + "\t" + ErrorMessageText;
+            double difference = difftime(imagetime, NUMBERS[j]->lastvalue);      // in Sekunden
+            difference /= 60;                                          // in Minuten
+            NUMBERS[j]->FlowRateAct = (NUMBERS[j]->Value - NUMBERS[j]->PreValue) / difference;
+            NUMBERS[j]->lastvalue = imagetime;
 
-    time_t currenttime;
-    if (flowMakeImage) 
-    {
-        currenttime = flowMakeImage->getTimeImageTaken();
-        zwtime = ConvertTimeToString(currenttime, PREVALUE_TIME_FORMAT_OUTPUT);
-    }
-    else
-    {
-        time(&currenttime);
-        localtime(&currenttime);
+            if (NUMBERS[j]->ErrorMessageText.length() == 0)
+            {
+                NUMBERS[j]->PreValue = NUMBERS[j]->Value;
+                NUMBERS[j]->ReturnPreValue = RundeOutput(NUMBERS[j]->PreValue, NUMBERS[j]->Nachkomma);
+                NUMBERS[j]->ErrorMessageText = "no error";
+                UpdatePreValueINI = true;
+            }
+        }
     }
 
-    double difference = difftime(currenttime, lastvalue);      // in Sekunden
-    difference /= 60;                                          // in Minuten
-    FlowRateAct = (Value - PreValue) / difference;
-    lastvalue = currenttime;
-//    std::string _zw = "CalcRate: " + std::to_string(FlowRateAct) + " TimeDifference[min]: " +  std::to_string(difference);
-//    _zw = _zw  + " Value: " +  std::to_string(Value) + " PreValue: " +  std::to_string(PreValue);
-//    LogFile.WriteToFile(_zw);
-
-    if (ErrorMessageText.length() == 0)
-    {
-        PreValue = Value;
-        ErrorMessageText = "no error";
-        SavePreValue(Value, zwtime);
-    }
+    SavePreValue();
     return true;
 }
 
-string ClassFlowPostProcessing::getReadout()
+string ClassFlowPostProcessing::getReadout(int _number)
 {
-    return ReturnValue;
+    return NUMBERS[_number]->ReturnValue;
 }
 
-string ClassFlowPostProcessing::getReadoutParam(bool _rawValue, bool _noerror)
+string ClassFlowPostProcessing::getReadoutParam(bool _rawValue, bool _noerror, int _number)
 {
     if (_rawValue)
-        return ReturnRawValue;
+        return NUMBERS[_number]->ReturnRawValue;
     if (_noerror)
-        return ReturnValueNoError;
-    return ReturnValue;
+        return NUMBERS[_number]->ReturnValueNoError;
+    return NUMBERS[_number]->ReturnValue;
 }
 
 string ClassFlowPostProcessing::RundeOutput(float _in, int _anzNachkomma){
@@ -478,7 +646,7 @@ string ClassFlowPostProcessing::RundeOutput(float _in, int _anzNachkomma){
 }
 
 
-string ClassFlowPostProcessing::ErsetzteN(string input)
+string ClassFlowPostProcessing::ErsetzteN(string input, float _prevalue)
 {
     int posN, posPunkt;
     int pot, ziffer;
@@ -499,7 +667,7 @@ string ClassFlowPostProcessing::ErsetzteN(string input)
             pot = posPunkt - posN;
         }
 
-        zw = PreValue / pow(10, pot);
+        zw =_prevalue / pow(10, pot);
         ziffer = ((int) zw) % 10;
         input[posN] = ziffer + 48;
 
@@ -509,7 +677,7 @@ string ClassFlowPostProcessing::ErsetzteN(string input)
     return input;
 }
 
-float ClassFlowPostProcessing::checkDigitConsistency(float input, int _decilamshift, bool _isanalog){
+float ClassFlowPostProcessing::checkDigitConsistency(float input, int _decilamshift, bool _isanalog, float _preValue){
     int aktdigit, olddigit;
     int aktdigit_before, olddigit_before;
     int pot, pot_max;
@@ -527,12 +695,12 @@ float ClassFlowPostProcessing::checkDigitConsistency(float input, int _decilamsh
     {
         zw = input / pow(10, pot-1);
         aktdigit_before = ((int) zw) % 10;
-        zw = PreValue / pow(10, pot-1);
+        zw = _preValue / pow(10, pot-1);
         olddigit_before = ((int) zw) % 10;
 
         zw = input / pow(10, pot);
         aktdigit = ((int) zw) % 10;
-        zw = PreValue / pow(10, pot);
+        zw = _preValue / pow(10, pot);
         olddigit = ((int) zw) % 10;
 
         no_nulldurchgang = (olddigit_before <= aktdigit_before);
@@ -558,18 +726,18 @@ float ClassFlowPostProcessing::checkDigitConsistency(float input, int _decilamsh
     return input;
 }
 
-string ClassFlowPostProcessing::getReadoutRate()
+string ClassFlowPostProcessing::getReadoutRate(int _number)
 {
-    return std::to_string(FlowRateAct);
+    return std::to_string(NUMBERS[_number]->FlowRateAct);
 }
 
-string ClassFlowPostProcessing::getReadoutTimeStamp()
+string ClassFlowPostProcessing::getReadoutTimeStamp(int _number)
 {
-   return timeStamp; 
+   return NUMBERS[_number]->timeStamp; 
 }
 
 
-string ClassFlowPostProcessing::getReadoutError() 
+string ClassFlowPostProcessing::getReadoutError(int _number) 
 {
-    return ErrorMessageText;
+    return NUMBERS[_number]->ErrorMessageText;
 }

+ 60 - 24
code/components/jomjol_flowcontroll/ClassFlowPostProcessing.h

@@ -1,58 +1,94 @@
 #pragma once
 #include "ClassFlow.h"
 #include "ClassFlowMakeImage.h"
-
-#include <string>
+#include "ClassFlowAnalog.h"
+#include "ClassFlowDigit.h"
 
 
+#include <string>
 
 
-class ClassFlowPostProcessing :
-    public ClassFlow
-{
-protected:
-    bool PreValueUse;
-    int PreValueAgeStartup; 
-    bool AllowNegativeRates;
+struct NumberPost {
+//    int PreValueAgeStartup; 
     float MaxRateValue;
     bool useMaxRateValue;
     bool ErrorMessage;
     bool PreValueOkay;
+    bool AllowNegativeRates;
     bool checkDigitIncreaseConsistency;
-    int DecimalShift;
     time_t lastvalue;
+    string timeStamp;
     float FlowRateAct;          // m3 / min
-
-
-    string FilePreValue;
     float PreValue;             // letzter Wert, der gut ausgelesen wurde
     float Value;                // letzer ausgelesener Wert, inkl. Korrekturen
     string ReturnRawValue;      // Rohwert (mit N & führenden 0)    
     string ReturnValue;         // korrigierter Rückgabewert, ggf. mit Fehlermeldung
-    string ReturnValueNoError;  // korrigierter Rückgabewert ohne Fehlermeldung
+    string ReturnPreValue;  // korrigierter Rückgabewert ohne Fehlermeldung
+    string ReturnValueNoError;
     string ErrorMessageText;        // Fehlermeldung bei Consistency Check
-    string timeStamp;
+    int AnzahlAnalog;
+    int AnzahlDigital;
+    int DecimalShift;
+    int Nachkomma;
+//    ClassFlowAnalog* ANALOG;
+//    ClassFlowDigit* DIGIT;
+
+    digit *digit_roi;
+    analog *analog_roi;
+
+
+
+    string name;
+};
+
+
+
+
+class ClassFlowPostProcessing :
+    public ClassFlow
+{
+protected:
+    std::vector<NumberPost*> NUMBERS;
+    bool UpdatePreValueINI;
+
+    bool PreValueUse;
+    int PreValueAgeStartup; 
+    bool ErrorMessage;
+
+
+    ClassFlowAnalog* flowAnalog;
+    ClassFlowDigit* flowDigit;    
+
+
+    string FilePreValue;
 
     ClassFlowMakeImage *flowMakeImage;
 
     bool LoadPreValue(void);
     string ShiftDecimal(string in, int _decShift);
 
-    string ErsetzteN(string);
-    float checkDigitConsistency(float input, int _decilamshift, bool _isanalog);
+    string ErsetzteN(string, float _prevalue);
+    float checkDigitConsistency(float input, int _decilamshift, bool _isanalog, float _preValue);
     string RundeOutput(float _in, int _anzNachkomma);
 
+    void InitNUMBERS();
+    void handleDecimalSeparator(string _decsep, string _value);
+    void handleMaxRateValue(string _decsep, string _value);
+
+
 public:
     ClassFlowPostProcessing(std::vector<ClassFlow*>* lfc);
     bool ReadParameter(FILE* pfile, string& aktparamgraph);
     bool doFlow(string time);
-    string getReadout();
-    string getReadoutParam(bool _rawValue, bool _noerror);
-    string getReadoutError();
-    string getReadoutRate();
-    string getReadoutTimeStamp();
-    void SavePreValue(float value, string time = "");
-    string GetPreValue();
+    string getReadout(int _number);
+    string getReadoutParam(bool _rawValue, bool _noerror, int _number = 0);
+    string getReadoutError(int _number = 0);
+    string getReadoutRate(int _number = 0);
+    string getReadoutTimeStamp(int _number = 0);
+    void SavePreValue();
+    string GetPreValue(std::string _number = "");
+    void SetPreValue(float zw, string _numbers);
+    std::vector<NumberPost*> GetNumbers(){return NUMBERS;};
 
     string name(){return "ClassFlowPostProcessing";};
 };

+ 28 - 0
code/components/jomjol_helper/Helper.cpp

@@ -10,6 +10,7 @@
 #include <string.h>
 #include <esp_log.h>
 
+
 #include "ClassLogFile.h"
 //#include "ClassLogFile.h"
 
@@ -358,3 +359,30 @@ int removeFolder(const char* folderPath, const char* logTag) {
 
 	return deleted;
 }
+
+
+
+std::vector<string> HelperZerlegeZeile(std::string input, std::string _delimiter = "")
+{
+	std::vector<string> Output;
+	std::string delimiter = " =,";
+    if (_delimiter.length() > 0){
+        delimiter = _delimiter;
+    }
+
+	input = trim(input, delimiter);
+	size_t pos = findDelimiterPos(input, delimiter);
+	std::string token;
+	while (pos != std::string::npos) {
+		token = input.substr(0, pos);
+		token = trim(token, delimiter);
+		Output.push_back(token);
+		input.erase(0, pos + 1);
+		input = trim(input, delimiter);
+		pos = findDelimiterPos(input, delimiter);
+	}
+	Output.push_back(input);
+
+	return Output;
+}
+

+ 3 - 0
code/components/jomjol_helper/Helper.h

@@ -1,6 +1,7 @@
 #pragma once
 #include <string>
 #include <fstream>
+#include <vector>
 
 
 using namespace std;
@@ -30,6 +31,8 @@ time_t addDays(time_t startTime, int days);
 
 void memCopyGen(uint8_t* _source, uint8_t* _target, int _size);
 
+std::vector<string> HelperZerlegeZeile(std::string input, std::string _delimiter);
+
 ///////////////////////////
 size_t getInternalESPHeapSize();
 size_t getESPHeapSize();

+ 54 - 3
code/components/jomjol_tfliteclass/server_tflite.cpp

@@ -18,7 +18,7 @@
 
 #include "ClassLogFile.h"
 
-//#define DEBUG_DETAIL_ON       
+// #define DEBUG_DETAIL_ON       
 
 
 ClassFlowControll tfliteflow;
@@ -196,6 +196,8 @@ esp_err_t handler_wasserzaehler(httpd_req_t *req)
 
     bool _rawValue = false;
     bool _noerror = false;
+    bool _all = false;
+    std::string _type = "value";
     string zw;
 
     printf("handler_wasserzaehler uri:\n"); printf(req->uri); printf("\n");
@@ -206,6 +208,22 @@ esp_err_t handler_wasserzaehler(httpd_req_t *req)
     if (httpd_req_get_url_query_str(req, _query, 100) == ESP_OK)
     {
 //        printf("Query: "); printf(_query); printf("\n");
+        if (httpd_query_key_value(_query, "all", _size, 10) == ESP_OK)
+        {
+#ifdef DEBUG_DETAIL_ON       
+            printf("all is found"); printf(_size); printf("\n"); 
+#endif
+            _all = true;
+        }
+
+        if (httpd_query_key_value(_query, "type", _size, 10) == ESP_OK)
+        {
+#ifdef DEBUG_DETAIL_ON       
+            printf("all is found"); printf(_size); printf("\n"); 
+#endif
+            _type = std::string(_size);
+        }
+
         if (httpd_query_key_value(_query, "rawvalue", _size, 10) == ESP_OK)
         {
 #ifdef DEBUG_DETAIL_ON       
@@ -222,6 +240,29 @@ esp_err_t handler_wasserzaehler(httpd_req_t *req)
         }        
     }  
 
+    httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
+
+    if (_all)
+    {
+        httpd_resp_set_type(req, "text/plain");
+        printf("TYPE: %s\n", _type.c_str());
+        int _intype = READOUT_TYPE_VALUE;
+        if (_type == "prevalue")
+            _intype = READOUT_TYPE_PREVALUE;
+        if (_type == "raw")
+            _intype = READOUT_TYPE_RAWVALUE;
+        if (_type == "error")
+            _intype = READOUT_TYPE_ERROR;
+
+
+        zw = tfliteflow.getReadoutAll(_intype);
+        printf("ZW: %s\n", zw.c_str());
+        if (zw.length() > 0)
+            httpd_resp_sendstr_chunk(req, zw.c_str()); 
+        httpd_resp_sendstr_chunk(req, NULL);   
+        return ESP_OK;
+    }
+
     zw = tfliteflow.getReadout(_rawValue, _noerror);
     if (zw.length() > 0)
         httpd_resp_sendstr_chunk(req, zw.c_str()); 
@@ -498,6 +539,7 @@ esp_err_t handler_prevalue(httpd_req_t *req)
 
     char _query[100];
     char _size[10] = "";
+    char _numbers[50] = "default";
 
     if (httpd_req_get_url_query_str(req, _query, 100) == ESP_OK)
     {
@@ -511,15 +553,24 @@ esp_err_t handler_prevalue(httpd_req_t *req)
             printf("Value: "); printf(_size); printf("\n"); 
 #endif
         }
+
+        httpd_query_key_value(_query, "numbers", _numbers, 50);
     }      
 
     if (strlen(_size) == 0)
-        zw = tfliteflow.GetPrevalue();
+    {
+        zw = tfliteflow.GetPrevalue(std::string(_numbers));
+    }
     else
-        zw = "SetPrevalue to " + tfliteflow.UpdatePrevalue(_size);
+    {
+        zw = "SetPrevalue to " + tfliteflow.UpdatePrevalue(_size, _numbers);
+    }
     
     resp_str = zw.c_str();
 
+    httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
+
+
     httpd_resp_send(req, resp_str, strlen(resp_str));   
     /* Respond with an empty chunk to signal HTTP response completion */
     httpd_resp_send_chunk(req, NULL, 0);      

+ 1 - 1
code/components/jomjol_wlan/read_wlanini.cpp

@@ -135,7 +135,7 @@ void LoadWlanFromFile(std::string fn, char *&_ssid, char *&_password, char *&_ho
     fclose(pFile);
 
     // Check if Hostname was empty in .ini if yes set to std_hostname
-    if(hostname.length() >= 0){
+    if(hostname.length() == 0){
         hostname = std_hostname;
     }
 

+ 2 - 2
code/main/server_main.cpp

@@ -234,7 +234,7 @@ esp_err_t img_tmp_handler(httpd_req_t *req)
     filetosend = filetosend + "/img_tmp/" + std::string(filename);
     printf("File to upload: %s\n", filetosend.c_str());    
 
-    esp_err_t res = send_file(req, filetosend);
+    esp_err_t res = send_file(req, filetosend); 
     if (res != ESP_OK)
         return res;
 
@@ -387,7 +387,7 @@ httpd_handle_t start_webserver(void)
     httpd_config_t config = { };
 
     config.task_priority      = tskIDLE_PRIORITY+5;
-    config.stack_size         = 32384;                  // bei 32k stürzt das Programm beim Bilderaufnehmen ab
+    config.stack_size         = 32768;                  // bei 32k stürzt das Programm beim Bilderaufnehmen ab
     config.core_id            = tskNO_AFFINITY;
     config.server_port        = 80;
     config.ctrl_port          = 32768;

+ 4 - 4
code/main/version.cpp

@@ -1,4 +1,4 @@
-const char* GIT_REV="6cefc44";
-const char* GIT_TAG="v7.1.0";
-const char* GIT_BRANCH="master";
-const char* BUILD_TIME="2021-05-30 21:47";
+const char* GIT_REV="894c7f6";
+const char* GIT_TAG="";
+const char* GIT_BRANCH="rolling";
+const char* BUILD_TIME="2021-07-04 10:15";

+ 2 - 0
code/platformio.ini

@@ -37,5 +37,7 @@ lib_deps =
   jomjol_controlGPIO
 
 monitor_speed = 115200
+monitor_rts = 0
+monitor_dtr = 0
 
 debug_tool = esp-prog

+ 174 - 5
code/sdkconfig.old

@@ -131,8 +131,8 @@ CONFIG_EXAMPLE_CONNECT_IPV6=y
 #
 # Compiler options
 #
-CONFIG_COMPILER_OPTIMIZATION_DEFAULT=y
-# CONFIG_COMPILER_OPTIMIZATION_SIZE is not set
+# CONFIG_COMPILER_OPTIMIZATION_DEFAULT is not set
+CONFIG_COMPILER_OPTIMIZATION_SIZE=y
 # CONFIG_COMPILER_OPTIMIZATION_PERF is not set
 # CONFIG_COMPILER_OPTIMIZATION_NONE is not set
 CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_ENABLE=y
@@ -165,6 +165,8 @@ CONFIG_APPTRACE_LOCK_ENABLE=y
 #
 # CONFIG_BT_ENABLED is not set
 CONFIG_BTDM_CTRL_BR_EDR_SCO_DATA_PATH_EFF=0
+CONFIG_BTDM_CTRL_PCM_ROLE_EFF=0
+CONFIG_BTDM_CTRL_PCM_POLAR_EFF=0
 CONFIG_BTDM_CTRL_BLE_MAX_CONN_EFF=0
 CONFIG_BTDM_CTRL_BR_EDR_MAX_ACL_CONN_EFF=0
 CONFIG_BTDM_CTRL_BR_EDR_MAX_SYNC_CONN_EFF=0
@@ -204,6 +206,12 @@ CONFIG_SPI_MASTER_ISR_IN_IRAM=y
 CONFIG_SPI_SLAVE_ISR_IN_IRAM=y
 # end of SPI configuration
 
+#
+# CAN configuration
+#
+# CONFIG_CAN_ISR_IN_IRAM is not set
+# end of CAN configuration
+
 #
 # UART configuration
 #
@@ -239,6 +247,7 @@ CONFIG_ESP_TLS_USING_MBEDTLS=y
 #
 # ESP32-specific
 #
+CONFIG_ESP32_ECO3_CACHE_LOCK_FIX=y
 CONFIG_ESP32_REV_MIN_0=y
 # CONFIG_ESP32_REV_MIN_1 is not set
 # CONFIG_ESP32_REV_MIN_2 is not set
@@ -598,7 +607,6 @@ CONFIG_FREERTOS_QUEUE_REGISTRY_SIZE=0
 # CONFIG_FREERTOS_USE_TRACE_FACILITY is not set
 # CONFIG_FREERTOS_GENERATE_RUN_TIME_STATS is not set
 # CONFIG_FREERTOS_DEBUG_INTERNALS is not set
-CONFIG_FREERTOS_TASK_FUNCTION_WRAPPER=y
 CONFIG_FREERTOS_CHECK_MUTEX_GIVEN_BY_OWNER=y
 # CONFIG_FREERTOS_CHECK_PORT_CRITICAL_COMPLIANCE is not set
 CONFIG_FREERTOS_DEBUG_OCDAWARE=y
@@ -657,8 +665,10 @@ CONFIG_LWIP_SO_REUSE=y
 CONFIG_LWIP_SO_REUSE_RXTOALL=y
 # CONFIG_LWIP_SO_RCVBUF is not set
 # CONFIG_LWIP_NETBUF_RECVINFO is not set
-CONFIG_LWIP_IP_FRAG=y
-# CONFIG_LWIP_IP_REASSEMBLY is not set
+CONFIG_LWIP_IP4_FRAG=y
+CONFIG_LWIP_IP6_FRAG=y
+# CONFIG_LWIP_IP4_REASSEMBLY is not set
+# CONFIG_LWIP_IP6_REASSEMBLY is not set
 # CONFIG_LWIP_STATS is not set
 # CONFIG_LWIP_ETHARP_TRUST_IP_MAC is not set
 CONFIG_LWIP_ESP_GRATUITOUS_ARP=y
@@ -682,8 +692,10 @@ CONFIG_LWIP_LOOPBACK_MAX_PBUFS=8
 #
 # TCP
 #
+CONFIG_LWIP_TCP_ISN_HOOK=y
 CONFIG_LWIP_MAX_ACTIVE_TCP=16
 CONFIG_LWIP_MAX_LISTENING_TCP=16
+CONFIG_LWIP_TCP_HIGH_SPEED_RETRANSMISSION=y
 CONFIG_LWIP_TCP_MAXRTX=12
 CONFIG_LWIP_TCP_SYNMAXRTX=6
 CONFIG_LWIP_TCP_MSS=1440
@@ -698,6 +710,7 @@ CONFIG_LWIP_TCP_QUEUE_OOSEQ=y
 CONFIG_LWIP_TCP_OVERSIZE_MSS=y
 # CONFIG_LWIP_TCP_OVERSIZE_QUARTER_MSS is not set
 # CONFIG_LWIP_TCP_OVERSIZE_DISABLE is not set
+CONFIG_LWIP_TCP_RTO_TIME=1500
 # end of TCP
 
 #
@@ -713,6 +726,8 @@ CONFIG_LWIP_TCPIP_TASK_AFFINITY_NO_AFFINITY=y
 # CONFIG_LWIP_TCPIP_TASK_AFFINITY_CPU1 is not set
 CONFIG_LWIP_TCPIP_TASK_AFFINITY=0x7FFFFFFF
 # CONFIG_LWIP_PPP_SUPPORT is not set
+CONFIG_LWIP_IPV6_MEMP_NUM_ND6_QUEUE=3
+CONFIG_LWIP_IPV6_ND6_NUM_NEIGHBORS=5
 
 #
 # ICMP
@@ -906,6 +921,7 @@ CONFIG_SPI_FLASH_DANGEROUS_WRITE_ABORTS=y
 CONFIG_SPI_FLASH_YIELD_DURING_ERASE=y
 CONFIG_SPI_FLASH_ERASE_YIELD_DURATION_MS=20
 CONFIG_SPI_FLASH_ERASE_YIELD_TICKS=1
+# CONFIG_SPI_FLASH_SIZE_OVERRIDE is not set
 
 #
 # Auto-detect flash chips
@@ -913,6 +929,8 @@ CONFIG_SPI_FLASH_ERASE_YIELD_TICKS=1
 CONFIG_SPI_FLASH_SUPPORT_ISSI_CHIP=y
 CONFIG_SPI_FLASH_SUPPORT_GD_CHIP=y
 # end of Auto-detect flash chips
+
+CONFIG_SPI_FLASH_ENABLE_ENCRYPTED_READ_WRITE=y
 # end of SPI Flash driver
 
 #
@@ -996,6 +1014,8 @@ CONFIG_WIFI_PROV_AUTOSTOP_TIMEOUT=30
 #
 CONFIG_WPA_MBEDTLS_CRYPTO=y
 # CONFIG_WPA_TLS_V12 is not set
+# CONFIG_WPA_WPS_WARS is not set
+# CONFIG_WPA_DEBUG_PRINT is not set
 # end of Supplicant
 
 #
@@ -1020,3 +1040,152 @@ CONFIG_CAMERA_CORE0=y
 #
 # CONFIG_LEGACY_INCLUDE_COMMON_HEADERS is not set
 # end of Compatibility options
+
+# Deprecated options for backward compatibility
+CONFIG_TOOLPREFIX="xtensa-esp32-elf-"
+# CONFIG_LOG_BOOTLOADER_LEVEL_NONE is not set
+# CONFIG_LOG_BOOTLOADER_LEVEL_ERROR is not set
+# CONFIG_LOG_BOOTLOADER_LEVEL_WARN is not set
+CONFIG_LOG_BOOTLOADER_LEVEL_INFO=y
+# CONFIG_LOG_BOOTLOADER_LEVEL_DEBUG is not set
+# CONFIG_LOG_BOOTLOADER_LEVEL_VERBOSE is not set
+CONFIG_LOG_BOOTLOADER_LEVEL=3
+# CONFIG_APP_ROLLBACK_ENABLE is not set
+# CONFIG_FLASH_ENCRYPTION_ENABLED is not set
+# CONFIG_FLASHMODE_QIO is not set
+# CONFIG_FLASHMODE_QOUT is not set
+CONFIG_FLASHMODE_DIO=y
+# CONFIG_FLASHMODE_DOUT is not set
+# CONFIG_MONITOR_BAUD_9600B is not set
+# CONFIG_MONITOR_BAUD_57600B is not set
+CONFIG_MONITOR_BAUD_115200B=y
+# CONFIG_MONITOR_BAUD_230400B is not set
+# CONFIG_MONITOR_BAUD_921600B is not set
+# CONFIG_MONITOR_BAUD_2MB is not set
+# CONFIG_MONITOR_BAUD_OTHER is not set
+CONFIG_MONITOR_BAUD_OTHER_VAL=115200
+CONFIG_MONITOR_BAUD=115200
+# CONFIG_COMPILER_OPTIMIZATION_LEVEL_DEBUG is not set
+CONFIG_COMPILER_OPTIMIZATION_LEVEL_RELEASE=y
+CONFIG_OPTIMIZATION_ASSERTIONS_ENABLED=y
+# CONFIG_OPTIMIZATION_ASSERTIONS_SILENT is not set
+# CONFIG_OPTIMIZATION_ASSERTIONS_DISABLED is not set
+# CONFIG_CXX_EXCEPTIONS is not set
+CONFIG_STACK_CHECK_NONE=y
+# CONFIG_STACK_CHECK_NORM is not set
+# CONFIG_STACK_CHECK_STRONG is not set
+# CONFIG_STACK_CHECK_ALL is not set
+# CONFIG_WARN_WRITE_STRINGS is not set
+# CONFIG_DISABLE_GCC8_WARNINGS is not set
+# CONFIG_ESP32_APPTRACE_DEST_TRAX is not set
+CONFIG_ESP32_APPTRACE_DEST_NONE=y
+CONFIG_ESP32_APPTRACE_LOCK_ENABLE=y
+CONFIG_BTDM_CONTROLLER_BLE_MAX_CONN_EFF=0
+CONFIG_BTDM_CONTROLLER_BR_EDR_MAX_ACL_CONN_EFF=0
+CONFIG_BTDM_CONTROLLER_BR_EDR_MAX_SYNC_CONN_EFF=0
+CONFIG_BTDM_CONTROLLER_PINNED_TO_CORE=0
+CONFIG_ADC2_DISABLE_DAC=y
+CONFIG_SPIRAM_SUPPORT=y
+# CONFIG_WIFI_LWIP_ALLOCATION_FROM_SPIRAM_FIRST is not set
+CONFIG_TRACEMEM_RESERVE_DRAM=0x0
+# CONFIG_TWO_UNIVERSAL_MAC_ADDRESS is not set
+CONFIG_FOUR_UNIVERSAL_MAC_ADDRESS=y
+CONFIG_NUMBER_OF_UNIVERSAL_MAC_ADDRESS=4
+# CONFIG_ULP_COPROC_ENABLED is not set
+CONFIG_ULP_COPROC_RESERVE_MEM=0
+CONFIG_BROWNOUT_DET=y
+CONFIG_BROWNOUT_DET_LVL_SEL_0=y
+# CONFIG_BROWNOUT_DET_LVL_SEL_1 is not set
+# CONFIG_BROWNOUT_DET_LVL_SEL_2 is not set
+# CONFIG_BROWNOUT_DET_LVL_SEL_3 is not set
+# CONFIG_BROWNOUT_DET_LVL_SEL_4 is not set
+# CONFIG_BROWNOUT_DET_LVL_SEL_5 is not set
+# CONFIG_BROWNOUT_DET_LVL_SEL_6 is not set
+# CONFIG_BROWNOUT_DET_LVL_SEL_7 is not set
+CONFIG_BROWNOUT_DET_LVL=0
+CONFIG_REDUCE_PHY_TX_POWER=y
+CONFIG_ESP32_RTC_CLOCK_SOURCE_INTERNAL_RC=y
+# CONFIG_ESP32_RTC_CLOCK_SOURCE_EXTERNAL_CRYSTAL is not set
+# CONFIG_ESP32_RTC_CLOCK_SOURCE_EXTERNAL_OSC is not set
+# CONFIG_ESP32_RTC_CLOCK_SOURCE_INTERNAL_8MD256 is not set
+# CONFIG_DISABLE_BASIC_ROM_CONSOLE is not set
+# CONFIG_NO_BLOBS is not set
+# CONFIG_COMPATIBLE_PRE_V2_1_BOOTLOADERS is not set
+CONFIG_SYSTEM_EVENT_QUEUE_SIZE=32
+CONFIG_SYSTEM_EVENT_TASK_STACK_SIZE=2304
+CONFIG_MAIN_TASK_STACK_SIZE=3584
+CONFIG_IPC_TASK_STACK_SIZE=1024
+CONFIG_TIMER_TASK_STACK_SIZE=3584
+CONFIG_CONSOLE_UART_DEFAULT=y
+# CONFIG_CONSOLE_UART_CUSTOM is not set
+# CONFIG_CONSOLE_UART_NONE is not set
+CONFIG_CONSOLE_UART_NUM=0
+CONFIG_CONSOLE_UART_BAUDRATE=115200
+CONFIG_INT_WDT=y
+CONFIG_INT_WDT_TIMEOUT_MS=300
+CONFIG_INT_WDT_CHECK_CPU1=y
+CONFIG_TASK_WDT=y
+# CONFIG_TASK_WDT_PANIC is not set
+CONFIG_TASK_WDT_TIMEOUT_S=3
+CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU0=y
+CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU1=y
+# CONFIG_EVENT_LOOP_PROFILING is not set
+CONFIG_POST_EVENTS_FROM_ISR=y
+CONFIG_POST_EVENTS_FROM_IRAM_ISR=y
+CONFIG_MB_MASTER_TIMEOUT_MS_RESPOND=150
+CONFIG_MB_MASTER_DELAY_MS_CONVERT=200
+CONFIG_MB_QUEUE_LENGTH=20
+CONFIG_MB_SERIAL_TASK_STACK_SIZE=2048
+CONFIG_MB_SERIAL_BUF_SIZE=256
+CONFIG_MB_SERIAL_TASK_PRIO=10
+# CONFIG_MB_CONTROLLER_SLAVE_ID_SUPPORT is not set
+CONFIG_MB_CONTROLLER_NOTIFY_TIMEOUT=20
+CONFIG_MB_CONTROLLER_NOTIFY_QUEUE_SIZE=20
+CONFIG_MB_CONTROLLER_STACK_SIZE=4096
+CONFIG_MB_EVENT_QUEUE_TIMEOUT=20
+CONFIG_MB_TIMER_PORT_ENABLED=y
+CONFIG_MB_TIMER_GROUP=0
+CONFIG_MB_TIMER_INDEX=0
+CONFIG_SUPPORT_STATIC_ALLOCATION=y
+# CONFIG_ENABLE_STATIC_TASK_CLEAN_UP_HOOK is not set
+CONFIG_TIMER_TASK_PRIORITY=1
+CONFIG_TIMER_TASK_STACK_DEPTH=2048
+CONFIG_TIMER_QUEUE_LENGTH=10
+# CONFIG_L2_TO_L3_COPY is not set
+# CONFIG_USE_ONLY_LWIP_SELECT is not set
+CONFIG_ESP_GRATUITOUS_ARP=y
+CONFIG_GARP_TMR_INTERVAL=60
+CONFIG_TCPIP_RECVMBOX_SIZE=32
+CONFIG_TCP_MAXRTX=12
+CONFIG_TCP_SYNMAXRTX=6
+CONFIG_TCP_MSS=1440
+CONFIG_TCP_MSL=60000
+CONFIG_TCP_SND_BUF_DEFAULT=5744
+CONFIG_TCP_WND_DEFAULT=5744
+CONFIG_TCP_RECVMBOX_SIZE=6
+CONFIG_TCP_QUEUE_OOSEQ=y
+# CONFIG_ESP_TCP_KEEP_CONNECTION_WHEN_IP_CHANGES is not set
+CONFIG_TCP_OVERSIZE_MSS=y
+# CONFIG_TCP_OVERSIZE_QUARTER_MSS is not set
+# CONFIG_TCP_OVERSIZE_DISABLE is not set
+CONFIG_UDP_RECVMBOX_SIZE=6
+CONFIG_TCPIP_TASK_STACK_SIZE=3072
+CONFIG_TCPIP_TASK_AFFINITY_NO_AFFINITY=y
+# CONFIG_TCPIP_TASK_AFFINITY_CPU0 is not set
+# CONFIG_TCPIP_TASK_AFFINITY_CPU1 is not set
+CONFIG_TCPIP_TASK_AFFINITY=0x7FFFFFFF
+# CONFIG_PPP_SUPPORT is not set
+CONFIG_ESP32_PTHREAD_TASK_PRIO_DEFAULT=5
+CONFIG_ESP32_PTHREAD_TASK_STACK_SIZE_DEFAULT=3072
+CONFIG_ESP32_PTHREAD_STACK_MIN=768
+CONFIG_ESP32_DEFAULT_PTHREAD_CORE_NO_AFFINITY=y
+# CONFIG_ESP32_DEFAULT_PTHREAD_CORE_0 is not set
+# CONFIG_ESP32_DEFAULT_PTHREAD_CORE_1 is not set
+CONFIG_ESP32_PTHREAD_TASK_CORE_DEFAULT=-1
+CONFIG_ESP32_PTHREAD_TASK_NAME_DEFAULT="pthread"
+CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_ABORTS=y
+# CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_FAILS is not set
+# CONFIG_SPI_FLASH_WRITING_DANGEROUS_REGIONS_ALLOWED is not set
+# CONFIG_SUPPRESS_SELECT_DEBUG_OUTPUT is not set
+CONFIG_SUPPORT_TERMIOS=y
+# End of deprecated options

+ 4 - 4
code/version.cpp

@@ -1,4 +1,4 @@
-const char* GIT_REV="6cefc44";
-const char* GIT_TAG="v7.1.0";
-const char* GIT_BRANCH="master";
-const char* BUILD_TIME="2021-05-30 21:47";
+const char* GIT_REV="894c7f6";
+const char* GIT_TAG="";
+const char* GIT_BRANCH="rolling";
+const char* BUILD_TIME="2021-07-04 10:15";

BIN
firmware/html.zip


BIN
images/numbers.jpg


BIN
images/powermeter.jpg


+ 29 - 31
sd-card/config/config.ini

@@ -1,57 +1,56 @@
 [MakeImage]
 ;LogImageLocation = /log/source
-;LogfileRetentionInDays = 15
 WaitBeforeTakingPicture = 5
+;LogfileRetentionInDays = 15
+Brightness = -2
+;Contrast = 0
+;Saturation = 0
 ImageQuality = 5
 ImageSize = VGA
-;Brightness = -2
 FixedExposure = false
 
 [Alignment]
-InitialRotate=180
-FlipImageSize = false
-/config/ref0.jpg 119 273
-/config/ref1.jpg 456 138
+InitialRotate = 179
+;InitialMirror = false
 SearchFieldX = 20
 SearchFieldY = 20
-InitialMirror= false
 AlignmentAlgo = Default
+;FlipImageSize = false
+/config/ref0.jpg 104 271
+/config/ref1.jpg 442 142
 
 [Digits]
-Model = /config/dig0870s3q.tflite
+Model = /config/dig1030s1q.tflite
 ;LogImageLocation = /log/digit
 ;LogfileRetentionInDays = 3
 ModelInputSize = 20 32
-digit1 306 120 37 67
-digit2 355 120 37 67
-digit3 404 120 37 67
+main.digit1 292 120 37 67
+main.digit2 340 120 37 67
+main.digit3 389 120 37 67
 
 [Analog]
-Model = /config/ana0700s1lq.tflite
+Model = /config/ana0630s2.tflite
 ;LogImageLocation = /log/analog
 ;LogfileRetentionInDays = 3
 ModelInputSize = 32 32
-analog1 444 225 92 92
-analog2 391 329 92 92
-analog3 294 369 92 92
-analog4 168 326 92 92
-ExtendedResolution = false
+ExtendedResolution = true
+main.analog1 430 230 92 92
+main.analog2 376 331 92 92
+main.analog3 279 372 92 92
+main.analog4 150 327 92 92
 
 [PostProcessing]
-DecimalShift = 0
+main.DecimalShift = 0
 PreValueUse = true
 PreValueAgeStartup = 720
 AllowNegativeRates = false
-MaxRateValue = 0.1
+main.MaxRateValue = 0.1
 ErrorMessage = true
-CheckDigitIncreaseConsistency = false
+CheckDigitIncreaseConsistency = true
 
-[MQTT]
+;[MQTT]
 ;Uri = mqtt://IP-ADRESS:1883
-;Topic = wasserzaehler/zaehlerstand
-;TopicError = wasserzaehler/error
-;TopicRate = wasserzaehler/rate
-;TopicTimeStamp = wasserzaehler/timestamp
+;MainTopic = wasserzaehler
 ;ClientID = wasser
 ;user = USERNAME
 ;password = PASSWORD
@@ -65,9 +64,8 @@ Logfile = false
 LogfileRetentionInDays = 3
 
 [System]
-TimeZone = CET-1CEST,M3.5.0,M10.5.0/3
-;TimeServer = fritz.box
-;hostname = watermeter
-SetupMode = true
-
-[Ende]
+TimeZone = CET-1CEST
+;TimeServer = undefined
+;AutoAdjustSummertime = false
+;Hostname = undefined
+SetupMode = true

BIN
sd-card/config/dig0870s3q.tflite


BIN
sd-card/config/dig1030s1q.tflite


+ 14 - 16
sd-card/html/edit_alignment.html

@@ -61,7 +61,7 @@ select {
 			  <option value="1" >Reference 1</option>
 			</select>
 		</td>
-		<td colspan="2">Storage Path/Name: <input type="text" name="name" id="name"></td>
+		<td colspan="2">Storage Path/Name: <input type="text" name="name" id="name" onchange="namechanged()"></td>
 	  </tr>
 	  <tr>
 		<td style="padding-top: 10px">x: <input type="number" name="refx" id="refx" step=1 onchange="valuemanualchanged()"></td>
@@ -90,9 +90,8 @@ select {
 	</table>
 
 <script type="text/javascript" src="./gethost.js"></script> 
-<script type="text/javascript" src="./readconfig.js"></script> 
 <script type="text/javascript" src="./readconfigcommon.js"></script>
-
+<script type="text/javascript" src="./readconfigparam.js"></script>  
 
 <script language="JavaScript">
         var canvas = document.getElementById('canvas'),
@@ -105,7 +104,8 @@ select {
             enhanceCon = false,
             param;
             basepath = "http://192.168.178.26";
-            basepath = "";
+            basepath = "",
+            param;
 
 function ChangeSelection(){
     aktindex = parseInt(document.getElementById("index").value);
@@ -113,14 +113,9 @@ function ChangeSelection(){
 }
 
 function SaveToConfig(){
-/*
-    refInfo[aktindex]["name"] = document.getElementById("name").value;
-    refInfo[aktindex]["x"] = document.getElementById("refx").value;
-    refInfo[aktindex]["y"] = document.getElementById("refy").value; 
-    refInfo[aktindex]["dx"] = document.getElementById("refdx").value;
-    refInfo[aktindex]["dy"] = document.getElementById("refdy").value;
-*/   
-    UpdateConfigReference(refInfo, basepath); 
+    WriteConfigININew();
+    UpdateConfigReference(basepath)
+    SaveConfigToServer(basepath);
 }
 
 function EnhanceContrast(){
@@ -133,10 +128,6 @@ function EnhanceContrast(){
     enhanceCon = true;
     MakeContrastImageZW(refInfo[aktindex], enhanceCon, basepath);
     UpdateReference();
-//    var url = basepath + "/fileserver" + "/img_tmp/ref_zw.jpg?" + Date.now();
-//    document.getElementById("img_ref").src = url;
-//    var url = basepath + "/fileserver" + "/img_tmp/ref_zw_org.jpg?" + Date.now();
-//    document.getElementById("img_ref_org").src = url;
 }
 
 function UpdateReference(){
@@ -211,6 +202,7 @@ function dataURLtoBlob(dataurl) {
             basepath = getbasepath();
             loadConfig(basepath); 
             ParseConfig();
+            param = getConfigParameters();
 
             canvas.addEventListener('mousedown', mouseDown, false);
             canvas.addEventListener('mouseup', mouseUp, false);
@@ -355,6 +347,12 @@ function dataURLtoBlob(dataurl) {
         }
     }
 
+    function namechanged()
+    {
+        _name = document.getElementById("name").value;
+        refInfo[aktindex]["name"] = _name;
+    }
+
     function valuemanualchanged(){
         if (!drag) {
             rect.w = document.getElementById("refdx").value;

+ 168 - 53
sd-card/html/edit_analog.html

@@ -69,13 +69,28 @@ th, td {
    
 
 <div id="div1">
-
 	<table>
 	  <tr>
 		<td><canvas id="canvas" crossorigin></canvas></td>
 	  </tr>
 	</table>	
-			 
+
+    <p>
+        <table>
+            <tr>
+                <class id="Numbers_text" style="color:black;"><b>Number: </b></class>
+                <select id="Numbers_value1" onchange="numberChanged()">
+                    <option value="0" selected>default</option>
+                    <option value="1" >NT</option>
+                    <option value="2" >HT</option>
+                </select>
+                <input class="move" type="submit" id="renameNumber" name="renameNumber" onclick="renameNumber()" value="Rename">  
+                <input class="move" type="submit" id="newNumber" name="newNumber" onclick="newNumber()" value="New">  
+                <input class="move" type="submit" id="removeNumber" name="removeNumber" onclick="removeNumber()" value="Remove">
+            </tr>
+        </table>
+    </p>
+
 	<table>
 	  <tr>
 		<td><input class="button" type="submit" id= "newROI" name="newROI" onclick="newROI()" value="New ROI (after current)"></td>	  
@@ -89,10 +104,12 @@ th, td {
 			  <option value="1" >ROI 1</option>
             </select>
 		</td>
-		<td>Name: <input type="text" name="name" id="name" onchange="onNameChange()" size="13"></td>
+		<td>                
+            <input class="button" type="submit" id="renameROI" name="renameROI" onclick="renameROI()" value="Rename">  
 		<td>
-		<input class="button" type="submit" id="moveNext" onclick="moveNext()" value="move Next">
-		<input class="button" type="submit" id="movePrevious" onclick="movePrevious()" value="move Previous">  
+		<td>
+		<input class="move" type="submit" id="moveNext" onclick="moveNext()" value="move Next">
+		<input class="move" type="submit" id="movePrevious" onclick="movePrevious()" value="move Previous">  
 		</td>	
 	  </tr>
 	  <tr>
@@ -114,11 +131,10 @@ th, td {
     </table>	
 
 
-<script type="text/javascript" src="./gethost.js"></script> 
-<script type="text/javascript" src="./readconfigcommon.js"></script>  
-<script type="text/javascript" src="./readconfig.js"></script>  
-<script type="text/javascript" src="./jquery-3.5.1.min.js"></script>  
-
+    <script type="text/javascript" src="./gethost.js"></script> 
+    <script type="text/javascript" src="./readconfigcommon.js"></script>
+    <script type="text/javascript" src="./readconfigparam.js"></script>  
+    
 <script language="JavaScript">
         var canvas = document.getElementById('canvas'),
             ctx = canvas.getContext('2d'),
@@ -179,21 +195,22 @@ function deleteROI(){
 }
 
 function newROI(){
-    var zw = ROIInfo[ROIInfo.length-1];
-    ROIInfo.push(zw);
-    for (var i = ROIInfo.length-2; i > aktindex + 1; --i){
-        ROIInfo[i] = ROIInfo[i-1];
-    }
-    aktindex++;
-    ROIInfo[aktindex] = new Object;
-    ROIInfo[aktindex]["pos_ref"] = -1;
-    ROIInfo[aktindex]["name"] = "ROI" + aktindex;
-    ROIInfo[aktindex]["x"] = 1;
-    ROIInfo[aktindex]["y"] = 1;
-    ROIInfo[aktindex]["dx"] = ROIInfo[aktindex-1]["dx"];
-    ROIInfo[aktindex]["dy"] = ROIInfo[aktindex-1]["dy"];
-    ROIInfo[aktindex]["ar"] = ROIInfo[aktindex-1]["ar"];
-    UpdateROIs();
+    var sel = document.getElementById("Numbers_value1");
+    var _number= sel.options[sel.selectedIndex].text;
+    sel = document.getElementById("index");
+    var _roialt= sel.options[sel.selectedIndex].text;
+
+    var _roinew = prompt("Please enter name of new ROI", "name");
+
+    if (ROIInfo.length > 0)
+        erg = CreateROI(_number, "analog", sel.selectedIndex, _roinew, 1, 1, ROIInfo[aktindex]["dx"], ROIInfo[aktindex]["dy"]);
+    else
+        erg = CreateROI(_number, "analog", sel.selectedIndex, _roinew, 1, 1, 30, 30);
+
+    if (erg != "")
+        alert(erg);
+    else
+        UpdateROIs(_roinew);
 }
 
 function movePrevious(){
@@ -223,34 +240,64 @@ function ChangeSelection(){
 }
 
 function SaveToConfig(){
-    _enabled = document.getElementById("Category_Analog_enabled").checked;
-    SaveROIToConfig(ROIInfo, "[Analog]", basepath, _enabled);
-    UpdatePage();  
+    _zwcat = getConfigCategory();
+    _zwcat["Analog"]["enabled"] = document.getElementById("Category_Analog_enabled").checked;
+    WriteConfigININew();
+    SaveConfigToServer(basepath);    
 }
 
 
 function UpdateROIs(){
+    document.getElementById("Category_Analog_enabled").checked = true;
+    var sel = document.getElementById("Numbers_value1");
+    var _number = sel.options[sel.selectedIndex].text;
+
+    ROIInfo = getROIInfo("analog", _number);
+    _catzw = getConfigCategory();
+
+    if (_catzw["Analog"]["enabled"] == false) 
+    {
+        document.getElementById("Category_Analog_enabled").checked = false;
+        EnDisableDigits();
+        alert("Analog ROIs are disabled - please enable (Check box top left).\n");
+        return;
+    }
+
     if (ROIInfo.length == 0){
-        alert("There are no ROIs defined.\nPlease first define minimum one ROI in the config.ini by hand.\n");
-        document.getElementById("newROI").disabled = true;
+        alert("There are no ROIs defined.\nPlease first create a new ROI (\"New ROIs ...\").\n");
+        document.getElementById("newROI").disabled = false;
         document.getElementById("deleteROI").disabled = true;
         document.getElementById("index").disabled = true;
-        document.getElementById("saveroi").disabled = true;
+        document.getElementById("renameROI").disabled = true;
         document.getElementById("moveNext").disabled = true;
         document.getElementById("movePrevious").disabled = true;
         return;
     }
+    else
+    {
+        document.getElementById("newROI").disabled = false;
+        document.getElementById("deleteROI").disabled = false;
+        document.getElementById("renameROI").disabled = false;
+        document.getElementById("index").disabled = false;
+    }
 
     var _index = document.getElementById("index");
     while (_index.length){
         _index.remove(0);
     }
 
+    if (aktindex > ROIInfo.length)
+        aktindex = ROIInfo.length;
+
     for (var i = 0; i < ROIInfo.length; ++i){
         var option = document.createElement("option");
-        option.text = "ROI " + (i + 1);
+        option.text = ROIInfo[i]["name"];
         option.value = i;
-        _index.add(option); 
+        _index.add(option);
+        if (typeof _sel !== 'undefined') {
+            if (option.text == _sel)
+                aktindex = i;
+        }
     }
     _index.selectedIndex = aktindex; 
 
@@ -267,7 +314,6 @@ function UpdateROIs(){
     
     document.getElementById("lockAR").checked = lockAR;
        
-    document.getElementById("name").value = ROIInfo[aktindex]["name"];
     document.getElementById("refx").value = ROIInfo[aktindex]["x"];
     document.getElementById("refy").value = ROIInfo[aktindex]["y"];  
     document.getElementById("refdx").value = ROIInfo[aktindex]["dx"];  
@@ -277,26 +323,8 @@ function UpdateROIs(){
     rect.w = ROIInfo[aktindex]["dx"];
     rect.h = ROIInfo[aktindex]["dy"];
     draw();      
-}
-
-function ParseIni(_basepath) {
-    loadConfig(_basepath);
-    ParseConfig();
-
-    document.getElementById("Category_Analog_enabled").checked = true;
-    ROIInfo = getROIInfo("[Analog]");
 
-    if (!GetAnalogEnabled()) 
-    {
-        document.getElementById("Category_Analog_enabled").checked = false;
-        EnDisableAnalog();
-        alert("Analog ROIs are disabled - please enable (Check box top left).\n");
-        return;
-    }
-
-    UpdateROIs();
 }
-			
     
         function loadCanvas(dataURL) {
                 var canvas = document.getElementById('canvas');
@@ -334,7 +362,10 @@ function ParseIni(_basepath) {
             canvas.addEventListener('mouseup', mouseUp, false);
             canvas.addEventListener('mousemove', mouseMove, false);
             loadCanvas(basepath + "/fileserver/config/reference.jpg");
-            ParseIni(basepath);
+            loadConfig(basepath); 
+            ParseConfig();
+            param = getConfigParameters(); 
+            UpdateNUMBERS();
             drawImage();
             draw();
         }
@@ -349,6 +380,66 @@ function ParseIni(_basepath) {
 //            context.restore();
         }  
 
+function UpdateNUMBERS(_sel){
+    zw = getNUMBERInfo();
+
+    index = 0;
+
+    var _index = document.getElementById("Numbers_value1");
+    while (_index.length){
+        _index.remove(0);
+    }
+
+    for (var i = 0; i < zw.length; ++i){
+        var option = document.createElement("option");
+        option.text = zw[i]["name"];
+        option.value = i;
+        _index.add(option); 
+
+        if (typeof _sel !== 'undefined') {
+            if (zw[i]["name"] == _sel)
+                index = i
+        }
+    }
+    _index.selectedIndex = index;
+
+    UpdateROIs();
+}
+
+function renameNumber(){
+    var sel = document.getElementById("Numbers_value1");
+    var _delte= sel.options[sel.selectedIndex].text;
+    var _numbernew = prompt("Please enter new name", _delte);
+
+    erg = RenameNUMBER(_delte, _numbernew);
+    if (erg != "")
+        alert(erg);
+    else
+        UpdateNUMBERS(_numbernew);
+}
+
+function newNumber(){
+    var _numbernew = prompt("Please enter name of new number", "name");
+
+    erg = CreateNUMBER(_numbernew);
+    if (erg != "")
+        alert(erg);
+    else
+        UpdateNUMBERS(_numbernew);
+}
+
+
+function removeNumber(){
+	if (confirm("This will remove the number complete (analog and digital).\nIf you only want to remove the digital ROIs, please use \"Delete ROIs\".\nDo you want to proceed?")) {
+        var sel = document.getElementById("Numbers_value1");
+        var _delte= sel.options[sel.selectedIndex].text;
+        erg = DeleteNUMBER(_delte);
+        if (erg != "")
+            alert(erg);
+        UpdateNUMBERS();
+	}	    
+}
+
 
     function draw() {
         var canvas = document.getElementById('canvas');
@@ -483,6 +574,30 @@ function ParseIni(_basepath) {
         }
     }
 
+
+    function renameROI(){
+        var sel = document.getElementById("Numbers_value1");
+        var _number= sel.options[sel.selectedIndex].text;
+        sel = document.getElementById("index");
+        var _roialt= sel.options[sel.selectedIndex].text;
+
+
+        var _roinew = prompt("Please enter new name", _roialt);
+
+        erg = RenameROI(_number, "analog", _roialt, _roinew);
+        if (erg != "")
+            alert(erg);
+        else
+            UpdateROIs(_roinew);
+    }
+
+    function numberChanged()
+    {
+        UpdateROIs();
+    }    
+
+
+
     
     init();
 </script>

+ 0 - 1
sd-card/html/edit_config.html

@@ -41,7 +41,6 @@ textarea {
 </table>
 
 <script type="text/javascript" src="./gethost.js"></script> 
-<script type="text/javascript" src="./readconfig.js"></script>  
 <script type="text/javascript" src="./readconfigcommon.js"></script>  
  
 <script type="text/javascript">

+ 171 - 114
sd-card/html/edit_config_param.html

@@ -362,20 +362,6 @@ textarea {
 		<tr>
 			<td colspan="4" style="padding-left: 20px;"><h4>PostProcessing</h4></td>
 		</tr> 		
-		<tr>
-			<td width="20px"  style="padding-left: 40px;">
-				<input type="checkbox" id="PostProcessing_DecimalShift_enabled" value="1"  onclick = 'InvertEnableItem("PostProcessing", "DecimalShift")' unchecked >
-			</td>
-			<td  width="200px">
-				<class id="PostProcessing_DecimalShift_text" style="color:black;">DecimalShift</class>
-			</td>
-			<td>
-				<input type="number" id="PostProcessing_DecimalShift_value1" step="1">
-			</td>
-			<td style="font-size: 80%;">
-				shift the digit separator within the digital digits (positiv and negativ)
-			</td>
-		</tr>
 		<tr>
 			<td width="20px"  style="padding-left: 40px;">
 				<input type="checkbox" id="PostProcessing_PreValueUse_enabled" value="1"  onclick = 'InvertEnableItem("PostProcessing", "PreValueUse")' unchecked >
@@ -424,20 +410,6 @@ textarea {
 				Set on "false" to ensure, that only positive changes are accepted (typically for counter)
 			</td>
 		</tr>
-		<tr>
-			<td width="20px"  style="padding-left: 40px;">
-				<input type="checkbox" id="PostProcessing_MaxRateValue_enabled" value="1"  onclick = 'InvertEnableItem("PostProcessing", "MaxRateValue")' unchecked >
-			</td>
-			<td  width="200px">
-				<class id="PostProcessing_MaxRateValue_text" style="color:black;">MaxRateValue</class>
-			</td>
-			<td>
-				<input type="number" id="PostProcessing_MaxRateValue_value1" size="13" min="0" step="any">
-			</td>
-			<td style="font-size: 80%;">
-				Maximum change of reading from one to the next readout
-			</td>
-		</tr>
 		<tr class="expert"  id="ex12">
 			<td width="20px"  style="padding-left: 40px;">
 				<input type="checkbox" id="PostProcessing_ErrorMessage_enabled" value="1"  onclick = 'InvertEnableItem("PostProcessing", "ErrorMessage")' unchecked >
@@ -474,76 +446,78 @@ textarea {
 		</tr>
 
 		<tr>
-			<td colspan="4" style="padding-left: 20px;"><h4><input type="checkbox" id="Category_MQTT_enabled" value="1"  onclick = 'UpdateAfterCategoryCheck()' unchecked > MQTT</h4></td>
-		</tr> 		
-		<tr>
-			<td width="20px"  style="padding-left: 40px;">
-				<input type="checkbox" id="MQTT_Uri_enabled" value="1"  onclick = 'InvertEnableItem("MQTT", "Uri")' unchecked >
-			</td>
-			<td  width="200px">
-				<class id="MQTT_Uri_text" style="color:black;">Uri</class>
-			</td>
-			<td>
-				<input type="text" id="MQTT_Uri_value1">
-			</td>
-			<td style="font-size: 80%;">
-				URI to the MQTT broker including port e.g.: mqtt://IP-Address:Port
+			<td style="padding-left: 40px;" colspan="4">
+				<br>
+				<b>Postprocessing Individual Paramters: 
+                <select id="Numbers_value1" onchange="numberChanged()">
+                    <option value="0" selected>default</option>
+                    <option value="1" >NT</option>
+                    <option value="2" >HT</option>
+                </select></b>
 			</td>
 		</tr>
 		<tr>
 			<td width="20px"  style="padding-left: 40px;">
-				<input type="checkbox" id="MQTT_Topic_enabled" value="1"  onclick = 'InvertEnableItem("MQTT", "Topic")' unchecked >
+				<input type="checkbox" id="PostProcessing_DecimalShift_enabled" value="1"  onclick = 'InvertEnableItem("PostProcessing", "DecimalShift")' unchecked >
 			</td>
 			<td  width="200px">
-				<class id="MQTT_Topic_text" style="color:black;">Topic</class>
+				<class id="PostProcessing_DecimalShift_text" style="color:black;">DecimalShift</class>
 			</td>
 			<td>
-				<input type="text" id="MQTT_Topic_value1">
+				<input type="number" id="PostProcessing_DecimalShift_value1" step="1">
 			</td>
 			<td style="font-size: 80%;">
-				MQTT topic, in which the value is registered
+				shift the digit separator within the digital digits (positiv and negativ)
 			</td>
 		</tr>
 		<tr>
 			<td width="20px"  style="padding-left: 40px;">
-				<input type="checkbox" id="MQTT_TopicError_enabled" value="1"  onclick = 'InvertEnableItem("MQTT", "TopicError")' unchecked >
+				<input type="checkbox" id="PostProcessing_MaxRateValue_enabled" value="1"  onclick = 'InvertEnableItem("PostProcessing", "MaxRateValue")' unchecked >
 			</td>
 			<td  width="200px">
-				<class id="MQTT_TopicError_text" style="color:black;">TopicError</class>
+				<class id="PostProcessing_MaxRateValue_text" style="color:black;">MaxRateValue</class>
 			</td>
 			<td>
-				<input type="text" id="MQTT_TopicError_value1">
+				<input type="number" id="PostProcessing_MaxRateValue_value1" size="13" min="0" step="any">
 			</td>
 			<td style="font-size: 80%;">
-				MQTT topic, in which the error status is reported (empty = no error)
+				Maximum change of reading from one to the next readout
 			</td>
 		</tr>
+
+
+
+		<tr>
+			<td colspan="4" style="padding-left: 20px;"><h4><input type="checkbox" id="Category_MQTT_enabled" value="1"  onclick = 'UpdateAfterCategoryCheck()' unchecked > MQTT</h4></td>
+		</tr> 		
 		<tr>
 			<td width="20px"  style="padding-left: 40px;">
-				<input type="checkbox" id="MQTT_TopicRate_enabled" value="1"  onclick = 'InvertEnableItem("MQTT", "TopicRate")' unchecked >
+				<input type="checkbox" id="MQTT_Uri_enabled" value="1"  onclick = 'InvertEnableItem("MQTT", "Uri")' unchecked >
 			</td>
 			<td  width="200px">
-				<class id="MQTT_TopicRate_text" style="color:black;">TopicRate</class>
+				<class id="MQTT_Uri_text" style="color:black;">Uri</class>
 			</td>
 			<td>
-				<input type="text" id="MQTT_TopicRate_value1">
+				<input type="text" id="MQTT_Uri_value1">
 			</td>
 			<td style="font-size: 80%;">
-				MQTT topic, in which the flow rate [units / minute] is reported
+				URI to the MQTT broker including port e.g.: mqtt://IP-Address:Port
 			</td>
 		</tr>
 		<tr>
 			<td width="20px"  style="padding-left: 40px;">
-				<input type="checkbox" id="MQTT_TopicTimeStamp_enabled" value="1"  onclick = 'InvertEnableItem("MQTT", "TopicTimeStamp")' unchecked >
+				<input type="checkbox" id="MQTT_MainTopic_enabled" value="1"  onclick = 'InvertEnableItem("MQTT", "MainTopic")' unchecked >
 			</td>
 			<td  width="200px">
-				<class id="MQTT_TopicTimeStamp_text" style="color:black;">TopicTimeStamp</class>
+				<class id="MQTT_MainTopic_text" style="color:black;">MainTopic</class>
 			</td>
 			<td>
-				<input type="text" id="MQTT_TopicTimeStamp_value1">
+				<input type="text" id="MQTT_MainTopic_value1">
 			</td>
 			<td style="font-size: 80%;">
-				MQTT topic, reporting the last correct readout
+				MQTT main topic, under which the counters are published. The single value will be published with the following key: MAINTOPIC/VALUE_NAME/PARAMTER <br>
+				where parameters are: value, rate, timestamp, error<br>
+				The general connection status can be found in MAINTOPiC"/CONNECTION
 			</td>
 		</tr>
 		<tr>
@@ -730,6 +704,8 @@ textarea {
 		basepath = "http://192.168.178.22"; 
 		param;
 		category;
+		NUNBERSAkt = -1;
+		NUMBERS;
 
 
 function LoadConfigNeu() {
@@ -746,15 +722,34 @@ function LoadConfigNeu() {
 		alert("Config.ini could not be loaded!\nPlease reload the page.");
 		return;
 	} 
-	loadConfig(basepath); 
 	ParseConfig();	
 	param = getConfigParameters();
-	category = getConfigCategory();	
+	category = getConfigCategory();
+	InitIndivParameter();
+
 	UpdateInput();
+	UpdateInputIndividual();
 	UpdateExpertModus();
 	document.getElementById("divall").style.display = ''; 
 	}
 
+function InitIndivParameter()
+{
+	NUMBERS = getNUMBERInfo();
+
+    var _index = document.getElementById("Numbers_value1");
+    while (_index.length)
+        _index.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);
+        }
+    _index.selectedIndex = 0; 
+}
+
 
 function getParameterByName(name, url = window.location.href) {
     name = name.replace(/[\[\]]/g, '\\$&');
@@ -765,43 +760,60 @@ function getParameterByName(name, url = window.location.href) {
     return decodeURIComponent(results[2].replace(/\+/g, ' '));
 }	
 
-function WriteParameter(_param, _category, _cat, _name, _optional, _select = false, _anzpara = 1){
-	if (_param[_cat][_name]["found"]){
-		if (_optional) {
-			document.getElementById(_cat+"_"+_name+"_enabled").checked = _param[_cat][_name]["enabled"];
-			for (var j = 1; j <= _anzpara; ++j) {
-				document.getElementById(_cat+"_"+_name+"_value"+j).disabled = !_param[_cat][_name]["enabled"];	
-			}		
-		}
-		document.getElementById(_cat+"_"+_name+"_text").style="color:black;"
-		if (_select) {
-			var textToFind = _param[_cat][_name]["value1"];
-			var dd = document.getElementById(_cat+"_"+_name+"_value1");
-			for (var i = 0; i < dd.options.length; i++) {
-				if (dd.options[i].text.toLowerCase() === textToFind.toLowerCase()) {
-					dd.selectedIndex = i;
-					break;
+function WriteParameter(_param, _category, _cat, _name, _optional, _select = false, _anzpara = 1, _number = -1){
+	if (_number > -1)
+	{
+		{
+			if (_optional) {
+				document.getElementById(_cat+"_"+_name+"_enabled").checked = _param[_cat][_name]["enabled"];
+				for (var j = 1; j <= _anzpara; ++j) 
+					document.getElementById(_cat+"_"+_name+"_value"+j).disabled = NUMBERS[_number][_cat][_name]["enabled"];
+			}
+			document.getElementById(_cat+"_"+_name+"_text").style="color:black;"
+			if (_select) {
+				var textToFind; 
+				textToFind = NUMBERS[_number][_cat][_name]["value1"];
+				var dd = document.getElementById(_cat+"_"+_name+"_value1");
+				for (var i = 0; i < dd.options.length; i++) {
+					if (dd.options[i].text.toLowerCase() === textToFind.toLowerCase()) {
+						dd.selectedIndex = i;
+						break;
+					}
 				}
 			}
-		}
-		else {
-			for (var j = 1; j <= _anzpara; ++j) {
-				document.getElementById(_cat+"_"+_name+"_value"+j).value = _param[_cat][_name]["value"+j];
+			else {
+				for (var j = 1; j <= _anzpara; ++j) 
+					document.getElementById(_cat+"_"+_name+"_value"+j).value = NUMBERS[_number][_cat][_name]["value"+j];
 			}
 		}
-
 	}
-	else {
-		if (_optional) {
-			document.getElementById(_cat+"_"+_name+"_enabled").disabled = true;	
-			for (var j = 1; j <= _anzpara; ++j) {
-				document.getElementById(_cat+"_"+_name+"_value"+j).disabled = true;	
-			}	
+	else
+	{
+		{
+			if (_optional) {
+				document.getElementById(_cat+"_"+_name+"_enabled").checked = _param[_cat][_name]["enabled"];
+				for (var j = 1; j <= _anzpara; ++j) 
+					document.getElementById(_cat+"_"+_name+"_value"+j).disabled = !_param[_cat][_name]["enabled"];
+			}
+			document.getElementById(_cat+"_"+_name+"_text").style="color:black;"
+			if (_select) {
+				var textToFind; 
+				textToFind = _param[_cat][_name]["value1"];
+				var dd = document.getElementById(_cat+"_"+_name+"_value1");
+				for (var i = 0; i < dd.options.length; i++) {
+					if (dd.options[i].text.toLowerCase() === textToFind.toLowerCase()) {
+						dd.selectedIndex = i;
+						break;
+					}
+				}
+			}
+			else {
+				for (var j = 1; j <= _anzpara; ++j) 
+					document.getElementById(_cat+"_"+_name+"_value"+j).value = _param[_cat][_name]["value"+j];
+			}
 		}
-		document.getElementById(_cat+"_"+_name+"_text").style="color:lightgrey;"		
 	}
 
-
 	///////////////// am Ende, falls Kategorie als gesamtes nicht ausgewählt --> deaktivieren
 	if (_category[_cat]["enabled"] == false) 
 	{
@@ -813,6 +825,7 @@ function WriteParameter(_param, _category, _cat, _name, _optional, _select = fal
 		}
 		document.getElementById(_cat+"_"+_name+"_text").style="color:lightgrey;"		
 	}
+
 	EnDisableItem(_category[_cat]["enabled"], _param, _category, _cat, _name, _optional);
 }
 
@@ -843,9 +856,9 @@ function InvertEnableItem(_cat, _param)
 
 }
 
-function EnDisableItem(_status, _param, _category, _cat, _name, _optional)
+function EnDisableItem(_status, _param, _category, _cat, _name, _optional, _number = -1)
 {
-	_status = _param[_cat][_name]["found"] && _category[_cat]["enabled"];
+	_status = _category[_cat]["enabled"];
 
 	_color = "color:lightgrey;";
 	if (_status) {
@@ -857,10 +870,18 @@ function EnDisableItem(_status, _param, _category, _cat, _name, _optional)
 		document.getElementById(_cat+"_"+_name+"_enabled").style=_color;	
 	}
 
-	if (!_param[_cat][_name]["enabled"]) {
-		_status = false;
-		_color = "color:lightgrey;";
+	if (_number == -1){
+		if (!_param[_cat][_name]["enabled"]) {
+			_status = false;
+			_color = "color:lightgrey;";
+		}
 	}
+	else
+		if (!NUMBERS[_number][_cat][_name]["enabled"]) {
+				_status = false;
+				_color = "color:lightgrey;";
+			}
+
 
 	document.getElementById(_cat+"_"+_name+"_text").disabled = !_status;
 	document.getElementById(_cat+"_"+_name+"_text").style = _color;
@@ -877,10 +898,31 @@ function EnDisableItem(_status, _param, _category, _cat, _name, _optional)
 }
 
 
-function ReadParameter(_param, _cat, _name, _optional, _select = false){
-	if (_param[_cat][_name]["found"]){
+function ReadParameter(_param, _cat, _name, _optional, _select = false, _number = -1){
+	if (_number > -1)
+	{
+		if (_cat == "Digits")
+			_cat = "digit"
+		if (_cat == "Analog")
+			_cat = "analog"
+
 		if (_optional) {
-			_param[_cat][_name]["enabled"] = document.getElementById(_cat+"_"+_name+"_enabled").checked;			
+			NUMBERS[_number][_cat][_name]["enabled"] = document.getElementById(_cat+"_"+_name+"_enabled").checked;
+		}
+		if (_select) {
+			var sel = document.getElementById(_cat+"_"+_name+"_value1");
+			NUMBERS[_number][_cat][_name]["value1"] = sel.options[sel.selectedIndex].text;
+		}
+		else {
+			for (var j = 1; j <= _param[_cat][_name]["anzParam"]; ++j) {
+				NUMBERS[_number][_cat][_name]["value"+j] = document.getElementById(_cat+"_"+_name+"_value"+j).value;
+			}
+		}
+	}
+	else
+	{
+		if (_optional) {
+			_param[_cat][_name]["enabled"] = document.getElementById(_cat+"_"+_name+"_enabled").checked;
 		}
 		if (_select) {
 			var sel = document.getElementById(_cat+"_"+_name+"_value1");
@@ -894,6 +936,20 @@ function ReadParameter(_param, _cat, _name, _optional, _select = false){
 	}
 }
 
+function UpdateInputIndividual()
+{
+	if (NUNBERSAkt != -1)
+	{
+		ReadParameter(param, "PostProcessing", "DecimalShift", true, false, NUNBERSAkt)		
+		ReadParameter(param, "PostProcessing", "MaxRateValue", true, false, NUNBERSAkt)		
+	}
+
+	var sel = document.getElementById("Numbers_value1");
+	NUNBERSAkt = sel.selectedIndex;
+	WriteParameter(param, category, "PostProcessing", "DecimalShift", true, false, 1, NUNBERSAkt);
+	WriteParameter(param, category, "PostProcessing", "MaxRateValue", true, false, 1, NUNBERSAkt);
+}
+
 function UpdateInput() {
 	document.getElementById("Category_Analog_enabled").checked = category["Analog"]["enabled"];
 	document.getElementById("Category_Digits_enabled").checked = category["Digits"]["enabled"];
@@ -924,19 +980,15 @@ function UpdateInput() {
 	WriteParameter(param, category, "Analog", "ExtendedResolution", true, true);		
 	WriteParameter(param, category, "Analog", "ModelInputSize", false, false, 2);		
 	
-	WriteParameter(param, category, "PostProcessing", "DecimalShift", true);		
 	WriteParameter(param, category, "PostProcessing", "PreValueUse", true, true);		
 	WriteParameter(param, category, "PostProcessing", "PreValueAgeStartup", true);		
 	WriteParameter(param, category, "PostProcessing", "AllowNegativeRates", true, true);
-	WriteParameter(param, category, "PostProcessing", "MaxRateValue", true);		
+//	WriteParameter(param, category, "PostProcessing", "MaxRateValue", true);		
 	WriteParameter(param, category, "PostProcessing", "ErrorMessage", true, true);
 	WriteParameter(param, category, "PostProcessing", "CheckDigitIncreaseConsistency", true, true);
 
 	WriteParameter(param, category, "MQTT", "Uri", true);	
-	WriteParameter(param, category, "MQTT", "Topic", true);	
-	WriteParameter(param, category, "MQTT", "TopicError", true);	
-	WriteParameter(param, category, "MQTT", "TopicRate", true);	
-	WriteParameter(param, category, "MQTT", "TopicTimeStamp", true);	
+	WriteParameter(param, category, "MQTT", "MainTopic", true);	
 	WriteParameter(param, category, "MQTT", "ClientID", true);	
 	WriteParameter(param, category, "MQTT", "user", true);	
 	WriteParameter(param, category, "MQTT", "password", true);	
@@ -975,15 +1027,14 @@ function ReadParameterAll()
 	ReadParameter(param, "Digits", "Model", false);		
 	ReadParameter(param, "Digits", "LogImageLocation", true);		
 	ReadParameter(param, "Digits", "LogfileRetentionInDays", true);		
-	ReadParameter(param, "Digits", "ModelInputSize", false, false, 2);
+	ReadParameter(param, "Digits", "ModelInputSize", false, false);
 
 	ReadParameter(param, "Analog", "Model", false);		
 	ReadParameter(param, "Analog", "LogImageLocation", true);		
 	ReadParameter(param, "Analog", "LogfileRetentionInDays", true);		
 	ReadParameter(param, "Analog", "ExtendedResolution", true, true);		
-	ReadParameter(param, "Analog", "ModelInputSize", false, false, 2);
+	ReadParameter(param, "Analog", "ModelInputSize", false, false);
 
-	ReadParameter(param, "PostProcessing", "DecimalShift", true);		
 	ReadParameter(param, "PostProcessing", "PreValueUse", true, true);		
 	ReadParameter(param, "PostProcessing", "PreValueAgeStartup", true);		
 	ReadParameter(param, "PostProcessing", "AllowNegativeRates", true, true);
@@ -992,10 +1043,7 @@ function ReadParameterAll()
 	ReadParameter(param, "PostProcessing", "CheckDigitIncreaseConsistency", true, true);
 
 	ReadParameter(param, "MQTT", "Uri", true);	
-	ReadParameter(param, "MQTT", "Topic", true);	
-	ReadParameter(param, "MQTT", "TopicError", true);	
-	ReadParameter(param, "MQTT", "TopicRate", true);
-	ReadParameter(param, "MQTT", "TopicTimeStamp", true);
+	ReadParameter(param, "MQTT", "MainTopic", true);	
 	ReadParameter(param, "MQTT", "ClientID", true);	
 	ReadParameter(param, "MQTT", "user", true);	
 	ReadParameter(param, "MQTT", "password", true);	
@@ -1009,8 +1057,10 @@ function ReadParameterAll()
 	ReadParameter(param, "System", "TimeZone", true);	
 	ReadParameter(param, "System", "Hostname", true);	
 	ReadParameter(param, "System", "TimeServer", true);	
+
+	UpdateInputIndividual();
 	
-	FormatDecimalValue(param, "PostProcessing", "MaxRateValue");
+//	FormatDecimalValue(param, "PostProcessing", "MaxRateValue");
 }
 
 function WriteConfig(){
@@ -1030,7 +1080,9 @@ function UpdateAfterCategoryCheck() {
 	ReadParameterAll();
 	category["Analog"]["enabled"] = document.getElementById("Category_Analog_enabled").checked;
 	category["Digits"]["enabled"] = document.getElementById("Category_Digits_enabled").checked;
+	category["MQTT"]["enabled"] = document.getElementById("Category_MQTT_enabled").checked;
 	UpdateInput();
+	UpdateInputIndividual();
 }
 
 function UpdateExpertModus()
@@ -1055,9 +1107,9 @@ function UpdateExpertModus()
 function saveTextAsFile()
 {
 	if (confirm("Are you sure you want to update \"config.ini\"?")) {
-		var textToSave = WriteConfig();
-		FileDeleteOnServer("/config/config.ini", basepath);
-		FileSendContent(textToSave, "/config/config.ini", basepath);
+		ReadParameterAll();
+		WriteConfigININew();
+	    SaveConfigToServer(basepath);    
 	}
 }
 
@@ -1080,6 +1132,11 @@ function editConfigDirect() {
 		window.location.replace(stringota);
 	}	
 }
+
+function numberChanged()
+{
+	UpdateInputIndividual();
+}
  
 LoadConfigNeu();
  

+ 170 - 55
sd-card/html/edit_digits.html

@@ -64,8 +64,24 @@ th, td {
 	  <tr>
 		<canvas id="canvas" crossorigin></canvas>
 	  </tr>
-	</table>	
-			 
+	</table>
+    
+    <p>
+        <table>
+            <tr>
+                <class id="Numbers_text" style="color:black;"><b>Number:</b> </class>
+                <select id="Numbers_value1" onchange="numberChanged()">
+                    <option value="0" selected>default</option>
+                    <option value="1" >NT</option>
+                    <option value="2" >HT</option>
+                </select>
+                <input class="move" type="submit" id="renameNumber" name="renameNumber" onclick="renameNumber()" value="Rename">  
+                <input class="move" type="submit" id="newNumber" name="newNumber" onclick="newNumber()" value="New">  
+                <input class="move" type="submit" id="removeNumber" name="removeNumber" onclick="removeNumber()" value="Remove">
+            </tr>
+        </table>
+    </p>
+    
 	<table>
 	  <tr>
 		<td><input class="button" type="submit" id="newROI" name="newROI" onclick="newROI()" value="New ROI (after current)"></td>	  
@@ -79,7 +95,8 @@ th, td {
 			  <option value="1" >ROI 1</option>
 			</select>
 		</td>
-		<td>Name: <input type="text" name="name" id="name" onchange="onNameChange()" size="13"></td>
+		<td>                
+            <input class="button" type="submit" id="renameROI" name="renameROI" onclick="renameROI()" value="Rename">  
 		<td>
 		<input class="move" type="submit" id="moveNext" onclick="moveNext()" value="move Next">
 		<input class="move" type="submit" id="movePrevious" onclick="movePrevious()" value="move Previous">  
@@ -105,9 +122,10 @@ th, td {
 	</table>
 
 <script type="text/javascript" src="./gethost.js"></script> 
-<script type="text/javascript" src="./readconfig.js"></script>  
-<script type="text/javascript" src="./readconfigcommon.js"></script>  
-<script type="text/javascript" src="./jquery-3.5.1.min.js"></script>  
+<script type="text/javascript" src="./readconfigcommon.js"></script>
+<script type="text/javascript" src="./readconfigparam.js"></script>  
+
+<script type="text/javascript" src="./jquery-3.6.0.min.js"></script>  
 
 <script language="JavaScript">
         var canvas = document.getElementById('canvas'),
@@ -169,22 +187,23 @@ function deleteROI(){
     UpdateROIs();
 }
 
-function newROI(){
-    var zw = ROIInfo[ROIInfo.length-1];
-    ROIInfo.push(zw);
-    for (var i = ROIInfo.length-2; i > aktindex + 1; --i){
-        ROIInfo[i] = ROIInfo[i-1];
-    }
-    aktindex++;
-    ROIInfo[aktindex] = new Object;
-    ROIInfo[aktindex]["pos_ref"] = -1;
-    ROIInfo[aktindex]["name"] = "ROI" + aktindex;
-    ROIInfo[aktindex]["x"] = 1;
-    ROIInfo[aktindex]["y"] = 1;
-    ROIInfo[aktindex]["dx"] = ROIInfo[aktindex-1]["dx"];
-    ROIInfo[aktindex]["dy"] = ROIInfo[aktindex-1]["dy"];
-    ROIInfo[aktindex]["ar"] = ROIInfo[aktindex-1]["ar"];
-    UpdateROIs();
+function newROI() {
+    var sel = document.getElementById("Numbers_value1");
+    var _number= sel.options[sel.selectedIndex].text;
+    sel = document.getElementById("index");
+    var _roialt= sel.options[sel.selectedIndex].text;
+
+    var _roinew = prompt("Please enter name of new ROI", "name");
+
+    if (ROIInfo.length > 0)
+        erg = CreateROI(_number, "digit", sel.selectedIndex, _roinew, 1, 1, ROIInfo[aktindex]["dx"], ROIInfo[aktindex]["dy"]);
+    else
+        erg = CreateROI(_number, "digit", sel.selectedIndex, _roinew, 1, 1, 30, 51);
+
+    if (erg != "")
+        alert(erg);
+    else
+        UpdateROIs(_roinew);
 }
 
 function movePrevious(){
@@ -214,34 +233,66 @@ function ChangeSelection(){
 }
 
 function SaveToConfig(){
-    _enabled = document.getElementById("Category_Digits_enabled").checked;
-    SaveROIToConfig(ROIInfo, "[Digits]", basepath, _enabled);
-    UpdatePage();  
+    _zwcat = getConfigCategory();
+    _zwcat["Digits"]["enabled"] = document.getElementById("Category_Digits_enabled").checked;
+    WriteConfigININew();
+    SaveConfigToServer(basepath);    
 }
 
 
-function UpdateROIs(){
+function UpdateROIs(_sel){
+    document.getElementById("Category_Digits_enabled").checked = true;
+    var sel = document.getElementById("Numbers_value1");
+    var _number = sel.options[sel.selectedIndex].text;
+
+    ROIInfo = getROIInfo("digit", _number);
+    _catzw = getConfigCategory();
+
+    if (_catzw["Digits"]["enabled"] == false) 
+    {
+        document.getElementById("Category_Digits_enabled").checked = false;
+        EnDisableDigits();
+        alert("Digital ROIs are disabled - please enable (Check box top left).\n");
+        return;
+    }
+
     if (ROIInfo.length == 0){
-        alert("There are no ROIs defined.\nPlease first define minimum one ROI in the config.ini by hand.\n");
-        document.getElementById("newROI").disabled = true;
+        alert("There are no ROIs defined.\nPlease first create a new ROI (\"New ROIs ...\").\n");
+        document.getElementById("newROI").disabled = false;
         document.getElementById("deleteROI").disabled = true;
         document.getElementById("index").disabled = true;
         document.getElementById("saveroi").disabled = true;
+        document.getElementById("renameROI").disabled = true;
         document.getElementById("moveNext").disabled = true;
         document.getElementById("movePrevious").disabled = true;
         return;
     }
+    else
+    {
+        document.getElementById("newROI").disabled = false;
+        document.getElementById("deleteROI").disabled = false;
+        document.getElementById("renameROI").disabled = false;
+        document.getElementById("index").disabled = false;
+        document.getElementById("saveroi").disabled = false;
+    }
 
     var _index = document.getElementById("index");
     while (_index.length){
         _index.remove(0);
     }
 
+    if (aktindex > ROIInfo.length)
+        aktindex = ROIInfo.length;
+
     for (var i = 0; i < ROIInfo.length; ++i){
         var option = document.createElement("option");
-        option.text = "ROI " + (i + 1);
+        option.text = ROIInfo[i]["name"];
         option.value = i;
-        _index.add(option); 
+        _index.add(option);
+        if (typeof _sel !== 'undefined') {
+            if (option.text == _sel)
+                aktindex = i;
+        }
     }
     _index.selectedIndex = aktindex; 
 
@@ -258,7 +309,6 @@ function UpdateROIs(){
     
     document.getElementById("lockAR").checked = lockAR;
        
-    document.getElementById("name").value = ROIInfo[aktindex]["name"];
     document.getElementById("refx").value = ROIInfo[aktindex]["x"];
     document.getElementById("refy").value = ROIInfo[aktindex]["y"];  
     document.getElementById("refdx").value = ROIInfo[aktindex]["dx"];  
@@ -269,26 +319,6 @@ function UpdateROIs(){
     rect.h = ROIInfo[aktindex]["dy"];
     draw();      
 }
-
-function ParseIni(_basepath) {
-    loadConfig(_basepath);
-    ParseConfig();
-
-    document.getElementById("Category_Digits_enabled").checked = true;
-    ROIInfo = getROIInfo("[Digits]");
-
-    if (!GetDigitsEnabled()) 
-    {
-        document.getElementById("Category_Digits_enabled").checked = false;
-        EnDisableDigits();
-        alert("Digital ROIs are disabled - please enable (Check box top left).\n");
-        return;
-    }
-
-
-    UpdateROIs();
-}
-			
     
         function loadCanvas(dataURL) {
                 var canvas = document.getElementById('canvas');
@@ -317,8 +347,6 @@ function ParseIni(_basepath) {
             var left = box.left + scrollLeft - clientLeft;
             return { top: Math.round(top), left: Math.round(left) };
         }
-   
-    
     
         function init() {
             basepath = getbasepath();
@@ -326,10 +354,14 @@ function ParseIni(_basepath) {
             canvas.addEventListener('mouseup', mouseUp, false);
             canvas.addEventListener('mousemove', mouseMove, false);
             loadCanvas(basepath + "/fileserver/config/reference.jpg");
-            ParseIni(basepath);
+            loadConfig(basepath); 
+            ParseConfig();
+            param = getConfigParameters(); 
+            UpdateNUMBERS();
             drawImage();
             draw();
         }
+
         function drawImage(){
             var canvas = document.getElementById('canvas');
             var context = canvas.getContext('2d');
@@ -340,6 +372,66 @@ function ParseIni(_basepath) {
 //            context.restore();
         }  
 
+function UpdateNUMBERS(_sel){
+    zw = getNUMBERInfo();
+
+    index = 0;
+
+    var _index = document.getElementById("Numbers_value1");
+    while (_index.length){
+        _index.remove(0);
+    }
+
+    for (var i = 0; i < zw.length; ++i){
+        var option = document.createElement("option");
+        option.text = zw[i]["name"];
+        option.value = i;
+        _index.add(option); 
+
+        if (typeof _sel !== 'undefined') {
+            if (zw[i]["name"] == _sel)
+                index = i
+        }
+    }
+    _index.selectedIndex = index;
+
+    UpdateROIs();
+}
+
+function renameNumber(){
+    var sel = document.getElementById("Numbers_value1");
+    var _delte= sel.options[sel.selectedIndex].text;
+    var _numbernew = prompt("Please enter new name", _delte);
+
+    erg = RenameNUMBER(_delte, _numbernew);
+    if (erg != "")
+        alert(erg);
+    else
+        UpdateNUMBERS(_numbernew);
+}
+
+function newNumber(){
+    var _numbernew = prompt("Please enter name of new number", "name");
+
+    erg = CreateNUMBER(_numbernew);
+    if (erg != "")
+        alert(erg);
+    else
+        UpdateNUMBERS(_numbernew);
+}
+
+
+function removeNumber(){
+	if (confirm("This will remove the number complete (analog and digital).\nIf you only want to remove the digital ROIs, please use \"Delete ROIs\".\nDo you want to proceed?")) {
+        var sel = document.getElementById("Numbers_value1");
+        var _delte= sel.options[sel.selectedIndex].text;
+        erg = DeleteNUMBER(_delte);
+        if (erg != "")
+            alert(erg);
+        UpdateNUMBERS();
+	}	    
+}
+
 
 function draw() {
         var canvas = document.getElementById('canvas');
@@ -468,8 +560,31 @@ function draw() {
         }
     }
 
-    
+    function renameROI(){
+        var sel = document.getElementById("Numbers_value1");
+        var _number= sel.options[sel.selectedIndex].text;
+        sel = document.getElementById("index");
+        var _roialt= sel.options[sel.selectedIndex].text;
+
+
+        var _roinew = prompt("Please enter new name", _roialt);
+
+        erg = RenameROI(_number, "digit", _roialt, _roinew);
+        if (erg != "")
+            alert(erg);
+        else
+            UpdateROIs(_roinew);
+    }
+
+    function numberChanged()
+    {
+        UpdateROIs();
+    }    
+
+
+
     init();
+
 </script>
 
 </body>

+ 1 - 2
sd-card/html/edit_reference.html

@@ -53,7 +53,7 @@ table {
 	  </tr>
 	  <tr>
         <td><label for="mirror">Pre-rotate Angle:</label></td>	  
-		<td><input type="number" id="prerotateangle" name="prerotateangle" value=0 min="-360" max="360" onchange="drawRotated()">Degrees</td>
+		<td><input type="number" id="prerotateangle" name="prerotateangle" value="0" min="-360" max="360" onchange="drawRotated()">Degrees</td>
         <td>
             <class id="MakeImage_Brightness_text" style="color:black;">Brightness: </class>
             <input type="number" id="MakeImage_Brightness_value1" size="13" value=0  min="-2" max="2" style="float: right; clear: both;">
@@ -86,7 +86,6 @@ table {
 
 
     <script type="text/javascript" src="./gethost.js"></script> 
-    <script type="text/javascript" src="./readconfig.js"></script>  
     <script type="text/javascript" src="./readconfigcommon.js"></script>  
     <script type="text/javascript" src="./readconfigparam.js"></script>  
     

+ 4 - 3
sd-card/html/gethost.js

@@ -7,9 +7,10 @@ function getbasepath(){
     var host = window.location.hostname;
     if ((host == "127.0.0.1") || (host == "localhost"))
     {
-//        host = "http://192.168.2.118";          // jomjol interner test
-//        host = "http://192.168.178.26";          // jomjol interner test
-        host = "http://192.168.178.22";          // jomjol interner Real
+//        host = "http://192.168.2.219";          // jomjol interner test
+        host = "http://192.168.178.46";          // jomjol interner test
+//        host = "http://192.168.178.22";          // jomjol interner Real
+
 //        host = ".";                           // jomjol interner localhost   
 
     }

+ 17 - 0
sd-card/html/info.html

@@ -24,8 +24,25 @@ div {
 </head>
 
 <body style="font-family: arial; padding: 0px 10px;">
+<h3>Current</h3>
+<table style="font-family: arial">
+	<tr>
+		<td>
+			Last restart:
+		</td>
+		<td>
+			<div id="gitbranch">
+				<object data="/starttime"></object>
+			</div>
+		</td>
+	</tr>
+	</table>
+
+
+<table style="font-family: arial">
 <h3>Host Info</h3>
 
+
 <table style="font-family: arial">
 	<tr>
 		<td>

Разница между файлами не показана из-за своего большого размера
+ 0 - 1
sd-card/html/jquery-3.5.1.min.js


Разница между файлами не показана из-за своего большого размера
+ 1 - 0
sd-card/html/jquery-3.6.0.min.js


+ 103 - 23
sd-card/html/prevalue_set.html

@@ -36,33 +36,23 @@ input[type=number] {
 	
 </head>
 
-<script src="/jquery-3.5.1.min.js"></script>
-<script>
-  $ (document).ready(function() {
-	$("#prevalue").load("/setPreValue.html");
-  });
-</script>
-
-<script>
-function setprevalue() {
-	var inputVal = document.getElementById("myInput").value;
-	inputVal = inputVal.replace(",", ".");
-	_value = "<object data=" + "/setPreValue.html?value=" + inputVal + " ></object>";
-	document.getElementById("result").innerHTML=_value;
-//	location.reload();	
-}
-</script>
-
 <body style="font-family: arial; padding: 0px 10px;">
 <h3>Set the previous value for consistency check and substitution for NaN</h3>
 
+<class id="Numbers_text" style="font-size: 120%; color:black;"><b>Choose Number: </b>
+<select id="Numbers_value1" onchange="numberChanged()">
+	<option value="0" selected>default</option>
+	<option value="1" >NT</option>
+	<option value="2" >HT</option>
+</select>
+</class>
+
+
 <table style="width:100%">
   <tr>
-    <h2>Current Value:</h2><p>
+    <h3>Current Value:</h3><p>
 	<div id="prevalue"></div>
-  </tr>	 
-  <tr>
-  <h2>Set Value:</h2><p>
+  <h3>Set Value:</h3><p>
     Input (Format = 123.456):<p>
 	PreValue: 
 	 <input type="number" id="myInput" name="myInput"
@@ -72,10 +62,100 @@ function setprevalue() {
 	<button class="button" type="button" onclick="setprevalue()">Set PreValue</button>
   </tr>	
   <tr>
-    <h2>Result:</h2><p>
+    <h3>Result:</h3><p>
 	<div id="result" readonly></div>
   </tr>	 
 
 </table>
 
-</body></html>
+</body></html>
+
+
+<script type="text/javascript" src="./gethost.js"></script> 
+<script type="text/javascript" src="./readconfigcommon.js"></script>  
+<script type="text/javascript" src="./readconfigparam.js"></script>  
+
+<script type="text/javascript">
+ 	var basepath = "http://192.168.178.22"; 
+  var	NUMBERS;
+
+function setprevalue() {
+	var inputVal = document.getElementById("myInput").value;
+	var sel = document.getElementById("Numbers_value1");
+	var _number = sel.options[sel.selectedIndex].text;  
+	inputVal = inputVal.replace(",", ".");
+  	var xhttp = new XMLHttpRequest();
+    try {
+          url = basepath + "/setPreValue.html?value=" + inputVal + "&numbers=" + _number;     
+          xhttp.open("GET", url, false);
+          xhttp.send();
+          response = xhttp.responseText;
+          document.getElementById("result").innerHTML=response;
+     }
+     catch (error)
+     {
+     //          alert("Deleting Config.ini failed");
+     }
+}
+
+function loadPrevalue(_basepath) {
+    var sel = document.getElementById("Numbers_value1");
+    var _number = sel.options[sel.selectedIndex].text;  
+
+     var xhttp = new XMLHttpRequest();
+     try {
+          url = _basepath + '/setPreValue.html?numbers=' + _number;     
+          xhttp.open("GET", url, false);
+          xhttp.send();
+          response = xhttp.responseText;
+          document.getElementById("prevalue").innerHTML=response;
+     }
+     catch (error)
+     {
+     //          alert("Deleting Config.ini failed");
+     }
+     return true;
+}
+
+
+function numberChanged(){
+  loadPrevalue(basepath);
+}
+
+function UpdateNUMBERS(_sel){
+    zw = getNUMBERInfo();
+
+    index = 0;
+
+    var _index = document.getElementById("Numbers_value1");
+    while (_index.length){
+        _index.remove(0);
+    }
+
+    for (var i = 0; i < zw.length; ++i){
+        var option = document.createElement("option");
+        option.text = zw[i]["name"];
+        option.value = i;
+        _index.add(option); 
+
+        if (typeof _sel !== 'undefined') {
+            if (zw[i]["name"] == _sel)
+                index = i
+        }
+    }
+    _index.selectedIndex = index;
+
+    loadPrevalue(basepath);
+}
+
+
+function init(){
+	basepath = getbasepath();
+  loadConfig(basepath); 
+  ParseConfig();
+  UpdateNUMBERS();
+  loadPrevalue(basepath);
+}
+
+init();
+</script>

+ 0 - 427
sd-card/html/readconfig.js

@@ -1,427 +0,0 @@
-function readconfig_Version(){
-     return "1.0.0 - 20200910";
- }
-
-var config_gesamt;
-var config_split;
-var ref = new Array(2);
-var digit = new Array(0);
-var analog = new Array(0);
-var initalrotate = new Object();
-var analogEnabled = false;
-var posAnalogHeader;
-var digitsEnabled = false;
-var posDigitsHeader;
-
-function MakeRefZW(zw, _basepath){
-     _filetarget = zw["name"].replace("/config/", "/img_tmp/");
-     _filetarget = _filetarget.replace(".jpg", "_org.jpg");
-     url = _basepath + "/editflow.html?task=cutref&in=/config/reference.jpg&out="+_filetarget+"&x=" + zw["x"] + "&y="  + zw["y"] + "&dx=" + zw["dx"] + "&dy=" + zw["dy"];
-     var xhttp = new XMLHttpRequest();  
-     try {
-          xhttp.open("GET", url, false);
-          xhttp.send();     }
-     catch (error)
-     {
-//          alert("Deleting Config.ini failed");
-     }
-     _filetarget2 = zw["name"].replace("/config/", "/img_tmp/");
-//     _filetarget2 = _filetarget2.replace(".jpg", "_org.jpg");
-     FileCopyOnServer(_filetarget, _filetarget2, _basepath);
-}
-
-function CopyReferenceToImgTmp(_basepath)
-{
-     for (index = 0; index < 2; ++index)
-     {
-          _filenamevon = ref[index]["name"];
-          _filenamenach = _filenamevon.replace("/config/", "/img_tmp/");
-          FileDeleteOnServer(_filenamenach, _basepath);
-          FileCopyOnServer(_filenamevon, _filenamenach, _basepath);
-     
-          _filenamevon = _filenamevon.replace(".jpg", "_org.jpg");
-          _filenamenach = _filenamenach.replace(".jpg", "_org.jpg");
-          FileDeleteOnServer(_filenamenach, _basepath);
-          FileCopyOnServer(_filenamevon, _filenamenach, _basepath);
-     }
-}
-
-function GetReferencesInfo(){
-     return ref;
-}
-
-function ParseConfigAlignment(_aktline){
-     var akt_ref = 0;
-     ++_aktline;
-
-     while ((_aktline < config_split.length) 
-            && !(config_split[_aktline][0] == "[") 
-            && !((config_split[_aktline][0] == ";") && (config_split[_aktline][1] == "["))) {
-          var linesplit = ZerlegeZeile(config_split[_aktline]);
-          if ((linesplit[0].toUpperCase() == "INITIALMIRROR") && (linesplit.length > 1))
-          {
-              initalrotate["mirror"] = linesplit[1].toUpperCase().localeCompare("TRUE") == 0;
-              initalrotate["pos_config_mirror"] = _aktline;
-          }          
-
-          if (((linesplit[0].toUpperCase() == "INITALROTATE") || (linesplit[0].toUpperCase() == "INITIALROTATE"))  && (linesplit.length > 1))
-          {
-              initalrotate["angle"] = parseInt(linesplit[1]);
-              initalrotate["pos_config"] = _aktline;
-          }          
-          if (linesplit.length == 3)
-          {
-               ref[akt_ref] = new Object();
-               ref[akt_ref]["pos_ref"] = _aktline;
-               ref[akt_ref]["name"] = linesplit[0];
-               ref[akt_ref]["x"] = linesplit[1];
-               ref[akt_ref]["y"] = linesplit[2];
-               akt_ref++;
-          }
-          ++_aktline;
-     }    
-     return _aktline; 
-}
-
-function ParseConfigDigit(_aktline){
-     ++_aktline;
-     digit.length = 0;
-
-     while ((_aktline < config_split.length) 
-            && !(config_split[_aktline][0] == "[") 
-            && !((config_split[_aktline][0] == ";") && (config_split[_aktline][1] == "["))) {
-          var linesplit = ZerlegeZeile(config_split[_aktline]);
-          if (linesplit.length >= 5)
-          {
-               zw = new Object();
-               zw["pos_ref"] = _aktline;
-               zw["name"] = linesplit[0];
-               zw["x"] = linesplit[1];
-               zw["y"] = linesplit[2];
-               zw["dx"] = linesplit[3];
-               zw["dy"] = linesplit[4];
-               zw["ar"] = parseFloat(linesplit[3]) / parseFloat(linesplit[4]);
-               digit.push(zw);
-          }
-          ++_aktline;
-     }    
-     return _aktline; 
-}
-
-function GetAnalogEnabled() {
-     return analogEnabled;
-}
-
-
-function GetDigitsEnabled() {
-     return digitsEnabled;
-}
-
-
-function ParseConfigAnalog(_aktline){
-     ++_aktline;
-     analog.length = 0;
-
-     while ((_aktline < config_split.length) 
-            && !(config_split[_aktline][0] == "[") 
-            && !((config_split[_aktline][0] == ";") && (config_split[_aktline][1] == "["))) {
-          var linesplit = ZerlegeZeile(config_split[_aktline]);
-          if (linesplit.length >= 5)
-          {
-               zw = new Object();
-               zw["pos_ref"] = _aktline;
-               zw["name"] = linesplit[0];
-               zw["x"] = linesplit[1];
-               zw["y"] = linesplit[2];
-               zw["dx"] = linesplit[3];
-               zw["dy"] = linesplit[4];
-               zw["ar"] = parseFloat(linesplit[3]) / parseFloat(linesplit[4]);
-               analog.push(zw);
-          }
-          ++_aktline;
-     }    
-     return _aktline; 
-}
-
-
-function getROIInfo(_typeROI){
-     if (_typeROI == "[Digits]"){
-          targetROI = digit;
-     }
-     if (_typeROI == "[Analog]"){
-          targetROI = analog;
-     }
-     return targetROI.slice();         // Kopie senden, nicht orginal!!!
-}
-
-function SaveROIToConfig(_ROIInfo, _typeROI, _basepath, _enabled){
-     if (_enabled) {
-          text = _typeROI;
-     }
-     else {
-          text = ";" + _typeROI;
-     }
-
-     if (_typeROI == "[Digits]"){
-          config_split[posDigitsHeader] = text;
-          targetROI = digit;
-     }
-
-     if (_typeROI == "[Analog]"){
-          config_split[posAnalogHeader] = text;
-          targetROI = analog;
-     }
-
-     // Abstimmen Anzahl ROIs:
-     var _pos = targetROI[targetROI.length-1]["pos_ref"];
-
-     for (var i = targetROI.length; i < _ROIInfo.length; ++i){
-          var zw = config_split[config_split.length-1];
-          config_split.push(zw);
-          for (var j = config_split.length-2; j > _pos + 1; --j){
-               config_split[j] = config_split[j-1];
-          }
-     }
-
-     for (i = targetROI.length-1; i > _ROIInfo.length-1; --i){
-          var _zwpos = targetROI[i]["pos_ref"];
-          config_split.splice(_zwpos, 1);
-     }
-
-     var linewrite = 0;
-     for (i = 0; i < _ROIInfo.length; ++i){
-          if (i < targetROI.length){
-               linewrite = targetROI[i]["pos_ref"];
-          }
-          else {
-               linewrite++;
-          }
-          config_split[linewrite] = _ROIInfo[i]["name"] + " " + _ROIInfo[i]["x"] + " " + _ROIInfo[i]["y"] + " " + _ROIInfo[i]["dx"] + " " + _ROIInfo[i]["dy"];
-     }
-
-     SaveConfigToServer(_basepath);
-}
-
-
-function ParseConfig() {
-     config_split = config_gesamt.split("\n");
-     var aktline = 0;
-
-     while (aktline < config_split.length){
-          if ((config_split[aktline].trim().toUpperCase() == "[ALIGNMENT]") || (config_split[aktline].trim().toUpperCase() == ";[ALIGNMENT]")){
-               aktline = ParseConfigAlignment(aktline);
-               continue;
-          }
-          if ((config_split[aktline].trim().toUpperCase() == "[DIGITS]") || (config_split[aktline].trim().toUpperCase() == ";[DIGITS]")){
-               posDigitsHeader = aktline;
-               if (config_split[aktline][0] == "[") {
-                    digitsEnabled = true;
-               }
-               aktline = ParseConfigDigit(aktline);
-               continue;
-          }
-
-          if ((config_split[aktline].trim().toUpperCase() == "[ANALOG]") || (config_split[aktline].trim().toUpperCase() == ";[ANALOG]")) {
-               posAnalogHeader = aktline;
-               if (config_split[aktline][0] == "[") {
-                    analogEnabled = true;
-               }
-               aktline = ParseConfigAnalog(aktline);
-               continue;
-          }
-
-          aktline++;
-     }
-}
-
-function getPreRotate(){
-     return initalrotate["angle"];
-}
-
-function setPreRotate(_prerotate){
-     initalrotate["angle"] = _prerotate;
-}
-
-function getMirror(){
-     if (initalrotate.hasOwnProperty("mirror")) {
-          return initalrotate["mirror"];
-     }
-     return false;
-}
-
-function setMirror(_mirror){
-     initalrotate["mirror"] = _mirror;
-}
-
-function SaveCanvasToImage(_canvas, _filename, _delete = true, _basepath = ""){
-     var JPEG_QUALITY=0.8;
-     var dataUrl = _canvas.toDataURL('image/jpeg', JPEG_QUALITY);	
-     var rtn = dataURLtoBlob(dataUrl);
-
-     if (_delete) {
-          FileDeleteOnServer(_filename, _basepath);
-     }
-	
-     FileSendContent(rtn, _filename, _basepath);
-}
-
-function SaveConfigToServer(_basepath){
-     // leere Zeilen am Ende löschen
-     var zw = config_split.length - 1;
-     while (config_split[zw] == "") {
-          config_split.pop();
-     }
-
-     var config_gesamt = "";
-     for (var i = 0; i < config_split.length; ++i)
-     {
-          config_gesamt = config_gesamt + config_split[i] + "\n";
-     } 
-
-     FileDeleteOnServer("/config/config.ini", _basepath);
-
-     FileSendContent(config_gesamt, "/config/config.ini", _basepath);          
-}
-
-function UpdateConfigFileReferenceChange(_basepath){
-     for (var _index = 0; _index < ref.length; ++_index){
-          var zeile = ref[_index]["name"] + " " + ref[_index]["x"] + " " + ref[_index]["y"];
-          var _pos = ref[_index]["pos_ref"];
-          config_split[_pos] = zeile;          
-     }
-
-     zeile = "InitialRotate = " + initalrotate["angle"];
-     var _pos = initalrotate["pos_config"];
-     config_split[_pos] = zeile;
-
-     var mirror = false;
-     if (initalrotate.hasOwnProperty("mirror")) {
-          mirror = initalrotate["mirror"];
-     }
-     var mirror_pos = -1;
-     if (initalrotate.hasOwnProperty("pos_config_mirror")) {
-          mirror_pos = initalrotate["pos_config_mirror"];
-     }     
-     if (mirror_pos > -1) {
-          if (mirror) {
-               config_split[mirror_pos] = "InitialMirror = true";
-          }
-          else {
-               config_split[mirror_pos] = "InitialMirror = false";
-          }
-     }
-     else {
-          if (mirror) {       // neue Zeile muss an der richtigen Stelle eingefügt werden - hier direct nach [Alignment]
-               var aktline = 0;
-
-               while (aktline < config_split.length){
-                    if (config_split[aktline].trim() == "[Alignment]") {
-                         break;
-                    }
-                    aktline++
-               }
-
-               // fuege neue Zeile in config_split ein
-               var zw = config_split[config_split.length-1];
-               config_split.push(zw);
-               for (var j = config_split.length-2; j > aktline + 1; --j){
-                    config_split[j] = config_split[j-1];
-               }
-
-               config_split[aktline + 1] = "InitialMirror = True"
-          }
-     }
-
-     SaveConfigToServer(_basepath);
-}
-
-function UpdateConfigReference(zw, _basepath){
-     for (var index = 0; index < 2; ++index)
-     {
-          var zeile = zw[index]["name"] + " " + zw[index]["x"] + " " + zw[index]["y"];
-          var _pos = zw[index]["pos_ref"];
-          config_split[_pos] = zeile;
-
-          _filenamenach = ref[index]["name"];
-          _filenamevon = _filenamenach.replace("/config/", "/img_tmp/");
-          FileDeleteOnServer(_filenamenach, _basepath);
-          FileCopyOnServer(_filenamevon, _filenamenach, _basepath);
-     
-          _filenamenach = _filenamenach.replace(".jpg", "_org.jpg");
-          _filenamevon = _filenamevon.replace(".jpg", "_org.jpg");
-          FileDeleteOnServer(_filenamenach, _basepath);
-          FileCopyOnServer(_filenamevon, _filenamenach, _basepath);
-
-     }
-
-     SaveConfigToServer(_basepath);
-}
-
-function MakeContrastImageZW(zw, _enhance, _basepath){
-     _filename = zw["name"].replace("/config/", "/img_tmp/");
-     url = _basepath + "/editflow.html?task=cutref&in=/config/reference.jpg&out=" + _filename + "&x=" + zw["x"] + "&y="  + zw["y"] + "&dx=" + zw["dx"] + "&dy=" + zw["dy"];
-     if (_enhance == true){
-          url = url + "&enhance=true";
-     }
-
-     var xhttp = new XMLHttpRequest();  
-     try {
-          xhttp.open("GET", url, false);
-          xhttp.send();     }
-     catch (error)
-     {
-//          alert("Deleting Config.ini failed");
-     }
-}
-
-
-function GetReferenceSize(name){
-     img = new Image();
-     var xhttp = new XMLHttpRequest();
-			
-     url = "http://192.168.178.22/fileserver" + name;
-     xhttp.open("GET", url, false);
-     xhttp.send();
-
-     var response = xhttp.responseText;
-     var binary = ""
-     
-     for (var responseText = xhttp.responseText, responseTextLen = responseText.length, binary = "", i = 0; i < responseTextLen; ++i) {
-          binary += String.fromCharCode(responseText.charCodeAt(i) & 255)
-        }
-     img.src = 'data:image/jpeg;base64,'+ window.btoa(binary);     
-
-     return [img.width, img.height];
-}
-
-	 
-function getConfig() {
-	return config_gesamt;
-     }
-     
-
-
-function dataURLtoBlob(dataurl) {
-     var arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1],
-          bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n);
-     while(n--){
-          u8arr[n] = bstr.charCodeAt(n);
-     }
-     return new Blob([u8arr], {type:mime});
-     }	
-
-                    
-function SaveReferenceImage(_id_canvas, _filename, _doDelete, _basepath = ""){
-     if (_doDelete){
-          FileDeleteOnServer(_filename, _basepath);
-     }
-
-     var canvas = document.getElementById(_id_canvas);
-     var JPEG_QUALITY=0.8;
-     var dataUrl = canvas.toDataURL('image/jpeg', JPEG_QUALITY);	
-     var rtn = dataURLtoBlob(dataUrl);	
-     if (!FileSendContent(rtn, _filename, _basepath)){
-          alert("Error on saving reference image (" + _filename + ")!\nPlease retry.");
-          location.reload();  
-     };  
-}

+ 58 - 61
sd-card/html/readconfigcommon.js

@@ -20,65 +20,7 @@ function SaveConfigToServer(_basepath){
      FileSendContent(config_gesamt, "/config/config.ini", _basepath);          
 }
 
-function UpdateConfigFileReferenceChange(_basepath){
-     for (var _index = 0; _index < ref.length; ++_index){
-          var zeile = ref[_index]["name"] + " " + ref[_index]["x"] + " " + ref[_index]["y"];
-          var _pos = ref[_index]["pos_ref"];
-          config_split[_pos] = zeile;          
-     }
-
-     zeile = "InitialRotate = " + initalrotate["angle"];
-     var _pos = initalrotate["pos_config"];
-     config_split[_pos] = zeile;
-
-     var mirror = false;
-     if (initalrotate.hasOwnProperty("mirror")) {
-          mirror = initalrotate["mirror"];
-     }
-     var mirror_pos = -1;
-     if (initalrotate.hasOwnProperty("pos_config_mirror")) {
-          mirror_pos = initalrotate["pos_config_mirror"];
-     }     
-     if (mirror_pos > -1) {
-          if (mirror) {
-               config_split[mirror_pos] = "InitialMirror = true";
-          }
-          else {
-               config_split[mirror_pos] = "InitialMirror = false";
-          }
-     }
-     else {
-          if (mirror) {       // neue Zeile muss an der richtigen Stelle eingefügt werden - hier direct nach [Alignment]
-               var aktline = 0;
-
-               while (aktline < config_split.length){
-                    if (config_split[aktline].trim() == "[Alignment]") {
-                         break;
-                    }
-                    aktline++
-               }
-
-               // fuege neue Zeile in config_split ein
-               var zw = config_split[config_split.length-1];
-               config_split.push(zw);
-               for (var j = config_split.length-2; j > aktline + 1; --j){
-                    config_split[j] = config_split[j-1];
-               }
-
-               config_split[aktline + 1] = "InitialMirror = True"
-          }
-     }
-
-     SaveConfigToServer(_basepath);
-}
-
 function UpdateConfig(zw, _index, _enhance, _basepath){
-     var zeile = zw["name"] + " " + zw["x"] + " " + zw["y"];
-     var _pos = ref[_index]["pos_ref"];
-     config_split[_pos] = zeile;
-
-     SaveConfigToServer(_basepath);
-
      var namezw = zw["name"];
      FileCopyOnServer("/img_tmp/ref_zw.jpg", namezw, _basepath);
      var namezw = zw["name"].replace(".jpg", "_org.jpg");
@@ -102,10 +44,10 @@ function createReader(file) {
 
 
 
-function ZerlegeZeile(input)
+function ZerlegeZeile(input, delimiter = " =,\t\r")
      {
           var Output = Array(0);
-          delimiter = " =,\r";
+//          delimiter = " =,\t";
      
           input = trim(input, delimiter);
           var pos = findDelimiterPos(input, delimiter);
@@ -164,6 +106,11 @@ function trim(istring, adddelimiter)
      }
      
 
+function getConfig()
+{
+     return config_gesamt;
+}
+
      
 function loadConfig(_basepath) {
      var xhttp = new XMLHttpRequest();
@@ -261,4 +208,54 @@ function FileSendContent(_content, _filename, _basepath = ""){
 //          alert("Deleting Config.ini failed");
      }     
     return okay;        
-}
+}
+
+
+function SaveCanvasToImage(_canvas, _filename, _delete = true, _basepath = ""){
+     var JPEG_QUALITY=0.8;
+     var dataUrl = _canvas.toDataURL('image/jpeg', JPEG_QUALITY);	
+     var rtn = dataURLtoBlob(dataUrl);
+
+     if (_delete) {
+          FileDeleteOnServer(_filename, _basepath);
+     }
+	
+     FileSendContent(rtn, _filename, _basepath);
+}
+
+function MakeContrastImageZW(zw, _enhance, _basepath){
+     _filename = zw["name"].replace("/config/", "/img_tmp/");
+     url = _basepath + "/editflow.html?task=cutref&in=/config/reference.jpg&out=" + _filename + "&x=" + zw["x"] + "&y="  + zw["y"] + "&dx=" + zw["dx"] + "&dy=" + zw["dy"];
+     if (_enhance == true){
+          url = url + "&enhance=true";
+     }
+
+     var xhttp = new XMLHttpRequest();  
+     try {
+          xhttp.open("GET", url, false);
+          xhttp.send();     }
+     catch (error)
+     {
+//          alert("Deleting Config.ini failed");
+     }
+}
+
+
+
+function MakeRefZW(zw, _basepath){
+     _filetarget = zw["name"].replace("/config/", "/img_tmp/");
+     _filetarget = _filetarget.replace(".jpg", "_org.jpg");
+     url = _basepath + "/editflow.html?task=cutref&in=/config/reference.jpg&out="+_filetarget+"&x=" + zw["x"] + "&y="  + zw["y"] + "&dx=" + zw["dx"] + "&dy=" + zw["dy"];
+     var xhttp = new XMLHttpRequest();  
+     try {
+          xhttp.open("GET", url, false);
+          xhttp.send();     }
+     catch (error)
+     {
+//          alert("Deleting Config.ini failed");
+     }
+     _filetarget2 = zw["name"].replace("/config/", "/img_tmp/");
+//     _filetarget2 = _filetarget2.replace(".jpg", "_org.jpg");
+     FileCopyOnServer(_filetarget, _filetarget2, _basepath);
+}
+

+ 418 - 14
sd-card/html/readconfigparam.js

@@ -7,6 +7,8 @@ var config_split;
 var param;
 var category;
 var ref = new Array(2);
+var NUMBERS = new Array(0);
+var REFERENCES = new Array(0);
 
 function ParseConfig() {
      config_split = config_gesamt.split("\n");
@@ -68,11 +70,11 @@ function ParseConfig() {
      category[catname]["enabled"] = false;
      category[catname]["found"] = false;
      param[catname] = new Object();
-     ParamAddValue(param, catname, "DecimalShift");
+     ParamAddValue(param, catname, "DecimalShift", 1, true);
      ParamAddValue(param, catname, "PreValueUse");
      ParamAddValue(param, catname, "PreValueAgeStartup");
      ParamAddValue(param, catname, "AllowNegativeRates");
-     ParamAddValue(param, catname, "MaxRateValue");
+     ParamAddValue(param, catname, "MaxRateValue", 1, true);
      ParamAddValue(param, catname, "ErrorMessage");
      ParamAddValue(param, catname, "CheckDigitIncreaseConsistency");     
 
@@ -82,10 +84,7 @@ function ParseConfig() {
      category[catname]["found"] = false;
      param[catname] = new Object();
      ParamAddValue(param, catname, "Uri");
-     ParamAddValue(param, catname, "Topic");
-     ParamAddValue(param, catname, "TopicError");
-     ParamAddValue(param, catname, "TopicRate");
-     ParamAddValue(param, catname, "TopicTimeStamp");
+     ParamAddValue(param, catname, "MainTopic");
      ParamAddValue(param, catname, "ClientID");
      ParamAddValue(param, catname, "user");
      ParamAddValue(param, catname, "password");     
@@ -115,8 +114,9 @@ function ParseConfig() {
      ParamAddValue(param, catname, "TimeServer");         
      ParamAddValue(param, catname, "AutoAdjustSummertime");
      ParamAddValue(param, catname, "Hostname");   
-     ParamAddValue(param, catname, "SetupMode");   
-
+     ParamAddValue(param, catname, "SetupMode"); 
+     
+     
      while (aktline < config_split.length){
           for (var cat in category) {
                zw = cat.toUpperCase();
@@ -136,16 +136,15 @@ function ParseConfig() {
      }
 }
 
-function ParamAddValue(param, _cat, _param, _anzParam = 1){
+function ParamAddValue(param, _cat, _param, _anzParam = 1, _isIndividual = false){
      param[_cat][_param] = new Object(); 
      param[_cat][_param]["found"] = false;
      param[_cat][_param]["enabled"] = false;
      param[_cat][_param]["line"] = -1; 
      param[_cat][_param]["anzParam"] = _anzParam;    
+     param[_cat][_param]["Numbers"] = _isIndividual;
 };
 
-
-
 function ParseConfigParamAll(_aktline, _catname){
      ++_aktline;
 
@@ -156,6 +155,18 @@ function ParseConfigParamAll(_aktline, _catname){
           let [isCom, input] = isCommented(_input);
           var linesplit = ZerlegeZeile(input);
           ParamExtractValueAll(param, linesplit, _catname, _aktline, isCom);
+          if (!isCom && (linesplit.length == 5) && (_catname == 'Digits'))
+               ExtractROIs(input, "digit");
+          if (!isCom && (linesplit.length == 5) && (_catname == 'Analog'))
+               ExtractROIs(input, "analog");
+          if (!isCom && (linesplit.length == 3) && (_catname == 'Alignment'))
+          {
+               _newref = new Object();
+               _newref["name"] = linesplit[0];
+               _newref["x"] = linesplit[1];
+               _newref["y"] = linesplit[2];
+               REFERENCES.push(_newref);
+          }
 
           ++_aktline;
      }    
@@ -177,14 +188,50 @@ function ParamExtractValue(_param, _linesplit, _catname, _paramname, _aktline, _
 
 function ParamExtractValueAll(_param, _linesplit, _catname, _aktline, _iscom){
      for (var paramname in _param[_catname]) {
-          if ((_linesplit[0].toUpperCase() == paramname.toUpperCase()) && (_linesplit.length > _param[_catname][paramname]["anzParam"]))
+          _param_zw = _linesplit[0].substring(_linesplit[0].length - paramname.length, _linesplit[0].length);
+          if ((_param_zw.toUpperCase() == paramname.toUpperCase()) && (_linesplit.length > _param[_catname][paramname]["anzParam"]))
           {
                _param[_catname][paramname]["found"] = true;
                _param[_catname][paramname]["enabled"] = !_iscom;
                _param[_catname][paramname]["line"] = _aktline;
-               for (var j = 1; j <= _param[_catname][paramname]["anzParam"]; ++j) {
-                    _param[_catname][paramname]["value"+j] = _linesplit[j];
+               if (_param[_catname][paramname]["Numbers"] == true)         // möglicher Multiusage
+               {
+                    abc = getNUMBERS(_linesplit[0]);
+                    abc[_catname][paramname] = new Object;
+                    abc[_catname][paramname]["found"] = true;
+                    abc[_catname][paramname]["enabled"] = !_iscom;
+     
+                    for (var j = 1; j <= _param[_catname][paramname]["anzParam"]; ++j) {
+                         abc[_catname][paramname]["value"+j] = _linesplit[j];
+                         }
+                    if (abc["name"] == "default")
+                    {
+                         _param[_catname][paramname]["found"] = true;
+                         _param[_catname][paramname]["enabled"] = !_iscom;
+                         _param[_catname][paramname]["line"] = _aktline;
+                         for (var j = 1; j <= _param[_catname][paramname]["anzParam"]; ++j) {
+                              _param[_catname][paramname]["value"+j] = _linesplit[j];
+                              }
+                         for (_num in NUMBERS)         // wert mit Default belegen
+                              {
+                                   NUMBERS[_num][_catname][paramname]["found"] = true;
+                                   NUMBERS[_num][_catname][paramname]["enabled"] = !_iscom;
+                                   NUMBERS[_num][_catname][paramname]["line"] = _aktline;
+                                   for (var j = 1; j <= _param[_catname][paramname]["anzParam"]; ++j) {
+                                        NUMBERS[_num][_catname][paramname]["value"+j] = _linesplit[j];
+                                        }
+                                   }
                     }
+               }
+               else
+               {
+                    _param[_catname][paramname]["found"] = true;
+                    _param[_catname][paramname]["enabled"] = !_iscom;
+                    _param[_catname][paramname]["line"] = _aktline;
+                         for (var j = 1; j <= _param[_catname][paramname]["anzParam"]; ++j) {
+                         _param[_catname][paramname]["value"+j] = _linesplit[j];
+                         }
+               }
           }
      }
 }
@@ -193,6 +240,101 @@ function getConfigParameters() {
      return param;
 }
 
+function WriteConfigININew()
+{
+     config_split = new Array(0);
+
+     for (var cat in param) {
+          text = "[" + cat + "]";
+          if (!category[cat]["enabled"]) {
+               text = ";" + text;
+          }
+          config_split.push(text);
+
+          for (var name in param[cat]) {
+               if (param[cat][name]["Numbers"])
+               {
+                    for (_num in NUMBERS)
+                    {
+                         text = NUMBERS[_num]["name"] + "." + name;
+
+                         var text = text + " =" 
+                         
+                         for (var j = 1; j <= param[cat][name]["anzParam"]; ++j) {
+                              if (!(typeof NUMBERS[_num][cat][name]["value"+j] == 'undefined'))
+                                   text = text + " " + NUMBERS[_num][cat][name]["value"+j];
+                              }
+                         if (!NUMBERS[_num][cat][name]["enabled"]) {
+                              text = ";" + text;
+                         }
+                         config_split.push(text);
+                    }
+               }
+               else
+               {
+                    var text = name + " =" 
+                    
+                    for (var j = 1; j <= param[cat][name]["anzParam"]; ++j) {
+                         if (!(typeof param[cat][name]["value"+j] == 'undefined'))
+                              text = text + " " + param[cat][name]["value"+j];
+                         }
+                    if (!param[cat][name]["enabled"]) {
+                         text = ";" + text;
+                    }
+                    config_split.push(text);
+               }
+          }
+          if (cat == "Digits")
+          {
+               for (var _roi in NUMBERS)
+               {
+                    if (NUMBERS[_roi]["digit"].length > 0)
+                    {
+                         for (var _roiddet in NUMBERS[_roi]["digit"])
+                         {
+                              text = NUMBERS[_roi]["name"] + "." + NUMBERS[_roi]["digit"][_roiddet]["name"];
+                              text = text + " " + NUMBERS[_roi]["digit"][_roiddet]["x"];
+                              text = text + " " + NUMBERS[_roi]["digit"][_roiddet]["y"];
+                              text = text + " " + NUMBERS[_roi]["digit"][_roiddet]["dx"];
+                              text = text + " " + NUMBERS[_roi]["digit"][_roiddet]["dy"];
+                              config_split.push(text);
+                         }
+                    }
+               }
+          }
+          if (cat == "Analog")
+          {
+               for (var _roi in NUMBERS)
+               {
+                    if (NUMBERS[_roi]["analog"].length > 0)
+                    {
+                         for (var _roiddet in NUMBERS[_roi]["analog"])
+                         {
+                              text = NUMBERS[_roi]["name"] + "." + NUMBERS[_roi]["analog"][_roiddet]["name"];
+                              text = text + " " + NUMBERS[_roi]["analog"][_roiddet]["x"];
+                              text = text + " " + NUMBERS[_roi]["analog"][_roiddet]["y"];
+                              text = text + " " + NUMBERS[_roi]["analog"][_roiddet]["dx"];
+                              text = text + " " + NUMBERS[_roi]["analog"][_roiddet]["dy"];
+                              config_split.push(text);
+                         }
+                    }
+               }
+          }
+          if (cat == "Alignment")
+          {
+               for (var _roi in REFERENCES)
+               {
+                    text = REFERENCES[_roi]["name"];
+                    text = text + " " + REFERENCES[_roi]["x"];
+                    text = text + " " + REFERENCES[_roi]["y"];
+                    config_split.push(text);
+               }
+          }
+
+          config_split.push("");
+     }
+}
+
 function setConfigParameters(_param, _category = "") {
      for (var cat in _param) {
           for (var name in _param[cat]) {
@@ -275,6 +417,268 @@ function getConfig() {
 function getConfigCategory() {
      return category;
 }
+
+
+
+function ExtractROIs(_aktline, _type){
+     var linesplit = ZerlegeZeile(_aktline);
+     abc = getNUMBERS(linesplit[0], _type);
+     abc["pos_ref"] = _aktline;
+     abc["x"] = linesplit[1];
+     abc["y"] = linesplit[2];
+     abc["dx"] = linesplit[3];
+     abc["dy"] = linesplit[4];
+     abc["ar"] = parseFloat(linesplit[3]) / parseFloat(linesplit[4]);
+}
+
+
+function getNUMBERS(_name, _type, _create = true)
+{
+     _pospunkt = _name.indexOf (".");
+     if (_pospunkt > -1)
+     {
+          _digit = _name.substring(0, _pospunkt);
+          _roi = _name.substring(_pospunkt+1);
+     }
+     else
+     {
+          _digit = "default";
+          _roi = _name;
+     }
+
+     _ret = -1;
+
+     for (i = 0; i < NUMBERS.length; ++i)
+     {
+          if (NUMBERS[i]["name"] == _digit)
+               _ret = NUMBERS[i];
+     }
+
+     if (!_create)         // nicht gefunden und soll auch nicht erzeugt werden, ggf. geht eine NULL zurück
+          return _ret;
+
+     if (_ret == -1)
+     {
+          _ret = new Object();
+          _ret["name"] = _digit;
+          _ret['digit'] = new Array();
+          _ret['analog'] = new Array();
+
+          for (_cat in param)
+               for (_param in param[_cat])
+                    if (param[_cat][_param]["Numbers"] == true){
+                         if (typeof  _ret[_cat] == 'undefined')
+                              _ret[_cat] = new Object();
+                         _ret[_cat][_param] = new Object();
+                         _ret[_cat][_param]["found"] = false;
+                         _ret[_cat][_param]["enabled"] = false;
+                         _ret[_cat][_param]["anzParam"] = param[_cat][_param]["anzParam"]; 
+
+                    }
+
+          NUMBERS.push(_ret);
+     }
+
+     if (typeof _type == 'undefined')             // muss schon existieren !!! - also erst nach Digits / Analog aufrufen
+          return _ret;
+
+     neuroi = new Object();
+     neuroi["name"] = _roi;
+     _ret[_type].push(neuroi);
+
+
+     return neuroi;
+
+}
+
+ 
+
+function CopyReferenceToImgTmp(_basepath)
+{
+     for (index = 0; index < 2; ++index)
+     {
+          _filenamevon = REFERENCES[index]["name"];
+          _filenamenach = _filenamevon.replace("/config/", "/img_tmp/");
+          FileDeleteOnServer(_filenamenach, _basepath);
+          FileCopyOnServer(_filenamevon, _filenamenach, _basepath);
+     
+          _filenamevon = _filenamevon.replace(".jpg", "_org.jpg");
+          _filenamenach = _filenamenach.replace(".jpg", "_org.jpg");
+          FileDeleteOnServer(_filenamenach, _basepath);
+          FileCopyOnServer(_filenamevon, _filenamenach, _basepath);
+     }
+}
+
+function GetReferencesInfo(){
+     return REFERENCES;
+}
+
+
+function UpdateConfigReference(_basepath){
+     for (var index = 0; index < 2; ++index)
+     {
+          _filenamenach = REFERENCES[index]["name"];
+          _filenamevon = _filenamenach.replace("/config/", "/img_tmp/");
+          FileDeleteOnServer(_filenamenach, _basepath);
+          FileCopyOnServer(_filenamevon, _filenamenach, _basepath);
+     
+          _filenamenach = _filenamenach.replace(".jpg", "_org.jpg");
+          _filenamevon = _filenamevon.replace(".jpg", "_org.jpg");
+          FileDeleteOnServer(_filenamenach, _basepath);
+          FileCopyOnServer(_filenamevon, _filenamenach, _basepath);
+
+     }
+}
+
+
+function getNUMBERInfo(){
+     return NUMBERS;
+}
+
+function RenameNUMBER(_alt, _neu){
+     index = -1;
+     found = false;
+     for (i = 0; i < NUMBERS.length; ++i) {
+          if (NUMBERS[i]["name"] == _alt)
+               index = i;
+          if (NUMBERS[i]["name"] == _neu)
+               found = true;
+     }
+
+     if (found)
+          return "Name is already existing - please use another name";
+
+     NUMBERS[index]["name"] = _neu;
+     
+     return "";
+}
+
+function DeleteNUMBER(_delte){
+     if (NUMBERS.length == 1)
+          return "The last number cannot be deleted."
+     
+
+     index = -1;
+     for (i = 0; i < NUMBERS.length; ++i) {
+          if (NUMBERS[i]["name"] == _delte)
+               index = i;
+     }
+
+     if (index > -1) {
+          NUMBERS.splice(index, 1);
+     }
+
+     return "";
+}
+
+function CreateNUMBER(_numbernew){
+     found = false;
+     for (i = 0; i < NUMBERS.length; ++i) {
+          if (NUMBERS[i]["name"] == _numbernew)
+               found = true;
+     }
+
+     if (found)
+          return "Name does already exist, please choose another one!";
+
+     _ret = new Object();
+     _ret["name"] = _numbernew;
+     _ret['digit'] = new Array();
+     _ret['analog'] = new Array();
+
+     for (_cat in param)
+          for (_param in param[_cat])
+               if (param[_cat][_param]["Numbers"] == true){
+                    _ret[_cat] = new Object();
+                    _ret[_cat][_param] = new Object();
+                    _ret[_cat][_param]["found"] = false;
+                    _ret[_cat][_param]["enabled"] = false;
+                    _ret[_cat][_param]["anzParam"] = param[_cat][_param]["anzParam"]; 
+
+               }
+
+     NUMBERS.push(_ret);
+
+     return "";
+}
+
+
+function getROIInfo(_typeROI, _number){
+     index = 0;
+     for (var i = 0; i < NUMBERS.length; ++i)
+          if (NUMBERS[i]["name"] == _number)
+               index = i;
+
+     return NUMBERS[index][_typeROI];         
+}
+
+
+function RenameROI(_number, _type, _alt, _neu){
+     index = -1;
+     found = false;
+     _indexnumber = -1;
+     for (j = 0; j < NUMBERS.length; ++j)
+          if (NUMBERS[j]["name"] == _number)
+               _indexnumber = j;
+
+     for (i = 0; i < NUMBERS[_indexnumber][_type].length; ++i) {
+          if (NUMBERS[_indexnumber][_type][i]["name"] == _alt)
+               index = i;
+          if (NUMBERS[_indexnumber][_type][i]["name"] == _neu)
+               found = true;
+     }
+
+     if (found)
+          return "Name is already existing - please use another name";
+
+     NUMBERS[_indexnumber][_type][index]["name"] = _neu;
+     
+     return "";
+}
+
+function DeleteNUMBER(_delte){
+     if (NUMBERS.length == 1)
+          return "The last number cannot be deleted."
      
 
+     index = -1;
+     for (i = 0; i < NUMBERS.length; ++i) {
+          if (NUMBERS[i]["name"] == _delte)
+               index = i;
+     }
+
+     if (index > -1) {
+          NUMBERS.splice(index, 1);
+     }
+
+     return "";
+}
+
+function CreateROI(_number, _type, _pos, _roinew, _x, _y, _dx, _dy){
+     _indexnumber = -1;
+     for (j = 0; j < NUMBERS.length; ++j)
+          if (NUMBERS[j]["name"] == _number)
+               _indexnumber = j;
+
+
+     found = false;
+     for (i = 0; i < NUMBERS.length; ++i) {
+          if (NUMBERS[_indexnumber][_type]["name"] == _roinew)
+               found = true;
+     }
+
+     if (found)
+          return "ROI does already exist, please choose another name!";
+
+     _ret = new Object();
+     _ret["name"] = _roinew;
+     _ret["x"] = _x;
+     _ret["y"] = _y;
+     _ret["dx"] = _dx;
+     _ret["dy"] = _dy;
+     _ret["ar"] = _dx / _dy;
+
+     NUMBERS[_indexnumber][_type].splice(_pos+1, 0, _ret);
 
+     return "";
+}

BIN
sd-card/html/sd-card - Verknüpfung.lnk


+ 32 - 0
sd-card/html/test.html

@@ -0,0 +1,32 @@
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+</head>
+
+<body style="font-family: arial">
+	testschrift
+  <div id="value"></div>
+</html>
+
+<script type="text/javascript" src="./gethost.js"></script> 
+
+<script type="text/javascript">
+	var basepath = "http://192.168.178.22"; 
+	function testinit(){
+		basepath = getbasepath();
+		url = basepath + '/wasserzaehler.html?all=true';     
+		var xhttp = new XMLHttpRequest();
+		xhttp.onreadystatechange = function() {
+			if (this.readyState == 4 && this.status == 200) {
+			// Typical action to be performed when the document is ready:
+			document.getElementById("value").innerHTML = xhttp.responseText;
+			}
+		};
+		xhttp.open("GET", url, true);
+		xhttp.send();		
+	}
+
+	testinit();
+</script>
+</body>

+ 1 - 1
sd-card/html/version.txt

@@ -1 +1 @@
-6.8.0
+9.1.0

+ 107 - 57
sd-card/html/wasserzaehler_roi.html

@@ -7,7 +7,7 @@
 <style>
 .tg  {border-collapse:collapse;border-spacing:0;width:100%;color: darkslategray;border: inset;height:585px;}
 .tg td{font-size:14px;padding:10px 5px;border-style:solid;border-width:1px;overflow:hidden;word-break:normal;}
-.tg th{height: 55px;font-size:24px;font-weight:bold;text-align:left;padding:0px 5px;border-style:solid;border-width:1px;overflow:hidden;word-break:normal;background-color:#f0f0f0}
+.tg th{height: 50px;font-size:24px;font-weight:bold;text-align:left;padding:0px 5px;border-style:solid;border-width:1px;overflow:hidden;word-break:normal;background-color:#f0f0f0}
 .tg .tg-1{width:77%;font-size:20px;font-family:Arial, Helvetica, sans-serif !important;border: inset;}
 .tg .tg-2{font-size:20px;font-family:Arial, Helvetica, sans-serif !important;border: inset;}
 .tg .tg-3{height: 15px;font-size:14px;font-family:Arial, Helvetica, sans-serif !important;border: inset;}		
@@ -15,27 +15,72 @@
 
 </head>
 
-<script src="/jquery-3.5.1.min.js"></script>
+<body style="font-family: arial">
 
-<script>
-	function addZero(i) {
+<table class="tg">
+  <tr>
+    <td class="tg-1" rowspan="9"><div id="img"></div></td>
+    <th class="th">Value:</th>
+  </tr>	
+  <tr>	
+    <td class="tg-2">
+	<div id="value"></div>
+	</td>	
+  </tr>
+  <tr>
+    <th class="th">Previous Value:</th>
+  </tr>	
+  <tr>	
+    <td class="tg-2">
+	<div id="prevalue"></div>
+	</td>	
+  </tr>
+
+  <tr>
+    <th class="th">Raw Value:</th>
+  </tr>	
+  <tr>	
+    <td class="tg-2">
+	<div id="raw"></div>
+	</td>	
+  </tr>
+  <tr>
+    <th class="th">Error:</th>
+  </tr>	
+  <tr>	
+    <td class="tg-2">
+	<div id="error"></div>
+	</td>	
+  </tr> 
+  <tr>	
+    <td class="tg-3">
+	<div id="timestamp" ></div>	
+	</td>	
+  </tr>    
+</table>
+
+</body>
+</html>
+
+<script src="/jquery-3.6.0.min.js"></script>
+<script type="text/javascript" src="./gethost.js"></script> 
+<script type="text/javascript" src="./readconfigcommon.js"></script> 
+<script type="text/javascript">
+
+function addZero(i) {
 	  if (i < 10) {
 		i = "0" + i;
 	  }
 	  return i;
 	}
 
-	$ (document).ready(function() {
+	$(document).ready(function() {
 	var d = new Date();
 	var h = addZero(d.getHours());
 	var m = addZero(d.getMinutes());
 	var s = addZero(d.getSeconds());
 
 	$('#img').html('<img src="/img_tmp/alg_roi.jpg" style="max-height:555px; display:block; margin-left:auto;  margin-right:auto;"></img>');
-	$("#raw").load("/wasserzaehler.html?rawvalue=true");
-	$("#corrected").load("/wasserzaehler.html");
-	$("#checked").load("/setPreValue.html");
-	$("#start").load("/starttime");
 	$('#timestamp').html("Last Page Refresh:" + (h + ":" + m + ":" + s));
 	refresh();
 	});
@@ -50,58 +95,63 @@
 	var s = addZero(d.getSeconds());	
 	// reassign the url to be like alg_roi.jpg?timestamp=456784512 based on timestamp
 	$('#img').html('<img src="/img_tmp/alg_roi.jpg?timestamp='+ timestamp +'"max-height:555px; display:block; margin-left:auto;  margin-right:auto;"></img>');
-	$("#raw").load("/wasserzaehler.html?rawvalue=true");
-	$("#corrected").load("/wasserzaehler.html");
-	$("#checked").load("/setPreValue.html");
-	$("#start").load("/starttime");
 	$('#timestamp').html("Last Page Refresh:" + (h + ":" + m + ":" + s));
+	init();
 	  refresh();
 	}, 300000);
+
   }
-</script>
 
-<body style="font-family: arial">
+	var basepath = "http://192.168.178.22"; 
 
-<table class="tg">
-  <tr>
-    <td class="tg-1" rowspan="9"><div id="img"></div></td>
-    <th class="th">Raw Value:</th>
-  </tr>	
-  <tr>	
-    <td class="tg-2">
-	<div id="raw"></div>
-	</td>	
-  </tr>
-  <tr>
-    <th class="th">Corrected Value:</th>
-  </tr>	
-  <tr>	
-    <td class="tg-2">
-	<div id="corrected"></div>
-	</td>	
-  </tr>
-  <tr>
-    <th class="th">Checked Value:</th>
-  </tr>	
-  <tr>	
-    <td class="tg-2">
-	<div id="checked"></div>
-	</td>	
-  </tr> 
-   <tr>
-    <th class="th">Start Time:</th>
-  </tr>	
-  <tr>	
-    <td class="tg-2">
-	<div id="start"></div>	
-	</td>	
-  </tr> 
-  <tr>	
-    <td class="tg-3">
-	<div id="timestamp"></div>	
-	</td>	
-  </tr>    
-</table>
+	function loadValue(_type, _div, _style) {
+		url = basepath + '/wasserzaehler.html?all=true&type=' + _type;     
+		var xhttp = new XMLHttpRequest();
+		xhttp.onreadystatechange = function() {
+			if (this.readyState == 4 && this.status == 200) {
+			var _rsp = xhttp.responseText;
+			var _split = _rsp.split("\r");
+			if (typeof _style == undefined)
+				out = "<table>";
+			else
+				out = "<table style=\"" + _style + "\">";
 
-</body>
-</html>
+			if (_split.length == 1)
+			{
+				var _zer = ZerlegeZeile(_split[0], "\t")
+				if (_zer.length > 1)
+					out = _zer[1]; 
+				else
+					out = ""; 
+			}
+			else
+			{
+				for (var j = 0; j < _split.length; ++j)
+				{
+					var _zer = ZerlegeZeile(_split[j], "\t")
+					if (_zer.length == 1)
+						out = out + "<tr><td>" + _zer[0] + "</td><td> </td></tr>"; 
+					else
+						out = out + "<tr><td>" + _zer[0] + "</td><td>" + _zer[1] + "</td></tr>"; 
+				}
+				out = out + "</table>"
+
+				}
+			document.getElementById(_div).innerHTML = out;
+			}
+		};
+		xhttp.open("GET", url, true);
+		xhttp.send();		
+	}
+
+	function init(){
+		basepath = getbasepath();
+		loadValue("value", "value");
+		loadValue("raw", "raw");
+		loadValue("prevalue", "prevalue");
+		loadValue("error", "error", "font-size:8px");
+	}
+
+	init();
+
+</script>

Некоторые файлы не были показаны из-за большого количества измененных файлов