jomjol 4 лет назад
Родитель
Сommit
147d97421b
72 измененных файлов с 4161 добавлено и 469 удалено
  1. 6 0
      FeatureRequest.md
  2. 0 21
      LICENSE
  3. 25 2
      README.md
  4. 63 0
      code/SmartLeds.cpp
  5. 530 0
      code/SmartLeds.h
  6. 132 0
      code/components/jomjol_controlGPIO/Color.cpp
  7. 69 0
      code/components/jomjol_controlGPIO/Color.h
  8. 63 0
      code/components/jomjol_controlGPIO/SmartLeds.cpp
  9. 530 0
      code/components/jomjol_controlGPIO/SmartLeds.h
  10. 84 4
      code/components/jomjol_controlGPIO/server_GPIO.cpp
  11. 8 0
      code/components/jomjol_controlGPIO/server_GPIO.h
  12. 1 0
      code/components/jomjol_controlcamera/ClassControllCamera.cpp
  13. 2 0
      code/components/jomjol_fileserver_ota/server_help.cpp
  14. 57 45
      code/components/jomjol_flowcontroll/ClassFlowCNNGeneral.cpp
  15. 15 20
      code/components/jomjol_flowcontroll/ClassFlowCNNGeneral.h
  16. 85 101
      code/components/jomjol_flowcontroll/ClassFlowControll.cpp
  17. 5 3
      code/components/jomjol_flowcontroll/ClassFlowControll.h
  18. 52 0
      code/components/jomjol_flowcontroll/ClassFlowDefineTypes.h
  19. 7 7
      code/components/jomjol_flowcontroll/ClassFlowMQTT.cpp
  20. 97 24
      code/components/jomjol_flowcontroll/ClassFlowPostProcessing.cpp
  21. 12 37
      code/components/jomjol_flowcontroll/ClassFlowPostProcessing.h
  22. 4 1
      code/components/jomjol_helper/Helper.cpp
  23. 1 27
      code/components/jomjol_tfliteclass/CTfLiteClass.cpp
  24. 19 53
      code/components/jomjol_tfliteclass/server_tflite.cpp
  25. 4 4
      code/components/jomjol_wlan/connect_wlan.cpp
  26. 2 2
      code/components/jomjol_wlan/connect_wlan.h
  27. BIN
      code/components/tfmicro.zip
  28. BIN
      code/components/tfmicro_new_version.zip
  29. 132 0
      code/main/Color.cpp
  30. 69 0
      code/main/Color.h
  31. 63 0
      code/main/SmartLeds.cpp
  32. 530 0
      code/main/SmartLeds.h
  33. 11 1
      code/main/main.cpp
  34. 26 54
      code/main/server_main.cpp
  35. 3 3
      code/main/version.cpp
  36. 8 10
      code/main/version.h
  37. 2 2
      code/sdkconfig
  38. 1300 0
      code/sdkconfig.esp32cam
  39. 2 1
      code/sdkconfig.old
  40. 3 3
      code/version.cpp
  41. BIN
      firmware/bootloader.bin
  42. BIN
      firmware/firmware.bin
  43. BIN
      firmware/html.zip
  44. BIN
      sd-card/config/dig1200s1q.tflite
  45. BIN
      sd-card/config/dig1300s1q.tflite
  46. 1 0
      sd-card/html/edit_alignment.html
  47. 1 0
      sd-card/html/edit_analog.html
  48. 1 0
      sd-card/html/edit_check.html
  49. 1 0
      sd-card/html/edit_config.html
  50. 45 23
      sd-card/html/edit_config_param.html
  51. 1 0
      sd-card/html/edit_digits.html
  52. 1 0
      sd-card/html/edit_explain_0.html
  53. 1 0
      sd-card/html/edit_explain_6.html
  54. 1 0
      sd-card/html/edit_reference.html
  55. 1 0
      sd-card/html/explain_0.html
  56. 1 0
      sd-card/html/explain_1.html
  57. 1 0
      sd-card/html/explain_2.html
  58. 1 0
      sd-card/html/explain_3.html
  59. 1 0
      sd-card/html/explain_4.html
  60. 1 0
      sd-card/html/explain_5.html
  61. 1 0
      sd-card/html/explain_6.html
  62. 57 15
      sd-card/html/index.html
  63. 1 0
      sd-card/html/index_configure.html
  64. 1 0
      sd-card/html/ota_page.html
  65. 3 1
      sd-card/html/ota_page_v2.html
  66. 1 0
      sd-card/html/prevalue_set.html
  67. 11 4
      sd-card/html/readconfigparam.js
  68. 1 0
      sd-card/html/reboot_page.html
  69. 1 0
      sd-card/html/setup.html
  70. 1 0
      sd-card/html/test.html
  71. 1 1
      sd-card/html/version.txt
  72. 1 0
      sd-card/html/wasserzaehler_roi.html

+ 6 - 0
FeatureRequest.md

@@ -11,6 +11,12 @@
 
 ____
 
+#### #11 MQTT - configurable payload
+
+* https://github.com/jomjol/AI-on-the-edge-device/issues/344
+
+  
+
 #### #10 Improve and bug fix logging of images
 
 * https://github.com/jomjol/AI-on-the-edge-device/issues/307

+ 0 - 21
LICENSE

@@ -1,21 +0,0 @@
-MIT License
-
-Copyright (c) 2020 jomjol
-
-Permission is hereby granted, free of charge, to any person obtaining a copy
-of this software and associated documentation files (the "Software"), to deal
-in the Software without restriction, including without limitation the rights
-to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
-copies of the Software, and to permit persons to whom the Software is
-furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all
-copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
-FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
-SOFTWARE.

+ 25 - 2
README.md

@@ -47,9 +47,32 @@ In other cases you can contact the developer via email: <img src="https://raw.gi
 
 
 
-##### 8.3.1 - Multi Meter Support (2021-09-14
+##### 8.4.0 - Multi Meter Support (2021-09-25)
+
+* License change (remove MIT license, remark see below)
+
+* html: show hostname in title and main page
+
+* configuration: 
+
+  * moved setting `ExtendedResolution` to individual number settings
+  * New parameter `IgnoreLeadingNaN` (delete leading NaN's specifically)
+  * **ATTENTION**: update of the `config.ini` needed (open, adjust `ExtendedResolution`, save)
+
+* Bug fixing (html, images of recognized numbers)
+
+  
+
+### **ATTENTION: LICENSE CHANGE - removal of MIT License.** 
+
+- Currently no licence published - copyright belongs to author
+- If you are interested in a commercial usage or dedicated versions please contact the developer
+  - no limits to private usage
+
+
+
+##### 8.3.0 - Multi Meter Support (2021-09-12)
 
-* NEW 8.3.1: Bug fix sd-card file structure (tmp_img)
 * Upgrade digital CNN to v12.1.0 (added new images)
 * Dedicated NaN handling, internal refactoring (CNN-Handling)
 * HTML: confirmation after config.ini update

+ 63 - 0
code/SmartLeds.cpp

@@ -0,0 +1,63 @@
+#include "SmartLeds.h"
+
+IsrCore SmartLed::_interruptCore = CoreCurrent;
+intr_handle_t SmartLed::_interruptHandle = NULL;
+
+SmartLed*& IRAM_ATTR SmartLed::ledForChannel( int channel ) {
+    static SmartLed* table[8] = { nullptr };
+    assert( channel < 8 );
+    return table[ channel ];
+}
+
+void IRAM_ATTR SmartLed::interruptHandler(void*) {
+    for (int channel = 0; channel != 8; channel++) {
+        auto self = ledForChannel( channel );
+
+        if ( RMT.int_st.val & (1 << (24 + channel ) ) ) { // tx_thr_event
+            if ( self )
+                self->copyRmtHalfBlock();
+            RMT.int_clr.val |= 1 << ( 24 + channel );
+        } else if ( RMT.int_st.val & ( 1 << (3 * channel ) ) ) { // tx_end
+            if ( self )
+                xSemaphoreGiveFromISR( self->_finishedFlag, nullptr );
+            RMT.int_clr.val |= 1 << ( 3 * channel );
+        }
+    }
+}
+
+void IRAM_ATTR SmartLed::copyRmtHalfBlock() {
+    int offset = detail::MAX_PULSES * _halfIdx;
+    _halfIdx = !_halfIdx;
+    int len = 3 - _componentPosition + 3 * ( _count - 1 );
+    len = std::min( len, detail::MAX_PULSES / 8 );
+
+    if ( !len ) {
+        for ( int i = 0; i < detail::MAX_PULSES; i++) {
+            RMTMEM.chan[ _channel].data32[i + offset ].val = 0;
+        }
+    }
+
+    int i;
+    for ( i = 0; i != len && _pixelPosition != _count; i++ ) {
+        uint8_t val = _buffer[ _pixelPosition ].getGrb( _componentPosition );
+        for ( int j = 0; j != 8; j++, val <<= 1 ) {
+            int bit = val >> 7;
+            int idx = i * 8 + offset + j;
+            RMTMEM.chan[ _channel ].data32[ idx ].val = _bitToRmt[ bit & 0x01 ].value;
+        }
+        if ( _pixelPosition == _count - 1 && _componentPosition == 2 ) {
+            RMTMEM.chan[ _channel ].data32[ i * 8 + offset + 7 ].duration1 =
+                _timing.TRS / ( detail::RMT_DURATION_NS * detail::DIVIDER );
+        }
+
+        _componentPosition++;
+        if ( _componentPosition == 3 ) {
+            _componentPosition = 0;
+            _pixelPosition++;
+        }
+    }
+
+    for ( i *= 8; i != detail::MAX_PULSES; i++ ) {
+        RMTMEM.chan[ _channel ].data32[ i + offset ].val = 0;
+    }
+}

+ 530 - 0
code/SmartLeds.h

@@ -0,0 +1,530 @@
+#pragma once
+
+/*
+ * A C++ driver for the WS2812 LEDs using the RMT peripheral on the ESP32.
+ *
+ * Jan "yaqwsx" Mrázek <email@honzamrazek.cz>
+ *
+ * Based on the work by Martin F. Falatic - https://github.com/FozzTexx/ws2812-demo
+ */
+
+/*
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <memory>
+#include <cassert>
+#include <cstring>
+
+#if defined ( ARDUINO )
+    extern "C" { // ...someone forgot to put in the includes...
+        #include "esp32-hal.h"
+        #include "esp_intr_alloc.h"
+        #include "esp_ipc.h"
+        #include "driver/gpio.h"
+        #include "driver/periph_ctrl.h"
+        #include "freertos/semphr.h"
+        #include "soc/rmt_struct.h"
+        #include <driver/spi_master.h>
+        #include "esp_idf_version.h"
+#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL( 4, 0, 0 )
+        #include "soc/dport_reg.h"
+#endif
+    }
+#elif defined ( ESP_PLATFORM )
+    extern "C" { // ...someone forgot to put in the includes...
+        #include <esp_intr_alloc.h>
+        #include <esp_ipc.h>
+        #include <driver/gpio.h>
+        #include <freertos/FreeRTOS.h>
+        #include <freertos/semphr.h>
+        #include <soc/dport_reg.h>
+        #include <soc/gpio_sig_map.h>
+        #include <soc/rmt_struct.h>
+        #include <driver/spi_master.h>
+    }
+    #include <stdio.h>
+#endif
+
+#include "Color.h"
+
+namespace detail {
+
+struct TimingParams {
+    uint32_t T0H;
+    uint32_t T1H;
+    uint32_t T0L;
+    uint32_t T1L;
+    uint32_t TRS;
+};
+
+union RmtPulsePair {
+    struct {
+        int duration0:15;
+        int level0:1;
+        int duration1:15;
+        int level1:1;
+    };
+    uint32_t value;
+};
+
+static const int DIVIDER = 4; // 8 still seems to work, but timings become marginal
+static const int MAX_PULSES = 32; // A channel has a 64 "pulse" buffer - we use half per pass
+static const double RMT_DURATION_NS = 12.5; // minimum time of a single RMT duration based on clock ns
+
+} // namespace detail
+
+using LedType = detail::TimingParams;
+
+static const LedType LED_WS2812  = { 350, 700, 800, 600, 50000 };
+static const LedType LED_WS2812B = { 400, 850, 850, 400, 50100 };
+static const LedType LED_SK6812  = { 300, 600, 900, 600, 80000 };
+static const LedType LED_WS2813  = { 350, 800, 350, 350, 300000 };
+
+enum BufferType { SingleBuffer = 0, DoubleBuffer };
+
+enum IsrCore { CoreFirst = 0, CoreSecond = 1, CoreCurrent = 2};
+
+class SmartLed {
+public:
+    // The RMT interrupt must not run on the same core as WiFi interrupts, otherwise SmartLeds
+    // can't fill the RMT buffer fast enough, resulting in rendering artifacts.
+    // Usually, that means you have to set isrCore == CoreSecond.
+    //
+    // If you use anything other than CoreCurrent, the FreeRTOS scheduler MUST be already running,
+    // so you can't use it if you define SmartLed as global variable.
+    SmartLed( const LedType& type, int count, int pin, int channel = 0, BufferType doubleBuffer = SingleBuffer, IsrCore isrCore = CoreCurrent)
+        : _timing( type ),
+          _channel( channel ),
+          _count( count ),
+          _firstBuffer( new Rgb[ count ] ),
+          _secondBuffer( doubleBuffer ? new Rgb[ count ] : nullptr ),
+          _finishedFlag( xSemaphoreCreateBinary() )
+    {
+        assert( channel >= 0 && channel < 8 );
+        assert( ledForChannel( channel ) == nullptr );
+
+        xSemaphoreGive( _finishedFlag );
+
+        DPORT_SET_PERI_REG_MASK( DPORT_PERIP_CLK_EN_REG, DPORT_RMT_CLK_EN );
+        DPORT_CLEAR_PERI_REG_MASK( DPORT_PERIP_RST_EN_REG, DPORT_RMT_RST );
+
+        PIN_FUNC_SELECT( GPIO_PIN_MUX_REG[ pin ], 2 );
+        gpio_set_direction( static_cast< gpio_num_t >( pin ), GPIO_MODE_OUTPUT );
+        gpio_matrix_out( static_cast< gpio_num_t >( pin ), RMT_SIG_OUT0_IDX + _channel, 0, 0 );
+        initChannel( _channel );
+
+        RMT.tx_lim_ch[ _channel ].limit = detail::MAX_PULSES;
+        RMT.int_ena.val |= 1 << ( 24 + _channel );
+        RMT.int_ena.val |= 1 << ( 3 * _channel );
+
+        _bitToRmt[ 0 ].level0 = 1;
+        _bitToRmt[ 0 ].level1 = 0;
+        _bitToRmt[ 0 ].duration0 = _timing.T0H / ( detail::RMT_DURATION_NS * detail::DIVIDER );
+        _bitToRmt[ 0 ].duration1 = _timing.T0L / ( detail::RMT_DURATION_NS * detail::DIVIDER );
+
+        _bitToRmt[ 1 ].level0 = 1;
+        _bitToRmt[ 1 ].level1 = 0;
+        _bitToRmt[ 1 ].duration0 = _timing.T1H / ( detail::RMT_DURATION_NS * detail::DIVIDER );
+        _bitToRmt[ 1 ].duration1 = _timing.T1L / ( detail::RMT_DURATION_NS * detail::DIVIDER );
+
+        if ( !anyAlive() ) {
+            _interruptCore = isrCore;
+            if(isrCore != CoreCurrent) {
+                ESP_ERROR_CHECK(esp_ipc_call_blocking(isrCore, registerInterrupt, NULL));
+            } else {
+                registerInterrupt(NULL);
+            }
+        }
+
+        ledForChannel( channel ) = this;
+    }
+
+    ~SmartLed() {
+        ledForChannel( _channel ) = nullptr;
+        if ( !anyAlive() ) {
+            if(_interruptCore != CoreCurrent) {
+                ESP_ERROR_CHECK(esp_ipc_call_blocking(_interruptCore, unregisterInterrupt, NULL));
+            } else {
+                unregisterInterrupt(NULL);
+            }
+        }
+        vSemaphoreDelete( _finishedFlag );
+    }
+
+    Rgb& operator[]( int idx ) {
+        return _firstBuffer[ idx ];
+    }
+
+    const Rgb& operator[]( int idx ) const {
+        return _firstBuffer[ idx ];
+    }
+
+    void show() {
+        _buffer = _firstBuffer.get();
+        startTransmission();
+        swapBuffers();
+    }
+
+    bool wait( TickType_t timeout = portMAX_DELAY ) {
+        if( xSemaphoreTake( _finishedFlag, timeout ) == pdTRUE ) {
+            xSemaphoreGive( _finishedFlag );
+            return true;
+        }
+        return false;
+    }
+
+    int size() const {
+        return _count;
+    }
+
+    Rgb *begin() { return _firstBuffer.get(); }
+    const Rgb *begin() const { return _firstBuffer.get(); }
+    const Rgb *cbegin() const { return _firstBuffer.get(); }
+
+    Rgb *end() { return _firstBuffer.get() + _count; }
+    const Rgb *end() const { return _firstBuffer.get() + _count; }
+    const Rgb *cend() const { return _firstBuffer.get() + _count; }
+
+private:
+    static intr_handle_t _interruptHandle;
+    static IsrCore _interruptCore;
+
+    static void initChannel( int channel ) {
+        RMT.apb_conf.fifo_mask = 1;  //enable memory access, instead of FIFO mode.
+        RMT.apb_conf.mem_tx_wrap_en = 1; //wrap around when hitting end of buffer
+        RMT.conf_ch[ channel ].conf0.div_cnt = detail::DIVIDER;
+        RMT.conf_ch[ channel ].conf0.mem_size = 1;
+        RMT.conf_ch[ channel ].conf0.carrier_en = 0;
+        RMT.conf_ch[ channel ].conf0.carrier_out_lv = 1;
+        RMT.conf_ch[ channel ].conf0.mem_pd = 0;
+
+        RMT.conf_ch[ channel ].conf1.rx_en = 0;
+        RMT.conf_ch[ channel ].conf1.mem_owner = 0;
+        RMT.conf_ch[ channel ].conf1.tx_conti_mode = 0;    //loop back mode.
+        RMT.conf_ch[ channel ].conf1.ref_always_on = 1;    // use apb clock: 80M
+        RMT.conf_ch[ channel ].conf1.idle_out_en = 1;
+        RMT.conf_ch[ channel ].conf1.idle_out_lv = 0;
+    }
+
+    static void registerInterrupt(void *) {
+        ESP_ERROR_CHECK(esp_intr_alloc( ETS_RMT_INTR_SOURCE, 0, interruptHandler, nullptr, &_interruptHandle));
+    }
+
+    static void unregisterInterrupt(void*) {
+        esp_intr_free( _interruptHandle );
+    }
+
+    static SmartLed*& IRAM_ATTR ledForChannel( int channel );
+    static void IRAM_ATTR interruptHandler( void* );
+
+    void IRAM_ATTR copyRmtHalfBlock();
+
+    void swapBuffers() {
+        if ( _secondBuffer )
+            _firstBuffer.swap( _secondBuffer );
+    }
+
+    void startTransmission() {
+        // Invalid use of the library
+        if( xSemaphoreTake( _finishedFlag, 0 ) != pdTRUE )
+            abort();
+
+        _pixelPosition = _componentPosition = _halfIdx = 0;
+        copyRmtHalfBlock();
+        if ( _pixelPosition < _count )
+            copyRmtHalfBlock();
+
+        RMT.conf_ch[ _channel ].conf1.mem_rd_rst = 1;
+        RMT.conf_ch[ _channel ].conf1.tx_start = 1;
+    }
+
+    static bool anyAlive() {
+        for ( int i = 0; i != 8; i++ )
+            if ( ledForChannel( i ) != nullptr ) return true;
+        return false;
+    }
+
+    const LedType& _timing;
+    int _channel;
+    detail::RmtPulsePair _bitToRmt[ 2 ];
+    int _count;
+    std::unique_ptr< Rgb[] > _firstBuffer;
+    std::unique_ptr< Rgb[] > _secondBuffer;
+    Rgb *_buffer;
+
+    xSemaphoreHandle _finishedFlag;
+
+    int _pixelPosition;
+    int _componentPosition;
+    int _halfIdx;
+};
+
+class Apa102 {
+public:
+    struct ApaRgb {
+        ApaRgb( uint8_t r = 0, uint8_t g = 0, uint32_t b = 0, uint32_t v = 0xFF )
+            : v( 0xE0 | v ), b( b ), g( g ), r( r )
+        {}
+
+        ApaRgb& operator=( const Rgb& o ) {
+            r = o.r;
+            g = o.g;
+            b = o.b;
+            return *this;
+        }
+
+        ApaRgb& operator=( const Hsv& o ) {
+            *this = Rgb{ o };
+            return *this;
+        }
+
+        uint8_t v, b, g, r;
+    };
+
+    static const int FINAL_FRAME_SIZE = 4;
+    static const int TRANS_COUNT = 2 + 8;
+
+    Apa102( int count, int clkpin, int datapin, BufferType doubleBuffer = SingleBuffer )
+        : _count( count ),
+          _firstBuffer( new ApaRgb[ count ] ),
+          _secondBuffer( doubleBuffer ? new ApaRgb[ count ] : nullptr ),
+          _initFrame( 0 )
+    {
+        spi_bus_config_t buscfg;
+        memset( &buscfg, 0, sizeof( buscfg ) );
+        buscfg.mosi_io_num = datapin;
+        buscfg.miso_io_num = -1;
+        buscfg.sclk_io_num = clkpin;
+        buscfg.quadwp_io_num = -1;
+        buscfg.quadhd_io_num = -1;
+        buscfg.max_transfer_sz = 65535;
+
+        spi_device_interface_config_t devcfg;
+        memset( &devcfg, 0, sizeof( devcfg ) );
+        devcfg.clock_speed_hz = 1000000;
+        devcfg.mode = 0;
+        devcfg.spics_io_num = -1;
+        devcfg.queue_size = TRANS_COUNT;
+        devcfg.pre_cb = nullptr;
+
+        auto ret = spi_bus_initialize( HSPI_HOST, &buscfg, 1 );
+        assert( ret == ESP_OK );
+
+        ret = spi_bus_add_device( HSPI_HOST, &devcfg, &_spi );
+        assert( ret == ESP_OK );
+
+        std::fill_n( _finalFrame, FINAL_FRAME_SIZE, 0xFFFFFFFF );
+    }
+
+    ~Apa102() {
+        // ToDo
+    }
+
+    ApaRgb& operator[]( int idx ) {
+        return _firstBuffer[ idx ];
+    }
+
+    const ApaRgb& operator[]( int idx ) const {
+        return _firstBuffer[ idx ];
+    }
+
+    void show() {
+        _buffer = _firstBuffer.get();
+        startTransmission();
+        swapBuffers();
+    }
+
+    void wait() {
+        for ( int i = 0; i != _transCount; i++ ) {
+            spi_transaction_t *t;
+            spi_device_get_trans_result( _spi, &t, portMAX_DELAY );
+        }
+    }
+private:
+    void swapBuffers() {
+        if ( _secondBuffer )
+            _firstBuffer.swap( _secondBuffer );
+    }
+
+    void startTransmission() {
+        for ( int i = 0; i != TRANS_COUNT; i++ ) {
+            _transactions[ i ].cmd = 0;
+            _transactions[ i ].addr = 0;
+            _transactions[ i ].flags = 0;
+            _transactions[ i ].rxlength = 0;
+            _transactions[ i ].rx_buffer = nullptr;
+        }
+        // Init frame
+        _transactions[ 0 ].length = 32;
+        _transactions[ 0 ].tx_buffer = &_initFrame;
+        spi_device_queue_trans( _spi, _transactions + 0, portMAX_DELAY );
+        // Data
+        _transactions[ 1 ].length = 32 * _count;
+        _transactions[ 1 ].tx_buffer = _buffer;
+        spi_device_queue_trans( _spi, _transactions + 1, portMAX_DELAY );
+        _transCount = 2;
+        // End frame
+        for ( int i = 0; i != 1 + _count / 32 / FINAL_FRAME_SIZE; i++ ) {
+            _transactions[ 2 + i ].length = 32 * FINAL_FRAME_SIZE;
+            _transactions[ 2 + i ].tx_buffer = _finalFrame;
+            spi_device_queue_trans( _spi, _transactions + 2 + i, portMAX_DELAY );
+            _transCount++;
+        }
+    }
+
+    spi_device_handle_t _spi;
+    int _count;
+    std::unique_ptr< ApaRgb[] > _firstBuffer, _secondBuffer;
+    ApaRgb *_buffer;
+
+    spi_transaction_t _transactions[ TRANS_COUNT ];
+    int _transCount;
+
+    uint32_t _initFrame;
+    uint32_t _finalFrame[ FINAL_FRAME_SIZE ];
+};
+
+class LDP8806 {
+public:
+    struct LDP8806_GRB {
+
+        LDP8806_GRB( uint8_t g_7bit = 0, uint8_t r_7bit = 0, uint32_t b_7bit = 0 )
+            : g( g_7bit ), r( r_7bit ), b( b_7bit )
+        {
+        }
+
+        LDP8806_GRB& operator=( const Rgb& o ) {
+            //Convert 8->7bit colour
+            r = ( o.r * 127 / 256 ) | 0x80;
+            g = ( o.g * 127 / 256 ) | 0x80;
+            b = ( o.b * 127 / 256 ) | 0x80;
+            return *this;
+        }
+
+        LDP8806_GRB& operator=( const Hsv& o ) {
+            *this = Rgb{ o };
+            return *this;
+        }
+
+        uint8_t g, r, b;
+    };
+
+    static const int LED_FRAME_SIZE_BYTES = sizeof( LDP8806_GRB );
+    static const int LATCH_FRAME_SIZE_BYTES = 3;
+    static const int TRANS_COUNT_MAX = 20;//Arbitrary, supports up to 600 LED
+
+    LDP8806( int count, int clkpin, int datapin, BufferType doubleBuffer = SingleBuffer, uint32_t clock_speed_hz = 2000000 )
+        : _count( count ),
+          _firstBuffer( new LDP8806_GRB[ count ] ),
+          _secondBuffer( doubleBuffer ? new LDP8806_GRB[ count ] : nullptr ),
+          // one 'latch'/start-of-data mark frame for every 32 leds
+          _latchFrames( ( count + 31 ) / 32 )
+    {
+        spi_bus_config_t buscfg;
+        memset( &buscfg, 0, sizeof( buscfg ) );
+        buscfg.mosi_io_num = datapin;
+        buscfg.miso_io_num = -1;
+        buscfg.sclk_io_num = clkpin;
+        buscfg.quadwp_io_num = -1;
+        buscfg.quadhd_io_num = -1;
+        buscfg.max_transfer_sz = 65535;
+
+        spi_device_interface_config_t devcfg;
+        memset( &devcfg, 0, sizeof( devcfg ) );
+        devcfg.clock_speed_hz = clock_speed_hz;
+        devcfg.mode = 0;
+        devcfg.spics_io_num = -1;
+        devcfg.queue_size = TRANS_COUNT_MAX;
+        devcfg.pre_cb = nullptr;
+
+        auto ret = spi_bus_initialize( HSPI_HOST, &buscfg, 1 );
+        assert( ret == ESP_OK );
+
+        ret = spi_bus_add_device( HSPI_HOST, &devcfg, &_spi );
+        assert( ret == ESP_OK );
+
+        std::fill_n( _latchBuffer, LATCH_FRAME_SIZE_BYTES, 0x0 );
+    }
+
+    ~LDP8806() {
+        // noop
+    }
+
+    LDP8806_GRB& operator[]( int idx ) {
+        return _firstBuffer[ idx ];
+    }
+
+    const LDP8806_GRB& operator[]( int idx ) const {
+        return _firstBuffer[ idx ];
+    }
+
+    void show() {
+        _buffer = _firstBuffer.get();
+        startTransmission();
+        swapBuffers();
+    }
+
+    void wait() {
+        while ( _transCount-- ) {
+            spi_transaction_t *t;
+            spi_device_get_trans_result( _spi, &t, portMAX_DELAY );
+        }
+    }
+private:
+    void swapBuffers() {
+        if ( _secondBuffer )
+            _firstBuffer.swap( _secondBuffer );
+    }
+
+    void startTransmission() {
+        _transCount = 0;
+        for ( int i = 0; i != TRANS_COUNT_MAX; i++ ) {
+            _transactions[ i ].cmd = 0;
+            _transactions[ i ].addr = 0;
+            _transactions[ i ].flags = 0;
+            _transactions[ i ].rxlength = 0;
+            _transactions[ i ].rx_buffer = nullptr;
+        }
+        // LED Data
+        _transactions[ 0 ].length = ( LED_FRAME_SIZE_BYTES * 8 ) * _count;
+        _transactions[ 0 ].tx_buffer = _buffer;
+        spi_device_queue_trans( _spi, _transactions + _transCount, portMAX_DELAY );
+        _transCount++;
+
+        // 'latch'/start-of-data marker frames
+        for ( int i = 0; i < _latchFrames; i++ ) {
+            _transactions[ _transCount ].length = ( LATCH_FRAME_SIZE_BYTES * 8 );
+            _transactions[ _transCount ].tx_buffer = _latchBuffer;
+            spi_device_queue_trans( _spi, _transactions + _transCount, portMAX_DELAY );
+            _transCount++;
+        }
+    }
+
+    spi_device_handle_t _spi;
+    int _count;
+    std::unique_ptr< LDP8806_GRB[] > _firstBuffer, _secondBuffer;
+    LDP8806_GRB *_buffer;
+
+    spi_transaction_t _transactions[ TRANS_COUNT_MAX ];
+    int _transCount;
+
+    int _latchFrames;
+    uint8_t _latchBuffer[ LATCH_FRAME_SIZE_BYTES ];
+};

+ 132 - 0
code/components/jomjol_controlGPIO/Color.cpp

@@ -0,0 +1,132 @@
+#include "Color.h"
+#include <algorithm>
+#include <cmath>
+#include <cassert>
+
+namespace {
+
+// Int -> fixed point
+int up( int x ) { return x * 255; }
+
+} // namespace
+
+int iRgbSqrt( int num ) {
+    // https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Binary_numeral_system_.28base_2.29
+    assert( "sqrt input should be non-negative" && num >= 0 );
+    assert( "sqrt input should no exceed 16 bits" && num <= 0xFFFF );
+    int res = 0;
+    int bit = 1 << 16;
+    while ( bit > num )
+        bit >>= 2;
+    while ( bit != 0 ) {
+        if ( num >= res + bit ) {
+            num -= res + bit;
+            res = ( res >> 1 ) + bit;
+        } else
+            res >>= 1;
+        bit >>= 2;
+    }
+    return res;
+}
+
+Rgb::Rgb( Hsv y ) {
+    // https://stackoverflow.com/questions/24152553/hsv-to-rgb-and-back-without-floating-point-math-in-python
+    // greyscale
+    if( y.s == 0 ) {
+        r = g = b = y.v;
+        return;
+    }
+
+    const int region = y.h / 43;
+    const int remainder = ( y.h - ( region * 43 ) ) * 6;
+
+    const int p = ( y.v * ( 255 - y.s ) ) >> 8;
+    const int q = ( y.v * ( 255 - ( ( y.s * remainder ) >> 8 ) ) ) >> 8;
+    const int t = ( y.v * ( 255 - ( ( y.s * (255 -remainder ) ) >> 8 ) ) ) >> 8;
+
+    switch( region ) {
+        case 0: r = y.v; g = t; b = p; break;
+        case 1: r = q; g = y.v; b = p; break;
+        case 2: r = p; g = y.v; b = t; break;
+        case 3: r = p; g = q; b = y.v; break;
+        case 4: r = t; g = p; b = y.v; break;
+        case 5: r = y.v; g = p; b = q; break;
+        default: __builtin_trap();
+    }
+
+    a = y.a;
+}
+
+Rgb& Rgb::operator=( Hsv hsv ) {
+    Rgb r{ hsv };
+    swap( r );
+    return *this;
+}
+
+Rgb Rgb::operator+( Rgb in ) const {
+    auto copy = *this;
+    copy += in;
+    return copy;
+}
+
+Rgb& Rgb::operator+=( Rgb in ) {
+    unsigned int red = r + in.r;
+    r = ( red < 255 ) ? red : 255;
+    unsigned int green = g + in.g;
+    g = ( green < 255 ) ? green : 255;
+    unsigned int blue = b + in.b;
+    b = ( blue < 255 ) ? blue : 255;
+    return *this;
+}
+
+Rgb& Rgb::blend( Rgb in ) {
+    unsigned int inAlpha = in.a * ( 255 - a );
+    unsigned int alpha = a + inAlpha;
+    r = iRgbSqrt( ( ( r * r * a ) + ( in.r * in.r * inAlpha ) ) / alpha );
+    g = iRgbSqrt( ( ( g * g * a ) + ( in.g * in.g * inAlpha ) ) / alpha );
+    b = iRgbSqrt( ( ( b * b * a ) + ( in.b * in.b * inAlpha ) ) / alpha );
+    a = alpha;
+    return *this;
+}
+
+uint8_t IRAM_ATTR Rgb::getGrb( int idx ) {
+    switch ( idx ) {
+        case 0: return g;
+        case 1: return r;
+        case 2: return b;
+    }
+    __builtin_unreachable();
+}
+
+Hsv::Hsv( Rgb r ) {
+    int min = std::min( r.r, std::min( r.g, r.b ) );
+    int max = std::max( r.r, std::max( r.g, r.b ) );
+    int chroma = max - min;
+
+    v = max;
+    if ( chroma == 0 ) {
+        h = s = 0;
+        return;
+    }
+
+    s = up( chroma ) / max;
+    int hh;
+    if ( max == r.r )
+        hh = ( up( int( r.g ) - int( r.b ) ) ) / chroma / 6;
+    else if ( max == r.g )
+        hh = 255 / 3 + ( up( int( r.b ) - int( r.r ) ) ) / chroma / 6;
+    else
+        hh = 2 * 255 / 3 + ( up( int( r.r ) - int( r.g ) ) ) / chroma / 6;
+
+    if ( hh < 0 )
+        hh += 255;
+    h = hh;
+
+    a = r.a;
+}
+
+Hsv& Hsv::operator=( Rgb rgb ) {
+    Hsv h{ rgb };
+    swap( h );
+    return *this;
+}

+ 69 - 0
code/components/jomjol_controlGPIO/Color.h

@@ -0,0 +1,69 @@
+#pragma once
+
+#include <cstdint>
+#include "esp_attr.h"
+union Hsv;
+
+union Rgb {
+    struct __attribute__ ((packed)) {
+        uint8_t r, g, b, a;
+    };
+    uint32_t value;
+
+    Rgb( uint8_t r = 0, uint8_t g = 0, uint8_t b = 0, uint8_t a = 255 ) : r( r ), g( g ), b( b ), a( a ) {}
+    Rgb( Hsv c );
+    Rgb& operator=( Rgb rgb ) { swap( rgb ); return *this; }
+    Rgb& operator=( Hsv hsv );
+    Rgb operator+( Rgb in ) const;
+    Rgb& operator+=( Rgb in );
+    bool operator==( Rgb in ) const { return in.value == value; }
+    Rgb& blend( Rgb in );
+    void swap( Rgb& o ) {  value = o.value; }
+    void linearize() {
+        r = channelGamma(r);
+        g = channelGamma(g);
+        b = channelGamma(b);
+    }
+
+    uint8_t IRAM_ATTR getGrb( int idx );
+
+    void stretchChannels( uint8_t maxR, uint8_t maxG, uint8_t maxB ) {
+        r = stretch( r, maxR );
+        g = stretch( g, maxG );
+        b = stretch( b, maxB );
+    }
+
+    void stretchChannelsEvenly( uint8_t max ) {
+        stretchChannels( max, max, max );
+    }
+
+private:
+    uint8_t stretch( int value, uint8_t max ) {
+        return ( value * max ) >> 8;
+    }
+
+    uint8_t channelGamma( int channel ) {
+        /* The optimal gamma correction is x^2.8. However, this is expensive to
+         * compute. Therefore, we use x^3 for gamma correction. Also, we add a
+         * bias as the WS2812 LEDs do not turn on for values less than 4. */
+        if (channel == 0)
+            return channel;
+        channel = channel * channel * channel * 251;
+        channel >>= 24;
+        return static_cast< uint8_t >( 4 + channel );
+    }
+};
+
+union Hsv {
+    struct __attribute__ ((packed)) {
+        uint8_t h, s, v, a;
+    };
+    uint32_t value;
+
+    Hsv( uint8_t h, uint8_t s = 0, uint8_t v = 0, uint8_t a = 255 ) : h( h ), s( s ), v( v ), a( a ) {}
+    Hsv( Rgb r );
+    Hsv& operator=( Hsv h ) { swap( h ); return *this; }
+    Hsv& operator=( Rgb rgb );
+    bool operator==( Hsv in ) const { return in.value == value; }
+    void swap( Hsv& o ) { value = o.value; }
+};

+ 63 - 0
code/components/jomjol_controlGPIO/SmartLeds.cpp

@@ -0,0 +1,63 @@
+#include "SmartLeds.h"
+
+IsrCore SmartLed::_interruptCore = CoreCurrent;
+intr_handle_t SmartLed::_interruptHandle = NULL;
+
+SmartLed*& IRAM_ATTR SmartLed::ledForChannel( int channel ) {
+    static SmartLed* table[8] = { nullptr };
+    assert( channel < 8 );
+    return table[ channel ];
+}
+
+void IRAM_ATTR SmartLed::interruptHandler(void*) {
+    for (int channel = 0; channel != 8; channel++) {
+        auto self = ledForChannel( channel );
+
+        if ( RMT.int_st.val & (1 << (24 + channel ) ) ) { // tx_thr_event
+            if ( self )
+                self->copyRmtHalfBlock();
+            RMT.int_clr.val |= 1 << ( 24 + channel );
+        } else if ( RMT.int_st.val & ( 1 << (3 * channel ) ) ) { // tx_end
+            if ( self )
+                xSemaphoreGiveFromISR( self->_finishedFlag, nullptr );
+            RMT.int_clr.val |= 1 << ( 3 * channel );
+        }
+    }
+}
+
+void IRAM_ATTR SmartLed::copyRmtHalfBlock() {
+    int offset = detail::MAX_PULSES * _halfIdx;
+    _halfIdx = !_halfIdx;
+    int len = 3 - _componentPosition + 3 * ( _count - 1 );
+    len = std::min( len, detail::MAX_PULSES / 8 );
+
+    if ( !len ) {
+        for ( int i = 0; i < detail::MAX_PULSES; i++) {
+            RMTMEM.chan[ _channel].data32[i + offset ].val = 0;
+        }
+    }
+
+    int i;
+    for ( i = 0; i != len && _pixelPosition != _count; i++ ) {
+        uint8_t val = _buffer[ _pixelPosition ].getGrb( _componentPosition );
+        for ( int j = 0; j != 8; j++, val <<= 1 ) {
+            int bit = val >> 7;
+            int idx = i * 8 + offset + j;
+            RMTMEM.chan[ _channel ].data32[ idx ].val = _bitToRmt[ bit & 0x01 ].value;
+        }
+        if ( _pixelPosition == _count - 1 && _componentPosition == 2 ) {
+            RMTMEM.chan[ _channel ].data32[ i * 8 + offset + 7 ].duration1 =
+                _timing.TRS / ( detail::RMT_DURATION_NS * detail::DIVIDER );
+        }
+
+        _componentPosition++;
+        if ( _componentPosition == 3 ) {
+            _componentPosition = 0;
+            _pixelPosition++;
+        }
+    }
+
+    for ( i *= 8; i != detail::MAX_PULSES; i++ ) {
+        RMTMEM.chan[ _channel ].data32[ i + offset ].val = 0;
+    }
+}

+ 530 - 0
code/components/jomjol_controlGPIO/SmartLeds.h

@@ -0,0 +1,530 @@
+#pragma once
+
+/*
+ * A C++ driver for the WS2812 LEDs using the RMT peripheral on the ESP32.
+ *
+ * Jan "yaqwsx" Mrázek <email@honzamrazek.cz>
+ *
+ * Based on the work by Martin F. Falatic - https://github.com/FozzTexx/ws2812-demo
+ */
+
+/*
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <memory>
+#include <cassert>
+#include <cstring>
+
+#if defined ( ARDUINO )
+    extern "C" { // ...someone forgot to put in the includes...
+        #include "esp32-hal.h"
+        #include "esp_intr_alloc.h"
+        #include "esp_ipc.h"
+        #include "driver/gpio.h"
+        #include "driver/periph_ctrl.h"
+        #include "freertos/semphr.h"
+        #include "soc/rmt_struct.h"
+        #include <driver/spi_master.h>
+        #include "esp_idf_version.h"
+#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL( 4, 0, 0 )
+        #include "soc/dport_reg.h"
+#endif
+    }
+#elif defined ( ESP_PLATFORM )
+    extern "C" { // ...someone forgot to put in the includes...
+        #include <esp_intr_alloc.h>
+        #include <esp_ipc.h>
+        #include <driver/gpio.h>
+        #include <freertos/FreeRTOS.h>
+        #include <freertos/semphr.h>
+        #include <soc/dport_reg.h>
+        #include <soc/gpio_sig_map.h>
+        #include <soc/rmt_struct.h>
+        #include <driver/spi_master.h>
+    }
+    #include <stdio.h>
+#endif
+
+#include "Color.h"
+
+namespace detail {
+
+struct TimingParams {
+    uint32_t T0H;
+    uint32_t T1H;
+    uint32_t T0L;
+    uint32_t T1L;
+    uint32_t TRS;
+};
+
+union RmtPulsePair {
+    struct {
+        int duration0:15;
+        int level0:1;
+        int duration1:15;
+        int level1:1;
+    };
+    uint32_t value;
+};
+
+static const int DIVIDER = 4; // 8 still seems to work, but timings become marginal
+static const int MAX_PULSES = 32; // A channel has a 64 "pulse" buffer - we use half per pass
+static const double RMT_DURATION_NS = 12.5; // minimum time of a single RMT duration based on clock ns
+
+} // namespace detail
+
+using LedType = detail::TimingParams;
+
+static const LedType LED_WS2812  = { 350, 700, 800, 600, 50000 };
+static const LedType LED_WS2812B = { 400, 850, 850, 400, 50100 };
+static const LedType LED_SK6812  = { 300, 600, 900, 600, 80000 };
+static const LedType LED_WS2813  = { 350, 800, 350, 350, 300000 };
+
+enum BufferType { SingleBuffer = 0, DoubleBuffer };
+
+enum IsrCore { CoreFirst = 0, CoreSecond = 1, CoreCurrent = 2};
+
+class SmartLed {
+public:
+    // The RMT interrupt must not run on the same core as WiFi interrupts, otherwise SmartLeds
+    // can't fill the RMT buffer fast enough, resulting in rendering artifacts.
+    // Usually, that means you have to set isrCore == CoreSecond.
+    //
+    // If you use anything other than CoreCurrent, the FreeRTOS scheduler MUST be already running,
+    // so you can't use it if you define SmartLed as global variable.
+    SmartLed( const LedType& type, int count, int pin, int channel = 0, BufferType doubleBuffer = SingleBuffer, IsrCore isrCore = CoreCurrent)
+        : _timing( type ),
+          _channel( channel ),
+          _count( count ),
+          _firstBuffer( new Rgb[ count ] ),
+          _secondBuffer( doubleBuffer ? new Rgb[ count ] : nullptr ),
+          _finishedFlag( xSemaphoreCreateBinary() )
+    {
+        assert( channel >= 0 && channel < 8 );
+        assert( ledForChannel( channel ) == nullptr );
+
+        xSemaphoreGive( _finishedFlag );
+
+        DPORT_SET_PERI_REG_MASK( DPORT_PERIP_CLK_EN_REG, DPORT_RMT_CLK_EN );
+        DPORT_CLEAR_PERI_REG_MASK( DPORT_PERIP_RST_EN_REG, DPORT_RMT_RST );
+
+        PIN_FUNC_SELECT( GPIO_PIN_MUX_REG[ pin ], 2 );
+        gpio_set_direction( static_cast< gpio_num_t >( pin ), GPIO_MODE_OUTPUT );
+        gpio_matrix_out( static_cast< gpio_num_t >( pin ), RMT_SIG_OUT0_IDX + _channel, 0, 0 );
+        initChannel( _channel );
+
+        RMT.tx_lim_ch[ _channel ].limit = detail::MAX_PULSES;
+        RMT.int_ena.val |= 1 << ( 24 + _channel );
+        RMT.int_ena.val |= 1 << ( 3 * _channel );
+
+        _bitToRmt[ 0 ].level0 = 1;
+        _bitToRmt[ 0 ].level1 = 0;
+        _bitToRmt[ 0 ].duration0 = _timing.T0H / ( detail::RMT_DURATION_NS * detail::DIVIDER );
+        _bitToRmt[ 0 ].duration1 = _timing.T0L / ( detail::RMT_DURATION_NS * detail::DIVIDER );
+
+        _bitToRmt[ 1 ].level0 = 1;
+        _bitToRmt[ 1 ].level1 = 0;
+        _bitToRmt[ 1 ].duration0 = _timing.T1H / ( detail::RMT_DURATION_NS * detail::DIVIDER );
+        _bitToRmt[ 1 ].duration1 = _timing.T1L / ( detail::RMT_DURATION_NS * detail::DIVIDER );
+
+        if ( !anyAlive() ) {
+            _interruptCore = isrCore;
+            if(isrCore != CoreCurrent) {
+                ESP_ERROR_CHECK(esp_ipc_call_blocking(isrCore, registerInterrupt, NULL));
+            } else {
+                registerInterrupt(NULL);
+            }
+        }
+
+        ledForChannel( channel ) = this;
+    }
+
+    ~SmartLed() {
+        ledForChannel( _channel ) = nullptr;
+        if ( !anyAlive() ) {
+            if(_interruptCore != CoreCurrent) {
+                ESP_ERROR_CHECK(esp_ipc_call_blocking(_interruptCore, unregisterInterrupt, NULL));
+            } else {
+                unregisterInterrupt(NULL);
+            }
+        }
+        vSemaphoreDelete( _finishedFlag );
+    }
+
+    Rgb& operator[]( int idx ) {
+        return _firstBuffer[ idx ];
+    }
+
+    const Rgb& operator[]( int idx ) const {
+        return _firstBuffer[ idx ];
+    }
+
+    void show() {
+        _buffer = _firstBuffer.get();
+        startTransmission();
+        swapBuffers();
+    }
+
+    bool wait( TickType_t timeout = portMAX_DELAY ) {
+        if( xSemaphoreTake( _finishedFlag, timeout ) == pdTRUE ) {
+            xSemaphoreGive( _finishedFlag );
+            return true;
+        }
+        return false;
+    }
+
+    int size() const {
+        return _count;
+    }
+
+    Rgb *begin() { return _firstBuffer.get(); }
+    const Rgb *begin() const { return _firstBuffer.get(); }
+    const Rgb *cbegin() const { return _firstBuffer.get(); }
+
+    Rgb *end() { return _firstBuffer.get() + _count; }
+    const Rgb *end() const { return _firstBuffer.get() + _count; }
+    const Rgb *cend() const { return _firstBuffer.get() + _count; }
+
+private:
+    static intr_handle_t _interruptHandle;
+    static IsrCore _interruptCore;
+
+    static void initChannel( int channel ) {
+        RMT.apb_conf.fifo_mask = 1;  //enable memory access, instead of FIFO mode.
+        RMT.apb_conf.mem_tx_wrap_en = 1; //wrap around when hitting end of buffer
+        RMT.conf_ch[ channel ].conf0.div_cnt = detail::DIVIDER;
+        RMT.conf_ch[ channel ].conf0.mem_size = 1;
+        RMT.conf_ch[ channel ].conf0.carrier_en = 0;
+        RMT.conf_ch[ channel ].conf0.carrier_out_lv = 1;
+        RMT.conf_ch[ channel ].conf0.mem_pd = 0;
+
+        RMT.conf_ch[ channel ].conf1.rx_en = 0;
+        RMT.conf_ch[ channel ].conf1.mem_owner = 0;
+        RMT.conf_ch[ channel ].conf1.tx_conti_mode = 0;    //loop back mode.
+        RMT.conf_ch[ channel ].conf1.ref_always_on = 1;    // use apb clock: 80M
+        RMT.conf_ch[ channel ].conf1.idle_out_en = 1;
+        RMT.conf_ch[ channel ].conf1.idle_out_lv = 0;
+    }
+
+    static void registerInterrupt(void *) {
+        ESP_ERROR_CHECK(esp_intr_alloc( ETS_RMT_INTR_SOURCE, 0, interruptHandler, nullptr, &_interruptHandle));
+    }
+
+    static void unregisterInterrupt(void*) {
+        esp_intr_free( _interruptHandle );
+    }
+
+    static SmartLed*& IRAM_ATTR ledForChannel( int channel );
+    static void IRAM_ATTR interruptHandler( void* );
+
+    void IRAM_ATTR copyRmtHalfBlock();
+
+    void swapBuffers() {
+        if ( _secondBuffer )
+            _firstBuffer.swap( _secondBuffer );
+    }
+
+    void startTransmission() {
+        // Invalid use of the library
+        if( xSemaphoreTake( _finishedFlag, 0 ) != pdTRUE )
+            abort();
+
+        _pixelPosition = _componentPosition = _halfIdx = 0;
+        copyRmtHalfBlock();
+        if ( _pixelPosition < _count )
+            copyRmtHalfBlock();
+
+        RMT.conf_ch[ _channel ].conf1.mem_rd_rst = 1;
+        RMT.conf_ch[ _channel ].conf1.tx_start = 1;
+    }
+
+    static bool anyAlive() {
+        for ( int i = 0; i != 8; i++ )
+            if ( ledForChannel( i ) != nullptr ) return true;
+        return false;
+    }
+
+    const LedType& _timing;
+    int _channel;
+    detail::RmtPulsePair _bitToRmt[ 2 ];
+    int _count;
+    std::unique_ptr< Rgb[] > _firstBuffer;
+    std::unique_ptr< Rgb[] > _secondBuffer;
+    Rgb *_buffer;
+
+    xSemaphoreHandle _finishedFlag;
+
+    int _pixelPosition;
+    int _componentPosition;
+    int _halfIdx;
+};
+
+class Apa102 {
+public:
+    struct ApaRgb {
+        ApaRgb( uint8_t r = 0, uint8_t g = 0, uint32_t b = 0, uint32_t v = 0xFF )
+            : v( 0xE0 | v ), b( b ), g( g ), r( r )
+        {}
+
+        ApaRgb& operator=( const Rgb& o ) {
+            r = o.r;
+            g = o.g;
+            b = o.b;
+            return *this;
+        }
+
+        ApaRgb& operator=( const Hsv& o ) {
+            *this = Rgb{ o };
+            return *this;
+        }
+
+        uint8_t v, b, g, r;
+    };
+
+    static const int FINAL_FRAME_SIZE = 4;
+    static const int TRANS_COUNT = 2 + 8;
+
+    Apa102( int count, int clkpin, int datapin, BufferType doubleBuffer = SingleBuffer )
+        : _count( count ),
+          _firstBuffer( new ApaRgb[ count ] ),
+          _secondBuffer( doubleBuffer ? new ApaRgb[ count ] : nullptr ),
+          _initFrame( 0 )
+    {
+        spi_bus_config_t buscfg;
+        memset( &buscfg, 0, sizeof( buscfg ) );
+        buscfg.mosi_io_num = datapin;
+        buscfg.miso_io_num = -1;
+        buscfg.sclk_io_num = clkpin;
+        buscfg.quadwp_io_num = -1;
+        buscfg.quadhd_io_num = -1;
+        buscfg.max_transfer_sz = 65535;
+
+        spi_device_interface_config_t devcfg;
+        memset( &devcfg, 0, sizeof( devcfg ) );
+        devcfg.clock_speed_hz = 1000000;
+        devcfg.mode = 0;
+        devcfg.spics_io_num = -1;
+        devcfg.queue_size = TRANS_COUNT;
+        devcfg.pre_cb = nullptr;
+
+        auto ret = spi_bus_initialize( HSPI_HOST, &buscfg, 1 );
+        assert( ret == ESP_OK );
+
+        ret = spi_bus_add_device( HSPI_HOST, &devcfg, &_spi );
+        assert( ret == ESP_OK );
+
+        std::fill_n( _finalFrame, FINAL_FRAME_SIZE, 0xFFFFFFFF );
+    }
+
+    ~Apa102() {
+        // ToDo
+    }
+
+    ApaRgb& operator[]( int idx ) {
+        return _firstBuffer[ idx ];
+    }
+
+    const ApaRgb& operator[]( int idx ) const {
+        return _firstBuffer[ idx ];
+    }
+
+    void show() {
+        _buffer = _firstBuffer.get();
+        startTransmission();
+        swapBuffers();
+    }
+
+    void wait() {
+        for ( int i = 0; i != _transCount; i++ ) {
+            spi_transaction_t *t;
+            spi_device_get_trans_result( _spi, &t, portMAX_DELAY );
+        }
+    }
+private:
+    void swapBuffers() {
+        if ( _secondBuffer )
+            _firstBuffer.swap( _secondBuffer );
+    }
+
+    void startTransmission() {
+        for ( int i = 0; i != TRANS_COUNT; i++ ) {
+            _transactions[ i ].cmd = 0;
+            _transactions[ i ].addr = 0;
+            _transactions[ i ].flags = 0;
+            _transactions[ i ].rxlength = 0;
+            _transactions[ i ].rx_buffer = nullptr;
+        }
+        // Init frame
+        _transactions[ 0 ].length = 32;
+        _transactions[ 0 ].tx_buffer = &_initFrame;
+        spi_device_queue_trans( _spi, _transactions + 0, portMAX_DELAY );
+        // Data
+        _transactions[ 1 ].length = 32 * _count;
+        _transactions[ 1 ].tx_buffer = _buffer;
+        spi_device_queue_trans( _spi, _transactions + 1, portMAX_DELAY );
+        _transCount = 2;
+        // End frame
+        for ( int i = 0; i != 1 + _count / 32 / FINAL_FRAME_SIZE; i++ ) {
+            _transactions[ 2 + i ].length = 32 * FINAL_FRAME_SIZE;
+            _transactions[ 2 + i ].tx_buffer = _finalFrame;
+            spi_device_queue_trans( _spi, _transactions + 2 + i, portMAX_DELAY );
+            _transCount++;
+        }
+    }
+
+    spi_device_handle_t _spi;
+    int _count;
+    std::unique_ptr< ApaRgb[] > _firstBuffer, _secondBuffer;
+    ApaRgb *_buffer;
+
+    spi_transaction_t _transactions[ TRANS_COUNT ];
+    int _transCount;
+
+    uint32_t _initFrame;
+    uint32_t _finalFrame[ FINAL_FRAME_SIZE ];
+};
+
+class LDP8806 {
+public:
+    struct LDP8806_GRB {
+
+        LDP8806_GRB( uint8_t g_7bit = 0, uint8_t r_7bit = 0, uint32_t b_7bit = 0 )
+            : g( g_7bit ), r( r_7bit ), b( b_7bit )
+        {
+        }
+
+        LDP8806_GRB& operator=( const Rgb& o ) {
+            //Convert 8->7bit colour
+            r = ( o.r * 127 / 256 ) | 0x80;
+            g = ( o.g * 127 / 256 ) | 0x80;
+            b = ( o.b * 127 / 256 ) | 0x80;
+            return *this;
+        }
+
+        LDP8806_GRB& operator=( const Hsv& o ) {
+            *this = Rgb{ o };
+            return *this;
+        }
+
+        uint8_t g, r, b;
+    };
+
+    static const int LED_FRAME_SIZE_BYTES = sizeof( LDP8806_GRB );
+    static const int LATCH_FRAME_SIZE_BYTES = 3;
+    static const int TRANS_COUNT_MAX = 20;//Arbitrary, supports up to 600 LED
+
+    LDP8806( int count, int clkpin, int datapin, BufferType doubleBuffer = SingleBuffer, uint32_t clock_speed_hz = 2000000 )
+        : _count( count ),
+          _firstBuffer( new LDP8806_GRB[ count ] ),
+          _secondBuffer( doubleBuffer ? new LDP8806_GRB[ count ] : nullptr ),
+          // one 'latch'/start-of-data mark frame for every 32 leds
+          _latchFrames( ( count + 31 ) / 32 )
+    {
+        spi_bus_config_t buscfg;
+        memset( &buscfg, 0, sizeof( buscfg ) );
+        buscfg.mosi_io_num = datapin;
+        buscfg.miso_io_num = -1;
+        buscfg.sclk_io_num = clkpin;
+        buscfg.quadwp_io_num = -1;
+        buscfg.quadhd_io_num = -1;
+        buscfg.max_transfer_sz = 65535;
+
+        spi_device_interface_config_t devcfg;
+        memset( &devcfg, 0, sizeof( devcfg ) );
+        devcfg.clock_speed_hz = clock_speed_hz;
+        devcfg.mode = 0;
+        devcfg.spics_io_num = -1;
+        devcfg.queue_size = TRANS_COUNT_MAX;
+        devcfg.pre_cb = nullptr;
+
+        auto ret = spi_bus_initialize( HSPI_HOST, &buscfg, 1 );
+        assert( ret == ESP_OK );
+
+        ret = spi_bus_add_device( HSPI_HOST, &devcfg, &_spi );
+        assert( ret == ESP_OK );
+
+        std::fill_n( _latchBuffer, LATCH_FRAME_SIZE_BYTES, 0x0 );
+    }
+
+    ~LDP8806() {
+        // noop
+    }
+
+    LDP8806_GRB& operator[]( int idx ) {
+        return _firstBuffer[ idx ];
+    }
+
+    const LDP8806_GRB& operator[]( int idx ) const {
+        return _firstBuffer[ idx ];
+    }
+
+    void show() {
+        _buffer = _firstBuffer.get();
+        startTransmission();
+        swapBuffers();
+    }
+
+    void wait() {
+        while ( _transCount-- ) {
+            spi_transaction_t *t;
+            spi_device_get_trans_result( _spi, &t, portMAX_DELAY );
+        }
+    }
+private:
+    void swapBuffers() {
+        if ( _secondBuffer )
+            _firstBuffer.swap( _secondBuffer );
+    }
+
+    void startTransmission() {
+        _transCount = 0;
+        for ( int i = 0; i != TRANS_COUNT_MAX; i++ ) {
+            _transactions[ i ].cmd = 0;
+            _transactions[ i ].addr = 0;
+            _transactions[ i ].flags = 0;
+            _transactions[ i ].rxlength = 0;
+            _transactions[ i ].rx_buffer = nullptr;
+        }
+        // LED Data
+        _transactions[ 0 ].length = ( LED_FRAME_SIZE_BYTES * 8 ) * _count;
+        _transactions[ 0 ].tx_buffer = _buffer;
+        spi_device_queue_trans( _spi, _transactions + _transCount, portMAX_DELAY );
+        _transCount++;
+
+        // 'latch'/start-of-data marker frames
+        for ( int i = 0; i < _latchFrames; i++ ) {
+            _transactions[ _transCount ].length = ( LATCH_FRAME_SIZE_BYTES * 8 );
+            _transactions[ _transCount ].tx_buffer = _latchBuffer;
+            spi_device_queue_trans( _spi, _transactions + _transCount, portMAX_DELAY );
+            _transCount++;
+        }
+    }
+
+    spi_device_handle_t _spi;
+    int _count;
+    std::unique_ptr< LDP8806_GRB[] > _firstBuffer, _secondBuffer;
+    LDP8806_GRB *_buffer;
+
+    spi_transaction_t _transactions[ TRANS_COUNT_MAX ];
+    int _transCount;
+
+    int _latchFrames;
+    uint8_t _latchBuffer[ LATCH_FRAME_SIZE_BYTES ];
+};

+ 84 - 4
code/components/jomjol_controlGPIO/server_GPIO.cpp

@@ -107,7 +107,8 @@ void GpioPin::init()
     //configure GPIO with the given settings
     gpio_config(&io_conf);
 
-    if (_interruptType != GPIO_INTR_DISABLE) {
+//    if (_interruptType != GPIO_INTR_DISABLE) {                // ohne GPIO_PIN_MODE_EXTERNAL_FLASH_WS281X, wenn das genutzt wird, dann soll auch der Handler hier nicht initialisiert werden, da das dann über SmartLED erfolgt.
+    if ((_interruptType != GPIO_INTR_DISABLE) && (_interruptType != GPIO_PIN_MODE_EXTERNAL_FLASH_WS281X)) {
         //hook isr handler for specific gpio pin
         ESP_LOGD(TAG_SERVERGPIO, "GpioPin::init add isr handler for GPIO %d\r\n", _gpio);
         gpio_isr_handler_add(_gpio, gpio_isr_handler, (void*)&_gpio);
@@ -212,6 +213,8 @@ void GpioHandler::init()
     // printf("wait before start %ldms\r\n", (long) xDelay);
     // vTaskDelay( xDelay );
 
+    printf("*************** Start GPIOHandler_Init *****************\n");
+
     if (gpioMap == NULL) {
         gpioMap = new std::map<gpio_num_t, GpioPin*>();
     } else {
@@ -295,16 +298,24 @@ bool GpioHandler::readConfig()
     std::string line = "";
     bool disabledLine = false;
     bool eof = false;
+    gpio_num_t gpioExtLED = (gpio_num_t) 0;
+    
+//    printf("readConfig - Start 1\n");
         
-    while ((!configFile.GetNextParagraph(line, disabledLine, eof) || (line.compare("[GPIO]") != 0)) && !disabledLine && !eof) {}
+    while ((!configFile.GetNextParagraph(line, disabledLine, eof) || (line.compare("[GPIO]") != 0)) && !eof) {}
     if (eof)
         return false;
-    
+
+//    printf("readConfig - Start 2 line: %s, disabbledLine: %d\n", line.c_str(), (int) disabledLine);
+
+
     _isEnabled = !disabledLine;
 
     if (!_isEnabled)
         return false;
 
+//    printf("readConfig - Start 3\n");
+
 //    std::string mainTopicMQTT = "";
     std::string mainTopicMQTT = GetMQTTMainTopic();
     if (mainTopicMQTT.length() > 0)
@@ -346,10 +357,40 @@ bool GpioHandler::readConfig()
             GpioPin* gpioPin = new GpioPin(gpioNr, gpioName, pinMode, intType,dutyResolution, mqttTopic, httpEnabled);
             (*gpioMap)[gpioNr] = gpioPin;
 
+            if (pinMode == GPIO_PIN_MODE_EXTERNAL_FLASH_WS281X)
+            {
+                printf("Set WS2812 to GPIO %d\n", gpioNr);
+                gpioExtLED = gpioNr;
+            }
+
             if (intType != GPIO_INTR_DISABLE) {
                 registerISR = true;
             }
         }
+        if (toUpper(zerlegt[0]) == "LEDNUMBERS")
+        {
+            LEDNumbers = stoi(zerlegt[1]);
+        }
+        if (toUpper(zerlegt[0]) == "LEDCOLOR")
+        {
+            uint8_t _r, _g, _b;
+            _r = stoi(zerlegt[1]);
+            _g = stoi(zerlegt[2]);
+            _b = stoi(zerlegt[3]);
+
+            LEDColor = Rgb{_r, _g, _b};
+        }
+        if (toUpper(zerlegt[0]) == "LEDTYPE")
+        {
+            if (zerlegt[1] == "WS2812")
+                LEDType = LED_WS2812;
+            if (zerlegt[1] == "WS2812B")
+                LEDType = LED_WS2812B;
+            if (zerlegt[1] == "SK6812")
+                LEDType = LED_SK6812;
+            if (zerlegt[1] == "WS2813")
+                LEDType = LED_WS2813;
+        }
     }
 
     if (registerISR) {
@@ -357,6 +398,28 @@ bool GpioHandler::readConfig()
         gpio_install_isr_service(ESP_INTR_FLAG_LOWMED | ESP_INTR_FLAG_IRAM);
     }
 
+    if (gpioExtLED > 0)
+    {
+    //    LogFile.WriteToFile("Startsequence 06");      
+//        vTaskDelay( xDelay );   
+//        xDelay = 5000 / portTICK_PERIOD_MS;
+//        printf("main: sleep for : %ldms\n", (long) xDelay);
+
+        SmartLed leds( LED_WS2812, 2, GPIO_NUM_12, 0, DoubleBuffer );
+
+
+        leds[ 0 ] = Rgb{ 255, 0, 0 };
+        leds[ 1 ] = Rgb{ 255, 255, 255 };
+        leds.show();    
+/*
+//        _SmartLED = new SmartLed(LEDType, LEDNumbers, gpioExtLED, 0, DoubleBuffer);
+        _SmartLED = new SmartLed( LED_WS2812, 2, GPIO_NUM_12, 0, DoubleBuffer );
+        (*_SmartLED)[ 0 ] = Rgb{ 255, 0, 0 };
+        (*_SmartLED)[ 1 ] = LEDColor;
+        _SmartLED->show();
+*/
+    }
+
     return true;
 }
 
@@ -498,7 +561,24 @@ void GpioHandler::flashLightEnable(bool value)
                 } else {
                     ESP_LOGE(TAG_SERVERGPIO, "Can't set flash light pin GPIO %d.  Error: %s\r\n", (int)it->first, resp_str.c_str());
                 }
-            }
+            } else 
+                {
+                    if (it->second->getMode() == GPIO_PIN_MODE_EXTERNAL_FLASH_WS281X)
+                    {
+                        SmartLed leds( LEDType, LEDNumbers, it->second->getGPIO(), 0, DoubleBuffer );
+                        if (value)
+                        {
+                            for (int i = 0; i < LEDNumbers; ++i)
+                                leds[i] = LEDColor;
+                        }
+                        else
+                        {
+                            for (int i = 0; i < LEDNumbers; ++i)
+                                leds[i] = Rgb{0, 0, 0};
+                        }
+                        leds.show();   
+                    }
+                }
         }
     }
 }

+ 8 - 0
code/components/jomjol_controlGPIO/server_GPIO.h

@@ -7,6 +7,8 @@
 #include <map>
 #include "driver/gpio.h"
 
+#include "SmartLeds.h"
+
 //#include "ClassControllCamera.h"
 
 typedef enum {
@@ -45,6 +47,7 @@ public:
     void gpioInterrupt(int value);
     gpio_int_type_t getInterruptType() { return _interruptType; }
     gpio_pin_mode_t getMode() { return _mode; }
+    gpio_num_t getGPIO(){return _gpio;};
 
 private:
     gpio_num_t _gpio;
@@ -80,6 +83,11 @@ private:
     TaskHandle_t xHandleTaskGpio = NULL;
     bool _isEnabled = false;
 
+    int LEDNumbers = 2;
+    Rgb LEDColor = Rgb{ 255, 255, 255 };
+    LedType LEDType = LED_WS2812;
+
+
     bool readConfig();
     void clear();
     

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

@@ -499,6 +499,7 @@ void CCamera::LightOnOff(bool status)
 {
     GpioHandler* gpioHandler = gpio_handler_get();
     if ((gpioHandler != NULL) && (gpioHandler->isEnabled())) {
+        printf("Use gpioHandler flashLigh\n");
         gpioHandler->flashLightEnable(status);
     }  else {
         // Init the GPIO

+ 2 - 0
code/components/jomjol_fileserver_ota/server_help.cpp

@@ -111,6 +111,8 @@ esp_err_t set_content_type_from_file(httpd_req_t *req, const char *filename)
         return httpd_resp_set_type(req, "image/jpeg");
     } else if (IS_FILE_EXT(filename, ".ico")) {
         return httpd_resp_set_type(req, "image/x-icon");
+    } else if (IS_FILE_EXT(filename, ".js")) {
+        return httpd_resp_set_type(req, "text/javascript");
     }
     /* This is a limited set only */
     /* For any other type always set as plain text */

+ 57 - 45
code/components/jomjol_flowcontroll/ClassFlowCNNGeneral.cpp

@@ -21,23 +21,23 @@ ClassFlowCNNGeneral::ClassFlowCNNGeneral(ClassFlowAlignment *_flowalign, t_CNNTy
     previousElement = NULL;   
     SaveAllFiles = false; 
     disabled = false;
-    extendedResolution = false;
+//    extendedResolution = false;
     isLogImageSelect = false;
     CNNType = AutoDetect;
     CNNType = _cnntype;
     flowpostalignment = _flowalign;
 }
 
-
+/*
 int ClassFlowCNNGeneral::AnzahlROIs(int _analog = 0)
 {
     int zw = GENERAL[_analog]->ROI.size();
     if (extendedResolution && (CNNType != Digital)) zw++;   // da letzte Ziffer inkl Nachhkomma, es sei denn, das Nachkomma gibt es nicht (Digital)
     return zw;
 } 
+*/
 
-
-string ClassFlowCNNGeneral::getReadout(int _analog = 0)
+string ClassFlowCNNGeneral::getReadout(int _analog = 0, bool _extendedResolution = false)
 {
     string result = "";    
     if (GENERAL[_analog]->ROI.size() == 0)
@@ -45,20 +45,20 @@ string ClassFlowCNNGeneral::getReadout(int _analog = 0)
 
     if (CNNType == Analogue)
     {
-        float zahl = GENERAL[_analog]->ROI[GENERAL[_analog]->ROI.size() - 1]->result;
-        int ergebnis_nachkomma = ((int) floor(zahl * 10)) % 10;
+        float zahl = GENERAL[_analog]->ROI[GENERAL[_analog]->ROI.size() - 1]->result_float;
+        int ergebnis_nachkomma = ((int) floor(zahl * 10) + 10) % 10;
 
         int prev = -1;
 
-        prev = ZeigerEval(GENERAL[_analog]->ROI[GENERAL[_analog]->ROI.size() - 1]->result, prev);
+        prev = ZeigerEval(GENERAL[_analog]->ROI[GENERAL[_analog]->ROI.size() - 1]->result_float, prev);
         result = std::to_string(prev);
 
-        if (extendedResolution && (CNNType != Digital))
+        if (_extendedResolution && (CNNType != Digital))
             result = result + std::to_string(ergebnis_nachkomma);
 
         for (int i = GENERAL[_analog]->ROI.size() - 2; i >= 0; --i)
         {
-            prev = ZeigerEval(GENERAL[_analog]->ROI[i]->result, prev);
+            prev = ZeigerEval(GENERAL[_analog]->ROI[i]->result_float, prev);
             result = std::to_string(prev) + result;
         }
     }
@@ -67,10 +67,10 @@ string ClassFlowCNNGeneral::getReadout(int _analog = 0)
     {
         for (int i = 0; i < GENERAL[_analog]->ROI.size(); ++i)
         {
-            if (GENERAL[_analog]->ROI[i]->resultklasse == 10)
+            if (GENERAL[_analog]->ROI[i]->result_klasse >= 10)
                 result = result + "N";
             else
-                result = result + std::to_string(GENERAL[_analog]->ROI[i]->resultklasse);
+                result = result + std::to_string(GENERAL[_analog]->ROI[i]->result_klasse);
         }
     }
 
@@ -79,34 +79,35 @@ string ClassFlowCNNGeneral::getReadout(int _analog = 0)
 //        int ergebnis_nachkomma = -1;
         int zif_akt = -1;
 
-        float zahl = GENERAL[_analog]->ROI[GENERAL[_analog]->ROI.size() - 1]->result;
+        float zahl = GENERAL[_analog]->ROI[GENERAL[_analog]->ROI.size() - 1]->result_float;
         if (zahl >= 0)       // NaN?
         {
-            if (extendedResolution)
+            if (_extendedResolution)
             {
                 int ergebnis_nachkomma = ((int) floor(zahl * 10)) % 10;
                 int ergebnis_vorkomma = ((int) floor(zahl)) % 10;
 
                 result = std::to_string(ergebnis_vorkomma) + std::to_string(ergebnis_nachkomma);
+                zif_akt = ergebnis_vorkomma;
             }
             else
             {
-                zif_akt = ZeigerEvalHybrid(GENERAL[_analog]->ROI[GENERAL[_analog]->ROI.size() - 1]->result, -1, -1);
+                zif_akt = ZeigerEvalHybrid(GENERAL[_analog]->ROI[GENERAL[_analog]->ROI.size() - 1]->result_float, -1, -1);
                 result = std::to_string(zif_akt);
             }
         }
         else
         {
             result = "N";
-            if (extendedResolution && (CNNType != Digital))
+            if (_extendedResolution && (CNNType != Digital))
                 result = "NN";
         }
 
         for (int i = GENERAL[_analog]->ROI.size() - 2; i >= 0; --i)
         {
-            if (GENERAL[_analog]->ROI[i]->result >= 0)
+            if (GENERAL[_analog]->ROI[i]->result_float >= 0)
             {
-                zif_akt = ZeigerEvalHybrid(GENERAL[_analog]->ROI[i]->result, GENERAL[_analog]->ROI[i+1]->result, zif_akt);
+                zif_akt = ZeigerEvalHybrid(GENERAL[_analog]->ROI[i]->result_float, GENERAL[_analog]->ROI[i+1]->result_float, zif_akt);
                 result = std::to_string(zif_akt) + result;
             }
             else
@@ -117,7 +118,6 @@ string ClassFlowCNNGeneral::getReadout(int _analog = 0)
         }
     }
 
-
     return result;
 }
 
@@ -129,43 +129,43 @@ int ClassFlowCNNGeneral::ZeigerEvalHybrid(float zahl, float zahl_vorgaenger, int
     if (zahl_vorgaenger < 0)                // keine Vorzahl vorhanden !!! --> Runde die Zahl
     {
         if ((ergebnis_nachkomma <= 2) || (ergebnis_nachkomma >= 8))     // Band um die Ziffer --> Runden, da Ziffer im Rahmen Ungenauigkeit erreicht
-            return (int) round(zahl);
+            return ((int) round(zahl) + 10) % 10;
         else
-            return (int) trunc(zahl);
+            return ((int) trunc(zahl) + 10) % 10;
     }
 
     if (zahl_vorgaenger > 9.2)              // Ziffernwechsel beginnt
     {
         if (eval_vorgaenger == 0)           // Wechsel hat schon stattgefunden
         {
-            return (int) round(zahl);       // Annahme, dass die neue Zahl schon in der Nähe des Ziels ist
+            return ((int) round(zahl) + 10) % 10;      // Annahme, dass die neue Zahl schon in der Nähe des Ziels ist
         }
         else
         {
             if (zahl_vorgaenger <= 9.5)     // Wechsel startet gerade, aber beginnt erst
             {
                 if ((ergebnis_nachkomma <= 2) || (ergebnis_nachkomma >= 8))     // Band um die Ziffer --> Runden, da Ziffer im Rahmen Ungenauigkeit erreicht
-                    return (int) round(zahl);
+                    return ((int) round(zahl) + 10) % 10;
                 else
-                    return (int) trunc(zahl);
+                    return ((int) trunc(zahl) + 10) % 10;
             }
             else
             {
-                return (int) trunc(zahl);   // Wechsel schon weiter fortgeschritten, d.h. über 2 als Nachkomma
+                return ((int) trunc(zahl) + 10) % 10;   // Wechsel schon weiter fortgeschritten, d.h. über 2 als Nachkomma
             }
         }
     }
 
     if ((ergebnis_nachkomma <= 2) || (ergebnis_nachkomma >= 8))     // Band um die Ziffer --> Runden, da Ziffer im Rahmen Ungenauigkeit erreicht
-        return (int) round(zahl);
+        return ((int) round(zahl) + 10) % 10;
 
-    return (int) trunc(zahl);
+    return ((int) trunc(zahl) + 10) % 10;
 }
 
 int ClassFlowCNNGeneral::ZeigerEval(float zahl, int ziffer_vorgaenger)
 {
-    int ergebnis_nachkomma = ((int) floor(zahl * 10)) % 10;
-    int ergebnis_vorkomma = ((int) floor(zahl)) % 10;
+    int ergebnis_nachkomma = ((int) floor(zahl * 10) + 10) % 10;
+    int ergebnis_vorkomma = ((int) floor(zahl) + 10) % 10;
     int ergebnis, ergebnis_rating;
 
     if (ziffer_vorgaenger == -1)
@@ -182,7 +182,7 @@ int ClassFlowCNNGeneral::ZeigerEval(float zahl, int ziffer_vorgaenger)
     if (ergebnis == -1)
         ergebnis+=10;
 
-    ergebnis = ergebnis % 10;
+    ergebnis = (ergebnis + 10) % 10;
     return ergebnis;
 }
 
@@ -260,7 +260,7 @@ bool ClassFlowCNNGeneral::ReadParameter(FILE* pfile, string& aktparamgraph)
             neuroi->posy = std::stoi(zerlegt[2]);
             neuroi->deltax = std::stoi(zerlegt[3]);
             neuroi->deltay = std::stoi(zerlegt[4]);
-            neuroi->result = -1;
+            neuroi->result_float = -1;
             neuroi->image = NULL;
             neuroi->image_org = NULL;
         }
@@ -271,13 +271,16 @@ bool ClassFlowCNNGeneral::ReadParameter(FILE* pfile, string& aktparamgraph)
                 SaveAllFiles = true;
         }
 
+/*
         if ((toUpper(zerlegt[0]) == "EXTENDEDRESOLUTION") && (zerlegt.size() > 1))
         {
             if (toUpper(zerlegt[1]) == "TRUE")
                 extendedResolution = true;
         }
+*/
     }
 
+
    for (int _ana = 0; _ana < GENERAL.size(); ++_ana)
         for (int i = 0; i < GENERAL[_ana]->ROI.size(); ++i)
         {
@@ -482,6 +485,7 @@ bool ClassFlowCNNGeneral::doNeuralNetwork(string time)
             default:
                 printf("ERROR ERROR ERROR - tflite passt nicht zur Firmware - ERROR ERROR ERROR\n");
         }
+//        flowpostprocessing->UpdateNachkommaDecimalShift();
     }
 
     for (int _ana = 0; _ana < GENERAL.size(); ++_ana)
@@ -503,27 +507,27 @@ bool ClassFlowCNNGeneral::doNeuralNetwork(string time)
                         f1 = tflite->GetOutputValue(0);
                         f2 = tflite->GetOutputValue(1);
                         float result = fmod(atan2(f1, f2) / (M_PI * 2) + 2, 1);
-                        GENERAL[_ana]->ROI[i]->result = result * 10;
-                        printf("Result General(Analog)%i: %f\n", i, GENERAL[_ana]->ROI[i]->result); 
+                        GENERAL[_ana]->ROI[i]->result_float = result * 10;
+                        printf("Result General(Analog)%i: %f\n", i, GENERAL[_ana]->ROI[i]->result_float); 
                         if (isLogImage)
-                            LogImage(logPath, GENERAL[_ana]->ROI[i]->name, &GENERAL[_ana]->ROI[i]->result, NULL, time, GENERAL[_ana]->ROI[i]->image_org);
+                            LogImage(logPath, GENERAL[_ana]->ROI[i]->name, &GENERAL[_ana]->ROI[i]->result_float, NULL, time, GENERAL[_ana]->ROI[i]->image_org);
                     } break;
                 case Digital:
                     {
-                        GENERAL[_ana]->ROI[i]->resultklasse = 0;
-                        GENERAL[_ana]->ROI[i]->resultklasse = tflite->GetClassFromImageBasis(GENERAL[_ana]->ROI[i]->image);
-                        printf("Result General(Digit)%i: %d\n", i, GENERAL[_ana]->ROI[i]->resultklasse);
+                        GENERAL[_ana]->ROI[i]->result_klasse = 0;
+                        GENERAL[_ana]->ROI[i]->result_klasse = tflite->GetClassFromImageBasis(GENERAL[_ana]->ROI[i]->image);
+                        printf("Result General(Digit)%i: %d\n", i, GENERAL[_ana]->ROI[i]->result_klasse);
 
                         if (isLogImage)
                         {
                             if (isLogImageSelect)
                             {
                                 if (LogImageSelect.find(GENERAL[_ana]->ROI[i]->name) != std::string::npos)
-                                    LogImage(logPath, GENERAL[_ana]->ROI[i]->name, NULL, &GENERAL[_ana]->ROI[i]->resultklasse, time, GENERAL[_ana]->ROI[i]->image_org);
+                                    LogImage(logPath, GENERAL[_ana]->ROI[i]->name, NULL, &GENERAL[_ana]->ROI[i]->result_klasse, time, GENERAL[_ana]->ROI[i]->image_org);
                             }
                             else
                             {
-                                LogImage(logPath, GENERAL[_ana]->ROI[i]->name, NULL, &GENERAL[_ana]->ROI[i]->resultklasse, time, GENERAL[_ana]->ROI[i]->image_org);
+                                LogImage(logPath, GENERAL[_ana]->ROI[i]->name, NULL, &GENERAL[_ana]->ROI[i]->result_klasse, time, GENERAL[_ana]->ROI[i]->image_org);
                             }
                         }
                     } break;
@@ -543,16 +547,16 @@ bool ClassFlowCNNGeneral::doNeuralNetwork(string time)
                         if (debugdetailgeneral) LogFile.WriteToFile(_zwres);
 
                         if ((_num == 10) || (_nachkomma == 10))                      // NaN detektiert
-                            GENERAL[_ana]->ROI[i]->result = -1;
+                            GENERAL[_ana]->ROI[i]->result_float = -1;
                         else
-                            GENERAL[_ana]->ROI[i]->result = fmod((double) _num + (((double)_nachkomma)-5)/10 + (double) 10, 10);
+                            GENERAL[_ana]->ROI[i]->result_float = fmod((double) _num + (((double)_nachkomma)-5)/10 + (double) 10, 10);
 
-                        printf("Result General(DigitalHyprid)%i: %f\n", i, GENERAL[_ana]->ROI[i]->result); 
-                        _zwres = "Result General(DigitalHyprid)" + to_string(i) + ": " + to_string(GENERAL[_ana]->ROI[i]->result);
+                        printf("Result General(DigitalHyprid)%i: %f\n", i, GENERAL[_ana]->ROI[i]->result_float); 
+                        _zwres = "Result General(DigitalHyprid)" + to_string(i) + ": " + to_string(GENERAL[_ana]->ROI[i]->result_float);
                         if (debugdetailgeneral) LogFile.WriteToFile(_zwres);
 
                         if (isLogImage)
-                            LogImage(logPath, GENERAL[_ana]->ROI[i]->name, &GENERAL[_ana]->ROI[i]->result, NULL, time, GENERAL[_ana]->ROI[i]->image_org);
+                            LogImage(logPath, GENERAL[_ana]->ROI[i]->name, &GENERAL[_ana]->ROI[i]->result_float, NULL, time, GENERAL[_ana]->ROI[i]->image_org);
                     } break;
                 default:
                     break;
@@ -567,7 +571,8 @@ bool ClassFlowCNNGeneral::doNeuralNetwork(string time)
 
 bool ClassFlowCNNGeneral::isExtendedResolution(int _number)
 {
-    if (extendedResolution && !(CNNType == Digital))
+//    if (extendedResolution && !(CNNType == Digital))
+    if (!(CNNType == Digital))
         return true;
 
     return false;
@@ -600,13 +605,20 @@ std::vector<HTMLInfo*> ClassFlowCNNGeneral::GetHTMLInfo()
                 zw->filename_org = GENERAL[_ana]->name + "_" + GENERAL[_ana]->ROI[i]->name + ".jpg";
             }
 
-            zw->val = GENERAL[_ana]->ROI[i]->result;
+            if (CNNType == Digital)
+                zw->val = GENERAL[_ana]->ROI[i]->result_klasse;
+            else
+                zw->val = GENERAL[_ana]->ROI[i]->result_float;
             zw->image = GENERAL[_ana]->ROI[i]->image;
             zw->image_org = GENERAL[_ana]->ROI[i]->image_org;
 
+//            printf("Push %s\n", zw->filename.c_str());
+
             result.push_back(zw);
         }
 
+//    printf("größe: %d\n", result.size());
+
     return result;
 }
 

+ 15 - 20
code/components/jomjol_flowcontroll/ClassFlowCNNGeneral.h

@@ -1,6 +1,10 @@
-#pragma once
-#include "ClassFlowImage.h"
+#ifndef __CLASSCNNGENERAL__
+#define __CLASSCNNGENERAL__
+
+#include"ClassFlowDefineTypes.h"
 #include "ClassFlowAlignment.h"
+// #include "ClassFlowPostProcessing.h"
+
 
 enum t_CNNType {
     AutoDetect,
@@ -10,20 +14,6 @@ enum t_CNNType {
     None
  };
 
-struct roi {
-    int posx, posy, deltax, deltay;
-    float result;
-    int resultklasse;
-    string name;
-    CImageBasis *image, *image_org;
-};
-
-struct general {
-    string name;
-    std::vector<roi*> ROI;
-};
-
-
 class ClassFlowCNNGeneral :
     public ClassFlowImage
 {
@@ -36,8 +26,9 @@ protected:
     bool isLogImageSelect;
     string LogImageSelect;
     ClassFlowAlignment* flowpostalignment;
+//    ClassFlowPostProcessing *flowpostprocessing = NULL;
     bool SaveAllFiles;   
-    bool extendedResolution;
+//    bool extendedResolution;
 
     int ZeigerEval(float zahl, int ziffer_vorgaenger);
     int ZeigerEvalHybrid(float zahl, float zahl_vorgaenger, int eval_vorgaenger);
@@ -53,20 +44,22 @@ public:
     bool doFlow(string time);
 
     string getHTMLSingleStep(string host);
-    string getReadout(int _analog);   
+    string getReadout(int _analog, bool _extendedResolution);   
 
     void DrawROI(CImageBasis *_zw); 
 
    	std::vector<HTMLInfo*> GetHTMLInfo();   
 
-    int AnzahlROIs(int _analog);
+//    int AnzahlROIs(int _analog);
     int getAnzahlGENERAL();
     general* GetGENERAL(int _analog);
     general* GetGENERAL(string _name, bool _create);
     general* FindGENERAL(string _name_number);    
     string getNameGENERAL(int _analog);    
 
-    bool isExtendedResolution(int _number = 0); 
+    bool isExtendedResolution(int _number = 0);
+
+//    void setPostprocessing(ClassFlowPostProcessing *_fpp){flowpostprocessing = _fpp;}; 
 
     void UpdateNameNumbers(std::vector<std::string> *_name_numbers);
 
@@ -75,3 +68,5 @@ public:
     string name(){return "ClassFlowCNNGeneral";}; 
 };
 
+#endif
+

+ 85 - 101
code/components/jomjol_flowcontroll/ClassFlowControll.cpp

@@ -74,16 +74,13 @@ std::string ClassFlowControll::TranslateAktstatus(std::string _input)
 }
 
 
-std::vector<HTMLInfo*> ClassFlowControll::GetAllDigital()
+std::vector<HTMLInfo*> ClassFlowControll::GetAllDigital() 
 {
-/*    
-    for (int i = 0; i < FlowControll.size(); ++i)
-        if (FlowControll[i]->name().compare("ClassFlowCNNGeneral") == 0)
-            return ((ClassFlowCNNGeneral*) (FlowControll[i]))->GetHTMLInfo();
-*/
-
     if (flowdigit)
-        flowdigit->GetHTMLInfo();
+    {
+        printf("ClassFlowControll::GetAllDigital - flowdigit != NULL\n");
+        return flowdigit->GetHTMLInfo();
+    }
 
     std::vector<HTMLInfo*> empty;
     return empty;
@@ -91,17 +88,8 @@ std::vector<HTMLInfo*> ClassFlowControll::GetAllDigital()
 
 std::vector<HTMLInfo*> ClassFlowControll::GetAllAnalog()
 {
-/*
-    for (int i = 0; i < FlowControll.size(); ++i)
-        if (FlowControll[i]->name().compare("ClassFlowAnalog") == 0)
-            return ((ClassFlowAnalog*) (FlowControll[i]))->GetHTMLInfo();
-
-    std::vector<HTMLInfo*> empty;
-    return empty;
-*/
-
     if (flowanalog)
-        flowanalog->GetHTMLInfo();
+        return flowanalog->GetHTMLInfo();
 
     std::vector<HTMLInfo*> empty;
     return empty;
@@ -252,8 +240,8 @@ void ClassFlowControll::InitFlow(std::string config)
 
 }
 
-std::string ClassFlowControll::getActStatus(){
-    return aktstatus;
+std::string* ClassFlowControll::getActStatus(){
+    return &aktstatus;
 }
 
 void ClassFlowControll::doFlowMakeImageOnly(string time){
@@ -297,7 +285,7 @@ bool ClassFlowControll::doFlow(string time)
         if (!FlowControll[i]->doFlow(time)){
             repeat++;
             LogFile.WriteToFile("Fehler im vorheriger Schritt - wird zum " + to_string(repeat) + ". Mal wiederholt");
-            i = -1;    // vorheriger Schritt muss wiederholt werden (vermutlich Bilder aufnehmen)
+            if (i) i -= 1;    // vorheriger Schritt muss wiederholt werden (vermutlich Bilder aufnehmen)
             result = false;
             if (repeat > 5) {
                 LogFile.WriteToFile("Wiederholung 5x nicht erfolgreich --> reboot");
@@ -323,40 +311,42 @@ bool ClassFlowControll::doFlow(string time)
 
 string ClassFlowControll::getReadoutAll(int _type)
 {
-    std::vector<NumberPost*> numbers = flowpostprocessing->GetNumbers();
     std::string out = "";
-
-    for (int i = 0; i < numbers.size(); ++i)
+    if (flowpostprocessing)
     {
-        out = out + numbers[i]->name + "\t";
-        switch (_type) {
-            case READOUT_TYPE_VALUE:
-                out = out + numbers[i]->ReturnValueNoError;
-                break;
-            case READOUT_TYPE_PREVALUE:
-                if (flowpostprocessing->PreValueUse)
-                {
-                    if (numbers[i]->PreValueOkay)
-                        out = out + numbers[i]->ReturnPreValue;
+        std::vector<NumberPost*> *numbers = flowpostprocessing->GetNumbers();
+
+        for (int i = 0; i < (*numbers).size(); ++i)
+        {
+            out = out + (*numbers)[i]->name + "\t";
+            switch (_type) {
+                case READOUT_TYPE_VALUE:
+                    out = out + (*numbers)[i]->ReturnValueNoError;
+                    break;
+                case READOUT_TYPE_PREVALUE:
+                    if (flowpostprocessing->PreValueUse)
+                    {
+                        if ((*numbers)[i]->PreValueOkay)
+                            out = out + (*numbers)[i]->ReturnPreValue;
+                        else
+                            out = out + "PreValue too old";                
+                    }
                     else
-                        out = out + "PreValue too old";                
-                }
-                else
-                    out = out + "PreValue deactivated";
-                break;
-            case READOUT_TYPE_RAWVALUE:
-                out = out + numbers[i]->ReturnRawValue;
-                break;
-            case READOUT_TYPE_ERROR:
-                out = out + numbers[i]->ErrorMessageText;
-                break;
+                        out = out + "PreValue deactivated";
+                    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";
         }
-        if (i < numbers.size()-1)
-            out = out + "\r\n";
+    //    printf("OUT: %s", out.c_str());
     }
 
-//    printf("OUT: %s", out.c_str());
-
     return out;
 }	
 
@@ -564,65 +554,59 @@ esp_err_t ClassFlowControll::GetJPGStream(std::string _fn, httpd_req_t *req)
     {
         _send = flowalignment->ImageBasis;  
     }
-
-
-
-    if (_fn == "alg_roi.jpg")
-    {
-        CImageBasis* _imgzw = new CImageBasis(flowalignment->ImageBasis);
-        flowalignment->DrawRef(_imgzw);
-        if (flowdigit) flowdigit->DrawROI(_imgzw);
-        if (flowanalog) flowanalog->DrawROI(_imgzw);
-
-/*/////////////////////////////////////        
-        cimg_library::CImg<unsigned char> cimg(_imgzw->rgb_image, _imgzw->bpp, _imgzw->width, _imgzw->height, 1);
-    
-        //Convert cimg type
-//        cimg.permute_axes("yzcx");
-        cimg.draw_text(300, 300, "Dies ist ein Test", "black");
-
-        
-        //Convert back to stb type to save
-//        cimg.permute_axes("cxyz");
-*////////////////////////////////////
-        _send = _imgzw;
-        Dodelete = true;
-    }
-
-    std::vector<HTMLInfo*> htmlinfo;
-    htmlinfo = GetAllDigital();
-    for (int i = 0; i < htmlinfo.size(); ++i)
+    else
     {
-        if (_fn == htmlinfo[i]->filename)
+        if (_fn == "alg_roi.jpg")
         {
-            if (htmlinfo[i]->image)
-                _send = htmlinfo[i]->image;
+            CImageBasis* _imgzw = new CImageBasis(flowalignment->ImageBasis);
+            flowalignment->DrawRef(_imgzw);
+            if (flowdigit) flowdigit->DrawROI(_imgzw);
+            if (flowanalog) flowanalog->DrawROI(_imgzw);
+            _send = _imgzw;
+            Dodelete = true;
         }
-        if (_fn == htmlinfo[i]->filename_org)
+        else
         {
-            if (htmlinfo[i]->image_org)
-                _send = htmlinfo[i]->image_org;        
-        }
-        delete htmlinfo[i];
-    }
-    htmlinfo.clear();
+            std::vector<HTMLInfo*> htmlinfo;
+            htmlinfo = GetAllDigital();
+            for (int i = 0; i < htmlinfo.size(); ++i)
+            {
+                if (_fn == htmlinfo[i]->filename)
+                {
+                    if (htmlinfo[i]->image)
+                        _send = htmlinfo[i]->image;
+                }
+                if (_fn == htmlinfo[i]->filename_org)
+                {
+                    if (htmlinfo[i]->image_org)
+                        _send = htmlinfo[i]->image_org;        
+                }
+                delete htmlinfo[i];
+            }
+            htmlinfo.clear();
 
-    htmlinfo = GetAllAnalog();
-    for (int i = 0; i < htmlinfo.size(); ++i)
-    {
-        if (_fn == htmlinfo[i]->filename)
-        {
-            if (htmlinfo[i]->image)
-                _send = htmlinfo[i]->image;
-        }
-        if (_fn == htmlinfo[i]->filename_org)
-        {
-            if (htmlinfo[i]->image_org)
-                _send = htmlinfo[i]->image_org;        
+            if (!_send)
+            {
+                htmlinfo = GetAllAnalog();
+                for (int i = 0; i < htmlinfo.size(); ++i)
+                {
+                    if (_fn == htmlinfo[i]->filename)
+                    {
+                        if (htmlinfo[i]->image)
+                            _send = htmlinfo[i]->image;
+                    }
+                    if (_fn == htmlinfo[i]->filename_org)
+                    {
+                        if (htmlinfo[i]->image_org)
+                            _send = htmlinfo[i]->image_org;        
+                    }
+                    delete htmlinfo[i];
+                }
+                htmlinfo.clear();
+
+            }
         }
-        delete htmlinfo[i];
     }
-    htmlinfo.clear();
 
     if (_send)
     {

+ 5 - 3
code/components/jomjol_flowcontroll/ClassFlowControll.h

@@ -1,11 +1,11 @@
-#pragma once
+#ifndef __FLOWCONTROLL__
+#define __FLOWCONTROLL__
 
 #include <string>
 
 #include "ClassFlow.h"
 #include "ClassFlowMakeImage.h"
 #include "ClassFlowAlignment.h"
-//#include "ClassFlowDigit.h"
 #include "ClassFlowCNNGeneral.h"
 #include "ClassFlowPostProcessing.h"
 #include "ClassFlowMQTT.h"
@@ -60,7 +60,7 @@ public:
 
 	bool isAutoStart(long &_intervall);
 
-	std::string getActStatus();
+	std::string* getActStatus();
 
 	std::vector<HTMLInfo*> GetAllDigital();
 	std::vector<HTMLInfo*> GetAllAnalog();	
@@ -73,4 +73,6 @@ public:
 	string name(){return "ClassFlowControll";};
 };
 
+#endif
+
 

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

@@ -0,0 +1,52 @@
+#ifndef __CLASSFLOWIMAGE_CLASS__
+#define __CLASSFLOWIMAGE_CLASS__
+
+#include "ClassFlowImage.h"
+
+struct roi {
+    int posx, posy, deltax, deltay;
+    float result_float;
+    int result_klasse;
+    string name;
+    CImageBasis *image, *image_org;
+};
+
+struct general {
+    string name;
+    std::vector<roi*> ROI;
+};
+
+
+struct NumberPost {
+    float MaxRateValue;
+    bool useMaxRateValue;
+    bool ErrorMessage;
+    bool PreValueOkay;
+    bool AllowNegativeRates;
+    bool checkDigitIncreaseConsistency;
+    time_t lastvalue;
+    string timeStamp;
+    float FlowRateAct;          // m3 / min
+    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 ReturnPreValue;  // korrigierter Rückgabewert ohne Fehlermeldung
+    string ReturnValueNoError;
+    string ErrorMessageText;        // Fehlermeldung bei Consistency Check
+    int AnzahlAnalog;
+    int AnzahlDigital;
+    int DecimalShift;
+    int DecimalShiftInitial;
+    int Nachkomma;
+
+    bool isExtendedResolution;
+
+    general *digit_roi;
+    general *analog_roi;
+
+    string name;
+};
+
+#endif
+

+ 7 - 7
code/components/jomjol_flowcontroll/ClassFlowMQTT.cpp

@@ -154,16 +154,16 @@ bool ClassFlowMQTT::doFlow(string zwtime)
 
     if (flowpostprocessing)
     {
-        std::vector<NumberPost*> NUMBERS = flowpostprocessing->GetNumbers();
+        std::vector<NumberPost*>* NUMBERS = flowpostprocessing->GetNumbers();
 
-        for (int i = 0; i < NUMBERS.size(); ++i)
+        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;
+            result =  (*NUMBERS)[i]->ReturnValueNoError;
+            resulterror = (*NUMBERS)[i]->ErrorMessageText;
+            resultrate = std::to_string((*NUMBERS)[i]->FlowRateAct);
+            resulttimestamp = (*NUMBERS)[i]->timeStamp;
 
-            namenumber = NUMBERS[i]->name;
+            namenumber = (*NUMBERS)[i]->name;
             if (namenumber == "default")
                 namenumber = maintopic + "/";
             else

+ 97 - 24
code/components/jomjol_flowcontroll/ClassFlowPostProcessing.cpp

@@ -1,5 +1,4 @@
 #include "ClassFlowPostProcessing.h"
-
 #include "Helper.h"
 #include "ClassFlowMakeImage.h"
 #include "ClassLogFile.h"
@@ -124,7 +123,7 @@ bool ClassFlowPostProcessing::LoadPreValue(void)
 
                         if (NUMBERS[j]->digit_roi || NUMBERS[j]->analog_roi)
                         {
-                            NUMBERS[j]->ReturnValue = RundeOutput(NUMBERS[j]->Value, NUMBERS[j]->AnzahlAnalog - NUMBERS[j]->DecimalShift);
+                            NUMBERS[j]->ReturnValue = RundeOutput(NUMBERS[j]->Value, NUMBERS[j]->Nachkomma);
                             NUMBERS[j]->ReturnValueNoError = NUMBERS[j]->ReturnValue;
                         }
                     }
@@ -186,7 +185,7 @@ bool ClassFlowPostProcessing::LoadPreValue(void)
 
         if (NUMBERS[0]->digit_roi || NUMBERS[0]->analog_roi)
         {
-            NUMBERS[0]->ReturnValue = RundeOutput(NUMBERS[0]->Value, NUMBERS[0]->AnzahlAnalog - NUMBERS[0]->DecimalShift);
+            NUMBERS[0]->ReturnValue = RundeOutput(NUMBERS[0]->Value, NUMBERS[0]->Nachkomma);
             NUMBERS[0]->ReturnValueNoError = NUMBERS[0]->ReturnValue;
         }
 
@@ -241,7 +240,6 @@ ClassFlowPostProcessing::ClassFlowPostProcessing(std::vector<ClassFlow*>* lfc, C
     flowAnalog = _analog;
     flowDigit = _digit;
 
-
     for (int i = 0; i < ListFlowControll->size(); ++i)
     {
         if (((*ListFlowControll)[i])->name().compare("ClassFlowMakeImage") == 0)
@@ -251,6 +249,36 @@ ClassFlowPostProcessing::ClassFlowPostProcessing(std::vector<ClassFlow*>* lfc, C
     }
 }
 
+void ClassFlowPostProcessing::handleDecimalExtendedResolution(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)
+    {
+        bool _zwdc = false;
+
+        if (toUpper(_value) == "TRUE")
+            _zwdc = true;
+     
+        if (_digit == "default")                        // erstmal auf default setzen (falls sonst nichts gesetzt)
+        {
+            NUMBERS[j]->isExtendedResolution = _zwdc;
+        }
+
+        if (NUMBERS[j]->name == _digit)
+        {
+            NUMBERS[j]->isExtendedResolution = _zwdc;
+        }
+    }
+}
+
+
 void ClassFlowPostProcessing::handleDecimalSeparator(string _decsep, string _value)
 {
     string _digit, _decpos;
@@ -265,15 +293,15 @@ void ClassFlowPostProcessing::handleDecimalSeparator(string _decsep, string _val
     {
         int _zwdc = 0;
 
-        try
+//        try
         {
             _zwdc = stoi(_value);
         }
-        catch(const std::exception& e)
+/*        catch(const std::exception& e)
         {
             printf("ERROR - Decimalshift is not a number: %s\n", _value.c_str());
         }
-        
+*/        
         if (_digit == "default")                        // erstmal auf default setzen (falls sonst nichts gesetzt)
         {
             NUMBERS[j]->DecimalShift = _zwdc;
@@ -304,15 +332,15 @@ void ClassFlowPostProcessing::handleMaxRateValue(string _decsep, string _value)
     {
         float _zwdc = 1;
 
-        try
+//        try
         {
             _zwdc = stof(_value);
         }
-        catch(const std::exception& e)
+/*        catch(const std::exception& e)
         {
             printf("ERROR - MaxRateValue is not a number: %s\n", _value.c_str());
         }
-
+*/
 
         if (_digit == "default")                        // erstmal auf default setzen (falls sonst nichts gesetzt)
         {
@@ -352,6 +380,11 @@ bool ClassFlowPostProcessing::ReadParameter(FILE* pfile, string& aktparamgraph)
         zerlegt = this->ZerlegeZeile(aktparamgraph);
         std::string _param = GetParameterName(zerlegt[0]);
 
+        if ((toUpper(_param) == "EXTENDEDRESOLUTION") && (zerlegt.size() > 1))
+        {
+            handleDecimalExtendedResolution(zerlegt[0], zerlegt[1]);
+        }
+
         if ((toUpper(_param) == "DECIMALSHIFT") && (zerlegt.size() > 1))
         {
             handleDecimalSeparator(zerlegt[0], zerlegt[1]);
@@ -463,6 +496,7 @@ void ClassFlowPostProcessing::InitNUMBERS()
         _number->useMaxRateValue = false;
         _number->DecimalShift = 0;
         _number->DecimalShiftInitial = 0;
+        _number->isExtendedResolution = false;
 
 
         _number->FlowRateAct = 0;          // m3 / min
@@ -557,26 +591,23 @@ bool ClassFlowPostProcessing::doFlow(string zwtime)
         NUMBERS[j]->ReturnRawValue = "";
         NUMBERS[j]->ErrorMessageText = "";
 
-        if (flowAnalog) NUMBERS[j]->AnzahlAnalog = flowAnalog->AnzahlROIs(j);
-        if (flowDigit) NUMBERS[j]->AnzahlDigital = flowDigit->AnzahlROIs(j);
-        
-        if (flowDigit->isExtendedResolution()) 
-            NUMBERS[j]->DecimalShift = NUMBERS[j]->DecimalShiftInitial - 1;
-
-        NUMBERS[j]->Nachkomma = NUMBERS[j]->AnzahlAnalog - NUMBERS[j]->DecimalShift;
-
+        UpdateNachkommaDecimalShift();
 
         if (NUMBERS[j]->digit_roi)
-            NUMBERS[j]->ReturnRawValue = flowDigit->getReadout(j);
+        {
+            if (NUMBERS[j]->analog_roi)
+                NUMBERS[j]->ReturnRawValue = flowDigit->getReadout(j, false);
+            else
+                NUMBERS[j]->ReturnRawValue = flowDigit->getReadout(j, NUMBERS[j]->isExtendedResolution);        // Extended Resolution nur falls es keine analogen Ziffern gibt
+        }
         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); 
+            NUMBERS[j]->ReturnRawValue = NUMBERS[j]->ReturnRawValue + flowAnalog->getReadout(j, NUMBERS[j]->isExtendedResolution); 
 
         NUMBERS[j]->ReturnRawValue = ShiftDecimal(NUMBERS[j]->ReturnRawValue, NUMBERS[j]->DecimalShift);  
 
 
-///////////////// SPEZIALFALL für User Gustl ///////////////////////////////////////////////////////
         if (IgnoreLeadingNaN)               
         {
             while ((NUMBERS[j]->ReturnRawValue.length() > 1) && (NUMBERS[j]->ReturnRawValue[0] == 'N'))
@@ -584,7 +615,6 @@ bool ClassFlowPostProcessing::doFlow(string zwtime)
                 NUMBERS[j]->ReturnRawValue.erase(0, 1);
             }
         } 
-////////////////////////////////////////////////////////////////////////////////////////////////////
 
         rohwert = NUMBERS[j]->ReturnRawValue;
 
@@ -622,13 +652,13 @@ bool ClassFlowPostProcessing::doFlow(string zwtime)
                 NUMBERS[j]->Value = checkDigitConsistency(NUMBERS[j]->Value, NUMBERS[j]->DecimalShift, NUMBERS[j]->analog_roi != NULL, NUMBERS[j]->PreValue);
             }
 
-            zwvalue = RundeOutput(NUMBERS[j]->Value, NUMBERS[j]->AnzahlAnalog - NUMBERS[j]->DecimalShift);
+            zwvalue = RundeOutput(NUMBERS[j]->Value, NUMBERS[j]->Nachkomma);
 
             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: " + RundeOutput(NUMBERS[j]->PreValue, NUMBERS[j]->Nachkomma) + " "; 
                 NUMBERS[j]->Value = NUMBERS[j]->PreValue;
-                zwvalue = RundeOutput(NUMBERS[j]->Value, NUMBERS[j]->AnzahlAnalog - NUMBERS[j]->DecimalShift);
+                zwvalue = RundeOutput(NUMBERS[j]->Value, NUMBERS[j]->Nachkomma);
             }
 
             if (NUMBERS[j]->useMaxRateValue && (abs(NUMBERS[j]->Value - NUMBERS[j]->PreValue) > NUMBERS[j]->MaxRateValue))
@@ -663,6 +693,49 @@ bool ClassFlowPostProcessing::doFlow(string zwtime)
     return true;
 }
 
+
+void ClassFlowPostProcessing::UpdateNachkommaDecimalShift()
+{
+    for (int j = 0; j < NUMBERS.size(); ++j)
+    {
+        if (NUMBERS[j]->digit_roi && !NUMBERS[j]->analog_roi)            // es gibt nur digitale ziffern
+        {
+//            printf("Nurdigital\n");
+            NUMBERS[j]->DecimalShift = NUMBERS[j]->DecimalShiftInitial;
+
+            if (NUMBERS[j]->isExtendedResolution && flowDigit->isExtendedResolution())  // extended resolution ist an und soll auch bei dieser Ziffer verwendet werden
+                NUMBERS[j]->DecimalShift = NUMBERS[j]->DecimalShift-1;
+
+            NUMBERS[j]->Nachkomma = -NUMBERS[j]->DecimalShift;
+        }
+
+        if (!NUMBERS[j]->digit_roi && NUMBERS[j]->analog_roi)            // es gibt nur analoge ziffern
+        {
+//            printf("Nur analog\n");
+            NUMBERS[j]->DecimalShift = NUMBERS[j]->DecimalShiftInitial;
+            if (NUMBERS[j]->isExtendedResolution && flowAnalog->isExtendedResolution())  // extended resolution ist an und soll auch bei dieser Ziffer verwendet werden
+                NUMBERS[j]->DecimalShift = NUMBERS[j]->DecimalShift-1;
+
+            NUMBERS[j]->Nachkomma = -NUMBERS[j]->DecimalShift;
+        }
+
+        if (NUMBERS[j]->digit_roi && NUMBERS[j]->analog_roi)            // digital + analog
+        {
+//            printf("Nur digital + analog\n");
+
+            NUMBERS[j]->Nachkomma = NUMBERS[j]->analog_roi->ROI.size();
+            NUMBERS[j]->DecimalShift = NUMBERS[j]->DecimalShiftInitial;
+
+            if (NUMBERS[j]->isExtendedResolution && flowAnalog->isExtendedResolution())  // extended resolution ist an und soll auch bei dieser Ziffer verwendet werden
+                NUMBERS[j]->Nachkomma = NUMBERS[j]->Nachkomma+1;
+
+        }
+
+        printf("UpdateNachkommaDecShift NUMBER%i: Nachkomma %i, DecShift %i\n", j, NUMBERS[j]->Nachkomma,NUMBERS[j]->DecimalShift);
+    }
+}
+
+
 string ClassFlowPostProcessing::getReadout(int _number)
 {
     return NUMBERS[_number]->ReturnValue;

+ 12 - 37
code/components/jomjol_flowcontroll/ClassFlowPostProcessing.h

@@ -1,45 +1,13 @@
-#pragma once
+#ifndef __FLOWPOSTPROCESSING__
+#define __FLOWPOSTPROCESSING__
+
 #include "ClassFlow.h"
 #include "ClassFlowMakeImage.h"
 #include "ClassFlowCNNGeneral.h"
-#include "ClassFlowCNNGeneral.h"
-
+#include "ClassFlowDefineTypes.h"
 
 #include <string>
 
-
-struct NumberPost {
-    float MaxRateValue;
-    bool useMaxRateValue;
-    bool ErrorMessage;
-    bool PreValueOkay;
-    bool AllowNegativeRates;
-    bool checkDigitIncreaseConsistency;
-    time_t lastvalue;
-    string timeStamp;
-    float FlowRateAct;          // m3 / min
-    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 ReturnPreValue;  // korrigierter Rückgabewert ohne Fehlermeldung
-    string ReturnValueNoError;
-    string ErrorMessageText;        // Fehlermeldung bei Consistency Check
-    int AnzahlAnalog;
-    int AnzahlDigital;
-    int DecimalShift;
-    int DecimalShiftInitial;
-    int Nachkomma;
-
-    general *digit_roi;
-    general *analog_roi;
-
-    string name;
-};
-
-
-
-
 class ClassFlowPostProcessing :
     public ClassFlow
 {
@@ -70,6 +38,8 @@ protected:
     void InitNUMBERS();
     void handleDecimalSeparator(string _decsep, string _value);
     void handleMaxRateValue(string _decsep, string _value);
+    void handleDecimalExtendedResolution(string _decsep, string _value);    
+
 
 
 public:
@@ -86,8 +56,13 @@ public:
     void SavePreValue();
     string GetPreValue(std::string _number = "");
     void SetPreValue(float zw, string _numbers, bool _extern = false);
-    std::vector<NumberPost*> GetNumbers(){return NUMBERS;};
+
+    void UpdateNachkommaDecimalShift();
+
+    std::vector<NumberPost*>* GetNumbers(){return &NUMBERS;};
 
     string name(){return "ClassFlowPostProcessing";};
 };
 
+
+#endif

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

@@ -83,17 +83,20 @@ FILE* OpenFileAndWait(const char* nm, const char* _mode, int _waitsec)
 	printf("open config file %s in mode %s\n", nm, _mode);
 	FILE *pfile = fopen(nm, _mode);
 
+/*
 	if (pfile == NULL)
 	{
 		TickType_t xDelay;
 		xDelay = _waitsec * 1000 / portTICK_PERIOD_MS;
-		std::string zw = "File is locked: " + std::string(nm) + " - wait for " + std::to_string(_waitsec);
+		std::string zw = "File is locked: " + std::string(nm) + " - wait for " + std::to_string(_waitsec) + " seconds";
 	    printf(zw.c_str());
 		printf("\n");
 		LogFile.WriteToFile(zw);      
 		vTaskDelay( xDelay );
 		pfile = fopen(nm, _mode);
 	}
+*/
+
 	return pfile;
 }
 

+ 1 - 27
code/components/jomjol_tfliteclass/CTfLiteClass.cpp

@@ -69,32 +69,6 @@ int CTfLiteClass::GetOutClassification(int _von, int _bis)
   return (zw_class - _von);
 }
 
-/*
-int CTfLiteClass::GetOutClassification()
-{
-  TfLiteTensor* output2 = interpreter->output(0);
-
-  float zw_max = 0;
-  float zw;
-  int zw_class = -1;
-
-  if (output2 == NULL)
-    return -1;
-
-  int numeroutput = output2->dims->data[1];
-  for (int i = 0; i < numeroutput; ++i)
-  {
-    zw = output2->data.f[i];
-    if (zw > zw_max)
-    {
-        zw_max = zw;
-        zw_class = i;
-    }
-  }
-  return zw_class;
-}
-*/
-
 void CTfLiteClass::GetInputDimension(bool silent = false)
 {
   TfLiteTensor* input2 = this->interpreter->input(0);
@@ -283,7 +257,7 @@ CTfLiteClass::CTfLiteClass()
     this->interpreter = nullptr;
     this->input = nullptr;
     this->output = nullptr;  
-    this->kTensorArenaSize = 200 * 1024;   /// laut testfile: 108000 - bisher 600
+    this->kTensorArenaSize = 800 * 1024;   /// laut testfile: 108000 - bisher 600;; 2021-09-11: 200 * 1024
     this->tensor_arena = new uint8_t[kTensorArenaSize]; 
 }
 

+ 19 - 53
code/components/jomjol_tfliteclass/server_tflite.cpp

@@ -28,9 +28,6 @@ ClassFlowControll tfliteflow;
 TaskHandle_t xHandleblink_task_doFlow = NULL;
 TaskHandle_t xHandletask_autodoFlow = NULL;
 
-
-
-
 bool flowisrunning = false;
 
 long auto_intervall = 0;
@@ -283,48 +280,48 @@ esp_err_t handler_wasserzaehler(httpd_req_t *req)
         txt = txt + "Digital Counter: <p> ";
         httpd_resp_sendstr_chunk(req, txt.c_str()); 
         
-        std::vector<HTMLInfo*> htmlinfo;
-        htmlinfo = tfliteflow.GetAllDigital();  
-        printf("Size of htmlinfo: %i\n", htmlinfo.size());
-        for (int i = 0; i < htmlinfo.size(); ++i)
+        std::vector<HTMLInfo*> htmlinfodig;
+        htmlinfodig = tfliteflow.GetAllDigital();  
+        for (int i = 0; i < htmlinfodig.size(); ++i)
         {
             if (tfliteflow.GetTypeDigital() == Digital)
             {
-                if (htmlinfo[i]->val == 10)
+                if (htmlinfodig[i]->val == 10)
                     zw = "NaN";
                 else
-                    zw = to_string((int) htmlinfo[i]->val);
+                    zw = to_string((int) htmlinfodig[i]->val);
 
-                txt = "<img src=\"/img_tmp/" +  htmlinfo[i]->filename + "\"> " + zw;
+                txt = "<img src=\"/img_tmp/" +  htmlinfodig[i]->filename + "\"> " + zw;
             }
             else
             {
                 std::stringstream stream;
-                stream << std::fixed << std::setprecision(1) << htmlinfo[i]->val;
+                stream << std::fixed << std::setprecision(1) << htmlinfodig[i]->val;
                 zw = stream.str();
 
-                txt = "<img src=\"/img_tmp/" +  htmlinfo[i]->filename + "\"> " + zw;
+                txt = "<img src=\"/img_tmp/" +  htmlinfodig[i]->filename + "\"> " + zw;
             }
             httpd_resp_sendstr_chunk(req, txt.c_str()); 
-            delete htmlinfo[i];
+            delete htmlinfodig[i];
         }
-        htmlinfo.clear();
+        htmlinfodig.clear();
       
         txt = " <p> Analog Meter: <p> ";
         httpd_resp_sendstr_chunk(req, txt.c_str()); 
         
-        htmlinfo = tfliteflow.GetAllAnalog();
-        for (int i = 0; i < htmlinfo.size(); ++i)
+        std::vector<HTMLInfo*> htmlinfoana;
+        htmlinfoana = tfliteflow.GetAllAnalog();
+        for (int i = 0; i < htmlinfoana.size(); ++i)
         {
             std::stringstream stream;
-            stream << std::fixed << std::setprecision(1) << htmlinfo[i]->val;
+            stream << std::fixed << std::setprecision(1) << htmlinfoana[i]->val;
             zw = stream.str();
 
-            txt = "<img src=\"/img_tmp/" +  htmlinfo[i]->filename + "\"> " + zw;
+            txt = "<img src=\"/img_tmp/" +  htmlinfoana[i]->filename + "\"> " + zw;
             httpd_resp_sendstr_chunk(req, txt.c_str()); 
-            delete htmlinfo[i];
+            delete htmlinfoana[i];
         }
-        htmlinfo.clear();   
+        htmlinfoana.clear();   
 
     }   
 
@@ -506,35 +503,6 @@ esp_err_t handler_editflow(httpd_req_t *req)
         httpd_resp_sendstr_chunk(req, zw.c_str()); 
     }
 
-/*      
-    if (_task.compare("test_analog") == 0)
-    {
-        std::string _host = "";
-        if (httpd_query_key_value(_query, "host", _valuechar, 30) == ESP_OK) {
-            _host = std::string(_valuechar);
-        }
-//        printf("Parameter host: "); printf(_host.c_str()); printf("\n"); 
-//        string zwzw = "Do " + _task + " start\n"; printf(zwzw.c_str());
-        std::string zw = tfliteflow.doSingleStep("[Analog]", _host);
-        httpd_resp_sendstr_chunk(req, zw.c_str()); 
-    }
-*/  
-/*    
-    if (_task.compare("test_digits") == 0)
-    {
-        std::string _host = "";
-        if (httpd_query_key_value(_query, "host", _valuechar, 30) == ESP_OK) {
-            _host = std::string(_valuechar);
-        }
-//        printf("Parameter host: "); printf(_host.c_str()); printf("\n"); 
-
-//        string zwzw = "Do " + _task + " start\n"; printf(zwzw.c_str());
-        std::string zw = tfliteflow.doSingleStep("[Digits]", _host);
-        httpd_resp_sendstr_chunk(req, zw.c_str()); 
-    } 
-*/
-
-
     /* Respond with an empty chunk to signal HTTP response completion */
     httpd_resp_sendstr_chunk(req, NULL);   
 
@@ -553,15 +521,13 @@ esp_err_t handler_statusflow(httpd_req_t *req)
 #endif
 
     const char* resp_str;
-    string zw;
 
 #ifdef DEBUG_DETAIL_ON       
     printf("handler_prevalue:\n"); printf(req->uri); printf("\n");
 #endif
 
-    zw = tfliteflow.getActStatus();
-    
-    resp_str = zw.c_str();
+    string* zw = tfliteflow.getActStatus();
+    resp_str = zw->c_str();
 
     httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
     httpd_resp_send(req, resp_str, strlen(resp_str));   

+ 4 - 4
code/components/jomjol_wlan/connect_wlan.cpp

@@ -50,14 +50,14 @@ std::string std_hostname = "watermeter";
 std::string ipadress = "";
 std::string ssid = "";
 
-std::string getIPAddress()
+std::string* getIPAddress()
 {
-    return ipadress;
+    return &ipadress;
 }
 
-std::string getSSID()
+std::string* getSSID()
 {
-    return ssid;
+    return &ssid;
 }
 
 

+ 2 - 2
code/components/jomjol_wlan/connect_wlan.h

@@ -7,8 +7,8 @@ void wifi_init_sta(const char *_ssid, const char *_password, const char *_hostna
 void wifi_init_sta(const char *_ssid, const char *_password, const char *_hostname);
 void wifi_init_sta(const char *_ssid, const char *_password);
 
-std::string getIPAddress();
-std::string getSSID();
+std::string* getIPAddress();
+std::string* getSSID();
 
 extern std::string hostname;
 extern std::string std_hostname;

BIN
code/components/tfmicro.zip


BIN
code/components/tfmicro_new_version.zip


+ 132 - 0
code/main/Color.cpp

@@ -0,0 +1,132 @@
+#include "Color.h"
+#include <algorithm>
+#include <cmath>
+#include <cassert>
+
+namespace {
+
+// Int -> fixed point
+int up( int x ) { return x * 255; }
+
+} // namespace
+
+int iRgbSqrt( int num ) {
+    // https://en.wikipedia.org/wiki/Methods_of_computing_square_roots#Binary_numeral_system_.28base_2.29
+    assert( "sqrt input should be non-negative" && num >= 0 );
+    assert( "sqrt input should no exceed 16 bits" && num <= 0xFFFF );
+    int res = 0;
+    int bit = 1 << 16;
+    while ( bit > num )
+        bit >>= 2;
+    while ( bit != 0 ) {
+        if ( num >= res + bit ) {
+            num -= res + bit;
+            res = ( res >> 1 ) + bit;
+        } else
+            res >>= 1;
+        bit >>= 2;
+    }
+    return res;
+}
+
+Rgb::Rgb( Hsv y ) {
+    // https://stackoverflow.com/questions/24152553/hsv-to-rgb-and-back-without-floating-point-math-in-python
+    // greyscale
+    if( y.s == 0 ) {
+        r = g = b = y.v;
+        return;
+    }
+
+    const int region = y.h / 43;
+    const int remainder = ( y.h - ( region * 43 ) ) * 6;
+
+    const int p = ( y.v * ( 255 - y.s ) ) >> 8;
+    const int q = ( y.v * ( 255 - ( ( y.s * remainder ) >> 8 ) ) ) >> 8;
+    const int t = ( y.v * ( 255 - ( ( y.s * (255 -remainder ) ) >> 8 ) ) ) >> 8;
+
+    switch( region ) {
+        case 0: r = y.v; g = t; b = p; break;
+        case 1: r = q; g = y.v; b = p; break;
+        case 2: r = p; g = y.v; b = t; break;
+        case 3: r = p; g = q; b = y.v; break;
+        case 4: r = t; g = p; b = y.v; break;
+        case 5: r = y.v; g = p; b = q; break;
+        default: __builtin_trap();
+    }
+
+    a = y.a;
+}
+
+Rgb& Rgb::operator=( Hsv hsv ) {
+    Rgb r{ hsv };
+    swap( r );
+    return *this;
+}
+
+Rgb Rgb::operator+( Rgb in ) const {
+    auto copy = *this;
+    copy += in;
+    return copy;
+}
+
+Rgb& Rgb::operator+=( Rgb in ) {
+    unsigned int red = r + in.r;
+    r = ( red < 255 ) ? red : 255;
+    unsigned int green = g + in.g;
+    g = ( green < 255 ) ? green : 255;
+    unsigned int blue = b + in.b;
+    b = ( blue < 255 ) ? blue : 255;
+    return *this;
+}
+
+Rgb& Rgb::blend( Rgb in ) {
+    unsigned int inAlpha = in.a * ( 255 - a );
+    unsigned int alpha = a + inAlpha;
+    r = iRgbSqrt( ( ( r * r * a ) + ( in.r * in.r * inAlpha ) ) / alpha );
+    g = iRgbSqrt( ( ( g * g * a ) + ( in.g * in.g * inAlpha ) ) / alpha );
+    b = iRgbSqrt( ( ( b * b * a ) + ( in.b * in.b * inAlpha ) ) / alpha );
+    a = alpha;
+    return *this;
+}
+
+uint8_t IRAM_ATTR Rgb::getGrb( int idx ) {
+    switch ( idx ) {
+        case 0: return g;
+        case 1: return r;
+        case 2: return b;
+    }
+    __builtin_unreachable();
+}
+
+Hsv::Hsv( Rgb r ) {
+    int min = std::min( r.r, std::min( r.g, r.b ) );
+    int max = std::max( r.r, std::max( r.g, r.b ) );
+    int chroma = max - min;
+
+    v = max;
+    if ( chroma == 0 ) {
+        h = s = 0;
+        return;
+    }
+
+    s = up( chroma ) / max;
+    int hh;
+    if ( max == r.r )
+        hh = ( up( int( r.g ) - int( r.b ) ) ) / chroma / 6;
+    else if ( max == r.g )
+        hh = 255 / 3 + ( up( int( r.b ) - int( r.r ) ) ) / chroma / 6;
+    else
+        hh = 2 * 255 / 3 + ( up( int( r.r ) - int( r.g ) ) ) / chroma / 6;
+
+    if ( hh < 0 )
+        hh += 255;
+    h = hh;
+
+    a = r.a;
+}
+
+Hsv& Hsv::operator=( Rgb rgb ) {
+    Hsv h{ rgb };
+    swap( h );
+    return *this;
+}

+ 69 - 0
code/main/Color.h

@@ -0,0 +1,69 @@
+#pragma once
+
+#include <cstdint>
+#include "esp_attr.h"
+union Hsv;
+
+union Rgb {
+    struct __attribute__ ((packed)) {
+        uint8_t r, g, b, a;
+    };
+    uint32_t value;
+
+    Rgb( uint8_t r = 0, uint8_t g = 0, uint8_t b = 0, uint8_t a = 255 ) : r( r ), g( g ), b( b ), a( a ) {}
+    Rgb( Hsv c );
+    Rgb& operator=( Rgb rgb ) { swap( rgb ); return *this; }
+    Rgb& operator=( Hsv hsv );
+    Rgb operator+( Rgb in ) const;
+    Rgb& operator+=( Rgb in );
+    bool operator==( Rgb in ) const { return in.value == value; }
+    Rgb& blend( Rgb in );
+    void swap( Rgb& o ) {  value = o.value; }
+    void linearize() {
+        r = channelGamma(r);
+        g = channelGamma(g);
+        b = channelGamma(b);
+    }
+
+    uint8_t IRAM_ATTR getGrb( int idx );
+
+    void stretchChannels( uint8_t maxR, uint8_t maxG, uint8_t maxB ) {
+        r = stretch( r, maxR );
+        g = stretch( g, maxG );
+        b = stretch( b, maxB );
+    }
+
+    void stretchChannelsEvenly( uint8_t max ) {
+        stretchChannels( max, max, max );
+    }
+
+private:
+    uint8_t stretch( int value, uint8_t max ) {
+        return ( value * max ) >> 8;
+    }
+
+    uint8_t channelGamma( int channel ) {
+        /* The optimal gamma correction is x^2.8. However, this is expensive to
+         * compute. Therefore, we use x^3 for gamma correction. Also, we add a
+         * bias as the WS2812 LEDs do not turn on for values less than 4. */
+        if (channel == 0)
+            return channel;
+        channel = channel * channel * channel * 251;
+        channel >>= 24;
+        return static_cast< uint8_t >( 4 + channel );
+    }
+};
+
+union Hsv {
+    struct __attribute__ ((packed)) {
+        uint8_t h, s, v, a;
+    };
+    uint32_t value;
+
+    Hsv( uint8_t h, uint8_t s = 0, uint8_t v = 0, uint8_t a = 255 ) : h( h ), s( s ), v( v ), a( a ) {}
+    Hsv( Rgb r );
+    Hsv& operator=( Hsv h ) { swap( h ); return *this; }
+    Hsv& operator=( Rgb rgb );
+    bool operator==( Hsv in ) const { return in.value == value; }
+    void swap( Hsv& o ) { value = o.value; }
+};

+ 63 - 0
code/main/SmartLeds.cpp

@@ -0,0 +1,63 @@
+#include "SmartLeds.h"
+
+IsrCore SmartLed::_interruptCore = CoreCurrent;
+intr_handle_t SmartLed::_interruptHandle = NULL;
+
+SmartLed*& IRAM_ATTR SmartLed::ledForChannel( int channel ) {
+    static SmartLed* table[8] = { nullptr };
+    assert( channel < 8 );
+    return table[ channel ];
+}
+
+void IRAM_ATTR SmartLed::interruptHandler(void*) {
+    for (int channel = 0; channel != 8; channel++) {
+        auto self = ledForChannel( channel );
+
+        if ( RMT.int_st.val & (1 << (24 + channel ) ) ) { // tx_thr_event
+            if ( self )
+                self->copyRmtHalfBlock();
+            RMT.int_clr.val |= 1 << ( 24 + channel );
+        } else if ( RMT.int_st.val & ( 1 << (3 * channel ) ) ) { // tx_end
+            if ( self )
+                xSemaphoreGiveFromISR( self->_finishedFlag, nullptr );
+            RMT.int_clr.val |= 1 << ( 3 * channel );
+        }
+    }
+}
+
+void IRAM_ATTR SmartLed::copyRmtHalfBlock() {
+    int offset = detail::MAX_PULSES * _halfIdx;
+    _halfIdx = !_halfIdx;
+    int len = 3 - _componentPosition + 3 * ( _count - 1 );
+    len = std::min( len, detail::MAX_PULSES / 8 );
+
+    if ( !len ) {
+        for ( int i = 0; i < detail::MAX_PULSES; i++) {
+            RMTMEM.chan[ _channel].data32[i + offset ].val = 0;
+        }
+    }
+
+    int i;
+    for ( i = 0; i != len && _pixelPosition != _count; i++ ) {
+        uint8_t val = _buffer[ _pixelPosition ].getGrb( _componentPosition );
+        for ( int j = 0; j != 8; j++, val <<= 1 ) {
+            int bit = val >> 7;
+            int idx = i * 8 + offset + j;
+            RMTMEM.chan[ _channel ].data32[ idx ].val = _bitToRmt[ bit & 0x01 ].value;
+        }
+        if ( _pixelPosition == _count - 1 && _componentPosition == 2 ) {
+            RMTMEM.chan[ _channel ].data32[ i * 8 + offset + 7 ].duration1 =
+                _timing.TRS / ( detail::RMT_DURATION_NS * detail::DIVIDER );
+        }
+
+        _componentPosition++;
+        if ( _componentPosition == 3 ) {
+            _componentPosition = 0;
+            _pixelPosition++;
+        }
+    }
+
+    for ( i *= 8; i != detail::MAX_PULSES; i++ ) {
+        RMTMEM.chan[ _channel ].data32[ i + offset ].val = 0;
+    }
+}

+ 530 - 0
code/main/SmartLeds.h

@@ -0,0 +1,530 @@
+#pragma once
+
+/*
+ * A C++ driver for the WS2812 LEDs using the RMT peripheral on the ESP32.
+ *
+ * Jan "yaqwsx" Mrázek <email@honzamrazek.cz>
+ *
+ * Based on the work by Martin F. Falatic - https://github.com/FozzTexx/ws2812-demo
+ */
+
+/*
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <memory>
+#include <cassert>
+#include <cstring>
+
+#if defined ( ARDUINO )
+    extern "C" { // ...someone forgot to put in the includes...
+        #include "esp32-hal.h"
+        #include "esp_intr_alloc.h"
+        #include "esp_ipc.h"
+        #include "driver/gpio.h"
+        #include "driver/periph_ctrl.h"
+        #include "freertos/semphr.h"
+        #include "soc/rmt_struct.h"
+        #include <driver/spi_master.h>
+        #include "esp_idf_version.h"
+#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL( 4, 0, 0 )
+        #include "soc/dport_reg.h"
+#endif
+    }
+#elif defined ( ESP_PLATFORM )
+    extern "C" { // ...someone forgot to put in the includes...
+        #include <esp_intr_alloc.h>
+        #include <esp_ipc.h>
+        #include <driver/gpio.h>
+        #include <freertos/FreeRTOS.h>
+        #include <freertos/semphr.h>
+        #include <soc/dport_reg.h>
+        #include <soc/gpio_sig_map.h>
+        #include <soc/rmt_struct.h>
+        #include <driver/spi_master.h>
+    }
+    #include <stdio.h>
+#endif
+
+#include "Color.h"
+
+namespace detail {
+
+struct TimingParams {
+    uint32_t T0H;
+    uint32_t T1H;
+    uint32_t T0L;
+    uint32_t T1L;
+    uint32_t TRS;
+};
+
+union RmtPulsePair {
+    struct {
+        int duration0:15;
+        int level0:1;
+        int duration1:15;
+        int level1:1;
+    };
+    uint32_t value;
+};
+
+static const int DIVIDER = 4; // 8 still seems to work, but timings become marginal
+static const int MAX_PULSES = 32; // A channel has a 64 "pulse" buffer - we use half per pass
+static const double RMT_DURATION_NS = 12.5; // minimum time of a single RMT duration based on clock ns
+
+} // namespace detail
+
+using LedType = detail::TimingParams;
+
+static const LedType LED_WS2812  = { 350, 700, 800, 600, 50000 };
+static const LedType LED_WS2812B = { 400, 850, 850, 400, 50100 };
+static const LedType LED_SK6812  = { 300, 600, 900, 600, 80000 };
+static const LedType LED_WS2813  = { 350, 800, 350, 350, 300000 };
+
+enum BufferType { SingleBuffer = 0, DoubleBuffer };
+
+enum IsrCore { CoreFirst = 0, CoreSecond = 1, CoreCurrent = 2};
+
+class SmartLed {
+public:
+    // The RMT interrupt must not run on the same core as WiFi interrupts, otherwise SmartLeds
+    // can't fill the RMT buffer fast enough, resulting in rendering artifacts.
+    // Usually, that means you have to set isrCore == CoreSecond.
+    //
+    // If you use anything other than CoreCurrent, the FreeRTOS scheduler MUST be already running,
+    // so you can't use it if you define SmartLed as global variable.
+    SmartLed( const LedType& type, int count, int pin, int channel = 0, BufferType doubleBuffer = SingleBuffer, IsrCore isrCore = CoreCurrent)
+        : _timing( type ),
+          _channel( channel ),
+          _count( count ),
+          _firstBuffer( new Rgb[ count ] ),
+          _secondBuffer( doubleBuffer ? new Rgb[ count ] : nullptr ),
+          _finishedFlag( xSemaphoreCreateBinary() )
+    {
+        assert( channel >= 0 && channel < 8 );
+        assert( ledForChannel( channel ) == nullptr );
+
+        xSemaphoreGive( _finishedFlag );
+
+        DPORT_SET_PERI_REG_MASK( DPORT_PERIP_CLK_EN_REG, DPORT_RMT_CLK_EN );
+        DPORT_CLEAR_PERI_REG_MASK( DPORT_PERIP_RST_EN_REG, DPORT_RMT_RST );
+
+        PIN_FUNC_SELECT( GPIO_PIN_MUX_REG[ pin ], 2 );
+        gpio_set_direction( static_cast< gpio_num_t >( pin ), GPIO_MODE_OUTPUT );
+        gpio_matrix_out( static_cast< gpio_num_t >( pin ), RMT_SIG_OUT0_IDX + _channel, 0, 0 );
+        initChannel( _channel );
+
+        RMT.tx_lim_ch[ _channel ].limit = detail::MAX_PULSES;
+        RMT.int_ena.val |= 1 << ( 24 + _channel );
+        RMT.int_ena.val |= 1 << ( 3 * _channel );
+
+        _bitToRmt[ 0 ].level0 = 1;
+        _bitToRmt[ 0 ].level1 = 0;
+        _bitToRmt[ 0 ].duration0 = _timing.T0H / ( detail::RMT_DURATION_NS * detail::DIVIDER );
+        _bitToRmt[ 0 ].duration1 = _timing.T0L / ( detail::RMT_DURATION_NS * detail::DIVIDER );
+
+        _bitToRmt[ 1 ].level0 = 1;
+        _bitToRmt[ 1 ].level1 = 0;
+        _bitToRmt[ 1 ].duration0 = _timing.T1H / ( detail::RMT_DURATION_NS * detail::DIVIDER );
+        _bitToRmt[ 1 ].duration1 = _timing.T1L / ( detail::RMT_DURATION_NS * detail::DIVIDER );
+
+        if ( !anyAlive() ) {
+            _interruptCore = isrCore;
+            if(isrCore != CoreCurrent) {
+                ESP_ERROR_CHECK(esp_ipc_call_blocking(isrCore, registerInterrupt, NULL));
+            } else {
+                registerInterrupt(NULL);
+            }
+        }
+
+        ledForChannel( channel ) = this;
+    }
+
+    ~SmartLed() {
+        ledForChannel( _channel ) = nullptr;
+        if ( !anyAlive() ) {
+            if(_interruptCore != CoreCurrent) {
+                ESP_ERROR_CHECK(esp_ipc_call_blocking(_interruptCore, unregisterInterrupt, NULL));
+            } else {
+                unregisterInterrupt(NULL);
+            }
+        }
+        vSemaphoreDelete( _finishedFlag );
+    }
+
+    Rgb& operator[]( int idx ) {
+        return _firstBuffer[ idx ];
+    }
+
+    const Rgb& operator[]( int idx ) const {
+        return _firstBuffer[ idx ];
+    }
+
+    void show() {
+        _buffer = _firstBuffer.get();
+        startTransmission();
+        swapBuffers();
+    }
+
+    bool wait( TickType_t timeout = portMAX_DELAY ) {
+        if( xSemaphoreTake( _finishedFlag, timeout ) == pdTRUE ) {
+            xSemaphoreGive( _finishedFlag );
+            return true;
+        }
+        return false;
+    }
+
+    int size() const {
+        return _count;
+    }
+
+    Rgb *begin() { return _firstBuffer.get(); }
+    const Rgb *begin() const { return _firstBuffer.get(); }
+    const Rgb *cbegin() const { return _firstBuffer.get(); }
+
+    Rgb *end() { return _firstBuffer.get() + _count; }
+    const Rgb *end() const { return _firstBuffer.get() + _count; }
+    const Rgb *cend() const { return _firstBuffer.get() + _count; }
+
+private:
+    static intr_handle_t _interruptHandle;
+    static IsrCore _interruptCore;
+
+    static void initChannel( int channel ) {
+        RMT.apb_conf.fifo_mask = 1;  //enable memory access, instead of FIFO mode.
+        RMT.apb_conf.mem_tx_wrap_en = 1; //wrap around when hitting end of buffer
+        RMT.conf_ch[ channel ].conf0.div_cnt = detail::DIVIDER;
+        RMT.conf_ch[ channel ].conf0.mem_size = 1;
+        RMT.conf_ch[ channel ].conf0.carrier_en = 0;
+        RMT.conf_ch[ channel ].conf0.carrier_out_lv = 1;
+        RMT.conf_ch[ channel ].conf0.mem_pd = 0;
+
+        RMT.conf_ch[ channel ].conf1.rx_en = 0;
+        RMT.conf_ch[ channel ].conf1.mem_owner = 0;
+        RMT.conf_ch[ channel ].conf1.tx_conti_mode = 0;    //loop back mode.
+        RMT.conf_ch[ channel ].conf1.ref_always_on = 1;    // use apb clock: 80M
+        RMT.conf_ch[ channel ].conf1.idle_out_en = 1;
+        RMT.conf_ch[ channel ].conf1.idle_out_lv = 0;
+    }
+
+    static void registerInterrupt(void *) {
+        ESP_ERROR_CHECK(esp_intr_alloc( ETS_RMT_INTR_SOURCE, 0, interruptHandler, nullptr, &_interruptHandle));
+    }
+
+    static void unregisterInterrupt(void*) {
+        esp_intr_free( _interruptHandle );
+    }
+
+    static SmartLed*& IRAM_ATTR ledForChannel( int channel );
+    static void IRAM_ATTR interruptHandler( void* );
+
+    void IRAM_ATTR copyRmtHalfBlock();
+
+    void swapBuffers() {
+        if ( _secondBuffer )
+            _firstBuffer.swap( _secondBuffer );
+    }
+
+    void startTransmission() {
+        // Invalid use of the library
+        if( xSemaphoreTake( _finishedFlag, 0 ) != pdTRUE )
+            abort();
+
+        _pixelPosition = _componentPosition = _halfIdx = 0;
+        copyRmtHalfBlock();
+        if ( _pixelPosition < _count )
+            copyRmtHalfBlock();
+
+        RMT.conf_ch[ _channel ].conf1.mem_rd_rst = 1;
+        RMT.conf_ch[ _channel ].conf1.tx_start = 1;
+    }
+
+    static bool anyAlive() {
+        for ( int i = 0; i != 8; i++ )
+            if ( ledForChannel( i ) != nullptr ) return true;
+        return false;
+    }
+
+    const LedType& _timing;
+    int _channel;
+    detail::RmtPulsePair _bitToRmt[ 2 ];
+    int _count;
+    std::unique_ptr< Rgb[] > _firstBuffer;
+    std::unique_ptr< Rgb[] > _secondBuffer;
+    Rgb *_buffer;
+
+    xSemaphoreHandle _finishedFlag;
+
+    int _pixelPosition;
+    int _componentPosition;
+    int _halfIdx;
+};
+
+class Apa102 {
+public:
+    struct ApaRgb {
+        ApaRgb( uint8_t r = 0, uint8_t g = 0, uint32_t b = 0, uint32_t v = 0xFF )
+            : v( 0xE0 | v ), b( b ), g( g ), r( r )
+        {}
+
+        ApaRgb& operator=( const Rgb& o ) {
+            r = o.r;
+            g = o.g;
+            b = o.b;
+            return *this;
+        }
+
+        ApaRgb& operator=( const Hsv& o ) {
+            *this = Rgb{ o };
+            return *this;
+        }
+
+        uint8_t v, b, g, r;
+    };
+
+    static const int FINAL_FRAME_SIZE = 4;
+    static const int TRANS_COUNT = 2 + 8;
+
+    Apa102( int count, int clkpin, int datapin, BufferType doubleBuffer = SingleBuffer )
+        : _count( count ),
+          _firstBuffer( new ApaRgb[ count ] ),
+          _secondBuffer( doubleBuffer ? new ApaRgb[ count ] : nullptr ),
+          _initFrame( 0 )
+    {
+        spi_bus_config_t buscfg;
+        memset( &buscfg, 0, sizeof( buscfg ) );
+        buscfg.mosi_io_num = datapin;
+        buscfg.miso_io_num = -1;
+        buscfg.sclk_io_num = clkpin;
+        buscfg.quadwp_io_num = -1;
+        buscfg.quadhd_io_num = -1;
+        buscfg.max_transfer_sz = 65535;
+
+        spi_device_interface_config_t devcfg;
+        memset( &devcfg, 0, sizeof( devcfg ) );
+        devcfg.clock_speed_hz = 1000000;
+        devcfg.mode = 0;
+        devcfg.spics_io_num = -1;
+        devcfg.queue_size = TRANS_COUNT;
+        devcfg.pre_cb = nullptr;
+
+        auto ret = spi_bus_initialize( HSPI_HOST, &buscfg, 1 );
+        assert( ret == ESP_OK );
+
+        ret = spi_bus_add_device( HSPI_HOST, &devcfg, &_spi );
+        assert( ret == ESP_OK );
+
+        std::fill_n( _finalFrame, FINAL_FRAME_SIZE, 0xFFFFFFFF );
+    }
+
+    ~Apa102() {
+        // ToDo
+    }
+
+    ApaRgb& operator[]( int idx ) {
+        return _firstBuffer[ idx ];
+    }
+
+    const ApaRgb& operator[]( int idx ) const {
+        return _firstBuffer[ idx ];
+    }
+
+    void show() {
+        _buffer = _firstBuffer.get();
+        startTransmission();
+        swapBuffers();
+    }
+
+    void wait() {
+        for ( int i = 0; i != _transCount; i++ ) {
+            spi_transaction_t *t;
+            spi_device_get_trans_result( _spi, &t, portMAX_DELAY );
+        }
+    }
+private:
+    void swapBuffers() {
+        if ( _secondBuffer )
+            _firstBuffer.swap( _secondBuffer );
+    }
+
+    void startTransmission() {
+        for ( int i = 0; i != TRANS_COUNT; i++ ) {
+            _transactions[ i ].cmd = 0;
+            _transactions[ i ].addr = 0;
+            _transactions[ i ].flags = 0;
+            _transactions[ i ].rxlength = 0;
+            _transactions[ i ].rx_buffer = nullptr;
+        }
+        // Init frame
+        _transactions[ 0 ].length = 32;
+        _transactions[ 0 ].tx_buffer = &_initFrame;
+        spi_device_queue_trans( _spi, _transactions + 0, portMAX_DELAY );
+        // Data
+        _transactions[ 1 ].length = 32 * _count;
+        _transactions[ 1 ].tx_buffer = _buffer;
+        spi_device_queue_trans( _spi, _transactions + 1, portMAX_DELAY );
+        _transCount = 2;
+        // End frame
+        for ( int i = 0; i != 1 + _count / 32 / FINAL_FRAME_SIZE; i++ ) {
+            _transactions[ 2 + i ].length = 32 * FINAL_FRAME_SIZE;
+            _transactions[ 2 + i ].tx_buffer = _finalFrame;
+            spi_device_queue_trans( _spi, _transactions + 2 + i, portMAX_DELAY );
+            _transCount++;
+        }
+    }
+
+    spi_device_handle_t _spi;
+    int _count;
+    std::unique_ptr< ApaRgb[] > _firstBuffer, _secondBuffer;
+    ApaRgb *_buffer;
+
+    spi_transaction_t _transactions[ TRANS_COUNT ];
+    int _transCount;
+
+    uint32_t _initFrame;
+    uint32_t _finalFrame[ FINAL_FRAME_SIZE ];
+};
+
+class LDP8806 {
+public:
+    struct LDP8806_GRB {
+
+        LDP8806_GRB( uint8_t g_7bit = 0, uint8_t r_7bit = 0, uint32_t b_7bit = 0 )
+            : g( g_7bit ), r( r_7bit ), b( b_7bit )
+        {
+        }
+
+        LDP8806_GRB& operator=( const Rgb& o ) {
+            //Convert 8->7bit colour
+            r = ( o.r * 127 / 256 ) | 0x80;
+            g = ( o.g * 127 / 256 ) | 0x80;
+            b = ( o.b * 127 / 256 ) | 0x80;
+            return *this;
+        }
+
+        LDP8806_GRB& operator=( const Hsv& o ) {
+            *this = Rgb{ o };
+            return *this;
+        }
+
+        uint8_t g, r, b;
+    };
+
+    static const int LED_FRAME_SIZE_BYTES = sizeof( LDP8806_GRB );
+    static const int LATCH_FRAME_SIZE_BYTES = 3;
+    static const int TRANS_COUNT_MAX = 20;//Arbitrary, supports up to 600 LED
+
+    LDP8806( int count, int clkpin, int datapin, BufferType doubleBuffer = SingleBuffer, uint32_t clock_speed_hz = 2000000 )
+        : _count( count ),
+          _firstBuffer( new LDP8806_GRB[ count ] ),
+          _secondBuffer( doubleBuffer ? new LDP8806_GRB[ count ] : nullptr ),
+          // one 'latch'/start-of-data mark frame for every 32 leds
+          _latchFrames( ( count + 31 ) / 32 )
+    {
+        spi_bus_config_t buscfg;
+        memset( &buscfg, 0, sizeof( buscfg ) );
+        buscfg.mosi_io_num = datapin;
+        buscfg.miso_io_num = -1;
+        buscfg.sclk_io_num = clkpin;
+        buscfg.quadwp_io_num = -1;
+        buscfg.quadhd_io_num = -1;
+        buscfg.max_transfer_sz = 65535;
+
+        spi_device_interface_config_t devcfg;
+        memset( &devcfg, 0, sizeof( devcfg ) );
+        devcfg.clock_speed_hz = clock_speed_hz;
+        devcfg.mode = 0;
+        devcfg.spics_io_num = -1;
+        devcfg.queue_size = TRANS_COUNT_MAX;
+        devcfg.pre_cb = nullptr;
+
+        auto ret = spi_bus_initialize( HSPI_HOST, &buscfg, 1 );
+        assert( ret == ESP_OK );
+
+        ret = spi_bus_add_device( HSPI_HOST, &devcfg, &_spi );
+        assert( ret == ESP_OK );
+
+        std::fill_n( _latchBuffer, LATCH_FRAME_SIZE_BYTES, 0x0 );
+    }
+
+    ~LDP8806() {
+        // noop
+    }
+
+    LDP8806_GRB& operator[]( int idx ) {
+        return _firstBuffer[ idx ];
+    }
+
+    const LDP8806_GRB& operator[]( int idx ) const {
+        return _firstBuffer[ idx ];
+    }
+
+    void show() {
+        _buffer = _firstBuffer.get();
+        startTransmission();
+        swapBuffers();
+    }
+
+    void wait() {
+        while ( _transCount-- ) {
+            spi_transaction_t *t;
+            spi_device_get_trans_result( _spi, &t, portMAX_DELAY );
+        }
+    }
+private:
+    void swapBuffers() {
+        if ( _secondBuffer )
+            _firstBuffer.swap( _secondBuffer );
+    }
+
+    void startTransmission() {
+        _transCount = 0;
+        for ( int i = 0; i != TRANS_COUNT_MAX; i++ ) {
+            _transactions[ i ].cmd = 0;
+            _transactions[ i ].addr = 0;
+            _transactions[ i ].flags = 0;
+            _transactions[ i ].rxlength = 0;
+            _transactions[ i ].rx_buffer = nullptr;
+        }
+        // LED Data
+        _transactions[ 0 ].length = ( LED_FRAME_SIZE_BYTES * 8 ) * _count;
+        _transactions[ 0 ].tx_buffer = _buffer;
+        spi_device_queue_trans( _spi, _transactions + _transCount, portMAX_DELAY );
+        _transCount++;
+
+        // 'latch'/start-of-data marker frames
+        for ( int i = 0; i < _latchFrames; i++ ) {
+            _transactions[ _transCount ].length = ( LATCH_FRAME_SIZE_BYTES * 8 );
+            _transactions[ _transCount ].tx_buffer = _latchBuffer;
+            spi_device_queue_trans( _spi, _transactions + _transCount, portMAX_DELAY );
+            _transCount++;
+        }
+    }
+
+    spi_device_handle_t _spi;
+    int _count;
+    std::unique_ptr< LDP8806_GRB[] > _firstBuffer, _secondBuffer;
+    LDP8806_GRB *_buffer;
+
+    spi_transaction_t _transactions[ TRANS_COUNT_MAX ];
+    int _transCount;
+
+    int _latchFrames;
+    uint8_t _latchBuffer[ LATCH_FRAME_SIZE_BYTES ];
+};

+ 11 - 1
code/main/main.cpp

@@ -28,6 +28,9 @@
 #include "server_main.h"
 #include "server_camera.h"
 
+// #include "jomjol_WS2812Slow.h"
+#include "SmartLeds.h"
+
 
 #define __SD_USE_ONE_LINE_MODE__
 
@@ -135,8 +138,12 @@ void task_NoSDBlink(void *pvParameter)
     vTaskDelete(NULL); //Delete this task if it exits from the loop above
 }
 
+
 extern "C" void app_main(void)
 {
+    TickType_t xDelay;
+
+
     printf("Do Reset Camera\n");
     PowerResetCamera();
     Camera.InitCam();
@@ -171,7 +178,7 @@ extern "C" void app_main(void)
 
     wifi_init_sta(ssid, passwd, hostname, ip, gateway, netmask, dns);
     
-    TickType_t xDelay;
+
     xDelay = 2000 / portTICK_PERIOD_MS;
     printf("main: sleep for : %ldms\n", (long) xDelay);
 //    LogFile.WriteToFile("Startsequence 06");      
@@ -184,6 +191,9 @@ extern "C" void app_main(void)
     LogFile.WriteToFile("=============================================================================================");
     LogFile.SwitchOnOff(false);
 
+
+
+
     std::string zw = gettimestring("%Y%m%d-%H%M%S");
     printf("time %s\n", zw.c_str());    
 

+ 26 - 54
code/main/server_main.cpp

@@ -47,11 +47,11 @@ esp_err_t info_get_handler(httpd_req_t *req)
         }
     };
 
+    httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
+
     if (_task.compare("GitBranch") == 0)
     {
-        std::string zw;
-        zw = std::string(libfive_git_branch());
-        httpd_resp_sendstr_chunk(req, zw.c_str());
+        httpd_resp_sendstr_chunk(req, libfive_git_branch());
         httpd_resp_sendstr_chunk(req, NULL);  
         return ESP_OK;        
     }
@@ -59,9 +59,7 @@ esp_err_t info_get_handler(httpd_req_t *req)
 
     if (_task.compare("GitTag") == 0)
     {
-        std::string zw;
-        zw = std::string(libfive_git_version());
-        httpd_resp_sendstr_chunk(req, zw.c_str());
+        httpd_resp_sendstr_chunk(req, libfive_git_version());
         httpd_resp_sendstr_chunk(req, NULL);  
         return ESP_OK;        
     }
@@ -70,36 +68,30 @@ esp_err_t info_get_handler(httpd_req_t *req)
 
     if (_task.compare("GitRevision") == 0)
     {
-        std::string zw;
-        zw = std::string(libfive_git_revision());
-        httpd_resp_sendstr_chunk(req, zw.c_str());
+        httpd_resp_sendstr_chunk(req, libfive_git_revision());
         httpd_resp_sendstr_chunk(req, NULL);  
         return ESP_OK;        
     }
 
     if (_task.compare("BuildTime") == 0)
     {
-        std::string zw;
-        zw = std::string(build_time());
-        httpd_resp_sendstr_chunk(req, zw.c_str());
+        httpd_resp_sendstr_chunk(req, build_time());
         httpd_resp_sendstr_chunk(req, NULL);  
         return ESP_OK;        
     }
 
     if (_task.compare("GitBaseBranch") == 0)
     {
-        std::string zw;
-        zw = std::string(git_base_branch());
-        httpd_resp_sendstr_chunk(req, zw.c_str());
+        httpd_resp_sendstr_chunk(req, git_base_branch());
         httpd_resp_sendstr_chunk(req, NULL);  
         return ESP_OK;        
     }
 
     if (_task.compare("HTMLVersion") == 0)
     {
-        std::string zw;
-        zw = std::string(getHTMLversion());
-        httpd_resp_sendstr_chunk(req, zw.c_str());
+//        std::string zw;
+//        zw = std::string(getHTMLversion());
+        httpd_resp_sendstr_chunk(req, getHTMLversion());
         httpd_resp_sendstr_chunk(req, NULL);  
         return ESP_OK;        
     }
@@ -115,18 +107,18 @@ esp_err_t info_get_handler(httpd_req_t *req)
 
     if (_task.compare("IP") == 0)
     {
-        std::string zw;
-        zw = std::string(getIPAddress());
-        httpd_resp_sendstr_chunk(req, zw.c_str());
+        std::string *zw;
+        zw = getIPAddress();
+        httpd_resp_sendstr_chunk(req, zw->c_str());
         httpd_resp_sendstr_chunk(req, NULL);  
         return ESP_OK;        
     }
 
     if (_task.compare("SSID") == 0)
     {
-        std::string zw;
-        zw = std::string(getSSID());
-        httpd_resp_sendstr_chunk(req, zw.c_str());
+        std::string *zw;
+        zw = getSSID();
+        httpd_resp_sendstr_chunk(req, zw->c_str());
         httpd_resp_sendstr_chunk(req, NULL);  
         return ESP_OK;        
     }
@@ -140,28 +132,15 @@ esp_err_t info_get_handler(httpd_req_t *req)
         return ESP_OK;        
     }
 
-
-#ifdef DEBUG_DETAIL_ON      
-    LogFile.WriteHeapInfo("info_get_handler - Done"); 
-#endif   
-
     return ESP_OK;
 }
 
 esp_err_t starttime_get_handler(httpd_req_t *req)
 {
-#ifdef DEBUG_DETAIL_ON      
-    LogFile.WriteHeapInfo("starttime_get_handler - Start");       
-#endif
-
     httpd_resp_send(req, starttime.c_str(), strlen(starttime.c_str())); 
     /* Respond with an empty chunk to signal HTTP response completion */
     httpd_resp_send_chunk(req, NULL, 0);  
 
-#ifdef DEBUG_DETAIL_ON      
-    LogFile.WriteHeapInfo("starttime_get_handler - Done"); 
-#endif         
-
     return ESP_OK;
 }
 
@@ -215,12 +194,15 @@ esp_err_t hello_main_handler(httpd_req_t *req)
     }
 
     res = send_file(req, filetosend);
+    /* Respond with an empty chunk to signal HTTP response completion */
+    httpd_resp_send_chunk(req, NULL, 0);
+
     if (res != ESP_OK)
         return res;
 
     /* Respond with an empty chunk to signal HTTP response completion */
 //    httpd_resp_sendstr(req, "");
-    httpd_resp_send_chunk(req, NULL, 0);
+//    httpd_resp_send_chunk(req, NULL, 0);
 
 #ifdef DEBUG_DETAIL_ON      
     LogFile.WriteHeapInfo("hello_main_handler - Stop");   
@@ -297,10 +279,6 @@ esp_err_t img_tmp_virtual_handler(httpd_req_t *req)
 
 esp_err_t sysinfo_handler(httpd_req_t *req)
 {
-#ifdef DEBUG_DETAIL_ON      
-    LogFile.WriteHeapInfo("sysinfo_handler - Start");  
-#endif
-
     const char* resp_str; 
     std::string zw;
     std::string cputemp = std::to_string(temperatureRead());
@@ -331,7 +309,6 @@ esp_err_t sysinfo_handler(httpd_req_t *req)
             }\
         ]";
 
-
     resp_str = zw.c_str();
 
     httpd_resp_set_type(req, "application/json");
@@ -339,10 +316,6 @@ esp_err_t sysinfo_handler(httpd_req_t *req)
     /* Respond with an empty chunk to signal HTTP response completion */
     httpd_resp_send_chunk(req, NULL, 0);  
 
-#ifdef DEBUG_DETAIL_ON      
-    LogFile.WriteHeapInfo("sysinfo_handler - Done");
-#endif          
-
     return ESP_OK;
 }
 
@@ -399,25 +372,24 @@ httpd_handle_t start_webserver(void)
     httpd_handle_t server = NULL;
     httpd_config_t config = { };
 
-    config.task_priority      = tskIDLE_PRIORITY+5;
-    config.stack_size         = 32768;                  // bei 32k stürzt das Programm beim Bilderaufnehmen ab
+    config.task_priority      = tskIDLE_PRIORITY+1;         // 20210924 --> vorher +5
+    config.stack_size         = 32768;      //20210921 --> vorher 32768             // bei 32k stürzt das Programm beim Bilderaufnehmen ab
     config.core_id            = tskNO_AFFINITY;
     config.server_port        = 80;
     config.ctrl_port          = 32768;
-    config.max_open_sockets   = 7;      
+    config.max_open_sockets   = 5;          //20210921 --> vorher 7   
     config.max_uri_handlers   = 24;                       
     config.max_resp_headers   = 8;                        
     config.backlog_conn       = 5;                        
-    config.lru_purge_enable   = true;       // dadurch werden alter Verbindungen gekappt, falls neue benögt werden.               
-    config.recv_wait_timeout  = 30;         // default: 5                       
-    config.send_wait_timeout  = 30;         // default: 5                        
+    config.lru_purge_enable   = true;       // dadurch werden alte Verbindungen gekappt, falls neue benögt werden.               
+    config.recv_wait_timeout  = 5;         // default: 5         20210924 --> vorher 30              
+    config.send_wait_timeout  = 5;         // default: 5         20210924 --> vorher 30                   
     config.global_user_ctx = NULL;                        
     config.global_user_ctx_free_fn = NULL;                
     config.global_transport_ctx = NULL;                   
     config.global_transport_ctx_free_fn = NULL;           
     config.open_fn = NULL;                                
     config.close_fn = NULL;     
-    config.lru_purge_enable = true;             // neu, um schlechte Serverbindung zu verhindern                          
 //    config.uri_match_fn = NULL;                            
     config.uri_match_fn = httpd_uri_match_wildcard;
 

+ 3 - 3
code/main/version.cpp

@@ -1,4 +1,4 @@
-const char* GIT_REV="7fcb5d1";
+const char* GIT_REV="f15e5f0";
 const char* GIT_TAG="";
-const char* GIT_BRANCH="master";
-const char* BUILD_TIME="2021-09-12 07:30";
+const char* GIT_BRANCH="rolling";
+const char* BUILD_TIME="2021-09-24 19:25";

+ 8 - 10
code/main/version.h

@@ -13,7 +13,7 @@ extern "C"
 #include "Helper.h"
 #include <fstream>
 
-const char* GIT_BASE_BRANCH = "master - v8.3.0 - 2021-09-12";
+const char* GIT_BASE_BRANCH = "master - v8.4.0 - 2021-09-24";
 
 
 const char* git_base_branch(void)
@@ -42,21 +42,19 @@ const char* libfive_git_branch(void)
     return GIT_BRANCH;
 }
 
-std::string getHTMLversion(void){
-    
-    string line = "";
-    
+
+char _char_getHTMLversion[20]="NaN\0";
+
+const char* getHTMLversion(void){
     FILE* pFile;
     string fn = FormatFileName("/sdcard/html/version.txt");
     pFile = fopen(fn.c_str(), "r");
 
     if (pFile == NULL)
-        return std::string("NAN");
+        return _char_getHTMLversion;
 
-    char zw[1024];
-    fgets(zw, 1024, pFile);
-    line = std::string(trim(zw));
+    fgets(_char_getHTMLversion, 20, pFile);
     fclose(pFile);
 
-    return line;
+    return _char_getHTMLversion;
 }

+ 2 - 2
code/sdkconfig

@@ -389,7 +389,7 @@ CONFIG_ESP_INT_WDT_TIMEOUT_MS=300
 CONFIG_ESP_INT_WDT_CHECK_CPU1=y
 CONFIG_ESP_TASK_WDT=y
 # CONFIG_ESP_TASK_WDT_PANIC is not set
-CONFIG_ESP_TASK_WDT_TIMEOUT_S=3
+CONFIG_ESP_TASK_WDT_TIMEOUT_S=6
 CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU0=y
 CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU1=y
 # CONFIG_ESP_PANIC_HANDLER_IRAM is not set
@@ -1107,7 +1107,7 @@ 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_TIMEOUT_S=6
 CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU0=y
 CONFIG_TASK_WDT_CHECK_IDLE_TASK_CPU1=y
 # CONFIG_EVENT_LOOP_PROFILING is not set

+ 1300 - 0
code/sdkconfig.esp32cam

@@ -0,0 +1,1300 @@
+#
+# Automatically generated file. DO NOT EDIT.
+# Espressif IoT Development Framework (ESP-IDF) Project Configuration
+#
+CONFIG_IDF_CMAKE=y
+CONFIG_IDF_TARGET_ARCH_XTENSA=y
+CONFIG_IDF_TARGET="esp32"
+CONFIG_IDF_TARGET_ESP32=y
+CONFIG_IDF_FIRMWARE_CHIP_ID=0x0000
+
+#
+# SDK tool configuration
+#
+CONFIG_SDK_TOOLPREFIX="xtensa-esp32-elf-"
+# CONFIG_SDK_TOOLCHAIN_SUPPORTS_TIME_WIDE_64_BITS is not set
+# end of SDK tool configuration
+
+#
+# Build type
+#
+CONFIG_APP_BUILD_TYPE_APP_2NDBOOT=y
+# CONFIG_APP_BUILD_TYPE_ELF_RAM is not set
+CONFIG_APP_BUILD_GENERATE_BINARIES=y
+CONFIG_APP_BUILD_BOOTLOADER=y
+CONFIG_APP_BUILD_USE_FLASH_SECTIONS=y
+# end of Build type
+
+#
+# Application manager
+#
+CONFIG_APP_COMPILE_TIME_DATE=y
+# CONFIG_APP_EXCLUDE_PROJECT_VER_VAR is not set
+# CONFIG_APP_EXCLUDE_PROJECT_NAME_VAR is not set
+# CONFIG_APP_PROJECT_VER_FROM_CONFIG is not set
+CONFIG_APP_RETRIEVE_LEN_ELF_SHA=16
+# end of Application manager
+
+#
+# Bootloader config
+#
+CONFIG_BOOTLOADER_OFFSET_IN_FLASH=0x1000
+CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_SIZE=y
+# CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_DEBUG is not set
+# CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_PERF is not set
+# CONFIG_BOOTLOADER_COMPILER_OPTIMIZATION_NONE is not set
+# CONFIG_BOOTLOADER_LOG_LEVEL_NONE is not set
+# CONFIG_BOOTLOADER_LOG_LEVEL_ERROR is not set
+# CONFIG_BOOTLOADER_LOG_LEVEL_WARN is not set
+CONFIG_BOOTLOADER_LOG_LEVEL_INFO=y
+# CONFIG_BOOTLOADER_LOG_LEVEL_DEBUG is not set
+# CONFIG_BOOTLOADER_LOG_LEVEL_VERBOSE is not set
+CONFIG_BOOTLOADER_LOG_LEVEL=3
+# CONFIG_BOOTLOADER_VDDSDIO_BOOST_1_8V is not set
+CONFIG_BOOTLOADER_VDDSDIO_BOOST_1_9V=y
+# CONFIG_BOOTLOADER_FACTORY_RESET is not set
+# CONFIG_BOOTLOADER_APP_TEST is not set
+CONFIG_BOOTLOADER_WDT_ENABLE=y
+# CONFIG_BOOTLOADER_WDT_DISABLE_IN_USER_CODE is not set
+CONFIG_BOOTLOADER_WDT_TIME_MS=9000
+# CONFIG_BOOTLOADER_APP_ROLLBACK_ENABLE is not set
+# CONFIG_BOOTLOADER_SKIP_VALIDATE_IN_DEEP_SLEEP is not set
+# CONFIG_BOOTLOADER_SKIP_VALIDATE_ON_POWER_ON is not set
+# CONFIG_BOOTLOADER_SKIP_VALIDATE_ALWAYS is not set
+CONFIG_BOOTLOADER_RESERVE_RTC_SIZE=0
+# CONFIG_BOOTLOADER_CUSTOM_RESERVE_RTC is not set
+# end of Bootloader config
+
+#
+# Security features
+#
+# CONFIG_SECURE_SIGNED_APPS_NO_SECURE_BOOT is not set
+# CONFIG_SECURE_BOOT is not set
+# CONFIG_SECURE_FLASH_ENC_ENABLED is not set
+# end of Security features
+
+#
+# Serial flasher config
+#
+CONFIG_ESPTOOLPY_BAUD_OTHER_VAL=115200
+# CONFIG_ESPTOOLPY_NO_STUB is not set
+# CONFIG_ESPTOOLPY_FLASHMODE_QIO is not set
+# CONFIG_ESPTOOLPY_FLASHMODE_QOUT is not set
+CONFIG_ESPTOOLPY_FLASHMODE_DIO=y
+# CONFIG_ESPTOOLPY_FLASHMODE_DOUT is not set
+CONFIG_ESPTOOLPY_FLASHMODE="dio"
+# CONFIG_ESPTOOLPY_FLASHFREQ_80M is not set
+CONFIG_ESPTOOLPY_FLASHFREQ_40M=y
+# CONFIG_ESPTOOLPY_FLASHFREQ_26M is not set
+# CONFIG_ESPTOOLPY_FLASHFREQ_20M is not set
+CONFIG_ESPTOOLPY_FLASHFREQ="40m"
+# CONFIG_ESPTOOLPY_FLASHSIZE_1MB is not set
+CONFIG_ESPTOOLPY_FLASHSIZE_2MB=y
+# CONFIG_ESPTOOLPY_FLASHSIZE_4MB is not set
+# CONFIG_ESPTOOLPY_FLASHSIZE_8MB is not set
+# CONFIG_ESPTOOLPY_FLASHSIZE_16MB is not set
+CONFIG_ESPTOOLPY_FLASHSIZE="2MB"
+CONFIG_ESPTOOLPY_FLASHSIZE_DETECT=y
+CONFIG_ESPTOOLPY_BEFORE_RESET=y
+# CONFIG_ESPTOOLPY_BEFORE_NORESET is not set
+CONFIG_ESPTOOLPY_BEFORE="default_reset"
+CONFIG_ESPTOOLPY_AFTER_RESET=y
+# CONFIG_ESPTOOLPY_AFTER_NORESET is not set
+CONFIG_ESPTOOLPY_AFTER="hard_reset"
+# CONFIG_ESPTOOLPY_MONITOR_BAUD_CONSOLE is not set
+# CONFIG_ESPTOOLPY_MONITOR_BAUD_9600B is not set
+# CONFIG_ESPTOOLPY_MONITOR_BAUD_57600B is not set
+CONFIG_ESPTOOLPY_MONITOR_BAUD_115200B=y
+# CONFIG_ESPTOOLPY_MONITOR_BAUD_230400B is not set
+# CONFIG_ESPTOOLPY_MONITOR_BAUD_921600B is not set
+# CONFIG_ESPTOOLPY_MONITOR_BAUD_2MB is not set
+# CONFIG_ESPTOOLPY_MONITOR_BAUD_OTHER is not set
+CONFIG_ESPTOOLPY_MONITOR_BAUD_OTHER_VAL=115200
+CONFIG_ESPTOOLPY_MONITOR_BAUD=115200
+# end of Serial flasher config
+
+#
+# Partition Table
+#
+CONFIG_PARTITION_TABLE_SINGLE_APP=y
+# CONFIG_PARTITION_TABLE_TWO_OTA is not set
+# CONFIG_PARTITION_TABLE_CUSTOM is not set
+CONFIG_PARTITION_TABLE_CUSTOM_FILENAME="partitions.csv"
+CONFIG_PARTITION_TABLE_FILENAME="partitions_singleapp.csv"
+CONFIG_PARTITION_TABLE_OFFSET=0x8000
+CONFIG_PARTITION_TABLE_MD5=y
+# end of Partition Table
+
+#
+# Example Connection Configuration
+#
+CONFIG_EXAMPLE_CONNECT_WIFI=y
+CONFIG_EXAMPLE_WIFI_SSID="myssid"
+CONFIG_EXAMPLE_WIFI_PASSWORD="mypassword"
+# CONFIG_EXAMPLE_CONNECT_ETHERNET is not set
+CONFIG_EXAMPLE_CONNECT_IPV6=y
+CONFIG_EXAMPLE_CONNECT_IPV6_PREF_LOCAL_LINK=y
+# CONFIG_EXAMPLE_CONNECT_IPV6_PREF_GLOBAL is not set
+# CONFIG_EXAMPLE_CONNECT_IPV6_PREF_SITE_LOCAL is not set
+# CONFIG_EXAMPLE_CONNECT_IPV6_PREF_UNIQUE_LOCAL is not set
+# end of Example Connection Configuration
+
+#
+# Compiler options
+#
+CONFIG_COMPILER_OPTIMIZATION_DEFAULT=y
+# CONFIG_COMPILER_OPTIMIZATION_SIZE is not set
+# CONFIG_COMPILER_OPTIMIZATION_PERF is not set
+# CONFIG_COMPILER_OPTIMIZATION_NONE is not set
+CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_ENABLE=y
+# CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT is not set
+# CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_DISABLE is not set
+# CONFIG_COMPILER_CXX_EXCEPTIONS is not set
+# CONFIG_COMPILER_CXX_RTTI is not set
+CONFIG_COMPILER_STACK_CHECK_MODE_NONE=y
+# CONFIG_COMPILER_STACK_CHECK_MODE_NORM is not set
+# CONFIG_COMPILER_STACK_CHECK_MODE_STRONG is not set
+# CONFIG_COMPILER_STACK_CHECK_MODE_ALL is not set
+# CONFIG_COMPILER_WARN_WRITE_STRINGS is not set
+# CONFIG_COMPILER_DISABLE_GCC8_WARNINGS is not set
+# CONFIG_COMPILER_DUMP_RTL_FILES is not set
+# end of Compiler options
+
+#
+# Component config
+#
+
+#
+# Application Level Tracing
+#
+# CONFIG_APPTRACE_DEST_TRAX is not set
+CONFIG_APPTRACE_DEST_NONE=y
+CONFIG_APPTRACE_LOCK_ENABLE=y
+# end of Application Level Tracing
+
+#
+# ESP-ASIO
+#
+# CONFIG_ASIO_SSL_SUPPORT is not set
+# end of ESP-ASIO
+
+#
+# Bluetooth
+#
+# 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
+CONFIG_BTDM_CTRL_PINNED_TO_CORE=0
+CONFIG_BTDM_BLE_SLEEP_CLOCK_ACCURACY_INDEX_EFF=1
+CONFIG_BT_CTRL_MODE_EFF=1
+CONFIG_BT_CTRL_BLE_MAX_ACT=10
+CONFIG_BT_CTRL_BLE_MAX_ACT_EFF=10
+CONFIG_BT_CTRL_BLE_STATIC_ACL_TX_BUF_NB=0
+CONFIG_BT_CTRL_PINNED_TO_CORE=0
+CONFIG_BT_CTRL_HCI_TL=1
+CONFIG_BT_CTRL_ADV_DUP_FILT_MAX=30
+CONFIG_BT_CTRL_HW_CCA_EFF=0
+CONFIG_BT_CTRL_DFT_TX_POWER_LEVEL_EFF=0
+CONFIG_BT_CTRL_BLE_ADV_REPORT_FLOW_CTRL_SUPP=y
+CONFIG_BT_CTRL_BLE_ADV_REPORT_FLOW_CTRL_NUM=100
+CONFIG_BT_CTRL_BLE_ADV_REPORT_DISCARD_THRSHOLD=20
+CONFIG_BT_CTRL_BLE_SCAN_DUPL=y
+CONFIG_BT_CTRL_SCAN_DUPL_TYPE=0
+CONFIG_BT_CTRL_SCAN_DUPL_CACHE_SIZE=100
+CONFIG_BT_CTRL_COEX_PHY_CODED_TX_RX_TLIM_EFF=0
+CONFIG_BT_CTRL_SLEEP_MODE_EFF=0
+CONFIG_BT_CTRL_SLEEP_CLOCK_EFF=0
+CONFIG_BT_CTRL_HCI_TL_EFF=1
+CONFIG_BT_RESERVE_DRAM=0
+# end of Bluetooth
+
+#
+# CoAP Configuration
+#
+CONFIG_COAP_MBEDTLS_PSK=y
+# CONFIG_COAP_MBEDTLS_PKI is not set
+# CONFIG_COAP_MBEDTLS_DEBUG is not set
+CONFIG_COAP_LOG_DEFAULT_LEVEL=0
+# end of CoAP Configuration
+
+#
+# Driver configurations
+#
+
+#
+# ADC configuration
+#
+# CONFIG_ADC_FORCE_XPD_FSM is not set
+CONFIG_ADC_DISABLE_DAC=y
+# end of ADC configuration
+
+#
+# SPI configuration
+#
+# CONFIG_SPI_MASTER_IN_IRAM is not set
+CONFIG_SPI_MASTER_ISR_IN_IRAM=y
+# CONFIG_SPI_SLAVE_IN_IRAM is not set
+CONFIG_SPI_SLAVE_ISR_IN_IRAM=y
+# end of SPI configuration
+
+#
+# TWAI configuration
+#
+# CONFIG_TWAI_ISR_IN_IRAM is not set
+# CONFIG_TWAI_ERRATA_FIX_BUS_OFF_REC is not set
+# CONFIG_TWAI_ERRATA_FIX_TX_INTR_LOST is not set
+# CONFIG_TWAI_ERRATA_FIX_RX_FRAME_INVALID is not set
+# CONFIG_TWAI_ERRATA_FIX_RX_FIFO_CORRUPT is not set
+# end of TWAI configuration
+
+#
+# UART configuration
+#
+# CONFIG_UART_ISR_IN_IRAM is not set
+# end of UART configuration
+
+#
+# RTCIO configuration
+#
+# CONFIG_RTCIO_SUPPORT_RTC_GPIO_DESC is not set
+# end of RTCIO configuration
+
+#
+# GPIO Configuration
+#
+# CONFIG_GPIO_ESP32_SUPPORT_SWITCH_SLP_PULL is not set
+# end of GPIO Configuration
+# end of Driver configurations
+
+#
+# eFuse Bit Manager
+#
+# CONFIG_EFUSE_CUSTOM_TABLE is not set
+# CONFIG_EFUSE_VIRTUAL is not set
+# CONFIG_EFUSE_CODE_SCHEME_COMPAT_NONE is not set
+CONFIG_EFUSE_CODE_SCHEME_COMPAT_3_4=y
+# CONFIG_EFUSE_CODE_SCHEME_COMPAT_REPEAT is not set
+CONFIG_EFUSE_MAX_BLK_LEN=192
+# end of eFuse Bit Manager
+
+#
+# ESP-TLS
+#
+CONFIG_ESP_TLS_USING_MBEDTLS=y
+# CONFIG_ESP_TLS_USE_SECURE_ELEMENT is not set
+# CONFIG_ESP_TLS_SERVER is not set
+# CONFIG_ESP_TLS_PSK_VERIFICATION is not set
+# CONFIG_ESP_TLS_INSECURE is not set
+# end of ESP-TLS
+
+#
+# ESP32-specific
+#
+CONFIG_ESP32_REV_MIN_0=y
+# CONFIG_ESP32_REV_MIN_1 is not set
+# CONFIG_ESP32_REV_MIN_2 is not set
+# CONFIG_ESP32_REV_MIN_3 is not set
+CONFIG_ESP32_REV_MIN=0
+CONFIG_ESP32_DPORT_WORKAROUND=y
+# CONFIG_ESP32_DEFAULT_CPU_FREQ_80 is not set
+CONFIG_ESP32_DEFAULT_CPU_FREQ_160=y
+# CONFIG_ESP32_DEFAULT_CPU_FREQ_240 is not set
+CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ=160
+# CONFIG_ESP32_SPIRAM_SUPPORT is not set
+# CONFIG_ESP32_TRAX is not set
+CONFIG_ESP32_TRACEMEM_RESERVE_DRAM=0x0
+# CONFIG_ESP32_UNIVERSAL_MAC_ADDRESSES_TWO is not set
+CONFIG_ESP32_UNIVERSAL_MAC_ADDRESSES_FOUR=y
+CONFIG_ESP32_UNIVERSAL_MAC_ADDRESSES=4
+# CONFIG_ESP32_ULP_COPROC_ENABLED is not set
+CONFIG_ESP32_ULP_COPROC_RESERVE_MEM=0
+CONFIG_ESP32_DEBUG_OCDAWARE=y
+CONFIG_ESP32_BROWNOUT_DET=y
+CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_0=y
+# CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_1 is not set
+# CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_2 is not set
+# CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_3 is not set
+# CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_4 is not set
+# CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_5 is not set
+# CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_6 is not set
+# CONFIG_ESP32_BROWNOUT_DET_LVL_SEL_7 is not set
+CONFIG_ESP32_BROWNOUT_DET_LVL=0
+CONFIG_ESP32_REDUCE_PHY_TX_POWER=y
+CONFIG_ESP32_TIME_SYSCALL_USE_RTC_FRC1=y
+# CONFIG_ESP32_TIME_SYSCALL_USE_RTC is not set
+# CONFIG_ESP32_TIME_SYSCALL_USE_FRC1 is not set
+# CONFIG_ESP32_TIME_SYSCALL_USE_NONE is not set
+CONFIG_ESP32_RTC_CLK_SRC_INT_RC=y
+# CONFIG_ESP32_RTC_CLK_SRC_EXT_CRYS is not set
+# CONFIG_ESP32_RTC_CLK_SRC_EXT_OSC is not set
+# CONFIG_ESP32_RTC_CLK_SRC_INT_8MD256 is not set
+CONFIG_ESP32_RTC_CLK_CAL_CYCLES=1024
+CONFIG_ESP32_DEEP_SLEEP_WAKEUP_DELAY=2000
+CONFIG_ESP32_XTAL_FREQ_40=y
+# CONFIG_ESP32_XTAL_FREQ_26 is not set
+# CONFIG_ESP32_XTAL_FREQ_AUTO is not set
+CONFIG_ESP32_XTAL_FREQ=40
+# CONFIG_ESP32_DISABLE_BASIC_ROM_CONSOLE is not set
+# CONFIG_ESP32_NO_BLOBS is not set
+# CONFIG_ESP32_COMPATIBLE_PRE_V2_1_BOOTLOADERS is not set
+# CONFIG_ESP32_USE_FIXED_STATIC_RAM_SIZE is not set
+CONFIG_ESP32_DPORT_DIS_INTERRUPT_LVL=5
+# end of ESP32-specific
+
+#
+# ADC-Calibration
+#
+CONFIG_ADC_CAL_EFUSE_TP_ENABLE=y
+CONFIG_ADC_CAL_EFUSE_VREF_ENABLE=y
+CONFIG_ADC_CAL_LUT_ENABLE=y
+# end of ADC-Calibration
+
+#
+# Common ESP-related
+#
+CONFIG_ESP_ERR_TO_NAME_LOOKUP=y
+CONFIG_ESP_SYSTEM_EVENT_QUEUE_SIZE=32
+CONFIG_ESP_SYSTEM_EVENT_TASK_STACK_SIZE=2304
+CONFIG_ESP_MAIN_TASK_STACK_SIZE=3584
+CONFIG_ESP_IPC_TASK_STACK_SIZE=1024
+CONFIG_ESP_IPC_USES_CALLERS_PRIORITY=y
+CONFIG_ESP_MINIMAL_SHARED_STACK_SIZE=2048
+CONFIG_ESP_CONSOLE_UART_DEFAULT=y
+# CONFIG_ESP_CONSOLE_UART_CUSTOM is not set
+# CONFIG_ESP_CONSOLE_NONE is not set
+CONFIG_ESP_CONSOLE_UART=y
+CONFIG_ESP_CONSOLE_MULTIPLE_UART=y
+CONFIG_ESP_CONSOLE_UART_NUM=0
+CONFIG_ESP_CONSOLE_UART_BAUDRATE=115200
+CONFIG_ESP_INT_WDT=y
+CONFIG_ESP_INT_WDT_TIMEOUT_MS=300
+CONFIG_ESP_INT_WDT_CHECK_CPU1=y
+CONFIG_ESP_TASK_WDT=y
+# CONFIG_ESP_TASK_WDT_PANIC is not set
+CONFIG_ESP_TASK_WDT_TIMEOUT_S=5
+CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU0=y
+CONFIG_ESP_TASK_WDT_CHECK_IDLE_TASK_CPU1=y
+# CONFIG_ESP_PANIC_HANDLER_IRAM is not set
+CONFIG_ESP_MAC_ADDR_UNIVERSE_WIFI_STA=y
+CONFIG_ESP_MAC_ADDR_UNIVERSE_WIFI_AP=y
+CONFIG_ESP_MAC_ADDR_UNIVERSE_BT=y
+CONFIG_ESP_MAC_ADDR_UNIVERSE_ETH=y
+# end of Common ESP-related
+
+#
+# Ethernet
+#
+CONFIG_ETH_ENABLED=y
+CONFIG_ETH_USE_ESP32_EMAC=y
+CONFIG_ETH_PHY_INTERFACE_RMII=y
+# CONFIG_ETH_PHY_INTERFACE_MII is not set
+CONFIG_ETH_RMII_CLK_INPUT=y
+# CONFIG_ETH_RMII_CLK_OUTPUT is not set
+CONFIG_ETH_RMII_CLK_IN_GPIO=0
+CONFIG_ETH_DMA_BUFFER_SIZE=512
+CONFIG_ETH_DMA_RX_BUFFER_NUM=10
+CONFIG_ETH_DMA_TX_BUFFER_NUM=10
+CONFIG_ETH_USE_SPI_ETHERNET=y
+# CONFIG_ETH_SPI_ETHERNET_DM9051 is not set
+# CONFIG_ETH_SPI_ETHERNET_W5500 is not set
+# CONFIG_ETH_USE_OPENETH is not set
+# end of Ethernet
+
+#
+# Event Loop Library
+#
+# CONFIG_ESP_EVENT_LOOP_PROFILING is not set
+CONFIG_ESP_EVENT_POST_FROM_ISR=y
+CONFIG_ESP_EVENT_POST_FROM_IRAM_ISR=y
+# end of Event Loop Library
+
+#
+# GDB Stub
+#
+# end of GDB Stub
+
+#
+# ESP HTTP client
+#
+CONFIG_ESP_HTTP_CLIENT_ENABLE_HTTPS=y
+# CONFIG_ESP_HTTP_CLIENT_ENABLE_BASIC_AUTH is not set
+# end of ESP HTTP client
+
+#
+# HTTP Server
+#
+CONFIG_HTTPD_MAX_REQ_HDR_LEN=512
+CONFIG_HTTPD_MAX_URI_LEN=512
+CONFIG_HTTPD_ERR_RESP_NO_DELAY=y
+CONFIG_HTTPD_PURGE_BUF_LEN=32
+# CONFIG_HTTPD_LOG_PURGE_DATA is not set
+# CONFIG_HTTPD_WS_SUPPORT is not set
+# end of HTTP Server
+
+#
+# ESP HTTPS OTA
+#
+# CONFIG_OTA_ALLOW_HTTP is not set
+# end of ESP HTTPS OTA
+
+#
+# ESP HTTPS server
+#
+# CONFIG_ESP_HTTPS_SERVER_ENABLE is not set
+# end of ESP HTTPS server
+
+#
+# ESP NETIF Adapter
+#
+CONFIG_ESP_NETIF_IP_LOST_TIMER_INTERVAL=120
+CONFIG_ESP_NETIF_TCPIP_LWIP=y
+# CONFIG_ESP_NETIF_LOOPBACK is not set
+CONFIG_ESP_NETIF_TCPIP_ADAPTER_COMPATIBLE_LAYER=y
+# end of ESP NETIF Adapter
+
+#
+# Power Management
+#
+# CONFIG_PM_ENABLE is not set
+# end of Power Management
+
+#
+# ESP System Settings
+#
+# CONFIG_ESP_SYSTEM_PANIC_PRINT_HALT is not set
+CONFIG_ESP_SYSTEM_PANIC_PRINT_REBOOT=y
+# CONFIG_ESP_SYSTEM_PANIC_SILENT_REBOOT is not set
+# CONFIG_ESP_SYSTEM_PANIC_GDBSTUB is not set
+CONFIG_ESP_SYSTEM_PD_FLASH=y
+
+#
+# Memory protection
+#
+# end of Memory protection
+# end of ESP System Settings
+
+#
+# High resolution timer (esp_timer)
+#
+# CONFIG_ESP_TIMER_PROFILING is not set
+CONFIG_ESP_TIME_FUNCS_USE_RTC_TIMER=y
+CONFIG_ESP_TIME_FUNCS_USE_ESP_TIMER=y
+CONFIG_ESP_TIMER_TASK_STACK_SIZE=3584
+# CONFIG_ESP_TIMER_IMPL_FRC2 is not set
+CONFIG_ESP_TIMER_IMPL_TG0_LAC=y
+# end of High resolution timer (esp_timer)
+
+#
+# Wi-Fi
+#
+CONFIG_ESP32_WIFI_STATIC_RX_BUFFER_NUM=10
+CONFIG_ESP32_WIFI_DYNAMIC_RX_BUFFER_NUM=32
+# CONFIG_ESP32_WIFI_STATIC_TX_BUFFER is not set
+CONFIG_ESP32_WIFI_DYNAMIC_TX_BUFFER=y
+CONFIG_ESP32_WIFI_TX_BUFFER_TYPE=1
+CONFIG_ESP32_WIFI_DYNAMIC_TX_BUFFER_NUM=32
+# CONFIG_ESP32_WIFI_CSI_ENABLED is not set
+CONFIG_ESP32_WIFI_AMPDU_TX_ENABLED=y
+CONFIG_ESP32_WIFI_TX_BA_WIN=6
+CONFIG_ESP32_WIFI_AMPDU_RX_ENABLED=y
+CONFIG_ESP32_WIFI_RX_BA_WIN=6
+CONFIG_ESP32_WIFI_NVS_ENABLED=y
+CONFIG_ESP32_WIFI_TASK_PINNED_TO_CORE_0=y
+# CONFIG_ESP32_WIFI_TASK_PINNED_TO_CORE_1 is not set
+CONFIG_ESP32_WIFI_SOFTAP_BEACON_MAX_LEN=752
+CONFIG_ESP32_WIFI_MGMT_SBUF_NUM=32
+# CONFIG_ESP32_WIFI_DEBUG_LOG_ENABLE is not set
+CONFIG_ESP32_WIFI_IRAM_OPT=y
+CONFIG_ESP32_WIFI_RX_IRAM_OPT=y
+CONFIG_ESP32_WIFI_ENABLE_WPA3_SAE=y
+# CONFIG_ESP_WIFI_SLP_IRAM_OPT is not set
+# CONFIG_ESP_WIFI_STA_DISCONNECTED_PM_ENABLE is not set
+# end of Wi-Fi
+
+#
+# PHY
+#
+CONFIG_ESP32_PHY_CALIBRATION_AND_DATA_STORAGE=y
+# CONFIG_ESP32_PHY_INIT_DATA_IN_PARTITION is not set
+CONFIG_ESP32_PHY_MAX_WIFI_TX_POWER=20
+CONFIG_ESP32_PHY_MAX_TX_POWER=20
+# end of PHY
+
+#
+# Core dump
+#
+# CONFIG_ESP_COREDUMP_ENABLE_TO_FLASH is not set
+# CONFIG_ESP_COREDUMP_ENABLE_TO_UART is not set
+CONFIG_ESP_COREDUMP_ENABLE_TO_NONE=y
+# end of Core dump
+
+#
+# FAT Filesystem support
+#
+# CONFIG_FATFS_CODEPAGE_DYNAMIC is not set
+CONFIG_FATFS_CODEPAGE_437=y
+# CONFIG_FATFS_CODEPAGE_720 is not set
+# CONFIG_FATFS_CODEPAGE_737 is not set
+# CONFIG_FATFS_CODEPAGE_771 is not set
+# CONFIG_FATFS_CODEPAGE_775 is not set
+# CONFIG_FATFS_CODEPAGE_850 is not set
+# CONFIG_FATFS_CODEPAGE_852 is not set
+# CONFIG_FATFS_CODEPAGE_855 is not set
+# CONFIG_FATFS_CODEPAGE_857 is not set
+# CONFIG_FATFS_CODEPAGE_860 is not set
+# CONFIG_FATFS_CODEPAGE_861 is not set
+# CONFIG_FATFS_CODEPAGE_862 is not set
+# CONFIG_FATFS_CODEPAGE_863 is not set
+# CONFIG_FATFS_CODEPAGE_864 is not set
+# CONFIG_FATFS_CODEPAGE_865 is not set
+# CONFIG_FATFS_CODEPAGE_866 is not set
+# CONFIG_FATFS_CODEPAGE_869 is not set
+# CONFIG_FATFS_CODEPAGE_932 is not set
+# CONFIG_FATFS_CODEPAGE_936 is not set
+# CONFIG_FATFS_CODEPAGE_949 is not set
+# CONFIG_FATFS_CODEPAGE_950 is not set
+CONFIG_FATFS_CODEPAGE=437
+CONFIG_FATFS_LFN_NONE=y
+# CONFIG_FATFS_LFN_HEAP is not set
+# CONFIG_FATFS_LFN_STACK is not set
+CONFIG_FATFS_FS_LOCK=0
+CONFIG_FATFS_TIMEOUT_MS=10000
+CONFIG_FATFS_PER_FILE_CACHE=y
+# CONFIG_FATFS_USE_FASTSEEK is not set
+# end of FAT Filesystem support
+
+#
+# Modbus configuration
+#
+CONFIG_FMB_COMM_MODE_TCP_EN=y
+CONFIG_FMB_TCP_PORT_DEFAULT=502
+CONFIG_FMB_TCP_PORT_MAX_CONN=5
+CONFIG_FMB_TCP_CONNECTION_TOUT_SEC=20
+CONFIG_FMB_COMM_MODE_RTU_EN=y
+CONFIG_FMB_COMM_MODE_ASCII_EN=y
+CONFIG_FMB_MASTER_TIMEOUT_MS_RESPOND=150
+CONFIG_FMB_MASTER_DELAY_MS_CONVERT=200
+CONFIG_FMB_QUEUE_LENGTH=20
+CONFIG_FMB_PORT_TASK_STACK_SIZE=4096
+CONFIG_FMB_SERIAL_BUF_SIZE=256
+CONFIG_FMB_SERIAL_ASCII_BITS_PER_SYMB=8
+CONFIG_FMB_SERIAL_ASCII_TIMEOUT_RESPOND_MS=1000
+CONFIG_FMB_PORT_TASK_PRIO=10
+CONFIG_FMB_CONTROLLER_SLAVE_ID_SUPPORT=y
+CONFIG_FMB_CONTROLLER_SLAVE_ID=0x00112233
+CONFIG_FMB_CONTROLLER_NOTIFY_TIMEOUT=20
+CONFIG_FMB_CONTROLLER_NOTIFY_QUEUE_SIZE=20
+CONFIG_FMB_CONTROLLER_STACK_SIZE=4096
+CONFIG_FMB_EVENT_QUEUE_TIMEOUT=20
+CONFIG_FMB_TIMER_PORT_ENABLED=y
+CONFIG_FMB_TIMER_GROUP=0
+CONFIG_FMB_TIMER_INDEX=0
+# CONFIG_FMB_TIMER_ISR_IN_IRAM is not set
+# end of Modbus configuration
+
+#
+# FreeRTOS
+#
+# CONFIG_FREERTOS_UNICORE is not set
+CONFIG_FREERTOS_NO_AFFINITY=0x7FFFFFFF
+CONFIG_FREERTOS_CORETIMER_0=y
+# CONFIG_FREERTOS_CORETIMER_1 is not set
+CONFIG_FREERTOS_HZ=100
+CONFIG_FREERTOS_ASSERT_ON_UNTESTED_FUNCTION=y
+# CONFIG_FREERTOS_CHECK_STACKOVERFLOW_NONE is not set
+# CONFIG_FREERTOS_CHECK_STACKOVERFLOW_PTRVAL is not set
+CONFIG_FREERTOS_CHECK_STACKOVERFLOW_CANARY=y
+# CONFIG_FREERTOS_WATCHPOINT_END_OF_STACK is not set
+CONFIG_FREERTOS_INTERRUPT_BACKTRACE=y
+CONFIG_FREERTOS_THREAD_LOCAL_STORAGE_POINTERS=1
+CONFIG_FREERTOS_ASSERT_FAIL_ABORT=y
+# CONFIG_FREERTOS_ASSERT_FAIL_PRINT_CONTINUE is not set
+# CONFIG_FREERTOS_ASSERT_DISABLE is not set
+CONFIG_FREERTOS_IDLE_TASK_STACKSIZE=2304
+CONFIG_FREERTOS_ISR_STACKSIZE=1536
+# CONFIG_FREERTOS_LEGACY_HOOKS is not set
+CONFIG_FREERTOS_MAX_TASK_NAME_LEN=16
+CONFIG_FREERTOS_SUPPORT_STATIC_ALLOCATION=y
+# CONFIG_FREERTOS_ENABLE_STATIC_TASK_CLEAN_UP is not set
+CONFIG_FREERTOS_TIMER_TASK_PRIORITY=1
+CONFIG_FREERTOS_TIMER_TASK_STACK_DEPTH=2048
+CONFIG_FREERTOS_TIMER_QUEUE_LENGTH=10
+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_TASK_FUNCTION_WRAPPER=y
+CONFIG_FREERTOS_CHECK_MUTEX_GIVEN_BY_OWNER=y
+# CONFIG_FREERTOS_CHECK_PORT_CRITICAL_COMPLIANCE is not set
+# CONFIG_FREERTOS_PLACE_FUNCTIONS_INTO_FLASH is not set
+CONFIG_FREERTOS_DEBUG_OCDAWARE=y
+# CONFIG_FREERTOS_FPU_IN_ISR is not set
+# end of FreeRTOS
+
+#
+# Heap memory debugging
+#
+CONFIG_HEAP_POISONING_DISABLED=y
+# CONFIG_HEAP_POISONING_LIGHT is not set
+# CONFIG_HEAP_POISONING_COMPREHENSIVE is not set
+CONFIG_HEAP_TRACING_OFF=y
+# CONFIG_HEAP_TRACING_STANDALONE is not set
+# CONFIG_HEAP_TRACING_TOHOST is not set
+# CONFIG_HEAP_ABORT_WHEN_ALLOCATION_FAILS is not set
+# end of Heap memory debugging
+
+#
+# jsmn
+#
+# CONFIG_JSMN_PARENT_LINKS is not set
+# CONFIG_JSMN_STRICT is not set
+# end of jsmn
+
+#
+# libsodium
+#
+# end of libsodium
+
+#
+# Log output
+#
+# CONFIG_LOG_DEFAULT_LEVEL_NONE is not set
+# CONFIG_LOG_DEFAULT_LEVEL_ERROR is not set
+# CONFIG_LOG_DEFAULT_LEVEL_WARN is not set
+CONFIG_LOG_DEFAULT_LEVEL_INFO=y
+# CONFIG_LOG_DEFAULT_LEVEL_DEBUG is not set
+# CONFIG_LOG_DEFAULT_LEVEL_VERBOSE is not set
+CONFIG_LOG_DEFAULT_LEVEL=3
+CONFIG_LOG_COLORS=y
+CONFIG_LOG_TIMESTAMP_SOURCE_RTOS=y
+# CONFIG_LOG_TIMESTAMP_SOURCE_SYSTEM is not set
+# end of Log output
+
+#
+# LWIP
+#
+CONFIG_LWIP_LOCAL_HOSTNAME="espressif"
+CONFIG_LWIP_DNS_SUPPORT_MDNS_QUERIES=y
+# CONFIG_LWIP_L2_TO_L3_COPY is not set
+# CONFIG_LWIP_IRAM_OPTIMIZATION is not set
+CONFIG_LWIP_TIMERS_ONDEMAND=y
+CONFIG_LWIP_MAX_SOCKETS=10
+# CONFIG_LWIP_USE_ONLY_LWIP_SELECT is not set
+# CONFIG_LWIP_SO_LINGER is not set
+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_IP4_FRAG=y
+CONFIG_LWIP_IP6_FRAG=y
+# CONFIG_LWIP_IP4_REASSEMBLY is not set
+# CONFIG_LWIP_IP6_REASSEMBLY is not set
+# CONFIG_LWIP_IP_FORWARD is not set
+# CONFIG_LWIP_STATS is not set
+# CONFIG_LWIP_ETHARP_TRUST_IP_MAC is not set
+CONFIG_LWIP_ESP_GRATUITOUS_ARP=y
+CONFIG_LWIP_GARP_TMR_INTERVAL=60
+CONFIG_LWIP_TCPIP_RECVMBOX_SIZE=32
+CONFIG_LWIP_DHCP_DOES_ARP_CHECK=y
+# CONFIG_LWIP_DHCP_RESTORE_LAST_IP is not set
+
+#
+# DHCP server
+#
+CONFIG_LWIP_DHCPS_LEASE_UNIT=60
+CONFIG_LWIP_DHCPS_MAX_STATION_NUM=8
+# end of DHCP server
+
+# CONFIG_LWIP_AUTOIP is not set
+CONFIG_LWIP_IPV6=y
+# CONFIG_LWIP_IPV6_AUTOCONFIG is not set
+CONFIG_LWIP_NETIF_LOOPBACK=y
+CONFIG_LWIP_LOOPBACK_MAX_PBUFS=8
+
+#
+# TCP
+#
+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=12
+CONFIG_LWIP_TCP_MSS=1440
+CONFIG_LWIP_TCP_TMR_INTERVAL=250
+CONFIG_LWIP_TCP_MSL=60000
+CONFIG_LWIP_TCP_SND_BUF_DEFAULT=5744
+CONFIG_LWIP_TCP_WND_DEFAULT=5744
+CONFIG_LWIP_TCP_RECVMBOX_SIZE=6
+CONFIG_LWIP_TCP_QUEUE_OOSEQ=y
+# CONFIG_LWIP_TCP_SACK_OUT is not set
+# CONFIG_LWIP_TCP_KEEP_CONNECTION_WHEN_IP_CHANGES is not set
+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
+
+#
+# UDP
+#
+CONFIG_LWIP_MAX_UDP_PCBS=16
+CONFIG_LWIP_UDP_RECVMBOX_SIZE=6
+# end of UDP
+
+#
+# Checksums
+#
+# CONFIG_LWIP_CHECKSUM_CHECK_IP is not set
+# CONFIG_LWIP_CHECKSUM_CHECK_UDP is not set
+CONFIG_LWIP_CHECKSUM_CHECK_ICMP=y
+# end of Checksums
+
+CONFIG_LWIP_TCPIP_TASK_STACK_SIZE=3072
+CONFIG_LWIP_TCPIP_TASK_AFFINITY_NO_AFFINITY=y
+# CONFIG_LWIP_TCPIP_TASK_AFFINITY_CPU0 is not set
+# 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
+# CONFIG_LWIP_SLIP_SUPPORT is not set
+
+#
+# ICMP
+#
+# CONFIG_LWIP_MULTICAST_PING is not set
+# CONFIG_LWIP_BROADCAST_PING is not set
+# end of ICMP
+
+#
+# LWIP RAW API
+#
+CONFIG_LWIP_MAX_RAW_PCBS=16
+# end of LWIP RAW API
+
+#
+# SNTP
+#
+CONFIG_LWIP_DHCP_MAX_NTP_SERVERS=1
+CONFIG_LWIP_SNTP_UPDATE_DELAY=3600000
+# end of SNTP
+
+CONFIG_LWIP_ESP_LWIP_ASSERT=y
+
+#
+# Hooks
+#
+# CONFIG_LWIP_HOOK_TCP_ISN_NONE is not set
+CONFIG_LWIP_HOOK_TCP_ISN_DEFAULT=y
+# CONFIG_LWIP_HOOK_TCP_ISN_CUSTOM is not set
+CONFIG_LWIP_HOOK_IP6_ROUTE_NONE=y
+# CONFIG_LWIP_HOOK_IP6_ROUTE_DEFAULT is not set
+# CONFIG_LWIP_HOOK_IP6_ROUTE_CUSTOM is not set
+CONFIG_LWIP_HOOK_NETCONN_EXT_RESOLVE_NONE=y
+# CONFIG_LWIP_HOOK_NETCONN_EXT_RESOLVE_DEFAULT is not set
+# CONFIG_LWIP_HOOK_NETCONN_EXT_RESOLVE_CUSTOM is not set
+# end of Hooks
+
+# CONFIG_LWIP_DEBUG is not set
+# end of LWIP
+
+#
+# mbedTLS
+#
+CONFIG_MBEDTLS_INTERNAL_MEM_ALLOC=y
+# CONFIG_MBEDTLS_DEFAULT_MEM_ALLOC is not set
+# CONFIG_MBEDTLS_CUSTOM_MEM_ALLOC is not set
+CONFIG_MBEDTLS_ASYMMETRIC_CONTENT_LEN=y
+CONFIG_MBEDTLS_SSL_IN_CONTENT_LEN=16384
+CONFIG_MBEDTLS_SSL_OUT_CONTENT_LEN=4096
+# CONFIG_MBEDTLS_DYNAMIC_BUFFER is not set
+# CONFIG_MBEDTLS_DEBUG is not set
+
+#
+# Certificate Bundle
+#
+CONFIG_MBEDTLS_CERTIFICATE_BUNDLE=y
+CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_FULL=y
+# CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_CMN is not set
+# CONFIG_MBEDTLS_CERTIFICATE_BUNDLE_DEFAULT_NONE is not set
+# CONFIG_MBEDTLS_CUSTOM_CERTIFICATE_BUNDLE is not set
+# end of Certificate Bundle
+
+# CONFIG_MBEDTLS_ECP_RESTARTABLE is not set
+# CONFIG_MBEDTLS_CMAC_C is not set
+CONFIG_MBEDTLS_HARDWARE_AES=y
+CONFIG_MBEDTLS_HARDWARE_MPI=y
+CONFIG_MBEDTLS_HARDWARE_SHA=y
+CONFIG_MBEDTLS_ROM_MD5=y
+# CONFIG_MBEDTLS_ATCA_HW_ECDSA_SIGN is not set
+# CONFIG_MBEDTLS_ATCA_HW_ECDSA_VERIFY is not set
+CONFIG_MBEDTLS_HAVE_TIME=y
+# CONFIG_MBEDTLS_HAVE_TIME_DATE is not set
+CONFIG_MBEDTLS_ECDSA_DETERMINISTIC=y
+CONFIG_MBEDTLS_SHA512_C=y
+CONFIG_MBEDTLS_TLS_SERVER_AND_CLIENT=y
+# CONFIG_MBEDTLS_TLS_SERVER_ONLY is not set
+# CONFIG_MBEDTLS_TLS_CLIENT_ONLY is not set
+# CONFIG_MBEDTLS_TLS_DISABLED is not set
+CONFIG_MBEDTLS_TLS_SERVER=y
+CONFIG_MBEDTLS_TLS_CLIENT=y
+CONFIG_MBEDTLS_TLS_ENABLED=y
+
+#
+# TLS Key Exchange Methods
+#
+# CONFIG_MBEDTLS_PSK_MODES is not set
+CONFIG_MBEDTLS_KEY_EXCHANGE_RSA=y
+CONFIG_MBEDTLS_KEY_EXCHANGE_DHE_RSA=y
+CONFIG_MBEDTLS_KEY_EXCHANGE_ELLIPTIC_CURVE=y
+CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_RSA=y
+CONFIG_MBEDTLS_KEY_EXCHANGE_ECDHE_ECDSA=y
+CONFIG_MBEDTLS_KEY_EXCHANGE_ECDH_ECDSA=y
+CONFIG_MBEDTLS_KEY_EXCHANGE_ECDH_RSA=y
+# end of TLS Key Exchange Methods
+
+CONFIG_MBEDTLS_SSL_RENEGOTIATION=y
+# CONFIG_MBEDTLS_SSL_PROTO_SSL3 is not set
+CONFIG_MBEDTLS_SSL_PROTO_TLS1=y
+CONFIG_MBEDTLS_SSL_PROTO_TLS1_1=y
+CONFIG_MBEDTLS_SSL_PROTO_TLS1_2=y
+# CONFIG_MBEDTLS_SSL_PROTO_DTLS is not set
+CONFIG_MBEDTLS_SSL_ALPN=y
+CONFIG_MBEDTLS_CLIENT_SSL_SESSION_TICKETS=y
+CONFIG_MBEDTLS_SERVER_SSL_SESSION_TICKETS=y
+
+#
+# Symmetric Ciphers
+#
+CONFIG_MBEDTLS_AES_C=y
+# CONFIG_MBEDTLS_CAMELLIA_C is not set
+# CONFIG_MBEDTLS_DES_C is not set
+CONFIG_MBEDTLS_RC4_DISABLED=y
+# CONFIG_MBEDTLS_RC4_ENABLED_NO_DEFAULT is not set
+# CONFIG_MBEDTLS_RC4_ENABLED is not set
+# CONFIG_MBEDTLS_BLOWFISH_C is not set
+# CONFIG_MBEDTLS_XTEA_C is not set
+CONFIG_MBEDTLS_CCM_C=y
+CONFIG_MBEDTLS_GCM_C=y
+# end of Symmetric Ciphers
+
+# CONFIG_MBEDTLS_RIPEMD160_C is not set
+
+#
+# Certificates
+#
+CONFIG_MBEDTLS_PEM_PARSE_C=y
+CONFIG_MBEDTLS_PEM_WRITE_C=y
+CONFIG_MBEDTLS_X509_CRL_PARSE_C=y
+CONFIG_MBEDTLS_X509_CSR_PARSE_C=y
+# end of Certificates
+
+CONFIG_MBEDTLS_ECP_C=y
+CONFIG_MBEDTLS_ECDH_C=y
+CONFIG_MBEDTLS_ECDSA_C=y
+# CONFIG_MBEDTLS_ECJPAKE_C is not set
+CONFIG_MBEDTLS_ECP_DP_SECP192R1_ENABLED=y
+CONFIG_MBEDTLS_ECP_DP_SECP224R1_ENABLED=y
+CONFIG_MBEDTLS_ECP_DP_SECP256R1_ENABLED=y
+CONFIG_MBEDTLS_ECP_DP_SECP384R1_ENABLED=y
+CONFIG_MBEDTLS_ECP_DP_SECP521R1_ENABLED=y
+CONFIG_MBEDTLS_ECP_DP_SECP192K1_ENABLED=y
+CONFIG_MBEDTLS_ECP_DP_SECP224K1_ENABLED=y
+CONFIG_MBEDTLS_ECP_DP_SECP256K1_ENABLED=y
+CONFIG_MBEDTLS_ECP_DP_BP256R1_ENABLED=y
+CONFIG_MBEDTLS_ECP_DP_BP384R1_ENABLED=y
+CONFIG_MBEDTLS_ECP_DP_BP512R1_ENABLED=y
+CONFIG_MBEDTLS_ECP_DP_CURVE25519_ENABLED=y
+CONFIG_MBEDTLS_ECP_NIST_OPTIM=y
+# CONFIG_MBEDTLS_POLY1305_C is not set
+# CONFIG_MBEDTLS_CHACHA20_C is not set
+# CONFIG_MBEDTLS_HKDF_C is not set
+# CONFIG_MBEDTLS_THREADING_C is not set
+# CONFIG_MBEDTLS_LARGE_KEY_SOFTWARE_MPI is not set
+# CONFIG_MBEDTLS_SECURITY_RISKS is not set
+# end of mbedTLS
+
+#
+# mDNS
+#
+CONFIG_MDNS_MAX_SERVICES=10
+CONFIG_MDNS_TASK_PRIORITY=1
+CONFIG_MDNS_TASK_STACK_SIZE=4096
+# CONFIG_MDNS_TASK_AFFINITY_NO_AFFINITY is not set
+CONFIG_MDNS_TASK_AFFINITY_CPU0=y
+# CONFIG_MDNS_TASK_AFFINITY_CPU1 is not set
+CONFIG_MDNS_TASK_AFFINITY=0x0
+CONFIG_MDNS_SERVICE_ADD_TIMEOUT_MS=2000
+# CONFIG_MDNS_STRICT_MODE is not set
+CONFIG_MDNS_TIMER_PERIOD_MS=100
+# end of mDNS
+
+#
+# ESP-MQTT Configurations
+#
+CONFIG_MQTT_PROTOCOL_311=y
+CONFIG_MQTT_TRANSPORT_SSL=y
+CONFIG_MQTT_TRANSPORT_WEBSOCKET=y
+CONFIG_MQTT_TRANSPORT_WEBSOCKET_SECURE=y
+# CONFIG_MQTT_MSG_ID_INCREMENTAL is not set
+# CONFIG_MQTT_SKIP_PUBLISH_IF_DISCONNECTED is not set
+# CONFIG_MQTT_REPORT_DELETED_MESSAGES is not set
+# CONFIG_MQTT_USE_CUSTOM_CONFIG is not set
+# CONFIG_MQTT_TASK_CORE_SELECTION_ENABLED is not set
+# CONFIG_MQTT_CUSTOM_OUTBOX is not set
+# end of ESP-MQTT Configurations
+
+#
+# Newlib
+#
+CONFIG_NEWLIB_STDOUT_LINE_ENDING_CRLF=y
+# CONFIG_NEWLIB_STDOUT_LINE_ENDING_LF is not set
+# CONFIG_NEWLIB_STDOUT_LINE_ENDING_CR is not set
+# CONFIG_NEWLIB_STDIN_LINE_ENDING_CRLF is not set
+# CONFIG_NEWLIB_STDIN_LINE_ENDING_LF is not set
+CONFIG_NEWLIB_STDIN_LINE_ENDING_CR=y
+# CONFIG_NEWLIB_NANO_FORMAT is not set
+# end of Newlib
+
+#
+# NVS
+#
+# end of NVS
+
+#
+# OpenSSL
+#
+# CONFIG_OPENSSL_DEBUG is not set
+CONFIG_OPENSSL_ERROR_STACK=y
+# CONFIG_OPENSSL_ASSERT_DO_NOTHING is not set
+CONFIG_OPENSSL_ASSERT_EXIT=y
+# end of OpenSSL
+
+#
+# PThreads
+#
+CONFIG_PTHREAD_TASK_PRIO_DEFAULT=5
+CONFIG_PTHREAD_TASK_STACK_SIZE_DEFAULT=3072
+CONFIG_PTHREAD_STACK_MIN=768
+CONFIG_PTHREAD_DEFAULT_CORE_NO_AFFINITY=y
+# CONFIG_PTHREAD_DEFAULT_CORE_0 is not set
+# CONFIG_PTHREAD_DEFAULT_CORE_1 is not set
+CONFIG_PTHREAD_TASK_CORE_DEFAULT=-1
+CONFIG_PTHREAD_TASK_NAME_DEFAULT="pthread"
+# end of PThreads
+
+#
+# SPI Flash driver
+#
+# CONFIG_SPI_FLASH_VERIFY_WRITE is not set
+# CONFIG_SPI_FLASH_ENABLE_COUNTERS is not set
+CONFIG_SPI_FLASH_ROM_DRIVER_PATCH=y
+CONFIG_SPI_FLASH_DANGEROUS_WRITE_ABORTS=y
+# CONFIG_SPI_FLASH_DANGEROUS_WRITE_FAILS is not set
+# CONFIG_SPI_FLASH_DANGEROUS_WRITE_ALLOWED is not set
+# CONFIG_SPI_FLASH_USE_LEGACY_IMPL is not set
+# CONFIG_SPI_FLASH_SHARE_SPI1_BUS is not set
+# CONFIG_SPI_FLASH_BYPASS_BLOCK_ERASE is not set
+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_WRITE_CHUNK_SIZE=8192
+# CONFIG_SPI_FLASH_SIZE_OVERRIDE is not set
+# CONFIG_SPI_FLASH_CHECK_ERASE_TIMEOUT_DISABLED is not set
+
+#
+# Auto-detect flash chips
+#
+CONFIG_SPI_FLASH_SUPPORT_ISSI_CHIP=y
+CONFIG_SPI_FLASH_SUPPORT_MXIC_CHIP=y
+CONFIG_SPI_FLASH_SUPPORT_GD_CHIP=y
+CONFIG_SPI_FLASH_SUPPORT_WINBOND_CHIP=y
+# end of Auto-detect flash chips
+
+CONFIG_SPI_FLASH_ENABLE_ENCRYPTED_READ_WRITE=y
+# end of SPI Flash driver
+
+#
+# SPIFFS Configuration
+#
+CONFIG_SPIFFS_MAX_PARTITIONS=3
+
+#
+# SPIFFS Cache Configuration
+#
+CONFIG_SPIFFS_CACHE=y
+CONFIG_SPIFFS_CACHE_WR=y
+# CONFIG_SPIFFS_CACHE_STATS is not set
+# end of SPIFFS Cache Configuration
+
+CONFIG_SPIFFS_PAGE_CHECK=y
+CONFIG_SPIFFS_GC_MAX_RUNS=10
+# CONFIG_SPIFFS_GC_STATS is not set
+CONFIG_SPIFFS_PAGE_SIZE=256
+CONFIG_SPIFFS_OBJ_NAME_LEN=32
+# CONFIG_SPIFFS_FOLLOW_SYMLINKS is not set
+CONFIG_SPIFFS_USE_MAGIC=y
+CONFIG_SPIFFS_USE_MAGIC_LENGTH=y
+CONFIG_SPIFFS_META_LENGTH=4
+CONFIG_SPIFFS_USE_MTIME=y
+
+#
+# Debug Configuration
+#
+# CONFIG_SPIFFS_DBG is not set
+# CONFIG_SPIFFS_API_DBG is not set
+# CONFIG_SPIFFS_GC_DBG is not set
+# CONFIG_SPIFFS_CACHE_DBG is not set
+# CONFIG_SPIFFS_CHECK_DBG is not set
+# CONFIG_SPIFFS_TEST_VISUALISATION is not set
+# end of Debug Configuration
+# end of SPIFFS Configuration
+
+#
+# TCP Transport
+#
+CONFIG_WS_BUFFER_SIZE=1024
+# end of TCP Transport
+
+#
+# TinyUSB
+#
+# end of TinyUSB
+
+#
+# Unity unit testing library
+#
+CONFIG_UNITY_ENABLE_FLOAT=y
+CONFIG_UNITY_ENABLE_DOUBLE=y
+# CONFIG_UNITY_ENABLE_COLOR is not set
+CONFIG_UNITY_ENABLE_IDF_TEST_RUNNER=y
+# CONFIG_UNITY_ENABLE_FIXTURE is not set
+# CONFIG_UNITY_ENABLE_BACKTRACE_ON_FAIL is not set
+# end of Unity unit testing library
+
+#
+# Virtual file system
+#
+CONFIG_VFS_SUPPORT_IO=y
+CONFIG_VFS_SUPPORT_DIR=y
+CONFIG_VFS_SUPPORT_SELECT=y
+CONFIG_VFS_SUPPRESS_SELECT_DEBUG_OUTPUT=y
+CONFIG_VFS_SUPPORT_TERMIOS=y
+
+#
+# Host File System I/O (Semihosting)
+#
+CONFIG_VFS_SEMIHOSTFS_MAX_MOUNT_POINTS=1
+CONFIG_VFS_SEMIHOSTFS_HOST_PATH_MAX_LEN=128
+# end of Host File System I/O (Semihosting)
+# end of Virtual file system
+
+#
+# Wear Levelling
+#
+# CONFIG_WL_SECTOR_SIZE_512 is not set
+CONFIG_WL_SECTOR_SIZE_4096=y
+CONFIG_WL_SECTOR_SIZE=4096
+# end of Wear Levelling
+
+#
+# Wi-Fi Provisioning Manager
+#
+CONFIG_WIFI_PROV_SCAN_MAX_ENTRIES=16
+CONFIG_WIFI_PROV_AUTOSTOP_TIMEOUT=30
+# end of Wi-Fi Provisioning Manager
+
+#
+# Supplicant
+#
+CONFIG_WPA_MBEDTLS_CRYPTO=y
+# CONFIG_WPA_WAPI_PSK is not set
+# CONFIG_WPA_DEBUG_PRINT is not set
+# CONFIG_WPA_TESTING_OPTIONS is not set
+# CONFIG_WPA_WPS_WARS is not set
+# CONFIG_WPA_11KV_SUPPORT is not set
+# end of Supplicant
+
+#
+# Camera configuration
+#
+CONFIG_OV7670_SUPPORT=y
+# CONFIG_OV7725_SUPPORT is not set
+CONFIG_NT99141_SUPPORT=y
+CONFIG_OV2640_SUPPORT=y
+CONFIG_OV3660_SUPPORT=y
+CONFIG_OV5640_SUPPORT=y
+# CONFIG_SCCB_HARDWARE_I2C_PORT0 is not set
+CONFIG_SCCB_HARDWARE_I2C_PORT1=y
+CONFIG_CAMERA_CORE0=y
+# CONFIG_CAMERA_CORE1 is not set
+# CONFIG_CAMERA_NO_AFFINITY is not set
+# end of Camera configuration
+# end of Component config
+
+#
+# Compatibility options
+#
+# 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=y
+# CONFIG_COMPILER_OPTIMIZATION_LEVEL_RELEASE is not set
+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 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_CONSOLE_UART_DEFAULT=y
+# CONFIG_CONSOLE_UART_CUSTOM is not set
+# CONFIG_ESP_CONSOLE_UART_NONE is not set
+CONFIG_CONSOLE_UART=y
+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=5
+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_ESP32S2_PANIC_PRINT_HALT is not set
+CONFIG_ESP32S2_PANIC_PRINT_REBOOT=y
+# CONFIG_ESP32S2_PANIC_SILENT_REBOOT is not set
+# CONFIG_ESP32S2_PANIC_GDBSTUB is not set
+CONFIG_TIMER_TASK_STACK_SIZE=3584
+# CONFIG_ESP32_ENABLE_COREDUMP_TO_FLASH is not set
+# CONFIG_ESP32_ENABLE_COREDUMP_TO_UART is not set
+CONFIG_ESP32_ENABLE_COREDUMP_TO_NONE=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=4096
+CONFIG_MB_SERIAL_BUF_SIZE=256
+CONFIG_MB_SERIAL_TASK_PRIO=10
+CONFIG_MB_CONTROLLER_SLAVE_ID_SUPPORT=y
+CONFIG_MB_CONTROLLER_SLAVE_ID=0x00112233
+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_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=12
+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=y
+CONFIG_SUPPORT_TERMIOS=y
+CONFIG_SEMIHOSTFS_MAX_MOUNT_POINTS=1
+CONFIG_SEMIHOSTFS_HOST_PATH_MAX_LEN=128
+# End of deprecated options

+ 2 - 1
code/sdkconfig.old

@@ -138,7 +138,8 @@ CONFIG_COMPILER_OPTIMIZATION_SIZE=y
 CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_ENABLE=y
 # CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_SILENT is not set
 # CONFIG_COMPILER_OPTIMIZATION_ASSERTIONS_DISABLE is not set
-# CONFIG_COMPILER_CXX_EXCEPTIONS is not set
+CONFIG_COMPILER_CXX_EXCEPTIONS=y
+CONFIG_COMPILER_CXX_EXCEPTIONS_EMG_POOL_SIZE=0
 # CONFIG_COMPILER_CXX_RTTI is not set
 CONFIG_COMPILER_STACK_CHECK_MODE_NONE=y
 # CONFIG_COMPILER_STACK_CHECK_MODE_NORM is not set

+ 3 - 3
code/version.cpp

@@ -1,4 +1,4 @@
-const char* GIT_REV="7fcb5d1";
+const char* GIT_REV="f15e5f0";
 const char* GIT_TAG="";
-const char* GIT_BRANCH="master";
-const char* BUILD_TIME="2021-09-12 07:30";
+const char* GIT_BRANCH="rolling";
+const char* BUILD_TIME="2021-09-24 19:25";

BIN
firmware/bootloader.bin


BIN
firmware/firmware.bin


BIN
firmware/html.zip


BIN
sd-card/config/dig1200s1q.tflite


BIN
sd-card/config/dig1300s1q.tflite


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

@@ -1,6 +1,7 @@
 <!DOCTYPE html>
 <html>
 <head>
+<link rel="icon" href="data:,">
 <title>Make Alignment</title>
 <meta charset="utf-8"/>
 	

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

@@ -1,6 +1,7 @@
 <!DOCTYPE html>
 <html>
 <head>
+<link rel="icon" href="data:,">
 <meta charset="utf-8"/>
 <title>Make Analog Alignment</title>
 

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

@@ -1,6 +1,7 @@
 <!DOCTYPE html>
 <html>
 <head>
+<link rel="icon" href="data:,">
 <meta charset="utf-8"/>
 <title>Check</title>
 

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

@@ -1,6 +1,7 @@
 <!DOCTYPE html>
 <html>
 <head>
+<link rel="icon" href="data:,">
 <title>Edit Config</title>
 <meta charset="utf-8">
 

+ 45 - 23
sd-card/html/edit_config_param.html

@@ -1,6 +1,7 @@
 <!DOCTYPE html>
 <html>
 <head>
+<link rel="icon" href="data:,">
 <title>Edit Config</title>
 <meta charset="utf-8">
 
@@ -349,24 +350,6 @@ textarea {
 			<td style="font-size: 80%;"> Time to keep the separated digit images (in days -"0" = forever) </td>
 		</tr>
 
-		<tr class="expert"  id="Analog_ExtendedResolution_ex10">
-			<td width="20px"  style="padding-left: 40px;">
-				<input type="checkbox" id="Analog_ExtendedResolution_enabled" value="1"  onclick = 'InvertEnableItem("Analog", "ExtendedResolution")' unchecked >
-			</td>
-			<td  width="200px">
-				<class id="Analog_ExtendedResolution_text" style="color:black;">ExtendedResolution</class>
-			</td>
-			<td>
-				<select id="Analog_ExtendedResolution_value1">
-					<option value="true" selected>true</option>
-					<option value="false" >false</option>
-				</select>
-			</td>
-			<td style="font-size: 80%;">
-				Enable to use the after point resolution for the last analog counter
-			</td>
-		</tr>
-
 		<tr class="expert"  id="ex10">
 			<td width="20px"  style="padding-left: 40px;"> </td>
 			<td> <class id="Analog_ModelInputSize_text" style="color:black;">ModelInputSize</class> </td>
@@ -502,6 +485,41 @@ textarea {
 				Maximum change of reading from one to the next readout
 			</td>
 		</tr>
+		<tr>
+			<td width="20px"  style="padding-left: 40px;">
+				<input type="checkbox" id="PostProcessing_ExtendedResolution_enabled" value="1"  onclick = 'InvertEnableItem("PostProcessing", "ExtendedResolution")' unchecked >
+			</td>
+			<td  width="200px">
+				<class id="PostProcessing_ExtendedResolution_text" style="color:black;">ExtendedResolution</class>
+			</td>
+			<td>
+				<select id="PostProcessing_ExtendedResolution_value1">
+					<option value="true" >true</option>
+					<option value="false" selected>false</option>
+				</select>
+			</td>
+			<td style="font-size: 80%;">
+				Enable to use the after point resolution for the last analog counter
+			</td>
+		</tr>
+		
+		<tr>
+			<td id="ex121" width="20px"  style="padding-left: 40px;">
+				<input type="checkbox" id="PostProcessing_IgnoreLeadingNaN_enabled" value="1"  onclick = 'InvertEnableItem("PostProcessing", "IgnoreLeadingNaN")' unchecked >
+			</td>
+			<td  width="200px">
+				<class id="PostProcessing_IgnoreLeadingNaN_text" style="color:black;">IgnoreLeadingNaN</class>
+			</td>
+			<td>
+				<select id="PostProcessing_IgnoreLeadingNaN_value1">
+					<option value="true" >true</option>
+					<option value="false" selected>false</option>
+				</select>
+			</td>
+			<td style="font-size: 80%;">
+				Leading "N"'s will be deleted before further processing
+			</td>
+		</tr>
 
 
 
@@ -1028,7 +1046,7 @@ textarea {
 						<option value="output">output</option>
 						<option value="output-pwm" disabled>output pwm (not implemented)</option>
 						<option value="external-flash-pwm" disabled>external flash light pwm controlled (not implemented)</option>
-						<option value="external-flash-ws281x" disabled>external flash light ws281x controlled (not implemented)</option>
+						<option value="external-flash-ws281x">external flash light ws281x controlled (experimental)</option>
 					</select>
 				</td>
 			</td>
@@ -1452,7 +1470,7 @@ function WriteParameter(_param, _category, _cat, _name, _optional, _number = -1)
 		setEnabled(_cat+"_"+_name, false);
 	}
 
-	EnDisableItem(_category[_cat]["enabled"], _param, _category, _cat, _name, _optional);
+	EnDisableItem(_category[_cat]["enabled"], _param, _category, _cat, _name, _optional, _number);
 }
 
 function InvertEnableItem(_cat, _param)
@@ -1619,12 +1637,16 @@ function UpdateInputIndividual()
 	{
 		ReadParameter(param, "PostProcessing", "DecimalShift", true, NUNBERSAkt)		
 		ReadParameter(param, "PostProcessing", "MaxRateValue", true, NUNBERSAkt)		
+		ReadParameter(param, "PostProcessing", "ExtendedResolution", true, NUNBERSAkt)		
+		ReadParameter(param, "PostProcessing", "IgnoreLeadingNaN", true, NUNBERSAkt)		
 	}
 
 	var sel = document.getElementById("Numbers_value1");
 	NUNBERSAkt = sel.selectedIndex;
 	WriteParameter(param, category, "PostProcessing", "DecimalShift", true, NUNBERSAkt);
 	WriteParameter(param, category, "PostProcessing", "MaxRateValue", true, NUNBERSAkt);
+	WriteParameter(param, category, "PostProcessing", "ExtendedResolution", true, NUNBERSAkt);
+	WriteParameter(param, category, "PostProcessing", "IgnoreLeadingNaN", true, NUNBERSAkt);
 }
 
 function UpdateInput() {
@@ -1656,7 +1678,7 @@ function UpdateInput() {
 	WriteParameter(param, category, "Analog", "Model", false);		
 	WriteParameter(param, category, "Analog", "LogImageLocation", true);		
 	WriteParameter(param, category, "Analog", "LogfileRetentionInDays", true);		
-	WriteParameter(param, category, "Analog", "ExtendedResolution", true);		
+//	WriteParameter(param, category, "Analog", "ExtendedResolution", true);		
 	WriteParameter(param, category, "Analog", "ModelInputSize", false);		
 	
 	WriteParameter(param, category, "PostProcessing", "PreValueUse", true);		
@@ -1719,13 +1741,13 @@ function ReadParameterAll()
 	ReadParameter(param, "Analog", "Model", false);		
 	ReadParameter(param, "Analog", "LogImageLocation", true);		
 	ReadParameter(param, "Analog", "LogfileRetentionInDays", true);		
-	ReadParameter(param, "Analog", "ExtendedResolution", true);		
+//	ReadParameter(param, "Analog", "ExtendedResolution", true);		
 	ReadParameter(param, "Analog", "ModelInputSize", false);
 
 	ReadParameter(param, "PostProcessing", "PreValueUse", true);		
 	ReadParameter(param, "PostProcessing", "PreValueAgeStartup", true);		
 	ReadParameter(param, "PostProcessing", "AllowNegativeRates", true);
-	ReadParameter(param, "PostProcessing", "MaxRateValue", true);		
+//	ReadParameter(param, "PostProcessing", "MaxRateValue", true);		
 	ReadParameter(param, "PostProcessing", "ErrorMessage", true);
 	ReadParameter(param, "PostProcessing", "CheckDigitIncreaseConsistency", true);
 

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

@@ -1,6 +1,7 @@
 <!DOCTYPE html>
 <html>
 <head>
+<link rel="icon" href="data:,">
 <meta charset="utf-8"/>
 <title>Make Digital Alignment</title>
 

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

@@ -1,6 +1,7 @@
 <!DOCTYPE html>
 <html style="width: fit-content">
 <head>
+<link rel="icon" href="data:,">
 <title>jomjol - AI on the edge</title>
 <meta charset="utf-8">
 <meta name="viewport" content="width=device-width, initial-scale=1.0">

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

@@ -1,6 +1,7 @@
 <!DOCTYPE html>
 <html style="width: fit-content">
 <head>
+<link rel="icon" href="data:,">
 <title>jomjol - AI on the edge</title>
 <meta charset="utf-8">
 <meta name="viewport" content="width=device-width, initial-scale=1.0">

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

@@ -1,6 +1,7 @@
 <!DOCTYPE html>
 <html>
 <head>
+<link rel="icon" href="data:,">
 <title>Make Reference</title>
 <meta charset="utf-8"/>
 	

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

@@ -1,6 +1,7 @@
 <!DOCTYPE html>
 <html style="width: fit-content">
 <head>
+<link rel="icon" href="data:,">
 <title>jomjol - AI on the edge</title>
 <meta charset="utf-8">
 <meta name="viewport" content="width=device-width, initial-scale=1.0">

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

@@ -1,6 +1,7 @@
 <!DOCTYPE html>
 <html style="width: fit-content">
 <head>
+<link rel="icon" href="data:,">
 <title>jomjol - AI on the edge</title>
 <meta charset="utf-8">
 <meta name="viewport" content="width=device-width, initial-scale=1.0">

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

@@ -1,6 +1,7 @@
 <!DOCTYPE html>
 <html style="width: fit-content">
 <head>
+<link rel="icon" href="data:,">
 <title>jomjol - AI on the edge</title>
 <meta charset="utf-8">
 <meta name="viewport" content="width=device-width, initial-scale=1.0">

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

@@ -1,6 +1,7 @@
 <!DOCTYPE html>
 <html style="width: fit-content">
 <head>
+<link rel="icon" href="data:,">
 <title>jomjol - AI on the edge</title>
 <meta charset="utf-8">
 <meta name="viewport" content="width=device-width, initial-scale=1.0">

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

@@ -1,6 +1,7 @@
 <!DOCTYPE html>
 <html style="width: fit-content">
 <head>
+<link rel="icon" href="data:,">
 <title>jomjol - AI on the edge</title>
 <meta charset="utf-8">
 <meta name="viewport" content="width=device-width, initial-scale=1.0">

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

@@ -1,6 +1,7 @@
 <!DOCTYPE html>
 <html style="width: fit-content">
 <head>
+<link rel="icon" href="data:,">
 <title>jomjol - AI on the edge</title>
 <meta charset="utf-8">
 <meta name="viewport" content="width=device-width, initial-scale=1.0">

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

@@ -1,6 +1,7 @@
 <!DOCTYPE html>
 <html style="width: fit-content">
 <head>
+<link rel="icon" href="data:,">
 <title>jomjol - AI on the edge</title>
 <meta charset="utf-8">
 <meta name="viewport" content="width=device-width, initial-scale=1.0">

+ 57 - 15
sd-card/html/index.html

@@ -1,6 +1,7 @@
 <!DOCTYPE html>
 <html style="width: fit-content">
 <head>
+<link rel="icon" href="data:,">
 <title>jomjol - AI on the edge</title>
 <meta charset="utf-8">
 <meta name="viewport" content="width=device-width, initial-scale=1.0">
@@ -73,28 +74,28 @@ li.dropdown {
 
 <body style="font-family: arial">
 
-<h1>Digitizer - AI on the edge</h1>
+<h1 id="id_title">Digitizer - AI on the edge</h1>
 <h2>An ESP32 all inclusive neural network recognition system for meter digitalization</h2>
 
 <ul>
   <li><a href="#"onclick="document.getElementById('maincontent').src = '/wasserzaehler_roi.html';">Overview</a></li>
-    <li class="dropdown">
-    <a href="javascript:void(0)" class="dropbtn">Configuration</a>
-    <div class="dropdown-content">
-      <a href="#"onclick="document.getElementById('maincontent').src = '/prevalue_set.html';">Set preValue</a>
-      <a href="index_configure.html">Edit Configuration</a>
-    </div>
+	<li class="dropdown">
+	<a href="javascript:void(0)" class="dropbtn">Configuration</a>
+	<div class="dropdown-content">
+	  <a href="#"onclick="document.getElementById('maincontent').src = '/prevalue_set.html';">Set preValue</a>
+	  <a href="index_configure.html">Edit Configuration</a>
+	</div>
   </li>
   <li><a href="#"onclick="document.getElementById('maincontent').src = '/wasserzaehler.html?full';">Recognition</a></li>
   <li><a href="#"onclick="document.getElementById('maincontent').src = '/fileserver/';">File Server</a></li>
-    <li class="dropdown">
-    <a href="javascript:void(0)" class="dropbtn">System</a>
-    <div class="dropdown-content">
-      <a href="#"onclick="document.getElementById('maincontent').src = '/ota_page.html';">OTA Update</a>
-      <a href="#"onclick="document.getElementById('maincontent').src = '/fileserver/log/message/?readonly=true';">Log Viewer</a>      
-      <a href="#"onclick="document.getElementById('maincontent').src = '/reboot_page.html';">Reboot</a>
-      <a href="#"onclick="document.getElementById('maincontent').src = '/info.html';">Info</a>      
-    </div> 
+	<li class="dropdown">
+	<a href="javascript:void(0)" class="dropbtn">System</a>
+	<div class="dropdown-content">
+	  <a href="#"onclick="document.getElementById('maincontent').src = '/ota_page.html';">OTA Update</a>
+	  <a href="#"onclick="document.getElementById('maincontent').src = '/fileserver/log/message/?readonly=true';">Log Viewer</a>      
+	  <a href="#"onclick="document.getElementById('maincontent').src = '/reboot_page.html';">Reboot</a>
+	  <a href="#"onclick="document.getElementById('maincontent').src = '/info.html';">Info</a>      
+	</div> 
 </ul>
 <p>
 
@@ -102,5 +103,46 @@ li.dropdown {
 	 <iframe name="maincontent" id ="maincontent" src="/wasserzaehler_roi.html" title="fileserver" allowfullscreen></iframe> 
 </div>
 
+<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";
+
+
+  function LoadHostname() {
+	_basepath = getbasepath(); 
+
+
+	var xhttp = new XMLHttpRequest();
+	xhttp.addEventListener('load', function(event) {
+	  if (xhttp.status >= 200 && xhttp.status < 300) {
+		hostname = xhttp.responseText;
+		  document.title = "jomjol - AI on the edge - " + hostname;
+		  document.getElementById("id_title").innerHTML  = "Digitizer - AI on the edge - " + hostname;
+	  } else {
+		 console.warn(request.statusText, request.responseText);
+	  }
+	 });
+
+//     var xhttp = new XMLHttpRequest();
+	 try {
+		  url = _basepath + '/version?type=Hostname';     
+		  xhttp.open("GET", url, true);
+		  xhttp.send();
+
+	 }
+	 catch (error)
+	 {
+//               alert("Loading Hostname failed");
+	 }
+  }
+
+  LoadHostname();
+
+</script>
+
 </body>
 </html>

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

@@ -1,6 +1,7 @@
 <!DOCTYPE html>
 <html>
 <head>
+<link rel="icon" href="data:,">
 <title>jomjol - AI on the edge</title>
 <meta charset="utf-8">
 <meta name="viewport" content="width=device-width, initial-scale=1.0">

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

@@ -1,6 +1,7 @@
 <!DOCTYPE html>
 <html>
 <head>
+<link rel="icon" href="data:,">
 <title>OTA Update</title>
 <meta charset="utf-8">
 

+ 3 - 1
sd-card/html/ota_page_v2.html

@@ -1,4 +1,6 @@
-<html><head>
+<html>
+<head>
+<link rel="icon" href="data:,">
 	<title>jomjol - AI on the edge</title>
 	<meta charset="utf-8">
 	<meta name="viewport" content="width=device-width, initial-scale=1">

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

@@ -1,6 +1,7 @@
 <!DOCTYPE html>
 <html>
 <head>
+<link rel="icon" href="data:,">
 <title>Set PreValue</title>
 <meta charset="utf-8">
 	

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

@@ -31,6 +31,7 @@ function ParseConfig() {
      ParamAddValue(param, catname, "ImageQuality");
      ParamAddValue(param, catname, "ImageSize");     
      ParamAddValue(param, catname, "FixedExposure");     
+     ParamAddValue(param, catname, "UseGPIOControlledIllumination");
 
      var catname = "Alignment";
      category[catname] = new Object(); 
@@ -53,7 +54,7 @@ function ParseConfig() {
      ParamAddValue(param, catname, "LogImageLocation");
      ParamAddValue(param, catname, "LogfileRetentionInDays");
      ParamAddValue(param, catname, "ModelInputSize", 2);     
-     ParamAddValue(param, catname, "ExtendedResolution");
+//     ParamAddValue(param, catname, "ExtendedResolution");
 
      var catname = "Analog";
      category[catname] = new Object(); 
@@ -64,7 +65,7 @@ function ParseConfig() {
      ParamAddValue(param, catname, "LogImageLocation");
      ParamAddValue(param, catname, "LogfileRetentionInDays");
      ParamAddValue(param, catname, "ModelInputSize", 2);
-     ParamAddValue(param, catname, "ExtendedResolution");
+//     ParamAddValue(param, catname, "ExtendedResolution");
 
      var catname = "PostProcessing";
      category[catname] = new Object(); 
@@ -76,9 +77,11 @@ function ParseConfig() {
      ParamAddValue(param, catname, "PreValueAgeStartup");
      ParamAddValue(param, catname, "AllowNegativeRates");
      ParamAddValue(param, catname, "MaxRateValue", 1, true);
+     ParamAddValue(param, catname, "ExtendedResolution", 1, true);
+     ParamAddValue(param, catname, "IgnoreLeadingNaN", 1, true);
      ParamAddValue(param, catname, "ErrorMessage");
      ParamAddValue(param, catname, "CheckDigitIncreaseConsistency");     
-     ParamAddValue(param, catname, "IgnoreLeadingNaN");     
+//     ParamAddValue(param, catname, "IgnoreLeadingNaN");     
 
      var catname = "MQTT";
      category[catname] = new Object(); 
@@ -102,6 +105,10 @@ function ParseConfig() {
      ParamAddValue(param, catname, "IO4", 6, false, [null, null, /^[0-9]*$/, null, null, /^[a-zA-Z0-9_-]*$/]);
      ParamAddValue(param, catname, "IO12", 6, false, [null, null, /^[0-9]*$/, null, null, /^[a-zA-Z0-9_-]*$/]);
      ParamAddValue(param, catname, "IO13", 6, false, [null, null, /^[0-9]*$/, null, null, /^[a-zA-Z0-9_-]*$/]);
+     ParamAddValue(param, catname, "LEDType");
+     ParamAddValue(param, catname, "LEDNumbers");
+     ParamAddValue(param, catname, "LEDColor", 3);
+
 
      var catname = "AutoTimer";
      category[catname] = new Object(); 
@@ -673,4 +680,4 @@ function CreateROI(_number, _type, _pos, _roinew, _x, _y, _dx, _dy){
      NUMBERS[_indexnumber][_type].splice(_pos+1, 0, _ret);
 
      return "";
-}
+}

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

@@ -1,6 +1,7 @@
 <!DOCTYPE html>
 <html>
 <head>
+<link rel="icon" href="data:,">
 <title>Reboot</title>
 <meta charset="utf-8">
 

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

@@ -1,6 +1,7 @@
 <!DOCTYPE html>
 <html style="width: fit-content">
 <head>
+<link rel="icon" href="data:,">
 <title>jomjol - AI on the edge</title>
 <meta charset="utf-8">
 <meta name="viewport" content="width=device-width, initial-scale=1.0">

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

@@ -1,6 +1,7 @@
 <!DOCTYPE html>
 <html>
 <head>
+<link rel="icon" href="data:,">
 <meta charset="utf-8">
 </head>
 

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

@@ -1 +1 @@
-9.7.1
+10.1.0

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

@@ -1,6 +1,7 @@
 <!DOCTYPE html>
 <html>
 <head>
+<link rel="icon" href="data:,">
 <title>Overview</title>
 <meta charset="utf-8">