Merge branch 'rolling'

# Conflicts:
#	Changelog.md
#	code/components/jomjol_helper/Helper.cpp
#	code/components/jomjol_helper/Helper.h
#	sd-card/html/edit_config_param.html
#	sd-card/html/readconfigparam.js
This commit is contained in:
CaCO3
2023-02-24 20:19:45 +01:00
43 changed files with 941 additions and 307 deletions

View File

@@ -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();

View File

@@ -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);

View File

@@ -65,7 +65,7 @@ bool ClassFlowAlignment::ReadParameter(FILE* pfile, string& aktparamgraph)
std::vector<string> 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;
}

View File

@@ -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());

View File

@@ -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"

View File

@@ -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;

View File

@@ -0,0 +1,219 @@
#ifdef ENABLE_INFLUXDB
#include <sstream>
#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 <time.h>
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<ClassFlow*>* 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<ClassFlow*>* 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<string> 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<NumberPost*>* 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

View File

@@ -0,0 +1,41 @@
#ifdef ENABLE_INFLUXDB
#pragma once
#ifndef CLASSFINFLUXDBv2_H
#define CLASSFINFLUXDBv2_H
#include "ClassFlow.h"
#include "ClassFlowPostProcessing.h"
#include <string>
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<ClassFlow*>* lfc);
ClassFlowInfluxDBv2(std::vector<ClassFlow*>* 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

View File

@@ -15,7 +15,6 @@ class ClassFlowPostProcessing :
public ClassFlow
{
protected:
std::vector<NumberPost*> NUMBERS;
bool UpdatePreValueINI;
int PreValueAgeStartup;
@@ -54,6 +53,8 @@ protected:
public:
bool PreValueUse;
std::vector<NumberPost*> NUMBERS;
ClassFlowPostProcessing(std::vector<ClassFlow*>* lfc, ClassFlowCNNGeneral *_analog, ClassFlowCNNGeneral *_digit);
virtual ~ClassFlowPostProcessing(){};

View File

@@ -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<string> HelperZerlegeZeile(std::string input, std::string _delimiter
std::vector<string> ZerlegeZeile(std::string input, std::string delimiter)
{
std::vector<string> Output;
input = trim(input, delimiter);
/* The input can have multiple formats:
* - key = value
* - key = value1 value2 value3 ...
@@ -593,12 +625,13 @@ std::vector<string> 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) {

View File

@@ -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);

View File

@@ -8,10 +8,17 @@
#include <map>
#include <functional>
// 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

View File

@@ -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);