Эх сурвалжийг харах

Merge pull request #216 from jomjol/rolling

Update to v7.0.0
jomjol 4 жил өмнө
parent
commit
1e09bfbb80

+ 79 - 1
Changelog.md

@@ -1,5 +1,83 @@
 # Versions
 
+
+
+##### 6.7.2 Image Processing in Memory - (2021-05-01)
+
+* NEW 6.7.2: Updated html for setup modus - remove reboot on edit configuration)
+
+* NEW 6.7.1: Improved stability of camera (back to v6.6.1) - remove black strips and areas
+
+* Upgrade digital CNN to v8.3.0  (added new type of digits)
+
+* Internal update: TFlite (v2.5), esp32cam, startup sequence
+
+* Rollback to espressif v2.1.0, as v3.2.0 shows unstable reboot
+
+* Bugfix: WLan-passwords, reset of hostname
+
+
+##### 6.6.1 Image Processing in Memory - (2021-04-05)
+
+* NEW 6.6.1: failed SD card initialization indicated by fast blinking LED at startup
+* Improved SD-card handling (increase compatibility with more type of cards)
+
+##### 6.5.0 Image Processing in Memory - (2021-03-25)
+
+* Upgrade digital CNN to v8.2.0  (added new type of digits)
+* Supporting alignment structures in ROI definition
+* Bug fixing: definition of  hostname in `config.ini`
+
+##### 6.4.0 Image Processing in Memory - (2021-03-20)
+
+* Additional alignment marks for settings the ROIs (analog and digit)
+* Upgrade analog CNN to v7.0.0 (added new type of pointer)
+
+##### 6.3.1 Image Processing in Memory - (2021-03-16)
+
+* NEW: 6.3.1: bug fixing in initial edit reference image and `config.ini` (Spelling error in `InitialRotate`)
+* Initial setup mode: bug fixing, error correction
+* Bug-fixing
+
+##### 6.2.2 Image Processing in Memory - (2021-03-10)
+
+* NEW 6.2.2: bug fixing
+* NEW 6.2.1: Changed brightness and contrast to default if not enabled (resolves to bright images)
+* Determination of fixed illumination settings during startup - speed up of 5s in each run
+* Update digital CNN to v8.1.1 (additional digital images trained)
+* Extended error message in MQTT error message
+
+
+* Image brightness is now adjustable 
+
+
+* Bug fixing: minor topics 
+
+
+##### 6.1.0 Image Processing in Memory - (2021-01-20)
+
+* Disabling of analog / digital counters in configuration 
+* Improved Alignment Algorithm (`AlignmentAlgo`  = `Default`,  `Accurate` , `Fast`)
+* Analog counters: `ExtendedResolution` (last digit is extended by sub comma value of CNN)
+* `config.ini`: additional parameter `hostname`  (additional to wlan.ini)
+* Switching of GPIO12/13 via http-interface: `/GPIO?GPIO=12&Status=high/low`
+* Bug fixing: html configuration page, wlan password ("=" now possible)
+
+##### 6.0.0 Image Processing in Memory - (2021-01-02)
+
+* **Major change**: image processing fully in memory - no need of SD card buffer anymore
+
+  * Need to limit camera resolution to VGA (due to memory limits)
+* MQTT: Last Will Testament (LWT) implemented: "connection lost" in case of connection lost to `TopicError`
+* Disabled `CheckDigitIncreaseConsistency` in default configuration - must now be explicit enabled if needed
+* Update digital CNN to v7.2.1 (additional digital images trained) 
+* Setting of arbitrary time server in `config.ini`
+* Option for fixed IP-, DNS-Settings in `wlan.ini`
+* Increased stability (internal image and camera handling)
+* Bug fixing: edit digits, handling PreValue, html-bugs
+
+
+
 ##### 5.0.0 Setup Modus - (2020-12-06)
 
 * Implementation of initial setup modus for fresh installation
@@ -127,4 +205,4 @@
 
 ##### 0.1.0 (2020-08-07)
 
-* Initial Version
+* Initial Version

+ 7 - 71
README.md

@@ -45,82 +45,16 @@ In other cases you can contact the developer via email: <img src="https://raw.gi
 
 
 
-##### 6.7.2 Image Processing in Memory - (2021-01-05)
+##### 7.0.0 MQTT-Update - (2021-05-08)
 
-* NEW 6.7.2: Updated html for setup modus - remove reboot on edit configuration)
+* Upgrade digital CNN to v8.5.0  (added new images)
+* New MQTT topics: flow rate (units/minute), time stamp (last correct read readout)
 
-* NEW 6.7.1: Improved stability of camera (back to v6.6.1) - remove black strips and areas
+* Update MQTT/Error topic to " " in case no error (instead of empty string)
 
-* Upgrade digital CNN to v8.3.0  (added new type of digits)
+* Portrait or landscape image orientation in rotated image (avoid cropping)
 
-* Internal update: TFlite (v2.5), esp32cam, startup sequence
-
-* Rollback to espressif v2.1.0, as v3.2.0 shows unstable reboot
-
-* Bugfix: WLan-passwords, reset of hostname
-
-  
-
-##### 6.6.1 Image Processing in Memory - (2021-04-05)
-
-* NEW 6.6.1: failed SD card initialization indicated by fast blinking LED at startup
-* Improved SD-card handling (increase compatibility with more type of cards)
-
-##### 6.5.0 Image Processing in Memory - (2021-03-25)
-
-* Upgrade digital CNN to v8.2.0  (added new type of digits)
-* Supporting alignment structures in ROI definition
-* Bug fixing: definition of  hostname in `config.ini`
-
-##### 6.4.0 Image Processing in Memory - (2021-03-20)
-
-* Additional alignment marks for settings the ROIs (analog and digit)
-* Upgrade analog CNN to v7.0.0 (added new type of pointer)
-
-##### 6.3.1 Image Processing in Memory - (2021-03-16)
-
-* NEW: 6.3.1: bug fixing in initial edit reference image and `config.ini` (Spelling error in `InitialRotate`)
-* Initial setup mode: bug fixing, error correction
-* Bug-fixing
-
-##### 6.2.2 Image Processing in Memory - (2021-03-10)
-
-* NEW 6.2.2: bug fixing
-* NEW 6.2.1: Changed brightness and contrast to default if not enabled (resolves to bright images)
-* Determination of fixed illumination settings during startup - speed up of 5s in each run
-* Update digital CNN to v8.1.1 (additional digital images trained)
-* Extended error message in MQTT error message
-
-
-* Image brightness is now adjustable 
-
-
-* Bug fixing: minor topics 
-
-
-##### 6.1.0 Image Processing in Memory - (2021-01-20)
-
-* Disabling of analog / digital counters in configuration 
-* Improved Alignment Algorithm (`AlignmentAlgo`  = `Default`,  `Accurate` , `Fast`)
-* Analog counters: `ExtendedResolution` (last digit is extended by sub comma value of CNN)
-* `config.ini`: additional parameter `hostname`  (additional to wlan.ini)
-* Switching of GPIO12/13 via http-interface: `/GPIO?GPIO=12&Status=high/low`
-* Bug fixing: html configuration page, wlan password ("=" now possible)
-
-##### 6.0.0 Image Processing in Memory - (2021-01-02)
-
-* **Major change**: image processing fully in memory - no need of SD card buffer anymore
   
-  * Need to limit camera resolution to VGA (due to memory limits)
-* MQTT: Last Will Testament (LWT) implemented: "connection lost" in case of connection lost to `TopicError`
-* Disabled `CheckDigitIncreaseConsistency` in default configuration - must now be explicit enabled if needed
-* Update digital CNN to v7.2.1 (additional digital images trained) 
-* Setting of arbitrary time server in `config.ini`
-* Option for fixed IP-, DNS-Settings in `wlan.ini`
-* Increased stability (internal image and camera handling)
-* Bug fixing: edit digits, handling PreValue, html-bugs
-
-
 
 
 ## Additional ideas
@@ -133,6 +67,8 @@ There are some ideas and feature request, which are not followed currently - mai
 
 ## History
 
+##### 6.7.2 Image Processing in Memory - (2021-05-01)
+
 ##### 5.0.0 Setup Modus - (2020-12-06)
 
 ##### 4.1.1 Configuration editor - (2020-12-02)

+ 21 - 3
code/components/jomjol_flowcontroll/ClassFlowAlignment.cpp

@@ -19,6 +19,7 @@ void ClassFlowAlignment::SetInitialParameter(void)
     initalrotate = 0;
     anz_ref = 0;
     initialmirror = false;
+    initialflip = false;
     SaveAllFiles = false;
     namerawimage =  "/sdcard/img_tmp/raw.jpg";
     FileStoreRefAlignment = "/sdcard/config/align.txt";
@@ -72,6 +73,11 @@ bool ClassFlowAlignment::ReadParameter(FILE* pfile, string& aktparamgraph)
     while (this->getNextLine(pfile, &aktparamgraph) && !this->isNewParagraph(aktparamgraph))
     {
         zerlegt = ZerlegeZeile(aktparamgraph);
+        if ((toUpper(zerlegt[0]) == "FLIPIMAGESIZE") && (zerlegt.size() > 1))
+        {
+            if (toUpper(zerlegt[1]) == "TRUE")
+                initialflip = true;
+        }
         if ((toUpper(zerlegt[0]) == "INITIALMIRROR") && (zerlegt.size() > 1))
         {
             if (toUpper(zerlegt[1]) == "TRUE")
@@ -153,7 +159,13 @@ bool ClassFlowAlignment::doFlow(string time)
         delete AlignAndCutImage;
     AlignAndCutImage = new CAlignAndCutImage(ImageBasis, ImageTMP);   
 
-    CRotateImage rt(AlignAndCutImage, ImageTMP);
+    CRotateImage rt(AlignAndCutImage, ImageTMP, initialflip);
+    if (initialflip)
+    {
+        int _zw = ImageBasis->height;
+        ImageBasis->height = ImageBasis->width;
+        ImageBasis->width = _zw;
+    }
 
     if (initialmirror){
         printf("do mirror\n");
@@ -161,7 +173,7 @@ bool ClassFlowAlignment::doFlow(string time)
         if (SaveAllFiles) AlignAndCutImage->SaveToFile(FormatFileName("/sdcard/img_tmp/mirror.jpg"));
     }
  
-    if (initalrotate != 0)
+    if ((initalrotate != 0) || initialflip)
     {
         rt.Rotate(initalrotate);
         if (SaveAllFiles) AlignAndCutImage->SaveToFile(FormatFileName("/sdcard/img_tmp/rot.jpg"));
@@ -176,6 +188,12 @@ bool ClassFlowAlignment::doFlow(string time)
 
     if (SaveAllFiles)
     {
+        if (initialflip)
+        {
+            int _zw = ImageTMP->width;
+            ImageTMP->width = ImageTMP->height;
+            ImageTMP->height = _zw;
+        }
         DrawRef(ImageTMP);
         ImageTMP->SaveToFile(FormatFileName("/sdcard/img_tmp/alg_roi.jpg"));
     }
@@ -209,7 +227,7 @@ void ClassFlowAlignment::SaveReferenceAlignmentValues()
         time(&rawtime);
         timeinfo = localtime(&rawtime);
 
-        strftime(buffer, 80, "%Y-%m-%d_%H-%M-%S", timeinfo);
+        strftime(buffer, 80, "%Y-%m-%dT%H:%M:%S", timeinfo);
         zwtime = std::string(buffer);
     }
 

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

@@ -15,6 +15,7 @@ class ClassFlowAlignment :
 protected:
     float initalrotate;
     bool initialmirror;
+    bool initialflip;
     RefInfo References[2];
     int anz_ref;
     string namerawimage;

+ 27 - 0
code/components/jomjol_flowcontroll/ClassFlowMQTT.cpp

@@ -11,6 +11,8 @@ void ClassFlowMQTT::SetInitialParameter(void)
     uri = "";
     topic = "";
     topicError = "";
+    topicRate = "";
+    topicTimeStamp = "";
     clientname = "watermeter";
     OldValue = "";
     flowpostprocessing = NULL;  
@@ -94,6 +96,15 @@ bool ClassFlowMQTT::ReadParameter(FILE* pfile, string& aktparamgraph)
         {
             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];
@@ -114,12 +125,16 @@ bool ClassFlowMQTT::doFlow(string zwtime)
 {
     std::string result;
     std::string resulterror = "";
+    std::string resultrate = "";
+    std::string resulttimestamp = "";
     string zw = "";
     
     if (flowpostprocessing)
     {
         result =  flowpostprocessing->getReadoutParam(false, true);
         resulterror = flowpostprocessing->getReadoutError();
+        resultrate = flowpostprocessing->getReadoutRate();
+        resulttimestamp = flowpostprocessing->getReadoutTimeStamp();
     }
     else
     {
@@ -139,9 +154,21 @@ bool ClassFlowMQTT::doFlow(string zwtime)
     MQTTPublish(topic, result);
 
     if (topicError.length() > 0) {
+        if (resulterror.length() == 0)
+        {
+            resulterror = " ";
+        }
         MQTTPublish(topicError, resulterror);
     }
 
+    if (topicRate.length() > 0) {
+        MQTTPublish(topicRate, resultrate);
+    }
+
+    if (topicRate.length() > 0) {
+        MQTTPublish(topicTimeStamp, resulttimestamp);
+    }
+
     OldValue = result;
     
     return true;

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

@@ -9,7 +9,7 @@ class ClassFlowMQTT :
     public ClassFlow
 {
 protected:
-    std::string uri, topic, topicError, clientname;
+    std::string uri, topic, topicError, clientname, topicRate, topicTimeStamp;
     std::string OldValue;
 	ClassFlowPostProcessing* flowpostprocessing;  
     std::string user, password;  

+ 4 - 0
code/components/jomjol_flowcontroll/ClassFlowMakeImage.cpp

@@ -19,6 +19,10 @@ esp_err_t ClassFlowMakeImage::camera_capture(){
 
 void ClassFlowMakeImage::takePictureWithFlash(int flashdauer)
 {
+    // für den Fall, dass das Bild geflippt wird, muss es hier zurück gesetzt werden ////
+    rawImage->width = image_width;          
+    rawImage->height = image_height;
+    /////////////////////////////////////////////////////////////////////////////////////
     Camera.CaptureToBasisImage(rawImage, flashdauer);
     if (SaveAllFiles) rawImage->SaveToFile(namerawimage);
 }

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

@@ -63,7 +63,7 @@ bool ClassFlowPostProcessing::LoadPreValue(void)
     int yy, month, dd, hh, mm, ss;
     struct tm whenStart;
 
-    sscanf(zwtime.c_str(), "%d-%d-%d_%d-%d-%d", &yy, &month, &dd, &hh, &mm, &ss);
+    sscanf(zwtime.c_str(), "%d-%d-%dT%d:%d:%d", &yy, &month, &dd, &hh, &mm, &ss);
     whenStart.tm_year = yy - 1900;
     whenStart.tm_mon = month - 1;
     whenStart.tm_mday = dd;
@@ -74,10 +74,9 @@ bool ClassFlowPostProcessing::LoadPreValue(void)
 
     tStart = mktime(&whenStart);
 
-    time_t now;
-    time(&now);
-    localtime(&now);
-    double difference = difftime(now, tStart);
+    time(&lastvalue);
+    localtime(&lastvalue);
+    double difference = difftime(lastvalue, tStart);
     difference /= 60;
     if (difference > PreValueAgeStartup)
         return false;
@@ -122,13 +121,17 @@ void ClassFlowPostProcessing::SavePreValue(float value, string zwtime)
         time(&rawtime);
         timeinfo = localtime(&rawtime);
 
-        strftime(buffer, 80, "%Y-%m-%d_%H-%M-%S", timeinfo);
-        zwtime = std::string(buffer);
+        strftime(buffer, 80, "%Y-%m-%dT%H:%M:%S", timeinfo);
+        timeStamp = std::string(buffer);
+    }
+    else
+    {
+        timeStamp = zwtime;
     }
 
     PreValue = value;
 
-    fputs(zwtime.c_str(), pFile);
+    fputs(timeStamp.c_str(), pFile);
     fputs("\n", pFile);
     fputs(to_string(value).c_str(), pFile);
     fputs("\n", pFile);
@@ -139,6 +142,7 @@ void ClassFlowPostProcessing::SavePreValue(float value, string zwtime)
 
 ClassFlowPostProcessing::ClassFlowPostProcessing(std::vector<ClassFlow*>* lfc)
 {
+    FlowRateAct = 0;
     PreValueUse = false;
     PreValueAgeStartup = 30;
     AllowNegativeRates = false;
@@ -150,6 +154,7 @@ ClassFlowPostProcessing::ClassFlowPostProcessing(std::vector<ClassFlow*>* lfc)
     checkDigitIncreaseConsistency = false;
     DecimalShift = 0;    
     ErrorMessageText = "";
+    timeStamp = "";
     FilePreValue = FormatFileName("/sdcard/config/prevalue.ini");
     ListFlowControll = lfc;
 }
@@ -300,7 +305,7 @@ bool ClassFlowPostProcessing::doFlow(string zwtime)
     timeinfo = localtime(&imagetime);
 
     char strftime_buf[64];
-    strftime(strftime_buf, sizeof(strftime_buf), "%Y-%m-%d_%H-%M-%S", timeinfo);
+    strftime(strftime_buf, sizeof(strftime_buf), "%Y-%m-%dT%H:%M:%S", timeinfo);
     zwtime = std::string(strftime_buf);
 
 
@@ -343,12 +348,15 @@ bool ClassFlowPostProcessing::doFlow(string zwtime)
 
             PreValueOkay = true;
             PreValue = Value;
-            
+            time(&lastvalue);
+            localtime(&lastvalue);
+
             SavePreValue(Value, zwtime);
         }
         return true;
     }
 
+
     zw = ErsetzteN(ReturnRawValue); 
 
     Value = std::stof(zw);
@@ -373,6 +381,7 @@ bool ClassFlowPostProcessing::doFlow(string zwtime)
         zwvalue = RundeOutput(Value, AnzahlAnalog - DecimalShift);
     }
 
+
     ReturnValueNoError = zwvalue;
     ReturnValue = zwvalue;
     if (ErrorMessage && (ErrorMessageText.length() > 0))
@@ -380,10 +389,15 @@ bool ClassFlowPostProcessing::doFlow(string zwtime)
 
     if (ErrorMessageText.length() == 0)
     {
+        time_t currenttime;
+        time(&currenttime);
+        localtime(&currenttime);
+        double difference = difftime(currenttime, lastvalue);      // in Sekunden
+        difference /= 60;                                          // in Minuten
+        FlowRateAct = (Value - PreValue) / difference;
+
         PreValue = Value;
-        
         SavePreValue(Value, zwtime);
-       
     }
     return true;
 }
@@ -506,6 +520,16 @@ float ClassFlowPostProcessing::checkDigitConsistency(float input, int _decilamsh
     return input;
 }
 
+string ClassFlowPostProcessing::getReadoutRate()
+{
+    return std::to_string(FlowRateAct);
+}
+
+string ClassFlowPostProcessing::getReadoutTimeStamp()
+{
+   return timeStamp; 
+}
+
 
 string ClassFlowPostProcessing::getReadoutError() 
 {

+ 6 - 0
code/components/jomjol_flowcontroll/ClassFlowPostProcessing.h

@@ -17,6 +17,9 @@ protected:
     bool PreValueOkay;
     bool checkDigitIncreaseConsistency;
     int DecimalShift;
+    time_t lastvalue;
+    float FlowRateAct;          // m3 / min
+
 
     string FilePreValue;
     float PreValue;             // letzter Wert, der gut ausgelesen wurde
@@ -25,6 +28,7 @@ protected:
     string ReturnValue;         // korrigierter Rückgabewert, ggf. mit Fehlermeldung
     string ReturnValueNoError;  // korrigierter Rückgabewert ohne Fehlermeldung
     string ErrorMessageText;        // Fehlermeldung bei Consistency Check
+    string timeStamp;
 
     bool LoadPreValue(void);
     string ShiftDecimal(string in, int _decShift);
@@ -40,6 +44,8 @@ public:
     string getReadout();
     string getReadoutParam(bool _rawValue, bool _noerror);
     string getReadoutError();
+    string getReadoutRate();
+    string getReadoutTimeStamp();
     void SavePreValue(float value, string time = "");
     string GetPreValue();
 

+ 33 - 4
code/components/jomjol_image_proc/CRotateImage.cpp

@@ -1,7 +1,7 @@
 #include "CRotateImage.h"
 
 
-CRotateImage::CRotateImage(CImageBasis *_org, CImageBasis *_temp)
+CRotateImage::CRotateImage(CImageBasis *_org, CImageBasis *_temp, bool _flip)
 {
     rgb_image = _org->rgb_image;
     channels = _org->channels;
@@ -9,8 +9,10 @@ CRotateImage::CRotateImage(CImageBasis *_org, CImageBasis *_temp)
     height = _org->height;
     bpp = _org->bpp;
     externalImage = true;   
-    ImageTMP = _temp;    
+    ImageTMP = _temp;   
+    ImageOrg = _org; 
     islocked = false;
+    doflip = _flip;
 }
 
 void CRotateImage::Mirror(){
@@ -58,12 +60,33 @@ void CRotateImage::Mirror(){
 
 void CRotateImage::Rotate(float _angle, int _centerx, int _centery)
 {
+    int org_width, org_height;
     float m[2][3];
 
     float x_center = _centerx;
     float y_center = _centery;
     _angle = _angle / 180 * M_PI;
 
+    if (doflip)
+    {
+        org_width = width;
+        org_height = height;
+        height = org_width;
+        width = org_height;
+        x_center =  x_center - (org_width/2) + (org_height/2);
+        y_center =  y_center + (org_width/2) - (org_height/2);
+        if (ImageOrg)
+        {
+            ImageOrg->height = height;
+            ImageOrg->width = width;
+        }
+    }
+    else
+    {
+        org_width = width;
+        org_height = height;
+    }
+
     m[0][0] = cos(_angle);
     m[0][1] = sin(_angle);
     m[0][2] = (1 - m[0][0]) * x_center - m[0][1] * y_center;
@@ -72,6 +95,12 @@ void CRotateImage::Rotate(float _angle, int _centerx, int _centery)
     m[1][1] = m[0][0];
     m[1][2] = m[0][1] * x_center + (1 - m[0][0]) * y_center;
 
+    if (doflip)
+    {
+        m[0][2] = m[0][2] + (org_width/2) - (org_height/2);
+        m[1][2] = m[1][2] - (org_width/2) + (org_height/2);
+    }
+
     int memsize = width * height * channels;
     uint8_t* odata;
     if (ImageTMP)
@@ -101,9 +130,9 @@ void CRotateImage::Rotate(float _angle, int _centerx, int _centery)
             x_source += int(m[0][2]);
             y_source += int(m[1][2]);
 
-            if ((x_source >= 0) && (x_source < width) && (y_source >= 0) && (y_source < height))
+            if ((x_source >= 0) && (x_source < org_width) && (y_source >= 0) && (y_source < org_height))
             {
-                p_source = rgb_image + (channels * (y_source * width + x_source));
+                p_source = rgb_image + (channels * (y_source * org_width + x_source));
                 for (int _channels = 0; _channels < channels; ++_channels)
                     p_target[_channels] = p_source[_channels];
             }

+ 5 - 4
code/components/jomjol_image_proc/CRotateImage.h

@@ -4,10 +4,11 @@
 class CRotateImage: public CImageBasis
 {
     public:
-        CImageBasis *ImageTMP;
-        CRotateImage(std::string _image) : CImageBasis(_image) {ImageTMP = NULL;};
-        CRotateImage(uint8_t* _rgb_image, int _channels, int _width, int _height, int _bpp) : CImageBasis(_rgb_image, _channels, _width, _height, _bpp) {ImageTMP = NULL;};
-        CRotateImage(CImageBasis *_org, CImageBasis *_temp);
+        CImageBasis *ImageTMP, *ImageOrg;
+        bool doflip;
+        CRotateImage(std::string _image, bool _flip = false) : CImageBasis(_image) {ImageTMP = NULL; ImageOrg = NULL; doflip = _flip;};
+        CRotateImage(uint8_t* _rgb_image, int _channels, int _width, int _height, int _bpp, bool _flip = false) : CImageBasis(_rgb_image, _channels, _width, _height, _bpp) {ImageTMP = NULL;  ImageOrg = NULL; doflip = _flip;};
+        CRotateImage(CImageBasis *_org, CImageBasis *_temp, bool _flip = false);
 
         void Rotate(float _angle);
         void Rotate(float _angle, int _centerx, int _centery);

+ 1 - 1
code/components/jomjol_logfile/ClassLogFile.cpp

@@ -77,7 +77,7 @@ void ClassLogFile::WriteToDedicatedFile(std::string _fn, std::string info, bool
             time(&rawtime);
             timeinfo = localtime(&rawtime);
 
-            strftime(buffer, 80, "%Y-%m-%d_%H-%M-%S", timeinfo);
+            strftime(buffer, 80, "%Y-%m-%dT%H:%M:%S", timeinfo);
 
             zwtime = std::string(buffer);
             info = zwtime + ": " + info;

+ 1 - 1
code/main/server_main.cpp

@@ -387,7 +387,7 @@ httpd_handle_t start_webserver(void)
     httpd_config_t config = { };
 
     config.task_priority      = tskIDLE_PRIORITY+5;
-    config.stack_size         = 16384;                  // bei 32k stürzt das Programm beim Bilderaufnehmen ab
+    config.stack_size         = 32384;                  // bei 32k stürzt das Programm beim Bilderaufnehmen ab
     config.core_id            = tskNO_AFFINITY;
     config.server_port        = 80;
     config.ctrl_port          = 32768;

+ 3 - 3
code/main/version.cpp

@@ -1,4 +1,4 @@
-const char* GIT_REV="a45a529";
+const char* GIT_REV="10d49b5";
 const char* GIT_TAG="";
-const char* GIT_BRANCH="master";
-const char* BUILD_TIME="2021-05-01 17:42";
+const char* GIT_BRANCH="rolling";
+const char* BUILD_TIME="2021-05-08 18:03";

+ 1 - 1
code/main/version.h

@@ -13,7 +13,7 @@ extern "C"
 #include "Helper.h"
 #include <fstream>
 
-const char* GIT_BASE_BRANCH = "master - v6.7.1 - 2020-01-05";
+const char* GIT_BASE_BRANCH = "master - v7.0.0 - 2020-05-08";
 
 
 const char* git_base_branch(void)

+ 3 - 3
code/version.cpp

@@ -1,4 +1,4 @@
-const char* GIT_REV="a45a529";
+const char* GIT_REV="10d49b5";
 const char* GIT_TAG="";
-const char* GIT_BRANCH="master";
-const char* BUILD_TIME="2021-05-01 17:42";
+const char* GIT_BRANCH="rolling";
+const char* BUILD_TIME="2021-05-08 18:03";

BIN
firmware/bootloader.bin


BIN
firmware/firmware.bin


BIN
firmware/html.zip


+ 4 - 1
sd-card/config/config.ini

@@ -9,6 +9,7 @@ FixedExposure = false
 
 [Alignment]
 InitialRotate=180
+FlipImageSize = false
 /config/ref0.jpg 119 273
 /config/ref1.jpg 456 138
 SearchFieldX = 20
@@ -17,7 +18,7 @@ InitialMirror= false
 AlignmentAlgo = Default
 
 [Digits]
-Model = /config/dig0840s1q.tflite
+Model = /config/dig0850s1q.tflite
 ;LogImageLocation = /log/digit
 ;LogfileRetentionInDays = 3
 ModelInputSize = 20 32
@@ -49,6 +50,8 @@ CheckDigitIncreaseConsistency = false
 ;Uri = mqtt://IP-ADRESS:1883
 ;Topic = wasserzaehler/zaehlerstand
 ;TopicError = wasserzaehler/error
+;TopicRate = wasserzaehler/rate
+;TopicTimeStamp = wasserzaehler/timestamp
 ;ClientID = wasser
 ;user = USERNAME
 ;password = PASSWORD

BIN
sd-card/config/dig0850s1q.tflite


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

@@ -518,6 +518,34 @@ textarea {
 				MQTT topic, in which the error status is reported (empty = no error)
 			</td>
 		</tr>
+		<tr>
+			<td width="20px"  style="padding-left: 40px;">
+				<input type="checkbox" id="MQTT_TopicRate_enabled" value="1"  onclick = 'InvertEnableItem("MQTT", "TopicRate")' unchecked >
+			</td>
+			<td  width="200px">
+				<class id="MQTT_TopicRate_text" style="color:black;">TopicRate</class>
+			</td>
+			<td>
+				<input type="text" id="MQTT_TopicRate_value1">
+			</td>
+			<td style="font-size: 80%;">
+				MQTT topic, in which the flow rate [units / minute] is reported
+			</td>
+		</tr>
+		<tr>
+			<td width="20px"  style="padding-left: 40px;">
+				<input type="checkbox" id="MQTT_TopicTimeStamp_enabled" value="1"  onclick = 'InvertEnableItem("MQTT", "TopicTimeStamp")' unchecked >
+			</td>
+			<td  width="200px">
+				<class id="MQTT_TopicTimeStamp_text" style="color:black;">TopicTimeStamp</class>
+			</td>
+			<td>
+				<input type="text" id="MQTT_TopicTimeStamp_value1">
+			</td>
+			<td style="font-size: 80%;">
+				MQTT topic, reporting the last correct readout
+			</td>
+		</tr>
 		<tr>
 			<td width="20px"  style="padding-left: 40px;">
 				<input type="checkbox" id="MQTT_ClientID_enabled" value="1"  onclick = 'InvertEnableItem("MQTT", "ClientID")' unchecked >
@@ -907,6 +935,8 @@ function UpdateInput() {
 	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", "ClientID", true);	
 	WriteParameter(param, category, "MQTT", "user", true);	
 	WriteParameter(param, category, "MQTT", "password", true);	
@@ -964,6 +994,8 @@ function ReadParameterAll()
 	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", "ClientID", true);	
 	ReadParameter(param, "MQTT", "user", true);	
 	ReadParameter(param, "MQTT", "password", true);	

+ 40 - 9
sd-card/html/edit_reference.html

@@ -44,6 +44,11 @@ table {
 	  <tr>
 		<td style="padding-top: 10px"><label for="mirror" id="labelmirror">Mirror Image:</label></td>
         <td style="padding-top: 10px"><input type="checkbox" id="mirror" name="mirror" value="1" onchange="drawRotated()"></td>
+      </tr>
+      <tr>
+
+		<td><label for="flip" id="labelflip">Flip Image Size:</label></td>
+        <td><input type="checkbox" id="flip" name="flip" value="1" onchange="drawRotated()"></td>
         
 	  </tr>
 	  <tr>
@@ -129,6 +134,13 @@ table {
                 document.getElementById("labelmirror").style = "color:lightgrey;";
             }
 
+            if (param["Alignment"]["FlipImageSize"].found)
+                document.getElementById("flip").disabled = false;
+            else
+            {
+                document.getElementById("labelflip").style = "color:lightgrey;";
+            }
+
             if (param["MakeImage"]["Brightness"].found && param["MakeImage"]["Brightness"].enabled)
                 document.getElementById("MakeImage_Brightness_value1").disabled = false;
             else
@@ -156,6 +168,9 @@ table {
             if (_param["Alignment"]["InitialMirror"].found && (_param["Alignment"]["InitialMirror"].value1 == "true"))
                 document.getElementById("mirror").checked = true;
 
+            if (_param["Alignment"]["FlipImageSize"].found && (_param["Alignment"]["FlipImageSize"].value1 == "true"))
+                document.getElementById("flip").checked = true;
+
             document.getElementById("finerotate").disabled = true;
             document.getElementById("prerotateangle").disabled = true; 
             document.getElementById("updatereferenceimage").disabled = true;
@@ -164,6 +179,7 @@ table {
 //            document.getElementById("MakeImage_Saturation_value1").disabled = true;
 //            document.getElementById("MakeImage_Contrast_value1").disabled = true;
             document.getElementById("mirror").disabled = false;
+            document.getElementById("flip").disabled = false;
             if (!(param["MakeImage"]["Brightness"].found))
             {
                 document.getElementById("MakeImage_Brightness_value1").type = "hidden";
@@ -172,6 +188,7 @@ table {
 
 
             document.getElementById("mirror").disabled = true;
+            document.getElementById("flip").disabled = true;
 
             isActReference = true;                                  
             loadCanvas(url);
@@ -190,11 +207,17 @@ table {
         function SaveReference(){
             if (confirm("Are you sure you want to update the reference image?")) {
                 param["Alignment"]["InitialRotate"].value1 = document.getElementById("prerotateangle").value;
+
                 if ((param["Alignment"]["InitialMirror"].found == true) && (document.getElementById("mirror").checked))
                     param["Alignment"]["InitialMirror"].value1 = "true";
                 else
                     param["Alignment"]["InitialMirror"].value1 = "false";
 
+                if ((param["Alignment"]["FlipImageSize"].found == true) && (document.getElementById("flip").checked))
+                    param["Alignment"]["FlipImageSize"].value1 = "true";
+                else
+                    param["Alignment"]["FlipImageSize"].value1 = "false";
+
                 if (param["MakeImage"]["Brightness"].found && param["MakeImage"]["Brightness"].enabled)
                 {
                     ReadParameter(param, "MakeImage", "Brightness", false);		
@@ -319,6 +342,7 @@ table {
             finerot= parseFloat(document.getElementById("finerotate").value);
             prerot = parseFloat(document.getElementById("prerotateangle").value);
             mirror = document.getElementById("mirror").checked;
+            flip = document.getElementById("flip").checked;
 
             if (finerot == 1) {
                 prerot+=1
@@ -332,10 +356,22 @@ table {
             document.getElementById("finerotate").value =  finerot;
             document.getElementById("prerotateangle").value =  prerot;
 
+            var canvas = document.getElementById('canvas');
+            if (flip == 1)
+            {
+                canvas.width = imageObj.height;
+                canvas.height = imageObj.width;
+            }
+            else
+            {
+                canvas.width = imageObj.width;
+                canvas.height = imageObj.height;
+            }
+
             var canvas = document.getElementById('canvas');
             var context = canvas.getContext('2d');
 
-            context.clearRect(0,0,imageObj.width,imageObj.height);
+            context.clearRect(0,0,canvas.width,canvas.height);
             context.save();
 
             if (isActReference)
@@ -344,17 +380,12 @@ table {
             }
             else
             {
+                context.translate(canvas.width/2,canvas.height/2);
+                context.rotate(degrees*Math.PI/180);
                 if (mirror) {
                     context.scale(-1, 1);
-                    context.translate(-imageObj.width/2,imageObj.height/2);
-                    context.rotate(-degrees*Math.PI/180);
-                    context.drawImage(imageObj, imageObj.width/2,-imageObj.height/2, -imageObj.width, imageObj.height);
-                }
-                else {
-                    context.translate(imageObj.width/2,imageObj.height/2);
-                    context.rotate(degrees*Math.PI/180);
-                    context.drawImage(imageObj,-imageObj.width/2,-imageObj.height/2);
                 }
+                context.drawImage(imageObj,-imageObj.width/2,-imageObj.height/2);
             }
             
             

+ 4 - 1
sd-card/html/readconfigparam.js

@@ -39,7 +39,8 @@ function ParseConfig() {
      ParamAddValue(param, catname, "InitialMirror");
      ParamAddValue(param, catname, "SearchFieldX");
      ParamAddValue(param, catname, "SearchFieldY");     
-     ParamAddValue(param, catname, "AlignmentAlgo");     
+     ParamAddValue(param, catname, "AlignmentAlgo");
+     ParamAddValue(param, catname, "FlipImageSize");
 
      var catname = "Digits";
      category[catname] = new Object(); 
@@ -83,6 +84,8 @@ function ParseConfig() {
      ParamAddValue(param, catname, "Uri");
      ParamAddValue(param, catname, "Topic");
      ParamAddValue(param, catname, "TopicError");
+     ParamAddValue(param, catname, "TopicRate");
+     ParamAddValue(param, catname, "TopicTimeStamp");
      ParamAddValue(param, catname, "ClientID");
      ParamAddValue(param, catname, "user");
      ParamAddValue(param, catname, "password");     

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


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

@@ -1 +1 @@
-6.5.0
+6.8.0

+ 2 - 2
sd-card/html/wasserzaehler_roi.html

@@ -31,7 +31,7 @@
 	var m = addZero(d.getMinutes());
 	var s = addZero(d.getSeconds());
 
-	$('#img').html('<img src="/img_tmp/alg_roi.jpg" style="width:100%; max-height:555px;"></img>');
+	$('#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");
@@ -49,7 +49,7 @@
 	var m = addZero(d.getMinutes());
 	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 +'" style="width:100%; max-height:555px;"></img>');
+	$('#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");