Sfoglia il codice sorgente

Merge branch 'rolling' of https://github.com/jomjol/AI-on-the-edge-device into rolling

jomjol 4 anni fa
parent
commit
a688a69af6
50 ha cambiato i file con 1891 aggiunte e 326 eliminazioni
  1. 18 2
      README.md
  2. 3 3
      code/.helper/copy.bat
  3. 1 1
      code/.helper/makezip.bat
  4. 1 1
      code/components/esp32-camera-master/examples/take_picture.c
  5. 7 0
      code/components/jomjol_configfile/CMakeLists.txt
  6. 96 0
      code/components/jomjol_configfile/configFile.cpp
  7. 16 0
      code/components/jomjol_configfile/configFile.h
  8. 2 2
      code/components/jomjol_controlGPIO/CMakeLists.txt
  9. 513 62
      code/components/jomjol_controlGPIO/server_GPIO.cpp
  10. 91 2
      code/components/jomjol_controlGPIO/server_GPIO.h
  11. 1 1
      code/components/jomjol_controlcamera/CMakeLists.txt
  12. 18 13
      code/components/jomjol_controlcamera/ClassControllCamera.cpp
  13. 0 3
      code/components/jomjol_controlcamera/ClassControllCamera.h
  14. 5 2
      code/components/jomjol_controlcamera/server_camera.cpp
  15. 0 2
      code/components/jomjol_controlcamera/server_camera.h
  16. 2 2
      code/components/jomjol_fileserver_ota/CMakeLists.txt
  17. 55 45
      code/components/jomjol_fileserver_ota/server_file.cpp
  18. 13 9
      code/components/jomjol_fileserver_ota/server_ota.cpp
  19. 0 2
      code/components/jomjol_fileserver_ota/server_ota.h
  20. 5 1
      code/components/jomjol_flowcontroll/ClassFlowAnalog.cpp
  21. 13 3
      code/components/jomjol_flowcontroll/ClassFlowControll.cpp
  22. 6 1
      code/components/jomjol_flowcontroll/ClassFlowDigit.cpp
  23. 16 3
      code/components/jomjol_flowcontroll/ClassFlowMQTT.cpp
  24. 1 1
      code/components/jomjol_flowcontroll/ClassFlowMQTT.h
  25. 10 1
      code/components/jomjol_helper/Helper.cpp
  26. 2 1
      code/components/jomjol_helper/Helper.h
  27. 1 1
      code/components/jomjol_logfile/ClassLogFile.cpp
  28. 127 14
      code/components/jomjol_mqtt/interface_mqtt.cpp
  29. 17 1
      code/components/jomjol_mqtt/interface_mqtt.h
  30. 8 2
      code/components/jomjol_tfliteclass/CTfLiteClass.cpp
  31. 1 1
      code/components/jomjol_tfliteclass/CTfLiteClass.h
  32. 21 14
      code/components/jomjol_tfliteclass/server_tflite.cpp
  33. 0 2
      code/components/jomjol_tfliteclass/server_tflite.h
  34. 14 0
      code/components/jomjol_time_sntp/time_sntp.cpp
  35. 4 1
      code/components/jomjol_time_sntp/time_sntp.h
  36. 6 0
      code/include/defines.h
  37. 15 16
      code/main/main.cpp
  38. 12 11
      code/main/server_main.cpp
  39. 3 4
      code/main/server_main.h
  40. 2 2
      code/main/version.cpp
  41. 1 1
      code/main/version.h
  42. 3 1
      code/platformio.ini
  43. 2 2
      code/version.cpp
  44. BIN
      firmware/bootloader.bin
  45. BIN
      firmware/firmware.bin
  46. BIN
      firmware/html.zip
  47. 9 0
      sd-card/config/config.ini
  48. 722 78
      sd-card/html/edit_config_param.html
  49. 3 3
      sd-card/html/gethost.js
  50. 25 9
      sd-card/html/readconfigparam.js

+ 18 - 2
README.md

@@ -45,7 +45,23 @@ In other cases you can contact the developer via email: <img src="https://raw.gi
 
 **General remark:** Beside the `firmware.bin`, typically also the content of `/html` needs to be updated!
 
-
+##### Rolling - (2021-07-11)
+
+* GPIO: implements basic functionality for GPIO handler.
+  - Configuration via config.ini / HTML page
+  - GPIO 12, 13, 1, 3, 0, 4 can be used (see restrictions in HTML configuration page)  
+  - GPIO can be used as input or output
+  - pullup / pulldown can be enabled
+  - supports all interrupt types of the ESP32
+  - publishing via MQTT or HTTP
+  - definition of the MQTT topic name
+* HTML: implements regex mask for text input fields (currently enabled for GPIO inputs and main topic)
+* HTML: automatic detection of select fields
+* MQTT: added readings for uptime and freeMem (can be used for tracking with Infux DB and as memory leak detection)
+* MQTT: connection is no longer terminated and reestablished on each flow
+* Classe ConfigFile created. Can be used by all components in the future.
+* Bugfix: memory leaks in ClassFlowAnalog and ClassFlowControll fixed.
+* Removed compiler warnings 
 
 ##### Rolling - (2021-07-08)
 
@@ -157,4 +173,4 @@ There are some ideas and feature request, which are not followed currently - mai
 
 ## Solved topics
 
-* n.a.
+* n.a.

+ 3 - 3
code/.helper/copy.bat

@@ -1,3 +1,3 @@
-copy "C:\Users\Muell\Documents\Programmieren\GitHub\AI-on-the-edge-device\code\.pio\build\esp32cam\firmware.bin" "C:\Users\Muell\Documents\Programmieren\GitHub\AI-on-the-edge-device\firmware\firmware.bin"
-copy "C:\Users\Muell\Documents\Programmieren\GitHub\AI-on-the-edge-device\code\.pio\build\esp32cam\bootloader.bin" "C:\Users\Muell\Documents\Programmieren\GitHub\AI-on-the-edge-device\firmware\bootloader.bin"
-copy "C:\Users\Muell\Documents\Programmieren\GitHub\AI-on-the-edge-device\code\.pio\build\esp32cam\partitions.bin" "C:\Users\Muell\Documents\Programmieren\GitHub\AI-on-the-edge-device\firmware\partitions.bin"
+copy "..\..\code\.pio\build\esp32cam\firmware.bin" "..\..\firmware\firmware.bin"
+copy "..\..\code\.pio\build\esp32cam\bootloader.bin" "..\..\firmware\bootloader.bin"
+copy "..\..\code\.pio\build\esp32cam\partitions.bin" "..\..\firmware\partitions.bin"

+ 1 - 1
code/.helper/makezip.bat

@@ -1 +1 @@
-powershell Compress-Archive "C:\Users\Muell\Documents\Programmieren\GitHub\AI-on-the-edge-device\sd-card\html\*.*" "C:\Users\Muell\Documents\Programmieren\GitHub\AI-on-the-edge-device\firmware\html.zip"
+powershell Compress-Archive "..\..\sd-card\html\*.*" "..\..\firmware\html.zip"

+ 1 - 1
code/components/esp32-camera-master/examples/take_picture.c

@@ -29,7 +29,7 @@
 
 // ================================ CODE ======================================
 
-#include <esp_event_loop.h>
+#include <esp_event.h>
 #include <esp_log.h>
 #include <esp_system.h>
 #include <nvs_flash.h>

+ 7 - 0
code/components/jomjol_configfile/CMakeLists.txt

@@ -0,0 +1,7 @@
+FILE(GLOB_RECURSE app_sources ${CMAKE_CURRENT_SOURCE_DIR}/*.*)
+
+idf_component_register(SRCS ${app_sources}
+                    INCLUDE_DIRS "."
+                    REQUIRES jomjol_logfile)
+
+

+ 96 - 0
code/components/jomjol_configfile/configFile.cpp

@@ -0,0 +1,96 @@
+#include <string.h>
+#include "freertos/FreeRTOS.h"
+#include "freertos/task.h"
+
+#include "Helper.h"
+#include "configFile.h"
+
+//static const char *TAGCONFIGFILE = "configFile";
+
+ConfigFile::ConfigFile(std::string filePath)
+{
+    std::string config = FormatFileName(filePath);
+    pFile = OpenFileAndWait(config.c_str(), "r");
+}
+
+ConfigFile::~ConfigFile()
+{
+    fclose(pFile);
+}
+
+bool ConfigFile::isNewParagraph(std::string input)
+{
+	if ((input[0] == '[') || ((input[0] == ';') && (input[1] == '[')))
+	{
+		return true;
+	}
+	return false;
+}
+
+bool ConfigFile::GetNextParagraph(std::string& aktparamgraph, bool &disabled, bool &eof)
+{
+	while (getNextLine(&aktparamgraph, disabled, eof) && !isNewParagraph(aktparamgraph));
+
+	if (isNewParagraph(aktparamgraph))
+		return true;
+	return false;
+}
+
+bool ConfigFile::getNextLine(std::string *rt, bool &disabled, bool &eof)
+{
+    eof = false;
+	char zw[1024];
+	if (pFile == NULL)
+	{
+		*rt = "";
+		return false;
+	}
+	fgets(zw, 1024, pFile);
+	printf("%s", zw);
+	if ((strlen(zw) == 0) && feof(pFile))
+	{
+		*rt = "";
+        eof = true;
+		return false;
+	}
+	*rt = zw;
+	*rt = trim(*rt);
+	while ((zw[0] == ';' || zw[0] == '#' || (rt->size() == 0)) && !(zw[1] == '['))			// Kommentarzeilen (; oder #) und Leerzeilen überspringen, es sei denn es ist ein neuer auskommentierter Paragraph
+	{
+		fgets(zw, 1024, pFile);
+		printf("%s", zw);		
+		if (feof(pFile))
+		{
+			*rt = "";
+            eof = true;
+			return false;
+		}
+		*rt = zw;
+		*rt = trim(*rt);
+	}
+
+    disabled = ((*rt)[0] == ';');
+	return true;
+}
+
+std::vector<string> ConfigFile::ZerlegeZeile(std::string input, std::string delimiter)
+{
+	std::vector<string> Output;
+//	std::string delimiter = " =,";
+
+	input = trim(input, delimiter);
+	size_t pos = findDelimiterPos(input, delimiter);
+	std::string token;
+	while (pos != std::string::npos) {
+		token = input.substr(0, pos);
+		token = trim(token, delimiter);
+		Output.push_back(token);
+		input.erase(0, pos + 1);
+		input = trim(input, delimiter);
+		pos = findDelimiterPos(input, delimiter);
+	}
+	Output.push_back(input);
+
+	return Output;
+
+}

+ 16 - 0
code/components/jomjol_configfile/configFile.h

@@ -0,0 +1,16 @@
+#include <string>
+#include <vector>
+
+class ConfigFile {
+public:
+    ConfigFile(std::string filePath);
+    ~ConfigFile();
+
+    bool isNewParagraph(std::string input);
+    bool GetNextParagraph(std::string& aktparamgraph, bool &disabled, bool &eof);
+	bool getNextLine(std::string* rt, bool &disabled, bool &eof);
+    std::vector<std::string> ZerlegeZeile(std::string input, std::string delimiter = " =, \t");
+    
+private:
+    FILE* pFile;
+};

+ 2 - 2
code/components/jomjol_controlGPIO/CMakeLists.txt

@@ -3,7 +3,7 @@ FILE(GLOB_RECURSE app_sources ${CMAKE_CURRENT_SOURCE_DIR}/*.*)
 list(APPEND EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common)
 
 idf_component_register(SRCS ${app_sources}
-                    INCLUDE_DIRS "."
-                    REQUIRES esp_http_server jomjol_logfile)
+                    INCLUDE_DIRS "." "../../include"
+                    REQUIRES esp_http_server jomjol_logfile jomjol_configfile jomjol_mqtt jomjol_flowcontroll)
 
 

+ 513 - 62
code/components/jomjol_controlGPIO/server_GPIO.cpp

@@ -1,4 +1,5 @@
 #include <string>
+#include <functional>
 #include "string.h"
 
 #include <string.h>
@@ -6,22 +7,384 @@
 #include "freertos/task.h"
 #include "esp_system.h"
 #include "esp_event.h"
+
+//#define LOG_LOCAL_LEVEL ESP_LOG_DEBUG
 #include "esp_log.h"
-#include "driver/gpio.h"
 //#include "errno.h"
 
 #include <sys/stat.h>
+#include <vector>
+//#include <regex>
+
+#include "defines.h"
 
 #include "server_GPIO.h"
 
 #include "ClassLogFile.h"
-
+#include "configFile.h"
 #include "Helper.h"
+#include "interface_mqtt.h"
+
+static const char *TAG_SERVERGPIO = "server_GPIO";
+QueueHandle_t gpio_queue_handle = NULL;
+
+#define DEBUG_DETAIL_ON 
+
+GpioPin::GpioPin(gpio_num_t gpio, const char* name, gpio_pin_mode_t mode, gpio_int_type_t interruptType, uint8_t dutyResolution, std::string mqttTopic, bool httpEnable) 
+{
+    _gpio = gpio;
+    _name = name; 
+    _mode = mode;
+    _interruptType = interruptType;    
+    _mqttTopic = mqttTopic;
+}
+
+GpioPin::~GpioPin()
+{
+    ESP_LOGD(TAG_SERVERGPIO,"reset GPIO pin %d", _gpio);
+    if (_interruptType != GPIO_INTR_DISABLE) {
+        //hook isr handler for specific gpio pin
+        gpio_isr_handler_remove(_gpio);
+    }
+    gpio_reset_pin(_gpio);
+}
+
+static void IRAM_ATTR gpio_isr_handler(void* arg)
+{
+    GpioResult gpioResult;
+    gpioResult.gpio = *(gpio_num_t*) arg;
+    gpioResult.value = gpio_get_level(gpioResult.gpio);
+    BaseType_t ContextSwitchRequest = pdFALSE;
+ 
+    xQueueSendToBackFromISR(gpio_queue_handle,(void*)&gpioResult,&ContextSwitchRequest);
+   
+    if(ContextSwitchRequest){
+        taskYIELD();
+    }
+}
+
+static void gpioHandlerTask(void *arg) {
+    ESP_LOGD(TAG_SERVERGPIO,"start interrupt task");
+    while(1){
+        if(uxQueueMessagesWaiting(gpio_queue_handle)){
+            while(uxQueueMessagesWaiting(gpio_queue_handle)){
+                GpioResult gpioResult;
+                xQueueReceive(gpio_queue_handle,(void*)&gpioResult,10);
+                ESP_LOGD(TAG_SERVERGPIO,"gpio: %d state: %d", gpioResult.gpio, gpioResult.value);
+                ((GpioHandler*)arg)->gpioInterrupt(&gpioResult);
+            }  
+        }
+
+        ((GpioHandler*)arg)->taskHandler();
+        vTaskDelay(pdMS_TO_TICKS(1000));
+    }
+}
+
+void GpioPin::gpioInterrupt(int value) {
+    if (_mqttTopic != "") {
+        ESP_LOGD(TAG_SERVERGPIO, "gpioInterrupt %s %d", _mqttTopic.c_str(), value);
+
+        MQTTPublish(_mqttTopic, value ? "true" : "false");
+        currentState = value;
+    }
+}
+
+void GpioPin::init()
+{
+    gpio_config_t io_conf;
+    //set interrupt
+    io_conf.intr_type = _interruptType;
+    //set as output mode
+    io_conf.mode = (_mode == GPIO_PIN_MODE_OUTPUT) || (_mode == GPIO_PIN_MODE_BUILT_IN_FLASH_LED) ? gpio_mode_t::GPIO_MODE_OUTPUT : gpio_mode_t::GPIO_MODE_INPUT;
+    //bit mask of the pins that you want to set,e.g.GPIO18/19
+    io_conf.pin_bit_mask = (1ULL << _gpio);
+    //set pull-down mode
+    io_conf.pull_down_en = _mode == GPIO_PIN_MODE_INPUT_PULLDOWN ? gpio_pulldown_t::GPIO_PULLDOWN_ENABLE : gpio_pulldown_t::GPIO_PULLDOWN_DISABLE;
+    //set pull-up mode
+    io_conf.pull_up_en = _mode == GPIO_PIN_MODE_INPUT_PULLDOWN ? gpio_pullup_t::GPIO_PULLUP_ENABLE : gpio_pullup_t::GPIO_PULLUP_DISABLE;
+    //configure GPIO with the given settings
+    gpio_config(&io_conf);
+
+    if (_interruptType != GPIO_INTR_DISABLE) {
+        //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);
+    }
+
+    if ((_mqttTopic != "") && ((_mode == GPIO_PIN_MODE_OUTPUT) || (_mode == GPIO_PIN_MODE_OUTPUT_PWM) || (_mode == GPIO_PIN_MODE_BUILT_IN_FLASH_LED))) {
+        std::function<bool(std::string, char*, int)> f = std::bind(&GpioPin::handleMQTT, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
+        MQTTregisterSubscribeFunction(_mqttTopic, f);
+    }
+}
+
+bool GpioPin::getValue(std::string* errorText)
+{   
+    if ((_mode != GPIO_PIN_MODE_INPUT) && (_mode != GPIO_PIN_MODE_INPUT_PULLUP) && (_mode != GPIO_PIN_MODE_INPUT_PULLDOWN)) {
+        (*errorText) = "GPIO is not in input mode";
+    }
+
+    return gpio_get_level(_gpio) == 1;
+}
+
+void GpioPin::setValue(bool value, gpio_set_source setSource, std::string* errorText)
+{
+    ESP_LOGD(TAG_SERVERGPIO, "GpioPin::setValue %d\r\n", value);
+
+    if ((_mode != GPIO_PIN_MODE_OUTPUT) && (_mode != GPIO_PIN_MODE_OUTPUT_PWM) && (_mode != GPIO_PIN_MODE_BUILT_IN_FLASH_LED)) {
+        (*errorText) = "GPIO is not in output mode";
+    } else {
+        gpio_set_level(_gpio, value);
+
+        if ((_mqttTopic != "") && (setSource != GPIO_SET_SOURCE_MQTT)) {
+            MQTTPublish(_mqttTopic, value ? "true" : "false");
+        }
+    }
+}
+
+void GpioPin::publishState() {
+    int newState = gpio_get_level(_gpio);
+    if (newState != currentState) {
+        ESP_LOGD(TAG_SERVERGPIO,"publish state of GPIO %d new state %d", _gpio, newState);
+        MQTTPublish(_mqttTopic, newState ? "true" : "false");
+        currentState = newState;
+    }
+}
+
+bool GpioPin::handleMQTT(std::string, char* data, int data_len) {
+    ESP_LOGD(TAG_SERVERGPIO, "GpioPin::handleMQTT data %.*s\r\n", data_len, data);
+
+    std::string dataStr(data, data_len);
+    dataStr = toLower(dataStr);
+    std::string errorText = "";
+    if ((dataStr == "true") || (dataStr == "1")) {
+        setValue(true, GPIO_SET_SOURCE_MQTT, &errorText);
+    } else if ((dataStr == "false") || (dataStr == "0")) {
+        setValue(false, GPIO_SET_SOURCE_MQTT, &errorText);    
+    } else {
+        errorText = "wrong value ";
+        errorText.append(data, data_len);
+    }
+
+    if (errorText != "") {
+        ESP_LOGE(TAG_SERVERGPIO, "%s", errorText.c_str());
+    }
+
+    return (errorText == "");
+}
+
+
+esp_err_t callHandleHttpRequest(httpd_req_t *req)
+{
+    ESP_LOGD(TAG_SERVERGPIO,"callHandleHttpRequest");
+
+    GpioHandler *gpioHandler = (GpioHandler*)req->user_ctx;
+    return gpioHandler->handleHttpRequest(req);
+}
+
+void taskGpioHandler(void *pvParameter)
+{
+    ESP_LOGD(TAG_SERVERGPIO,"taskGpioHandler");
+    ((GpioHandler*)pvParameter)->init();
+}
+
+GpioHandler::GpioHandler(std::string configFile, httpd_handle_t httpServer) 
+{
+    ESP_LOGI(TAG_SERVERGPIO,"start GpioHandler");
+    _configFile = configFile;
+    _httpServer = httpServer;
+
+    ESP_LOGI(TAG_SERVERGPIO, "register GPIO Uri");
+    registerGpioUri();
+}
+
+GpioHandler::~GpioHandler()  {
+    if (gpioMap != NULL) {
+        clear();
+        delete gpioMap;
+    }
+}
+
+void GpioHandler::init()
+{
+    // TickType_t xDelay = 60000 / portTICK_PERIOD_MS;
+    // printf("wait before start %ldms\r\n", (long) xDelay);
+    // vTaskDelay( xDelay );
+
+    if (gpioMap == NULL) {
+        gpioMap = new std::map<gpio_num_t, GpioPin*>();
+    } else {
+        clear();
+    }
+    
+    ESP_LOGI(TAG_SERVERGPIO, "read GPIO config and init GPIO");
+    if (!readConfig()) {
+        clear();
+        delete gpioMap;
+        gpioMap = NULL;
+        ESP_LOGI(TAG_SERVERGPIO, "GPIO init comleted, handler is disabled");
+        return;
+    }
+
+    for(std::map<gpio_num_t, GpioPin*>::iterator it = gpioMap->begin(); it != gpioMap->end(); ++it) {
+        it->second->init();
+    }
+
+    std::function<void()> f = std::bind(&GpioHandler::handleMQTTconnect, this);
+    MQTTregisterConnectFunction("gpio-handler", f);
+
+    if (xHandleTaskGpio == NULL) {
+        gpio_queue_handle = xQueueCreate(10,sizeof(GpioResult));
+        BaseType_t  xReturned = xTaskCreate(&gpioHandlerTask, "gpio_int", configMINIMAL_STACK_SIZE * 8, (void *)this, tskIDLE_PRIORITY + 2, &xHandleTaskGpio);
+        if(xReturned == pdPASS ) {
+            ESP_LOGD(TAG_SERVERGPIO, "xHandletaskGpioHandler started");
+        } else {
+            ESP_LOGD(TAG_SERVERGPIO, "xHandletaskGpioHandler not started %d ", (int)xHandleTaskGpio);
+        }
+    }
+
+    ESP_LOGI(TAG_SERVERGPIO, "GPIO init comleted, is enabled");
+}
+
+void GpioHandler::taskHandler() {
+    if (gpioMap != NULL) {
+        for(std::map<gpio_num_t, GpioPin*>::iterator it = gpioMap->begin(); it != gpioMap->end(); ++it) {
+            if ((it->second->getInterruptType() == GPIO_INTR_DISABLE))
+                it->second->publishState();
+        }
+    }
+}
+
+
+void GpioHandler::handleMQTTconnect()
+{
+    if (gpioMap != NULL) {
+        for(std::map<gpio_num_t, GpioPin*>::iterator it = gpioMap->begin(); it != gpioMap->end(); ++it) {
+            if ((it->second->getMode() == GPIO_PIN_MODE_INPUT) || (it->second->getMode() == GPIO_PIN_MODE_INPUT_PULLDOWN) || (it->second->getMode() == GPIO_PIN_MODE_INPUT_PULLUP))
+                it->second->publishState();
+        }
+    }
+}
+
+void GpioHandler::deinit() {
+    MQTTunregisterConnectFunction("gpio-handler");
+    clear();
+    if (xHandleTaskGpio != NULL) {
+        vTaskDelete(xHandleTaskGpio);
+        xHandleTaskGpio = NULL;
+    }
+}
+
+void GpioHandler::gpioInterrupt(GpioResult* gpioResult) {
+    if ((gpioMap != NULL) && (gpioMap->find(gpioResult->gpio) != gpioMap->end())) {
+        (*gpioMap)[gpioResult->gpio]->gpioInterrupt(gpioResult->value);
+    }
+}
+
+bool GpioHandler::readConfig() 
+{
+    if (!gpioMap->empty())
+        clear();
+
+    ConfigFile configFile = ConfigFile(_configFile); 
+
+    std::vector<std::string> zerlegt;
+    std::string line = "";
+    bool disabledLine = false;
+    bool eof = false;
+        
+    while ((!configFile.GetNextParagraph(line, disabledLine, eof) || (line.compare("[GPIO]") != 0)) && !disabledLine && !eof) {}
+    if (eof)
+        return false;
+    
+    _isEnabled = !disabledLine;
+
+    if (!_isEnabled)
+        return false;
+
+    std::string mainTopicMQTT = "";
+    bool registerISR = false;
+    while (configFile.getNextLine(&line, disabledLine, eof) && !configFile.isNewParagraph(line))
+    {
+        zerlegt = configFile.ZerlegeZeile(line);
+        // const std::regex pieces_regex("IO([0-9]{1,2})");
+        // std::smatch pieces_match;
+        // if (std::regex_match(zerlegt[0], pieces_match, pieces_regex) && (pieces_match.size() == 2))
+        // {
+        //     std::string gpioStr = pieces_match[1];
+        ESP_LOGD(TAG_SERVERGPIO, "conf param %s\r\n", toUpper(zerlegt[0]).c_str());
+        if (toUpper(zerlegt[0]) == "MAINTOPICMQTT") {
+            ESP_LOGD(TAG_SERVERGPIO, "MAINTOPICMQTT found\r\n");
+            mainTopicMQTT = zerlegt[1];
+        } else if ((zerlegt[0].rfind("IO", 0) == 0) && (zerlegt.size() >= 6))
+        {
+            ESP_LOGI(TAG_SERVERGPIO,"Enable GP%s in %s mode", zerlegt[0].c_str(), zerlegt[1].c_str());
+            std::string gpioStr = zerlegt[0].substr(2, 2);
+            gpio_num_t gpioNr = (gpio_num_t)atoi(gpioStr.c_str());
+            gpio_pin_mode_t pinMode = resolvePinMode(toLower(zerlegt[1]));
+            gpio_int_type_t intType = resolveIntType(toLower(zerlegt[2]));
+            uint16_t dutyResolution = (uint8_t)atoi(zerlegt[3].c_str());
+            bool mqttEnabled = toLower(zerlegt[4]) == "true";
+            bool httpEnabled = toLower(zerlegt[5]) == "true";
+            char gpioName[100];
+            if (zerlegt.size() >= 7) {
+                strcpy(gpioName, trim(zerlegt[6]).c_str());
+            } else {
+                sprintf(gpioName, "GPIO%d", gpioNr);
+            }
+            std::string mqttTopic = mqttEnabled ? (mainTopicMQTT + "/" + gpioName) : "";
+            GpioPin* gpioPin = new GpioPin(gpioNr, gpioName, pinMode, intType,dutyResolution, mqttTopic, httpEnabled);
+            (*gpioMap)[gpioNr] = gpioPin;
+
+            if (intType != GPIO_INTR_DISABLE) {
+                registerISR = true;
+            }
+        }
+    }
+
+    if (registerISR) {
+        //install gpio isr service
+        gpio_install_isr_service(ESP_INTR_FLAG_LOWMED | ESP_INTR_FLAG_IRAM);
+    }
+
+    return true;
+}
 
-// #define DEBUG_DETAIL_ON 
+void GpioHandler::clear() 
+{
+    ESP_LOGD(TAG_SERVERGPIO, "GpioHandler::clear\r\n");
+
+    if (gpioMap != NULL) {
+        for(std::map<gpio_num_t, GpioPin*>::iterator it = gpioMap->begin(); it != gpioMap->end(); ++it) {
+            delete it->second;
+        }
+        gpioMap->clear();
+    }
+
+    // gpio_uninstall_isr_service(); can't uninstall, isr service is used by camera
+}
+ 
+void GpioHandler::registerGpioUri() 
+{
+    ESP_LOGI(TAG_SERVERGPIO, "server_GPIO - Registering URI handlers");
+    
+    httpd_uri_t camuri = { };
+    camuri.method    = HTTP_GET;
+    camuri.uri       = "/GPIO";
+    camuri.handler   = callHandleHttpRequest;
+    camuri.user_ctx  = (void*)this;    
+    httpd_register_uri_handler(_httpServer, &camuri);
+}
 
-esp_err_t handler_switch_GPIO(httpd_req_t *req)
+esp_err_t GpioHandler::handleHttpRequest(httpd_req_t *req)
 {
+    ESP_LOGD(TAG_SERVERGPIO, "handleHttpRequest");
+
+    if (gpioMap == NULL) {
+        std::string resp_str = "GPIO handler not initialized";
+        httpd_resp_send(req, resp_str.c_str(), resp_str.length());    
+        return ESP_OK;
+    }
+
 #ifdef DEBUG_DETAIL_ON 
     LogFile.WriteHeapInfo("handler_switch_GPIO - Start");    
 #endif
@@ -30,95 +393,183 @@ esp_err_t handler_switch_GPIO(httpd_req_t *req)
     char _query[200];
     char _valueGPIO[30];    
     char _valueStatus[30];    
-    std::string gpio, status, zw;
-    int gpionum = 0;
-    gpio_num_t gpio_num;
+    std::string gpio, status;
 
-    if (httpd_req_get_url_query_str(req, _query, 200) == ESP_OK)
-    {
-        printf("Query: "); printf(_query); printf("\n");
+    if (httpd_req_get_url_query_str(req, _query, 200) == ESP_OK) {
+        ESP_LOGD(TAG_SERVERGPIO, "Query: %s", _query);
         
         if (httpd_query_key_value(_query, "GPIO", _valueGPIO, 30) == ESP_OK)
         {
-            printf("GPIO is found"); printf(_valueGPIO); printf("\n"); 
+            ESP_LOGD(TAG_SERVERGPIO, "GPIO is found %s", _valueGPIO); 
             gpio = std::string(_valueGPIO);
+        } else {
+            std::string resp_str = "GPIO No is not defined";
+            httpd_resp_send(req, resp_str.c_str(), resp_str.length());    
+            return ESP_OK;
         }
         if (httpd_query_key_value(_query, "Status", _valueStatus, 30) == ESP_OK)
         {
-            printf("Status is found"); printf(_valueStatus); printf("\n"); 
+            ESP_LOGD(TAG_SERVERGPIO, "Status is found %s", _valueStatus); 
             status = std::string(_valueStatus);
         }
-    };
+    } else {
+        const char* resp_str = "Error in call. Use /GPIO?GPIO=12&Status=high";
+        httpd_resp_send(req, resp_str, strlen(resp_str));    
+        return ESP_OK;
+    }
 
     status = toUpper(status);
-    if (!(status == "HIGH") && !(status == "LOW"))
+    if ((status != "HIGH") && (status != "LOW") && (status != "TRUE") && (status != "FALSE") && (status != "0") && (status != "1") && (status != ""))
     {
-        zw = "Status not valid: " + status;;
+        std::string zw = "Status not valid: " + status;
         httpd_resp_sendstr_chunk(req, zw.c_str());
         httpd_resp_sendstr_chunk(req, NULL);          
         return ESP_OK;    
     }
 
-    gpionum = stoi(gpio);
-    
-    // frei: 16; 12-15; 2; 4  // nur 12 und 13 funktionieren 2: reboot, 4: BlitzLED, 14/15: DMA für SDKarte ???
+    int gpionum = stoi(gpio);
 
-    switch (gpionum) {
-        case 12:
-            gpio_num = GPIO_NUM_12;
-            break;
-        case 13:
-            gpio_num = GPIO_NUM_13;
-            break;
-        default:
-            zw = "GPIO" + std::to_string(gpionum) + " not support - only 12 & 13 free";
+    // frei: 16; 12-15; 2; 4  // nur 12 und 13 funktionieren 2: reboot, 4: BlitzLED, 15: PSRAM, 14/15: DMA für SDKarte ???
+    gpio_num_t gpio_num = resolvePinNr(gpionum);
+    if (gpio_num == GPIO_NUM_NC)
+    {
+        std::string zw = "GPIO" + std::to_string(gpionum) + " not support - only 12 & 13 free";
             httpd_resp_sendstr_chunk(req, zw.c_str());
             httpd_resp_sendstr_chunk(req, NULL);          
-            return ESP_OK;    
+            return ESP_OK;
     }
 
-    if (status == "HIGH")  
-        gpio_set_level(gpio_num, 1);
+    if (gpioMap->count(gpio_num) == 0) {
+        char resp_str [30];
+        sprintf(resp_str, "GPIO%d is not registred", gpio_num);
+        httpd_resp_send(req, resp_str, strlen(resp_str));  
+        return ESP_OK;     
+    }
+    
+    if (status == "") 
+    {
+        std::string resp_str = "";
+        status = (*gpioMap)[gpio_num]->getValue(&resp_str) ? "HIGH" : "LOW";
+        if (resp_str == "") {
+            resp_str = status;
+        }
+        httpd_resp_sendstr_chunk(req, resp_str.c_str());
+        httpd_resp_sendstr_chunk(req, NULL);
+    }
     else
-        gpio_set_level(gpio_num, 0); 
-
-
-    zw = "GPIO" + std::to_string(gpionum) + " switched to " + status;
-    httpd_resp_sendstr_chunk(req, zw.c_str());
-    httpd_resp_sendstr_chunk(req, NULL);          
+    {
+        std::string resp_str = "";
+        (*gpioMap)[gpio_num]->setValue((status == "HIGH") || (status == "TRUE") || (status == "1"), GPIO_SET_SOURCE_HTTP, &resp_str);
+        if (resp_str == "") {
+            resp_str = "GPIO" + std::to_string(gpionum) + " switched to " + status;
+        }
+        httpd_resp_sendstr_chunk(req, resp_str.c_str());
+        httpd_resp_sendstr_chunk(req, NULL);
+    }
+          
     return ESP_OK;    
 };
 
-void initGPIO()
+void GpioHandler::flashLightEnable(bool value) 
 {
-    gpio_config_t io_conf;
-    //disable interrupt
-    io_conf.intr_type = GPIO_INTR_DISABLE;
-    //set as output mode
-    io_conf.mode = GPIO_MODE_OUTPUT;
-    //bit mask of the pins that you want to set,e.g.GPIO18/19
-//    io_conf.pin_bit_mask = ((1ULL<<GPIO_OUTPUT_IO_0) | (1ULL<<GPIO_OUTPUT_IO_1));
-//    io_conf.pin_bit_mask = ((1ULL << GPIO_NUM_12) | (1ULL << GPIO_NUM_2) | (1ULL << GPIO_NUM_4) | (1ULL << GPIO_NUM_12) | (1ULL << GPIO_NUM_13) | (1ULL << GPIO_NUM_14) | (1ULL << GPIO_NUM_15));
-    io_conf.pin_bit_mask = ((1ULL << GPIO_NUM_12) | (1ULL << GPIO_NUM_13));
-    //disable pull-down mode
-    io_conf.pull_down_en = (gpio_pulldown_t) 0;
-    //disable pull-up mode
-    io_conf.pull_up_en = (gpio_pullup_t) 0;
-    //configure GPIO with the given settings
-    gpio_config(&io_conf);
+    ESP_LOGD(TAG_SERVERGPIO, "GpioHandler::flashLightEnable %s\r\n", value ? "true" : "false");
+
+    if (gpioMap != NULL) {
+        for(std::map<gpio_num_t, GpioPin*>::iterator it = gpioMap->begin(); it != gpioMap->end(); ++it) 
+        {
+            if (it->second->getMode() == GPIO_PIN_MODE_BUILT_IN_FLASH_LED) //|| (it->second->getMode() == GPIO_PIN_MODE_EXTERNAL_FLASH_PWM) || (it->second->getMode() == GPIO_PIN_MODE_EXTERNAL_FLASH_WS281X))
+            {
+                std::string resp_str = "";
+                it->second->setValue(value, GPIO_SET_SOURCE_INTERNAL, &resp_str);
+
+                if (resp_str == "") {
+                    ESP_LOGD(TAG_SERVERGPIO, "Flash light pin GPIO %d switched to %s\r\n", (int)it->first, (value ? "on" : "off"));
+                } else {
+                    ESP_LOGE(TAG_SERVERGPIO, "Can't set flash light pin GPIO %d.  Error: %s\r\n", (int)it->first, resp_str.c_str());
+                }
+            }
+        }
+    }
 }
 
+gpio_num_t GpioHandler::resolvePinNr(uint8_t pinNr) 
+{
+    switch(pinNr)  {
+        case 0:
+            return GPIO_NUM_0;
+        case 1:
+            return GPIO_NUM_1;
+        case 3:
+            return GPIO_NUM_3;
+        case 4:
+            return GPIO_NUM_4;
+        case 12:
+            return GPIO_NUM_12;
+        case 13:
+            return GPIO_NUM_13;
+        default: 
+            return GPIO_NUM_NC;   
+    }
+}
 
-void register_server_GPIO_uri(httpd_handle_t server)
+gpio_pin_mode_t GpioHandler::resolvePinMode(std::string input) 
 {
-    ESP_LOGI(TAGPARTGPIO, "server_GPIO - Registering URI handlers");
-    
-    httpd_uri_t camuri = { };
-    camuri.method    = HTTP_GET;
-    camuri.uri       = "/GPIO";
-    camuri.handler   = handler_switch_GPIO;
-    camuri.user_ctx  = (void*) "switch GPIO";    
-    httpd_register_uri_handler(server, &camuri);
+    if( input == "disabled" ) return GPIO_PIN_MODE_DISABLED;
+    if( input == "input" ) return GPIO_PIN_MODE_INPUT;
+    if( input == "input-pullup" ) return GPIO_PIN_MODE_INPUT_PULLUP;
+    if( input == "input-pulldown" ) return GPIO_PIN_MODE_INPUT_PULLDOWN;
+    if( input == "output" ) return GPIO_PIN_MODE_OUTPUT;
+    if( input == "built-in-led" ) return GPIO_PIN_MODE_BUILT_IN_FLASH_LED;
+    if( input == "output-pwm" ) return GPIO_PIN_MODE_OUTPUT_PWM;
+    if( input == "external-flash-pwm" ) return GPIO_PIN_MODE_EXTERNAL_FLASH_PWM;
+    if( input == "external-flash-ws281x" ) return GPIO_PIN_MODE_EXTERNAL_FLASH_WS281X;
+
+    return GPIO_PIN_MODE_DISABLED;
+}
+
+gpio_int_type_t GpioHandler::resolveIntType(std::string input) 
+{
+    if( input == "disabled" ) return GPIO_INTR_DISABLE;
+    if( input == "rising-edge" ) return GPIO_INTR_POSEDGE;
+    if( input == "falling-edge" ) return GPIO_INTR_NEGEDGE;
+    if( input == "rising-and-falling" ) return GPIO_INTR_ANYEDGE ;
+    if( input == "low-level-trigger" ) return GPIO_INTR_LOW_LEVEL;
+    if( input == "high-level-trigger" ) return GPIO_INTR_HIGH_LEVEL;
+
+
+    return GPIO_INTR_DISABLE;
+}
+
+static GpioHandler *gpioHandler = NULL;
+
+void gpio_handler_create(httpd_handle_t server) 
+{
+    if (gpioHandler == NULL)
+        gpioHandler = new GpioHandler(CONFIG_FILE, server);
+}
+
+void gpio_handler_init() 
+{
+    if (gpioHandler != NULL) {
+        gpioHandler->init();
+    }
+}
+
+void gpio_handler_deinit() {
+    if (gpioHandler != NULL) {
+        gpioHandler->deinit();
+   }
+}
+
+void gpio_handler_destroy()
+{
+    if (gpioHandler != NULL) {
+        delete gpioHandler;
+        gpioHandler = NULL;
+    }
+}
 
-    initGPIO();
+GpioHandler* gpio_handler_get()
+{
+    return gpioHandler;
 }

+ 91 - 2
code/components/jomjol_controlGPIO/server_GPIO.h

@@ -1,10 +1,99 @@
+#ifndef SERVER_GPIO_H
+#define SERVER_GPIO_H
+
 #include <esp_log.h>
 
 #include <esp_http_server.h>
+#include <map>
+#include "driver/gpio.h"
 
 //#include "ClassControllCamera.h"
 
-static const char *TAGPARTGPIO = "server_GPIO";
+typedef enum {
+    GPIO_PIN_MODE_DISABLED              = 0x0,
+    GPIO_PIN_MODE_INPUT                 = 0x1,
+    GPIO_PIN_MODE_INPUT_PULLUP          = 0x2,
+    GPIO_PIN_MODE_INPUT_PULLDOWN        = 0x3,
+    GPIO_PIN_MODE_OUTPUT                = 0x4,
+    GPIO_PIN_MODE_BUILT_IN_FLASH_LED    = 0x5,
+    GPIO_PIN_MODE_OUTPUT_PWM            = 0x6,
+    GPIO_PIN_MODE_EXTERNAL_FLASH_PWM    = 0x7,
+    GPIO_PIN_MODE_EXTERNAL_FLASH_WS281X = 0x8,
+} gpio_pin_mode_t;
+
+struct GpioResult {
+    gpio_num_t gpio;
+    int value;
+};
+
+typedef enum {
+    GPIO_SET_SOURCE_INTERNAL  = 0,
+    GPIO_SET_SOURCE_MQTT  = 1,
+    GPIO_SET_SOURCE_HTTP  = 2,
+} gpio_set_source;
+
+class GpioPin {
+public:
+    GpioPin(gpio_num_t gpio, const char* name, gpio_pin_mode_t mode, gpio_int_type_t interruptType, uint8_t dutyResolution, std::string mqttTopic, bool httpEnable);
+    ~GpioPin();
+
+    void init();
+    bool getValue(std::string* errorText);
+    void setValue(bool value, gpio_set_source setSource, std::string* errorText);
+    bool handleMQTT(std::string, char* data, int data_len);
+    void publishState();
+    void gpioInterrupt(int value);
+    gpio_int_type_t getInterruptType() { return _interruptType; }
+    gpio_pin_mode_t getMode() { return _mode; }
+
+private:
+    gpio_num_t _gpio;
+    const char* _name;
+    gpio_pin_mode_t _mode;
+    gpio_int_type_t _interruptType;
+    std::string _mqttTopic;
+    int currentState = -1;
+};
+
+esp_err_t callHandleHttpRequest(httpd_req_t *req);
+void taskGpioHandler(void *pvParameter);
+
+class GpioHandler {
+public:
+    GpioHandler(std::string configFile, httpd_handle_t httpServer);
+    ~GpioHandler();
+    
+    void init();
+    void deinit();
+    void registerGpioUri();
+    esp_err_t handleHttpRequest(httpd_req_t *req);
+    void taskHandler();
+    void gpioInterrupt(GpioResult* gpioResult);  
+    void flashLightEnable(bool value);
+    bool isEnabled() { return _isEnabled; }
+    void handleMQTTconnect();
+
+private:
+    std::string _configFile;
+    httpd_handle_t _httpServer;
+    std::map<gpio_num_t, GpioPin*> *gpioMap = NULL;
+    TaskHandle_t xHandleTaskGpio = NULL;
+    bool _isEnabled = false;
+
+    bool readConfig();
+    void clear();
+    
+    gpio_num_t resolvePinNr(uint8_t pinNr);
+    gpio_pin_mode_t resolvePinMode(std::string input);
+    gpio_int_type_t resolveIntType(std::string input);
+};
+
+void gpio_handler_create(httpd_handle_t server);
+void gpio_handler_init();
+void gpio_handler_deinit();
+void gpio_handler_destroy();
+GpioHandler* gpio_handler_get();
+
 
-void register_server_GPIO_uri(httpd_handle_t server);
 
+#endif //SERVER_GPIO_H

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

@@ -4,6 +4,6 @@ list(APPEND EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/proto
 
 idf_component_register(SRCS ${app_sources}
                     INCLUDE_DIRS "."
-                    REQUIRES esp32-camera-master esp_http_server jomjol_logfile jomjol_image_proc nvs_flash jomjol_fileserver_ota)
+                    REQUIRES esp32-camera-master esp_http_server jomjol_logfile jomjol_image_proc nvs_flash jomjol_fileserver_ota jomjol_controlGPIO)
 
 

+ 18 - 13
code/components/jomjol_controlcamera/ClassControllCamera.cpp

@@ -10,12 +10,13 @@
 #include "CImageBasis.h"
 
 #include "server_ota.h"
+#include "server_GPIO.h"
 
 
 #define BOARD_ESP32CAM_AITHINKER
 
 
-#include <esp_event_loop.h>
+#include <esp_event.h>
 #include <esp_log.h>
 #include <esp_system.h>
 #include <nvs_flash.h>
@@ -50,7 +51,7 @@
 #define CAM_PIN_HREF 23
 #define CAM_PIN_PCLK 22
 
-static const char *TAG = "example:take_picture";
+static const char *TAGCAMERACLASS = "server_part_camera"; 
 
 static camera_config_t camera_config = {
     .pin_pwdn = CAM_PIN_PWDN,
@@ -275,7 +276,7 @@ esp_err_t CCamera::CaptureToBasisImage(CImageBasis *_Image, int delay)
 
     camera_fb_t * fb = esp_camera_fb_get();
     if (!fb) {
-        ESP_LOGE(TAGCAMERACLASS, "Camera Capture Failed");
+        ESP_LOGE(TAGCAMERACLASS, "CaptureToBasisImage: Camera Capture Failed");
         LEDOnOff(false);
         LightOnOff(false);
         doReboot();
@@ -362,8 +363,7 @@ esp_err_t CCamera::CaptureToFile(std::string nm, int delay)
 
     camera_fb_t * fb = esp_camera_fb_get();
     if (!fb) {
-        ESP_LOGE(TAGCAMERACLASS, "Camera Capture Failed");
-        ESP_LOGE(TAGCAMERACLASS, "Reboot ?????");
+        ESP_LOGE(TAGCAMERACLASS, "CaptureToFile: Camera Capture Failed");
         LEDOnOff(false);
         LightOnOff(false);
         doReboot();
@@ -497,15 +497,20 @@ esp_err_t CCamera::CaptureToHTTP(httpd_req_t *req, int delay)
 
 void CCamera::LightOnOff(bool status)
 {
-	// Init the GPIO
-    gpio_pad_select_gpio(FLASH_GPIO);
-    /* Set the GPIO as a push/pull output */
-    gpio_set_direction(FLASH_GPIO, GPIO_MODE_OUTPUT);  
+    GpioHandler* gpioHandler = gpio_handler_get();
+    if ((gpioHandler != NULL) && (gpioHandler->isEnabled())) {
+        gpioHandler->flashLightEnable(status);
+    }  else {
+        // Init the GPIO
+        gpio_pad_select_gpio(FLASH_GPIO);
+        /* Set the GPIO as a push/pull output */
+        gpio_set_direction(FLASH_GPIO, GPIO_MODE_OUTPUT);  
 
-    if (status)  
-        gpio_set_level(FLASH_GPIO, 1);
-    else
-        gpio_set_level(FLASH_GPIO, 0);      
+        if (status)  
+            gpio_set_level(FLASH_GPIO, 1);
+        else
+            gpio_set_level(FLASH_GPIO, 0);
+    }
 }
 
 void CCamera::LEDOnOff(bool status)

+ 0 - 3
code/components/jomjol_controlcamera/ClassControllCamera.h

@@ -16,9 +16,6 @@
 #define CAMERA_MODEL_AI_THINKER
 
 
-static const char *TAGCAMERACLASS = "server_part_camera"; 
-
-
 class CCamera {
     protected:
         int ActualQuality;

+ 5 - 2
code/components/jomjol_controlcamera/server_camera.cpp

@@ -12,14 +12,17 @@
 char scratch2[SCRATCH_BUFSIZE2];
 
 //#define DEBUG_DETAIL_ON   
-
+static const char *TAGPARTCAMERA = "server_camera";
 
 
 void PowerResetCamera(){
         ESP_LOGD(TAGPARTCAMERA, "Resetting camera by power down line");
-        gpio_config_t conf = { 0 };
+        gpio_config_t conf;
+        conf.intr_type = GPIO_INTR_DISABLE;
         conf.pin_bit_mask = 1LL << GPIO_NUM_32;
         conf.mode = GPIO_MODE_OUTPUT;
+        conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
+        conf.pull_up_en = GPIO_PULLUP_DISABLE;
         gpio_config(&conf);
 
         // carefull, logic is inverted compared to reset pin

+ 0 - 2
code/components/jomjol_controlcamera/server_camera.h

@@ -7,8 +7,6 @@
 
 //#include "ClassControllCamera.h"
 
-static const char *TAGPARTCAMERA = "server_camera";
-
 void register_server_camera_uri(httpd_handle_t server);
 
 void PowerResetCamera();

+ 2 - 2
code/components/jomjol_fileserver_ota/CMakeLists.txt

@@ -1,7 +1,7 @@
 FILE(GLOB_RECURSE app_sources ${CMAKE_CURRENT_SOURCE_DIR}/*.*)
 
 idf_component_register(SRCS ${app_sources}
-                    INCLUDE_DIRS "."
-                    REQUIRES tfmicro esp_http_server app_update esp_http_client nvs_flash jomjol_tfliteclass jomjol_flowcontroll spiffs jomjol_helper)
+                    INCLUDE_DIRS "." "../../include"
+                    REQUIRES tfmicro esp_http_server app_update esp_http_client nvs_flash jomjol_tfliteclass jomjol_flowcontroll spiffs jomjol_helper jomjol_controlGPIO)
 
 

+ 55 - 45
code/components/jomjol_fileserver_ota/server_file.cpp

@@ -26,9 +26,12 @@
 #include <esp_spiffs.h>
 #include "esp_http_server.h"
 
+#include "defines.h"
 #include "ClassLogFile.h"
 
 #include "server_help.h"
+#include "interface_mqtt.h"
+#include "server_GPIO.h"
 
 #include "Helper.h"
 #include "miniz.h"
@@ -53,17 +56,17 @@ struct file_server_data {
     char scratch[SCRATCH_BUFSIZE];
 };
 
-static const char *TAG = "file_server";
+static const char *TAG_FILESERVER = "file_server";
 
 /* Handler to redirect incoming GET request for /index.html to /
  * This can be overridden by uploading file with same name */
-static esp_err_t index_html_get_handler(httpd_req_t *req)
-{
-    httpd_resp_set_status(req, "307 Temporary Redirect");
-    httpd_resp_set_hdr(req, "Location", "/");
-    httpd_resp_send(req, NULL, 0);  // Response body can be empty
-    return ESP_OK;
-}
+// static esp_err_t index_html_get_handler(httpd_req_t *req)
+// {
+//     httpd_resp_set_status(req, "307 Temporary Redirect");
+//     httpd_resp_set_hdr(req, "Location", "/");
+//     httpd_resp_send(req, NULL, 0);  // Response body can be empty
+//     return ESP_OK;
+// }
 
 /* Send HTTP response with a run-time generated html consisting of
  * a list of all files and folders under the requested path.
@@ -95,7 +98,7 @@ static esp_err_t http_resp_dir_html(httpd_req_t *req, const char *dirpath, const
     printf("entrypath: <%s>\n", entrypath);    
 
     if (!dir) {
-        ESP_LOGE(TAG, "Failed to stat dir : %s", dirpath);
+        ESP_LOGE(TAG_FILESERVER, "Failed to stat dir : %s", dirpath);
         /* Respond with 404 Not Found */
         httpd_resp_send_err(req, HTTPD_404_NOT_FOUND, "Directory does not exist");
         return ESP_FAIL;
@@ -115,7 +118,7 @@ static esp_err_t http_resp_dir_html(httpd_req_t *req, const char *dirpath, const
             if (chunksize > 0){
                 if (httpd_resp_send_chunk(req, chunk, chunksize) != ESP_OK) {
                 fclose(fd);
-                ESP_LOGE(TAG, "File sending failed!");
+                ESP_LOGE(TAG_FILESERVER, "File sending failed!");
                 return ESP_FAIL;
                 }
             }
@@ -154,11 +157,11 @@ static esp_err_t http_resp_dir_html(httpd_req_t *req, const char *dirpath, const
             strlcpy(entrypath + dirpath_len, entry->d_name, sizeof(entrypath) - dirpath_len);
             printf("Entrypath: %s\n", entrypath);
             if (stat(entrypath, &entry_stat) == -1) {
-                ESP_LOGE(TAG, "Failed to stat %s : %s", entrytype, entry->d_name);
+                ESP_LOGE(TAG_FILESERVER, "Failed to stat %s : %s", entrytype, entry->d_name);
                 continue;
             }
             sprintf(entrysize, "%ld", entry_stat.st_size);
-            ESP_LOGI(TAG, "Found %s : %s (%s bytes)", entrytype, entry->d_name, entrysize);
+            ESP_LOGI(TAG_FILESERVER, "Found %s : %s (%s bytes)", entrytype, entry->d_name, entrysize);
 
             /* Send chunk of HTML file containing table entries with file name and size */
             httpd_resp_sendstr_chunk(req, "<tr><td><a href=\"");
@@ -206,19 +209,19 @@ static esp_err_t logfileact_get_handler(httpd_req_t *req)
     LogFile.WriteToFile("logfileact_get_handler");
     char filepath[FILE_PATH_MAX];
     FILE *fd = NULL;
-    struct stat file_stat;
+    //struct stat file_stat;
     printf("uri: %s\n", req->uri);
 
-    const char filename = 'log_current.txt'; 
+    const char* filename = "log_current.txt"; 
 
-    printf("uri: %s, filename: %s, filepath: %s\n", req->uri, &filename, filepath);
+    printf("uri: %s, filename: %s, filepath: %s\n", req->uri, filename, filepath);
 
     std::string currentfilename = LogFile.GetCurrentFileName();
 
 
     fd = OpenFileAndWait(currentfilename.c_str(), "r");
     if (!fd) {
-        ESP_LOGE(TAG, "Failed to read existing file : %s", filepath);
+        ESP_LOGE(TAG_FILESERVER, "Failed to read existing file : %s", filepath);
         /* Respond with 500 Internal Server Error */
         httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Failed to read existing file");
         return ESP_FAIL;
@@ -226,8 +229,8 @@ static esp_err_t logfileact_get_handler(httpd_req_t *req)
 
     httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
 
-//    ESP_LOGI(TAG, "Sending file : %s (%ld bytes)...", &filename, file_stat.st_size);
-    set_content_type_from_file(req, &filename);
+//    ESP_LOGI(TAG_FILESERVER, "Sending file : %s (%ld bytes)...", &filename, file_stat.st_size);
+    set_content_type_from_file(req, filename);
 
     /* Retrieve the pointer to scratch buffer for temporary storage */
     char *chunk = ((struct file_server_data *)req->user_ctx)->scratch;
@@ -239,7 +242,7 @@ static esp_err_t logfileact_get_handler(httpd_req_t *req)
         /* Send the buffer contents as HTTP response chunk */
         if (httpd_resp_send_chunk(req, chunk, chunksize) != ESP_OK) {
             fclose(fd);
-            ESP_LOGE(TAG, "File sending failed!");
+            ESP_LOGE(TAG_FILESERVER, "File sending failed!");
             /* Abort sending file */
             httpd_resp_sendstr_chunk(req, NULL);
             /* Respond with 500 Internal Server Error */
@@ -252,7 +255,7 @@ static esp_err_t logfileact_get_handler(httpd_req_t *req)
 
     /* Close file after sending complete */
     fclose(fd);
-    ESP_LOGI(TAG, "File sending complete");
+    ESP_LOGI(TAG_FILESERVER, "File sending complete");
 
     /* Respond with an empty chunk to signal HTTP response completion */
     httpd_resp_send_chunk(req, NULL, 0);
@@ -284,7 +287,7 @@ static esp_err_t download_get_handler(httpd_req_t *req)
 
 
     if (!filename) {
-        ESP_LOGE(TAG, "Filename is too long");
+        ESP_LOGE(TAG_FILESERVER, "Filename is too long");
         /* Respond with 500 Internal Server Error */
         httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Filename too long");
         return ESP_FAIL;
@@ -297,11 +300,11 @@ static esp_err_t download_get_handler(httpd_req_t *req)
         if (buf_len > 1) {
             char buf[buf_len];
             if (httpd_req_get_url_query_str(req, buf, buf_len) == ESP_OK) {
-                ESP_LOGI(TAG, "Found URL query => %s", buf);
+                ESP_LOGI(TAG_FILESERVER, "Found URL query => %s", buf);
                 char param[32];
                 /* Get value of expected key from query string */
                 if (httpd_query_key_value(buf, "readonly", param, sizeof(param)) == ESP_OK) {
-                    ESP_LOGI(TAG, "Found URL query parameter => readonly=%s", param);
+                    ESP_LOGI(TAG_FILESERVER, "Found URL query parameter => readonly=%s", param);
                     readonly = param && strcmp(param,"true")==0;
                 }
             }
@@ -316,7 +319,7 @@ static esp_err_t download_get_handler(httpd_req_t *req)
 
         /* If file not present on SPIFFS check if URI
          * corresponds to one of the hardcoded paths */
-        ESP_LOGE(TAG, "Failed to stat file : %s", filepath);
+        ESP_LOGE(TAG_FILESERVER, "Failed to stat file : %s", filepath);
         /* Respond with 404 Not Found */
         httpd_resp_send_err(req, HTTPD_404_NOT_FOUND, "File does not exist");
         return ESP_FAIL;
@@ -324,7 +327,7 @@ static esp_err_t download_get_handler(httpd_req_t *req)
 
     fd = OpenFileAndWait(filepath, "r");
     if (!fd) {
-        ESP_LOGE(TAG, "Failed to read existing file : %s", filepath);
+        ESP_LOGE(TAG_FILESERVER, "Failed to read existing file : %s", filepath);
         /* Respond with 500 Internal Server Error */
         httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Failed to read existing file");
         return ESP_FAIL;
@@ -332,7 +335,7 @@ static esp_err_t download_get_handler(httpd_req_t *req)
 
     httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
 
-    ESP_LOGI(TAG, "Sending file : %s (%ld bytes)...", filename, file_stat.st_size);
+    ESP_LOGI(TAG_FILESERVER, "Sending file : %s (%ld bytes)...", filename, file_stat.st_size);
     set_content_type_from_file(req, filename);
 
     /* Retrieve the pointer to scratch buffer for temporary storage */
@@ -345,7 +348,7 @@ static esp_err_t download_get_handler(httpd_req_t *req)
         /* Send the buffer contents as HTTP response chunk */
         if (httpd_resp_send_chunk(req, chunk, chunksize) != ESP_OK) {
             fclose(fd);
-            ESP_LOGE(TAG, "File sending failed!");
+            ESP_LOGE(TAG_FILESERVER, "File sending failed!");
             /* Abort sending file */
             httpd_resp_sendstr_chunk(req, NULL);
             /* Respond with 500 Internal Server Error */
@@ -358,7 +361,7 @@ static esp_err_t download_get_handler(httpd_req_t *req)
 
     /* Close file after sending complete */
     fclose(fd);
-    ESP_LOGI(TAG, "File sending complete");
+    ESP_LOGI(TAG_FILESERVER, "File sending complete");
 
     /* Respond with an empty chunk to signal HTTP response completion */
     httpd_resp_send_chunk(req, NULL, 0);
@@ -385,13 +388,13 @@ static esp_err_t upload_post_handler(httpd_req_t *req)
 
     /* Filename cannot have a trailing '/' */
     if (filename[strlen(filename) - 1] == '/') {
-        ESP_LOGE(TAG, "Invalid filename : %s", filename);
+        ESP_LOGE(TAG_FILESERVER, "Invalid filename : %s", filename);
         httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Invalid filename");
         return ESP_FAIL;
     }
 
     if (stat(filepath, &file_stat) == 0) {
-        ESP_LOGE(TAG, "File already exists : %s", filepath);
+        ESP_LOGE(TAG_FILESERVER, "File already exists : %s", filepath);
         /* Respond with 400 Bad Request */
         httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "File already exists");
         return ESP_FAIL;
@@ -399,7 +402,7 @@ static esp_err_t upload_post_handler(httpd_req_t *req)
 
     /* File cannot be larger than a limit */
     if (req->content_len > MAX_FILE_SIZE) {
-        ESP_LOGE(TAG, "File too large : %d bytes", req->content_len);
+        ESP_LOGE(TAG_FILESERVER, "File too large : %d bytes", req->content_len);
         /* Respond with 400 Bad Request */
         httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST,
                             "File size must be less than "
@@ -411,13 +414,13 @@ static esp_err_t upload_post_handler(httpd_req_t *req)
 
     fd = OpenFileAndWait(filepath, "w");
     if (!fd) {
-        ESP_LOGE(TAG, "Failed to create file : %s", filepath);
+        ESP_LOGE(TAG_FILESERVER, "Failed to create file : %s", filepath);
         /* Respond with 500 Internal Server Error */
         httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Failed to create file");
         return ESP_FAIL;
     }
 
-    ESP_LOGI(TAG, "Receiving file : %s...", filename);
+    ESP_LOGI(TAG_FILESERVER, "Receiving file : %s...", filename);
 
     /* Retrieve the pointer to scratch buffer for temporary storage */
     char *buf = ((struct file_server_data *)req->user_ctx)->scratch;
@@ -429,7 +432,7 @@ static esp_err_t upload_post_handler(httpd_req_t *req)
 
     while (remaining > 0) {
 
-        ESP_LOGI(TAG, "Remaining size : %d", remaining);
+        ESP_LOGI(TAG_FILESERVER, "Remaining size : %d", remaining);
         /* Receive the file part by part into a buffer */
         if ((received = httpd_req_recv(req, buf, MIN(remaining, SCRATCH_BUFSIZE))) <= 0) {
             if (received == HTTPD_SOCK_ERR_TIMEOUT) {
@@ -442,7 +445,7 @@ static esp_err_t upload_post_handler(httpd_req_t *req)
             fclose(fd);
             unlink(filepath);
 
-            ESP_LOGE(TAG, "File reception failed!");
+            ESP_LOGE(TAG_FILESERVER, "File reception failed!");
             /* Respond with 500 Internal Server Error */
             httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Failed to receive file");
             return ESP_FAIL;
@@ -455,7 +458,7 @@ static esp_err_t upload_post_handler(httpd_req_t *req)
             fclose(fd);
             unlink(filepath);
 
-            ESP_LOGE(TAG, "File write failed!");
+            ESP_LOGE(TAG_FILESERVER, "File write failed!");
             /* Respond with 500 Internal Server Error */
             httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Failed to write file to storage");
             return ESP_FAIL;
@@ -468,7 +471,7 @@ static esp_err_t upload_post_handler(httpd_req_t *req)
 
     /* Close file upon upload completion */
     fclose(fd);
-    ESP_LOGI(TAG, "File reception complete");
+    ESP_LOGI(TAG_FILESERVER, "File reception complete");
 
     std::string directory = std::string(filepath);
 	size_t zw = directory.find("/");
@@ -496,6 +499,13 @@ static esp_err_t upload_post_handler(httpd_req_t *req)
     httpd_resp_set_status(req, "303 See Other");
     httpd_resp_set_hdr(req, "Location", directory.c_str());
     httpd_resp_sendstr(req, "File uploaded successfully");
+
+    if (strcmp(filepath, CONFIG_FILE) == 0) {
+        printf("New config foung. Reload handler.");
+        gpio_handler_deinit();
+        MQTTdestroy();
+    }
+
     return ESP_OK;
 }
 
@@ -567,19 +577,19 @@ static esp_err_t delete_post_handler(httpd_req_t *req)
 
         /* Filename cannot have a trailing '/' */
         if (filename[strlen(filename) - 1] == '/') {
-            ESP_LOGE(TAG, "Invalid filename : %s", filename);
+            ESP_LOGE(TAG_FILESERVER, "Invalid filename : %s", filename);
             httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Invalid filename");
             return ESP_FAIL;
         }
 
         if (stat(filepath, &file_stat) == -1) {
-            ESP_LOGE(TAG, "File does not exist : %s", filename);
+            ESP_LOGE(TAG_FILESERVER, "File does not exist : %s", filename);
             /* Respond with 400 Bad Request */
             httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "File does not exist");
             return ESP_FAIL;
         }
 
-        ESP_LOGI(TAG, "Deleting file : %s", filename);
+        ESP_LOGI(TAG_FILESERVER, "Deleting file : %s", filename);
         /* Delete file */
         unlink(filepath);
 
@@ -623,7 +633,7 @@ void delete_all_in_directory(std::string _directory)
     std::string filename;
 
     if (!dir) {
-        ESP_LOGE(TAG, "Failed to stat dir : %s", _directory.c_str());
+        ESP_LOGE(TAG_FILESERVER, "Failed to stat dir : %s", _directory.c_str());
         return;
     }
 
@@ -632,7 +642,7 @@ void delete_all_in_directory(std::string _directory)
         if (!(entry->d_type == DT_DIR)){
             if (strcmp("wlan.ini", entry->d_name) != 0){                    // auf wlan.ini soll nicht zugegriffen werden !!!
                 filename = _directory + "/" + std::string(entry->d_name);
-                ESP_LOGI(TAG, "Deleting file : %s", filename.c_str());
+                ESP_LOGI(TAG_FILESERVER, "Deleting file : %s", filename.c_str());
                 /* Delete file */
                 unlink(filename.c_str());    
             }
@@ -722,19 +732,19 @@ void register_server_file_uri(httpd_handle_t server, const char *base_path)
     /* Validate file storage base path */
     if (!base_path) {
 //    if (!base_path || strcmp(base_path, "/spiffs") != 0) {
-        ESP_LOGE(TAG, "File server base_path not set");
+        ESP_LOGE(TAG_FILESERVER, "File server base_path not set");
 //        return ESP_ERR_INVALID_ARG;
     }
 
     if (server_data) {
-        ESP_LOGE(TAG, "File server already started");
+        ESP_LOGE(TAG_FILESERVER, "File server already started");
 //        return ESP_ERR_INVALID_STATE;
     }
 
     /* Allocate memory for server data */
     server_data = (file_server_data *) calloc(1, sizeof(struct file_server_data));
     if (!server_data) {
-        ESP_LOGE(TAG, "Failed to allocate memory for server data");
+        ESP_LOGE(TAG_FILESERVER, "Failed to allocate memory for server data");
 //        return ESP_ERR_NO_MEM;
     }
     strlcpy(server_data->base_path, base_path,

+ 13 - 9
code/components/jomjol_fileserver_ota/server_ota.cpp

@@ -12,7 +12,7 @@
 #include "freertos/task.h"
 #include "esp_system.h"
 #include "esp_event.h"
-#include "esp_event_loop.h"
+#include "esp_event.h"
 #include "esp_log.h"
 #include <esp_ota_ops.h>
 #include "esp_http_client.h"
@@ -28,6 +28,7 @@
 
 #include "server_tflite.h"
 #include "server_file.h"
+#include "server_GPIO.h"
 
 #include "ClassLogFile.h"
 
@@ -46,6 +47,7 @@ static char ota_write_data[BUFFSIZE + 1] = { 0 };
 
 
 #define OTA_URL_SIZE 256
+static const char *TAGPARTOTA = "server_ota";
 
 
 static void infinite_loop(void)
@@ -60,14 +62,14 @@ static void infinite_loop(void)
 
 
 
-static bool ota_example_task(std::string fn)
+static bool ota_update_task(std::string fn)
 {
     esp_err_t err;
     /* update handle : set by esp_ota_begin(), must be freed via esp_ota_end() */
     esp_ota_handle_t update_handle = 0 ;
     const esp_partition_t *update_partition = NULL;
 
-    ESP_LOGI(TAGPARTOTA, "Starting OTA example");
+    ESP_LOGI(TAGPARTOTA, "Starting OTA update");
 
     const esp_partition_t *configured = esp_ota_get_boot_partition();
     const esp_partition_t *running = esp_ota_get_running_partition();
@@ -374,7 +376,9 @@ esp_err_t handler_ota_update(httpd_req_t *req)
 
     const char* resp_str;    
 
-    if (ota_example_task(fn))
+    KillTFliteTasks();
+    gpio_handler_deinit();
+    if (ota_update_task(fn))
     {
         resp_str = "Firmware Update Successfull!<br><br>You can restart now.";
     }
@@ -400,8 +404,6 @@ void hard_restart() {
 
 void task_reboot(void *pvParameter)
 {
-
-
     while(1)
     {
         vTaskDelay(5000 / portTICK_PERIOD_MS);
@@ -413,12 +415,14 @@ void task_reboot(void *pvParameter)
 }
 
 void doReboot(){
-    LogFile.WriteToFile("Reboot - now");
-    KillTFliteTasks();
+    ESP_LOGI(TAGPARTOTA, "Reboot in 5sec");
+    LogFile.WriteToFile("Reboot in 5sec");
     xTaskCreate(&task_reboot, "reboot", configMINIMAL_STACK_SIZE * 64, NULL, 10, NULL);
+    // KillTFliteTasks(); // kills itself 
+    gpio_handler_destroy();
     vTaskDelay(5000 / portTICK_PERIOD_MS);
     esp_restart();
-    hard_restart();    
+    hard_restart();
 }
 
 

+ 0 - 2
code/components/jomjol_fileserver_ota/server_ota.h

@@ -4,8 +4,6 @@
 
 //#include "ClassControllCamera.h"
 
-static const char *TAGPARTOTA = "server_ota";
-
 void register_server_ota_sdcard_uri(httpd_handle_t server);
 void CheckOTAUpdate();
 void doReboot();

+ 5 - 1
code/components/jomjol_flowcontroll/ClassFlowAnalog.cpp

@@ -359,7 +359,11 @@ bool ClassFlowAnalog::doNeuralNetwork(string time)
     string zwcnn = "/sdcard" + cnnmodelfile;
     zwcnn = FormatFileName(zwcnn);
     printf(zwcnn.c_str());printf("\n");
-    tflite->LoadModel(zwcnn); 
+    if (!tflite->LoadModel(zwcnn)) {
+        printf("Can't read model file /sdcard%s\n", cnnmodelfile.c_str());
+        delete tflite;
+        return false;
+    } 
     tflite->MakeAllocate();
 #endif
 

+ 13 - 3
code/components/jomjol_flowcontroll/ClassFlowControll.cpp

@@ -210,7 +210,7 @@ bool ClassFlowControll::doFlow(string time)
     int repeat = 0;
 
 #ifdef DEBUG_DETAIL_ON 
-    LogFile.WriteHeapInfo("ClassFlowAnalog::doFlow - Start");
+    LogFile.WriteHeapInfo("ClassFlowControll::doFlow - Start");
 #endif
 
     for (int i = 0; i < FlowControll.size(); ++i)
@@ -239,7 +239,7 @@ bool ClassFlowControll::doFlow(string time)
         }
         
 #ifdef DEBUG_DETAIL_ON  
-        LogFile.WriteHeapInfo("ClassFlowAnalog::doFlow");
+        LogFile.WriteHeapInfo("ClassFlowControll::doFlow");
 #endif
 
     }
@@ -475,7 +475,7 @@ int ClassFlowControll::CleanTempFolder() {
 
 esp_err_t ClassFlowControll::SendRawJPG(httpd_req_t *req)
 {
-    return flowmakeimage->SendRawJPG(req);
+    return flowmakeimage != NULL ? flowmakeimage->SendRawJPG(req) : ESP_FAIL;
 }
 
 
@@ -487,6 +487,12 @@ esp_err_t ClassFlowControll::GetJPGStream(std::string _fn, httpd_req_t *req)
     esp_err_t result = ESP_FAIL;
     bool Dodelete = false;    
 
+    if (flowalignment == NULL)
+    {
+        printf("Can't continue, flowalignment is NULL\n");
+        return ESP_FAIL;
+    }
+
     if (_fn == "alg.jpg")
     {
         _send = flowalignment->ImageBasis;  
@@ -518,7 +524,9 @@ esp_err_t ClassFlowControll::GetJPGStream(std::string _fn, httpd_req_t *req)
             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)
@@ -533,7 +541,9 @@ esp_err_t ClassFlowControll::GetJPGStream(std::string _fn, httpd_req_t *req)
             if (htmlinfo[i]->image_org)
                 _send = htmlinfo[i]->image_org;        
         }
+        delete htmlinfo[i];
     }
+    htmlinfo.clear();
 
     if (_send)
     {

+ 6 - 1
code/components/jomjol_flowcontroll/ClassFlowDigit.cpp

@@ -307,7 +307,12 @@ bool ClassFlowDigit::doNeuralNetwork(string time)
     CTfLiteClass *tflite = new CTfLiteClass;  
     string zwcnn =  FormatFileName("/sdcard" + cnnmodelfile);
     printf(zwcnn.c_str());printf("\n");
-    tflite->LoadModel(zwcnn); 
+    if (!tflite->LoadModel(zwcnn)) {
+        printf("Can't read model file /sdcard%s\n", cnnmodelfile.c_str());
+        delete tflite;
+        return false;
+    } 
+
     tflite->MakeAllocate();
 #endif
 

+ 16 - 3
code/components/jomjol_flowcontroll/ClassFlowMQTT.cpp

@@ -1,6 +1,8 @@
+#include <sstream>
 #include "ClassFlowMQTT.h"
 #include "Helper.h"
 
+#include "time_sntp.h"
 #include "interface_mqtt.h"
 #include "ClassFlowPostProcessing.h"
 
@@ -16,6 +18,8 @@ void ClassFlowMQTT::SetInitialParameter(void)
     maintopic = "";
     mainerrortopic = ""; 
 
+    topicUptime = "";
+    topicFreeMem = "";
     clientname = "watermeter";
     OldValue = "";
     flowpostprocessing = NULL;  
@@ -106,7 +110,7 @@ bool ClassFlowMQTT::ReadParameter(FILE* pfile, string& aktparamgraph)
         }
     }
 
-    if ((uri.length() > 0) && (maintopic.length() > 0)) 
+    if (!MQTTisConnected() && (uri.length() > 0) && (maintopic.length() > 0)) 
     {
         mainerrortopic = maintopic + "/connection";
         MQTTInit(uri, clientname, user, password, mainerrortopic, 60); 
@@ -132,6 +136,16 @@ bool ClassFlowMQTT::doFlow(string zwtime)
 
     MQTTPublish(mainerrortopic, "connected");
     
+    zw = maintopic + "/" + "uptime";
+    char uptimeStr[11];
+    sprintf(uptimeStr, "%ld", (long)getUpTime());
+    MQTTPublish(zw, uptimeStr);
+
+    zw = maintopic + "/" + "freeMem";
+    char freeheapmem[11];
+    sprintf(freeheapmem, "%zu", esp_get_free_heap_size());
+    MQTTPublish(zw, freeheapmem);
+
     if (flowpostprocessing)
     {
         std::vector<NumberPost*> NUMBERS = flowpostprocessing->GetNumbers();
@@ -158,7 +172,7 @@ bool ClassFlowMQTT::doFlow(string zwtime)
             zw = namenumber + "rate";    
             MQTTPublish(zw, resultrate);
 
-            zw = namenumber + "timestamp";    
+            zw = namenumber + "timestamp";
             MQTTPublish(zw, resulttimestamp);
 
 
@@ -187,7 +201,6 @@ bool ClassFlowMQTT::doFlow(string zwtime)
         MQTTPublish(topic, result);
     }
     
-
     OldValue = result;
     
     return true;

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

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

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

@@ -78,8 +78,9 @@ void memCopyGen(uint8_t* _source, uint8_t* _target, int _size)
 
 
 
-FILE* OpenFileAndWait(const char* nm, char* _mode, int _waitsec)
+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)
@@ -314,6 +315,14 @@ string toUpper(string in)
 	return in;
 }
 
+string toLower(string in)
+{
+	for (int i = 0; i < in.length(); ++i)
+		in[i] = tolower(in[i]);
+	
+	return in;
+}
+
 // CPU Temp
 extern "C" uint8_t temprature_sens_read();
 float temperatureRead()

+ 2 - 1
code/components/jomjol_helper/Helper.h

@@ -11,7 +11,7 @@ void FindReplace(std::string& line, std::string& oldString, std::string& newStri
 
 void CopyFile(string input, string output);
 
-FILE* OpenFileAndWait(const char* nm, char* _mode, int _waitsec = 1);
+FILE* OpenFileAndWait(const char* nm, const char* _mode, int _waitsec = 1);
 
 size_t findDelimiterPos(string input, string delimiter);
 //string trim(string istring);
@@ -23,6 +23,7 @@ string getFileType(string filename);
 int mkdir_r(const char *dir, const mode_t mode);
 int removeFolder(const char* folderPath, const char* logTag);
 
+string toLower(string in);
 string toUpper(string in);
 
 float temperatureRead();

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

@@ -12,7 +12,7 @@ ClassLogFile LogFile("/sdcard/log/message", "log_%Y-%m-%d.txt");
 
 void ClassLogFile::WriteHeapInfo(std::string _id)
 {
-std::string _zw = "\t" + _id;
+    std::string _zw = "\t" + _id;
     if (loglevel > 0)
         _zw =  _zw + "\t" + getESPHeapInfo();
 

+ 127 - 14
code/components/jomjol_mqtt/interface_mqtt.cpp

@@ -1,12 +1,14 @@
 #include "interface_mqtt.h"
 
-
+//#define LOG_LOCAL_LEVEL ESP_LOG_DEBUG
 #include "esp_log.h"
 #include "mqtt_client.h"
 #include "ClassLogFile.h"
 
-static const char *TAG = "interface_mqtt";
+static const char *TAG_INTERFACEMQTT = "interface_mqtt";
 
+std::map<std::string, std::function<void()>>* connectFunktionMap = NULL;  
+std::map<std::string, std::function<bool(std::string, char*, int)>>* subscribeFunktionMap = NULL;  
 bool debugdetail = true;
 
 // #define CONFIG_BROKER_URL "mqtt://192.168.178.43:1883"
@@ -23,44 +25,67 @@ void MQTTPublish(std::string _key, std::string _content, int retained_flag){
         msg_id = esp_mqtt_client_publish(client, _key.c_str(), _content.c_str(), 0, 1, retained_flag);
         zw = "sent publish successful in MQTTPublish, msg_id=" + std::to_string(msg_id) + ", " + _key + ", " + _content;
         if (debugdetail) LogFile.WriteToFile(zw);
-        ESP_LOGI(TAG, "sent publish successful in MQTTPublish, msg_id=%d, %s, %s", msg_id, _key.c_str(), _content.c_str());
+        ESP_LOGD(TAG_INTERFACEMQTT, "sent publish successful in MQTTPublish, msg_id=%d, %s, %s", msg_id, _key.c_str(), _content.c_str());
     }
     else {
-        ESP_LOGI(TAG, "Problem with Publish, client=%d, mqtt_connected %d", (int) client, (int) mqtt_connected);
+        ESP_LOGW(TAG_INTERFACEMQTT, "Problem with Publish, client=%d, mqtt_connected %d", (int) client, (int) mqtt_connected);
     }
 }
 
 
 static esp_err_t mqtt_event_handler_cb(esp_mqtt_event_handle_t event)
 {
+    int msg_id;
+    std::string topic = "";
     switch (event->event_id) {
+        case MQTT_EVENT_BEFORE_CONNECT:
+            ESP_LOGI(TAG_INTERFACEMQTT, "MQTT_EVENT_BEFORE_CONNECT");
+            break;
         case MQTT_EVENT_CONNECTED:
-            ESP_LOGI(TAG, "MQTT_EVENT_CONNECTED");
+            ESP_LOGI(TAG_INTERFACEMQTT, "MQTT_EVENT_CONNECTED");
             mqtt_connected = true;
+            MQTTconnected();
             break;
         case MQTT_EVENT_DISCONNECTED:
-            ESP_LOGI(TAG, "MQTT_EVENT_DISCONNECTED");
+            ESP_LOGI(TAG_INTERFACEMQTT, "MQTT_EVENT_DISCONNECTED");
+            break;
+        case MQTT_EVENT_SUBSCRIBED:
+            ESP_LOGI(TAG_INTERFACEMQTT, "MQTT_EVENT_SUBSCRIBED, msg_id=%d", event->msg_id);
+            msg_id = esp_mqtt_client_publish(client, "/topic/qos0", "data", 0, 0, 0);
+            ESP_LOGI(TAG_INTERFACEMQTT, "sent publish successful, msg_id=%d", msg_id);
+            break;
+        case MQTT_EVENT_UNSUBSCRIBED:
+            ESP_LOGI(TAG_INTERFACEMQTT, "MQTT_EVENT_UNSUBSCRIBED, msg_id=%d", event->msg_id);
             break;
         case MQTT_EVENT_PUBLISHED:
-            ESP_LOGI(TAG, "MQTT_EVENT_PUBLISHED, msg_id=%d", event->msg_id);
+            ESP_LOGI(TAG_INTERFACEMQTT, "MQTT_EVENT_PUBLISHED, msg_id=%d", event->msg_id);
             break;
         case MQTT_EVENT_DATA:
-            ESP_LOGI(TAG, "MQTT_EVENT_DATA");
-            printf("TOPIC=%.*s\r\n", event->topic_len, event->topic);
-            printf("DATA=%.*s\r\n", event->data_len, event->data);
+            ESP_LOGI(TAG_INTERFACEMQTT, "MQTT_EVENT_DATA");
+            ESP_LOGI(TAG_INTERFACEMQTT, "TOPIC=%.*s\r\n", event->topic_len, event->topic);
+            ESP_LOGI(TAG_INTERFACEMQTT, "DATA=%.*s\r\n", event->data_len, event->data);
+            topic.assign(event->topic, event->topic_len);
+            if (subscribeFunktionMap != NULL) {
+                if (subscribeFunktionMap->find(topic) != subscribeFunktionMap->end()) {
+                    ESP_LOGD(TAG_INTERFACEMQTT, "call handler function\r\n");
+                    (*subscribeFunktionMap)[topic](topic, event->data, event->data_len);
+                }
+            } else {
+                ESP_LOGW(TAG_INTERFACEMQTT, "no handler available\r\n");
+            }
             break;
         case MQTT_EVENT_ERROR:
-            ESP_LOGI(TAG, "MQTT_EVENT_ERROR");
+            ESP_LOGI(TAG_INTERFACEMQTT, "MQTT_EVENT_ERROR");
             break;
         default:
-            ESP_LOGI(TAG, "Other event id:%d", event->event_id);
+            ESP_LOGI(TAG_INTERFACEMQTT, "Other event id:%d", event->event_id);
             break;
     }
     return ESP_OK;
 }
 
 static void mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data) {
-    ESP_LOGD(TAG, "Event dispatched from event loop base=%s, event_id=%d", base, event_id);
+    ESP_LOGD(TAG_INTERFACEMQTT, "Event dispatched from event loop base=%s, event_id=%d", base, event_id);
     mqtt_event_handler_cb((esp_mqtt_event_handle_t) event_data);
 }
 
@@ -82,7 +107,7 @@ void MQTTInit(std::string _mqttURI, std::string _clientid, std::string _user, st
     if (_user.length() && _password.length()){
         mqtt_cfg.username = _user.c_str();
         mqtt_cfg.password = _password.c_str();
-        printf("Connect to MQTT: %s, %s", mqtt_cfg.username, mqtt_cfg.password);
+        ESP_LOGI(TAG_INTERFACEMQTT, "Connect to MQTT: %s, %s", mqtt_cfg.username, mqtt_cfg.password);
     };
 
     client = esp_mqtt_client_init(&mqtt_cfg);
@@ -91,3 +116,91 @@ void MQTTInit(std::string _mqttURI, std::string _clientid, std::string _user, st
 
     MQTTPublish(_LWTContext, "", 1);
 }
+
+void MQTTdestroy() {
+    if (client != NULL) {
+        esp_mqtt_client_stop(client);
+        esp_mqtt_client_destroy(client);
+    }
+}
+
+bool MQTTisConnected() {
+    return mqtt_connected;
+}
+
+void MQTTregisterConnectFunction(std::string name, std::function<void()> func){
+    ESP_LOGD(TAG_INTERFACEMQTT, "MQTTregisteronnectFunction %s\r\n", name.c_str());
+    if (connectFunktionMap == NULL) {
+        connectFunktionMap = new std::map<std::string, std::function<void()>>();
+    }
+
+    if ((*connectFunktionMap)[name] != NULL) {
+        ESP_LOGW(TAG_INTERFACEMQTT, "connect function %s already registred", name.c_str());
+        return;
+    }
+
+    (*connectFunktionMap)[name] = func;
+
+    if (mqtt_connected) {
+        func();
+    }
+}
+
+void MQTTunregisterConnectFunction(std::string name){
+    ESP_LOGD(TAG_INTERFACEMQTT, "MQTTregisteronnectFunction %s\r\n", name.c_str());
+    if ((connectFunktionMap != NULL) && (connectFunktionMap->find(name) != connectFunktionMap->end())) {
+        connectFunktionMap->erase(name);
+    }
+}
+
+void MQTTregisterSubscribeFunction(std::string topic, std::function<bool(std::string, char*, int)> func){
+    ESP_LOGD(TAG_INTERFACEMQTT, "MQTTregisterSubscribeFunction %s\r\n", topic.c_str());
+    if (subscribeFunktionMap == NULL) {
+        subscribeFunktionMap = new std::map<std::string, std::function<bool(std::string, char*, int)>>();
+    }
+
+    if ((*subscribeFunktionMap)[topic] != NULL) {
+        ESP_LOGW(TAG_INTERFACEMQTT, "topic %s already registred for subscription", topic.c_str());
+        return;
+    }
+
+    (*subscribeFunktionMap)[topic] = func;
+
+    if (mqtt_connected) {
+        int msg_id = esp_mqtt_client_subscribe(client, topic.c_str(), 0);
+        ESP_LOGD(TAG_INTERFACEMQTT, "topic %s subscribe successful, msg_id=%d", topic.c_str(), msg_id);
+    }
+}
+
+void MQTTconnected(){
+    if (mqtt_connected) {
+        if (connectFunktionMap != NULL) {
+            for(std::map<std::string, std::function<void()>>::iterator it = connectFunktionMap->begin(); it != connectFunktionMap->end(); ++it) {
+                it->second();
+                ESP_LOGD(TAG_INTERFACEMQTT, "call connect function %s", it->first.c_str());
+            }
+        }
+
+        if (subscribeFunktionMap != NULL) {
+            for(std::map<std::string, std::function<bool(std::string, char*, int)>>::iterator it = subscribeFunktionMap->begin(); it != subscribeFunktionMap->end(); ++it) {
+                int msg_id = esp_mqtt_client_subscribe(client, it->first.c_str(), 0);
+                ESP_LOGD(TAG_INTERFACEMQTT, "topic %s subscribe successful, msg_id=%d", it->first.c_str(), msg_id);
+            }
+        }
+    }
+}
+
+void MQTTdestroySubscribeFunction(){
+    if (subscribeFunktionMap != NULL) {
+        if (mqtt_connected) {
+            for(std::map<std::string, std::function<bool(std::string, char*, int)>>::iterator it = subscribeFunktionMap->begin(); it != subscribeFunktionMap->end(); ++it) {
+                int msg_id = esp_mqtt_client_unsubscribe(client, it->first.c_str());
+                ESP_LOGI(TAG_INTERFACEMQTT, "topic %s unsubscribe successful, msg_id=%d", it->first.c_str(), msg_id);
+            }
+        }
+
+        subscribeFunktionMap->clear();
+        delete subscribeFunktionMap;
+        subscribeFunktionMap = NULL;
+    }
+}

+ 17 - 1
code/components/jomjol_mqtt/interface_mqtt.h

@@ -1,7 +1,23 @@
+#ifndef INTERFACE_MQTT_H
+#define INTERFACE_MQTT_H
+
 #include <string>
+#include <map>
+#include <functional>
 
 void MQTTInit(std::string _mqttURI, std::string _clientid, std::string _user, std::string _password, std::string _LWTContext, int _keepalive);
+void MQTTdestroy();
 
 //void MQTTInit(std::string _mqttURI, std::string _clientid, std::string _user = "", std::string _password = "");
 
-void MQTTPublish(std::string _key, std::string _content, int retained_flag = 0);
+void MQTTPublish(std::string _key, std::string _content, int retained_flag = 0);
+
+bool MQTTisConnected();
+
+void MQTTregisterConnectFunction(std::string name, std::function<void()> func);
+void MQTTunregisterConnectFunction(std::string name);
+void MQTTregisterSubscribeFunction(std::string topic, std::function<bool(std::string, char*, int)> func);
+void MQTTdestroySubscribeFunction();
+void MQTTconnected();
+
+#endif //INTERFACE_MQTT_H

+ 8 - 2
code/components/jomjol_tfliteclass/CTfLiteClass.cpp

@@ -98,7 +98,8 @@ void CTfLiteClass::GetOutPut()
 
 void CTfLiteClass::Invoke()
 {
-    interpreter->Invoke();
+    if (interpreter != nullptr)
+      interpreter->Invoke();
 }
 
 
@@ -208,7 +209,7 @@ unsigned char* CTfLiteClass::ReadFileToCharArray(std::string _fn)
     return result;
 }
 
-void CTfLiteClass::LoadModel(std::string _fn){
+bool CTfLiteClass::LoadModel(std::string _fn){
 
 #ifdef SUPRESS_TFLITE_ERRORS
     this->error_reporter = new tflite::OwnMicroErrorReporter;
@@ -219,9 +220,14 @@ void CTfLiteClass::LoadModel(std::string _fn){
     unsigned char *rd;
     rd = ReadFileToCharArray(_fn.c_str());
 
+    if (rd == NULL) 
+      return false;
+
     this->model = tflite::GetModel(rd);
     free(rd);
     TFLITE_MINIMAL_CHECK(model != nullptr); 
+    
+    return true;
 }
 
 

+ 1 - 1
code/components/jomjol_tfliteclass/CTfLiteClass.h

@@ -56,7 +56,7 @@ class CTfLiteClass
     public:
         CTfLiteClass();
         ~CTfLiteClass();        
-        void LoadModel(std::string _fn);
+        bool LoadModel(std::string _fn);
         void MakeAllocate();
         void GetInputTensorSize();
         bool LoadInputImageBasis(CImageBasis *rs);

+ 21 - 14
code/components/jomjol_tfliteclass/server_tflite.cpp

@@ -8,6 +8,7 @@
 #include <iomanip>
 #include <sstream>
 
+#include "defines.h"
 #include "Helper.h"
 
 #include "esp_camera.h"
@@ -17,6 +18,7 @@
 #include "ClassFlowControll.h"
 
 #include "ClassLogFile.h"
+#include "server_GPIO.h"
 
 // #define DEBUG_DETAIL_ON       
 
@@ -37,6 +39,9 @@ bool auto_isrunning = false;
 
 int countRounds = 0;
 
+static const char *TAGTFLITE = "server_tflite";
+
+
 int getCountFlowRounds() {
     return countRounds;
 }
@@ -64,9 +69,11 @@ void KillTFliteTasks()
 #ifdef DEBUG_DETAIL_ON          
     printf("Handle: xHandleblink_task_doFlow: %ld\n", (long) xHandleblink_task_doFlow);  
 #endif  
-    if (xHandleblink_task_doFlow)
+    if (xHandleblink_task_doFlow != NULL)
     {
-        vTaskDelete(xHandleblink_task_doFlow);
+        TaskHandle_t xHandleblink_task_doFlowTmp = xHandleblink_task_doFlow;
+        xHandleblink_task_doFlow = NULL;
+        vTaskDelete(xHandleblink_task_doFlowTmp);
 #ifdef DEBUG_DETAIL_ON      
         printf("Killed: xHandleblink_task_doFlow\n");
 #endif
@@ -75,9 +82,11 @@ void KillTFliteTasks()
 #ifdef DEBUG_DETAIL_ON      
     printf("Handle: xHandletask_autodoFlow: %ld\n", (long) xHandletask_autodoFlow);  
 #endif
-    if (xHandletask_autodoFlow)
+    if (xHandletask_autodoFlow != NULL)
     {
-        vTaskDelete(xHandletask_autodoFlow);
+        TaskHandle_t xHandletask_autodoFlowTmp = xHandletask_autodoFlow;
+        xHandletask_autodoFlow = NULL;
+        vTaskDelete(xHandletask_autodoFlowTmp);
 #ifdef DEBUG_DETAIL_ON      
         printf("Killed: xHandletask_autodoFlow\n");
 #endif
@@ -87,11 +96,10 @@ void KillTFliteTasks()
 
 void doInit(void)
 {
-    string config = "/sdcard/config/config.ini";
 #ifdef DEBUG_DETAIL_ON             
     printf("Start tfliteflow.InitFlow(config);\n");
 #endif
-    tfliteflow.InitFlow(config);
+    tfliteflow.InitFlow(CONFIG_FILE);
 #ifdef DEBUG_DETAIL_ON      
     printf("Finished tfliteflow.InitFlow(config);\n");
 #endif
@@ -136,7 +144,7 @@ esp_err_t handler_init(httpd_req_t *req)
     printf("handler_doinit uri:\n"); printf(req->uri); printf("\n");
 #endif
 
-    char* resp_str = "Init started<br>";
+    const char* resp_str = "Init started<br>";
     httpd_resp_send(req, resp_str, strlen(resp_str));     
 
     doInit();
@@ -159,8 +167,6 @@ esp_err_t handler_doflow(httpd_req_t *req)
     LogFile.WriteHeapInfo("handler_doflow - Start");       
 #endif
 
-    char* resp_str;
-
     printf("handler_doFlow uri: "); printf(req->uri); printf("\n");
 
     if (flowisrunning)
@@ -173,7 +179,7 @@ esp_err_t handler_doflow(httpd_req_t *req)
     {
         xTaskCreate(&blink_task_doFlow, "blink_doFlow", configMINIMAL_STACK_SIZE * 64, NULL, tskIDLE_PRIORITY+1, &xHandleblink_task_doFlow);
     }
-    resp_str = "doFlow gestartet - dauert ca. 60 Sekunden";
+    const char* resp_str = "doFlow gestartet - dauert ca. 60 Sekunden";
     httpd_resp_send(req, resp_str, strlen(resp_str));  
     /* Respond with an empty chunk to signal HTTP response completion */
     httpd_resp_send_chunk(req, NULL, 0);       
@@ -470,7 +476,7 @@ esp_err_t handler_editflow(httpd_req_t *req)
 
 //        printf("Parameter host: "); printf(_host.c_str()); printf("\n"); 
 //        string zwzw = "Do " + _task + " start\n"; printf(zwzw.c_str());
-        bool changed = Camera.SetBrightnessContrastSaturation(bri, con, sat);
+        Camera.SetBrightnessContrastSaturation(bri, con, sat);
         std::string zw = tfliteflow.doSingleStep("[MakeImage]", _host);
         httpd_resp_sendstr_chunk(req, zw.c_str()); 
     } 
@@ -586,17 +592,17 @@ void task_autodoFlow(void *pvParameter)
 {
     int64_t fr_start, fr_delta_ms;
 
+    printf("task_autodoFlow: start\r\n");
     doInit();
-    
-    auto_isrunning = tfliteflow.isAutoStart(auto_intervall);
+    gpio_handler_init();
 
+    auto_isrunning = tfliteflow.isAutoStart(auto_intervall);
     if (isSetupModusActive()) {
         auto_isrunning = false;
         std::string zw_time = gettimestring(LOGFILE_TIME_FORMAT);
         tfliteflow.doFlowMakeImageOnly(zw_time);
 
     }
-
     while (auto_isrunning)
     {
         std::string _zw = "task_autodoFlow - next round - Round #" + std::to_string(++countRounds);
@@ -641,6 +647,7 @@ void task_autodoFlow(void *pvParameter)
     }
     vTaskDelete(NULL); //Delete this task if it exits from the loop above
     xHandletask_autodoFlow = NULL;
+    printf("task_autodoFlow: end\r\n");
 }
 
 void TFliteDoAutoStart()

+ 0 - 2
code/components/jomjol_tfliteclass/server_tflite.h

@@ -5,8 +5,6 @@
 
 //#include "ClassControllCamera.h"
 
-static const char *TAGTFLITE = "server_tflite";
-
 void register_server_tflite_uri(httpd_handle_t server);
 
 void KillTFliteTasks();

+ 14 - 0
code/components/jomjol_time_sntp/time_sntp.cpp

@@ -18,6 +18,7 @@
 static const char *TAG = "sntp";
 
 bool setTimeAlwaysOnReboot = true;
+time_t bootTime;
 
 static void obtain_time(void);
 static void initialize_sntp(void);
@@ -125,4 +126,17 @@ static void initialize_sntp(void)
     sntp_setservername(0, "pool.ntp.org");
 //    sntp_set_time_sync_notification_cb(time_sync_notification_cb);
     sntp_init();
+}
+
+void setBootTime() 
+{
+    time(&bootTime);
+}
+
+time_t getUpTime() 
+{
+    time_t now;
+    time(&now);
+
+    return now - bootTime;
 }

+ 4 - 1
code/components/jomjol_time_sntp/time_sntp.h

@@ -18,4 +18,7 @@ std::string gettimestring(const char * frm);
 std::string ConvertTimeToString(time_t _time, const char * frm);
 
 void setTimeZone(std::string _tzstring);
-void reset_servername(std::string _servername);
+void reset_servername(std::string _servername);
+
+void setBootTime();
+time_t getUpTime();

+ 6 - 0
code/include/defines.h

@@ -0,0 +1,6 @@
+#ifndef defines_h
+#define defines_h
+
+#define CONFIG_FILE "/sdcard/config/config.ini"
+
+#endif // ifndef defines_h

+ 15 - 16
code/main/main.cpp

@@ -19,6 +19,7 @@
 #include "connect_wlan.h"
 #include "read_wlanini.h"
 
+#include "server_main.h"
 #include "server_tflite.h"
 #include "server_file.h"
 #include "server_ota.h"
@@ -30,16 +31,14 @@
 
 #define __SD_USE_ONE_LINE_MODE__
 
-#ifdef __SD_USE_ONE_LINE_MODE__
 #include "server_GPIO.h"
-#endif
 
 
 #define BLINK_GPIO GPIO_NUM_33
 
-static const char *TAGMAIN = "connect_wlan_main";
+static const char *TAGMAIN = "main";
 
-#define FLASH_GPIO GPIO_NUM_4
+//#define FLASH_GPIO GPIO_NUM_4
 
 bool Init_NVS_SDCard()
 {
@@ -50,7 +49,7 @@ bool Init_NVS_SDCard()
     }
 ////////////////////////////////////////////////
 
-    ESP_LOGI(TAG, "Using SDMMC peripheral");
+    ESP_LOGI(TAGMAIN, "Using SDMMC peripheral");
     sdmmc_host_t host = SDMMC_HOST_DEFAULT();
 
     // This initializes the slot without card detect (CD) and write protect (WP) signals.
@@ -92,10 +91,10 @@ bool Init_NVS_SDCard()
 
     if (ret != ESP_OK) {
         if (ret == ESP_FAIL) {
-            ESP_LOGE(TAG, "Failed to mount filesystem. "
+            ESP_LOGE(TAGMAIN, "Failed to mount filesystem. "
                 "If you want the card to be formatted, set format_if_mount_failed = true.");
         } else {
-            ESP_LOGE(TAG, "Failed to initialize the card (%s). "
+            ESP_LOGE(TAGMAIN, "Failed to initialize the card (%s). "
                 "Make sure SD card lines have pull-up resistors in place.", esp_err_to_name(ret));
         }
         return false;
@@ -108,9 +107,9 @@ bool Init_NVS_SDCard()
 	// Init the GPIO
     // Flash ausschalten
     
-    gpio_pad_select_gpio(FLASH_GPIO);
-    gpio_set_direction(FLASH_GPIO, GPIO_MODE_OUTPUT);  
-    gpio_set_level(FLASH_GPIO, 0);   
+    // gpio_pad_select_gpio(FLASH_GPIO);
+    // gpio_set_direction(FLASH_GPIO, GPIO_MODE_OUTPUT);  
+    // gpio_set_level(FLASH_GPIO, 0);   
 
     return true;
 }
@@ -174,11 +173,12 @@ extern "C" void app_main(void)
     
     TickType_t xDelay;
     xDelay = 2000 / portTICK_PERIOD_MS;
-    printf("Autoflow: sleep for : %ldms\n", (long) xDelay);
+    printf("main: sleep for : %ldms\n", (long) xDelay);
 //    LogFile.WriteToFile("Startsequence 06");      
     vTaskDelay( xDelay );   
 //    LogFile.WriteToFile("Startsequence 07");  
     setup_time();
+    setBootTime();
     LogFile.WriteToFile("=============================================================================================");
     LogFile.WriteToFile("=================================== Main Started ============================================");
     LogFile.WriteToFile("=============================================================================================");
@@ -190,7 +190,7 @@ extern "C" void app_main(void)
 //    Camera.InitCam();
 //    Camera.LightOnOff(false); 
     xDelay = 2000 / portTICK_PERIOD_MS;
-    printf("Autoflow: sleep for : %ldms\n", (long) xDelay);
+    printf("main: sleep for : %ldms\n", (long) xDelay);
     vTaskDelay( xDelay ); 
 
     server = start_webserver();   
@@ -199,13 +199,12 @@ extern "C" void app_main(void)
     register_server_file_uri(server, "/sdcard");
     register_server_ota_sdcard_uri(server);
 
-#ifdef __SD_USE_ONE_LINE_MODE__
-    register_server_GPIO_uri(server);
-#endif    
-    printf("vor reg server main\n");
+    gpio_handler_create(server);
 
+    printf("vor reg server main\n");
     register_server_main_uri(server, "/sdcard");
 
     printf("vor dotautostart\n");
     TFliteDoAutoStart();
 }
+

+ 12 - 11
code/main/server_main.cpp

@@ -20,9 +20,9 @@
 
 
 httpd_handle_t server = NULL;   
-
 std::string starttime = "";
 
+static const char *TAG_SERVERMAIN = "server-main";
 
 /* An HTTP GET handler */
 esp_err_t info_get_handler(httpd_req_t *req)
@@ -198,7 +198,7 @@ esp_err_t hello_main_handler(httpd_req_t *req)
     printf("File requested: %s\n", filetosend.c_str());    
 
     if (!filename) {
-        ESP_LOGE(TAG, "Filename is too long");
+        ESP_LOGE(TAG_SERVERMAIN, "Filename is too long");
         /* Respond with 500 Internal Server Error */
         httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Filename too long");
         return ESP_FAIL;
@@ -299,7 +299,9 @@ esp_err_t sysinfo_handler(httpd_req_t *req)
     std::string gitbranch = libfive_git_branch();
     std::string gitbasebranch = git_base_branch();
     std::string htmlversion = getHTMLversion();
-
+    char freeheapmem[11];
+    sprintf(freeheapmem, "%zu", esp_get_free_heap_size());
+    
     tcpip_adapter_ip_info_t ip_info;
     ESP_ERROR_CHECK(tcpip_adapter_get_ip_info(TCPIP_ADAPTER_IF_STA, &ip_info));
     const char *hostname;
@@ -314,7 +316,8 @@ esp_err_t sysinfo_handler(httpd_req_t *req)
                 \"html\" : \"" + htmlversion + "\",\
                 \"cputemp\" : \"" + cputemp + "\",\
                 \"hostname\" : \"" + hostname + "\",\
-                \"IPv4\" : \"" + ip4addr_ntoa(&ip_info.ip) + "\"\
+                \"IPv4\" : \"" + ip4addr_ntoa(&ip_info.ip) + "\",\
+                \"freeHeapMem\" : \"" + freeheapmem + "\"\
             }\
         ]";
 
@@ -411,14 +414,14 @@ httpd_handle_t start_webserver(void)
     starttime = gettimestring("%Y%m%d-%H%M%S");
 
     // Start the httpd server
-    ESP_LOGI(TAG, "Starting server on port: '%d'", config.server_port);
+    ESP_LOGI(TAG_SERVERMAIN, "Starting server on port: '%d'", config.server_port);
     if (httpd_start(&server, &config) == ESP_OK) {
         // Set URI handlers
-        ESP_LOGI(TAG, "Registering URI handlers");
+        ESP_LOGI(TAG_SERVERMAIN, "Registering URI handlers");
         return server;
     }
 
-    ESP_LOGI(TAG, "Error starting server!");
+    ESP_LOGI(TAG_SERVERMAIN, "Error starting server!");
     return NULL;
 }
 
@@ -433,7 +436,7 @@ void disconnect_handler(void* arg, esp_event_base_t event_base,
 {
     httpd_handle_t* server = (httpd_handle_t*) arg;
     if (*server) {
-        ESP_LOGI(TAG, "Stopping webserver");
+        ESP_LOGI(TAG_SERVERMAIN, "Stopping webserver");
         stop_webserver(*server);
         *server = NULL;
     }
@@ -444,9 +447,7 @@ void connect_handler(void* arg, esp_event_base_t event_base,
 {
     httpd_handle_t* server = (httpd_handle_t*) arg;
     if (*server == NULL) {
-        ESP_LOGI(TAG, "Starting webserver");
+        ESP_LOGI(TAG_SERVERMAIN, "Starting webserver");
         *server = start_webserver();
     }
 }
-
-

+ 3 - 4
code/main/server_main.h

@@ -8,18 +8,17 @@
 #include <nvs_flash.h>
 #include <sys/param.h>
 #include "nvs_flash.h"
-#include "tcpip_adapter.h"
+#include "esp_netif.h"
 #include "esp_eth.h"
-
+#include "server_GPIO.h"
 
 #include <esp_http_server.h>
 
-static const char *TAG = "server-main";
-
 extern httpd_handle_t server;
 
 httpd_handle_t start_webserver(void);
 
 void register_server_main_uri(httpd_handle_t server, const char *base_path);
 
+
 #endif

+ 2 - 2
code/main/version.cpp

@@ -1,4 +1,4 @@
-const char* GIT_REV="d7bb147";
+const char* GIT_REV="a7ced40";
 const char* GIT_TAG="";
 const char* GIT_BRANCH="rolling";
-const char* BUILD_TIME="2021-07-11 17:52";
+const char* BUILD_TIME="2021-07-11 14:48";

+ 1 - 1
code/main/version.h

@@ -13,7 +13,7 @@ extern "C"
 #include "Helper.h"
 #include <fstream>
 
-const char* GIT_BASE_BRANCH = "master - v7.1.0 - 2020-05-28";
+const char* GIT_BASE_BRANCH = "master - v7.1.1 - 2020-05-30";
 
 
 const char* git_base_branch(void)

+ 3 - 1
code/platformio.ini

@@ -22,7 +22,8 @@ framework = espidf
 ;board_build.partitions = partitions_singleapp.csv
 board_build.partitions = partitions.csv
 
-lib_deps = 
+lib_deps =
+  jomjol_configfile 
   jomjol_helper 
   jomjol_wlan  
   jomjol_image_proc 
@@ -36,6 +37,7 @@ lib_deps =
   jomjol_mqtt
   jomjol_controlGPIO
 
+
 monitor_speed = 115200
 monitor_rts = 0
 monitor_dtr = 0

+ 2 - 2
code/version.cpp

@@ -1,4 +1,4 @@
-const char* GIT_REV="d7bb147";
+const char* GIT_REV="a7ced40";
 const char* GIT_TAG="";
 const char* GIT_BRANCH="rolling";
-const char* BUILD_TIME="2021-07-11 17:52";
+const char* BUILD_TIME="2021-07-11 14:48";

BIN
firmware/bootloader.bin


BIN
firmware/firmware.bin


BIN
firmware/html.zip


+ 9 - 0
sd-card/config/config.ini

@@ -55,6 +55,15 @@ CheckDigitIncreaseConsistency = true
 ;user = USERNAME
 ;password = PASSWORD
 
+;[GPIO]
+;MainTopicMQTT = wasserzaehler/GPIO
+;IO0 = input disabled 10 false false  
+;IO1 = input disabled 10 false false 
+;IO3 = input disabled 10 false false 
+;IO4 = built-in-led disabled 10 false false 
+;IO12 = input-pullup disabled 10 false false 
+;IO13 = input-pullup disabled 10 false false 
+
 [AutoTimer]
 AutoStart = true
 Intervall = 4.85

File diff suppressed because it is too large
+ 722 - 78
sd-card/html/edit_config_param.html


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

@@ -5,12 +5,12 @@ function gethost_Version(){
 
 function getbasepath(){
     var host = window.location.hostname;
-    if ((host == "127.0.0.1") || (host == "localhost"))
+    if ((host == "127.0.0.1") || (host == "localhost") || (host == ""))
     {
 //        host = "http://192.168.2.219";          // jomjol interner test
-        host = "http://192.168.178.51";          // jomjol interner test
+//        host = "http://192.168.178.46";          // jomjol interner test
 //        host = "http://192.168.178.22";          // jomjol interner Real
-
+        host = "http://192.168.43.191";
 //        host = ".";                           // jomjol interner localhost   
 
     }

+ 25 - 9
sd-card/html/readconfigparam.js

@@ -70,11 +70,11 @@ function ParseConfig() {
      category[catname]["enabled"] = false;
      category[catname]["found"] = false;
      param[catname] = new Object();
-     ParamAddValue(param, catname, "DecimalShift", 1, true);
+     ParamAddValue(param, catname, "DecimalShift", 1);
      ParamAddValue(param, catname, "PreValueUse");
      ParamAddValue(param, catname, "PreValueAgeStartup");
      ParamAddValue(param, catname, "AllowNegativeRates");
-     ParamAddValue(param, catname, "MaxRateValue", 1, true);
+     ParamAddValue(param, catname, "MaxRateValue", 1);
      ParamAddValue(param, catname, "ErrorMessage");
      ParamAddValue(param, catname, "CheckDigitIncreaseConsistency");     
 
@@ -84,10 +84,23 @@ function ParseConfig() {
      category[catname]["found"] = false;
      param[catname] = new Object();
      ParamAddValue(param, catname, "Uri");
-     ParamAddValue(param, catname, "MainTopic");
+     ParamAddValue(param, catname, "MainTopic", 1, [/^([a-zA-Z0-9_-]+\/){0,10}[a-zA-Z0-9_-]+$/]);
      ParamAddValue(param, catname, "ClientID");
      ParamAddValue(param, catname, "user");
-     ParamAddValue(param, catname, "password");     
+     ParamAddValue(param, catname, "password");
+     
+     var catname = "GPIO";
+     category[catname] = new Object(); 
+     category[catname]["enabled"] = false;
+     category[catname]["found"] = false;
+     param[catname] = new Object();
+     ParamAddValue(param, catname, "MainTopicMQTT", 1, [/^([a-zA-Z0-9_-]+\/){0,10}[a-zA-Z0-9_-]+$/]);
+     ParamAddValue(param, catname, "IO0", 6, [null, null, /^[0-9]*$/, null, null, /^[a-zA-Z0-9_-]*$/]);
+     ParamAddValue(param, catname, "IO1", 6, [null, null, /^[0-9]*$/, null, null, /^[a-zA-Z0-9_-]*$/]);
+     ParamAddValue(param, catname, "IO3", 6, [null, null, /^[0-9]*$/, null, null, /^[a-zA-Z0-9_-]*$/]);
+     ParamAddValue(param, catname, "IO4", 6, [null, null, /^[0-9]*$/, null, null, /^[a-zA-Z0-9_-]*$/]);
+     ParamAddValue(param, catname, "IO12", 6, [null, null, /^[0-9]*$/, null, null, /^[a-zA-Z0-9_-]*$/]);
+     ParamAddValue(param, catname, "IO13", 6, [null, null, /^[0-9]*$/, null, null, /^[a-zA-Z0-9_-]*$/]);
 
      var catname = "AutoTimer";
      category[catname] = new Object(); 
@@ -136,13 +149,13 @@ function ParseConfig() {
      }
 }
 
-function ParamAddValue(param, _cat, _param, _anzParam = 1, _isIndividual = false){
+function ParamAddValue(param, _cat, _param, _anzParam = 1, _checkRegExList = null){
      param[_cat][_param] = new Object(); 
      param[_cat][_param]["found"] = false;
      param[_cat][_param]["enabled"] = false;
      param[_cat][_param]["line"] = -1; 
-     param[_cat][_param]["anzParam"] = _anzParam;    
-     param[_cat][_param]["Numbers"] = _isIndividual;
+     param[_cat][_param]["anzParam"] = _anzParam;
+     param[_cat][_param].checkRegExList = _checkRegExList;
 };
 
 function ParseConfigParamAll(_aktline, _catname){
@@ -188,9 +201,12 @@ function ParamExtractValue(_param, _linesplit, _catname, _paramname, _aktline, _
 
 function ParamExtractValueAll(_param, _linesplit, _catname, _aktline, _iscom){
      for (var paramname in _param[_catname]) {
-          _param_zw = _linesplit[0].substring(_linesplit[0].length - paramname.length, _linesplit[0].length);
-          if ((_param_zw.toUpperCase() == paramname.toUpperCase()) && (_linesplit.length > _param[_catname][paramname]["anzParam"]))
+          if (_linesplit[0].toUpperCase() == paramname.toUpperCase())
           {
+               while (_linesplit.length <= _param[_catname][paramname]["anzParam"]) {
+                    _linesplit.push("");
+               }
+
                _param[_catname][paramname]["found"] = true;
                _param[_catname][paramname]["enabled"] = !_iscom;
                _param[_catname][paramname]["line"] = _aktline;

Some files were not shown because too many files changed in this diff