diff --git a/README.md b/README.md index 46d2d3be..d956ba21 100644 --- a/README.md +++ b/README.md @@ -45,7 +45,23 @@ In other cases you can contact the developer via email: +#include #include #include #include diff --git a/code/components/jomjol_configfile/CMakeLists.txt b/code/components/jomjol_configfile/CMakeLists.txt new file mode 100644 index 00000000..dc5e71d5 --- /dev/null +++ b/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) + + diff --git a/code/components/jomjol_configfile/configFile.cpp b/code/components/jomjol_configfile/configFile.cpp new file mode 100644 index 00000000..f8c9aa02 --- /dev/null +++ b/code/components/jomjol_configfile/configFile.cpp @@ -0,0 +1,96 @@ +#include +#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 ConfigFile::ZerlegeZeile(std::string input, std::string delimiter) +{ + std::vector 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; + +} diff --git a/code/components/jomjol_configfile/configFile.h b/code/components/jomjol_configfile/configFile.h new file mode 100644 index 00000000..65b0143c --- /dev/null +++ b/code/components/jomjol_configfile/configFile.h @@ -0,0 +1,16 @@ +#include +#include + +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 ZerlegeZeile(std::string input, std::string delimiter = " =, \t"); + +private: + FILE* pFile; +}; \ No newline at end of file diff --git a/code/components/jomjol_controlGPIO/CMakeLists.txt b/code/components/jomjol_controlGPIO/CMakeLists.txt index c5ad1e71..b287de81 100644 --- a/code/components/jomjol_controlGPIO/CMakeLists.txt +++ b/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) diff --git a/code/components/jomjol_controlGPIO/server_GPIO.cpp b/code/components/jomjol_controlGPIO/server_GPIO.cpp index fb06e694..c54d66ec 100644 --- a/code/components/jomjol_controlGPIO/server_GPIO.cpp +++ b/code/components/jomjol_controlGPIO/server_GPIO.cpp @@ -1,4 +1,5 @@ #include +#include #include "string.h" #include @@ -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 +#include +//#include + +#include "defines.h" #include "server_GPIO.h" #include "ClassLogFile.h" - +#include "configFile.h" #include "Helper.h" +#include "interface_mqtt.h" -// #define DEBUG_DETAIL_ON +static const char *TAG_SERVERGPIO = "server_GPIO"; +QueueHandle_t gpio_queue_handle = NULL; -esp_err_t handler_switch_GPIO(httpd_req_t *req) +#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 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(); + } 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::iterator it = gpioMap->begin(); it != gpioMap->end(); ++it) { + it->second->init(); + } + + std::function 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::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::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 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; +} + +void GpioHandler::clear() +{ + ESP_LOGD(TAG_SERVERGPIO, "GpioHandler::clear\r\n"); + + if (gpioMap != NULL) { + for(std::map::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 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<::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()); + } + } + } + } } - -void register_server_GPIO_uri(httpd_handle_t server) +gpio_num_t GpioHandler::resolvePinNr(uint8_t pinNr) { - 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); - - initGPIO(); + 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; + } +} + +gpio_pin_mode_t GpioHandler::resolvePinMode(std::string input) +{ + 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; + } +} + +GpioHandler* gpio_handler_get() +{ + return gpioHandler; } diff --git a/code/components/jomjol_controlGPIO/server_GPIO.h b/code/components/jomjol_controlGPIO/server_GPIO.h index f91e24c2..14d88412 100644 --- a/code/components/jomjol_controlGPIO/server_GPIO.h +++ b/code/components/jomjol_controlGPIO/server_GPIO.h @@ -1,10 +1,99 @@ +#ifndef SERVER_GPIO_H +#define SERVER_GPIO_H + #include #include +#include +#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; -void register_server_GPIO_uri(httpd_handle_t server); +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 *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(); + + + +#endif //SERVER_GPIO_H \ No newline at end of file diff --git a/code/components/jomjol_controlcamera/CMakeLists.txt b/code/components/jomjol_controlcamera/CMakeLists.txt index f006f013..ec401f60 100644 --- a/code/components/jomjol_controlcamera/CMakeLists.txt +++ b/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) diff --git a/code/components/jomjol_controlcamera/ClassControllCamera.cpp b/code/components/jomjol_controlcamera/ClassControllCamera.cpp index b7f80d38..defa7777 100644 --- a/code/components/jomjol_controlcamera/ClassControllCamera.cpp +++ b/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 +#include #include #include #include @@ -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) diff --git a/code/components/jomjol_controlcamera/ClassControllCamera.h b/code/components/jomjol_controlcamera/ClassControllCamera.h index b4389b8a..796a298e 100644 --- a/code/components/jomjol_controlcamera/ClassControllCamera.h +++ b/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; diff --git a/code/components/jomjol_controlcamera/server_camera.cpp b/code/components/jomjol_controlcamera/server_camera.cpp index d318a736..09cef729 100644 --- a/code/components/jomjol_controlcamera/server_camera.cpp +++ b/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 diff --git a/code/components/jomjol_controlcamera/server_camera.h b/code/components/jomjol_controlcamera/server_camera.h index b3f1fe19..ac58ca78 100644 --- a/code/components/jomjol_controlcamera/server_camera.h +++ b/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(); diff --git a/code/components/jomjol_fileserver_ota/CMakeLists.txt b/code/components/jomjol_fileserver_ota/CMakeLists.txt index 752bc5d1..58355dfe 100644 --- a/code/components/jomjol_fileserver_ota/CMakeLists.txt +++ b/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) diff --git a/code/components/jomjol_fileserver_ota/server_file.cpp b/code/components/jomjol_fileserver_ota/server_file.cpp index 26bf32b0..289d7bb6 100644 --- a/code/components/jomjol_fileserver_ota/server_file.cpp +++ b/code/components/jomjol_fileserver_ota/server_file.cpp @@ -26,9 +26,12 @@ #include #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, "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, diff --git a/code/components/jomjol_fileserver_ota/server_ota.cpp b/code/components/jomjol_fileserver_ota/server_ota.cpp index 6c69ae1e..39f4d7e9 100644 --- a/code/components/jomjol_fileserver_ota/server_ota.cpp +++ b/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 #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!

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(); } diff --git a/code/components/jomjol_fileserver_ota/server_ota.h b/code/components/jomjol_fileserver_ota/server_ota.h index e227d146..415e5fd9 100644 --- a/code/components/jomjol_fileserver_ota/server_ota.h +++ b/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(); diff --git a/code/components/jomjol_flowcontroll/ClassFlowAnalog.cpp b/code/components/jomjol_flowcontroll/ClassFlowAnalog.cpp index c38d15b5..91cf5fc6 100644 --- a/code/components/jomjol_flowcontroll/ClassFlowAnalog.cpp +++ b/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 diff --git a/code/components/jomjol_flowcontroll/ClassFlowControll.cpp b/code/components/jomjol_flowcontroll/ClassFlowControll.cpp index 10013455..7cc091e1 100644 --- a/code/components/jomjol_flowcontroll/ClassFlowControll.cpp +++ b/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) { diff --git a/code/components/jomjol_flowcontroll/ClassFlowDigit.cpp b/code/components/jomjol_flowcontroll/ClassFlowDigit.cpp index dad5fcfe..0c214a63 100644 --- a/code/components/jomjol_flowcontroll/ClassFlowDigit.cpp +++ b/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 diff --git a/code/components/jomjol_flowcontroll/ClassFlowMQTT.cpp b/code/components/jomjol_flowcontroll/ClassFlowMQTT.cpp index d4ad7bbe..4748b0d7 100644 --- a/code/components/jomjol_flowcontroll/ClassFlowMQTT.cpp +++ b/code/components/jomjol_flowcontroll/ClassFlowMQTT.cpp @@ -1,6 +1,8 @@ +#include #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 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; diff --git a/code/components/jomjol_flowcontroll/ClassFlowMQTT.h b/code/components/jomjol_flowcontroll/ClassFlowMQTT.h index 71ff8455..c79e9b13 100644 --- a/code/components/jomjol_flowcontroll/ClassFlowMQTT.h +++ b/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; diff --git a/code/components/jomjol_helper/Helper.cpp b/code/components/jomjol_helper/Helper.cpp index fdbd8644..07f7e7e0 100644 --- a/code/components/jomjol_helper/Helper.cpp +++ b/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() diff --git a/code/components/jomjol_helper/Helper.h b/code/components/jomjol_helper/Helper.h index ac6cccae..46fbf8d6 100644 --- a/code/components/jomjol_helper/Helper.h +++ b/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(); diff --git a/code/components/jomjol_logfile/ClassLogFile.cpp b/code/components/jomjol_logfile/ClassLogFile.cpp index 71825ca7..a026d985 100644 --- a/code/components/jomjol_logfile/ClassLogFile.cpp +++ b/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(); diff --git a/code/components/jomjol_mqtt/interface_mqtt.cpp b/code/components/jomjol_mqtt/interface_mqtt.cpp index 7fde4733..3230cb8f 100644 --- a/code/components/jomjol_mqtt/interface_mqtt.cpp +++ b/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>* connectFunktionMap = NULL; +std::map>* 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 func){ + ESP_LOGD(TAG_INTERFACEMQTT, "MQTTregisteronnectFunction %s\r\n", name.c_str()); + if (connectFunktionMap == NULL) { + connectFunktionMap = new std::map>(); + } + + 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 func){ + ESP_LOGD(TAG_INTERFACEMQTT, "MQTTregisterSubscribeFunction %s\r\n", topic.c_str()); + if (subscribeFunktionMap == NULL) { + subscribeFunktionMap = new std::map>(); + } + + 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>::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>::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>::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; + } +} \ No newline at end of file diff --git a/code/components/jomjol_mqtt/interface_mqtt.h b/code/components/jomjol_mqtt/interface_mqtt.h index f514ea2d..50990e6f 100644 --- a/code/components/jomjol_mqtt/interface_mqtt.h +++ b/code/components/jomjol_mqtt/interface_mqtt.h @@ -1,7 +1,23 @@ +#ifndef INTERFACE_MQTT_H +#define INTERFACE_MQTT_H + #include +#include +#include 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); \ No newline at end of file +void MQTTPublish(std::string _key, std::string _content, int retained_flag = 0); + +bool MQTTisConnected(); + +void MQTTregisterConnectFunction(std::string name, std::function func); +void MQTTunregisterConnectFunction(std::string name); +void MQTTregisterSubscribeFunction(std::string topic, std::function func); +void MQTTdestroySubscribeFunction(); +void MQTTconnected(); + +#endif //INTERFACE_MQTT_H \ No newline at end of file diff --git a/code/components/jomjol_tfliteclass/CTfLiteClass.cpp b/code/components/jomjol_tfliteclass/CTfLiteClass.cpp index d0a529f5..e2e20227 100644 --- a/code/components/jomjol_tfliteclass/CTfLiteClass.cpp +++ b/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; } diff --git a/code/components/jomjol_tfliteclass/CTfLiteClass.h b/code/components/jomjol_tfliteclass/CTfLiteClass.h index 07279f14..4c6ed8f7 100644 --- a/code/components/jomjol_tfliteclass/CTfLiteClass.h +++ b/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); diff --git a/code/components/jomjol_tfliteclass/server_tflite.cpp b/code/components/jomjol_tfliteclass/server_tflite.cpp index 3859fd98..d6b42067 100644 --- a/code/components/jomjol_tfliteclass/server_tflite.cpp +++ b/code/components/jomjol_tfliteclass/server_tflite.cpp @@ -8,6 +8,7 @@ #include #include +#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
"; + const char* resp_str = "Init started
"; 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() diff --git a/code/components/jomjol_tfliteclass/server_tflite.h b/code/components/jomjol_tfliteclass/server_tflite.h index 148be20e..cb39a10f 100644 --- a/code/components/jomjol_tfliteclass/server_tflite.h +++ b/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(); diff --git a/code/components/jomjol_time_sntp/time_sntp.cpp b/code/components/jomjol_time_sntp/time_sntp.cpp index 51f9175d..240a36d9 100644 --- a/code/components/jomjol_time_sntp/time_sntp.cpp +++ b/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; } \ No newline at end of file diff --git a/code/components/jomjol_time_sntp/time_sntp.h b/code/components/jomjol_time_sntp/time_sntp.h index da37ae0b..c56e6c91 100644 --- a/code/components/jomjol_time_sntp/time_sntp.h +++ b/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); \ No newline at end of file +void reset_servername(std::string _servername); + +void setBootTime(); +time_t getUpTime(); diff --git a/code/include/defines.h b/code/include/defines.h new file mode 100644 index 00000000..436b0baa --- /dev/null +++ b/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 \ No newline at end of file diff --git a/code/main/main.cpp b/code/main/main.cpp index 75dee4f9..145f862f 100644 --- a/code/main/main.cpp +++ b/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(); } + diff --git a/code/main/server_main.cpp b/code/main/server_main.cpp index 5885e48d..de2683e3 100644 --- a/code/main/server_main.cpp +++ b/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(); } } - - diff --git a/code/main/server_main.h b/code/main/server_main.h index e4f75b4c..00033b66 100644 --- a/code/main/server_main.h +++ b/code/main/server_main.h @@ -8,18 +8,17 @@ #include #include #include "nvs_flash.h" -#include "tcpip_adapter.h" +#include "esp_netif.h" #include "esp_eth.h" - +#include "server_GPIO.h" #include -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 diff --git a/code/main/version.cpp b/code/main/version.cpp index 76ed6f94..ad0a3677 100644 --- a/code/main/version.cpp +++ b/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"; \ No newline at end of file +const char* BUILD_TIME="2021-07-11 14:48"; \ No newline at end of file diff --git a/code/main/version.h b/code/main/version.h index d900509d..d470870a 100644 --- a/code/main/version.h +++ b/code/main/version.h @@ -13,7 +13,7 @@ extern "C" #include "Helper.h" #include -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) diff --git a/code/platformio.ini b/code/platformio.ini index be60a9b8..ebdc5da7 100644 --- a/code/platformio.ini +++ b/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 diff --git a/code/version.cpp b/code/version.cpp index 76ed6f94..ad0a3677 100644 --- a/code/version.cpp +++ b/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"; \ No newline at end of file +const char* BUILD_TIME="2021-07-11 14:48"; \ No newline at end of file diff --git a/firmware/bootloader.bin b/firmware/bootloader.bin index 7e505c2e..a251b4b1 100644 Binary files a/firmware/bootloader.bin and b/firmware/bootloader.bin differ diff --git a/firmware/firmware.bin b/firmware/firmware.bin index 2f82d251..c1f6ea38 100644 Binary files a/firmware/firmware.bin and b/firmware/firmware.bin differ diff --git a/firmware/html.zip b/firmware/html.zip index 0231dda6..ebedd9a6 100644 Binary files a/firmware/html.zip and b/firmware/html.zip differ diff --git a/sd-card/config/config.ini b/sd-card/config/config.ini index fcfeb5a5..cad8a749 100644 --- a/sd-card/config/config.ini +++ b/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 diff --git a/sd-card/html/edit_config_param.html b/sd-card/html/edit_config_param.html index b05d5b37..185a5990 100644 --- a/sd-card/html/edit_config_param.html +++ b/sd-card/html/edit_config_param.html @@ -19,6 +19,27 @@ p {font-size: 1em;} textarea { font-size: 14px; } + +.description { + color: black; + font-size: 80%; +} + +.disabled { + color:lightgrey; +} + +.smallSelect { + width: 30px; +} + +.invalid-input { + background-color: #FFAA00; +} + +.hidden { + display: none; +} @@ -69,7 +90,7 @@ textarea { - + Location to store raw images for logging @@ -83,7 +104,7 @@ textarea { - + Time to keep the raw image (in days -"0" = forever) @@ -97,7 +118,7 @@ textarea { - + Wait time between illumination switch on and take the picture (in seconds) @@ -110,7 +131,7 @@ textarea { - + Quality index for picture (default = "5" - "0" high ... "63" low) @@ -122,11 +143,11 @@ textarea { - + Picture size camera (default = "VGA") @@ -151,8 +172,8 @@ textarea { @@ -230,9 +251,9 @@ textarea { @@ -293,8 +314,8 @@ textarea { ModelInputSize - x: - y: + x: + y: Size of the input image for the CNN model @@ -337,8 +358,8 @@ textarea { @@ -353,8 +374,8 @@ textarea { ModelInputSize - x: - y: + x: + y: Size of the input image for the CNN model @@ -371,8 +392,8 @@ textarea { @@ -402,8 +423,8 @@ textarea { @@ -419,8 +440,8 @@ textarea { @@ -436,8 +457,8 @@ textarea { @@ -574,8 +595,8 @@ textarea { @@ -596,6 +617,610 @@ textarea { + + +

+ GPIO Settings + Enabling GPIO handler, disable by default integrated flash light. Please enable it with GPIO4 settings. +

+ + + + + + + + + MainTopicMQTT + + + + + + MQTT main topic for GPIO + + + + + + + + + + GPIO 0 state + + + + + + + + GPIO 0 Usable with restrictions.
+ Must be disabled when camera is used.
+ Pin is used to activate flash mode and must therefore be HIGH when booting. + + + + + + GPIO 0 use interrupt + + + + + + + + GPIO 0 enable interrupt trigger + + + + + + GPIO 0 PWM duty resolution + + + + + + GPIO 0 LEDC PWM duty resolution in bit + + + + + + GPIO 0 enable MQTT + + + + + + GPIO 0 enable MQTT publishing/subscribing + + + + + + GPIO 0 enable HTTP + + + + + + GPIO 0 enable HTTP write/read + + + + + + GPIO 0 name + + + + + + GPIO 0 MQTT topic name (empty = GPIO0). Allowed characters (a-z, A-Z, 0-9, _, -) + + + + + + + + + + + GPIO 1 state + + + + + + + + GPIO 1
Used by default for serial communication as TX pin.
Required for seriales monitor.
+ + + + + + GPIO 1 use interrupt + + + + + + + + GPIO 1 enable interrupt trigger + + + + + + GPIO 1 PWM duty resolution + + + + + + GPIO 1 LEDC PWM duty resolution in bit + + + + + + GPIO 1 enable MQTT + + + + + + GPIO 1 enable MQTT publishing/subscribing + + + + + + GPIO 1 enable HTTP + + + + + + GPIO 1 enable HTTP write/read + + + + + + GPIO 1 name + + + + + + GPIO 1 MQTT topic name (empty = GPIO1). Allowed characters (a-z, A-Z, 0-9, _, -) + + + + + + + + + + + GPIO 3 state + + + + + + + + GPIO 3 Used by default for serial communication as RX pin. + + + + + + GPIO 3 use interrupt + + + + + + + + GPIO 3 Used by default for serial communication as RX pin. + + + + + + GPIO 3 PWM duty resolution + + + + + + GPIO 3 LEDC PWM duty resolution in bit + + + + + + GPIO 3 enable MQTT + + + + + + GPIO 3 enable MQTT publishing/subscribing + + + + + + GPIO 3 enable HTTP + + + + + + GPIO 3 enable HTTP write/read + + + + + + GPIO 3 name + + + + + + GPIO 3 MQTT topic name (empty = GPIO3). Allowed characters (a-z, A-Z, 0-9, _, -) + + + + + + + + + + + GPIO 4 state + + + + + + + + GPIO 4 Usable with restrictions.
+ Pin is used for build-in flash light. + + + + + + GPIO 4 use interrupt + + + + + + + + GPIO 4 enable interrupt trigger + + + + + + GPIO 4 PWM duty resolution + + + + + + GPIO 4 LEDC PWM duty resolution in bit + + + + + + GPIO 4 enable MQTT + + + + + + GPIO 4 enable MQTT publishing/subscribing + + + + + + GPIO 4 enable HTTP + + + + + + GPIO 4 enable HTTP write/read + + + + + + GPIO 4 name + + + + + + GPIO 4 MQTT topic name (empty = GPIO4). Allowed characters (a-z, A-Z, 0-9, _, -) + + + + + + + + + + + GPIO 12 state + + + + + + + + GPIO 12 is usable without restrictions + + + + + + GPIO 12 use interrupt + + + + + + + + GPIO 12 enable interrupt trigger + + + + + + GPIO 12 PWM duty resolution + + + + + + GPIO 12 LEDC PWM duty resolution in bit + + + + + + GPIO 12 enable MQTT + + + + + + GPIO 12 enable MQTT publishing/subscribing + + + + + + GPIO 12 enable HTTP + + + + + + GPIO 12 enable HTTP write/read + + + + + + GPIO 12 name + + + + + + GPIO 12 MQTT topic name (empty = GPIO12). Allowed characters (a-z, A-Z, 0-9, _, -) + + + + + + + + + + + GPIO 13 state + + + + + + + + GPIO 13 is usable without restrictions + + + + + + GPIO 13 use interrupt + + + + + + + + GPIO 13 enable interrupt trigger + + + + + + GPIO 13 PWM duty resolution + + + + + + GPIO 13 LEDC PWM duty resolution in bit + + + + + + GPIO 13 enable MQTT + + + + + + GPIO 13 enable MQTT publishing/subscribing + + + + + + GPIO 13 enable HTTP + + + + + + GPIO 13 enable HTTP write/read + + + + + + GPIO 13 name + + + + + + GPIO 13 MQTT topic name (empty = GPIO13). Allowed characters (a-z, A-Z, 0-9, _, -) + + + +

Debug

@@ -608,11 +1233,11 @@ textarea { - + Turn on/off the extended logging @@ -626,7 +1251,7 @@ textarea { - + Time to keep the log files (in days - "0" = forever) @@ -644,7 +1269,7 @@ textarea { - + Time zone in POSIX syntax (Europe/Berlin = "CET-1CEST,M3.5.0,M10.5.0/3" - incl. daylight saving) @@ -658,7 +1283,7 @@ textarea { - + Time server to synchronize system time (default: "pool.ntp.org" - used if nothing is specified) @@ -672,7 +1297,7 @@ textarea { - + Hostname for server - will be transfered to wlan.ini at next startup) @@ -709,7 +1334,6 @@ textarea { function LoadConfigNeu() { - var isInitialSetup = getParameterByName('InitialSetup'); if (isInitialSetup === 'true') { @@ -731,7 +1355,7 @@ function LoadConfigNeu() { UpdateInputIndividual(); UpdateExpertModus(); document.getElementById("divall").style.display = ''; - } +} function InitIndivParameter() { @@ -755,63 +1379,82 @@ function getParameterByName(name, url = window.location.href) { name = name.replace(/[\[\]]/g, '\\$&'); var regex = new RegExp('[?&]' + name + '(=([^&#]*)|&|#|$)'), results = regex.exec(url); - if (!results) return null; + + if (!results) return null; if (!results[2]) return ''; - return decodeURIComponent(results[2].replace(/\+/g, ' ')); + return decodeURIComponent(results[2].replace(/\+/g, ' ')); } -function WriteParameter(_param, _category, _cat, _name, _optional, _select = false, _anzpara = 1, _number = -1){ - if (_number > -1) - { - { - if (_optional) { - document.getElementById(_cat+"_"+_name+"_enabled").checked = _param[_cat][_name]["enabled"]; - for (var j = 1; j <= _anzpara; ++j) - document.getElementById(_cat+"_"+_name+"_value"+j).disabled = NUMBERS[_number][_cat][_name]["enabled"]; - } - document.getElementById(_cat+"_"+_name+"_text").style="color:black;" - if (_select) { - var textToFind; - textToFind = NUMBERS[_number][_cat][_name]["value1"]; - var dd = document.getElementById(_cat+"_"+_name+"_value1"); - for (var i = 0; i < dd.options.length; i++) { - if (dd.options[i].text.toLowerCase() === textToFind.toLowerCase()) { - dd.selectedIndex = i; +function WriteParameter(_param, _category, _cat, _name, _optional, _number = -1){ + + let anzpara = _param[_cat][_name].anzParam; + + if (_number > -1) { + if ((NUMBERS[_number] == undefined) || (NUMBERS[_number][_cat] == undefined) || (NUMBERS[_number][_cat][_name] == undefined)) + return; + + if (_optional) { + document.getElementById(_cat+"_"+_name+"_enabled").checked = NUMBERS[_number][_cat][_name]["enabled"]; + for (var j = 1; j <= anzpara; ++j) { + document.getElementById(_cat+"_"+_name+"_value"+j).disabled = !NUMBERS[_number][_cat][_name]["enabled"]; + } + } + document.getElementById(_cat+"_"+_name+"_text").style="color:black;" + setEnabled(_cat+"_"+_name, true); + + for (var j = 1; j <= anzpara; ++j) { + let element = document.getElementById(_cat+"_"+_name+"_value"+j); + if (element.tagName.toLowerCase() == "select") { + var textToFind = NUMBERS[_number][_cat][_name]["value"+j]; + if (textToFind == undefined) + continue; + + for (var i = 0; i < element.options.length; i++) { + if (element.options[i].value.toLowerCase() === textToFind.toLowerCase()) { + element.selectedIndex = i; break; } } } + else if ((element.getAttribute("type") != null) && (element.getAttribute("type").toLowerCase() == "checkbox")) { + element.checked = NUMBERS[_number][_cat][_name]["value"+j] == "true"; + } else { - for (var j = 1; j <= _anzpara; ++j) - document.getElementById(_cat+"_"+_name+"_value"+j).value = NUMBERS[_number][_cat][_name]["value"+j]; + element.value = NUMBERS[_number][_cat][_name]["value"+j]; } } } - else - { - { - if (_optional) { - document.getElementById(_cat+"_"+_name+"_enabled").checked = _param[_cat][_name]["enabled"]; - for (var j = 1; j <= _anzpara; ++j) - document.getElementById(_cat+"_"+_name+"_value"+j).disabled = !_param[_cat][_name]["enabled"]; - } - document.getElementById(_cat+"_"+_name+"_text").style="color:black;" - if (_select) { - var textToFind; - textToFind = _param[_cat][_name]["value1"]; - var dd = document.getElementById(_cat+"_"+_name+"_value1"); - for (var i = 0; i < dd.options.length; i++) { - if (dd.options[i].text.toLowerCase() === textToFind.toLowerCase()) { - dd.selectedIndex = i; + else { + if (_optional) { + document.getElementById(_cat+"_"+_name+"_enabled").checked = _param[_cat][_name]["enabled"]; + for (var j = 1; j <= anzpara; ++j) { + document.getElementById(_cat+"_"+_name+"_value"+j).disabled = !_param[_cat][_name]["enabled"]; + } + } + document.getElementById(_cat+"_"+_name+"_text").style="color:black;" + setEnabled(_cat+"_"+_name, true); + + for (var j = 1; j <= anzpara; ++j) { + let element = document.getElementById(_cat+"_"+_name+"_value"+j); + if (element.tagName.toLowerCase() == "select") { + var textToFind = _param[_cat][_name]["value"+j]; + if (textToFind == undefined) + continue; + + for (var i = 0; i < element.options.length; i++) { + if (element.options[i].value.toLowerCase() === textToFind.toLowerCase()) { + element.selectedIndex = i; break; } } } - else { - for (var j = 1; j <= _anzpara; ++j) - document.getElementById(_cat+"_"+_name+"_value"+j).value = _param[_cat][_name]["value"+j]; + else if ((element.getAttribute("type") != null) && (element.getAttribute("type").toLowerCase() == "checkbox")) { + element.checked = _param[_cat][_name]["value"+j] == "true"; } - } + else { + element.value = _param[_cat][_name]["value"+j]; + } + } } ///////////////// am Ende, falls Kategorie als gesamtes nicht ausgewählt --> deaktivieren @@ -819,11 +1462,12 @@ function WriteParameter(_param, _category, _cat, _name, _optional, _select = fal { if (_optional) { document.getElementById(_cat+"_"+_name+"_enabled").disabled = true; - for (var j = 1; j <= _anzpara; ++j) { + for (var j = 1; j <= anzpara; ++j) { document.getElementById(_cat+"_"+_name+"_value"+j).disabled = true; } } document.getElementById(_cat+"_"+_name+"_text").style="color:lightgrey;" + setEnabled(_cat+"_"+_name, false); } EnDisableItem(_category[_cat]["enabled"], _param, _category, _cat, _name, _optional); @@ -843,17 +1487,46 @@ function InvertEnableItem(_cat, _param) document.getElementById(_zw).disabled = !_isOn; document.getElementById(_zw).style = _color; - if (param[_cat][_param]["anzParam"] == 2) { - _color = "width: 30px;" + _color; - } + setEnabled(_cat + "_" + _param, _isOn); for (var j = 1; j <= param[_cat][_param]["anzParam"]; ++j) { document.getElementById(_cat+"_"+_param+"_value"+j).disabled = !_isOn; document.getElementById(_cat+"_"+_param+"_value"+j).style=_color; } +} - +function setEnabled(className, enabled) { + let elements = document.getElementsByClassName(className); + for (i = 0; i < elements.length; i++) { + if (enabled) { + elements[i].classList.remove("disabled"); + } else { + elements[i].classList.add("disabled"); + } + let inputs = elements[i].getElementsByTagName("input"); + for (j = 0; j < inputs.length; j++) { + if (inputs[j].id.endsWith("_enabled")) + continue; + + if (enabled) { + inputs[j].removeAttribute("disabled"); + } else { + inputs[j].setAttribute("disabled", "disabled"); + } + } + } +} + +function setVisible(className, visible) { + let elements = document.getElementsByClassName(className); + for (i = 0; i < elements.length; i++) { + if (visible) { + elements[i].classList.remove("hidden"); + } else { + elements[i].classList.add("hidden"); + } + } } function EnDisableItem(_status, _param, _category, _cat, _name, _optional, _number = -1) @@ -886,53 +1559,75 @@ function EnDisableItem(_status, _param, _category, _cat, _name, _optional, _numb document.getElementById(_cat+"_"+_name+"_text").disabled = !_status; document.getElementById(_cat+"_"+_name+"_text").style = _color; - if (_param[_cat][_name]["anzParam"] == 2) { - _color = "width: 30px;" + _color; - } + setEnabled(_cat+"_"+_name, _status); for (var j = 1; j <= _param[_cat][_name]["anzParam"]; ++j) { document.getElementById(_cat+"_"+_name+"_value"+j).disabled = !_status; document.getElementById(_cat+"_"+_name+"_value"+j).style=_color; } - } -function ReadParameter(_param, _cat, _name, _optional, _select = false, _number = -1){ - if (_number > -1) - { +function ReadParameter(_param, _cat, _name, _optional, _number = -1){ + if (_number > -1) { if (_cat == "Digits") - _cat = "digit" + _cat = "digit"; if (_cat == "Analog") - _cat = "analog" + _cat = "analog"; + + if ((NUMBERS[_number] == undefined) || (NUMBERS[_number][_cat] == undefined) || (NUMBERS[_number][_cat][_name] == undefined)) + return; + if (_optional) { - NUMBERS[_number][_cat][_name]["enabled"] = document.getElementById(_cat+"_"+_name+"_enabled").checked; + NUMBERS[_number][_cat][_name]["enabled"] = document.getElementById(_cat+"_"+_name+"_enabled").checked; } - if (_select) { - var sel = document.getElementById(_cat+"_"+_name+"_value1"); - NUMBERS[_number][_cat][_name]["value1"] = sel.options[sel.selectedIndex].text; - } - else { - for (var j = 1; j <= _param[_cat][_name]["anzParam"]; ++j) { - NUMBERS[_number][_cat][_name]["value"+j] = document.getElementById(_cat+"_"+_name+"_value"+j).value; + + for (var j = 1; j <= _param[_cat][_name]["anzParam"]; ++j) { + let element = document.getElementById(_cat+"_"+_name+"_value"+j); + if (element.tagName.toLowerCase() == "select") { + NUMBERS[_number][_cat][_name]["value"+j] = element.selectedIndex > -1 ? element.options[element.selectedIndex].value : ""; + } + else if ((element.getAttribute("type") != null) && (element.getAttribute("type").toLowerCase() == "checkbox")) { + NUMBERS[_number][_cat][_name]["value"+j] = element.checked; + } + else { + if ((NUMBERS[_number][_cat][_name].checkRegExList != null) && (NUMBERS[_number][_cat][_name].checkRegExList[j-1] != null)) { + if (!element.value.match(NUMBERS[_cat][_name].checkRegExList[j-1])) { + element.classList.add("invalid-input"); + } else { + element.classList.remove("invalid-input"); + } + } + NUMBERS[_number][_cat][_name]["value"+j] = element.value; } } } else { if (_optional) { - _param[_cat][_name]["enabled"] = document.getElementById(_cat+"_"+_name+"_enabled").checked; + _param[_cat][_name]["enabled"] = document.getElementById(_cat+"_"+_name+"_enabled").checked; } - if (_select) { - var sel = document.getElementById(_cat+"_"+_name+"_value1"); - _param[_cat][_name]["value1"] = sel.options[sel.selectedIndex].text; - } - else { - for (var j = 1; j <= _param[_cat][_name]["anzParam"]; ++j) { - _param[_cat][_name]["value"+j] = document.getElementById(_cat+"_"+_name+"_value"+j).value; + + for (var j = 1; j <= _param[_cat][_name]["anzParam"]; ++j) { + let element = document.getElementById(_cat+"_"+_name+"_value"+j); + if (element.tagName.toLowerCase() == "select") { + _param[_cat][_name]["value"+j] = element.selectedIndex > -1 ? element.options[element.selectedIndex].value : ""; } - } + else if ((element.getAttribute("type") != null) && (element.getAttribute("type").toLowerCase() == "checkbox")) { + _param[_cat][_name]["value"+j] = element.checked; + } + else { + if ((_param[_cat][_name].checkRegExList != null) && (_param[_cat][_name].checkRegExList[j-1] != null)) { + if (!element.value.match(_param[_cat][_name].checkRegExList[j-1])) { + element.classList.add("invalid-input"); + } else { + element.classList.remove("invalid-input"); + } + } + _param[_cat][_name]["value"+j] = element.value; + } + } } } @@ -940,20 +1635,22 @@ function UpdateInputIndividual() { if (NUNBERSAkt != -1) { - ReadParameter(param, "PostProcessing", "DecimalShift", true, false, NUNBERSAkt) - ReadParameter(param, "PostProcessing", "MaxRateValue", true, false, NUNBERSAkt) + ReadParameter(param, "PostProcessing", "DecimalShift", true, NUNBERSAkt) + ReadParameter(param, "PostProcessing", "MaxRateValue", true, NUNBERSAkt) } var sel = document.getElementById("Numbers_value1"); NUNBERSAkt = sel.selectedIndex; - WriteParameter(param, category, "PostProcessing", "DecimalShift", true, false, 1, NUNBERSAkt); - WriteParameter(param, category, "PostProcessing", "MaxRateValue", true, false, 1, NUNBERSAkt); + WriteParameter(param, category, "PostProcessing", "DecimalShift", true, NUNBERSAkt); + WriteParameter(param, category, "PostProcessing", "MaxRateValue", true, NUNBERSAkt); } function UpdateInput() { document.getElementById("Category_Analog_enabled").checked = category["Analog"]["enabled"]; document.getElementById("Category_Digits_enabled").checked = category["Digits"]["enabled"]; document.getElementById("Category_MQTT_enabled").checked = category["MQTT"]["enabled"]; + document.getElementById("Category_GPIO_enabled").checked = category["GPIO"]["enabled"]; + setVisible("GPIO_item", category["GPIO"]["enabled"]); WriteParameter(param, category, "MakeImage", "LogImageLocation", true); WriteParameter(param, category, "MakeImage", "LogfileRetentionInDays", true); @@ -962,46 +1659,54 @@ function UpdateInput() { WriteParameter(param, category, "MakeImage", "Brightness", false); // WriteParameter(param, category, "MakeImage", "Contrast", false); // WriteParameter(param, category, "MakeImage", "Saturation", false); - WriteParameter(param, category, "MakeImage", "ImageSize", false, true, true); - WriteParameter(param, category, "MakeImage", "FixedExposure", false, true, true); + WriteParameter(param, category, "MakeImage", "ImageSize", false, true); + WriteParameter(param, category, "MakeImage", "FixedExposure", false, true); WriteParameter(param, category, "Alignment", "SearchFieldX", false); WriteParameter(param, category, "Alignment", "SearchFieldY", false); - WriteParameter(param, category, "Alignment", "AlignmentAlgo", true, true, true); + WriteParameter(param, category, "Alignment", "AlignmentAlgo", true, true); WriteParameter(param, category, "Digits", "Model", false); WriteParameter(param, category, "Digits", "LogImageLocation", true); WriteParameter(param, category, "Digits", "LogfileRetentionInDays", true); - WriteParameter(param, category, "Digits", "ModelInputSize", false, false, 2); + WriteParameter(param, category, "Digits", "ModelInputSize", false); WriteParameter(param, category, "Analog", "Model", false); WriteParameter(param, category, "Analog", "LogImageLocation", true); WriteParameter(param, category, "Analog", "LogfileRetentionInDays", true); - WriteParameter(param, category, "Analog", "ExtendedResolution", true, true); - WriteParameter(param, category, "Analog", "ModelInputSize", false, false, 2); + WriteParameter(param, category, "Analog", "ExtendedResolution", true); + WriteParameter(param, category, "Analog", "ModelInputSize", false); - WriteParameter(param, category, "PostProcessing", "PreValueUse", true, true); + WriteParameter(param, category, "PostProcessing", "PreValueUse", true); WriteParameter(param, category, "PostProcessing", "PreValueAgeStartup", true); - WriteParameter(param, category, "PostProcessing", "AllowNegativeRates", true, true); + WriteParameter(param, category, "PostProcessing", "AllowNegativeRates", true); // WriteParameter(param, category, "PostProcessing", "MaxRateValue", true); - WriteParameter(param, category, "PostProcessing", "ErrorMessage", true, true); - WriteParameter(param, category, "PostProcessing", "CheckDigitIncreaseConsistency", true, true); + WriteParameter(param, category, "PostProcessing", "ErrorMessage", true); + WriteParameter(param, category, "PostProcessing", "CheckDigitIncreaseConsistency", true); WriteParameter(param, category, "MQTT", "Uri", true); WriteParameter(param, category, "MQTT", "MainTopic", true); WriteParameter(param, category, "MQTT", "ClientID", true); WriteParameter(param, category, "MQTT", "user", true); - WriteParameter(param, category, "MQTT", "password", true); + WriteParameter(param, category, "MQTT", "password", true); + + WriteParameter(param, category, "GPIO", "MainTopicMQTT", true); + WriteParameter(param, category, "GPIO", "IO0", true); + WriteParameter(param, category, "GPIO", "IO1", true); + WriteParameter(param, category, "GPIO", "IO3", true); + WriteParameter(param, category, "GPIO", "IO4", true); + WriteParameter(param, category, "GPIO", "IO12", true); + WriteParameter(param, category, "GPIO", "IO13", true); - WriteParameter(param, category, "AutoTimer", "AutoStart", false, true); + WriteParameter(param, category, "AutoTimer", "AutoStart", false); WriteParameter(param, category, "AutoTimer", "Intervall", false); - WriteParameter(param, category, "Debug", "Logfile", true, true); + WriteParameter(param, category, "Debug", "Logfile", true); WriteParameter(param, category, "Debug", "LogfileRetentionInDays", true); WriteParameter(param, category, "System", "TimeZone", true); WriteParameter(param, category, "System", "Hostname", true); - WriteParameter(param, category, "System", "TimeServer", true); + WriteParameter(param, category, "System", "TimeServer", true); } function ReadParameterAll() @@ -1009,7 +1714,8 @@ function ReadParameterAll() category["Analog"]["enabled"] = document.getElementById("Category_Analog_enabled").checked; category["Digits"]["enabled"] = document.getElementById("Category_Digits_enabled").checked; category["MQTT"]["enabled"] = document.getElementById("Category_MQTT_enabled").checked; - + category["GPIO"]["enabled"] = document.getElementById("Category_GPIO_enabled").checked; + ReadParameter(param, "MakeImage", "LogImageLocation", true); ReadParameter(param, "MakeImage", "LogfileRetentionInDays", true); ReadParameter(param, "MakeImage", "WaitBeforeTakingPicture", false); @@ -1017,30 +1723,30 @@ function ReadParameterAll() ReadParameter(param, "MakeImage", "Brightness", false); // ReadParameter(param, "MakeImage", "Contrast", false); // ReadParameter(param, "MakeImage", "Saturation", false); - ReadParameter(param, "MakeImage", "ImageSize", false, true); - ReadParameter(param, "MakeImage", "FixedExposure", false, true); + ReadParameter(param, "MakeImage", "ImageSize", false); + ReadParameter(param, "MakeImage", "FixedExposure", false); ReadParameter(param, "Alignment", "SearchFieldX", false); ReadParameter(param, "Alignment", "SearchFieldY", false); - ReadParameter(param, "Alignment", "AlignmentAlgo", true, true); + ReadParameter(param, "Alignment", "AlignmentAlgo", true); ReadParameter(param, "Digits", "Model", false); ReadParameter(param, "Digits", "LogImageLocation", true); ReadParameter(param, "Digits", "LogfileRetentionInDays", true); - ReadParameter(param, "Digits", "ModelInputSize", false, false); + ReadParameter(param, "Digits", "ModelInputSize", false); ReadParameter(param, "Analog", "Model", false); ReadParameter(param, "Analog", "LogImageLocation", true); ReadParameter(param, "Analog", "LogfileRetentionInDays", true); - ReadParameter(param, "Analog", "ExtendedResolution", true, true); - ReadParameter(param, "Analog", "ModelInputSize", false, false); + ReadParameter(param, "Analog", "ExtendedResolution", true); + ReadParameter(param, "Analog", "ModelInputSize", false); - ReadParameter(param, "PostProcessing", "PreValueUse", true, true); + ReadParameter(param, "PostProcessing", "PreValueUse", true); ReadParameter(param, "PostProcessing", "PreValueAgeStartup", true); - ReadParameter(param, "PostProcessing", "AllowNegativeRates", true, true); + ReadParameter(param, "PostProcessing", "AllowNegativeRates", true); ReadParameter(param, "PostProcessing", "MaxRateValue", true); - ReadParameter(param, "PostProcessing", "ErrorMessage", true, true); - ReadParameter(param, "PostProcessing", "CheckDigitIncreaseConsistency", true, true); + ReadParameter(param, "PostProcessing", "ErrorMessage", true); + ReadParameter(param, "PostProcessing", "CheckDigitIncreaseConsistency", true); ReadParameter(param, "MQTT", "Uri", true); ReadParameter(param, "MQTT", "MainTopic", true); @@ -1048,10 +1754,18 @@ function ReadParameterAll() ReadParameter(param, "MQTT", "user", true); ReadParameter(param, "MQTT", "password", true); - ReadParameter(param, "AutoTimer", "AutoStart", false, true); + ReadParameter(param, "GPIO", "MainTopicMQTT", true); + ReadParameter(param, "GPIO", "IO0", true); + ReadParameter(param, "GPIO", "IO1", true); + ReadParameter(param, "GPIO", "IO3", true); + ReadParameter(param, "GPIO", "IO4", true); + ReadParameter(param, "GPIO", "IO12", true); + ReadParameter(param, "GPIO", "IO13", true); + + ReadParameter(param, "AutoTimer", "AutoStart", false); ReadParameter(param, "AutoTimer", "Intervall", false); - ReadParameter(param, "Debug", "Logfile", true, true); + ReadParameter(param, "Debug", "Logfile", true); ReadParameter(param, "Debug", "LogfileRetentionInDays", true); ReadParameter(param, "System", "TimeZone", true); @@ -1101,11 +1815,16 @@ function UpdateExpertModus() for (var i = 0; i < expert.length; i++) { document.getElementById(expert[i].id).style = _style; } - } function saveTextAsFile() { + ReadParameterAll(); + if (document.getElementsByClassName("invalid-input").length > 0) { + alert("Settings cannot be saved. Please check your entries."); + return; + } + if (confirm("Are you sure you want to update \"config.ini\"?")) { ReadParameterAll(); WriteConfigININew(); diff --git a/sd-card/html/gethost.js b/sd-card/html/gethost.js index d7a4c082..3299486f 100644 --- a/sd-card/html/gethost.js +++ b/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 } diff --git a/sd-card/html/readconfigparam.js b/sd-card/html/readconfigparam.js index 49b0f6ab..0c739e30 100644 --- a/sd-card/html/readconfigparam.js +++ b/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;