diff --git a/Changelog.md b/Changelog.md index 24e0843c..e4140754 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,3 +1,29 @@ +## [Unreleased] + +**Rolling** + + + +#### Added + +- Additional interface to InfluxDB Version 2 upwards +- Updated the Hybrid CNN network to `dig-cont_0610_s3` +- :bangbang: Update Camera driver: contrast, brightness and saturation now working + :bangbang: **Attention**: this can effect old version as well, because there not all settings were effective! + +#### Changed + +- n.a. + +#### Fixed + +- + +#### Removed + +- n.a. + + ## [15.0.1] - 2023-02-23 **Parameter Migration** @@ -29,11 +55,8 @@ If you want to revert back to `v14` or earlier, you will have to revert the migr - [2036](https://github.com/jomjol/AI-on-the-edge-device/issues/2036) Fix wrong url-encoding -#### Removed -- n.a. - -## [14.0.3] - 2023-02-05 +## [14.0.3] -2023-02-05 **Stabilization and Improved User Experience** @@ -82,6 +105,7 @@ For a full list of changes see [Full list of changes](https://github.com/jomjol/ - [1530](https://github.com/jomjol/AI-on-the-edge-device/pull/1530) Homeassistant `Problem Sensor` - [1518](https://github.com/jomjol/AI-on-the-edge-device/pull/1518) JSON Strings - [1817](https://github.com/jomjol/AI-on-the-edge-device/pull/1817) DataGraph: datafiles sorted -> newest on top +- **New 14.0.4:** Fix for InfluxDB timeshift problem [#1991](https://github.com/jomjol/AI-on-the-edge-device/issues/1991) #### Removed diff --git a/FeatureRequest.md b/FeatureRequest.md index 56677ba5..41315738 100644 --- a/FeatureRequest.md +++ b/FeatureRequest.md @@ -10,6 +10,11 @@ ____ +#### #35 Use the same model, but provide the image from a Smartphone Camera +as reading the Electricity or Water meter every few minutues only delivers apparent accuracy (DE: "Scheingenauigkeit") you could just as well take a picture with your Smartphone evey so often (e.g. once a week when you are in the Basement anyway), then with some "semi clever" tricks pass this image to the model developed here, and the values then on to who ever needs them e.g. via MQTT. +IMO: It is not needed to have that many readings (datapoints) as our behaviour (Use of electricity or water) doesn't vary that much, say, over a weeks time. The interpolation between weekly readings will give sufficient information on the power and/or water usage. + + #### #34 implement state and Roi for water leak detection for example see Roi on the next picture.. ![grafik](https://user-images.githubusercontent.com/38385805/207858812-2a6ba41d-1a8c-4fa1-9b6a-53cdd113c106.png) diff --git a/code/components/jomjol_controlcamera/ClassControllCamera.cpp b/code/components/jomjol_controlcamera/ClassControllCamera.cpp index 71637951..e1f04091 100644 --- a/code/components/jomjol_controlcamera/ClassControllCamera.cpp +++ b/code/components/jomjol_controlcamera/ClassControllCamera.cpp @@ -63,7 +63,6 @@ static camera_config_t camera_config = { .fb_count = 1, //if more than one, i2s runs in continuous mode. Use only with JPEG .fb_location = CAMERA_FB_IN_PSRAM, /*!< The location where the frame buffer will be allocated */ .grab_mode = CAMERA_GRAB_LATEST, // only from new esp32cam version - }; @@ -126,63 +125,97 @@ void CCamera::ledc_init(void) } -static size_t jpg_encode_stream(void * arg, size_t index, const void* data, size_t len){ +static size_t jpg_encode_stream(void * arg, size_t index, const void* data, size_t len) +{ jpg_chunking_t *j = (jpg_chunking_t *)arg; - if(!index){ + + if(!index) { j->len = 0; } - if(httpd_resp_send_chunk(j->req, (const char *)data, len) != ESP_OK){ + + if(httpd_resp_send_chunk(j->req, (const char *)data, len) != ESP_OK) { return 0; } + j->len += len; + return len; } bool CCamera::SetBrightnessContrastSaturation(int _brightness, int _contrast, int _saturation) { - bool result = false; - sensor_t * s = esp_camera_sensor_get(); - if (_brightness > -100) - _brightness = min(2, max(-2, _brightness)); - if (_contrast > -100) - _contrast = min(2, max(-2, _contrast)); - if (_saturation > -100) - _saturation = min(2, max(-2, _saturation)); + _brightness = min(2, max(-2, _brightness)); + _contrast = min(2, max(-2, _contrast)); + _saturation = min(2, max(-2, _saturation)); - if (_saturation > -100) + sensor_t * s = esp_camera_sensor_get(); + if (s) { s->set_saturation(s, _saturation); - if (_contrast > -100) s->set_contrast(s, _contrast); - if (_brightness > -100) s->set_brightness(s, _brightness); - if ((_brightness != brightness) && (_brightness > -100)) - result = true; - if ((_contrast != contrast) && (_contrast > -100)) - result = true; - if ((_saturation != saturation) && (_saturation > -100)) - result = true; - - if (_brightness > -100) - brightness = _brightness; - if (_contrast > -100) - contrast = _contrast; - if (_saturation > -100) - saturation = _saturation; + /* Workaround - bug in cam library - enable bits are set without using bitwise OR logic -> only latest enable setting is used */ + /* Library version: https://github.com/espressif/esp32-camera/commit/5c8349f4cf169c8a61283e0da9b8cff10994d3f3 */ + /* Reference: https://esp32.com/viewtopic.php?f=19&t=14376#p93178 */ + /* The memory structure is as follows for + byte_0 = enable_bits + byte_0->bit0 = enable saturation and hue --> OK + byte_0->bit1 = enable saturation --> OK + byte_0->bit2 = enable brightness and contrast --> OK + byte_0->bit3 = enable green -> blue spitial effect (Antique and blunish and greenish and readdish and b&w) enable + byte_0->bit4 = anable gray -> read spitial effect (Antique and blunish and greenish and readdish and b&w) enable + byte_0->bit5 = remove (UV) in YUV color system + byte_0->bit6 = enable negative + byte_0->bit7 = remove (Y) in YUV color system + byte_1 = saturation1 0-255 --> ? + byte_2 = hue 0-255 --> OK + byte_3 = saturation2 0-255 --> OK + byte_4 = reenter saturation2 in documents --> ? + byte_5 = spital effect green -> blue 0-255 --> ? + byte_6 = spital effect gray -> read 0-255 --> ? + byte_7 = contrast lower byte 0-255 --> OK + byte_8 = contrast higher byte 0-255 --> OK + byte_9 = brightness 0-255 --> OK + byte_10= if byte_10==4 contrast effective --> ? + */ - if (result && isFixedExposure) + //s->set_reg(s, 0x7C, 0xFF, 2); // Optional feature - hue setting: Select byte 2 in register 0x7C to set hue value + //s->set_reg(s, 0x7D, 0xFF, 0); // Optional feature - hue setting: Hue value 0 - 255 + s->set_reg(s, 0xFF, 0x01, 0); // Select DSP bank + s->set_reg(s, 0x7C, 0xFF, 0); // Select byte 0 in register 0x7C + s->set_reg(s, 0x7D, 7, 7); // Set bit 0, 1, 2 in register 0x7D to enable saturation, contrast, brightness and hue control + } + else { + LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "SetBrightnessContrastSaturation: Failed to get control structure"); + } + + if (((_brightness != brightness) || (_contrast != contrast) || (_saturation != saturation)) && isFixedExposure) EnableAutoExposure(waitbeforepicture_org); - return result; + brightness = _brightness; + contrast = _contrast; + saturation = _saturation; + + ESP_LOGD(TAG, "brightness %d, contrast: %d, saturation %d", brightness, contrast, saturation); + + return true; } void CCamera::SetQualitySize(int qual, framesize_t resol) { - sensor_t * s = esp_camera_sensor_get(); - s->set_quality(s, qual); - s->set_framesize(s, resol); + qual = min(63, max(8, qual)); // Limit quality from 8..63 (values lower than 8 tent to be unstable) + + sensor_t * s = esp_camera_sensor_get(); + if (s) { + s->set_quality(s, qual); + s->set_framesize(s, resol); + } + else { + LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "SetQualitySize: Failed to get control structure"); + } + ActualResolution = resol; ActualQuality = qual; @@ -191,41 +224,45 @@ void CCamera::SetQualitySize(int qual, framesize_t resol) image_height = 240; image_width = 320; } - if (resol == FRAMESIZE_VGA) + else if (resol == FRAMESIZE_VGA) { image_height = 480; image_width = 640; } - } void CCamera::EnableAutoExposure(int flash_duration) { ESP_LOGD(TAG, "EnableAutoExposure"); + LEDOnOff(true); - if (flash_duration > 0) + if (flash_duration > 0) { LightOnOff(true); - const TickType_t xDelay = flash_duration / portTICK_PERIOD_MS; - vTaskDelay( xDelay ); + const TickType_t xDelay = flash_duration / portTICK_PERIOD_MS; + vTaskDelay( xDelay ); + } camera_fb_t * fb = esp_camera_fb_get(); esp_camera_fb_return(fb); fb = esp_camera_fb_get(); if (!fb) { - ESP_LOGE(TAG, "Camera Capture Failed"); LEDOnOff(false); LightOnOff(false); - LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Capture Failed (Procedure 'EnableAutoExposure') --> Reboot! " - "Check that your camera module is working and connected properly."); + LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "EnableAutoExposure: Capture Failed. " + "Check camera module and/or proper electrical connection"); //doReboot(); } esp_camera_fb_return(fb); sensor_t * s = esp_camera_sensor_get(); - s->set_gain_ctrl(s, 0); - s->set_exposure_ctrl(s, 0); - + if (s) { + s->set_gain_ctrl(s, 0); + s->set_exposure_ctrl(s, 0); + } + else { + LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "EnableAutoExposure: Failed to get control structure to set gain+exposure"); + } LEDOnOff(false); LightOnOff(false); @@ -237,22 +274,21 @@ void CCamera::EnableAutoExposure(int flash_duration) esp_err_t CCamera::CaptureToBasisImage(CImageBasis *_Image, int delay) { #ifdef DEBUG_DETAIL_ON - LogFile.WriteHeapInfo("CCamera::CaptureToBasisImage - Start"); + LogFile.WriteHeapInfo("CaptureToBasisImage - Start"); #endif _Image->EmptyImage(); //Delete previous stored raw image -> black image LEDOnOff(true); - if (delay > 0) - { + if (delay > 0) { LightOnOff(true); const TickType_t xDelay = delay / portTICK_PERIOD_MS; vTaskDelay( xDelay ); } #ifdef DEBUG_DETAIL_ON - LogFile.WriteHeapInfo("CCamera::CaptureToBasisImage - After LightOn"); + LogFile.WriteHeapInfo("CaptureToBasisImage - After LightOn"); #endif camera_fb_t * fb = esp_camera_fb_get(); @@ -262,9 +298,8 @@ esp_err_t CCamera::CaptureToBasisImage(CImageBasis *_Image, int delay) LEDOnOff(false); LightOnOff(false); - ESP_LOGE(TAG, "CaptureToBasisImage: Capture Failed"); - LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "is not working anymore (CCamera::CaptureToBasisImage) - most probably caused by a hardware problem (instablility, ...). " - "System will reboot."); + LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "is not working anymore (CaptureToBasisImage) - most probably caused " + "by a hardware problem (instablility, ...). System will reboot."); doReboot(); return ESP_FAIL; @@ -276,11 +311,16 @@ esp_err_t CCamera::CaptureToBasisImage(CImageBasis *_Image, int delay) } CImageBasis* _zwImage = new CImageBasis(); - _zwImage->LoadFromMemory(fb->buf, fb->len); + if (_zwImage) { + _zwImage->LoadFromMemory(fb->buf, fb->len); + } + else { + LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "CaptureToBasisImage: Can't allocate _zwImage"); + } esp_camera_fb_return(fb); #ifdef DEBUG_DETAIL_ON - LogFile.WriteHeapInfo("CCamera::CaptureToBasisImage - After fb_get"); + LogFile.WriteHeapInfo("CaptureToBasisImage - After fb_get"); #endif LEDOnOff(false); @@ -292,7 +332,7 @@ esp_err_t CCamera::CaptureToBasisImage(CImageBasis *_Image, int delay) // vTaskDelay( xDelay ); // wait for power to recover #ifdef DEBUG_DETAIL_ON - LogFile.WriteHeapInfo("CCamera::CaptureToBasisImage - After LoadFromMemory"); + LogFile.WriteHeapInfo("CaptureToBasisImage - After LoadFromMemory"); #endif stbi_uc* p_target; @@ -320,7 +360,7 @@ esp_err_t CCamera::CaptureToBasisImage(CImageBasis *_Image, int delay) delete _zwImage; #ifdef DEBUG_DETAIL_ON - LogFile.WriteHeapInfo("CCamera::CaptureToBasisImage - Done"); + LogFile.WriteHeapInfo("CaptureToBasisImage - Done"); #endif return ESP_OK; @@ -333,8 +373,7 @@ esp_err_t CCamera::CaptureToFile(std::string nm, int delay) LEDOnOff(true); // Switched off to save power ! - if (delay > 0) - { + if (delay > 0) { LightOnOff(true); const TickType_t xDelay = delay / portTICK_PERIOD_MS; vTaskDelay( xDelay ); @@ -344,11 +383,10 @@ esp_err_t CCamera::CaptureToFile(std::string nm, int delay) esp_camera_fb_return(fb); fb = esp_camera_fb_get(); if (!fb) { - ESP_LOGE(TAG, "CaptureToFile: Camera Capture Failed"); LEDOnOff(false); LightOnOff(false); - LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Capture Failed (CCamera::CaptureToFile) --> Reboot! " - "Check that your camera module is working and connected properly."); + LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "CaptureToFile: Capture Failed. " + "Check camera module and/or proper electrical connection"); //doReboot(); return ESP_FAIL; @@ -395,24 +433,21 @@ esp_err_t CCamera::CaptureToFile(std::string nm, int delay) } FILE * fp = fopen(nm.c_str(), "wb"); - if (fp == NULL) /* If an error occurs during the file creation */ - { - fprintf(stderr, "fopen() failed for '%s'\n", nm.c_str()); + if (fp == NULL) { // If an error occurs during the file creation + LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "CaptureToFile: Failed to open file " + nm); } - else - { + else { fwrite(buf, sizeof(uint8_t), buf_len, fp); fclose(fp); - } + } + if (converted) free(buf); esp_camera_fb_return(fb); if (delay > 0) - { LightOnOff(false); - } return ESP_OK; } @@ -420,29 +455,26 @@ esp_err_t CCamera::CaptureToFile(std::string nm, int delay) esp_err_t CCamera::CaptureToHTTP(httpd_req_t *req, int delay) { - camera_fb_t * fb = NULL; esp_err_t res = ESP_OK; size_t fb_len = 0; int64_t fr_start = esp_timer_get_time(); - LEDOnOff(true); - if (delay > 0) - { + if (delay > 0) { LightOnOff(true); const TickType_t xDelay = delay / portTICK_PERIOD_MS; vTaskDelay( xDelay ); } - - fb = esp_camera_fb_get(); + camera_fb_t *fb = esp_camera_fb_get(); esp_camera_fb_return(fb); fb = esp_camera_fb_get(); if (!fb) { - ESP_LOGE(TAG, "Camera capture failed"); LEDOnOff(false); LightOnOff(false); + LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "CaptureToFile: Capture Failed. " + "Check camera module and/or proper electrical connection"); httpd_resp_send_500(req); // doReboot(); @@ -482,9 +514,7 @@ esp_err_t CCamera::CaptureToHTTP(httpd_req_t *req, int delay) ESP_LOGI(TAG, "JPG: %uKB %ums", (uint32_t)(fb_len/1024), (uint32_t)((fr_end - fr_start)/1000)); if (delay > 0) - { LightOnOff(false); - } return res; } @@ -494,19 +524,18 @@ void CCamera::LightOnOff(bool status) { GpioHandler* gpioHandler = gpio_handler_get(); if ((gpioHandler != NULL) && (gpioHandler->isEnabled())) { - ESP_LOGD(TAG, "Use gpioHandler flashLigh"); + ESP_LOGD(TAG, "Use gpioHandler to trigger flashlight"); gpioHandler->flashLightEnable(status); - } else { + } + else { #ifdef USE_PWM_LEDFLASH - if (status) - { + if (status) { ESP_LOGD(TAG, "Internal Flash-LED turn on with PWM %d", led_intensity); ESP_ERROR_CHECK(ledc_set_duty(LEDC_MODE, LEDC_CHANNEL, led_intensity)); // Update duty to apply the new value ESP_ERROR_CHECK(ledc_update_duty(LEDC_MODE, LEDC_CHANNEL)); } - else - { + else { ESP_LOGD(TAG, "Internal Flash-LED turn off PWM"); ESP_ERROR_CHECK(ledc_set_duty(LEDC_MODE, LEDC_CHANNEL, 0)); ESP_ERROR_CHECK(ledc_update_duty(LEDC_MODE, LEDC_CHANNEL)); @@ -555,33 +584,33 @@ void CCamera::GetCameraParameter(httpd_req_t *req, int &qual, framesize_t &resol ESP_LOGD(TAG, "Query: %s", _query); if (httpd_query_key_value(_query, "size", _size, 10) == ESP_OK) { -#ifdef DEBUG_DETAIL_ON + #ifdef DEBUG_DETAIL_ON ESP_LOGD(TAG, "Size: %s", _size); -#endif + #endif if (strcmp(_size, "QVGA") == 0) resol = FRAMESIZE_QVGA; // 320x240 - if (strcmp(_size, "VGA") == 0) + else if (strcmp(_size, "VGA") == 0) resol = FRAMESIZE_VGA; // 640x480 - if (strcmp(_size, "SVGA") == 0) + else if (strcmp(_size, "SVGA") == 0) resol = FRAMESIZE_SVGA; // 800x600 - if (strcmp(_size, "XGA") == 0) + else if (strcmp(_size, "XGA") == 0) resol = FRAMESIZE_XGA; // 1024x768 - if (strcmp(_size, "SXGA") == 0) + else if (strcmp(_size, "SXGA") == 0) resol = FRAMESIZE_SXGA; // 1280x1024 - if (strcmp(_size, "UXGA") == 0) + else if (strcmp(_size, "UXGA") == 0) resol = FRAMESIZE_UXGA; // 1600x1200 } if (httpd_query_key_value(_query, "quality", _qual, 10) == ESP_OK) { -#ifdef DEBUG_DETAIL_ON + #ifdef DEBUG_DETAIL_ON ESP_LOGD(TAG, "Quality: %s", _qual); -#endif + #endif qual = atoi(_qual); - if (qual > 63) + if (qual > 63) // Limit to max. 63 qual = 63; - if (qual < 0) - qual = 0; + else if (qual < 8) // Limit to min. 8 + qual = 8; } } } @@ -591,28 +620,29 @@ framesize_t CCamera::TextToFramesize(const char * _size) { if (strcmp(_size, "QVGA") == 0) return FRAMESIZE_QVGA; // 320x240 - if (strcmp(_size, "VGA") == 0) + else if (strcmp(_size, "VGA") == 0) return FRAMESIZE_VGA; // 640x480 - if (strcmp(_size, "SVGA") == 0) + else if (strcmp(_size, "SVGA") == 0) return FRAMESIZE_SVGA; // 800x600 - if (strcmp(_size, "XGA") == 0) + else if (strcmp(_size, "XGA") == 0) return FRAMESIZE_XGA; // 1024x768 - if (strcmp(_size, "SXGA") == 0) + else if (strcmp(_size, "SXGA") == 0) return FRAMESIZE_SXGA; // 1280x1024 - if (strcmp(_size, "UXGA") == 0) - return FRAMESIZE_UXGA; // 1600x1200 + else if (strcmp(_size, "UXGA") == 0) + return FRAMESIZE_UXGA; // 1600x1200 + return ActualResolution; } CCamera::CCamera() { -#ifdef DEBUG_DETAIL_ON - ESP_LOGD(TAG, "CreateClassCamera"); -#endif - brightness = -5; - contrast = -5; - saturation = -5; + #ifdef DEBUG_DETAIL_ON + ESP_LOGD(TAG, "CreateClassCamera"); + #endif + brightness = 0; + contrast = 0; + saturation = 0; isFixedExposure = false; ledc_init(); diff --git a/code/components/jomjol_fileserver_ota/server_file.cpp b/code/components/jomjol_fileserver_ota/server_file.cpp index b3f6605d..3c795f24 100644 --- a/code/components/jomjol_fileserver_ota/server_file.cpp +++ b/code/components/jomjol_fileserver_ota/server_file.cpp @@ -996,8 +996,12 @@ std::string unzip_new(std::string _in_zip_file, std::string _target_zip, std::st ESP_LOGI(TAG, "Filename to extract: %s, Zwischenfilename: %s", zw.c_str(), filename_zw.c_str()); + std::string folder = filename_zw.substr(0, filename_zw.find_last_of('/')); + MakeDir(folder); + // extrahieren in zwischendatei DeleteFile(filename_zw); + FILE* fpTargetFile = fopen(filename_zw.c_str(), "wb"); uint writtenbytes = fwrite(p, 1, (uint)uncomp_size, fpTargetFile); fclose(fpTargetFile); diff --git a/code/components/jomjol_flowcontroll/ClassFlowAlignment.cpp b/code/components/jomjol_flowcontroll/ClassFlowAlignment.cpp index 2514d5f9..c27b7674 100644 --- a/code/components/jomjol_flowcontroll/ClassFlowAlignment.cpp +++ b/code/components/jomjol_flowcontroll/ClassFlowAlignment.cpp @@ -65,7 +65,7 @@ bool ClassFlowAlignment::ReadParameter(FILE* pfile, string& aktparamgraph) std::vector splitted; int suchex = 40; int suchey = 40; - int alg_algo = 0; + int alg_algo = 0; //default=0; 1 =HIGHACCURACY; 2= FAST; 3= OFF //add disable aligment algo |01.2023 aktparamgraph = trim(aktparamgraph); @@ -130,6 +130,8 @@ bool ClassFlowAlignment::ReadParameter(FILE* pfile, string& aktparamgraph) alg_algo = 1; if (toUpper(splitted[1]) == "FAST") alg_algo = 2; + if (toUpper(splitted[1]) == "OFF") //no align algo if set to 3 = off => no draw ref //add disable aligment algo |01.2023 + alg_algo = 3; } } @@ -145,7 +147,10 @@ bool ClassFlowAlignment::ReadParameter(FILE* pfile, string& aktparamgraph) #endif } - LoadReferenceAlignmentValues(); + //no align algo if set to 3 = off => no draw ref //add disable aligment algo |01.2023 + if(References[0].alignment_algo != 3){ + LoadReferenceAlignmentValues(); + } return true; @@ -234,14 +239,22 @@ bool ClassFlowAlignment::doFlow(string time) AlignAndCutImage->SaveToFile(FormatFileName("/sdcard/img_tmp/rot.jpg")); } - if (!AlignAndCutImage->Align(&References[0], &References[1])) - { - SaveReferenceAlignmentValues(); - } + + //no align algo if set to 3 = off //add disable aligment algo |01.2023 + if(References[0].alignment_algo != 3){ + if (!AlignAndCutImage->Align(&References[0], &References[1])) + { + SaveReferenceAlignmentValues(); + } + }// no align + #ifdef ALGROI_LOAD_FROM_MEM_AS_JPG if (AlgROI) { - DrawRef(ImageTMP); + //no align algo if set to 3 = off => no draw ref //add disable aligment algo |01.2023 + if(References[0].alignment_algo != 3){ + DrawRef(ImageTMP); + } tfliteflow.DigitalDrawROI(ImageTMP); tfliteflow.AnalogDrawROI(ImageTMP); ImageTMP->writeToMemoryAsJPG((ImageData*)AlgROI, 90); @@ -258,7 +271,10 @@ bool ClassFlowAlignment::doFlow(string time) delete ImageTMP; ImageTMP = NULL; - LoadReferenceAlignmentValues(); + //no align algo if set to 3 = off => no draw ref //add disable aligment algo |01.2023 + if(References[0].alignment_algo != 3){ + LoadReferenceAlignmentValues(); + } return true; } diff --git a/code/components/jomjol_flowcontroll/ClassFlowControll.cpp b/code/components/jomjol_flowcontroll/ClassFlowControll.cpp index 94d3d9cb..6eb6024a 100644 --- a/code/components/jomjol_flowcontroll/ClassFlowControll.cpp +++ b/code/components/jomjol_flowcontroll/ClassFlowControll.cpp @@ -60,6 +60,9 @@ std::string ClassFlowControll::doSingleStep(std::string _stepname, std::string _ if ((_stepname.compare("[InfluxDB]") == 0) || (_stepname.compare(";[InfluxDB]") == 0)){ _classname = "ClassFlowInfluxDB"; } + if ((_stepname.compare("[InfluxDBv2]") == 0) || (_stepname.compare(";[InfluxDBv2]") == 0)){ + _classname = "ClassFlowInfluxDBv2"; + } #endif //ENABLE_INFLUXDB for (int i = 0; i < FlowControll.size(); ++i) @@ -90,6 +93,8 @@ std::string ClassFlowControll::TranslateAktstatus(std::string _input) #ifdef ENABLE_INFLUXDB if (_input.compare("ClassFlowInfluxDB") == 0) return ("Sending InfluxDB"); + if (_input.compare("ClassFlowInfluxDBv2") == 0) + return ("Sending InfluxDBv2"); #endif //ENABLE_INFLUXDB if (_input.compare("ClassFlowPostProcessing") == 0) return ("Post-Processing"); @@ -233,6 +238,8 @@ ClassFlow* ClassFlowControll::CreateClassFlow(std::string _type) #ifdef ENABLE_INFLUXDB if (toUpper(_type).compare("[INFLUXDB]") == 0) cfc = new ClassFlowInfluxDB(&FlowControll); + if (toUpper(_type).compare("[INFLUXDBV2]") == 0) + cfc = new ClassFlowInfluxDBv2(&FlowControll); #endif //ENABLE_INFLUXDB if (toUpper(_type).compare("[WRITELIST]") == 0) cfc = new ClassFlowWriteList(&FlowControll); @@ -290,6 +297,7 @@ void ClassFlowControll::InitFlow(std::string config) while ((line.size() > 0) && !(feof(pFile))) { cfc = CreateClassFlow(line); +// printf("Name: %s\n", cfc->name().c_str()); if (cfc) { ESP_LOGD(TAG, "Start ReadParameter (%s)", line.c_str()); diff --git a/code/components/jomjol_flowcontroll/ClassFlowControll.h b/code/components/jomjol_flowcontroll/ClassFlowControll.h index e42cf094..1c42bc3e 100644 --- a/code/components/jomjol_flowcontroll/ClassFlowControll.h +++ b/code/components/jomjol_flowcontroll/ClassFlowControll.h @@ -15,6 +15,7 @@ #endif //ENABLE_MQTT #ifdef ENABLE_INFLUXDB #include "ClassFlowInfluxDB.h" + #include "ClassFlowInfluxDBv2.h" #endif //ENABLE_INFLUXDB #include "ClassFlowCNNGeneral.h" #include "ClassFlowWriteList.h" diff --git a/code/components/jomjol_flowcontroll/ClassFlowDefineTypes.h b/code/components/jomjol_flowcontroll/ClassFlowDefineTypes.h index 4890d94f..4a35773f 100644 --- a/code/components/jomjol_flowcontroll/ClassFlowDefineTypes.h +++ b/code/components/jomjol_flowcontroll/ClassFlowDefineTypes.h @@ -50,6 +50,7 @@ struct NumberPost { int DecimalShiftInitial; float AnalogDigitalTransitionStart; // When is the digit > x.1, i.e. when does it start to tilt? int Nachkomma; + string Fieldname; // Fieldname in InfluxDB2 bool isExtendedResolution; diff --git a/code/components/jomjol_flowcontroll/ClassFlowInfluxDBv2.cpp b/code/components/jomjol_flowcontroll/ClassFlowInfluxDBv2.cpp new file mode 100644 index 00000000..d88ec25b --- /dev/null +++ b/code/components/jomjol_flowcontroll/ClassFlowInfluxDBv2.cpp @@ -0,0 +1,219 @@ +#ifdef ENABLE_INFLUXDB +#include +#include "ClassFlowInfluxDBv2.h" +#include "Helper.h" +#include "connect_wlan.h" + +#include "time_sntp.h" +#include "interface_influxdb.h" + +#include "ClassFlowPostProcessing.h" +#include "esp_log.h" +#include "../../include/defines.h" + +#include "ClassLogFile.h" + +#include + +static const char* TAG = "class_flow_influxDbv2"; + +void ClassFlowInfluxDBv2::SetInitialParameter(void) +{ + uri = ""; + database = ""; + measurement = ""; + dborg = ""; + dbtoken = ""; +// dbfield = ""; + + OldValue = ""; + flowpostprocessing = NULL; + previousElement = NULL; + ListFlowControll = NULL; + disabled = false; + InfluxDBenable = false; +} + +ClassFlowInfluxDBv2::ClassFlowInfluxDBv2() +{ + SetInitialParameter(); +} + +ClassFlowInfluxDBv2::ClassFlowInfluxDBv2(std::vector* lfc) +{ + SetInitialParameter(); + + ListFlowControll = lfc; + for (int i = 0; i < ListFlowControll->size(); ++i) + { + if (((*ListFlowControll)[i])->name().compare("ClassFlowPostProcessing") == 0) + { + flowpostprocessing = (ClassFlowPostProcessing*) (*ListFlowControll)[i]; + } + } +} + +ClassFlowInfluxDBv2::ClassFlowInfluxDBv2(std::vector* lfc, ClassFlow *_prev) +{ + SetInitialParameter(); + + previousElement = _prev; + ListFlowControll = lfc; + + for (int i = 0; i < ListFlowControll->size(); ++i) + { + if (((*ListFlowControll)[i])->name().compare("ClassFlowPostProcessing") == 0) + { + flowpostprocessing = (ClassFlowPostProcessing*) (*ListFlowControll)[i]; + } + } +} + + +bool ClassFlowInfluxDBv2::ReadParameter(FILE* pfile, string& aktparamgraph) +{ + std::vector splitted; + + aktparamgraph = trim(aktparamgraph); + printf("akt param: %s\n", aktparamgraph.c_str()); + + if (aktparamgraph.size() == 0) + if (!this->GetNextParagraph(pfile, aktparamgraph)) + return false; + + if (toUpper(aktparamgraph).compare("[INFLUXDBV2]") != 0) + return false; + + while (this->getNextLine(pfile, &aktparamgraph) && !this->isNewParagraph(aktparamgraph)) + { +// ESP_LOGD(TAG, "while loop reading line: %s", aktparamgraph.c_str()); + splitted = ZerlegeZeile(aktparamgraph); + std::string _param = GetParameterName(splitted[0]); + + if ((toUpper(_param) == "ORG") && (splitted.size() > 1)) + { + this->dborg = splitted[1]; + } + if ((toUpper(_param) == "TOKEN") && (splitted.size() > 1)) + { + this->dbtoken = splitted[1]; + } + if ((toUpper(_param) == "URI") && (splitted.size() > 1)) + { + this->uri = splitted[1]; + } + if (((toUpper(_param) == "MEASUREMENT")) && (splitted.size() > 1)) + { + this->measurement = splitted[1]; + } + if (((toUpper(_param) == "FIELDNAME")) && (splitted.size() > 1)) + { + handleFieldname(splitted[0], splitted[1]); + } + if (((toUpper(splitted[0]) == "DATABASE")) && (splitted.size() > 1)) + { + this->database = splitted[1]; + } + } + + printf("uri: %s\n", uri.c_str()); + printf("measurement: %s\n", measurement.c_str()); + printf("org: %s\n", dborg.c_str()); + printf("token: %s\n", dbtoken.c_str()); + + if ((uri.length() > 0) && (database.length() > 0) && (measurement.length() > 0) && (dbtoken.length() > 0) && (dborg.length() > 0)) + { + LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Init InfluxDB with uri: " + uri + ", measurement: " + measurement + ", org: " + dborg + ", token: *****"); +// printf("vor V2 Init\n"); + InfluxDB_V2_Init(uri, database, measurement, dborg, dbtoken); +// printf("nach V2 Init\n"); + InfluxDBenable = true; + } else { + LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "InfluxDBv2 (Verion2 !!!) init skipped as we are missing some parameters"); + } + + return true; +} + + +string ClassFlowInfluxDBv2::GetInfluxDBMeasurement() +{ + return measurement; +} + +void ClassFlowInfluxDBv2::handleFieldname(string _decsep, string _value) +{ + string _digit, _decpos; + int _pospunkt = _decsep.find_first_of("."); +// ESP_LOGD(TAG, "Name: %s, Pospunkt: %d", _decsep.c_str(), _pospunkt); + if (_pospunkt > -1) + _digit = _decsep.substr(0, _pospunkt); + else + _digit = "default"; + for (int j = 0; j < flowpostprocessing->NUMBERS.size(); ++j) + { + if (_digit == "default") // Set to default first (if nothing else is set) + { + flowpostprocessing->NUMBERS[j]->Fieldname = _value; + } + if (flowpostprocessing->NUMBERS[j]->name == _digit) + { + flowpostprocessing->NUMBERS[j]->Fieldname = _value; + } + } +} + + + +bool ClassFlowInfluxDBv2::doFlow(string zwtime) +{ + if (!InfluxDBenable) + return true; + + std::string result; + std::string resulterror = ""; + std::string resultraw = ""; + std::string resultrate = ""; + std::string resulttimestamp = ""; + string zw = ""; + string namenumber = ""; + + if (flowpostprocessing) + { + std::vector* NUMBERS = flowpostprocessing->GetNumbers(); + + for (int i = 0; i < (*NUMBERS).size(); ++i) + { + result = (*NUMBERS)[i]->ReturnValue; + resultraw = (*NUMBERS)[i]->ReturnRawValue; + resulterror = (*NUMBERS)[i]->ErrorMessageText; + resultrate = (*NUMBERS)[i]->ReturnRateValue; + resulttimestamp = (*NUMBERS)[i]->timeStamp; + + if ((*NUMBERS)[i]->Fieldname.length() > 0) + { + namenumber = (*NUMBERS)[i]->Fieldname; + } + else + { + namenumber = (*NUMBERS)[i]->name; + if (namenumber == "default") + namenumber = "value"; + else + namenumber = namenumber + "/value"; + } + + printf("vor sende Influx_DB_V2 - namenumber. %s, result: %s, timestampt: %s", namenumber.c_str(), result.c_str(), resulttimestamp.c_str()); + + if (result.length() > 0) + InfluxDB_V2_Publish(namenumber, result, resulttimestamp); +// InfluxDB_V2_Publish(namenumber, result, resulttimestamp); + } + } + + OldValue = result; + + return true; +} + +#endif //ENABLE_INFLUXDB \ No newline at end of file diff --git a/code/components/jomjol_flowcontroll/ClassFlowInfluxDBv2.h b/code/components/jomjol_flowcontroll/ClassFlowInfluxDBv2.h new file mode 100644 index 00000000..a1832025 --- /dev/null +++ b/code/components/jomjol_flowcontroll/ClassFlowInfluxDBv2.h @@ -0,0 +1,41 @@ +#ifdef ENABLE_INFLUXDB + +#pragma once + +#ifndef CLASSFINFLUXDBv2_H +#define CLASSFINFLUXDBv2_H + +#include "ClassFlow.h" + +#include "ClassFlowPostProcessing.h" + +#include + +class ClassFlowInfluxDBv2 : + public ClassFlow +{ +protected: + std::string uri, database, measurement; + std::string dborg, dbtoken, dbfield; + std::string OldValue; + ClassFlowPostProcessing* flowpostprocessing; + bool InfluxDBenable; + + void SetInitialParameter(void); + + void handleFieldname(string _decsep, string _value); + +public: + ClassFlowInfluxDBv2(); + ClassFlowInfluxDBv2(std::vector* lfc); + ClassFlowInfluxDBv2(std::vector* lfc, ClassFlow *_prev); + + string GetInfluxDBMeasurement(); + + bool ReadParameter(FILE* pfile, string& aktparamgraph); + bool doFlow(string time); + string name(){return "ClassFlowInfluxDBv2";}; +}; + +#endif //CLASSFINFLUXDBv2_H +#endif //ENABLE_INFLUXDB \ No newline at end of file diff --git a/code/components/jomjol_flowcontroll/ClassFlowMakeImage.cpp b/code/components/jomjol_flowcontroll/ClassFlowMakeImage.cpp deleted file mode 100644 index e69de29b..00000000 diff --git a/code/components/jomjol_flowcontroll/ClassFlowMakeImage.h b/code/components/jomjol_flowcontroll/ClassFlowMakeImage.h deleted file mode 100644 index e69de29b..00000000 diff --git a/code/components/jomjol_flowcontroll/ClassFlowPostProcessing.h b/code/components/jomjol_flowcontroll/ClassFlowPostProcessing.h index 0cc97a33..3fc8f11d 100644 --- a/code/components/jomjol_flowcontroll/ClassFlowPostProcessing.h +++ b/code/components/jomjol_flowcontroll/ClassFlowPostProcessing.h @@ -15,7 +15,6 @@ class ClassFlowPostProcessing : public ClassFlow { protected: - std::vector NUMBERS; bool UpdatePreValueINI; int PreValueAgeStartup; @@ -54,6 +53,8 @@ protected: public: bool PreValueUse; + std::vector NUMBERS; + ClassFlowPostProcessing(std::vector* lfc, ClassFlowCNNGeneral *_analog, ClassFlowCNNGeneral *_digit); virtual ~ClassFlowPostProcessing(){}; diff --git a/code/components/jomjol_helper/Helper.cpp b/code/components/jomjol_helper/Helper.cpp index 6ade4962..b6151b2a 100644 --- a/code/components/jomjol_helper/Helper.cpp +++ b/code/components/jomjol_helper/Helper.cpp @@ -224,15 +224,50 @@ void FindReplace(std::string& line, std::string& oldString, std::string& newStri } -bool MakeDir(std::string _what) +/** + * Create a folder and its parent folders as needed + */ +bool MakeDir(std::string path) { - int mk_ret = mkdir(_what.c_str(), 0775); - if (mk_ret) - { - ESP_LOGD(TAG, "error with mkdir %s ret %d", _what.c_str(), mk_ret); - return false; + std::string parent; + + LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Creating folder " + path + "..."); + + bool bSuccess = false; + int nRC = ::mkdir( path.c_str(), 0775 ); + if( nRC == -1 ) + { + switch( errno ) { + case ENOENT: + //parent didn't exist, try to create it + parent = path.substr(0, path.find_last_of('/')); + LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Need to create parent folder first: " + parent); + if(MakeDir(parent)) { + //Now, try to create again. + bSuccess = 0 == ::mkdir( path.c_str(), 0775 ); + } + else { + LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Failed to create parent folder: " + parent); + bSuccess = false; + } + break; + + case EEXIST: + //Done! + bSuccess = true; + break; + + default: + LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Failed to create folder: " + path); + bSuccess = false; + break; + } + } + else { + bSuccess = true; } - return true; + + return bSuccess; } @@ -576,9 +611,6 @@ std::vector HelperZerlegeZeile(std::string input, std::string _delimiter std::vector ZerlegeZeile(std::string input, std::string delimiter) { std::vector Output; - - input = trim(input, delimiter); - /* The input can have multiple formats: * - key = value * - key = value1 value2 value3 ... @@ -593,12 +625,13 @@ std::vector ZerlegeZeile(std::string input, std::string delimiter) * As a workaround and to not break any legacy usage, we enforce to only use the * equal sign, if the key is "password" */ - if (input.find("password") != string::npos) { // Line contains a password, use the equal sign as the only delimiter and only split on first occurrence + if ((input.find("password") != string::npos) || (input.find("Token") != string::npos)) { // Line contains a password, use the equal sign as the only delimiter and only split on first occurrence size_t pos = input.find("="); Output.push_back(trim(input.substr(0, pos), "")); Output.push_back(trim(input.substr(pos +1, string::npos), "")); } else { // Legacy Mode + input = trim(input, delimiter); // sonst werden delimiter am Ende (z.B. == im Token) gelöscht) size_t pos = findDelimiterPos(input, delimiter); std::string token; while (pos != std::string::npos) { diff --git a/code/components/jomjol_influxdb/interface_influxdb.cpp b/code/components/jomjol_influxdb/interface_influxdb.cpp index f311085e..bc878e84 100644 --- a/code/components/jomjol_influxdb/interface_influxdb.cpp +++ b/code/components/jomjol_influxdb/interface_influxdb.cpp @@ -16,6 +16,101 @@ std::string _influxDBMeasurement; std::string _influxDBUser; std::string _influxDBPassword; +std::string _influxDB_V2_URI; +std::string _influxDB_V2_Database; +std::string _influxDB_V2_Measurement; +std::string _influxDB_V2_Token; +std::string _influxDB_V2_Org; + +static esp_err_t http_event_handler(esp_http_client_event_t *evt); + +void InfluxDB_V2_Init(std::string _uri, std::string _database, std::string _measurement, std::string _org, std::string _token) +{ + _influxDB_V2_URI = _uri; + _influxDB_V2_Database = _database; + _influxDB_V2_Measurement = _measurement; + _influxDB_V2_Org = _org; + _influxDB_V2_Token = _token; +} + +void InfluxDB_V2_Publish(std::string _key, std::string _content, std::string _timestamp) +{ + char response_buffer[MAX_HTTP_OUTPUT_BUFFER] = {0}; + esp_http_client_config_t http_config = { + .user_agent = "ESP32 Meter reader", + .method = HTTP_METHOD_POST, + .event_handler = http_event_handler, + .buffer_size = MAX_HTTP_OUTPUT_BUFFER, + .user_data = response_buffer + }; + + LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "InfluxDB_V2_Publish - Key: " + _key + ", Content: " + _content + ", Timestamp: " + _timestamp); + + // Format: #define PREVALUE_TIME_FORMAT_OUTPUT "%Y-%m-%dT%H:%M:%S%z" + + char nowTimestamp[21]; + std::string payload; + + if (_timestamp.length() > 0) + { + struct tm tm; + strptime(_timestamp.c_str(), PREVALUE_TIME_FORMAT_OUTPUT, &tm); + time_t t = mktime(&tm); // Time in Localtime (looks like timezone is not used by strptime) + + struct tm * ptm; + ptm = gmtime ( &t ); + time_t utc = mktime(ptm); + utc = 2*t - utc; // Take care of timezone (looks difficult, but is easy: t = t + (t - utc), weil t-utc = timezone) + + sprintf(nowTimestamp,"%ld000000000", (long) utc); // UTC + + payload = _influxDB_V2_Measurement + " " + _key + "=" + _content + " " + nowTimestamp; +// payload = _influxDB_V2_Measurement + " " + _key + "=774 " + nowTimestamp; + } + else + { + payload = _influxDB_V2_Measurement + " " + _key + "=" + _content; +// payload = _influxDB_V2_Measurement + " " + _key + "=774"; + } + + payload.shrink_to_fit(); + + LogFile.WriteToFile(ESP_LOG_INFO, TAG, "sending line to influxdb:" + payload); + + std::string apiURI = _influxDB_V2_URI + "/api/v2/write?org=" + _influxDB_V2_Org + "&bucket=" + _influxDB_V2_Database; + apiURI.shrink_to_fit(); + http_config.url = apiURI.c_str(); + ESP_LOGI(TAG, "http_config: %s", http_config.url); // Add mark on log to see when it restarted + + LogFile.WriteToFile(ESP_LOG_INFO, TAG, "API URI: " + apiURI); + + esp_http_client_handle_t http_client = esp_http_client_init(&http_config); + LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "client is initialized"); + + esp_http_client_set_header(http_client, "Content-Type", "text/plain"); + std::string _zw = "Token " + _influxDB_V2_Token; + // LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Tokenheader: %s\n", _zw.c_str()); + esp_http_client_set_header(http_client, "Authorization", _zw.c_str()); + + LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "header is set"); + + ESP_ERROR_CHECK(esp_http_client_set_post_field(http_client, payload.c_str(), payload.length())); + LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "post payload is set"); + + esp_err_t err = ESP_ERROR_CHECK_WITHOUT_ABORT(esp_http_client_perform(http_client)); + + if( err == ESP_OK ) { + LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "HTTP request was performed"); + int status_code = esp_http_client_get_status_code(http_client); + LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "HTTP status code" + std::to_string(status_code)); + } else { + LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "HTTP request failed"); + } + esp_http_client_cleanup(http_client); +} + + + static esp_err_t http_event_handler(esp_http_client_event_t *evt) { switch(evt->event_id) @@ -64,28 +159,30 @@ void InfluxDBPublish(std::string _key, std::string _content, std::string _timest LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "InfluxDBPublish - Key: " + _key + ", Content: " + _content + ", Timestamp: " + _timestamp); - // Format: #define PREVALUE_TIME_FORMAT_OUTPUT "%Y-%m-%dT%H:%M:%S%z" - struct tm tm; - strptime(_timestamp.c_str(), PREVALUE_TIME_FORMAT_OUTPUT, &tm); - time_t t = mktime(&tm); // t is now your desired time_t - - struct tm * ptm; - ptm = gmtime ( &t ); - time_t utc = mktime(ptm); - -// time_t now; -// time(&now); char nowTimestamp[21]; - // pad with zeroes to get nanoseconds -// sprintf(nowTimestamp,"%ld000000000", (long) now); -// sprintf(nowTimestamp,"%ld000000000", (long) t); // Localtime - sprintf(nowTimestamp,"%ld000000000", (long) utc); // UTC - + std::string payload; -// LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Test Time Conversion - t: " + std::to_string(t) + ", utc: " + std::to_string(utc)); -// LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Test Time Conversion - now: " + std::to_string(now) + ", timestamp: " + std::to_string(t) + "(correct time not used yet)"); + if (_timestamp.length() > 0) + { + struct tm tm; + strptime(_timestamp.c_str(), PREVALUE_TIME_FORMAT_OUTPUT, &tm); + time_t t = mktime(&tm); // Time in Localtime (looks like timezone is not used by strptime) + + struct tm * ptm; + ptm = gmtime ( &t ); + time_t utc = mktime(ptm); + utc = 2*t - utc; // Take care of timezone (looks difficult, but is easy: t = t + (t - utc), weil t-utc = timezone) + + sprintf(nowTimestamp,"%ld000000000", (long) utc); // UTC + + payload = _influxDBMeasurement + " " + _key + "=" + _content + " " + nowTimestamp; +// payload = _influxDBMeasurement + " " + _key + "=774 " + nowTimestamp; + } + else + { + payload = _influxDBMeasurement + " " + _key + "=" + _content; + } - std::string payload = _influxDBMeasurement + " " + _key + "=" + _content + " " + nowTimestamp; payload.shrink_to_fit(); LogFile.WriteToFile(ESP_LOG_INFO, TAG, "sending line to influxdb:" + payload); diff --git a/code/components/jomjol_influxdb/interface_influxdb.h b/code/components/jomjol_influxdb/interface_influxdb.h index ab179577..919e4a3d 100644 --- a/code/components/jomjol_influxdb/interface_influxdb.h +++ b/code/components/jomjol_influxdb/interface_influxdb.h @@ -8,10 +8,17 @@ #include #include +// Interface to InfluxDB v1.x void InfluxDBInit(std::string _influxDBURI, std::string _database, std::string _measurement, std::string _user, std::string _password); -void InfluxDBdestroy(); - void InfluxDBPublish(std::string _key, std::string _content, std::string _timestamp); +// Interface to InfluxDB v2.x +void InfluxDB_V2_Init(std::string _uri, std::string _database, std::string _measurement, std::string _org, std::string _token); +void InfluxDB_V2_Publish(std::string _key, std::string _content, std::string _timestamp); + + + +void InfluxDBdestroy(); + #endif //INTERFACE_INFLUXDB_H #endif //ENABLE_INFLUXDB \ No newline at end of file diff --git a/code/components/jomjol_wlan/connect_wlan.cpp b/code/components/jomjol_wlan/connect_wlan.cpp index 3288b916..eee58d5f 100644 --- a/code/components/jomjol_wlan/connect_wlan.cpp +++ b/code/components/jomjol_wlan/connect_wlan.cpp @@ -556,7 +556,9 @@ bool getWIFIisConnected() void WIFIDestroy() { - esp_event_handler_unregister(IP_EVENT, IP_EVENT_STA_GOT_IP, event_handler); + esp_wifi_disconnect(); + + esp_event_handler_unregister(IP_EVENT, IP_EVENT_STA_GOT_IP, event_handler); esp_event_handler_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID, event_handler); #ifdef WLAN_USE_MESH_ROAMING esp_event_handler_unregister(WIFI_EVENT, WIFI_EVENT_STA_BSS_RSSI_LOW, esp_bss_rssi_low_handler); diff --git a/code/include/defines.h b/code/include/defines.h index 8b44f249..4fd8a4e1 100644 --- a/code/include/defines.h +++ b/code/include/defines.h @@ -21,7 +21,9 @@ // use himem //https://github.com/jomjol/AI-on-the-edge-device/issues/1842 - #define USE_HIMEM_IF_AVAILABLE + #if (CONFIG_SPIRAM_BANKSWITCH_ENABLE) + #define USE_HIMEM_IF_AVAILABLE 1 + #endif /* Uncomment this to generate task list with stack sizes using the /heap handler PLEASE BE AWARE: The following CONFIG parameters have to to be set in @@ -117,7 +119,6 @@ //ClassFlowControll: Serve alg_roi.jpg from memory as JPG #define ALGROI_LOAD_FROM_MEM_AS_JPG // Load ALG_ROI.JPG as rendered JPG from RAM - #define ALGROI_LOAD_FROM_MEM_AS_JPG__SHOW_TAKE_IMAGE_PROCESS // Show take image image processing on webinterface (overview.html) //ClassFlowMQTT #define LWT_TOPIC "connection" diff --git a/firmware/README.md b/firmware/README.md index bf3f5130..79e006a9 100644 --- a/firmware/README.md +++ b/firmware/README.md @@ -3,4 +3,4 @@ The firmware got moved to the [Release page](https://github.com/jomjol/AI-on-the # Installation Guide -You find the complete installation guide at +You find the complete installation guide at https://jomjol.github.io/AI-on-the-edge-device-docs/Installation/ diff --git a/sd-card/config/config.ini b/sd-card/config/config.ini index 5c7368b1..f703dd60 100644 --- a/sd-card/config/config.ini +++ b/sd-card/config/config.ini @@ -65,11 +65,19 @@ HomeassistantDiscovery = false ;[InfluxDB] ;Uri = undefined -;Database = +;Database = undefined ;Measurement = undefined ;user = undefined ;password = undefined +;[InfluxDBv2] +;Uri = undefined +;Database = undefined +;Measurement = undefined +;Org = undefined +;Token = undefined +;main.Fieldname = undefined + ;[GPIO] ;MainTopicMQTT = wasserzaehler/GPIO ;IO0 = input disabled 10 false false diff --git a/sd-card/config/dig-cont_0610_s3.tflite b/sd-card/config/dig-cont_0610_s3.tflite new file mode 100644 index 00000000..ecc71a88 Binary files /dev/null and b/sd-card/config/dig-cont_0610_s3.tflite differ diff --git a/sd-card/config/dig-cont_0610_s3_q.tflite b/sd-card/config/dig-cont_0610_s3_q.tflite new file mode 100644 index 00000000..c7dc9942 Binary files /dev/null and b/sd-card/config/dig-cont_0610_s3_q.tflite differ diff --git a/sd-card/html/backup.html b/sd-card/html/backup.html index b5622027..260354d9 100644 --- a/sd-card/html/backup.html +++ b/sd-card/html/backup.html @@ -121,9 +121,15 @@ function fetchFiles(urls, filesData, index, retry, zipFilename) { else if (retry == 1) { // longer timeout xhr.timeout = 5000; // time in milliseconds } - else { // very long timeout + else if (retry == 2) { // longer timeout xhr.timeout = 20000; // time in milliseconds } + else if (retry == 3) { // longer timeout + xhr.timeout = 30000; // time in milliseconds + } + else { // very long timeout + xhr.timeout = 60000; // time in milliseconds + } xhr.onload = () => { // Request finished //console.log(url + " done"); diff --git a/sd-card/html/common.js b/sd-card/html/common.js index a4e9cb38..ba170dee 100644 --- a/sd-card/html/common.js +++ b/sd-card/html/common.js @@ -1,7 +1,7 @@ /* The UI can also be run locally, but you have to set the IP of your devide accordingly. * And you also might have to disable CORS in your webbrowser! */ -var domainname_for_testing = "192.168.178.44"; +var domainname_for_testing = "192.168.178.62"; diff --git a/sd-card/html/edit_alignment.html b/sd-card/html/edit_alignment.html index d76682a3..f827992f 100644 --- a/sd-card/html/edit_alignment.html +++ b/sd-card/html/edit_alignment.html @@ -2,7 +2,7 @@ -Make Alignment +Alignment Marks - - - - -

Finished!

-Read below! - - + \ No newline at end of file diff --git a/sd-card/html/gethost.js b/sd-card/html/gethost.js index dc84410f..d838b629 100644 --- a/sd-card/html/gethost.js +++ b/sd-card/html/gethost.js @@ -13,7 +13,7 @@ function getbasepath(){ { // host = "http://192.168.2.219"; // jomjol interner test // host = "http://192.168.178.46"; // jomjol interner test - host = "http://192.168.178.62"; // jomjol interner Real + host = "http://192.168.178.44"; // jomjol interner Real // host = "http://192.168.43.191"; // host = "."; // jomjol interner localhost diff --git a/sd-card/html/ota_page.html b/sd-card/html/ota_page.html index ddee596d..f97bf753 100644 --- a/sd-card/html/ota_page.html +++ b/sd-card/html/ota_page.html @@ -118,7 +118,7 @@ * - *.bin * - *.zip */ else if (filename.endsWith(".zip") || filename.endsWith(".bin")) { // Warning but still accepted - firework.launch('The filename does not match the suggested filename pattern, but is nevertheless accepted. You can now press "Upload and install', 'warning', 10000); + firework.launch('The filename does not match the suggested filename pattern, but is nevertheless accepted. You can now press "Upload and install".', 'warning', 10000); } /* Any other file name format is not accepted */ else { // invalid diff --git a/sd-card/html/readconfigcommon.js b/sd-card/html/readconfigcommon.js index f4cf862a..0f9c83fe 100644 --- a/sd-card/html/readconfigcommon.js +++ b/sd-card/html/readconfigcommon.js @@ -45,7 +45,6 @@ function ZerlegeZeile(input, delimiter = " =\t\r") var Output = Array(0); // delimiter = " =,\t"; - input = trim(input, delimiter); /* The input can have multiple formats: * - key = value @@ -61,12 +60,14 @@ function ZerlegeZeile(input, delimiter = " =\t\r") * As a workaround and to not break any legacy usage, we enforce to only use the * equal sign, if the key is "password" */ - if (input.includes("password")) { // Line contains a password, use the equal sign as the only delimiter and only split on first occurrence + if (input.includes("password") || input.includes("Token")) { // Line contains a password, use the equal sign as the only delimiter and only split on first occurrence var pos = input.indexOf("="); + delimiter = " \t\r" Output.push(trim(input.substr(0, pos), delimiter)); Output.push(trim(input.substr(pos +1, input.length), delimiter)); } else { // Legacy Mode + input = trim(input, delimiter); var pos = findDelimiterPos(input, delimiter); var token; while (pos > -1) { diff --git a/sd-card/html/readconfigparam.js b/sd-card/html/readconfigparam.js index 601538db..34c1b056 100644 --- a/sd-card/html/readconfigparam.js +++ b/sd-card/html/readconfigparam.js @@ -194,8 +194,19 @@ function ParseConfig() { ParamAddValue(param, catname, "Measurement"); ParamAddValue(param, catname, "user"); ParamAddValue(param, catname, "password"); - - + + var catname = "InfluxDBv2"; + category[catname] = new Object(); + category[catname]["enabled"] = false; + category[catname]["found"] = false; + param[catname] = new Object(); + ParamAddValue(param, catname, "Uri"); + ParamAddValue(param, catname, "Database"); + ParamAddValue(param, catname, "Measurement"); + ParamAddValue(param, catname, "Org"); + ParamAddValue(param, catname, "Token"); + ParamAddValue(param, catname, "Fieldname", 1, true); + var catname = "GPIO"; category[catname] = new Object(); category[catname]["enabled"] = false; diff --git a/sd-card/html/setup.html b/sd-card/html/setup.html index c0a22219..c3383794 100644 --- a/sd-card/html/setup.html +++ b/sd-card/html/setup.html @@ -40,7 +40,7 @@ p {font-size: 1em;} - If you need support, have a look to the documenation or the discussion pages. + If you need support, have a look to the documentation or the discussion pages. @@ -83,53 +83,53 @@ function clickPrevious() { function LoadStep(){ switch (aktstatu) { case 0: - document.getElementById('maincontent').src = '/edit_explain_0.html?v=$COMMIT_HASH'; + document.getElementById('maincontent').src = 'edit_explain_0.html?v=$COMMIT_HASH'; document.getElementById('h_iframe_explain').style.display = "none"; document.getElementById("previous").disabled = true; document.getElementById("next").disabled = false; break; case 1: - document.getElementById('maincontent').src = '/edit_reference.html?v=$COMMIT_HASH'; - document.getElementById('explaincontent').src = '/explain_1.html?v=$COMMIT_HASH'; + document.getElementById('maincontent').src = 'edit_reference.html?v=$COMMIT_HASH'; + document.getElementById('explaincontent').src = 'explain_1.html?v=$COMMIT_HASH'; document.getElementById('h_iframe_explain').style.display = ""; document.getElementById("previous").disabled = false; document.getElementById("next").disabled = false; break; case 2: - document.getElementById('maincontent').src = '/edit_alignment.html?v=$COMMIT_HASH'; - document.getElementById('explaincontent').src = '/explain_2.html?v=$COMMIT_HASH'; + document.getElementById('maincontent').src = 'edit_alignment.html?v=$COMMIT_HASH'; + document.getElementById('explaincontent').src = 'explain_2.html?v=$COMMIT_HASH'; document.getElementById('h_iframe_explain').style.display = ""; document.getElementById("previous").disabled = false; document.getElementById("next").disabled = false; break; case 3: - document.getElementById('maincontent').src = '/edit_digits.html?v=$COMMIT_HASH'; - document.getElementById('explaincontent').src = '/explain_3.html?v=$COMMIT_HASH'; + document.getElementById('maincontent').src = 'edit_digits.html?v=$COMMIT_HASH'; + document.getElementById('explaincontent').src = 'explain_3.html?v=$COMMIT_HASH'; document.getElementById('h_iframe_explain').style.display = ""; document.getElementById("previous").disabled = false; document.getElementById("next").disabled = false; break; case 4: - document.getElementById('maincontent').src = '/edit_analog.html?v=$COMMIT_HASH'; - document.getElementById('explaincontent').src = '/explain_4.html?v=$COMMIT_HASH'; + document.getElementById('maincontent').src = 'edit_analog.html?v=$COMMIT_HASH'; + document.getElementById('explaincontent').src = 'explain_4.html?v=$COMMIT_HASH'; document.getElementById('h_iframe_explain').style.display = ""; document.getElementById("previous").disabled = false; document.getElementById("next").disabled = false; break; case 5: - document.getElementById('maincontent').src = '/edit_config_param.html?v=$COMMIT_HASH?InitialSetup=true'; - document.getElementById('explaincontent').src = '/explain_5.html?v=$COMMIT_HASH'; + document.getElementById('maincontent').src = 'edit_config_param.html?v=$COMMIT_HASH?InitialSetup=true'; + document.getElementById('explaincontent').src = 'explain_5.html?v=$COMMIT_HASH'; document.getElementById('h_iframe_explain').style.display = ""; document.getElementById("previous").disabled = false; document.getElementById("next").disabled = false; break; case 6: - document.getElementById('maincontent').src = '/edit_explain_6.html?v=$COMMIT_HASH'; - document.getElementById('explaincontent').src = '/explain_6.html?v=$COMMIT_HASH'; + document.getElementById('maincontent').src = 'edit_explain_6.html?v=$COMMIT_HASH'; + document.getElementById('explaincontent').src = 'explain_6.html?v=$COMMIT_HASH'; // Note: The page never gets shown! document.getElementById('h_iframe_explain').style.display = "none"; document.getElementById("previous").disabled = false; document.getElementById("next").disabled = true;