Compare commits

..

22 Commits

Author SHA1 Message Date
jomjol
961662f483 Merge branch 'rolling' 2022-12-04 15:48:18 +01:00
jomjol
306b1a75a5 Merge branch 'rolling' of https://github.com/jomjol/AI-on-the-edge-device into rolling 2022-12-04 15:47:46 +01:00
jomjol
7350864150 QuickFix MQTT Reboot 2022-12-04 15:47:38 +01:00
CaCO3
16d0758ea3 remove redundant log text ("5 minutes delay" gets loged further down already. (#1480)
Co-authored-by: CaCO3 <caco@ruinelli.ch>
2022-12-04 15:43:44 +01:00
jomjol
877a1b14e5 Merge branch 'rolling' of https://github.com/jomjol/AI-on-the-edge-device into rolling 2022-12-04 15:12:25 +01:00
jomjol
a122b37c81 Quick Fix for MQTT Init Problem 2022-12-04 15:12:20 +01:00
CaCO3
ad137b329b compare only the first 7 characters of the hashes (#1472)
Co-authored-by: CaCO3 <caco@ruinelli.ch>
2022-12-03 22:28:22 +01:00
Slider0007
85905a7045 Improve MQTT connection handling (#1462)
* modify mqtt init at startup + after disconnection

* mqtt_init only when not initialized

* Minor udapte

* Apply suggestions from code review

Co-authored-by: CaCO3 <caco3@ruinelli.ch>

* Correct typo

Co-authored-by: CaCO3 <caco3@ruinelli.ch>
2022-12-03 19:10:44 +01:00
github-actions
9847f95c93 Update Changelog.md for release 2022-12-02 21:29:30 +00:00
jomjol
e9e13588f6 Merge branch 'rolling' 2022-12-02 22:20:32 +01:00
jomjol
6c8a45f2dc Update to espressif v5.2.0 2022-12-02 22:05:00 +01:00
CaCO3
e7d28f9bde Update Changelog.md 2022-12-02 18:21:08 +01:00
CaCO3
33015351d6 Update Changelog.md (#1444)
* Update Changelog.md

* add latest PR to changelog

* Update Changelog.md
2022-12-02 18:19:53 +01:00
github-actions
0a461b2bd0 Update Changelog.md for release 2022-12-02 16:41:49 +00:00
jomjol
ecf1e78208 Update Changelog.md 2022-12-02 17:30:07 +01:00
Slider0007
a8b9acf170 Disable heap logs by default (#1464)
* disabale heap logs by default

* Cleanup log (INFO->DEBUG)
2022-12-02 17:00:31 +01:00
CaCO3
45a3138d28 write logfile logs earlier, shorten startup banner, add uptime to logfile (#1443)
Co-authored-by: CaCO3 <caco@ruinelli.ch>
2022-12-02 16:59:25 +01:00
CaCO3
7e997889aa add MQTT status topic (#1438) 2022-11-30 20:26:11 +01:00
CaCO3
6c51af7107 Use only commit hash for comparison instead whole string (#1436)
* Use only commit hash for comparison instead whole string

* .
2022-11-30 20:25:34 +01:00
CaCO3
8be7beab9a Add the timezone to the time output fomat (#1435)
* Add the timezone to the time output fomat, see https://github.com/jomjol/AI-on-the-edge-device/issues/1428

* use correct device class for timestamp
2022-11-30 20:25:03 +01:00
jomjol
62ec8d76c6 Update LogDownloader 2022-11-29 20:46:37 +01:00
github-actions
7a634797c4 Update Changelog.md for release 2022-11-28 20:11:57 +00:00
32 changed files with 476 additions and 723 deletions

View File

@@ -1,33 +1,37 @@
# Changelog
## [Unreleased]
## [Unreleased]
**Home Assistant MQTT Discovery Support**
### Update Procedure
:bangbang: **Make sure to read the instructions below carfully!**.
1. Backup your configuration (use the `System -> Backup/Restore` page)!
1. You should update to `12.0.1` before you update to this release. All other migrations are untested.
1. Upload and update the `update-*.zip` file from this release.
1. Let it restart and check on the `System -> Info` page that the Firmware as well as the Web UI got updated. If only one got updated, redo the update. If it fails several times, you also can update the Firmware and the Web UI separately.
1. Safe way:
1. Update first the `firmware.bin` (extract from zip file) and do the Reboot
1. Update with the full zip file (`update-*.zip`, ignore the version warning after the reboot)
1. Please go to `Settings -> Configuration` and address the changed parameters:
* DataLogging (storing the values for data graph)
* Debug (extended by different debug reporting levels)
2. You should update to `12.0.1` before you update to this release. All other migrations are untested.
3. Upload and update the `update-*.zip` file from this release.
4. Let it restart and check on the `System -> Info` page that the Firmware as well as the Web UI got updated. If only one got updated, redo the update. If it fails several times, you also can update the Firmware and the Web UI separately.
5. Safe way:
1. Update first the `firmware.bin` (extract from zip file) and do the Reboot
2. Update with the full zip file (`update-*.zip`, ignore the version warning after the reboot)
6. Please go to `Settings -> Configuration` and address the changed parameters:
- DataLogging (storing the values for data graph)
- Debug (extended by different debug reporting levels)
If anything breaks you can try to enforce manual update as following:
**OTA:**
1. Make sure the last run of the update completed the **Uploading** step.
1. Call `http://<IP>/ota?task=update&file=<UPLOAD_FILENAME>` to enforce the extraction/flashing.
1\. Make sure the last run of the update completed the **Uploading** step.
1\. Call `http://<IP>/ota?task=update&file=<UPLOAD_FILENAME>` to enforce the extraction/flashing.
**Initial Setup:**
1. Use the initial_esp32_setup.zip ( <https://github.com/jomjol/AI-on-the-edge-device/wiki/Installation> ) as alternative to have a clean install.
1\. Use the initial_esp32_setup.zip ( <https://github.com/jomjol/AI-on-the-edge-device/wiki/Installation> ) as alternative to have a clean install.
### Added
@@ -38,16 +42,16 @@ If anything breaks you can try to enforce manual update as following:
- Format: csv - comma separated
- Content: `time`, `name-of-number`, `raw-value`, `return-value`, `pre-value`, `change-rate`, `change-absolute`, `error-text`, `cnn-digital`, `cnn-analog`
- Show graph of values direct in the user interface (thanks to [@rdmueller](https://github.com/rdmueller))
- Using new data logging (see above)
- Possibility to choose different values and switch between different numbers (if present)
Note: You need to activate data logging for this feature to work, see above!
- PreValue is now contained in `/json` ([#1154](https://github.com/jomjol/AI-on-the-edge-device/issues/1154))
- SD card info into the `System>Info` menu (thanks to [@Slider007]( https://github.com/Slider0007))
- SD card info into the `System>Info` menu (thanks to [@Slider007](https://github.com/Slider0007))
- Version check (Firmware vs. Web UI)
- Various minor new features
### Changed
- Updated tflite (`dig-cont_0600_s3.tflite`)
@@ -55,23 +59,29 @@ If anything breaks you can try to enforce manual update as following:
- Updated Espressif library to `espressif32@v5.2.0`
- [#1176](https://github.com/jomjol/AI-on-the-edge-device/discussions/1176) accept minor negative values (-0.2) if extended resolution is enabled
- [#1143](https://github.com/jomjol/AI-on-the-edge-device/issues/1143) added config parameter `AnalogDigitalTransitionStart`. It can setup very early and very late digit transition starts.
- New version of `dig-class100` (v1.4.0): added images of heliowatt powermeter
- New version of `dig-class100` (v1.4.0): added images of heliowatt powermeter
- NEW v13.0.2: Update Tool "Logfile downloader and combiner" to handle the new csv file format.
- NEW v13.0.2: MQTT: Added MQTT topic `status` (Digitalization Status), Timezone to MQTT topic `timestamp`.#
- NEW v13.0.2: Logging: Disable heap logs by default, cleanup
### Fixed
- [#1116](https://github.com/jomjol/AI-on-the-edge-device/issues/1116) precision problem at setting prevalue
- [#1119](https://github.com/jomjol/AI-on-the-edge-device/issues/1119) renamed `firmware.bin` not working in OTA
- [#1143](https://github.com/jomjol/AI-on-the-edge-device/issues/1143) changed postprocess for `analog->digit` (lowest digit processing)
- [#1280](https://github.com/jomjol/AI-on-the-edge-device/issues/1280) check ROIs name for unsupported characters
- [#983](https://github.com/jomjol/AI-on-the-edge-device/issues/983) old log files did not get deleted
- Failed NTP time sync during startup gets now retried every round if needed
- Whitespaces and `=` in MQTT and InfluxDB passwords
- Various minor fixes and improvements
- [#1280](https://github.com/jomjol/AI-on-the-edge-device/issues/1280) check ROIs name for unsupported characters
- [#983](https://github.com/jomjol/AI-on-the-edge-device/issues/983) old log files did not get deleted
- Failed NTP time sync during startup gets now retried every round if needed
- Whitespaces and `=` in MQTT and InfluxDB passwords
- Various minor fixes and improvements
- NEW v13.0.2: Corrected Version comparison between firmware and Web UI.
- NEW v13.0.3: Re-updated build environment to v5.2.0 (from accidental downgrad to v4.4.0)
- **NEW v13.0.4**: Fix for reboot in case of MQTT not used
### Removed
- n.a.
## [12.0.1] 2022-09-29
Improve **u**ser e**x**perience
@@ -88,8 +98,8 @@ Improve **u**ser e**x**perience
5. Now you can reboot.
If anything breaks you can try to
1. Call `http://<IP>/ota?task=update&file=firmware.bin` resp. `http://<IP>/ota?task=update&file=html.zip` if the upload successed but the extraction failed.
1. Use the initial_esp32_setup.zip ( <https://github.com/jomjol/AI-on-the-edge-device/wiki/Installation> ) as alternative.
1\. Call `http://<IP>/ota?task=update&file=firmware.bin` resp. `http://<IP>/ota?task=update&file=html.zip` if the upload successed but the extraction failed.
1\. Use the initial_esp32_setup.zip ( <https://github.com/jomjol/AI-on-the-edge-device/wiki/Installation> ) as alternative.
### Added
@@ -741,7 +751,9 @@ External Illumination
- Initial Version
[Unreleased]: https://github.com/jomjol/AI-on-the-edge-device/compare/12.0.1...HEAD
[Unreleased]: https://github.com/jomjol/AI-on-the-edge-device/compare/13.0.1...HEAD
[13.0.1]: https://github.com/jomjol/AI-on-the-edge-device/compare/12.0.1...13.0.1
[12.0.1]: https://github.com/jomjol/AI-on-the-edge-device/compare/11.3.1...12.0.1

View File

@@ -30,7 +30,7 @@
static const char *TAG = "GPIO";
QueueHandle_t gpio_queue_handle = NULL;
#define DEBUG_DETAIL_ON
//#define DEBUG_DETAIL_ON
GpioPin::GpioPin(gpio_num_t gpio, const char* name, gpio_pin_mode_t mode, gpio_int_type_t interruptType, uint8_t dutyResolution, std::string mqttTopic, bool httpEnable)
{

View File

@@ -506,7 +506,7 @@ static esp_err_t send_logfile(httpd_req_t *req, bool send_full_file)
/* Close file after sending complete */
fclose(fd);
ESP_LOGI(TAG, "File sending complete");
ESP_LOGD(TAG, "File sending complete");
/* Respond with an empty chunk to signal HTTP response completion */
httpd_resp_send_chunk(req, NULL, 0);
@@ -582,7 +582,7 @@ static esp_err_t download_get_handler(httpd_req_t *req)
httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
ESP_LOGI(TAG, "Sending file : %s (%ld bytes)...", filename, file_stat.st_size);
ESP_LOGD(TAG, "Sending file : %s (%ld bytes)...", filename, file_stat.st_size);
set_content_type_from_file(req, filename);
/* Retrieve the pointer to scratch buffer for temporary storage */
@@ -608,7 +608,7 @@ static esp_err_t download_get_handler(httpd_req_t *req)
/* Close file after sending complete */
fclose(fd);
ESP_LOGI(TAG, "File successfully sent");
ESP_LOGD(TAG, "File successfully sent");
/* Respond with an empty chunk to signal HTTP response completion */
httpd_resp_send_chunk(req, NULL, 0);

View File

@@ -42,7 +42,7 @@ esp_err_t send_file(httpd_req_t *req, std::string filename)
return ESP_FAIL;
}
ESP_LOGI(TAG, "Sending file : %s ...", filename.c_str());
ESP_LOGD(TAG, "Sending file : %s ...", filename.c_str());
// httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
set_content_type_from_file(req, filename.c_str());
@@ -69,7 +69,7 @@ esp_err_t send_file(httpd_req_t *req, std::string filename)
/* Close file after sending complete */
fclose(fd);
ESP_LOGI(TAG, "File sending complete");
ESP_LOGD(TAG, "File sending complete");
return ESP_OK;
}

View File

@@ -19,6 +19,8 @@ extern "C" {
#include "time_sntp.h"
#include "Helper.h"
#include "server_ota.h"
#include "interface_mqtt.h"
#include "server_mqtt.h"
//#include "CImg.h"
@@ -30,7 +32,6 @@ extern "C" {
static const char* TAG = "FLOW CTRL";
std::string ClassFlowControll::doSingleStep(std::string _stepname, std::string _host){
std::string _classname = "";
std::string result = "";
@@ -139,6 +140,15 @@ string ClassFlowControll::GetMQTTMainTopic()
return "";
}
bool ClassFlowControll::StartMQTTService() {
/* Start the MQTT service */
for (int i = 0; i < FlowControll.size(); ++i) {
if (FlowControll[i]->name().compare("ClassFlowMQTT") == 0) {
return ((ClassFlowMQTT*) (FlowControll[i]))->Start(AutoIntervall);
}
}
return false;
}
void ClassFlowControll::SetInitialParameter(void)
@@ -275,7 +285,10 @@ void ClassFlowControll::doFlowMakeImageOnly(string time){
if (FlowControll[i]->name() == "ClassFlowMakeImage") {
// zw_time = gettimestring("%Y%m%d-%H%M%S");
zw_time = gettimestring("%H:%M:%S");
aktstatus = TranslateAktstatus(FlowControll[i]->name()) + " (" + zw_time + ")";
std::string flowStatus = TranslateAktstatus(FlowControll[i]->name());
aktstatus = flowStatus + " (" + zw_time + ")";
MQTTPublish(mqttServer_getMainTopic() + "/" + "status", flowStatus, false);
FlowControll[i]->doFlow(time);
}
}
@@ -302,14 +315,14 @@ bool ClassFlowControll::doFlow(string time)
for (int i = 0; i < FlowControll.size(); ++i)
{
zw_time = gettimestring("%H:%M:%S");
aktstatus = TranslateAktstatus(FlowControll[i]->name()) + " (" + zw_time + ")";
std::string flowStatus = TranslateAktstatus(FlowControll[i]->name());
aktstatus = flowStatus + " (" + zw_time + ")";
MQTTPublish(mqttServer_getMainTopic() + "/" + "status", flowStatus, false);
// zw_time = gettimestring("%Y%m%d-%H%M%S");
// aktstatus = zw_time + ": " + FlowControll[i]->name();
string zw = "FlowControll.doFlow - " + FlowControll[i]->name();
LogFile.WriteHeapInfo(zw);
#ifdef DEBUG_DETAIL_ON
LogFile.WriteHeapInfo(zw);
#endif
if (!FlowControll[i]->doFlow(time)){
repeat++;
@@ -333,7 +346,9 @@ bool ClassFlowControll::doFlow(string time)
}
zw_time = gettimestring("%H:%M:%S");
aktstatus = "Flow finished (" + zw_time + ")";
std::string flowStatus = "Flow finished";
aktstatus = flowStatus + " (" + zw_time + ")";
MQTTPublish(mqttServer_getMainTopic() + "/" + "status", flowStatus, false);
return result;
}
@@ -547,12 +562,6 @@ bool ClassFlowControll::ReadParameter(FILE* pfile, string& aktparamgraph)
}
}
}
/* Start the MQTT service */
for (int i = 0; i < FlowControll.size(); ++i)
if (FlowControll[i]->name().compare("ClassFlowMQTT") == 0)
return ((ClassFlowMQTT*) (FlowControll[i]))->Start(AutoIntervall);
return true;
}
@@ -560,7 +569,7 @@ bool ClassFlowControll::ReadParameter(FILE* pfile, string& aktparamgraph)
int ClassFlowControll::CleanTempFolder() {
const char* folderPath = "/sdcard/img_tmp";
ESP_LOGI(TAG, "Clean up temporary folder to avoid damage of sdcard sectors : %s", folderPath);
ESP_LOGD(TAG, "Clean up temporary folder to avoid damage of sdcard sectors : %s", folderPath);
DIR *dir = opendir(folderPath);
if (!dir) {
ESP_LOGE(TAG, "Failed to stat dir : %s", folderPath);
@@ -582,7 +591,7 @@ int ClassFlowControll::CleanTempFolder() {
}
}
closedir(dir);
ESP_LOGI(TAG, "%d files deleted", deleted);
ESP_LOGD(TAG, "%d files deleted", deleted);
return 0;
}
@@ -670,10 +679,10 @@ esp_err_t ClassFlowControll::GetJPGStream(std::string _fn, httpd_req_t *req)
if (_send)
{
ESP_LOGI(TAG, "Sending file : %s ...", _fn.c_str());
ESP_LOGD(TAG, "Sending file : %s ...", _fn.c_str());
set_content_type_from_file(req, _fn.c_str());
result = _send->SendJPGtoHTTP(req);
ESP_LOGI(TAG, "File sending complete");
ESP_LOGD(TAG, "File sending complete");
/* Respond with an empty chunk to signal HTTP response completion */
httpd_resp_send_chunk(req, NULL, 0);
}

View File

@@ -71,6 +71,7 @@ public:
t_CNNType GetTypeDigital();
t_CNNType GetTypeAnalog();
bool StartMQTTService();
int CleanTempFolder();

View File

@@ -189,6 +189,15 @@ string ClassFlowMQTT::GetMQTTMainTopic()
bool ClassFlowMQTT::Start(float AutoIntervall) {
// printf("URI: %s, MAINTOPIC: %s", uri.c_str(), maintopic.c_str());
if ((uri.length() == 0) || (maintopic.length() == 0))
{
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "MQTT not started because URI or Maintopic is not set. MQTT will be disabled.");
MQTTdisable();
return false;
}
roundInterval = AutoIntervall; // Minutes
keepAlive = roundInterval * 60 * 2.5; // Seconds, make sure it is greater thatn 2 rounds!
@@ -203,9 +212,8 @@ bool ClassFlowMQTT::Start(float AutoIntervall) {
keepAlive, SetRetainFlag, (void *)&GotConnected);
if (!MQTT_Init()) {
if (!MQTT_Init()) { // Retry
return false;
}
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Init at startup failed! Retry with next publish call");
return false;
}
return true;

View File

@@ -17,7 +17,7 @@ static const char* TAG = "FLOW POSTPROC";
//#define SERIAL_DEBUG // testing debug on serial enabled
#define PREVALUE_TIME_FORMAT_OUTPUT "%Y-%m-%dT%H:%M:%S"
#define PREVALUE_TIME_FORMAT_OUTPUT "%Y-%m-%dT%H:%M:%S%z"
#define PREVALUE_TIME_FORMAT_INPUT "%d-%d-%dT%d:%d:%d"
@@ -858,7 +858,7 @@ bool ClassFlowPostProcessing::doFlow(string zwtime)
string _zw = "PostProcessing - Raw: " + NUMBERS[j]->ReturnRawValue + " Value: " + NUMBERS[j]->ReturnValue + " Error: " + NUMBERS[j]->ErrorMessageText;
ESP_LOGD(TAG, "%s", zw.c_str());
LogFile.WriteToFile(ESP_LOG_INFO, TAG, _zw);
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, _zw);
WriteDataLog(j);
}

View File

@@ -12,6 +12,7 @@ static const char* TAG = "c_align_and_cut_image";
//#define GET_MEMORY malloc
#define GET_MEMORY(X) heap_caps_malloc(X, MALLOC_CAP_SPIRAM)
// #define DEBUG_DETAIL_ON
CAlignAndCutImage::CAlignAndCutImage(CImageBasis *_org, CImageBasis *_temp)

View File

@@ -23,10 +23,10 @@ ClassLogFile LogFile("/sdcard/log/message", "log_%Y-%m-%d.txt", "/sdcard/log/dat
void ClassLogFile::WriteHeapInfo(std::string _id)
{
std::string _zw = _id;
if (loglevel > ESP_LOG_WARN)
if (loglevel >= ESP_LOG_DEBUG) {
_zw = _zw + "\t" + getESPHeapInfo();
WriteToFile(ESP_LOG_DEBUG, "HEAP", _zw);
WriteToFile(ESP_LOG_DEBUG, "HEAP", _zw);
}
}
@@ -164,7 +164,9 @@ void ClassLogFile::WriteToDedicatedFile(std::string _fn, esp_log_level_t level,
break;
}
logline = logline + "\t<" + loglevelString + ">\t" + message.c_str() + "\n";
char uptime[20];
snprintf(uptime, sizeof(uptime), "%8d", (uint32_t)(esp_timer_get_time()/1000/1000)); // in seconds
logline = "[" + std::string(uptime) + "] " + logline + "\t<" + loglevelString + ">\t" + message + "\n";
fputs(logline.c_str(), pFile);
fclose(pFile);
} else {
@@ -337,7 +339,7 @@ void ClassLogFile::RemoveOldLogFile()
}
}
}
ESP_LOGI(TAG, "log files deleted: %d | files not deleted (incl. leer.txt): %d", deleted, notDeleted);
ESP_LOGD(TAG, "log files deleted: %d | files not deleted (incl. leer.txt): %d", deleted, notDeleted);
closedir(dir);
}
@@ -388,7 +390,7 @@ void ClassLogFile::RemoveOldDataLog()
}
}
}
ESP_LOGI(TAG, "data files deleted: %d | files not deleted (incl. leer.txt): %d", deleted, notDeleted);
ESP_LOGD(TAG, "data files deleted: %d | files not deleted (incl. leer.txt): %d", deleted, notDeleted);
closedir(dir);
}

View File

@@ -8,7 +8,9 @@
#define __HIDE_PASSWORD
static const char *TAG = "MQTT INTERFACE";
//#define DEBUG_DETAIL_ON
static const char *TAG = "MQTT IF";
std::map<std::string, std::function<void()>>* connectFunktionMap = NULL;
std::map<std::string, std::function<bool(std::string, char*, int)>>* subscribeFunktionMap = NULL;
@@ -16,9 +18,12 @@ std::map<std::string, std::function<bool(std::string, char*, int)>>* subscribeFu
int failedOnRound = -1;
bool MQTT_Enabled = true;
esp_mqtt_event_id_t esp_mmqtt_ID = MQTT_EVENT_ANY;
// ESP_EVENT_ANY_ID
bool mqtt_initialized = false;
bool mqtt_connected = false;
esp_mqtt_client_handle_t client = NULL;
std::string uri, client_id, lwt_topic, lwt_connected, lwt_disconnected, user, password, maintopic;
@@ -26,6 +31,11 @@ int keepalive, SetRetainFlag;
void (*callbackOnConnected)(std::string, int) = NULL;
void MQTTdisable()
{
MQTT_Enabled = false;
}
bool MQTTPublish(std::string _key, std::string _content, int retained_flag) {
int msg_id;
std::string zw;
@@ -34,27 +44,27 @@ bool MQTTPublish(std::string _key, std::string _content, int retained_flag) {
return true; // Fail quietly
}
LogFile.WriteHeapInfo("MQTT Publish");
if (!mqtt_connected) {
LogFile.WriteToFile(ESP_LOG_WARN, TAG, "Not connected, trying to re-connect...");
#ifdef DEBUG_DETAIL_ON
LogFile.WriteHeapInfo("MQTT Publish");
#endif
if (!mqtt_initialized) {
if (!MQTT_Init()) {
if (!MQTT_Init()) { // Retry
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Failed to init, skipping all MQTT publishings in this round!");
failedOnRound = getCountFlowRounds();
return false;
}
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Init failed, skipping all MQTT publishings in this round!");
failedOnRound = getCountFlowRounds();
return false;
}
}
}
msg_id = esp_mqtt_client_publish(client, _key.c_str(), _content.c_str(), 0, 1, retained_flag);
if (msg_id < 0) {
LogFile.WriteToFile(ESP_LOG_WARN, TAG, "Failed to publish topic '" + _key + "', re-trying...");
esp_mqtt_client_reconnect(client);
msg_id = esp_mqtt_client_publish(client, _key.c_str(), _content.c_str(), 0, 1, retained_flag);
if (msg_id < 0) {
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Failed to publish topic '" + _key + "', skipping all MQTT publishings in this round!");
mqtt_connected = false; // Force re-init on next call
failedOnRound = getCountFlowRounds();
return false;
}
@@ -87,9 +97,7 @@ static esp_err_t mqtt_event_handler_cb(esp_mqtt_event_handle_t event)
break;
case MQTT_EVENT_DISCONNECTED:
ESP_LOGD(TAG, "MQTT_EVENT_DISCONNECTED");
LogFile.WriteToFile(ESP_LOG_WARN, TAG, "Disconnected! Going to re-connect...");
mqtt_connected = false; // Force re-init on next call
esp_mqtt_client_reconnect(client);
mqtt_connected = false;
break;
case MQTT_EVENT_SUBSCRIBED:
ESP_LOGD(TAG, "MQTT_EVENT_SUBSCRIBED, msg_id=%d", event->msg_id);
@@ -118,7 +126,8 @@ static esp_err_t mqtt_event_handler_cb(esp_mqtt_event_handle_t event)
break;
case MQTT_EVENT_ERROR:
ESP_LOGD(TAG, "MQTT_EVENT_ERROR");
mqtt_connected = false; // Force re-init on next call
mqtt_initialized = false; // Force re-init on next publish call
mqtt_connected = false;
break;
default:
ESP_LOGD(TAG, "Other event id:%d", event->event_id);
@@ -161,6 +170,16 @@ void MQTT_Configure(std::string _mqttURI, std::string _clientid, std::string _us
}
bool MQTT_Init() {
if (MQTT_Enabled == false)
return false;
if ((client_id.length() == 0) || (lwt_topic.length() == 0))
{
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, std::string("Init with no Client_ID or Topic. Abort Init!"));
return false;
}
esp_err_t ret;
LogFile.WriteToFile(ESP_LOG_INFO, TAG, std::string("Init"));
@@ -175,7 +194,9 @@ bool MQTT_Init() {
.lwt_msg = lw.c_str(),
.lwt_retain = 1,
.lwt_msg_len = (int)(lw.length()),
.keepalive = keepalive
.keepalive = keepalive,
.disable_auto_reconnect = false, // Reconnection routine active
.reconnect_timeout_ms = 10000 // Try to reconnect to broker every 10s
};
if (user.length() && password.length()){
@@ -183,7 +204,10 @@ bool MQTT_Init() {
mqtt_cfg.password = password.c_str();
};
LogFile.WriteHeapInfo("MQTT Client Init");
#ifdef DEBUG_DETAIL_ON
LogFile.WriteHeapInfo("MQTT Client Init");
#endif
client = esp_mqtt_client_init(&mqtt_cfg);
if (client)
{
@@ -191,10 +215,13 @@ bool MQTT_Init() {
if (ret != ESP_OK)
{
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Could not register event (ret=" + std::to_string(ret) + ")!");
mqtt_initialized = false;
return false;
}
LogFile.WriteHeapInfo("MQTT Client Start");
#ifdef DEBUG_DETAIL_ON
LogFile.WriteHeapInfo("MQTT Client Start");
#endif
ret = esp_mqtt_client_start(client);
if (ret != ESP_OK)
{
@@ -203,25 +230,31 @@ bool MQTT_Init() {
if (ret != ESP_OK)
{
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Could not start client (ret=" + std::to_string(ret) + ")!");
mqtt_initialized = false;
return false;
}
}
}
else
{
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Could not init client!");
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Init failed, no handle created!");
mqtt_initialized = false;
return false;
}
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Init successful");
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Client started, waiting for established connection...");
mqtt_initialized = true;
return true;
}
void MQTTdestroy_client() {
if (client != NULL) {
if (client) {
esp_mqtt_client_stop(client);
esp_mqtt_client_destroy(client);
client = NULL;
mqtt_initialized = false;
mqtt_connected = false;
}
}
@@ -275,7 +308,7 @@ void MQTTregisterSubscribeFunction(std::string topic, std::function<bool(std::st
void MQTTconnected(){
if (mqtt_connected) {
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Connected");
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Connected to broker");
MQTTPublish(lwt_topic, lwt_connected, true);

View File

@@ -21,4 +21,6 @@ void MQTTregisterSubscribeFunction(std::string topic, std::function<bool(std::st
void MQTTdestroySubscribeFunction();
void MQTTconnected();
void MQTTdisable();
#endif //INTERFACE_MQTT_H

View File

@@ -139,6 +139,9 @@ void MQTThomeassistantDiscovery() {
sendHomeAssistantDiscoveryTopic("", "CPUtemp", "CPU Temperature", "thermometer", "°C", "temperature", "measurement", "diagnostic");
sendHomeAssistantDiscoveryTopic("", "interval", "Interval", "clock-time-eight-outline", "min", "" , "measurement", "diagnostic");
sendHomeAssistantDiscoveryTopic("", "IP", "IP", "network-outline", "", "", "", "diagnostic");
sendHomeAssistantDiscoveryTopic("", "status", "Status", "list-status", "", "", "", "diagnostic");
for (int i = 0; i < (*NUMBERS).size(); ++i) {
std::string group = (*NUMBERS)[i]->name;
@@ -150,11 +153,7 @@ void MQTThomeassistantDiscovery() {
// sendHomeAssistantDiscoveryTopic(group, "rate", "Rate (Unit/Minute)", "swap-vertical", "", "", "", ""); // Legacy, always Unit per Minute
sendHomeAssistantDiscoveryTopic(group, "rate_per_time_unit", "Rate (" + rateUnit + ")", "swap-vertical", rateUnit, "", "", "");
sendHomeAssistantDiscoveryTopic(group, "rate_per_digitalization_round", "Change since last digitalization round", "arrow-expand-vertical", valueUnit, "", "measurement", ""); // correctly the Unit is Uint/Interval!
/* The timestamp string misses the Timezone, see PREVALUE_TIME_FORMAT_OUTPUT!
We need to know the timezone and append it! Until we do this, we simply
do not set the device class to "timestamp" to avoid errors in Homeassistant! */
// sendHomeAssistantDiscoveryTopic(group, "timestamp", "Timestamp", "clock-time-eight-outline", "", "timestamp", "", "diagnostic");
sendHomeAssistantDiscoveryTopic(group, "timestamp", "Timestamp", "clock-time-eight-outline", "", "", "", "diagnostic");
sendHomeAssistantDiscoveryTopic(group, "timestamp", "Timestamp", "clock-time-eight-outline", "", "timestamp", "", "diagnostic");
sendHomeAssistantDiscoveryTopic(group, "json", "JSON", "code-json", "", "", "", "diagnostic");
sendHomeAssistantDiscoveryTopic(group, "problem", "Problem", "alert-outline", "", "", "", ""); // Special binary sensor which is based on error topic
}
@@ -240,3 +239,7 @@ void setMqtt_Server_Retain(int _retainFlag) {
void mqttServer_setMainTopic( std::string _maintopic) {
maintopic = _maintopic;
}
std::string mqttServer_getMainTopic() {
return maintopic;
}

View File

@@ -10,6 +10,7 @@ void mqttServer_setParameter(std::vector<NumberPost*>* _NUMBERS, int interval, f
void mqttServer_setMeterType(std::string meterType, std::string valueUnit, std::string timeUnit,std::string rateUnit);
void setMqtt_Server_Retain(int SetRetainFlag);
void mqttServer_setMainTopic( std::string maintopic);
std::string mqttServer_getMainTopic();
void register_server_mqtt_uri(httpd_handle_t server);

View File

@@ -23,7 +23,7 @@
#include "server_file.h"
#include "connect_wlan.h"
#define DEBUG_DETAIL_ON
//#define DEBUG_DETAIL_ON
ClassFlowControll tfliteflow;
@@ -103,6 +103,8 @@ void doInit(void)
#ifdef DEBUG_DETAIL_ON
ESP_LOGD(TAG, "Finished tfliteflow.InitFlow(config);");
#endif
tfliteflow.StartMQTTService();
}

View File

@@ -1,2 +1,3 @@
manifest_hash: 45994dbfed009907994c31f6d279c5861a1eacbf219ce8b58e74e39b3393816a
manifest_hash: 4e37bb0f9273c4de05f38688720fe32aa6e5b892452694a4f7a2ca1659f02cf6
target: esp32
version: 1.0.0

View File

@@ -41,9 +41,9 @@ const char* GIT_BRANCH=\"${GIT_BRANCH}\";
const char* BUILD_TIME=\"${BUILD_TIME}\";")
if ("${GIT_TAG}" STREQUAL "") # Tag not set, show branch
set(VERSION_HTML "Development-Branch: ${GIT_BRANCH} (Commit: ${GIT_REV}${GIT_DIFF})")
set(VERSION_HTML "Development-Branch: ${GIT_BRANCH} (Commit: ${GIT_REV}${GIT_DIFF})\n${GIT_REV}")
else() # Tag is set, ignore branch
set(VERSION_HTML "Release: ${GIT_TAG} (Commit: ${GIT_REV}${GIT_DIFF})")
set(VERSION_HTML "Release: ${GIT_TAG} (Commit: ${GIT_REV}${GIT_DIFF})\n${GIT_REV}")
endif()
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/version.cpp)

View File

@@ -35,7 +35,8 @@ extern const char* GIT_REV;
extern const char* GIT_BRANCH;
extern const char* BUILD_TIME;
extern const char* getHTMLversion(void);
extern std::string getHTMLversion(void);
extern std::string getHTMLcommit(void);
#define __HIDE_PASSWORD
@@ -169,26 +170,16 @@ extern "C" void app_main(void)
string versionFormated = "Tag: '" + std::string(GIT_TAG) + "', " + versionFormated;
}
ESP_LOGD(TAG, "=============================================================================================");
ESP_LOGD(TAG, "%s", versionFormated.c_str());
ESP_LOGD(TAG, "=============================================================================================");
ESP_LOGD(TAG, "Reset reason: %s", getResetReason().c_str());
LogFile.CreateLogDirectories();
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "=================================================");
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "==================== Startup ====================");
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "=================================================");
LogFile.WriteToFile(ESP_LOG_INFO, TAG, versionFormated);
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Reset reason: " + getResetReason());
CheckOTAUpdate();
LogFile.CreateLogDirectories();
CheckUpdate();
/*
int mk_ret = mkdir("/sdcard/new_fd_mkdir", 0775);
ESP_LOGI(TAG, "mkdir ret %d", mk_ret);
mk_ret = mkdir("/sdcard/new_fd_mkdir/test", 0775);
ESP_LOGI(TAG, "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);
@@ -222,20 +213,18 @@ extern "C" void app_main(void)
vTaskDelay( xDelay );
if (!setup_time()) {
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "NTP Initialization failed. Will restart in 5 minutes!");
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "NTP Initialization failed!");
initSucessful = false;
}
setBootTime();
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "=============================================================================================");
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "=================================== Main Started ============================================");
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "=============================================================================================");
LogFile.WriteToFile(ESP_LOG_INFO, TAG, versionFormated);
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Reset reason: " + getResetReason());
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "=================================================");
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "================== Main Started =================");
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "=================================================");
if (std::string(getHTMLversion()) != std::string(GIT_REV)) {
LogFile.WriteToFile(ESP_LOG_WARN, TAG, "Web UI version does not match firmware version!");
if (getHTMLcommit().substr(0, 7) != std::string(GIT_REV).substr(0, 7)) { // Compare the first 7 characters of both hashes
LogFile.WriteToFile(ESP_LOG_WARN, TAG, std::string("Web UI version (") + getHTMLcommit() + ") does not match firmware version (" + std::string(GIT_REV) + ") !");
}
std::string zw = gettimestring("%Y%m%d-%H%M%S");
@@ -259,14 +248,14 @@ extern "C" void app_main(void)
vTaskDelay( xDelay );
if (camStatus != ESP_OK) {
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Failed to initialize camera module. Will restart in 5 minutes!");
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Failed to initialize camera module!");
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Check that your camera module is working and connected properly!");
initSucessful = false;
}
} else { // Test Camera
camera_fb_t * fb = esp_camera_fb_get();
if (!fb) {
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Camera Framebuffer cannot be initialzed. Will restart in 5 minutes!");
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Camera Framebuffer cannot be initialized!");
initSucessful = false;
}
else {

View File

@@ -92,7 +92,7 @@ esp_err_t info_get_handler(httpd_req_t *req)
}
else if (_task.compare("HTMLVersion") == 0)
{
httpd_resp_sendstr_chunk(req, getHTMLversion());
httpd_resp_sendstr_chunk(req, getHTMLversion().c_str());
httpd_resp_sendstr_chunk(req, NULL);
return ESP_OK;
}

View File

@@ -38,20 +38,35 @@ const char* libfive_git_branch(void)
}
char _char_getHTMLversion[100]="?\0";
const char* getHTMLversion(void){
std::string getHTMLversion(void){
char buf[100]="?\0";
FILE* pFile;
string fn = FormatFileName("/sdcard/html/version.txt");
pFile = fopen(fn.c_str(), "r");
if (pFile == NULL)
return _char_getHTMLversion;
return std::string(buf);
fgets(_char_getHTMLversion, sizeof(_char_getHTMLversion), pFile);
fgets(buf, sizeof(buf), pFile); // Line 1: Version
fclose(pFile);
return _char_getHTMLversion;
return std::string(buf);
}
std::string getHTMLcommit(void){
char buf[100]="?\0";
FILE* pFile;
string fn = FormatFileName("/sdcard/html/version.txt");
pFile = fopen(fn.c_str(), "r");
if (pFile == NULL)
return std::string(buf);
fgets(buf, sizeof(buf), pFile); // Line 1: Version -> ignored
fgets(buf, sizeof(buf), pFile); // Line 2: Commit
fclose(pFile);
return std::string(buf);
}
#endif // _VERSION_H

View File

@@ -13,9 +13,7 @@
src_dir = main
[env:esp32cam]
platform = espressif32@4.4.0
;platform = espressif32@5.1.0
;platform = espressif32
platform = espressif32@5.2.0
board = esp32cam
;board = m5stack-core-esp32
framework = espidf

View File

@@ -100,6 +100,6 @@ function compareVersions() {
console.log("FW Hash: " + fWGitHash + ", Web UI Hash: " + webUiHash);
if (fWGitHash != webUiHash) {
alert("The Version of the Web Interface does not match the Firmware Version! It is suggested to keep them on the same version!");
alert("The Version of the Web Interface (" + webUiHash + ") does not match the Firmware Version (" + fWGitHash + ")! It is suggested to keep them on the same version!");
}
}

View File

@@ -1268,7 +1268,7 @@ textarea {
<input type="number" id="AutoTimer_Intervall_value1" size="13" min="3" step="any">
</td>
<td style="font-size: 80%;">
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.
Interval in which the number(s) are read (in minutes). If a digitalization round takes longer than this interval, the next run gets postponed until the current run completes.
</td>
</tr>

View File

@@ -57,6 +57,10 @@
function processLogLine(line, index, arr) {
/* Make sure the whitespaces in the uptime field get persevered */
uptimePart = line.slice(0, line.indexOf("]")).replace(/ /g, "&nbsp;");
line = uptimePart + line.slice(line.indexOf("]"))
if (line.includes("&lt;WRN&gt;")) {
arr[index] = "<span style=\"color:#e83c00\">" + line + "</span>";
}
@@ -66,7 +70,10 @@
else if (line.includes("&lt;DBG&gt;")) {
arr[index] = "<span style=\"color:gray\">" + line + "</span>";
}
else {
arr[index] = line;
}
arr[index] += "<br>";
}
@@ -80,7 +87,8 @@
return res.text();
})
.then((log) => {
log = log.replace(/</g, "&lt;").replace(/>/g, "&gt;");
log = log.replace(/</g, "&lt;");
log = log.replace(/>/g, "&gt;");
logArr = log.split("\n");
logArr.forEach(processLogLine);

View File

@@ -1,546 +0,0 @@
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Base>True</Base>
<AppType>Application</AppType>
<Config Condition="'$(Config)'==''">Debug</Config>
<FrameworkType>VCL</FrameworkType>
<MainSource>Gasmeter_Logdownloader.dpr</MainSource>
<Platform Condition="'$(Platform)'==''">Win32</Platform>
<ProjectGuid>{EF2C2455-2FD5-4992-8408-A473425308BD}</ProjectGuid>
<ProjectVersion>18.7</ProjectVersion>
<TargetedPlatforms>1</TargetedPlatforms>
</PropertyGroup>
<PropertyGroup Condition="'$(Config)'=='Base' or '$(Base)'!=''">
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Base)'=='true') or '$(Base_Win32)'!=''">
<Base_Win32>true</Base_Win32>
<CfgParent>Base</CfgParent>
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="'$(Config)'=='Debug' or '$(Cfg_1)'!=''">
<Cfg_1>true</Cfg_1>
<CfgParent>Base</CfgParent>
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Cfg_1)'=='true') or '$(Cfg_1_Win32)'!=''">
<Cfg_1_Win32>true</Cfg_1_Win32>
<CfgParent>Cfg_1</CfgParent>
<Cfg_1>true</Cfg_1>
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="'$(Config)'=='Release' or '$(Cfg_2)'!=''">
<Cfg_2>true</Cfg_2>
<CfgParent>Base</CfgParent>
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Cfg_2)'=='true') or '$(Cfg_2_Win32)'!=''">
<Cfg_2_Win32>true</Cfg_2_Win32>
<CfgParent>Cfg_2</CfgParent>
<Cfg_2>true</Cfg_2>
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="'$(Base)'!=''">
<SanitizedProjectName>Gasmeter_Logdownloader</SanitizedProjectName>
<DCC_DcuOutput>.\$(Platform)\$(Config)</DCC_DcuOutput>
<DCC_ExeOutput>.\$(Platform)\$(Config)</DCC_ExeOutput>
<DCC_Namespace>System;Xml;Data;Datasnap;Web;Soap;Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;$(DCC_Namespace)</DCC_Namespace>
<Icon_MainIcon>$(BDS)\bin\delphi_PROJECTICON.ico</Icon_MainIcon>
<UWP_DelphiLogo150>$(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_150.png</UWP_DelphiLogo150>
<UWP_DelphiLogo44>$(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_44.png</UWP_DelphiLogo44>
</PropertyGroup>
<PropertyGroup Condition="'$(Base_Win32)'!=''">
<BT_BuildType>Debug</BT_BuildType>
<DCC_Namespace>Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)</DCC_Namespace>
<DCC_UsePackage>DBXSqliteDriver;RESTComponents;WclBluetoothFrameworkR;DBXInterBaseDriver;vclactnband;vclFireDAC;dacfmx260;RSVML;tethering;svnui;FireDACADSDriver;vcltouch;vcldb;bindcompfmx;svn;IcsFmxD103Run;inetdb;IcsVclD103Run;FmxTeeUI;fmx;FireDACIBDriver;fmxdae;frxTee26;RSCommon;dacvcl260;fs26;IndyCore;dbexpress;vclx;frxIntIO26;dsnap;FireDACCommon;RSVclCommon;RESTBackendComponents;VCLRESTComponents;TMSVCLUIPackPkgWizDXE12;soapserver;fsTee26;TMSVCLUIPackPkgDXE12;vclie;bindengine;DBXMySQLDriver;CloudService;FireDACMySQLDriver;frx26;FireDACCommonODBC;FireDACCommonDriver;frxIntIOIndy26;inet;S0586_TRVclComponents;bindcompdbx;IndyIPCommon;vcl;IndyIPServer;frxDB26;IndySystem;fsADO26;frxDBX26;dsnapcon;sdac260;FireDACMSAccDriver;fsDB26;fmxFireDAC;vclimg;S0606_BMVclComponents;S0628_EWVclComponents;FireDAC;TeeDB;dOPCP;frxe26;FireDACSqliteDriver;FireDACPgDriver;tdstream260;sdacvcl260;crcontrols260;TMSVCLUIPackPkgXlsDXE12;FMXTee;soaprtl;DbxCommonDriver;Tee;xmlrtl;soapmidas;dac260;vclwinx;fmxobj;rtl;frxADO26;DbxClientDriver;CustomIPTransport;vcldsnap;SynEditDR;bindcomp;appanalytics;TMSVCLUIPackPkgExDXE12;RSFMXSVG;IndyIPClient;IcsCommonD103Run;sdacfmx260;bindcompvcl;TeeUI;dbxcds;VclSmp;adortl;sbridge260;dsnapxml;dbrtl;IndyProtocols;inetdbxpress;RSVclSVG;fmxase;$(DCC_UsePackage)</DCC_UsePackage>
<Manifest_File>$(BDS)\bin\default_app.manifest</Manifest_File>
<VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
<VerInfo_Keys>CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=</VerInfo_Keys>
<VerInfo_Locale>1033</VerInfo_Locale>
</PropertyGroup>
<PropertyGroup Condition="'$(Cfg_1)'!=''">
<DCC_DebugDCUs>true</DCC_DebugDCUs>
<DCC_DebugInfoInExe>true</DCC_DebugInfoInExe>
<DCC_Define>DEBUG;$(DCC_Define)</DCC_Define>
<DCC_GenerateStackFrames>true</DCC_GenerateStackFrames>
<DCC_Optimize>false</DCC_Optimize>
<DCC_RemoteDebug>true</DCC_RemoteDebug>
</PropertyGroup>
<PropertyGroup Condition="'$(Cfg_1_Win32)'!=''">
<AppDPIAwarenessMode>PerMonitorV2</AppDPIAwarenessMode>
<AppEnableRuntimeThemes>true</AppEnableRuntimeThemes>
<DCC_RemoteDebug>false</DCC_RemoteDebug>
</PropertyGroup>
<PropertyGroup Condition="'$(Cfg_2)'!=''">
<DCC_DebugInformation>0</DCC_DebugInformation>
<DCC_Define>RELEASE;$(DCC_Define)</DCC_Define>
<DCC_LocalDebugSymbols>false</DCC_LocalDebugSymbols>
<DCC_SymbolReferenceInfo>0</DCC_SymbolReferenceInfo>
</PropertyGroup>
<PropertyGroup Condition="'$(Cfg_2_Win32)'!=''">
<AppDPIAwarenessMode>PerMonitorV2</AppDPIAwarenessMode>
<AppEnableRuntimeThemes>true</AppEnableRuntimeThemes>
</PropertyGroup>
<ItemGroup>
<DelphiCompile Include="$(MainSource)">
<MainSource>MainSource</MainSource>
</DelphiCompile>
<DCCReference Include="uMain.pas">
<Form>Form1</Form>
<FormType>dfm</FormType>
</DCCReference>
<BuildConfiguration Include="Release">
<Key>Cfg_2</Key>
<CfgParent>Base</CfgParent>
</BuildConfiguration>
<BuildConfiguration Include="Base">
<Key>Base</Key>
</BuildConfiguration>
<BuildConfiguration Include="Debug">
<Key>Cfg_1</Key>
<CfgParent>Base</CfgParent>
</BuildConfiguration>
</ItemGroup>
<ProjectExtensions>
<Borland.Personality>Delphi.Personality.12</Borland.Personality>
<Borland.ProjectType>Application</Borland.ProjectType>
<BorlandProject>
<Delphi.Personality>
<Source>
<Source Name="MainSource">Gasmeter_Logdownloader.dpr</Source>
</Source>
</Delphi.Personality>
<Deployment Version="3">
<DeployFile LocalName="Win32\Debug\Gasmeter_Logdownloader.exe" Configuration="Debug" Class="ProjectOutput">
<Platform Name="Win32">
<RemoteName>Gasmeter_Logdownloader.exe</RemoteName>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployClass Name="AdditionalDebugSymbols">
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
<Platform Name="OSX32">
<RemoteDir>Contents\MacOS</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Win32">
<RemoteDir>Contents\MacOS</RemoteDir>
<Operation>0</Operation>
</Platform>
</DeployClass>
<DeployClass Name="AndroidClassesDexFile">
<Platform Name="Android">
<RemoteDir>classes</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="AndroidGDBServer">
<Platform Name="Android">
<RemoteDir>library\lib\armeabi-v7a</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="AndroidLibnativeArmeabiFile">
<Platform Name="Android">
<RemoteDir>library\lib\armeabi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="AndroidLibnativeMipsFile">
<Platform Name="Android">
<RemoteDir>library\lib\mips</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="AndroidServiceOutput">
<Platform Name="Android">
<RemoteDir>library\lib\armeabi-v7a</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="AndroidSplashImageDef">
<Platform Name="Android">
<RemoteDir>res\drawable</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="AndroidSplashStyles">
<Platform Name="Android">
<RemoteDir>res\values</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_DefaultAppIcon">
<Platform Name="Android">
<RemoteDir>res\drawable</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_LauncherIcon144">
<Platform Name="Android">
<RemoteDir>res\drawable-xxhdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_LauncherIcon36">
<Platform Name="Android">
<RemoteDir>res\drawable-ldpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_LauncherIcon48">
<Platform Name="Android">
<RemoteDir>res\drawable-mdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_LauncherIcon72">
<Platform Name="Android">
<RemoteDir>res\drawable-hdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_LauncherIcon96">
<Platform Name="Android">
<RemoteDir>res\drawable-xhdpi</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_SplashImage426">
<Platform Name="Android">
<RemoteDir>res\drawable-small</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_SplashImage470">
<Platform Name="Android">
<RemoteDir>res\drawable-normal</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_SplashImage640">
<Platform Name="Android">
<RemoteDir>res\drawable-large</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="Android_SplashImage960">
<Platform Name="Android">
<RemoteDir>res\drawable-xlarge</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="DebugSymbols">
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
<Platform Name="OSX32">
<RemoteDir>Contents\MacOS</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Win32">
<Operation>0</Operation>
</Platform>
</DeployClass>
<DeployClass Name="DependencyFramework">
<Platform Name="OSX32">
<RemoteDir>Contents\MacOS</RemoteDir>
<Operation>1</Operation>
<Extensions>.framework</Extensions>
</Platform>
<Platform Name="Win32">
<Operation>0</Operation>
</Platform>
</DeployClass>
<DeployClass Name="DependencyModule">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
<Platform Name="OSX32">
<RemoteDir>Contents\MacOS</RemoteDir>
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
<Platform Name="Win32">
<Operation>0</Operation>
<Extensions>.dll;.bpl</Extensions>
</Platform>
</DeployClass>
<DeployClass Required="true" Name="DependencyPackage">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
<Platform Name="OSX32">
<RemoteDir>Contents\MacOS</RemoteDir>
<Operation>1</Operation>
<Extensions>.dylib</Extensions>
</Platform>
<Platform Name="Win32">
<Operation>0</Operation>
<Extensions>.bpl</Extensions>
</Platform>
</DeployClass>
<DeployClass Name="File">
<Platform Name="Android">
<Operation>0</Operation>
</Platform>
<Platform Name="iOSDevice32">
<Operation>0</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>0</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>0</Operation>
</Platform>
<Platform Name="OSX32">
<RemoteDir>Contents\Resources\StartUp\</RemoteDir>
<Operation>0</Operation>
</Platform>
<Platform Name="Win32">
<Operation>0</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Launch1024">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Launch1536">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Launch2048">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPad_Launch768">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch320">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch640">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="iPhone_Launch640x1136">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectAndroidManifest">
<Platform Name="Android">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectiOSDeviceDebug">
<Platform Name="iOSDevice32">
<RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<RemoteDir>..\$(PROJECTNAME).app.dSYM\Contents\Resources\DWARF</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectiOSDeviceResourceRules">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectiOSEntitlements">
<Platform Name="iOSDevice32">
<RemoteDir>..\</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<RemoteDir>..\</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectiOSInfoPList">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectiOSResource">
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectOSXEntitlements">
<Platform Name="OSX32">
<RemoteDir>..\</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectOSXInfoPList">
<Platform Name="OSX32">
<RemoteDir>Contents</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectOSXResource">
<Platform Name="OSX32">
<RemoteDir>Contents\Resources</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Required="true" Name="ProjectOutput">
<Platform Name="Android">
<RemoteDir>library\lib\armeabi-v7a</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice32">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSDevice64">
<Operation>1</Operation>
</Platform>
<Platform Name="iOSSimulator">
<Operation>1</Operation>
</Platform>
<Platform Name="Linux64">
<Operation>1</Operation>
</Platform>
<Platform Name="OSX32">
<RemoteDir>Contents\MacOS</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Win32">
<Operation>0</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectUWPManifest">
<Platform Name="Win32">
<Operation>1</Operation>
</Platform>
<Platform Name="Win64">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="UWP_DelphiLogo150">
<Platform Name="Win32">
<RemoteDir>Assets</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Win64">
<RemoteDir>Assets</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="UWP_DelphiLogo44">
<Platform Name="Win32">
<RemoteDir>Assets</RemoteDir>
<Operation>1</Operation>
</Platform>
<Platform Name="Win64">
<RemoteDir>Assets</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<ProjectRoot Platform="iOSDevice64" Name="$(PROJECTNAME).app"/>
<ProjectRoot Platform="Win64" Name="$(PROJECTNAME)"/>
<ProjectRoot Platform="iOSDevice32" Name="$(PROJECTNAME).app"/>
<ProjectRoot Platform="Win32" Name="$(PROJECTNAME)"/>
<ProjectRoot Platform="Linux64" Name="$(PROJECTNAME)"/>
<ProjectRoot Platform="OSX32" Name="$(PROJECTNAME).app"/>
<ProjectRoot Platform="Android" Name="$(PROJECTNAME)"/>
<ProjectRoot Platform="iOSSimulator" Name="$(PROJECTNAME).app"/>
</Deployment>
<Platforms>
<Platform value="Win32">True</Platform>
<Platform value="Win64">False</Platform>
</Platforms>
</BorlandProject>
<ProjectFileVersion>12</ProjectFileVersion>
</ProjectExtensions>
<Import Project="$(BDS)\Bin\CodeGear.Delphi.Targets" Condition="Exists('$(BDS)\Bin\CodeGear.Delphi.Targets')"/>
<Import Project="$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj" Condition="Exists('$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj')"/>
<Import Project="$(MSBuildProjectName).deployproj" Condition="Exists('$(MSBuildProjectName).deployproj')"/>
</Project>

View File

@@ -1,4 +1,4 @@
program Gasmeter_Logdownloader;
program Gasmeter_Value_History;
uses
Vcl.Forms,

View File

@@ -0,0 +1,186 @@
<Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Base>True</Base>
<AppType>Application</AppType>
<Config Condition="'$(Config)'==''">Debug</Config>
<FrameworkType>VCL</FrameworkType>
<MainSource>Gasmeter_Value_History.dpr</MainSource>
<Platform Condition="'$(Platform)'==''">Win32</Platform>
<ProjectGuid>{EF2C2455-2FD5-4992-8408-A473425308BD}</ProjectGuid>
<ProjectVersion>18.7</ProjectVersion>
<TargetedPlatforms>1</TargetedPlatforms>
</PropertyGroup>
<PropertyGroup Condition="'$(Config)'=='Base' or '$(Base)'!=''">
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Base)'=='true') or '$(Base_Win32)'!=''">
<Base_Win32>true</Base_Win32>
<CfgParent>Base</CfgParent>
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="'$(Config)'=='Debug' or '$(Cfg_1)'!=''">
<Cfg_1>true</Cfg_1>
<CfgParent>Base</CfgParent>
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Cfg_1)'=='true') or '$(Cfg_1_Win32)'!=''">
<Cfg_1_Win32>true</Cfg_1_Win32>
<CfgParent>Cfg_1</CfgParent>
<Cfg_1>true</Cfg_1>
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="'$(Config)'=='Release' or '$(Cfg_2)'!=''">
<Cfg_2>true</Cfg_2>
<CfgParent>Base</CfgParent>
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="('$(Platform)'=='Win32' and '$(Cfg_2)'=='true') or '$(Cfg_2_Win32)'!=''">
<Cfg_2_Win32>true</Cfg_2_Win32>
<CfgParent>Cfg_2</CfgParent>
<Cfg_2>true</Cfg_2>
<Base>true</Base>
</PropertyGroup>
<PropertyGroup Condition="'$(Base)'!=''">
<SanitizedProjectName>Gasmeter_Value_History</SanitizedProjectName>
<DCC_DcuOutput>.\$(Platform)\$(Config)</DCC_DcuOutput>
<DCC_ExeOutput>.\$(Platform)\$(Config)</DCC_ExeOutput>
<DCC_Namespace>System;Xml;Data;Datasnap;Web;Soap;Vcl;Vcl.Imaging;Vcl.Touch;Vcl.Samples;Vcl.Shell;$(DCC_Namespace)</DCC_Namespace>
<Icon_MainIcon>$(BDS)\bin\delphi_PROJECTICON.ico</Icon_MainIcon>
<UWP_DelphiLogo150>$(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_150.png</UWP_DelphiLogo150>
<UWP_DelphiLogo44>$(BDS)\bin\Artwork\Windows\UWP\delphi_UwpDefault_44.png</UWP_DelphiLogo44>
</PropertyGroup>
<PropertyGroup Condition="'$(Base_Win32)'!=''">
<BT_BuildType>Debug</BT_BuildType>
<DCC_Namespace>Winapi;System.Win;Data.Win;Datasnap.Win;Web.Win;Soap.Win;Xml.Win;Bde;$(DCC_Namespace)</DCC_Namespace>
<DCC_UsePackage>DBXSqliteDriver;RESTComponents;WclBluetoothFrameworkR;DBXInterBaseDriver;vclactnband;vclFireDAC;dacfmx260;RSVML;tethering;svnui;FireDACADSDriver;vcltouch;vcldb;bindcompfmx;svn;IcsFmxD103Run;inetdb;IcsVclD103Run;FmxTeeUI;fmx;FireDACIBDriver;fmxdae;frxTee26;RSCommon;dacvcl260;fs26;IndyCore;dbexpress;vclx;frxIntIO26;dsnap;FireDACCommon;RSVclCommon;RESTBackendComponents;VCLRESTComponents;TMSVCLUIPackPkgWizDXE12;soapserver;fsTee26;TMSVCLUIPackPkgDXE12;vclie;bindengine;DBXMySQLDriver;CloudService;FireDACMySQLDriver;frx26;FireDACCommonODBC;FireDACCommonDriver;frxIntIOIndy26;inet;S0586_TRVclComponents;bindcompdbx;IndyIPCommon;vcl;IndyIPServer;frxDB26;IndySystem;fsADO26;frxDBX26;dsnapcon;sdac260;FireDACMSAccDriver;fsDB26;fmxFireDAC;vclimg;S0606_BMVclComponents;S0628_EWVclComponents;FireDAC;TeeDB;dOPCP;frxe26;FireDACSqliteDriver;FireDACPgDriver;tdstream260;sdacvcl260;crcontrols260;TMSVCLUIPackPkgXlsDXE12;FMXTee;soaprtl;DbxCommonDriver;Tee;xmlrtl;soapmidas;dac260;vclwinx;fmxobj;rtl;frxADO26;DbxClientDriver;CustomIPTransport;vcldsnap;SynEditDR;bindcomp;appanalytics;TMSVCLUIPackPkgExDXE12;RSFMXSVG;IndyIPClient;IcsCommonD103Run;sdacfmx260;bindcompvcl;TeeUI;dbxcds;VclSmp;adortl;sbridge260;dsnapxml;dbrtl;IndyProtocols;inetdbxpress;RSVclSVG;fmxase;$(DCC_UsePackage)</DCC_UsePackage>
<Manifest_File>$(BDS)\bin\default_app.manifest</Manifest_File>
<VerInfo_IncludeVerInfo>true</VerInfo_IncludeVerInfo>
<VerInfo_Keys>CompanyName=;FileDescription=$(MSBuildProjectName);FileVersion=1.0.0.0;InternalName=;LegalCopyright=;LegalTrademarks=;OriginalFilename=;ProgramID=com.embarcadero.$(MSBuildProjectName);ProductName=$(MSBuildProjectName);ProductVersion=1.0.0.0;Comments=</VerInfo_Keys>
<VerInfo_Locale>1033</VerInfo_Locale>
</PropertyGroup>
<PropertyGroup Condition="'$(Cfg_1)'!=''">
<DCC_DebugDCUs>true</DCC_DebugDCUs>
<DCC_DebugInfoInExe>true</DCC_DebugInfoInExe>
<DCC_Define>DEBUG;$(DCC_Define)</DCC_Define>
<DCC_GenerateStackFrames>true</DCC_GenerateStackFrames>
<DCC_Optimize>false</DCC_Optimize>
<DCC_RemoteDebug>true</DCC_RemoteDebug>
</PropertyGroup>
<PropertyGroup Condition="'$(Cfg_1_Win32)'!=''">
<AppDPIAwarenessMode>PerMonitorV2</AppDPIAwarenessMode>
<AppEnableRuntimeThemes>true</AppEnableRuntimeThemes>
<DCC_RemoteDebug>false</DCC_RemoteDebug>
</PropertyGroup>
<PropertyGroup Condition="'$(Cfg_2)'!=''">
<DCC_DebugInformation>0</DCC_DebugInformation>
<DCC_Define>RELEASE;$(DCC_Define)</DCC_Define>
<DCC_LocalDebugSymbols>false</DCC_LocalDebugSymbols>
<DCC_SymbolReferenceInfo>0</DCC_SymbolReferenceInfo>
</PropertyGroup>
<PropertyGroup Condition="'$(Cfg_2_Win32)'!=''">
<AppDPIAwarenessMode>PerMonitorV2</AppDPIAwarenessMode>
<AppEnableRuntimeThemes>true</AppEnableRuntimeThemes>
</PropertyGroup>
<ItemGroup>
<DelphiCompile Include="$(MainSource)">
<MainSource>MainSource</MainSource>
</DelphiCompile>
<DCCReference Include="uMain.pas">
<Form>Form1</Form>
<FormType>dfm</FormType>
</DCCReference>
<BuildConfiguration Include="Base">
<Key>Base</Key>
</BuildConfiguration>
<BuildConfiguration Include="Debug">
<Key>Cfg_1</Key>
<CfgParent>Base</CfgParent>
</BuildConfiguration>
<BuildConfiguration Include="Release">
<Key>Cfg_2</Key>
<CfgParent>Base</CfgParent>
</BuildConfiguration>
</ItemGroup>
<ProjectExtensions>
<Borland.Personality>Delphi.Personality.12</Borland.Personality>
<Borland.ProjectType>Application</Borland.ProjectType>
<BorlandProject>
<Delphi.Personality>
<Source>
<Source Name="MainSource">Gasmeter_Value_History.dpr</Source>
</Source>
</Delphi.Personality>
<Deployment Version="3">
<DeployFile LocalName="Win32\Debug\Gasmeter_Value_History.exe" Configuration="Debug" Class="ProjectOutput">
<Platform Name="Win32">
<RemoteName>Gasmeter_Value_History.exe</RemoteName>
<Overwrite>true</Overwrite>
</Platform>
</DeployFile>
<DeployClass Name="AdditionalDebugSymbols">
<Platform Name="Win32">
<Operation>0</Operation>
</Platform>
</DeployClass>
<DeployClass Name="DebugSymbols">
<Platform Name="Win32">
<Operation>0</Operation>
</Platform>
</DeployClass>
<DeployClass Name="DependencyFramework">
<Platform Name="Win32">
<Operation>0</Operation>
</Platform>
</DeployClass>
<DeployClass Name="DependencyModule">
<Platform Name="Win32">
<Operation>0</Operation>
<Extensions>.dll;.bpl</Extensions>
</Platform>
</DeployClass>
<DeployClass Required="true" Name="DependencyPackage">
<Platform Name="Win32">
<Operation>0</Operation>
<Extensions>.bpl</Extensions>
</Platform>
</DeployClass>
<DeployClass Name="File">
<Platform Name="Win32">
<Operation>0</Operation>
</Platform>
</DeployClass>
<DeployClass Required="true" Name="ProjectOutput">
<Platform Name="Win32">
<Operation>0</Operation>
</Platform>
</DeployClass>
<DeployClass Name="ProjectUWPManifest">
<Platform Name="Win32">
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="UWP_DelphiLogo150">
<Platform Name="Win32">
<RemoteDir>Assets</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<DeployClass Name="UWP_DelphiLogo44">
<Platform Name="Win32">
<RemoteDir>Assets</RemoteDir>
<Operation>1</Operation>
</Platform>
</DeployClass>
<ProjectRoot Platform="Win32" Name="$(PROJECTNAME)"/>
</Deployment>
<Platforms>
<Platform value="Win32">True</Platform>
<Platform value="Win64">False</Platform>
</Platforms>
</BorlandProject>
<ProjectFileVersion>12</ProjectFileVersion>
</ProjectExtensions>
<Import Project="$(BDS)\Bin\CodeGear.Delphi.Targets" Condition="Exists('$(BDS)\Bin\CodeGear.Delphi.Targets')"/>
<Import Project="$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj" Condition="Exists('$(APPDATA)\Embarcadero\$(BDSAPPDATABASEDIR)\$(PRODUCTVERSION)\UserTools.proj')"/>
<Import Project="$(MSBuildProjectName).deployproj" Condition="Exists('$(MSBuildProjectName).deployproj')"/>
</Project>

View File

@@ -1,5 +1,5 @@
[MAIN]
URL=http://192.168.178.62/fileserver/log/message/
CountLogfiles=3
Log=C:\Users\Muell\Downloads
CsvFile=C:\Users\Muell\Downloads\values.csv
URL=http://192.168.10.65/fileserver/log/
CountLogfiles=30
Log=D:\Daten\Dropbox\Eigene Dateien\Elektronik\Gasz<73>hler\Auswertung\Log-Downloads\
CsvFile=D:\Daten\Dropbox\Eigene Dateien\Elektronik\Gasz<73>hler\Auswertung\Tagesstand.csv

View File

@@ -1,14 +1,14 @@
<h2><strong>Gasmeter Log-Downloader</strong></h2>
<p>This small tool downloads the logfiles from your ESP32 and stores the last value of the day in an *.csv file.</p>
<p>To use this tool you need to <strong>activate the debug logfile</strong> in your configuration (Configuration / Debug / Logfile). I go with 30 days of retention in days.</p>
<p>It downloads only the past logfiles (yesterday and older).</p>
<p>You can define the max. number of Logfiles to download (beginning from newest [yesterday]).</p>
<h2><strong>Gasmeter Value History Downloader</strong></h2>
<p>This small tool downloads the datafiles (*.txt, before V13.0.1) or valuefiles (*.csv, since V13.0.1) from your ESP32 and stores the last value of the day in a *.csv file.</p>
<p>To use this tool you need to <strong>activate the DataLogging</strong> in your configuration (Configuration / Data Logging / DataLogActive). I go with 30 days of retention in days.</p>
<p>It downloads only the past datafiles (yesterday and older, not the actual day).</p>
<p>You can define the max. number of datafiles to download (beginning from newest [yesterday]).</p>
<p>I wrote this tool to get a chart of the daily gas consumption to optimize my gas powered heating.</p>
<p><strong>Variables to define by yourself:</strong></p>
<ul>
<li><strong>URL to Logfile-Path on Device:</strong> "http://ESP32-IP-Address/fileserver/log/message/"</li>
<li><strong>Download Logfiles to:</strong> enter a valid directory, e.g. "D:\Gaszaehler\Auswertung\Log-Downloads\"</li>
<li><strong>URL to Logfile-Path on Device:</strong> "http://ESP32-IP-Address/fileserver/log/"</li>
<li><strong>Download datafiles to:</strong> enter a valid directory, e.g. "D:\Gaszaehler\Auswertung\Log-Downloads\"</li>
<li><strong>Output CSV-File:</strong> enter a valid directory, e.g. "D:\Gaszaehler\Auswertung\DailyValues.csv"</li>
<li><strong>Download Logfiles from past # days:</strong> enter the max. number of logfiles you want to download (&lt;= your logfile retention value in your device configuration)</li>
<li><strong>Download past # days:</strong> enter the max. number of days you want to download (&lt;= your datafiles retention value in your device configuration)</li>
</ul>
<p>Feel free to optimize and modify it.</p>

View File

@@ -1,9 +1,9 @@
object Form1: TForm1
Left = 0
Top = 0
Caption = 'Gasmeter Log-Downloader'
ClientHeight = 521
ClientWidth = 513
Caption = 'Gasmeter Value-History'
ClientHeight = 523
ClientWidth = 453
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
Font.Color = clWindowText
@@ -16,7 +16,7 @@ object Form1: TForm1
PixelsPerInch = 96
TextHeight = 13
object lblImpressum: TLabel
Left = 376
Left = 316
Top = 468
Width = 68
Height = 13
@@ -31,25 +31,25 @@ object Form1: TForm1
EditLabel.Height = 13
EditLabel.Caption = 'URL to Logfile-Path on Device:'
TabOrder = 0
Text = 'http://192.168.10.65/fileserver/log/message/'
Text = 'http://192.168.10.65/fileserver/log/'
end
object btnDownloadLogfiles: TButton
Left = 28
Top = 174
Width = 273
Height = 25
Caption = 'Download Logfiles and generate CSV'
Caption = 'Download datafiles and generate CSV'
TabOrder = 1
OnClick = btnDownloadLogfilesClick
end
object lbledtMaxLogfilesOnServer: TLabeledEdit
Left = 323
Top = 36
Width = 121
Width = 114
Height = 21
EditLabel.Width = 173
EditLabel.Width = 112
EditLabel.Height = 13
EditLabel.Caption = 'Download logfiles from past # days:'
EditLabel.Caption = 'Download past # days:'
TabOrder = 2
Text = '30'
end
@@ -58,11 +58,11 @@ object Form1: TForm1
Top = 84
Width = 273
Height = 21
EditLabel.Width = 103
EditLabel.Width = 108
EditLabel.Height = 13
EditLabel.Caption = 'Download Logfiles to:'
EditLabel.Caption = 'Download datafiles to:'
TabOrder = 3
Text = 'C:\Temp\Gas\'
Text = 'C:\Temp\Gas\Log\'
end
object lbledtCsvFile: TLabeledEdit
Left = 28

View File

@@ -43,7 +43,8 @@ implementation
procedure TForm1.btnDownloadLogfilesClick(Sender: TObject);
var
lclDateString: string;
lclFilename: string;
lclFilenameCsv: string;
lclFilenameTxtOld: string;
i: Integer;
lclValue: Extended;
begin
@@ -51,13 +52,19 @@ begin
LoadCSV(lbledtCsvFile.Text);
for i := StrToInt(lbledtMaxLogfilesOnServer.Text) downto 1 do
begin
DateTimeToString(lclDateString, 'yyyy-mm-dd', incDay(Now, -i));
lclFilename := 'log_' + lclDateString + '.txt';
DateTimeToString(lclDateString, 'yyyy-mm-dd', incDay(Now, - i));
lclFilenameCsv := 'data_' + lclDateString + '.csv'; // http://192.168.10.65/fileserver/log/data/data_2022-11-28.csv
lclFilenameTxtOld := 'log_' + lclDateString + '.txt'; // http://192.168.10.65/fileserver/log/message/log_2022-11-10.txt
if (redtLog.FindText(lclDateString, 0, Length(redtLog.Lines.Text), [stWholeWord]) = -1) then
begin
if DownloadFile(lbledtURL.Text + lclFilename, lbledtTargetDirectory.Text + lclFilename) then
if DownloadFile(lbledtURL.Text + 'data/' + lclFilenameCsv, lbledtTargetDirectory.Text + lclFilenameCsv) then
begin
lclValue := LoadValue(lbledtTargetDirectory.Text + lclFilename);
lclValue := LoadValue(lbledtTargetDirectory.Text + lclFilenameCsv);
redtLog.Lines.Add(lclDateString + ';' + FloatToStrF(lclValue, ffFixed, 8, 2));
end
else if DownloadFile(lbledtURL.Text + 'message/' + lclFilenameTxtOld, lbledtTargetDirectory.Text + lclFilenameTxtOld) then
begin
lclValue := LoadValue(lbledtTargetDirectory.Text + lclFilenameTxtOld);
redtLog.Lines.Add(lclDateString + ';' + FloatToStrF(lclValue, ffFixed, 8, 2));
end;
end;
@@ -99,24 +106,45 @@ function TForm1.LoadValue(const pFileName: string): Extended;
var
Txt: TextFile;
s: string;
lclStringList: TStringList;
lclStartPos: Integer;
lclEndPos: Integer;
begin
Result := 0;
AssignFile(Txt, pFileName);
Reset(Txt);
while not Eof(Txt) do
begin
Readln(Txt, s);
if (AnsiPos('Value: ', s) <> 0) and (AnsiPos(' Error: no error', s) <> 0) then
lclStringList := TStringList.Create;
try
AssignFile(Txt, pFileName);
Reset(Txt);
while not Eof(Txt) do
begin
lclStartPos := AnsiPos('Value: ', s) + 7;
lclEndPos := AnsiPos(' Error: no error', s) - lclStartPos;
s := StringReplace(s, '.', ',', [rfReplaceAll, rfIgnoreCase]);
Result := StrToFloat(Copy(s, lclStartPos, lclEndPos));
Readln(Txt, s);
if ExtractFileExt(pFileName) = '.csv' then
begin
if (AnsiPos('no error', s) <> 0) then
begin
lclStringList.Clear;
lclStringList.Delimiter := ';';
s := StringReplace(s, ',', ';', [rfReplaceAll, rfIgnoreCase]);
s := StringReplace(s, '.', ',', [rfReplaceAll, rfIgnoreCase]);
lclStringList.DelimitedText := s;
Result := lclStringList[2].ToExtended;
end;
end
else
begin
if (AnsiPos('Value: ', s) <> 0) and (AnsiPos(' Error: no error', s) <> 0) then
begin
lclStartPos := AnsiPos('Value: ', s) + 7;
lclEndPos := AnsiPos(' Error: no error', s) - lclStartPos;
s := StringReplace(s, '.', ',', [rfReplaceAll, rfIgnoreCase]);
Result := StrToFloat(Copy(s, lclStartPos, lclEndPos));
end;
end;
end;
finally
CloseFile(Txt);
FreeAndNil(lclStringList);
end;
CloseFile(Txt);
end;
procedure TForm1.SaveCSV(const pFileName: string);