Преглед на файлове

Merge branch 'rolling' into add-log-level-to-logfile2

CaCO3 преди 3 години
родител
ревизия
1d367a58d5

+ 10 - 7
.github/workflows/build.yaml

@@ -1,6 +1,6 @@
 name: Build and Pack
 
-on: [push]
+on: [push, pull_request]
 
 jobs:
 #########################################################################################
@@ -77,23 +77,24 @@ jobs:
       id: vars
       run: |
         echo "sha_short=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
+        echo "branch=$(echo ${{ github.ref_name }} | tr / .)" >> $GITHUB_OUTPUT
 
     - name: Rename firmware file to contain versioning (old ota)
       run: |
         mkdir -p ./dist_old_ota
-        cp "./code/.pio/build/esp32cam/firmware.bin" "./dist_old_ota/firmware__${{ github.ref_name }}_(${{ steps.vars.outputs.sha_short }}).bin"
+        cp "./code/.pio/build/esp32cam/firmware.bin" "./dist_old_ota/firmware__${{ steps.vars.outputs.branch }}_(${{ steps.vars.outputs.sha_short }}).bin"
 
     - name: Upload Firmware artifact (old OTA concept)
       uses: actions/upload-artifact@v3
       with:
 #        name: "firmware__${{ github.ref_name }}__(${{ steps.vars.outputs.sha_short }})__(extract_before_upload__only_needed_for_migration_from_11.3.1)"
-        name: "firmware__(extract_before_upload)__${{ github.ref_name }}__(${{ steps.vars.outputs.sha_short }})"
+        name: "firmware__(extract_before_upload)__${{ steps.vars.outputs.branch }}__(${{ steps.vars.outputs.sha_short }})"
         path: ./dist_old_ota/*
 
     - name: Upload Web interface artifact (old OTA concept)
       uses: actions/upload-artifact@v3
       with:
-        name: "html__${{ github.ref_name }}__(${{ steps.vars.outputs.sha_short }})"
+        name: "html__${{ steps.vars.outputs.branch }}__(${{ steps.vars.outputs.sha_short }})"
         path: ./sd-card/html/*
 
 
@@ -127,6 +128,7 @@ jobs:
       id: vars
       run: |
         echo "sha_short=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
+        echo "branch=$(echo ${{ github.ref_name }} | tr / .)" >> $GITHUB_OUTPUT
 
     - name: Prepare update.zip artifact
       run: |
@@ -157,7 +159,7 @@ jobs:
     - name: Upload dist as update.zip artifact (Firmware + Web UI + CNN)
       uses: actions/upload-artifact@v3
       with:
-        name: "update__${{ github.ref_name }}_(${{ steps.vars.outputs.sha_short }})"
+        name: "update__${{ steps.vars.outputs.branch }}_(${{ steps.vars.outputs.sha_short }})"
         path: ./dist/*
 
     - name: Store generated files in cache
@@ -165,7 +167,7 @@ jobs:
       with:
         path: |
           ./dist
-        key: ${{ github.run_number }}-pack-for-OTA-v2
+        key: ${{ steps.vars.outputs.branch }}-pack-for-OTA-v2
 
 
 
@@ -195,6 +197,7 @@ jobs:
       id: vars
       run: |
         echo "sha_short=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
+        echo "branch=$(echo ${{ github.ref_name }} | tr / .)" >> $GITHUB_OUTPUT
 
     - name: Prepare artifacts for release
       run: |
@@ -211,7 +214,7 @@ jobs:
     - name: Upload initial_esp32_setup.zip artifact (Firmware + Bootloader + Partitions + Web UI)
       uses: actions/upload-artifact@v3
       with:
-        name: "initial_esp32_setup__${{ github.ref_name }}_(${{ steps.vars.outputs.sha_short }})"
+        name: "initial_esp32_setup__${{ steps.vars.outputs.branch }}_(${{ steps.vars.outputs.sha_short }})"
         path: ./firmware
 
     - name: Store generated files in cache

+ 6 - 0
Changelog.md

@@ -7,6 +7,12 @@
 -   added `/graph.html` to fetch measurements from the debug log and display them as a graph. Activate debug logging for this feature to work.
 -   Added PreValue to `/json` ([#1154](https://github.com/jomjol/AI-on-the-edge-device/issues/1154))
 -   Show graph of values direct in the user interface (thanks to [@rdmueller](https://github.com/rdmueller))
+-   SD card info into the "Info" Menue (thanks to [@Slider007]( https://github.com/Slider0007))
+-   Added a logging of the values in a text table in `/log/data` - each measurement is one line
+    -   Format: tabulator separated
+    -   Content: time, name-of-number, raw-value, return-value, pre-value, change-rate, change-absolute, error-text, cnn-digital, cnn-analog
+    -   ATTENTION: format not fully fixed yet!
+
 
 ### Changed
 

+ 62 - 4
code/components/jomjol_fileserver_ota/server_file.cpp

@@ -36,6 +36,8 @@ extern "C" {
 #include "defines.h"
 #include "ClassLogFile.h"
 
+#include "server_tflite.h""
+
 #include "server_help.h"
 #include "interface_mqtt.h"
 #include "server_GPIO.h"
@@ -78,13 +80,69 @@ using namespace std;
 string SUFFIX_ZW = "_0xge";
 
 
-esp_err_t get_tflite_file_handler(httpd_req_t *req)
+esp_err_t get_numbers_file_handler(httpd_req_t *req)
+{
+    std::string ret = tfliteflow.getNumbersName();
+
+//    ESP_LOGI(TAG, "Result get_numbers_file_handler: %s", ret.c_str());
+
+    httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
+    httpd_resp_set_type(req, "text/plain");
+
+    httpd_resp_sendstr_chunk(req, ret.c_str());
+    httpd_resp_sendstr_chunk(req, NULL);
+
+    return ESP_OK;
+}
+
+
+esp_err_t get_data_file_handler(httpd_req_t *req)
 {
-//    DIR *verzeichnis;
-//    struct dirent *files;
     struct dirent *entry;
-//    struct stat entry_stat;
 
+    std::string _filename, _fileext;
+    size_t pos = 0;
+    
+    const char verz_name[] = "/sdcard/log/data";
+    ESP_LOGD(TAG, "Suche TFLITE in /sdcard/log/data");
+
+    httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
+    httpd_resp_set_type(req, "text/plain");
+
+    DIR *dir = opendir(verz_name);
+    while ((entry = readdir(dir)) != NULL) 
+    {
+        _filename = std::string(entry->d_name);
+        ESP_LOGD(TAG, "File: %s", _filename.c_str());
+
+        // ignore all files with starting dot (hidden files)
+        if (_filename.rfind(".", 0) == 0) {
+            continue;
+        }
+
+        _fileext = _filename;
+        pos = _fileext.find_last_of(".");
+        if (pos != std::string::npos)
+            _fileext = _fileext.erase(0, pos + 1);
+
+        ESP_LOGD(TAG, " Extension: %s", _fileext.c_str());
+
+        if (_fileext == "txt")
+        {
+            _filename = _filename + "\t";
+            httpd_resp_sendstr_chunk(req, _filename.c_str());
+        }
+    }
+    closedir(dir);
+
+    httpd_resp_sendstr_chunk(req, NULL);
+    return ESP_OK;
+}
+
+
+esp_err_t get_tflite_file_handler(httpd_req_t *req)
+{
+    struct dirent *entry;
 
     std::string _filename, _fileext;
     size_t pos = 0;

+ 3 - 0
code/components/jomjol_fileserver_ota/server_file.h

@@ -10,3 +10,6 @@ std::string unzip_new(std::string _in_zip_file, std::string _target_zip, std::st
 void delete_all_in_directory(std::string _directory);
 
 esp_err_t get_tflite_file_handler(httpd_req_t *req);
+esp_err_t get_data_file_handler(httpd_req_t *req);
+esp_err_t get_numbers_file_handler(httpd_req_t *req);
+

+ 7 - 4
code/components/jomjol_flowcontroll/ClassFlowCNNGeneral.cpp

@@ -975,21 +975,24 @@ string ClassFlowCNNGeneral::getReadoutRawString(int _analog)
     if (GENERAL[_analog]->ROI.size() == 0)
         return rt;
  
-    for (int i = GENERAL[_analog]->ROI.size() - 1; i >= 0; --i)
+    for (int i = 0; i < GENERAL[_analog]->ROI.size(); ++i)
     {
         if (CNNType == Analogue || CNNType == Analogue100)
         {
-            rt = rt + "\t" + std::to_string(GENERAL[_analog]->ROI[i]->result_float);
+            rt = rt + "\t" + RundeOutput(GENERAL[_analog]->ROI[i]->result_float, 1);
         }
 
         if (CNNType == Digital)
         {
-            rt = rt + "\t" + std::to_string(GENERAL[_analog]->ROI[i]->result_klasse);
+            if (GENERAL[_analog]->ROI[i]->result_klasse == 10)
+                rt = rt + "\tN";
+            else
+                rt = rt + "\t" + RundeOutput(GENERAL[_analog]->ROI[i]->result_klasse, 0);
         }
 
         if ((CNNType == DoubleHyprid10) || (CNNType == Digital100))
         {
-            rt = rt + "\t" + std::to_string(GENERAL[_analog]->ROI[i]->result_float);
+            rt = rt + "\t" + RundeOutput(GENERAL[_analog]->ROI[i]->result_float, 1);
         }
     }
     return rt;

+ 6 - 0
code/components/jomjol_flowcontroll/ClassFlowControll.cpp

@@ -647,6 +647,12 @@ esp_err_t ClassFlowControll::GetJPGStream(std::string _fn, httpd_req_t *req)
     return result;
 }
 
+
+string ClassFlowControll::getNumbersName()
+{
+    return flowpostprocessing->getNumbersName();
+}
+
 string ClassFlowControll::getJSON(std::string _id, std::string _mac)
 {
     return flowpostprocessing->GetJSON(_id, _mac);

+ 1 - 0
code/components/jomjol_flowcontroll/ClassFlowControll.h

@@ -51,6 +51,7 @@ public:
 	string GetPrevalue(std::string _number = "");	
 	bool ReadParameter(FILE* pfile, string& aktparamgraph);	
 	string getJSON(std::string _id = "", std::string _mac = "");
+	string getNumbersName();
 
 	string TranslateAktstatus(std::string _input);
 

+ 34 - 6
code/components/jomjol_flowcontroll/ClassFlowPostProcessing.cpp

@@ -21,6 +21,22 @@ static const char* TAG = "class_flow_postproc";
 #define PREVALUE_TIME_FORMAT_INPUT "%d-%d-%dT%d:%d:%d"
 
 
+std::string ClassFlowPostProcessing::getNumbersName()
+{
+    std::string ret="";
+
+    for (int i = 0; i < NUMBERS.size(); ++i)
+    {
+        ret += NUMBERS[i]->name;
+        if (i < NUMBERS.size()-1)
+            ret = ret + "\t";
+    }
+
+//    ESP_LOGI(TAG, "Result ClassFlowPostProcessing::getNumbersName: %s", ret.c_str());
+
+    return ret;
+}
+
 std::string ClassFlowPostProcessing::GetJSON(std::string _id, std::string _mac, std::string _lineend)
 {
     std::string json="{" + _lineend;
@@ -848,17 +864,26 @@ bool ClassFlowPostProcessing::doFlow(string zwtime)
     return true;
 }
 
-void ClassFlowPostProcessing::WriteDataLog(int _analog)
+void ClassFlowPostProcessing::WriteDataLog(int _index)
 {
     string analog = "";
     string digital = "";
+    string timezw = "";
+    char buffer[80];
+    struct tm* timeinfo = localtime(&NUMBERS[_index]->lastvalue);
+    strftime(buffer, 80, PREVALUE_TIME_FORMAT_OUTPUT, timeinfo);
+    timezw = std::string(buffer);
+
     if (flowAnalog)
-        analog = flowAnalog->getReadoutRawString(_analog);
+        analog = flowAnalog->getReadoutRawString(_index);
     if (flowDigit)
-        digital = flowDigit->getReadoutRawString(_analog);
-//    LogFile.WriteToFile(ESP_LOG_INFO, analog);
-    LogFile.WriteToData(NUMBERS[_analog]->ReturnRawValue, NUMBERS[_analog]->ReturnValue, NUMBERS[_analog]->ReturnPreValue, NUMBERS[_analog]->ErrorMessageText, digital, analog);
-    ESP_LOGD(TAG, "WriteDataLog: %s, %s, %s, %s, %s", NUMBERS[_analog]->ReturnRawValue.c_str(), NUMBERS[_analog]->ReturnValue.c_str(), NUMBERS[_analog]->ErrorMessageText.c_str(), digital.c_str(), analog.c_str());
+        digital = flowDigit->getReadoutRawString(_index);
+    LogFile.WriteToData(timezw, NUMBERS[_index]->name, 
+                        NUMBERS[_index]->ReturnRawValue, NUMBERS[_index]->ReturnValue, NUMBERS[_index]->ReturnPreValue, 
+                        NUMBERS[_index]->ReturnRateValue, NUMBERS[_index]->ReturnChangeAbsolute,
+                        NUMBERS[_index]->ErrorMessageText, 
+                        digital, analog);
+    ESP_LOGD(TAG, "WriteDataLog: %s, %s, %s, %s, %s", NUMBERS[_index]->ReturnRawValue.c_str(), NUMBERS[_index]->ReturnValue.c_str(), NUMBERS[_index]->ErrorMessageText.c_str(), digital.c_str(), analog.c_str());
 }
 
 
@@ -918,6 +943,8 @@ string ClassFlowPostProcessing::getReadoutParam(bool _rawValue, bool _noerror, i
     return NUMBERS[_number]->ReturnValue;
 }
 
+/*  Jetzt als globale Funktion in Helper.h
+
 string ClassFlowPostProcessing::RundeOutput(double _in, int _anzNachkomma){
     std::stringstream stream;
     int _zw = _in;    
@@ -940,6 +967,7 @@ string ClassFlowPostProcessing::RundeOutput(double _in, int _anzNachkomma){
 
     return stream.str();  
 }
+*/
 
 
 string ClassFlowPostProcessing::ErsetzteN(string input, double _prevalue)

+ 2 - 2
code/components/jomjol_flowcontroll/ClassFlowPostProcessing.h

@@ -34,7 +34,6 @@ protected:
 
     string ErsetzteN(string, double _prevalue);
     float checkDigitConsistency(double input, int _decilamshift, bool _isanalog, double _preValue);
-    string RundeOutput(double _in, int _anzNachkomma);
 
     void InitNUMBERS();
     void handleDecimalSeparator(string _decsep, string _value);
@@ -44,7 +43,7 @@ protected:
     void handleAnalogDigitalTransitionStart(string _decsep, string _value);
     std::string GetStringReadouts(general);
 
-    void WriteDataLog(int _analog);
+    void WriteDataLog(int _index);
 
 
 
@@ -66,6 +65,7 @@ public:
     void SetPreValue(double zw, string _numbers, bool _extern = false);
 
     std::string GetJSON(std::string _id = "", std::string _mac = "", std::string _lineend = "\n");
+    std::string getNumbersName();
 
     void UpdateNachkommaDecimalShift();
 

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

@@ -2,6 +2,6 @@ FILE(GLOB_RECURSE app_sources ${CMAKE_CURRENT_SOURCE_DIR}/*.*)
 
 idf_component_register(SRCS ${app_sources}
                     INCLUDE_DIRS "."
-                    REQUIRES tflite-lib jomjol_logfile)
+                    REQUIRES tflite-lib jomjol_logfile fatfs sdmmc)
 
 

+ 242 - 6
code/components/jomjol_helper/Helper.cpp

@@ -7,6 +7,9 @@
 #include <sys/types.h>
 #include <sys/stat.h>
 
+#include <iomanip>
+#include <sstream>
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -20,7 +23,8 @@ extern "C" {
 
 
 #include "ClassLogFile.h"
-//#include "ClassLogFile.h"
+
+#include "esp_vfs_fat.h"
 
 static const char* TAG = "helper";
 
@@ -29,6 +33,9 @@ static const char* TAG = "helper";
 
 using namespace std;
 
+sdmmc_cid_t SDCardCid;
+sdmmc_csd_t SDCardCsd;
+
 /////////////////////////////////////////////////////////////////////////////////////////////
 string getESPHeapInfo(){
 	string espInfoResultStr = "";
@@ -75,8 +82,78 @@ size_t getInternalESPHeapSize() {
 	return aFreeInternalHeapSize;
 }
 
+string getSDCardPartitionSize(){
+	FATFS *fs;
+    uint32_t fre_clust, tot_sect;
+
+    /* Get volume information and free clusters of drive 0 */
+    f_getfree("0:", (DWORD *)&fre_clust, &fs);
+    tot_sect = ((fs->n_fatent - 2) * fs->csize) /1024 /(1024/SDCardCsd.sector_size);	//corrected by SD Card sector size (usually 512 bytes) and convert to MB
+
+    printf("%d MB total drive space (Sector size [bytes]: %d)\n", (int)tot_sect, (int)fs->csize*512);
+
+	return std::to_string(tot_sect);
+}
+
+string getSDCardFreePartitionSpace(){
+	FATFS *fs;
+    uint32_t fre_clust, fre_sect;
+  
+    /* Get volume information and free clusters of drive 0 */
+    f_getfree("0:", (DWORD *)&fre_clust, &fs);
+    fre_sect = (fre_clust * fs->csize) / 1024 /(1024/SDCardCsd.sector_size);	//corrected by SD Card sector size (usually 512 bytes) and convert to MB
 
+    printf("%d MB free drive space (Sector size [bytes]: %d)\n", (int)fre_sect, (int)fs->ssize);
+
+	return std::to_string(fre_sect);
+}
 
+string getSDCardPartitionAllocationSize(){
+	FATFS *fs;
+    uint32_t fre_clust, allocation_size;
+  
+    /* Get volume information and free clusters of drive 0 */
+    f_getfree("0:", (DWORD *)&fre_clust, &fs);
+    allocation_size = fs->ssize;
+
+    printf("SD Card Partition Allocation Size (bytes): %d)\n", allocation_size);
+
+	return std::to_string(allocation_size);
+}
+
+
+void SaveSDCardInfo(sdmmc_card_t* card) {
+	SDCardCid = card->cid;
+    SDCardCsd = card->csd;
+}
+
+string getSDCardManufacturer(){
+	string SDCardManufacturer = SDCardParseManufacturerIDs(SDCardCid.mfg_id);
+	printf("SD Card Manufactuer: %s\n", SDCardManufacturer.c_str());
+	
+	return (SDCardManufacturer + " (ID: " + std::to_string(SDCardCid.mfg_id) + ")");
+}
+
+string getSDCardName(){
+	char *SDCardName = SDCardCid.name;
+	printf("SD Card Name: %s\n", SDCardName); 
+
+	return std::string(SDCardName);
+}
+
+string getSDCardCapacity(){
+	int SDCardCapacity = SDCardCsd.capacity / (1024/SDCardCsd.sector_size) / 1024;  // total sectors * sector size  --> Byte to MB (1024*1024)
+	printf("SD Card Capacity: %s\n", std::to_string(SDCardCapacity).c_str()); 
+
+	return std::to_string(SDCardCapacity);
+}
+
+string getSDCardSectorSize(){
+	int SDCardSectorSize = SDCardCsd.sector_size;
+	printf("SD Card Sector Size: %s\n", std::to_string(SDCardSectorSize).c_str()); 
+
+	return std::to_string(SDCardSectorSize);
+}
 
 ///////////////////////////////////////////////////////////////////////////////////////////////
 
@@ -156,10 +233,9 @@ void FindReplace(std::string& line, std::string& oldString, std::string& newStri
 
 void MakeDir(std::string _what)
 {
-//	chdir(_where.c_str());
-
-	if (mkdir(_what.c_str(), S_IRWXU|S_IRWXG|S_IROTH))
-		ESP_LOGD(TAG, "Problem with MakeDir: %s", _what.c_str());
+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);
 }
 
 
@@ -462,7 +538,6 @@ int removeFolder(const char* folderPath, const char* logTag) {
 }
 
 
-
 std::vector<string> HelperZerlegeZeile(std::string input, std::string _delimiter = "")
 {
 	std::vector<string> Output;
@@ -487,3 +562,164 @@ std::vector<string> HelperZerlegeZeile(std::string input, std::string _delimiter
 	return Output;
 }
 
+
+/* Source: https://git.kernel.org/pub/scm/utils/mmc/mmc-utils.git/tree/lsmmc.c */
+/* SD Card Manufacturer Database */
+struct SDCard_Manufacturer_database {
+	string type;
+	int id;
+	string manufacturer;
+};
+
+/* Source: https://git.kernel.org/pub/scm/utils/mmc/mmc-utils.git/tree/lsmmc.c */
+/* SD Card Manufacturer Database */
+struct SDCard_Manufacturer_database database[] = {
+	{
+		.type = "sd",
+		.id = 0x01,
+		.manufacturer = "Panasonic",
+	},
+	{
+		.type = "sd",
+		.id = 0x02,
+		.manufacturer = "Toshiba/Kingston/Viking",
+	},
+	{
+		.type = "sd",
+		.id = 0x03,
+		.manufacturer = "SanDisk",
+	},
+	{
+		.type = "sd",
+		.id = 0x08,
+		.manufacturer = "Silicon Power",
+	},
+	{
+		.type = "sd",
+		.id = 0x18,
+		.manufacturer = "Infineon",
+	},
+	{
+		.type = "sd",
+		.id = 0x1b,
+		.manufacturer = "Transcend/Samsung",
+	},
+	{
+		.type = "sd",
+		.id = 0x1c,
+		.manufacturer = "Transcend",
+	},
+	{
+		.type = "sd",
+		.id = 0x1d,
+		.manufacturer = "Corsair/AData",
+	},
+	{
+		.type = "sd",
+		.id = 0x1e,
+		.manufacturer = "Transcend",
+	},
+	{
+		.type = "sd",
+		.id = 0x1f,
+		.manufacturer = "Kingston",
+	},
+	{
+		.type = "sd",
+		.id = 0x27,
+		.manufacturer = "Delkin/Phison",
+	},
+	{
+		.type = "sd",
+		.id = 0x28,
+		.manufacturer = "Lexar",
+	},
+	{
+		.type = "sd",
+		.id = 0x30,
+		.manufacturer = "SanDisk",
+	},
+	{
+		.type = "sd",
+		.id = 0x31,
+		.manufacturer = "Silicon Power",
+	},
+	{
+		.type = "sd",
+		.id = 0x33,
+		.manufacturer = "STMicroelectronics",
+	},
+	{
+		.type = "sd",
+		.id = 0x41,
+		.manufacturer = "Kingston",
+	},
+	{
+		.type = "sd",
+		.id = 0x6f,
+		.manufacturer = "STMicroelectronics",
+	},
+	{
+		.type = "sd",
+		.id = 0x74,
+		.manufacturer = "Transcend",
+	},
+	{
+		.type = "sd",
+		.id = 0x76,
+		.manufacturer = "Patriot",
+	},
+	{
+		.type = "sd",
+		.id = 0x82,
+		.manufacturer = "Gobe/Sony",
+	},
+	{
+		.type = "sd",
+		.id = 0x89,
+		.manufacturer = "Unknown",
+	}
+};
+
+/* Parse SD Card Manufacturer Database */
+string SDCardParseManufacturerIDs(int id) 
+{
+	unsigned int id_cnt = sizeof(database) / sizeof(struct SDCard_Manufacturer_database);
+	string ret_val = "";
+
+	for (int i = 0; i < id_cnt; i++) {
+		if (database[i].id == id) {
+			return database[i].manufacturer;
+		}
+		else {
+			ret_val = "ID unknown (not in DB)";
+		}
+	}
+	return ret_val;
+}
+
+
+string RundeOutput(double _in, int _anzNachkomma)
+{
+    std::stringstream stream;
+    int _zw = _in;    
+//    ESP_LOGD(TAG, "AnzNachkomma: %d", _anzNachkomma);
+
+    if (_anzNachkomma < 0) {
+        _anzNachkomma = 0;
+    }
+
+    if (_anzNachkomma > 0)
+    {
+        stream << std::fixed << std::setprecision(_anzNachkomma) << _in;
+        return stream.str();          
+    }
+    else
+    {
+        stream << _zw;
+    }
+
+
+    return stream.str();  
+}
+

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

@@ -2,7 +2,7 @@
 #include <string>
 #include <fstream>
 #include <vector>
-
+#include "sdmmc_cmd.h"
 
 using namespace std;
 
@@ -15,6 +15,8 @@ void RenameFile(string from, string to);
 void MakeDir(std::string _what);
 
 
+string RundeOutput(double _in, int _anzNachkomma);
+
 
 FILE* OpenFileAndWait(const char* nm, const char* _mode, int _waitsec = 1);
 
@@ -47,3 +49,13 @@ size_t getESPHeapSize();
 string getESPHeapInfo();
 
 /////////////////////////////
+string getSDCardPartitionSize();
+string getSDCardFreePartitionSpace();
+string getSDCardPartitionAllocationSize();
+
+void SaveSDCardInfo(sdmmc_card_t* card);
+string SDCardParseManufacturerIDs(int);
+string getSDCardManufacturer();
+string getSDCardName();
+string getSDCardCapacity();
+string getSDCardSectorSize();

+ 20 - 17
code/components/jomjol_logfile/ClassLogFile.cpp

@@ -63,7 +63,7 @@ std::string ClassLogFile::getESPHeapInfo(){
 	return 	espInfoResultStr;
 }
 
-void ClassLogFile::WriteToData(std::string _ReturnRawValue, std::string _ReturnValue, std::string _ReturnPreValue, std::string _ErrorMessageText, std::string _digital, std::string _analog)
+void ClassLogFile::WriteToData(std::string _timestamp, std::string _name, std::string  _ReturnRawValue, std::string  _ReturnValue, std::string  _ReturnPreValue, std::string  _ReturnRateValue, std::string  _ReturnChangeAbsolute, std::string  _ErrorMessageText, std::string  _digital, std::string  _analog)
 {
     ESP_LOGD(TAG, "Start WriteToData");
     time_t rawtime;
@@ -87,29 +87,23 @@ void ClassLogFile::WriteToData(std::string _ReturnRawValue, std::string _ReturnV
     pFile = fopen(logpath.c_str(), "a+");
 
     if (pFile!=NULL) {
-        time_t rawtime;
-        struct tm* timeinfo;
-        char buffer[80];
-
-        time(&rawtime);
-        timeinfo = localtime(&rawtime);
-
-        strftime(buffer, 80, "%Y-%m-%dT%H:%M:%S", timeinfo);
-
-        zwtime = std::string(buffer) + ":\t";
-        fputs(zwtime.c_str(), pFile);
+        fputs(_timestamp.c_str(), pFile);
+        fputs("\t", pFile);
+        fputs(_name.c_str(), pFile);
+        fputs("\t", pFile);
         fputs(_ReturnRawValue.c_str(), pFile);
         fputs("\t", pFile);
         fputs(_ReturnValue.c_str(), pFile);
         fputs("\t", pFile);
         fputs(_ReturnPreValue.c_str(), pFile);
         fputs("\t", pFile);
-        fputs(_ErrorMessageText.c_str(), pFile);
+        fputs(_ReturnRateValue.c_str(), pFile);
         fputs("\t", pFile);
-        fputs(_digital.c_str(), pFile);
+        fputs(_ReturnChangeAbsolute.c_str(), pFile);
         fputs("\t", pFile);
+        fputs(_ErrorMessageText.c_str(), pFile);
+        fputs(_digital.c_str(), pFile);
         fputs(_analog.c_str(), pFile);
-        fputs("\t", pFile);
         fputs("\n", pFile);
 
         fclose(pFile);    
@@ -311,6 +305,17 @@ void ClassLogFile::RemoveOld()
     closedir(dir);
 }
 
+void ClassLogFile::CreateLogDirectories()
+{
+    MakeDir("/sdcard/log");
+    MakeDir("/sdcard/log/data");
+    MakeDir("/sdcard/log/analog");
+    MakeDir("/sdcard/log/digit");
+    MakeDir("/sdcard/log/message");
+    MakeDir("/sdcard/log/source");
+}
+
+
 ClassLogFile::ClassLogFile(std::string _logroot, std::string _logfile, std::string _logdatapath, std::string _datafile)
 {
     logroot = _logroot;
@@ -321,6 +326,4 @@ ClassLogFile::ClassLogFile(std::string _logroot, std::string _logfile, std::stri
     retentionInDays = 10;
     loglevel = ESP_LOG_INFO;
     MakeDir("/sdcard/log/data");
-    MakeDir("/sdcard/test");
-    MakeDir("/test");
 }

+ 4 - 1
code/components/jomjol_logfile/ClassLogFile.h

@@ -27,9 +27,12 @@ public:
 
     void WriteToFile(esp_log_level_t level, std::string info, bool _time = true);
     void WriteToDedicatedFile(std::string _fn, esp_log_level_t level, std::string info, bool _time = true);
+
+    void CreateLogDirectories();
     void RemoveOld();
 
-    void WriteToData(std::string _ReturnRawValue, std::string _ReturnValue, std::string _ReturnPreValue, std::string _ErrorMessageText, std::string _digital, std::string _analog);
+//    void WriteToData(std::string _ReturnRawValue, std::string _ReturnValue, std::string _ReturnPreValue, std::string _ErrorMessageText, std::string _digital, std::string _analog);
+    void WriteToData(std::string _timestamp, std::string _name, std::string  _ReturnRawValue, std::string  _ReturnValue, std::string  _ReturnPreValue, std::string  _ReturnRateValue, std::string  _ReturnChangeAbsolute, std::string  _ErrorMessageText, std::string  _digital, std::string  _analog);
 
 
     std::string GetCurrentFileName();

+ 12 - 0
code/components/jomjol_tfliteclass/server_tflite.cpp

@@ -397,6 +397,18 @@ esp_err_t handler_editflow(httpd_req_t *req)
         }
     }  
 
+    if (_task.compare("namenumbers") == 0)
+    {
+        ESP_LOGI(TAGTFLITE, "Get NUMBER list");
+        return get_numbers_file_handler(req);
+    }
+
+    if (_task.compare("data") == 0)
+    {
+        ESP_LOGI(TAGTFLITE, "Get data list");
+        return get_data_file_handler(req);
+    }
+
     if (_task.compare("tflite") == 0)
     {
         ESP_LOGD(TAGTFLITE, "Get tflite list");

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

@@ -3,6 +3,7 @@
 
 #include <esp_http_server.h>
 #include "CImageBasis.h"
+#include "ClassFlowControll.h"
 
 //#include "ClassControllCamera.h"
 
@@ -19,3 +20,5 @@ std::string GetMQTTMainTopic();
 esp_err_t GetJPG(std::string _filename, httpd_req_t *req);
 
 esp_err_t GetRawJPG(httpd_req_t *req);
+
+extern ClassFlowControll tfliteflow;

+ 13 - 1
code/main/main.cpp

@@ -111,8 +111,9 @@ bool Init_NVS_SDCard()
         }
         return false;
     }
-    sdmmc_card_print_info(stdout, card);
 
+    sdmmc_card_print_info(stdout, card);
+    SaveSDCardInfo(card);
     return true;
 }
 
@@ -166,6 +167,17 @@ extern "C" void app_main(void)
 
     CheckOTAUpdate();
 
+    LogFile.CreateLogDirectories();
+/*
+    int mk_ret = mkdir("/sdcard/new_fd_mkdir", 0775);
+    ESP_LOGI(TAGMAIN, "mkdir ret %d", mk_ret);
+    mk_ret = mkdir("/sdcard/new_fd_mkdir/test", 0775);
+    ESP_LOGI(TAGMAIN, "mkdir ret %d", mk_ret);
+    MakeDir("/sdcard/test2");
+    MakeDir("/sdcard/test2/intern");
+*/
+
+
     char *ssid = NULL, *passwd = NULL, *hostname = NULL, *ip = NULL, *gateway = NULL, *netmask = NULL, *dns = NULL;
     LoadWlanFromFile("/sdcard/wlan.ini", ssid, passwd, hostname, ip, gateway, netmask, dns);
 

+ 66 - 0
code/main/server_main.cpp

@@ -16,6 +16,7 @@
 #include "server_tflite.h"
 #include "esp_log.h"
 
+#include "Helper.h"
 
 //#define DEBUG_DETAIL_ON      
 
@@ -136,6 +137,71 @@ esp_err_t info_get_handler(httpd_req_t *req)
         return ESP_OK;        
     }
 
+    if (_task.compare("SDCardPartitionSize") == 0)
+    {
+        std::string zw;
+        zw = getSDCardPartitionSize();
+        httpd_resp_sendstr_chunk(req, zw.c_str());
+        httpd_resp_sendstr_chunk(req, NULL);  
+        return ESP_OK;        
+    }
+
+    if (_task.compare("SDCardFreePartitionSpace") == 0)
+    {
+        std::string zw;
+        zw = getSDCardFreePartitionSpace();
+        httpd_resp_sendstr_chunk(req, zw.c_str());
+        httpd_resp_sendstr_chunk(req, NULL);  
+        return ESP_OK;        
+    }
+
+    if (_task.compare("SDCardPartitionAllocationSize") == 0)
+    {
+        std::string zw;
+        zw = getSDCardPartitionAllocationSize();
+        httpd_resp_sendstr_chunk(req, zw.c_str());
+        httpd_resp_sendstr_chunk(req, NULL);  
+        return ESP_OK;        
+    }
+
+    if (_task.compare("SDCardManufacturer") == 0)
+    {
+        std::string zw;
+        zw = getSDCardManufacturer(); 
+        httpd_resp_sendstr_chunk(req, zw.c_str());
+        httpd_resp_sendstr_chunk(req, NULL);  
+        return ESP_OK;        
+    }
+
+    if (_task.compare("SDCardName") == 0)
+    {
+        std::string zw;
+        zw = getSDCardName(); 
+        httpd_resp_sendstr_chunk(req, zw.c_str());
+        httpd_resp_sendstr_chunk(req, NULL);  
+        return ESP_OK;        
+    }
+
+    if (_task.compare("SDCardCapacity") == 0)
+    {
+        std::string zw;
+        zw = getSDCardCapacity();
+        httpd_resp_sendstr_chunk(req, zw.c_str());
+        httpd_resp_sendstr_chunk(req, NULL);  
+        return ESP_OK;        
+    }
+
+    if (_task.compare("SDCardSectorSize") == 0)
+    {
+        std::string zw;
+        zw = getSDCardSectorSize();
+        httpd_resp_sendstr_chunk(req, zw.c_str());
+        httpd_resp_sendstr_chunk(req, NULL);  
+        return ESP_OK;        
+    }
+
+
+
     return ESP_OK;
 }
 

+ 3 - 35
sd-card/html/edit_config_param.html

@@ -328,21 +328,6 @@ textarea {
 				Time to keep the separated digit images (in days, resp. "0" = forever)
 			</td>
 		</tr>
-<!--
-
-		<tr class="expert"  id="ex9">
-			<td class="indent1">
-				<class id="Digits_ModelInputSize_text" style="color:black;">ModelInputSize</class>
-			</td>
-			<td>
-				x: <input type="number" id="Digits_ModelInputSize_value1" class="smallSelect" min="1" step="1">
-				y: <input type="number" id="Digits_ModelInputSize_value2" class="smallSelect" min="1" step="1">
-			</td>
-			<td style="font-size: 80%;">
-				Size of the input image for the CNN model
-			</td>
-		</tr>
--->
 
 		<tr id="Category_Analog_ex4">
 			<td colspan="3" style="padding-left: 20px;">
@@ -377,19 +362,6 @@ textarea {
 			<td style="font-size: 80%;"> Time to keep the separated digit images (in days, resp. "0" = forever) </td>
 		</tr>
 
-<!--
-
-		<tr class="expert"  id="ex10">
-			<td class="indent1"> </td>
-			<td> <class id="Analog_ModelInputSize_text" style="color:black;">ModelInputSize</class> </td>
-			<td>
-				x: <input type="number" id="Analog_ModelInputSize_value1" class="smallSelect" min="1" step="1">
-				y: <input type="number" id="Analog_ModelInputSize_value2" class="smallSelect" min="1" step="1">
-			</td>
-			<td style="font-size: 80%;"> Size of the input image for the CNN model </td>
-		</tr>
--->
-
 		<tr>
 			<td colspan="3" style="padding-left: 20px;"><h4>PostProcessing</h4></td>
 		</tr> 		
@@ -527,7 +499,7 @@ textarea {
 				</select>
 			</td>
 			<td style="font-size: 80%;">
-				Defines if the change rate compared to the previous value is calculated as absolute change (AbsoluteChange) or as rate normalized to the intervall (RateChange = change/minute).
+				Defines if the change rate compared to the previous value is calculated as absolute change (AbsoluteChange) or as rate normalized to the interval (RateChange = change/minute).
 			</td>
 		</tr>
 		<tr>
@@ -743,13 +715,13 @@ textarea {
 		</tr>
 		<tr>
 			<td class="indent1">
-			    <class id="AutoTimer_Intervall_text" style="color:black;">Intervall</class>
+			    <class id="AutoTimer_Intervall_text" style="color:black;">Interval</class>
 			</td>
 			<td>
 				<input type="number" id="AutoTimer_Intervall_value1" size="13" min="3" step="any">
 			</td>
 			<td style="font-size: 80%;">
-				Intervall in which the counter is read (in minutes). Number must be greater than 3 minutes.
+				Interval in which the number(s) are read (in minutes). If a run takes longer than this interval, the next run gets postponed until the current run completes.
 			</td>
 		</tr>
 
@@ -1727,11 +1699,9 @@ function UpdateInput() {
 	WriteParameter(param, category, "Digits", "CNNGoodThreshold", true);
 	WriteParameter(param, category, "Digits", "LogImageLocation", true);		
 	WriteParameter(param, category, "Digits", "LogfileRetentionInDays", true);		
-//	WriteParameter(param, category, "Digits", "ModelInputSize", false);	
 	
 	WriteParameter(param, category, "Analog", "LogImageLocation", true);		
 	WriteParameter(param, category, "Analog", "LogfileRetentionInDays", true);		
-//	WriteParameter(param, category, "Analog", "ModelInputSize", false);		
 	
 	WriteParameter(param, category, "PostProcessing", "PreValueUse", true);		
 	WriteParameter(param, category, "PostProcessing", "PreValueAgeStartup", true);		
@@ -1844,12 +1814,10 @@ function ReadParameterAll()
 	ReadParameter(param, "Digits", "CNNGoodThreshold", true);
 	ReadParameter(param, "Digits", "LogImageLocation", true);		
 	ReadParameter(param, "Digits", "LogfileRetentionInDays", true);		
-//	ReadParameter(param, "Digits", "ModelInputSize", false);
 
 	ReadParameter(param, "Analog", "Model", false);		
 	ReadParameter(param, "Analog", "LogImageLocation", true);		
 	ReadParameter(param, "Analog", "LogfileRetentionInDays", true);		
-//	ReadParameter(param, "Analog", "ModelInputSize", false);
 
 	ReadParameter(param, "PostProcessing", "PreValueUse", true);		
 	ReadParameter(param, "PostProcessing", "PreValueAgeStartup", true);		

+ 82 - 27
sd-card/html/graph.html

@@ -2,6 +2,11 @@
 <html>
     <head>
     <script src='https://cdn.plot.ly/plotly-2.14.0.min.js'></script>
+
+    <script type="text/javascript" src="./gethost.js"></script> 
+    <script type="text/javascript" src="./readconfigcommon.js"></script>  
+    <script type="text/javascript" src="./readconfigparam.js"></script>  
+
     <style>
         textarea {
             width: 600px;
@@ -13,34 +18,35 @@
       var el = document.getElementById('cnsl');
       el && eval(el.value);
     }
+
+
     </script>
     </head>
     <body>
     <div id='chart'></div>
-    <select id="selector" onchange="document.location.href=document.location.href.split('#')[0]+'#'+this.value;run();"></select>
+    <select id="datafiles" onchange="run();"></select>
+    <select id="numbers" onchange="run();"></select>
+    <select id="datatype" onchange="run();">
+        <option value="3">Value</option>
+        <option value="4">PreValue</option>
+        <option value="5">Change-Rate</option>
+        <option value="6">Change-Absolut</option>
+      </select>
+
     <button onclick="document.getElementById('editor').hidden = false; this.hidden = true;" >Editor</button>
     <div id='editor' hidden='true'>
     <textarea id="cnsl">
-var hash = window.location.hash;
-console.log (hash);
-var d = new Date();
-var options="<option>Please Select...</option>";
-for (var i=0;  i<27; i++) {
-  var currentDate = new Date(d-i*60*60*24*1000);
-  var option = currentDate.getFullYear()+"-"+(currentDate.getMonth()+1)+"-"+currentDate.getDate()
-  options += "<option>"+option+"</option>\n";
-}
-document.getElementById("selector").innerHTML = options;
-
-var dateString = d.getFullYear() + "-" + (d.getMonth()+1) + "-" + d.getDate();    
-if (hash!="") {
-  dateString = hash.substring(1);
-}
-fetch('/fileserver/log/message/log_'+dateString+'.txt')
+datefile = document.getElementById("datafiles").value;
+numbername = document.getElementById("numbers").value;
+datatype = document.getElementById("datatype").value;
+//alert("Auslesen: " + datefile + " " + numbername);
+
+_basepath = getbasepath(); 
+fetch(_basepath + '/fileserver/log/data/' + datefile)
 .then(response => {
     // handle the response
     if (response.status == 404) {
-      alert("no log data available for "+dateString);
+        alert("no log data available for "+dateString);
     }
     response.text()
     .then( result => {
@@ -53,15 +59,18 @@ fetch('/fileserver/log/message/log_'+dateString+'.txt')
 
         var timex = 1;
         for (let line of lines) {
-            if (line.includes("PostProcessing - Raw")) {
+            {
                 console.log(line);
-                var value = line.split(" ")[6];
-                var time  = line.split(" ")[0];
-                console.log("> "+time+" "+value+"\n");
-                if (value<1000) {
-                    trace.x.push(timex);
-                    timex += 1;
-                    trace.y.push(value);
+                if (line.split("\t")[1] == numbername)
+                {
+                    var value = line.split("\t")[datatype];
+                    var time  = line.split("\t")[0];
+                    console.log("> "+time+" "+value+"\n");
+                    if (value<1000) {
+                        trace.x.push(timex);
+                        timex += 1;
+                        trace.y.push(value);
+                    }
                 }
             }
         }
@@ -77,6 +86,52 @@ alert("test");
 </textarea><br />
 <button onclick="run();">run</button>
 </div>
-<script>run();</script>
+<script>
+
+function WriteModelFiles()
+    {
+        list_data = getDATAList();
+
+        var _indexDig = document.getElementById("datafiles");
+        while (_indexDig.length)
+            _indexDig.remove(0);
+
+        for (var i = list_data.length - 1; i >= 0; --i)
+        {
+            var optionDig = document.createElement("option");
+            
+            var text = list_data[i];
+            optionDig.text = text;
+            optionDig.value = list_data[i];
+            _indexDig.add(optionDig);
+        }
+    }
+
+    function WriteNumbers()
+    {
+        list_data = getNUMBERSList();
+
+        var _indexDig = document.getElementById("numbers");
+        while (_indexDig.length)
+            _indexDig.remove(0);
+
+        for (var i = 0; i < list_data.length; ++i)
+        {
+            var optionDig = document.createElement("option");
+            
+            var text = list_data[i];
+            optionDig.text = text;
+            optionDig.value = list_data[i];
+            _indexDig.add(optionDig);
+        }
+    }
+
+    WriteModelFiles();
+    WriteNumbers();
+
+
+
+run();
+</script>
 </body>
 </html>

+ 78 - 0
sd-card/html/info.html

@@ -77,6 +77,84 @@ div {
 	</tr>
 </table>
 
+
+<table style="font-family: arial">
+<h3>SD Card Info</h3>
+<table style="font-family: arial">
+	<tr>
+		<td>
+			SD Card Manufacturer:
+		</td>
+		<td>
+			<div id="SDCardManufacturer">
+				<object data="/version?type=SDCardManufacturer"></object>
+			</div>
+		</td>
+	</tr>
+	<tr>
+		<td>
+			SD Card Name:
+		</td>
+		<td>
+			<div id="SDCardName">
+				<object data="/version?type=SDCardName"></object>
+			</div>
+		</td>
+	</tr>
+	<tr>
+		<td>
+			SD Card Size [MB]:
+		</td>
+		<td>
+			<div id="SDCardCapacity">
+				<object data="/version?type=SDCardCapacity"></object>
+			</div>
+		</td>
+	</tr>
+	<tr>
+		<td>
+			SD Card Sector Size [byte]:
+		</td>
+		<td>
+			<div id="SDCardSectorSize">
+				<object data="/version?type=SDCardSectorSize"></object>
+			</div>
+		</td>
+	</tr>
+	<tr>
+		<td>
+			Partition Size [MB]:
+		</td>
+		<td>
+			<div id="SDPartitionSize">
+				<object data="/version?type=SDCardPartitionSize"></object>
+			</div>
+		</td>
+	</tr>
+	<tr>
+		<td>
+			Partition Free Space [MB]:
+		</td>	
+		<td>
+			<div id="SDFreePartitionSpace">
+				<object data="/version?type=SDCardFreePartitionSpace"></object>
+			</div>
+		</td>
+	</tr>
+	<tr>
+		<td>
+			Partition Allocation Size [byte]:
+		</td>	
+		<td>
+			<div id="SDCardPartitionAllocationSize">
+				<object data="/version?type=SDCardPartitionAllocationSize"></object>
+			</div>
+		</td>
+	</tr>
+</table>
+
+
+<table style="font-family: arial">
 <h3>Version Info</h3>
 
 <table style="font-family: arial">

+ 62 - 0
sd-card/html/readconfigparam.js

@@ -11,6 +11,68 @@ var NUMBERS = new Array(0);
 var REFERENCES = new Array(0);
 
 
+function getNUMBERSList() {
+	_basepath = getbasepath(); 
+     var datalist = "";
+
+	var xhttp = new XMLHttpRequest();
+	xhttp.addEventListener('load', function(event) {
+	  if (xhttp.status >= 200 && xhttp.status < 300) {
+		datalist = xhttp.responseText;
+	  } else {
+		 console.warn(request.statusText, request.responseText);
+	  }
+	 });
+
+	 try {
+		  url = _basepath + '/editflow.html?task=namenumbers';     
+		  xhttp.open("GET", url, false);
+		  xhttp.send();
+
+	 }
+	 catch (error)
+	 {
+               alert("Loading Hostname failed");
+	 }
+
+      datalist = datalist.split("\t");
+//      datalist.pop();
+
+      return datalist;
+  }
+
+
+function getDATAList() {
+	_basepath = getbasepath(); 
+     tflitelist = "";
+
+	var xhttp = new XMLHttpRequest();
+	xhttp.addEventListener('load', function(event) {
+	  if (xhttp.status >= 200 && xhttp.status < 300) {
+		tflitelist = xhttp.responseText;
+	  } else {
+		 console.warn(request.statusText, request.responseText);
+	  }
+	 });
+
+	 try {
+		  url = _basepath + '/editflow.html?task=data';     
+		  xhttp.open("GET", url, false);
+		  xhttp.send();
+
+	 }
+	 catch (error)
+	 {
+//               alert("Loading Hostname failed");
+	 }
+
+      tflitelist = tflitelist.split("\t");
+      tflitelist.pop();
+
+      return tflitelist;
+  }
+
+
 function getTFLITEList() {
 	_basepath = getbasepath(); 
      tflitelist = "";