Compare commits

...

152 Commits

Author SHA1 Message Date
CaCO3
3dd2a80fd9 Merge branch 'mqtt-logfile' of https://github.com/jomjol/AI-on-the-edge-device into mqtt-logfile 2024-02-11 22:12:06 +01:00
CaCO3
0df0de3b16 Update interface_mqtt.cpp 2024-02-11 22:11:55 +01:00
CaCO3
ec08715919 Update interface_mqtt.cpp 2024-02-11 22:11:55 +01:00
CaCO3
9f6e711358 Update interface_mqtt.cpp 2024-02-11 22:11:55 +01:00
CaCO3
8f03ab04c4 Update interface_mqtt.cpp 2024-02-11 22:11:55 +01:00
CaCO3
9d8fade3d7 Update interface_mqtt.cpp 2024-02-11 22:11:55 +01:00
CaCO3
b6ab16ddd8 Update interface_mqtt.cpp 2024-02-11 22:11:55 +01:00
CaCO3
ba7d1ea320 Update interface_mqtt.cpp 2024-02-11 22:11:55 +01:00
CaCO3
c457e2fd20 Update interface_mqtt.cpp 2024-02-11 22:11:55 +01:00
CaCO3
dbd1f2a058 Update interface_mqtt.cpp 2024-02-11 22:11:55 +01:00
CaCO3
f2a1d97ba7 Update interface_mqtt.cpp 2024-02-11 22:11:55 +01:00
CaCO3
cd0268256f Update interface_mqtt.cpp 2024-02-11 22:11:55 +01:00
CaCO3
31385e16d1 Update interface_mqtt.cpp 2024-02-11 22:11:55 +01:00
CaCO3
beaaf3d6bb Update interface_mqtt.cpp 2024-02-11 22:11:55 +01:00
CaCO3
7b9b5c9066 Update interface_mqtt.cpp 2024-02-11 22:11:55 +01:00
CaCO3
a52c66054d Update interface_mqtt.cpp 2024-02-11 22:11:55 +01:00
CaCO3
8300e4473f Update interface_mqtt.cpp 2024-02-11 22:11:55 +01:00
CaCO3
b61f15b53a Update interface_mqtt.cpp 2024-02-11 22:11:55 +01:00
CaCO3
92485bcaba log MQTT messages to logfile instead just to UART 2024-02-11 22:11:55 +01:00
CaCO3
5053a31245 renaming 2024-02-11 22:10:41 +01:00
CaCO3
44cf8933d4 . 2024-02-11 22:10:41 +01:00
CaCO3
35de56be04 Add Firmware Version to MQTT 2024-02-11 22:10:41 +01:00
CaCO3
80a6fc1dc3 Update edit_config_param_template.html (#2881) 2024-02-09 23:02:10 +01:00
CaCO3
d2c47fcde2 Fix pipeline 2024-02-09 14:43:22 +01:00
CaCO3
7b3a493587 v15.6.0 (#2876) (#2877)
* Fix pipeline (#2860)

fix action

* ATA-Trim support (#2864)

Fix issues with the SD-Card initialization

* Update Changelog.md

---------

Co-authored-by: michael <Heinrich-Tuning@web.de>
2024-02-09 14:00:40 +01:00
CaCO3
217f543578 Update Changelog.md 2024-02-09 13:59:23 +01:00
michael
797fc5e764 ATA-Trim support (#2864)
Fix issues with the SD-Card initialization
2024-02-09 13:56:25 +01:00
CaCO3
3127990ccd Update interface_mqtt.cpp 2024-02-03 23:26:19 +01:00
CaCO3
7a4e82a44e Fix pipeline (#2860)
fix action
2024-02-03 23:16:15 +01:00
CaCO3
a82d9068c0 Update interface_mqtt.cpp 2024-02-03 00:38:43 +01:00
CaCO3
a014bdff39 Update interface_mqtt.cpp 2024-02-03 00:37:53 +01:00
CaCO3
238f452efb Update interface_mqtt.cpp 2024-02-03 00:36:38 +01:00
CaCO3
1aef8fa8a2 Update interface_mqtt.cpp 2024-02-03 00:35:25 +01:00
CaCO3
d31a318ab8 Update interface_mqtt.cpp 2024-02-03 00:33:18 +01:00
CaCO3
a21bd4c611 Update interface_mqtt.cpp 2024-02-03 00:32:40 +01:00
CaCO3
40ab0ee1ff Update interface_mqtt.cpp 2024-02-03 00:31:50 +01:00
CaCO3
13e7440e33 Update interface_mqtt.cpp 2024-02-03 00:30:34 +01:00
CaCO3
3696085ad6 Update interface_mqtt.cpp 2024-02-03 00:26:52 +01:00
CaCO3
68fbd7137b Update interface_mqtt.cpp 2024-02-03 00:25:13 +01:00
CaCO3
0b0381017a Update interface_mqtt.cpp 2024-02-03 00:22:45 +01:00
CaCO3
4c198e7eff Update interface_mqtt.cpp 2024-02-03 00:06:23 +01:00
CaCO3
fc7009bcc6 Update interface_mqtt.cpp 2024-02-03 00:04:15 +01:00
CaCO3
9084c35e92 Update interface_mqtt.cpp 2024-02-03 00:03:33 +01:00
CaCO3
4b3c0e0f4d Update interface_mqtt.cpp 2024-02-03 00:02:46 +01:00
CaCO3
d2ebca0902 Update interface_mqtt.cpp 2024-02-03 00:01:06 +01:00
CaCO3
d83e034b4f log MQTT messages to logfile instead just to UART 2024-02-02 23:57:04 +01:00
CaCO3
019069cd16 v15.5.0 (#2850) (#2851)
* update

* Revert "v15.4.0"

This reverts commit 74d4f20858.

* Revert "prepare v15.4.0 versuch 2"

This reverts commit e790a14caa.

* revert submnodules (#2768)



* Update submodules (#2769)

- Update `esp-nn` to v1.0.2
- Update `esp32-camera` to v2.0.6
- Updated `tflite-micro-esp-examples` (The repo got renamed to `esp-tflite-micro ` and the folder structure got cleaned up).

* fix(unity-test): Run unity tests in dedicated task
Avoid running out of heap

* Add delay

* Update

* Update

* Enhance busy notification (#2774)

* on marker updating, show message and retry until round got completed

* same for contrast enhancement

---------



* Fix negatives on extended resolution false #2744 (#2772)

* not extended resolution allows -1 on the lowest digit

* not extended resolution allows -1 on the lowest number

* negatives on last value digit with -1 will set to prevalue and is not an error  #2744

---------



* Implemented late analog / digital transition (#2778)

* Implemented late transition

Complete rewrite of analog / digital transition

Two tests is still failing, which need to be discussed.

* Allow wider range of transition values to support late transition

* Added documentation

* Fix testings (#2783)

* fix all tests and more description

* The decimal point offset. -3 corresponds to x.yyy

---------



* Bugfix InfluxDB shifting times (#2785)

* Modify time_sntp

* Update time_sntp.cpp

* Update time_sntp.cpp

* update

* Update interface_influxdb.cpp

* Update interface_influxdb.cpp

* Update time_sntp.cpp

* Upload

* Update interface_influxdb.cpp

* Update interface_influxdb.cpp

* Update interface_influxdb.cpp

* Remove Time Convert vom influx Interface

* Update platform-espressif32 to 6.5.0 (#2770)

* Update ESP IDF to 6.5.0

* Migration to new IDF

* Correct smtp vor v5.1

---------




* ATA-Trim support (#2781)

* Add files via upload

* Update main.cpp

* Update main.cpp

* Update main.cpp

* Update Helper.cpp

* Update Helper.h

* Update CMakeLists.txt

* Update CMakeLists.txt

* Update diskio_sdmmc_mh.c

* Update diskio_sdmmc_mh.h

* Update ff_mh.c

* Update vfs_fat_sdmmc_mh.c

* Update sdmmc_common_mh.h

* Update sdmmc_common_mh.c

* Update Helper.cpp

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Update ff_mh.c

---------



* Update Changelog.md

* Add device info info page (#2789)



* fix chip information REST API

* Update pipelines to fix warnings (#2841)

Update actions

* Move param doc (#2843)

moved param doc from docs repo to here

* fix(tflite): Fix memory leaks in tflite integration (#2842)

* Update Changelog.md (#2849)

---------

Signed-off-by: Florian Grabmeier <flo.grabmeier@gmail.com>
Co-authored-by: jomjol <30766535+jomjol@users.noreply.github.com>
Co-authored-by: CaCO3 <caco@ruinelli.ch>
Co-authored-by: Slider0007 <jobbelle@gmx.net>
Co-authored-by: Frank Haverland <fspapaping@googlemail.com>
Co-authored-by: Martin Siggel <martin.siggel@dlr.de>
Co-authored-by: michael <Heinrich-Tuning@web.de>
Co-authored-by: flox_x <93255373+flooxo@users.noreply.github.com>
Co-authored-by: Slider0007 <115730895+Slider0007@users.noreply.github.com>
2024-02-02 13:52:05 +01:00
CaCO3
4de1152cf3 Update Changelog.md (#2849) 2024-02-02 13:46:42 +01:00
Slider0007
0e0fb459dc fix(tflite): Fix memory leaks in tflite integration (#2842) 2024-02-02 13:23:51 +01:00
CaCO3
8410df6144 Move param doc (#2843)
moved param doc from docs repo to here
2024-01-31 21:53:56 +01:00
CaCO3
4990858101 Update pipelines to fix warnings (#2841)
Update actions
2024-01-31 20:53:41 +01:00
CaCO3
fc1f8ee242 fix chip information REST API 2024-01-08 23:41:48 +01:00
flox_x
252c399a76 Add device info info page (#2789)
Signed-off-by: Florian Grabmeier <flo.grabmeier@gmail.com>
2024-01-08 23:23:57 +01:00
jomjol
eb7f2b3705 Update Changelog.md 2024-01-02 09:04:15 +01:00
michael
2ed6fb0f0d ATA-Trim support (#2781)
* Add files via upload

* Update main.cpp

* Update main.cpp

* Update main.cpp

* Update Helper.cpp

* Update Helper.h

* Update CMakeLists.txt

* Update CMakeLists.txt

* Update diskio_sdmmc_mh.c

* Update diskio_sdmmc_mh.h

* Update ff_mh.c

* Update vfs_fat_sdmmc_mh.c

* Update sdmmc_common_mh.h

* Update sdmmc_common_mh.c

* Update Helper.cpp

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Update README.md

* Update ff_mh.c

---------

Co-authored-by: CaCO3 <caco3@ruinelli.ch>
2024-01-02 08:56:46 +01:00
CaCO3
b5213b01af Update platform-espressif32 to 6.5.0 (#2770)
* Update ESP IDF to 6.5.0

* Migration to new IDF

* Correct smtp vor v5.1

---------

Co-authored-by: CaCO3 <caco@ruinelli.ch>
Co-authored-by: jomjol <30766535+jomjol@users.noreply.github.com>
2024-01-01 22:00:23 +01:00
jomjol
473e458b85 Bugfix InfluxDB shifting times (#2785)
* Modify time_sntp

* Update time_sntp.cpp

* Update time_sntp.cpp

* update

* Update interface_influxdb.cpp

* Update interface_influxdb.cpp

* Update time_sntp.cpp

* Upload

* Update interface_influxdb.cpp

* Update interface_influxdb.cpp

* Update interface_influxdb.cpp

* Remove Time Convert vom influx Interface
2024-01-01 10:41:12 +01:00
Frank Haverland
4f3f3d9af2 Fix testings (#2783)
* fix all tests and more description

* The decimal point offset. -3 corresponds to x.yyy

---------

Co-authored-by: jomjol <30766535+jomjol@users.noreply.github.com>
2023-12-31 14:43:08 +01:00
Martin Siggel
b5a4cfed96 Implemented late analog / digital transition (#2778)
* Implemented late transition

Complete rewrite of analog / digital transition

Two tests is still failing, which need to be discussed.

* Allow wider range of transition values to support late transition

* Added documentation
2023-12-31 12:04:09 +01:00
Frank Haverland
6fca4d8d95 Fix negatives on extended resolution false #2744 (#2772)
* not extended resolution allows -1 on the lowest digit

* not extended resolution allows -1 on the lowest number

* negatives on last value digit with -1 will set to prevalue and is not an error  #2744

---------

Co-authored-by: jomjol <30766535+jomjol@users.noreply.github.com>
2023-12-31 12:03:52 +01:00
CaCO3
a11e19fb0c Enhance busy notification (#2774)
* on marker updating, show message and retry until round got completed

* same for contrast enhancement

---------

Co-authored-by: CaCO3 <caco@ruinelli.ch>
2023-12-31 11:47:28 +01:00
Frank Haverland
09fa94c95f Merge pull request #2777 from Slider0007/unity-test-rolling
chore(unity-test): Run unity tests in dedicated task
2023-12-30 11:55:22 +01:00
Slider0007
f01b4dbd13 Update 2023-12-29 09:57:59 +01:00
Slider0007
dbf1770016 Update 2023-12-29 09:56:47 +01:00
Slider0007
006f3aa063 Add delay 2023-12-29 09:47:37 +01:00
Slider0007
24c46c38b4 fix(unity-test): Run unity tests in dedicated task
Avoid running out of heap
2023-12-28 21:32:43 +01:00
CaCO3
9ced147d9c Update submodules (#2769)
- Update `esp-nn` to v1.0.2
- Update `esp32-camera` to v2.0.6
- Updated `tflite-micro-esp-examples` (The repo got renamed to `esp-tflite-micro ` and the folder structure got cleaned up).
2023-12-28 12:13:57 +01:00
CaCO3
0808895bd6 revert submnodules (#2768)
Co-authored-by: CaCO3 <caco@ruinelli.ch>
2023-12-28 09:27:42 +01:00
jomjol
d2dec9fa59 Revert "prepare v15.4.0 versuch 2"
This reverts commit e790a14caa.
2023-12-22 23:50:56 +01:00
jomjol
7e7bc3dd68 Revert "v15.4.0"
This reverts commit 74d4f20858.
2023-12-22 23:48:43 +01:00
jomjol
5b09cd0d59 update 2023-12-22 23:47:17 +01:00
jomjol
74d4f20858 v15.4.0 2023-12-22 23:38:31 +01:00
jomjol
e790a14caa prepare v15.4.0 versuch 2 2023-12-22 23:31:13 +01:00
jomjol
f023a6b739 Revert "v15.4.0"
This reverts commit 374462a7d8.
2023-12-22 23:22:57 +01:00
jomjol
1e463188ea Revert "Update Changelog.md"
This reverts commit 9991196961.
2023-12-22 23:22:08 +01:00
jomjol
9991196961 Update Changelog.md 2023-12-22 23:04:52 +01:00
jomjol
ecece0f7fc Update dependencies.lock 2023-12-22 22:55:54 +01:00
jomjol
1b3b7595c1 Merge branch 'rolling' 2023-12-22 22:46:36 +01:00
jomjol
6d10f712d1 Update Changelog.md 2023-12-22 22:46:16 +01:00
jomjol
b84a2db050 Update config.ini 2023-12-22 22:45:32 +01:00
jomjol
374462a7d8 v15.4.0 2023-12-22 22:43:08 +01:00
Frank Haverland
4facd7be05 new images on analog and digits (#2756)
* new images on dig-class100, older ana-class100 removed

* new images on analog and digits
2023-12-22 22:42:33 +01:00
jomjol
3baf5865ad Prepare 15.4.0 2023-12-21 19:21:22 +01:00
CaCO3
02138c44ac rename InfluxDBv2 parameter Database to Bucket (#2704)
* rename InfluxDBv2 parameter Database to Basket

* only enable the field if it is a boolean

* corrected "Basket" to "Bucket"

---------

Co-authored-by: CaCO3 <caco@ruinelli.ch>
2023-11-22 23:43:23 +01:00
Slider0007
1094c8a0a8 fix(influxdb): Consider DST setting for UTC time conversion (#2679)
* fix(influxdb): Consider DST setting for UTC time conversion

* Update
2023-11-12 12:04:18 +01:00
LordGuilly
75b15b8e9d added config entries for MQTT TLS (#2651)
3 new entries in the config section, for setting file paths for
        - Root CA
        - Client Certificate
        - Client Private Key
 (all set as expert parameters)

- logging cert filenames

added config entries for MQTT TLS

 3 new entries in the config section, for setting file paths for
        - Root CA
        - Client Certificate
        - Client Private Key

- logging cert filenames

MQTT-TLS: Updates for the PR comments

- config.ini now has default values closer to "real" life filenames
- MQTT cert entries are hidden as Expert parameters
- Fixed debug logging at MQTT interface for unhandled messages
2023-11-07 22:58:16 +01:00
CaCO3
36c12b400b rework test-domain check 2023-11-07 22:42:15 +01:00
CaCO3
35d90cd0ee update readme 2023-10-21 22:39:21 +02:00
CaCO3
999a8d9374 updated readme 2023-10-21 22:35:13 +02:00
CaCO3
8a4269c6a0 Add files via upload 2023-10-21 22:32:25 +02:00
CaCO3
8f5579cca5 updated readme 2023-10-21 22:30:29 +02:00
CaCO3
e58b3a2cf8 update webinstaller 2023-10-21 22:23:08 +02:00
CaCO3
222ee0921c udpate webinstaller 2023-10-21 22:19:07 +02:00
CaCO3
e2bfcd26c9 update web installer 2023-10-21 22:15:47 +02:00
CaCO3
18917b2d82 Delete docs/manifest_template.json 2023-10-21 01:06:52 +02:00
CaCO3
f0dea3abcb Delete docs/binary/firmware.bin 2023-10-21 01:06:42 +02:00
CaCO3
bd2d8b4a15 Update manual-update-webinstaller.yml 2023-10-21 01:06:15 +02:00
CaCO3
80e3f50a5b Update manifest.json 2023-10-21 01:05:19 +02:00
CaCO3
f6ca32d69f Update manual-update-webinstaller.yml 2023-10-21 01:03:00 +02:00
CaCO3
49e919c481 Update manual-update-webinstaller.yml 2023-10-21 01:00:21 +02:00
CaCO3
de768c4f44 Delete releases/download directory 2023-10-21 00:49:24 +02:00
CaCO3
002fc033aa Delete firmware directory 2023-10-21 00:47:05 +02:00
CaCO3
f4af8de699 fix paypal button (#2666)
* Add files via upload

* Update README.md

* Update README.md

* Update README.md

* Update README.md
2023-10-21 00:43:36 +02:00
CaCO3
e4d6707a0b Update README.md 2023-10-21 00:27:52 +02:00
CaCO3
9f03e68690 Update README.md 2023-10-21 00:27:32 +02:00
CaCO3
b1df7df580 added label action 2023-10-20 23:35:07 +02:00
CaCO3
ebc9be4a28 added label action 2023-10-20 23:27:10 +02:00
jomjol
5d0fc73c13 Updated feature request 2023-09-03 15:48:00 +02:00
jomjol
40a1aa0430 Update submodules, include only needed layers of tflite (#2586)
* Initial version

* Working Version

* Update

* Update main.cpp

* Updated Docu
2023-08-20 21:49:28 +02:00
TheDubliner
d7a733512f 📚 Fix minor typos, grammar and formatting issues. (#2575) 2023-08-15 21:37:22 +02:00
Frank Haverland
dc9f1aad27 new images on dig-class100, older ana-class100 removed (#2545) 2023-08-02 21:46:00 +02:00
Frank Haverland
cd3e641bcc #2540 fix trunc of first with imprecise precision (#2543)
* added more debug for #2447

* new model on new images dig-class100-0165_s2

* #2465 fix first digit with extended_Resolution=false

* fix #2491

* #2540 fix trunc of first with imprecise precision
2023-07-30 18:25:56 +02:00
Slider0007
ad72ffa37c mqtt_handler_set_prevalue: fix memory leak (#2544) 2023-07-30 18:25:35 +02:00
Giel van Schijndel
2d45a0ed26 fix: provide proper error messages for invalid /info?type= query parameter (#2533) 2023-07-24 21:44:06 +02:00
Giel van Schijndel
e8065ef414 fix(fileserver): avoid sending *two* "last-chunk" sequences (#2532)
Because a zero-sized chunk indicates the end of a HTTP response sending
another such zero-sized chunk is not interpretable by the HTTP client.

See [RFC2616 3.6.1] "Chunked Transfer Encoding" for details.

[RFC2616 3.6.1]: https://datatracker.ietf.org/doc/html/rfc2616#section-3.6.1
2023-07-24 21:43:56 +02:00
pfeifferch
33893eb566 Shortcut Icon hinzugefügt (#2530)
* Add files via upload

Shortcut icon

* Update index.html

Shortcut icon
2023-07-23 20:33:04 +02:00
jomjol
3fbff0ad33 Merge branch 'rolling' 2023-07-22 11:41:24 +02:00
jomjol
28cabea7f2 Prepare v15.3.0 2023-07-22 09:53:24 +02:00
CaCO3
5d06130a88 enable RSSI roaming by default and set it to -75 dBm (#2504) 2023-07-10 19:50:28 +02:00
LordGuilly
3497a86084 fixed build issues when enabling DEBUG_DETAIL_ON (#2509)
fixed build issues when enabling DEBUG_DETAIL_ON

added missing header when DEBUG_DETAIL_ON is enabled
2023-07-09 22:59:34 +02:00
Frank Haverland
84707fb27a fix #2491 - missing </li> (#2495)
* added more debug for #2447

* new model on new images dig-class100-0165_s2

* #2465 fix first digit with extended_Resolution=false

* fix #2491
2023-07-01 21:16:00 +02:00
CaCO3
0b81af7cb8 Update PlatformIO to 6.3.2 (#2499) 2023-06-30 00:11:56 +02:00
Frank Haverland
61efe1a6ef #2465 Fix first digit on extended_Resolution=false (#2466)
* added more debug for #2447

* new model on new images dig-class100-0165_s2

* #2465 fix first digit with extended_Resolution=false
2023-06-12 20:14:30 +02:00
Frank Haverland
09ecd722cc new model dig-class_0165_s2 on new images (#2455)
* added more debug for #2447

* new model on new images dig-class100-0165_s2
2023-06-06 20:17:27 +02:00
Frank Haverland
5615fd8137 added more debug for #2447 (#2450) 2023-06-03 07:24:14 +02:00
Slider0007
7ebf68411f Analog ROI: Fix wrong multiplier view - only analog ROI, no digit ROI (#2440)
* Fix multiplier view with only analog ROIs

* Refactor multiplier view for digit ROI
2023-06-01 20:46:34 +02:00
Frank Haverland
34835dca84 new version of dig-class100 (#2437) 2023-06-01 20:45:56 +02:00
CaCO3
697ff4c4b6 Update platformio to 6.3.1 2023-05-26 13:31:11 +02:00
CaCO3
0f7c685933 Update PlatformIO to 6.3.0 (#2420)
* Update WebUI

* Initial rotate default to 0.0

* Process related file update: no folder content redirect

* Try to clear cache after intial setup

* Update

* Reference image: remove updatepage

* Update

* Hide "manual flow start"

* Update

* Update

* Update text

* BugFix Make Reference

* Update MainFlowControl.cpp

* Update platformio.ini

* Fix #2393

* Update platformio.ini

---------

Co-authored-by: Slider0007 <jobbelle@gmx.net>
Co-authored-by: jomjol <30766535+jomjol@users.noreply.github.com>
Co-authored-by: CaCO3 <caco@ruinelli.ch>
2023-05-23 21:29:19 +02:00
CaCO3
3ace5aeff1 . 2023-05-23 00:02:18 +02:00
CaCO3
d47ed060b0 Enhance web UI 2023-05-22 23:43:33 +02:00
jomjol
e7dbebffa1 Fix #2393 2023-05-21 13:26:48 +02:00
jomjol
def13d46af Update MainFlowControl.cpp 2023-05-19 22:23:05 +02:00
jomjol
f82a6bf513 Merge branch 'rolling' into update-webui 2023-05-19 22:08:05 +02:00
jomjol
05deecee00 BugFix Make Reference 2023-05-19 21:53:56 +02:00
jomjol
8339b6788f Bug Fix #2403 2023-05-19 21:14:51 +02:00
CaCO3
4e5b084932 SHow correct message in log. Fixes https://github.com/jomjol/AI-on-the-edge-device/issues/2411 2023-05-17 22:16:12 +02:00
jomjol
62fcefee78 Update config.ini 2023-05-09 22:11:07 +02:00
Frank Haverland
14128ca3a7 new models ana-cont, ana-class100, dig-class100 2023-05-09 20:29:33 +02:00
CaCO3
431551fb45 speed up deletion of files (#2389)
* speed up deletion of files

* .

* .

* .

* .

* .

---------

Co-authored-by: CaCO3 <caco@ruinelli.ch>
2023-05-05 18:43:46 +02:00
Slider0007
ff52d785cd Update text 2023-05-03 08:50:19 +02:00
Slider0007
f5a7c082d6 Update 2023-05-03 08:46:33 +02:00
Slider0007
f3e90c6293 Update 2023-05-02 23:29:38 +02:00
CaCO3
cbd14a267f v15.2.4 (#2385)
* Testcase for #2145 and debug-log (#2151)

* new models ana-cont-11.0.5, ana-class100-1.5.7, dig-class100-1.6.0

* Testcase for #2145
Added debug log, if allowNegativeRates is handeled

* Fix timezone config parser (#2169)

* make sure to parse the whole config line

* fix crash on empty timezone parameter

---------

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

* Enhance ROI pages (#2161)

* Check if the ROIs are equidistant. Only if not, untick the checkbox

* renaming

* Check if the ROIs have same y, dy and dx. If so, tick the sync checkbox

* only allow editing space when box is checked

* fix sync check

* show inner frame on all ROIs

* cleanup

* Check if the ROIs have same dy and dx. If so, tick the sync checkbox

* checkbox position

* renaming

* renaming

* show inner frame and cross hairs on all ROIs

* update ROIs on ticking checkboxes

* show timezone hint

* fix deleting last ROI

* cleanup

---------

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

* restart timeout on progress, catch error (#2170)

* restart timeout on progress, catch error

* .

---------

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

* BugFix #2167

* Release 15.1 preparations (#2171)

* Update Changelog.md

* Update Changelog.md

* Update Changelog.md

* Update changelog

* Fix links to PR

* Formating

* Update Changelog.md

* Update Changelog.md

* Update Changelog.md

* Update Changelog.md

* Update Changelog.md

* Update Changelog.md

* Update Changelog.md

* Update Changelog.md

* Update Changelog.md

* Update Changelog.md

* Update Changelog.md

* Update Changelog.md

---------

Co-authored-by: Slider0007 <jobbelle@gmx.net>
Co-authored-by: Slider0007 <115730895+Slider0007@users.noreply.github.com>

* fix typo

* Replace relative documentation links with absolute ones pointing to the external documentation (#2180)

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

* Sort model files in configuration combobox (#2189)

* new models ana-cont-11.0.5, ana-class100-1.5.7, dig-class100-1.6.0

* Testcase for #2145
Added debug log, if allowNegativeRates is handeled

* Sort model files in combobox

* reboot task - increase stack size (#2201)

Avoid stack overflow

* Update interface_influxdb.cpp

* Update Changelog.md

* Show PSRAM usage (#2206)

* centralize PSRAM usage (application code only)

* update logging

* update logging

* fix use after free

* initialize buffer

* free rgb_image before ussing it for new allocation

* use wrapper function

* switch log level to debug

* .

* undo adding free() calls

* .

* add names to all CImage instances

* .

* .

* .

* revert changes of stbi_image_free() with free_psram_heap() on the places where is is not in PSRAM

* .

* typos

* typo

* Added MQTT Outbox explanation/warning

* added CONFIG_SPIRAM_USE_MEMMAP explanation

---------

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

* Disable custom MQTT Outbox. This also moves the MQTT Publishing memory usage back to the internal RAM!

* log MQTT connection refused reasons (#2216)

* Revert PSRAM usage as it lead to memory fragmentation.
See https://github.com/jomjol/AI-on-the-edge-device/issues/2200 for details

* fix missing value data

* Revert PSRAM usage as it lead to memory fragmentation. (#2224)

See https://github.com/jomjol/AI-on-the-edge-device/issues/2200 for details

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

* Fix missing value data in graph (#2230)

* fix missing value data

---------

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

* Update Changelog.md (#2231)

* Update interface_influxdb.cpp (#2233)

* update copyright year

* Cleanup

* Set prevalue using MQTT + set prevalue to RAW value (REST+MQTT) (#2252)

* Use double instead of float

* Error handling + set to RAW if newvalue < 0

* REST SetPrevalue: Set to RAW if newvalue < 0

* set prevalue with MQTT

* removed the stb_image files and re-add them as a submodule. (#2223)

- stb_image.h: Version update 2.25 -> 2.28
- stb_resize.h: Version update 0.96 -> 0.97
- stb_write.h: Version update 1.14 -> 1.16

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

* Remove obsolete ClassFlowWriteList (#2264)

* Renaming & cleanup of some modules / functions in source code (#2265)

* Rename module tag name

* Rename server_tflite.cpp -> MainFlowControl.cpp

* Remove redundandant MQTTMainTopic function

* Update

* Remove obsolete GetMQTTMainTopic

* Fix last element missing in digit model drop down (#2282)

* Debug influxdb (#2283)

* Fix time offset issues in InfluxDB component. (#2278)

Closes #2273
Closes #2150

* Update interface_influxdb.cpp

* Update interface_influxdb.cpp

* Improve Logging

* Implement TimeSync at beginning

* Update time_sntp.cpp

* Update time_sntp.cpp

* Set Time After WLAN Init

---------

Co-authored-by: Antonin Delpeuch <antonin@delpeuch.eu>

* Implement a camera livestream handler (#2286)

* fix leading NaN (#2310)

* analogROI: Activate save button after ROI creation (#2326)

* Migration of PlatformIO 5.2.0 to 6.1.0 (resp. ESP IDF from 4.4.2 to 5.0.1) (#2305)

* Migration to PlatformIO 6.1.0

* Disable RMTMEM usage as it is no longer allowed -> Smart LEDs not functional!

* moved miniz into subfolder of jomjol_fileserver_ota, else it does not build anymore.

* cleanup

* fix leading NaN (#2310)

* Migration to PlatformIO 6.1.0

* Disable RMTMEM usage as it is no longer allowed -> Smart LEDs not functional!

* moved miniz into subfolder of jomjol_fileserver_ota, else it does not build anymore.

* cleanup

* Task watchdog has new config name

* Fix return value check. It must be something else than ESP_FAIL, but it does not need to be ESP_OK!

* add missing strucures to work around new RMTMEM restriction (untested)

---------

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

* Keep MainFlowTask alive to handle reboot (#2325)

* Shared PSRAM memory (#2285)

* enable PSRAM logging

* add extra functions for psram shared memroy handling

* CImageBasis objects still should used dynamic memory (eg. rawImage), haw ever tmpImage must be placed inside the shared memory

* Place all STBI allocs inside the shared memory

* The models are placed in the shared PSRAM reagion and must be allocated through the dedicated functions

* .

* renaming

* fix cast warning

* add flag to switch STBI PSRAM usage

* improve PSRAM shared handling

* reserve shared PSRAM as early as possible

* init logging eralier so we can use it in PSRAM shared alloc

* move Wifi_LWIP, BSS_SEG and MQTT Outbox into PSRAM to ffree internal memory

* Check if model fits into reserved shared memory

* Update code/components/jomjol_tfliteclass/CTfLiteClass.cpp

* Update code/components/jomjol_helper/psram.cpp

* Update code/components/jomjol_helper/psram.cpp

* Update code/components/jomjol_flowcontroll/ClassFlowControll.cpp

* Update code/components/jomjol_helper/psram.cpp

* Update code/components/jomjol_helper/psram.cpp

* Update code/components/jomjol_helper/psram.cpp

* Update code/components/jomjol_image_proc/CImageBasis.cpp

* Update code/components/jomjol_helper/psram.cpp

* Update code/components/jomjol_helper/psram.cpp

* Update code/components/jomjol_helper/psram.cpp

* Update code/components/jomjol_helper/psram.cpp

* Update code/components/jomjol_helper/psram.cpp

* Update code/components/jomjol_helper/psram.cpp

* Update code/components/jomjol_helper/psram.cpp

* .

* .

* .

* .

* Korrektur Merge Conflict in main.cpp

---------

Co-authored-by: CaCO3 <caco@ruinelli.ch>
Co-authored-by: jomjol <30766535+jomjol@users.noreply.github.com>

* fix PSRAM init return value check

* Extend InfluxDBv1 with individual topic names (#2319)

* Implement individual influx topic

* Update interface_influxdb.cpp

* Update interface_influxdb.cpp

* Update FieldName

* analogROI: Activate save button after ROI creation (#2326)

* Migration of PlatformIO 5.2.0 to 6.1.0 (resp. ESP IDF from 4.4.2 to 5.0.1) (#2305)

* Migration to PlatformIO 6.1.0

* Disable RMTMEM usage as it is no longer allowed -> Smart LEDs not functional!

* moved miniz into subfolder of jomjol_fileserver_ota, else it does not build anymore.

* cleanup

* fix leading NaN (#2310)

* Migration to PlatformIO 6.1.0

* Disable RMTMEM usage as it is no longer allowed -> Smart LEDs not functional!

* moved miniz into subfolder of jomjol_fileserver_ota, else it does not build anymore.

* cleanup

* Task watchdog has new config name

* Fix return value check. It must be something else than ESP_FAIL, but it does not need to be ESP_OK!

* add missing strucures to work around new RMTMEM restriction (untested)

---------

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

* Keep MainFlowTask alive to handle reboot (#2325)

* Shared PSRAM memory (#2285)

* enable PSRAM logging

* add extra functions for psram shared memroy handling

* CImageBasis objects still should used dynamic memory (eg. rawImage), haw ever tmpImage must be placed inside the shared memory

* Place all STBI allocs inside the shared memory

* The models are placed in the shared PSRAM reagion and must be allocated through the dedicated functions

* .

* renaming

* fix cast warning

* add flag to switch STBI PSRAM usage

* improve PSRAM shared handling

* reserve shared PSRAM as early as possible

* init logging eralier so we can use it in PSRAM shared alloc

* move Wifi_LWIP, BSS_SEG and MQTT Outbox into PSRAM to ffree internal memory

* Check if model fits into reserved shared memory

* Update code/components/jomjol_tfliteclass/CTfLiteClass.cpp

* Update code/components/jomjol_helper/psram.cpp

* Update code/components/jomjol_helper/psram.cpp

* Update code/components/jomjol_flowcontroll/ClassFlowControll.cpp

* Update code/components/jomjol_helper/psram.cpp

* Update code/components/jomjol_helper/psram.cpp

* Update code/components/jomjol_helper/psram.cpp

* Update code/components/jomjol_image_proc/CImageBasis.cpp

* Update code/components/jomjol_helper/psram.cpp

* Update code/components/jomjol_helper/psram.cpp

* Update code/components/jomjol_helper/psram.cpp

* Update code/components/jomjol_helper/psram.cpp

* Update code/components/jomjol_helper/psram.cpp

* Update code/components/jomjol_helper/psram.cpp

* Update code/components/jomjol_helper/psram.cpp

* .

* .

* .

* .

* Korrektur Merge Conflict in main.cpp

---------

Co-authored-by: CaCO3 <caco@ruinelli.ch>
Co-authored-by: jomjol <30766535+jomjol@users.noreply.github.com>

* fix PSRAM init return value check

* Extend incl. indiv. Measurement

* Implement UX

* Update ClassFlowInfluxDBv2.cpp

* Implement individual influx topic

* Update interface_influxdb.cpp

* Update interface_influxdb.cpp

* Update FieldName

* Extend incl. indiv. Measurement

* Implement UX

* Update ClassFlowInfluxDBv2.cpp

* Update main.cpp

---------

Co-authored-by: Slider0007 <115730895+Slider0007@users.noreply.github.com>
Co-authored-by: CaCO3 <caco3@ruinelli.ch>
Co-authored-by: CaCO3 <caco@ruinelli.ch>

* Update Changelog.md (#2344)

* Update Changelog.md

* Update Changelog.md

* merge conflicts

* merge conflicts

* update changelog

* Update Changelog.md

* Fix alignment mark PSRAM issue (#2357)

* Add lock for shared PSRAM memory, use it for the relevant round steps and the Alignment Mark Task

* only allow taking a new image for the Alignment Mark while round got completed

* show success/denial of Alignment Mark Update Request

* .

---------

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

* Update Changelog.md (#2360)

* Update platformio.ini (#2368)

* Allow the Alignment Mark step while status is "Initializing" or "Initialization (delayed)" or while in setup mode (#2373)

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

* Improve logging if Autostart is not enabled. Renamed/splitted functions (#2376)

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

* Cleanup web UI (#2378)

* fix wrong index on backup log

* remove no longer used files/functions

* improve logging on Alignment Mark Update

---------

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

* Update Changelog.md

* fix broken sysinfo (#2381)

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

* Update Changelog.md

* Update Changelog.md

* Update sdcard_check.cpp (#2384)

* Update Changelog.md

---------

Co-authored-by: Frank Haverland <fspapaping@googlemail.com>
Co-authored-by: CaCO3 <caco@ruinelli.ch>
Co-authored-by: jomjol <30766535+jomjol@users.noreply.github.com>
Co-authored-by: Slider0007 <jobbelle@gmx.net>
Co-authored-by: Slider0007 <115730895+Slider0007@users.noreply.github.com>
Co-authored-by: Antonin Delpeuch <antonin@delpeuch.eu>
2023-05-02 07:54:28 +02:00
Slider0007
c30881f73c Hide "manual flow start" 2023-05-01 20:00:41 +02:00
Slider0007
e75e720869 Update 2023-05-01 19:23:01 +02:00
Slider0007
54cd7e511a Reference image: remove updatepage 2023-05-01 14:45:47 +02:00
Slider0007
c5a82e839f Update 2023-05-01 14:44:56 +02:00
Slider0007
9f97a2b223 Try to clear cache after intial setup 2023-05-01 14:23:14 +02:00
Slider0007
8d06de5792 Process related file update: no folder content redirect 2023-05-01 14:22:15 +02:00
Slider0007
1326585a33 Initial rotate default to 0.0 2023-05-01 14:20:05 +02:00
Slider0007
d7a507ca05 Update WebUI 2023-05-01 14:19:31 +02:00
229 changed files with 9111 additions and 4356 deletions

View File

@@ -3,7 +3,32 @@
# Make sure to also add the response to .github/workflows/reply-bot.yml!
# Due to the way it works, you have to add each response twice, once for the issue, once for the discussions!
labels:
labels:
#######################################################################
# Bot Response: Documentation
#######################################################################
- name: bot-reply Documentation
labeled:
issue:
body: |
Please have a look on our documentation: https://jomjol.github.io/AI-on-the-edge-device-docs
discussion:
body: |
Please have a look on our documentation: https://jomjol.github.io/AI-on-the-edge-device-docs
#######################################################################
# Bot Response: ROI setup
#######################################################################
- name: bot-reply ROI Setup
labeled:
issue:
body: |
Make sure to setup your ROIs properly. Have a look on our documentation: https://jomjol.github.io/AI-on-the-edge-device-docs/ROI-Configuration/#how-to-setup-the-digit-rois-perfectly
discussion:
body: |
Make sure to setup your ROIs properly. Have a look on our documentation: https://jomjol.github.io/AI-on-the-edge-device-docs/ROI-Configuration/#how-to-setup-the-digit-rois-perfectly
#######################################################################
# Bot Response: Logfile
#######################################################################

View File

@@ -15,7 +15,7 @@ jobs:
with:
concurrent_skipping: same_content_newer
- uses: actions/checkout@v3
- uses: actions/checkout@v4
with:
submodules: recursive
@@ -25,28 +25,28 @@ jobs:
echo "sha_short=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
- name: Update PIP cache on every commit
uses: actions/cache@v3.2.3
uses: actions/cache@v4
with:
path: ~/.cache/pip
key: pip-${{ github.run_id }}
restore-keys: pip # This matches above key as it is only used as a prefix. it the restores the nearest cache, see https://github.com/restore-keys:/blob/main/tips-and-workarounds.md#update-a-cache
- name: Update PlatformIO cache on every commit
uses: actions/cache@v3.2.3
uses: actions/cache@v4
with:
path: ~/.platformio
key: platformio-${{ github.run_id }}
restore-keys: platformio # This matches above key as it is only used as a prefix. it the restores the nearest cache, see https://github.com/restore-keys:/blob/main/tips-and-workarounds.md#update-a-cache
- name: Update Build cache on every commit
uses: actions/cache@v3.2.3
uses: actions/cache@v4
with:
path: ./code/.pio/
key: build-${{ github.run_id }}
restore-keys: build # This matches above key as it is only used as a prefix. it the restores the nearest cache, see https://github.com/restore-keys:/blob/main/tips-and-workarounds.md#update-a-cache
- name: Update generated-files cache on every commit
uses: actions/cache@v3.2.3
uses: actions/cache@v4
with:
path: |
./code/.pio/build/esp32cam/firmware.bin
@@ -57,7 +57,7 @@ jobs:
restore-keys: generated-files # This matches above key as it is only used as a prefix. it the restores the nearest cache, see https://github.com/restore-keys:/blob/main/tips-and-workarounds.md#update-a-cache
- name: Set up Python
uses: actions/setup-python@v4
uses: actions/setup-python@v5
with:
python-version: '3.10'
@@ -70,7 +70,7 @@ jobs:
#run: echo "Testing... ${{ github.ref_name }}, ${{ steps.vars.outputs.sha_short }}" > ./sd-card/html/version.txt; mkdir -p ./code/.pio/build/esp32cam/; cd ./code/.pio/build/esp32cam/; echo "${{ steps.vars.outputs.sha_short }}" > firmware.bin; cp firmware.bin partitions.bin; cp firmware.bin bootloader.bin # Testing
run: cd code; platformio run --environment esp32cam
- name: Prepare Web UI (copy data from repo, generate tooltip pages and update hashes in all files)
- name: Prepare Web UI (generate tooltip pages and update hashes in all files)
run: |
rm -rf ./html
mkdir html
@@ -79,7 +79,7 @@ jobs:
python -m pip install markdown
mkdir html/param-tooltips
cd tools/parameter-tooltip-generator
bash generate-param-doc-tooltips.sh
python generate-param-doc-tooltips.py
cd ../..
cp -r ./sd-card/html/* ./html/
@@ -101,10 +101,10 @@ jobs:
needs: build
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Update generated-files cache on every commit
uses: actions/cache@v3.2.3
uses: actions/cache@v4
with:
path: |
./code/.pio/build/esp32cam/firmware.bin
@@ -115,7 +115,7 @@ jobs:
restore-keys: generated-files # This matches above key as it is only used as a prefix. it the restores the nearest cache, see https://github.com/restore-keys:/blob/main/tips-and-workarounds.md#update-a-cache
- name: Update update cache on every commit
uses: actions/cache@v3.2.3
uses: actions/cache@v4
with:
path: update
key: update-${{ github.run_id }}
@@ -144,7 +144,7 @@ jobs:
cp ./sd-card/config/*.tflite ./update/config/ 2>/dev/null || true
- name: Upload update as update.zip artifact (Firmware + Web UI + CNN)
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: "AI-on-the-edge-device__update__${{ steps.vars.outputs.branch }}_(${{ steps.vars.outputs.sha_short }})"
path: ./update/*
@@ -164,10 +164,10 @@ jobs:
needs: build
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Update generated-files cache on every commit
uses: actions/cache@v3.2.3
uses: actions/cache@v4
with:
path: |
./code/.pio/build/esp32cam/firmware.bin
@@ -178,7 +178,7 @@ jobs:
restore-keys: generated-files # This matches above key as it is only used as a prefix. it the restores the nearest cache, see https://github.com/restore-keys:/blob/main/tips-and-workarounds.md#update-a-cache
- name: Update remote_setup cache on every commit
uses: actions/cache@v3.2.3
uses: actions/cache@v4
with:
path: remote_setup
key: remote_setup-${{ github.run_id }}
@@ -205,7 +205,7 @@ jobs:
cp ./sd-card/config/* ./remote_setup/config/ 2>/dev/null || true
- name: Upload remote_setup as remote_setup.zip artifact (Firmware + Web UI + Config)
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: "AI-on-the-edge-device__remote-setup__${{ steps.vars.outputs.branch }}_(${{ steps.vars.outputs.sha_short }})"
path: ./remote_setup/*
@@ -220,10 +220,10 @@ jobs:
needs: build
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Update generated-files cache on every commit
uses: actions/cache@v3.2.3
uses: actions/cache@v4
with:
path: |
./code/.pio/build/esp32cam/firmware.bin
@@ -234,7 +234,7 @@ jobs:
restore-keys: generated-files # This matches above key as it is only used as a prefix. it the restores the nearest cache, see https://github.com/restore-keys:/blob/main/tips-and-workarounds.md#update-a-cache
- name: Update manual_setup cache on every commit
uses: actions/cache@v3.2.3
uses: actions/cache@v4
with:
path: manual_setup
key: manual_setup-${{ github.run_id }}
@@ -263,7 +263,7 @@ jobs:
cd ./manual_setup
- name: Upload manual_setup.zip artifact (Firmware + Bootloader + Partitions + Web UI)
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: "AI-on-the-edge-device__manual-setup__${{ steps.vars.outputs.branch }}_(${{ steps.vars.outputs.sha_short }})"
path: ./manual_setup
@@ -284,24 +284,24 @@ jobs:
id-token: write
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Update update cache on every commit
uses: actions/cache@v3.2.3
uses: actions/cache@v4
with:
path: update
key: update-${{ github.run_id }}
restore-keys: update # This matches above key as it is only used as a prefix. it the restores the nearest cache, see https://github.com/restore-keys:/blob/main/tips-and-workarounds.md#update-a-cache
- name: Update remote_setup cache on every commit
uses: actions/cache@v3.2.3
uses: actions/cache@v4
with:
path: remote_setup
key: remote_setup-${{ github.run_id }}
restore-keys: remote_setup # This matches above key as it is only used as a prefix. it the restores the nearest cache, see https://github.com/restore-keys:/blob/main/tips-and-workarounds.md#update-a-cache
- name: Update manual_setup cache on every commit
uses: actions/cache@v3.2.3
uses: actions/cache@v4
with:
path: manual_setup
key: manual_setup-${{ github.run_id }}
@@ -380,7 +380,7 @@ jobs:
#########################################################################################
## Update the Web Installer on a release
#########################################################################################
# This is the same as in the update-webinstaller.yml
# Make sure to also update update-webinstaller.yml!
update-web-installer:
needs: [release]
environment:
@@ -396,7 +396,7 @@ jobs:
steps:
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Get version of last release
id: last_release
@@ -408,20 +408,23 @@ jobs:
- name: Add binary to Web Installer and update manifest
run: |
echo "Updating Web installer to use firmware from ${{ steps.last_release.outputs.tag_name }}..."
rm -f docs/binary/firmware.bin
wget https://github.com/jomjol/AI-on-the-edge-device/releases/download/${{ steps.last_release.outputs.tag_name }}/AI-on-the-edge-device__update__${{ steps.last_release.outputs.tag_name }}.zip
wget ${{ github.server_url }}/${{ github.repository }}/releases/download/${{ steps.last_release.outputs.tag_name }}/AI-on-the-edge-device__update__${{ steps.last_release.outputs.tag_name }}.zip
unzip AI-on-the-edge-device__update__${{ steps.last_release.outputs.tag_name }}.zip
cp -f firmware.bin docs/binary/firmware.bin
cp -f docs/manifest_template.json docs/manifest.json
sed -i 's/VERSION/${{ steps.last_release.outputs.tag_name }}/g' docs/manifest.json
echo "Updating index and manifest file..."
sed -i 's/$VERSION/${{ steps.last_release.outputs.tag_name }}/g' docs/index.html
sed -i 's/$VERSION/${{ steps.last_release.outputs.tag_name }}/g' docs/manifest.json
- name: Setup Pages
uses: actions/configure-pages@v2
uses: actions/configure-pages@v4
- name: Upload artifact
uses: actions/upload-pages-artifact@v1
uses: actions/upload-pages-artifact@v2
with:
path: 'docs'
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v1
uses: actions/deploy-pages@v3 # Note: v4 does not work!

View File

@@ -1,7 +1,7 @@
# This updates the Web Installer with the files from the docs folder and the binary of the latest release
# it only gets run on:
# - Changes to the docs folder in the `rolling` branch
# - On a release
# - Manually triggered
# Make sure to also update the lower part of build.yml!
name: Manual Web Installer Update
@@ -40,12 +40,14 @@ jobs:
- name: Add binary to Web Installer and update manifest
run: |
echo "Updating Web installer to use firmware from ${{ steps.last_release.outputs.tag_name }}..."
rm -f docs/binary/firmware.bin
wget https://github.com/jomjol/AI-on-the-edge-device/releases/download/${{ steps.last_release.outputs.tag_name }}/AI-on-the-edge-device__update__${{ steps.last_release.outputs.tag_name }}.zip
unzip AI-on-the-edge-device__update__${{ steps.last_release.outputs.tag_name }}.zip
cp -f firmware.bin docs/binary/firmware.bin
cp -f docs/manifest_template.json docs/manifest.json
sed -i 's/VERSION/${{ steps.last_release.outputs.tag_name }}/g' docs/manifest.json
echo "Updating index and manifest file..."
sed -i 's/$VERSION/${{ steps.last_release.outputs.tag_name }}/g' docs/index.html
sed -i 's/$VERSION/${{ steps.last_release.outputs.tag_name }}/g' docs/manifest.json
- name: Setup Pages
uses: actions/configure-pages@v2

6
.gitmodules vendored
View File

@@ -4,9 +4,9 @@
[submodule "code/components/esp-nn"]
path = code/components/esp-nn
url = https://github.com/espressif/esp-nn.git
[submodule "code/components/tflite-micro-esp-examples"]
path = code/components/tflite-micro-esp-examples
url = https://github.com/espressif/tflite-micro-esp-examples.git
[submodule "code/components/esp-tflite-micro"]
path = code/components/esp-tflite-micro
url = https://github.com/espressif/esp-tflite-micro.git
[submodule "code/components/stb"]
path = code/components/stb
url = https://github.com/nothings/stb.git

View File

@@ -1,6 +1,70 @@
## [15.2.4] - 2023-05-02
## [15.6.0] - 2024-02-09
### Changes
For a full list of changes see [Full list of changes](https://github.com/jomjol/AI-on-the-edge-device/compare/v15.5.0...v15.6.0)
#### Fixed
* Fixed issues with the SD-Card initialization
## [15.5.0] - 2024-02-02
For a full list of changes see [Full list of changes](https://github.com/jomjol/AI-on-the-edge-device/compare/v15.4.0...v15.5.0)
#### Changed
- Update PlattformIO to v6.5.0, which means esp-idf to v5.1
- Enhance busy notification
- Implemented late analog / digital transition
#### Fixed
* ATA-TRIM: workaround for old SD-cards with no trim function to work with esp-idf v5.x
* InfluxDB: Modified the time conversions to be more stable (UTC vs. local time shifts)
* Fix negatives on extended resolution false
* Show chip infos on info page
* Fix memory leaks in tflite integration
## [15.4.0] - 2023-12-22
For a full list of changes see [Full list of changes](https://github.com/jomjol/AI-on-the-edge-device/compare/v15.3.0...v15.4.0)
#### Changed
- Updates submodules (esp-nn, tflite-micro-example, esp-camera)
- Explicitly included needed tflite network layers (instead of all) , resulting in much smaller firmware size
- Added shortcut icon
- Rename in InfluxDB 'Database' to 'Bucket'
- Updated analog tflite files
- dig-class100-0167_s2_q.tflite
- dig-class11_1700_s2.tflite
- ana-cont_1208_s2_q.tflite
#### Fixed
* InfluxDB: consider DST setting for UTC time conversion
* Minor html response bugfix
- Memory leakage (MQTT)
## [15.3.0] - 2023-07-22
For a full list of changes see [Full list of changes](https://github.com/jomjol/AI-on-the-edge-device/compare/v15.3.0...v15.2.4)
#### Changed
- Updated PlatformIO to `6.3.2`
- Updated analog tflite files
- ana-cont_1207_s2_q.tflite
- dig-cont_0620_s3_q.tflite
## [15.2.4] - 2023-05-02
For a full list of changes see [Full list of changes](https://github.com/jomjol/AI-on-the-edge-device/compare/v15.2.1...v15.2.4)
@@ -25,8 +89,6 @@ For a full list of changes see [Full list of changes](https://github.com/jomjol/
## [15.2.0] - 2023-04-23
### Changes
For a full list of changes see [Full list of changes](https://github.com/jomjol/AI-on-the-edge-device/compare/v15.1.1...v15.2.0)
#### Added
@@ -56,8 +118,6 @@ For a full list of changes see [Full list of changes](https://github.com/jomjol/
## [15.1.1] - 2023-03-23
### Changes
For a full list of changes see [Full list of changes](https://github.com/jomjol/AI-on-the-edge-device/compare/v15.1.0...v15.1.1)
#### Added

View File

@@ -2,15 +2,41 @@
**There are a lot of ideas for further improvements, but only limited capacity on side of the developer.** Therefore I have created this page as a collection of ideas.
1. Who ever has a new idea can put it here, so it that it is not forgotten.
1. Whoever has a new idea can put it here, so that it is not forgotten.
2. Who ever has time, capacity and passion to support, can take any of the ideas and implement them.
I will support and help where ever I can!
2. Whoever has the time, capacity and passion to support the project can take any of the ideas and implement them. I will provide support and help wherever I can!
____
#### #40 Trigger with cron like exact time slot
* https://github.com/jomjol/AI-on-the-edge-device/issues/2470
#### #39 upnp implementation to auto detect the device
* https://github.com/jomjol/AI-on-the-edge-device/issues/2481
#### #38 Energy Saving
* Deep sleep between recognition
* https://github.com/jomjol/AI-on-the-edge-device/issues/2486
#### #37 Auto init SD card
* Fully implement the SD card handling (including formatting) into the firmware
* https://github.com/jomjol/AI-on-the-edge-device/issues/2488Demo
#### #36 Run demo without camera
Demo mode requires a working camera (if not, one receives a 'Cam bad' error). Would be nice to demo or play around on other ESP32 boards (or on ESP32-CAM boards when you broke the camera cable...).
#### #35 Use the same model, but provide the image from a Smartphone Camera
@@ -51,7 +77,7 @@ haveing this state in the mqtt broker can trigger functions like closing the ate
#### ~~#29 Add favicon and use the hostname for the website~~- implemented v11.3.1
~~* https://github.com/jomjol/AI-on-the-edge-device/issues/927~~
* ~~https://github.com/jomjol/AI-on-the-edge-device/issues/927~~
#### #28 Improved error handling for ROIs
@@ -89,7 +115,7 @@ haveing this state in the mqtt broker can trigger functions like closing the ate
#### ~~#22 Direct hint to the different neural network files in the other repositories~~- implemented >v11.3.1
~~* https://github.com/jomjol/AI-on-the-edge-device/issues/644~~
* ~~https://github.com/jomjol/AI-on-the-edge-device/issues/644~~

View File

@@ -1,31 +1,31 @@
# Welcome to the AI-on-the-edge-device
<img src="images/icon/watermeter.svg" width="100px">
Artificial intelligence based systems have been established in our every days live. Just think of speech or image recognition. Most of the systems relay on either powerful processors or a direct connection to the cloud for doing the calculations up there. With the increasing power of modern processors the AI systems are coming closer to the end user - which is usually called **edge computing**.
Here this edge computing is brought into a practical oriented example, where a AI network is implemented on a ESP32 device so: **AI on the edge**.
Artificial intelligence based systems have become established in our everyday lives. Just think of speech or image recognition. Most of the systems rely on either powerful processors or a direct connection to the cloud for doing the calculations there. With the increasing power of modern processors, the AI systems are coming closer to the end user which is usually called **edge computing**.
Here, this edge computing is put into a practically oriented example, where an AI network is implemented on an ESP32 device so: **AI on the edge**.
This projects allows you to digitalize your **analoge** water, gas, power and other meters using cheap and easily available hardware.
This project allows you to digitize your **analog** water, gas, power and other meters using cheap and easily available hardware.
All you need is an [ESP32 board with a supported camera](https://jomjol.github.io/AI-on-the-edge-device-docs/Hardware-Compatibility/) and a bit of a practical hand.
All you need is an [ESP32 board with a supported camera](https://jomjol.github.io/AI-on-the-edge-device-docs/Hardware-Compatibility/) and something of a practical hand.
<img src="images/esp32-cam.png" width="200px">
## Key features
- Tensorflow Lite (TFlite) integration - including easy to use wrapper
- Inline Image processing (feature detection, alignment, ROI extraction)
- **Small** and **cheap** device (3x4.5x2 cm³, < 10 EUR)
- camera and illumination integrated
- Web surface to administrate and control
- OTA-Interface to update directly through the web interface
- Tensorflow Lite (TFlite) integration including easy-to-use wrapper
- Inline image processing (feature detection, alignment, ROI extraction)
- **Small** and **cheap** device (3 x 4.5 x 2 cm³, < 10 EUR)
- Integrated camera and illumination
- Web interface for administration and control
- OTA interface for updating directly via the web interface
- Full integration into Homeassistant
- Support for Influx DB 1
- Support for Influx DB 1 and 2
- MQTT
- REST API
## Workflow
The device takes a photo of your meter at a defined interval. It then extracts the Regions of Interest (ROI's) out of it and runs them through an artificial inteligence. As a result, you get the digitalized value of your meter.
The device takes a photo of your meter at a defined interval. It then extracts the Regions of Interest (ROIs) from the image and runs them through artificial intelligence. As a result, you get the digitized value of your meter.
There are several options what to do with that value. Either send it to a MQTT broker, write it to an InfluxDb or simply provide it throug a REST API.
There are several options for what to do with that value. Either send it to an MQTT broker, write it to an InfluxDb or simply provide access to it via a REST API.
<img src="https://raw.githubusercontent.com/jomjol/AI-on-the-edge-device/master/images/idea.jpg" width="600">
@@ -41,62 +41,68 @@ There are several options what to do with that value. Either send it to a MQTT b
## Setup
There is a growing [documentation](https://jomjol.github.io/AI-on-the-edge-device-docs/) which provides you with a lot of information.
Head there to get a start, set it up and configure it.
There is growing [documentation](https://jomjol.github.io/AI-on-the-edge-device-docs/) which provides you with a lot of information. Head there to get a start, set it up and configure it.
There are also a articles in the German Heise magazine "make:" about the setup and the technical background (behind a paywall) : [DIY - Setup](https://www.heise.de/select/make/2021/2/2103513300897420296)
There are also articles in the German Heise magazine "make:" about the setup and technical background (behind a paywall): [DIY - Setup](https://www.heise.de/select/make/2021/2/2103513300897420296)
For further background information, head to [Neural Networks](https://www.heise.de/select/make/2021/6/2126410443385102621), [Training Neural Networks](https://www.heise.de/select/make/2022/1/2134114065999161585) and [Programming on the ESP32](https://www.heise.de/select/make/2022/2/2204010051597422030)
A lot of people created useful Youtube videos which might help you getting started.
Here a small selection:
- [youtube.com/watch?v=HKBofb1cnNc](https://www.youtube.com/watch?v=HKBofb1cnNc)
- [youtube.com/watch?v=yyf0ORNLCk4](https://www.youtube.com/watch?v=yyf0ORNLCk4)
- [youtube.com/watch?v=XxmTubGek6M](https://www.youtube.com/watch?v=XxmTubGek6M)
- [youtube.com/watch?v=mDIJEyElkAU](https://www.youtube.com/watch?v=mDIJEyElkAU)
- [youtube.com/watch?v=SssiPkyKVVs](https://www.youtube.com/watch?v=SssiPkyKVVs)
- [youtube.com/watch?v=MAHE_QyHZFQ](https://www.youtube.com/watch?v=MAHE_QyHZFQ)
- [youtube.com/watch?v=Uap_6bwtILQ](https://www.youtube.com/watch?v=Uap_6bwtILQ)
For further background information, head to [Neural Networks](https://www.heise.de/select/make/2021/6/2126410443385102621), [Training Neural Networks](https://www.heise.de/select/make/2022/1/2134114065999161585) and [Programming on the ESP32](https://www.heise.de/select/make/2022/2/2204010051597422030).
### Download
The latest available version is available on the [Releases page](https://github.com/jomjol/AI-on-the-edge-device/releases).
The latest available version can be found on the [Releases page](https://github.com/jomjol/AI-on-the-edge-device/releases).
### Flashing of the ESP32
Initially you will have to flash the ESP32 through an USB connection. Later an update is possible directly over the Air (OTA).
### Flashing the ESP32
Initially you will have to flash the ESP32 via a USB connection. Later updates are possible directly over the air (OTA using WIFI).
There are different ways to flash your ESP32:
- [Web Installer and Console](https://jomjol.github.io/AI-on-the-edge-device/index.html) (Webbrowser based tool to flash the ESP32 and extract the Log over USB)
- The prefered way is the [Web Installer and Console](https://jomjol.github.io/AI-on-the-edge-device/index.html) which is a browser-based tool to flash the ESP32 and extract the log over USB:
![](images/web-installer.png)
- Flash Tool from Espressif
- ESPtool (Command Line Tool)
- ESPtool (command-line tool)
See the [Docu](https://jomjol.github.io/AI-on-the-edge-device-docs/Installation/) for more information.
See the [documentation](https://jomjol.github.io/AI-on-the-edge-device-docs/Installation/) for more information.
### Flashing the SD-Card
The SD-Card must be flashed separately, see the [Docu](https://jomjol.github.io/AI-on-the-edge-device-docs/Installation/) for details.
### Flashing the SD Card
The SD card can be setup automatically after the firmware got installed. See the [documentation](https://jomjol.github.io/AI-on-the-edge-device-docs/Installation/#remote-setup-using-the-built-in-access-point) for details. For this to work, the SD card must be FAT formated (which is the default on a new SD card).
Alternatively the SD card still can be setup manually, see the [documentation](https://jomjol.github.io/AI-on-the-edge-device-docs/Installation/#3-sd-card) for details!
## Casing
A 3d-printable housing can be found here:
Various 3D-printable housing can be found here:
- https://www.thingiverse.com/thing:4573481 (Water Meter)
- https://www.thingiverse.com/thing:5028229 (Power Meter)
- https://www.thingiverse.com/thing:5224101 (Gas Meter)
- https://www.thingiverse.com/thing:4571627 (ESP32-Cam housing only)
## Build it yourself
See [Build Instructions](code/README.md).
- https://www.thingiverse.com/thing:4571627 (ESP32-cam housing only)
## Donate
If you would like to support the developer with a cup of coffee you can do that via [Paypal](https://www.paypal.com/donate?hosted_button_id=8TRSVYNYKDSWL).
If you would like to support the developer with a cup of coffee, you can do that via [PayPal](https://www.paypal.com/donate?hosted_button_id=8TRSVYNYKDSWL).
<form action="https://www.paypal.com/donate" method="post" target="_top">
<input type="hidden" name="hosted_button_id" value="8TRSVYNYKDSWL" />
<input type="image" src="https://www.paypalobjects.com/en_US/DK/i/btn/btn_donateCC_LG.gif" border="0" name="submit" title="PayPal - The safer, easier way to pay online!" alt="Donate with PayPal button" />
<img alt="" border="0" src="https://www.paypal.com/en_DE/i/scr/pixel.gif" width="1" height="1" />
</form>
If you have any technical topics, you can create an [Issue](https://github.com/jomjol/AI-on-the-edge-device/issues).
<a href="https://www.paypal.com/donate?hosted_button_id=8TRSVYNYKDSWL"><img border="0" src="images/paypal.png" width="200px" target="_blank"></a>
In other cases you can contact the developer via email: <img src="https://raw.githubusercontent.com/jomjol/AI-on-the-edge-device/master/images/mail.jpg" height="25">
## Support
If you have any technical problems please search the [discussions](https://github.com/jomjol/AI-on-the-edge-device/discussions). In case you found a ug or have a feature request, please open an [issue](https://github.com/jomjol/AI-on-the-edge-device/issues).
In other cases you can contact the developer via email: <img src="https://raw.githubusercontent.com/jomjol/AI-on-the-edge-device/master/images/mail.jpg" height="25">
## Changes and History
See [Changelog](Changelog.md)
See [Changelog](Changelog.md).
## Build It Yourself
See [Build Instructions](code/README.md).
## Tools
* Logfile downloader and combiner (Thx to [reserve85](https://github.com/reserve85))
* Files see ['/tools/logfile-tool'](tbd), How-to see [Docu](https://jomjol.github.io/AI-on-the-edge-device-docs/outdated--Gasmeter-Log-Downloader/)
* Files see ['/tools/logfile-tool'](tbd), how-to see [documentation](https://jomjol.github.io/AI-on-the-edge-device-docs/outdated--Gasmeter-Log-Downloader/)
## Additional Ideas
There are some ideas and feature requests which are not followed currently - mainly due to capacity reasons on side of the developer. They are collected here: [FeatureRequest.md](FeatureRequest.md)
------
There are some ideas and feature requests which are not currently being pursued mainly due to capacity reasons on the part of the developers.
They features are collected in the [issues](https://github.com/jomjol/AI-on-the-edge-device/issues) and in [FeatureRequest.md](FeatureRequest.md).

1
code/.gitignore vendored
View File

@@ -1,4 +1,5 @@
.pio
.idea
.vscode/.browse.c_cpp.db*
.vscode/c_cpp_properties.json
.vscode/launch.json

View File

@@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.16.0)
list(APPEND EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common components/tflite-micro-esp-examples/components/tflite-lib)
list(APPEND EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common components/esp-tflite-micro)
ADD_CUSTOM_COMMAND(
OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/version.cpp

View File

@@ -8,6 +8,15 @@ git checkout rolling
git submodule update --init
```
## Update Submodules
```
cd /components/submodule-name (e.g. tflite-micro-example)
git checkout VERSION (e.g. HASH of latest tflite-micro-example build)
cd ../../ (auf Ebene von code)
git submodule update --init
```
Evt. muss man vorher noch einige Verzeichnisse in compenents von Hand löschen, da sie beim checkout nicht gelöscht wurden (vor update -- init)
## Build and Flash within terminal
See further down to build it within an IDE.
### Compile
@@ -60,3 +69,6 @@ pio device monitor -p /dev/ttyUSB0
- `pio run --target erase` to erase the flash
- `pio run --target upload` this will upload the `bootloader.bin, partitions.bin,firmware.bin` from the `code/.pio/build/esp32cam/` folder.
- `pio device monitor` to observe the logs via uart
# Update Parameters
If you create or rename a parameter, make sure to update its documentation in `../param-docs/parameter-pages`! Check the `../param-docs/README.md` for more information.

View File

@@ -2,6 +2,6 @@ FILE(GLOB_RECURSE app_sources ${CMAKE_CURRENT_SOURCE_DIR}/*.*)
idf_component_register(SRCS ${app_sources}
INCLUDE_DIRS "." "../../include" "miniz"
REQUIRES vfs tflite-lib esp_http_server app_update esp_http_client nvs_flash jomjol_tfliteclass jomjol_flowcontroll spiffs jomjol_helper jomjol_controlGPIO)
REQUIRES vfs esp_http_server app_update esp_http_client nvs_flash jomjol_tfliteclass jomjol_flowcontroll spiffs jomjol_helper jomjol_controlGPIO)

View File

@@ -153,7 +153,7 @@
/*#define MINIZ_NO_MALLOC */
#ifdef MINIZ_NO_INFLATE_APIS
#define MINIZ_NO_ARCHIVE_APIS
//#define MINIZ_NO_ARCHIVE_APIS
#endif
#ifdef MINIZ_NO_DEFLATE_APIS

View File

@@ -547,7 +547,7 @@ static esp_err_t download_get_handler(httpd_req_t *req)
/* Get value of expected key from query string */
if (httpd_query_key_value(buf, "readonly", param, sizeof(param)) == ESP_OK) {
ESP_LOGI(TAG, "Found URL query parameter => readonly=%s", param);
readonly = param && strcmp(param,"true")==0;
readonly = (strcmp(param,"true") == 0);
}
}
}
@@ -588,7 +588,9 @@ static esp_err_t download_get_handler(httpd_req_t *req)
/* Read file in chunks into the scratch buffer */
chunksize = fread(chunk, 1, SERVER_FILER_SCRATCH_BUFSIZE, fd);
/* Send the buffer contents as HTTP response chunk */
/* Send buffer contents as HTTP chunk. If empty this functions as a
* last-chunk message, signaling end-of-response, to the HTTP client.
* See RFC 2616, section 3.6.1 for details on Chunked Transfer Encoding. */
if (httpd_resp_send_chunk(req, chunk, chunksize) != ESP_OK) {
fclose(fd);
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "File sending failed!");
@@ -606,8 +608,6 @@ static esp_err_t download_get_handler(httpd_req_t *req)
fclose(fd);
ESP_LOGD(TAG, "File successfully sent");
/* Respond with an empty chunk to signal HTTP response completion */
httpd_resp_send_chunk(req, NULL, 0);
return ESP_OK;
}
@@ -717,7 +717,8 @@ static esp_err_t upload_post_handler(httpd_req_t *req)
/* Close file upon upload completion */
fclose(fd);
ESP_LOGI(TAG, "File reception complete");
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "File saved: " + string(filename));
ESP_LOGI(TAG, "File reception completed");
std::string directory = std::string(filepath);
size_t zw = directory.find("/");
@@ -736,21 +737,27 @@ static esp_err_t upload_post_handler(httpd_req_t *req)
// ESP_LOGD(TAG, "Directory danach 2: %s", directory.c_str());
/* Redirect onto root to see the updated file list */
httpd_resp_set_status(req, "303 See Other");
httpd_resp_set_hdr(req, "Location", directory.c_str());
if (strcmp(filename, "/config/config.ini") == 0 ||
strcmp(filename, "/config/ref0.jpg") == 0 ||
strcmp(filename, "/config/ref0_org.jpg") == 0 ||
strcmp(filename, "/config/ref1.jpg") == 0 ||
strcmp(filename, "/config/ref1_org.jpg") == 0 ||
strcmp(filename, "/config/reference.jpg") == 0 ||
strcmp(filename, "/img_tmp/ref0.jpg") == 0 ||
strcmp(filename, "/img_tmp/ref0_org.jpg") == 0 ||
strcmp(filename, "/img_tmp/ref1.jpg") == 0 ||
strcmp(filename, "/img_tmp/ref1_org.jpg") == 0 ||
strcmp(filename, "/img_tmp/reference.jpg") == 0 )
{
httpd_resp_set_status(req, HTTPD_200); // Avoid reloading of folder content
}
else {
httpd_resp_set_status(req, "303 See Other"); // Reload folder content after upload
}
/* Redirect onto root to see the updated file list */
httpd_resp_set_status(req, "303 See Other");
httpd_resp_set_hdr(req, "Location", directory.c_str());
httpd_resp_sendstr(req, "File uploaded successfully");
/*
if (strcmp(filepath, CONFIG_FILE) == 0) {
ESP_LOGD(TAG, "New config found. Reload handler.");
gpio_handler_deinit();
MQTTdestroy();
}
*/
return ESP_OK;
}
@@ -837,16 +844,15 @@ static esp_err_t delete_post_handler(httpd_req_t *req)
return ESP_FAIL;
}
if (stat(filepath, &file_stat) == -1) {
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "File does not exist: " + string(filename));
/* Respond with 400 Bad Request */
httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "File does not exist");
return ESP_FAIL;
if (stat(filepath, &file_stat) == -1) { // File does not exist
/* This is ok, we would delete it anyway */
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "File does not exist: " + string(filename));
}
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Deleting file: " + string(filename));
/* Delete file */
unlink(filepath);
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "File deleted: " + string(filename));
ESP_LOGI(TAG, "File deletion completed");
directory = std::string(filepath);
size_t zw = directory.find("/");
@@ -863,16 +869,30 @@ static esp_err_t delete_post_handler(httpd_req_t *req)
directory = directory.substr(start_fn, found - start_fn + 1);
directory = "/fileserver" + directory;
ESP_LOGD(TAG, "Directory danach 4: %s", directory.c_str());
}
//////////////////////////////////////////////////////////////
/* Redirect onto root to see the updated file list */
if (strcmp(filename, "/config/config.ini") == 0 ||
strcmp(filename, "/config/ref0.jpg") == 0 ||
strcmp(filename, "/config/ref0_org.jpg") == 0 ||
strcmp(filename, "/config/ref1.jpg") == 0 ||
strcmp(filename, "/config/ref1_org.jpg") == 0 ||
strcmp(filename, "/config/reference.jpg") == 0 ||
strcmp(filename, "/img_tmp/ref0.jpg") == 0 ||
strcmp(filename, "/img_tmp/ref0_org.jpg") == 0 ||
strcmp(filename, "/img_tmp/ref1.jpg") == 0 ||
strcmp(filename, "/img_tmp/ref1_org.jpg") == 0 ||
strcmp(filename, "/img_tmp/reference.jpg") == 0 )
{
httpd_resp_set_status(req, HTTPD_200); // Avoid reloading of folder content
}
else {
httpd_resp_set_status(req, "303 See Other"); // Reload folder content after upload
}
}
//////////////////////////////////////////////////////////////
/* Redirect onto root to see the updated file list */
httpd_resp_set_status(req, "303 See Other");
httpd_resp_set_hdr(req, "Location", directory.c_str());
httpd_resp_sendstr(req, "File successfully deleted");
return ESP_OK;
@@ -929,7 +949,7 @@ std::string unzip_new(std::string _in_zip_file, std::string _target_zip, std::st
// Get and print information about each file in the archive.
int numberoffiles = (int)mz_zip_reader_get_num_files(&zip_archive);
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Numbers of files to be extracted: " + to_string(numberoffiles));
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Files to be extracted: " + to_string(numberoffiles));
sort_iter = 0;
{
@@ -993,7 +1013,7 @@ std::string unzip_new(std::string _in_zip_file, std::string _target_zip, std::st
string filename_zw = zw + SUFFIX_ZW;
ESP_LOGI(TAG, "Filename to extract: %s, Zwischenfilename: %s", zw.c_str(), filename_zw.c_str());
ESP_LOGI(TAG, "File to extract: %s, Temp. Filename: %s", zw.c_str(), filename_zw.c_str());
std::string folder = filename_zw.substr(0, filename_zw.find_last_of('/'));
MakeDir(folder);
@@ -1097,7 +1117,7 @@ void unzip(std::string _in_zip_file, std::string _target_directory){
// Save to File.
zw = std::string(archive_filename);
zw = _target_directory + zw;
ESP_LOGD(TAG, "Filename to extract: %s", zw.c_str());
ESP_LOGD(TAG, "File to extract: %s", zw.c_str());
FILE* fpTargetFile = fopen(zw.c_str(), "wb");
fwrite(p, 1, (uint)uncomp_size, fpTargetFile);
fclose(fpTargetFile);

View File

@@ -61,7 +61,13 @@ esp_err_t send_file(httpd_req_t *req, std::string filename)
endsWith(filename, ".jpeg") ||
endsWith(filename, ".ico") ||
endsWith(filename, ".png")) {
httpd_resp_set_hdr(req, "Cache-Control", "max-age=86400");
if (filename == "/sdcard/html/setup.html") {
httpd_resp_set_hdr(req, "Clear-Site-Data", "\"*\"");
}
else {
httpd_resp_set_hdr(req, "Cache-Control", "max-age=86400");
}
}
set_content_type_from_file(req, filename.c_str());

View File

@@ -55,7 +55,7 @@ string ClassFlowCNNGeneral::getReadout(int _analog = 0, bool _extendedResolution
// LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "getReadout(analog) number=" + std::to_string(number) + ", result_after_decimal_point=" + std::to_string(result_after_decimal_point) + ", prev=" + std::to_string(prev));
result = std::to_string(prev);
if (_extendedResolution && (CNNType != Digital))
if (_extendedResolution)
result = result + std::to_string(result_after_decimal_point);
for (int i = GENERAL[_analog]->ROI.size() - 2; i >= 0; --i)
@@ -134,7 +134,22 @@ string ClassFlowCNNGeneral::getReadout(int _analog = 0, bool _extendedResolution
return result;
}
/**
* @brief Determines the number of an ROI in connection with previous ROI results
*
* @param number: is the current ROI as float value from recognition
* @param number_of_predecessors: is the last (lower) ROI as float from recognition
* @param eval_predecessors: is the evaluated number. Sometimes a much lower value can change higer values
* example: 9.8, 9.9, 0.1
* 0.1 => 0 (eval_predecessors)
* The 0 makes a 9.9 to 0 (eval_predecessors)
* The 0 makes a 9.8 to 0
* @param Analog_Predecessors false/true if the last ROI is an analog or digital ROI (default=false)
* runs in special handling because analog is much less precise
* @param digitalAnalogTransitionStart start of the transitionlogic begins on number_of_predecessor (default=9.2)
*
* @return int the determined number of the current ROI
*/
int ClassFlowCNNGeneral::PointerEvalHybridNew(float number, float number_of_predecessors, int eval_predecessors, bool Analog_Predecessors, float digitalAnalogTransitionStart)
{
int result;
@@ -142,11 +157,11 @@ int ClassFlowCNNGeneral::PointerEvalHybridNew(float number, float number_of_pred
int result_before_decimal_point = ((int) floor(number) + 10) % 10;
if (eval_predecessors < 0)
{
if ((result_after_decimal_point <= Digital_Uncertainty * 10) || (result_after_decimal_point >= Digital_Uncertainty * 10)) // Band around the digit --> Rounding, as digit reaches inaccuracy in the frame
result = (int) (round(number) + 10) % 10;
else
result = (int) ((int) trunc(number) + 10) % 10;
{
// on first digit is no spezial logic for transition needed
// we use the recognition as given. The result is the int value of the recognition
// add precisition of 2 digits and round before trunc
result = (int) ((int) trunc(round((number+10 % 10)*100)) ) / 100;
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "PointerEvalHybridNew - No predecessor - Result = " + std::to_string(result) +
" number: " + std::to_string(number) + " number_of_predecessors = " + std::to_string(number_of_predecessors)+ " eval_predecessors = " + std::to_string(eval_predecessors) + " Digital_Uncertainty = " + std::to_string(Digital_Uncertainty));
@@ -485,7 +500,7 @@ bool ClassFlowCNNGeneral::doFlow(string time)
if (!doAlignAndCut(time)){
return false;
};
}
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "doFlow after alignment");
@@ -853,10 +868,9 @@ bool ClassFlowCNNGeneral::doNeuralNetwork(string time)
bool ClassFlowCNNGeneral::isExtendedResolution(int _number)
{
if (!(CNNType == Digital))
return true;
return false;
if (CNNType == Digital)
return false;
return true;
}

View File

@@ -34,13 +34,14 @@ protected:
bool AutoStart;
float AutoInterval;
bool SetupModeActive;
void SetInitialParameter(void);
std::string aktstatusWithTime;
std::string aktstatus;
int aktRunNr;
public:
bool SetupModeActive;
void InitFlow(std::string config);
bool doFlow(string time);
void doFlowTakeImageOnly(string time);

View File

@@ -34,6 +34,7 @@ struct NumberPost {
bool AllowNegativeRates;
bool checkDigitIncreaseConsistency;
time_t lastvalue;
time_t timeStampTimeUTC;
string timeStamp;
double FlowRateAct; // m3 / min
double PreValue; // last value that was read out well

View File

@@ -137,6 +137,7 @@ bool ClassFlowInfluxDB::doFlow(string zwtime)
std::string resultraw = "";
std::string resultrate = "";
std::string resulttimestamp = "";
long int timeutc;
string zw = "";
string namenumber = "";
@@ -152,6 +153,7 @@ bool ClassFlowInfluxDB::doFlow(string zwtime)
resulterror = (*NUMBERS)[i]->ErrorMessageText;
resultrate = (*NUMBERS)[i]->ReturnRateValue;
resulttimestamp = (*NUMBERS)[i]->timeStamp;
timeutc = (*NUMBERS)[i]->timeStampTimeUTC;
if ((*NUMBERS)[i]->FieldV1.length() > 0)
{
@@ -167,7 +169,7 @@ bool ClassFlowInfluxDB::doFlow(string zwtime)
}
if (result.length() > 0)
InfluxDBPublish(measurement, namenumber, result, resulttimestamp);
InfluxDBPublish(measurement, namenumber, result, timeutc);
}
}

View File

@@ -20,7 +20,7 @@ static const char* TAG = "INFLUXDBV2";
void ClassFlowInfluxDBv2::SetInitialParameter(void)
{
uri = "";
database = "";
bucket = "";
dborg = "";
dbtoken = "";
// dbfield = "";
@@ -109,9 +109,9 @@ bool ClassFlowInfluxDBv2::ReadParameter(FILE* pfile, string& aktparamgraph)
{
handleMeasurement(splitted[0], splitted[1]);
}
if (((toUpper(splitted[0]) == "DATABASE")) && (splitted.size() > 1))
if (((toUpper(splitted[0]) == "BUCKET")) && (splitted.size() > 1))
{
this->database = splitted[1];
this->bucket = splitted[1];
}
}
@@ -119,11 +119,11 @@ bool ClassFlowInfluxDBv2::ReadParameter(FILE* pfile, string& aktparamgraph)
printf("org: %s\n", dborg.c_str());
printf("token: %s\n", dbtoken.c_str());
if ((uri.length() > 0) && (database.length() > 0) && (dbtoken.length() > 0) && (dborg.length() > 0))
if ((uri.length() > 0) && (bucket.length() > 0) && (dbtoken.length() > 0) && (dborg.length() > 0))
{
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Init InfluxDB with uri: " + uri + ", org: " + dborg + ", token: *****");
// printf("vor V2 Init\n");
InfluxDB_V2_Init(uri, database, dborg, dbtoken);
InfluxDB_V2_Init(uri, bucket, dborg, dbtoken);
// printf("nach V2 Init\n");
InfluxDBenable = true;
} else {
@@ -196,6 +196,7 @@ bool ClassFlowInfluxDBv2::doFlow(string zwtime)
std::string resultraw = "";
std::string resultrate = "";
std::string resulttimestamp = "";
long int resulttimeutc = 0;
string zw = "";
string namenumber = "";
@@ -212,6 +213,8 @@ bool ClassFlowInfluxDBv2::doFlow(string zwtime)
resulterror = (*NUMBERS)[i]->ErrorMessageText;
resultrate = (*NUMBERS)[i]->ReturnRateValue;
resulttimestamp = (*NUMBERS)[i]->timeStamp;
resulttimeutc = (*NUMBERS)[i]->timeStampTimeUTC;
if ((*NUMBERS)[i]->FieldV2.length() > 0)
{
@@ -229,8 +232,7 @@ bool ClassFlowInfluxDBv2::doFlow(string zwtime)
printf("vor sende Influx_DB_V2 - namenumber. %s, result: %s, timestampt: %s", namenumber.c_str(), result.c_str(), resulttimestamp.c_str());
if (result.length() > 0)
InfluxDB_V2_Publish(measurement, namenumber, result, resulttimestamp);
// InfluxDB_V2_Publish(namenumber, result, resulttimestamp);
InfluxDB_V2_Publish(measurement, namenumber, result, resulttimeutc);
}
}

View File

@@ -15,7 +15,7 @@ class ClassFlowInfluxDBv2 :
public ClassFlow
{
protected:
std::string uri, database;
std::string uri, bucket;
std::string dborg, dbtoken, dbfield;
std::string OldValue;
ClassFlowPostProcessing* flowpostprocessing;

View File

@@ -37,6 +37,9 @@ void ClassFlowMQTT::SetInitialParameter(void)
topicUptime = "";
topicFreeMem = "";
caCertFilename = "";
clientCertFilename = "";
clientKeyFilename = "";
clientname = wlan_config.hostname;
OldValue = "";
@@ -102,6 +105,18 @@ bool ClassFlowMQTT::ReadParameter(FILE* pfile, string& aktparamgraph)
while (this->getNextLine(pfile, &aktparamgraph) && !this->isNewParagraph(aktparamgraph))
{
splitted = ZerlegeZeile(aktparamgraph);
if ((toUpper(splitted[0]) == "CACERT") && (splitted.size() > 1))
{
this->caCertFilename = splitted[1];
}
if ((toUpper(splitted[0]) == "CLIENTCERT") && (splitted.size() > 1))
{
this->clientCertFilename = splitted[1];
}
if ((toUpper(splitted[0]) == "CLIENTKEY") && (splitted.size() > 1))
{
this->clientKeyFilename = splitted[1];
}
if ((toUpper(splitted[0]) == "USER") && (splitted.size() > 1))
{
this->user = splitted[1];
@@ -196,7 +211,8 @@ bool ClassFlowMQTT::Start(float AutoInterval)
mqttServer_setParameter(flowpostprocessing->GetNumbers(), keepAlive, roundInterval);
bool MQTTConfigCheck = MQTT_Configure(uri, clientname, user, password, maintopic, LWT_TOPIC, LWT_CONNECTED,
LWT_DISCONNECTED, keepAlive, SetRetainFlag, (void *)&GotConnected);
LWT_DISCONNECTED, caCertFilename, clientCertFilename, clientKeyFilename,
keepAlive, SetRetainFlag, (void *)&GotConnected);
if (!MQTTConfigCheck) {
return false;

View File

@@ -19,6 +19,7 @@ protected:
std::string OldValue;
ClassFlowPostProcessing* flowpostprocessing;
std::string user, password;
std::string caCertFilename, clientCertFilename, clientKeyFilename;
bool SetRetainFlag;
int keepAlive; // Seconds
float roundInterval; // Minutes

View File

@@ -5,6 +5,7 @@
#include <iomanip>
#include <sstream>
#include <cassert>
#include <time.h>
@@ -284,6 +285,7 @@ void ClassFlowPostProcessing::SavePreValue()
struct tm* timeinfo = localtime(&NUMBERS[j]->lastvalue);
strftime(buffer, 80, PREVALUE_TIME_FORMAT_OUTPUT, timeinfo);
NUMBERS[j]->timeStamp = std::string(buffer);
NUMBERS[j]->timeStampTimeUTC = NUMBERS[j]->lastvalue;
// ESP_LOGD(TAG, "SaverPreValue %d, Value: %f, Nachkomma %d", j, NUMBERS[j]->PreValue, NUMBERS[j]->Nachkomma);
_zw = NUMBERS[j]->name + "\t" + NUMBERS[j]->timeStamp + "\t" + RundeOutput(NUMBERS[j]->PreValue, NUMBERS[j]->Nachkomma) + "\n";
@@ -725,6 +727,130 @@ string ClassFlowPostProcessing::ShiftDecimal(string in, int _decShift){
return zw;
}
float wrapAround(float val)
{
return fmod(val, 10.);
}
/**
* @brief Checks whether val is in the range [min, max]
*
* Note, this function also handles the wrap around case,
* in which min could be larger than max in case of
* a circular range
*
* @param val The value to be checked
* @param min Minimal bound of the range
* @param max Maximum bound of the range
* @return True, if val is in the range
*/
bool inRange(float val, float min, float max)
{
assert(min >= 0. && min < 10.0);
assert(max >= 0. && max <= 10.0);
assert(val >= 0. && val < 10.0);
if (min <= max)
{
return min <= val && val <= max;
}
else
{
// e.g. between 8 and 2 (of the next round)
return (min <= val && val < 10.) || (0. <= val && val <= max);
}
}
/**
* @brief Synchronizes a potential misalignment between analog and digital part
*
* @param The current value assembled from digits (pre comma) and analogs (post comma)
* @param digitalPrecision The post-comma value of the last digit ([0...9])
* @param analogDigitalShift The value of the 0.1 analog, when the digital precision == 5 in [0, 9.9]
*
* We define 3 phases:
* - Pre transition: analog post comma < analogDigitalShift && not in transition
* - Transition: Digital Precision in range 1...9
* - Post transition: analog post comma > analogDigitalShift && not in transition
*
* @return The synchronized values as a string
*/
std::string syncDigitalAnalog(const std::string& value, const std::string& digitalPrecision,
double analogDigitalShift)
{
if (digitalPrecision.empty())
{
return value;
}
const auto pos = value.find('.');
if (pos == std::string::npos)
{
return value;
}
// disassemble value into pre and post comma part
const auto preComma = value.substr(0, pos);
// memorize, to be able to assemble right numbers of leading zeros
const size_t nPreComma = preComma.size();
const auto postComma = value.substr(pos+1);
const float digitalPostComma = std::atof(digitalPrecision.c_str());
int digitalPreComma = std::atoi(preComma.c_str());
const float analogPostComma = std::atof(("0." + postComma).c_str());
// Determine phase
const bool inTransition = digitalPostComma > 0. && digitalPostComma < 10.;
const bool postTransition = !inTransition && inRange(analogPostComma*10., analogDigitalShift, wrapAround(analogDigitalShift + 5.));
const bool preTransition = !inTransition && inRange(analogPostComma*10., 0, analogDigitalShift);
if (inRange(analogDigitalShift, 0.5, 5.))
{
// late transition, last digit starts transition, when analog is between [0.5, 5)
if (inTransition || preTransition)
{
ESP_LOGD("syncDigitalAnalog", "Late digital transition. Increase digital value by 1.");
digitalPreComma += 1;
}
}
else if (inRange(analogDigitalShift, 5., 9.5))
{
// early transition
if (postTransition && analogPostComma*10 > analogDigitalShift)
{
ESP_LOGD("syncDigitalAnalog", "Early digital transition. Decrease digital value by 1.");
digitalPreComma -= 1;
}
// transition has not finished, but we are already at the new cycle
// this also should handle hanging digits
if (inTransition && analogPostComma < 0.5) {
digitalPreComma += 1;
}
}
else
{
return value;
}
// assemble result into string again, pad with zeros
auto preCommaNew = std::to_string(digitalPreComma);
for (size_t i = preCommaNew.size(); i < nPreComma; ++i)
preCommaNew = "0" + preCommaNew;
const std::string result = preCommaNew + "." + postComma;
#if debugSync
ESP_LOGD("syncDigitalAnalog", "result: %s", result.c_str());
#endif
return result;
}
bool ClassFlowPostProcessing::doFlow(string zwtime)
{
string result = "";
@@ -768,6 +894,8 @@ bool ClassFlowPostProcessing::doFlow(string zwtime)
int previous_value = -1;
// ------------------- start processing analog values --------------------------//
if (NUMBERS[j]->analog_roi)
{
NUMBERS[j]->ReturnRawValue = flowAnalog->getReadout(j, NUMBERS[j]->isExtendedResolution);
@@ -781,19 +909,38 @@ bool ClassFlowPostProcessing::doFlow(string zwtime)
#ifdef SERIAL_DEBUG
ESP_LOGD(TAG, "After analog->getReadout: ReturnRaw %s", NUMBERS[j]->ReturnRawValue.c_str());
#endif
if (NUMBERS[j]->digit_roi && NUMBERS[j]->analog_roi)
NUMBERS[j]->ReturnRawValue = "." + NUMBERS[j]->ReturnRawValue;
if (NUMBERS[j]->digit_roi)
// ----------------- start processing digital values --------------------------//
// we need the precision of the digital values to determine transition phase
std::string digitalPrecision = {"0"};
if (NUMBERS[j]->digit_roi && NUMBERS[j]->analog_roi) {
// we have nachkommad and vorkomman part!
std::string analogValues = NUMBERS[j]->ReturnRawValue;
std::string digitValues = flowDigit->getReadout(j, true, previous_value, NUMBERS[j]->analog_roi->ROI[0]->result_float, 0.);
if (flowDigit->getCNNType() != Digital)
{
// The digital type does not provide an extended resolution, so we cannot extract it
digitalPrecision = digitValues.substr(digitValues.size() - 1);
digitValues = digitValues.substr(0, digitValues.size() - 1);
}
NUMBERS[j]->ReturnRawValue = digitValues + "." + analogValues;
}
if (NUMBERS[j]->digit_roi && !NUMBERS[j]->analog_roi)
{
if (NUMBERS[j]->analog_roi)
NUMBERS[j]->ReturnRawValue = flowDigit->getReadout(j, false, previous_value, NUMBERS[j]->analog_roi->ROI[0]->result_float, NUMBERS[j]->AnalogDigitalTransitionStart) + NUMBERS[j]->ReturnRawValue;
else
NUMBERS[j]->ReturnRawValue = flowDigit->getReadout(j, NUMBERS[j]->isExtendedResolution, previous_value); // Extended Resolution only if there are no analogue digits
NUMBERS[j]->ReturnRawValue = flowDigit->getReadout(j, NUMBERS[j]->isExtendedResolution, previous_value); // Extended Resolution only if there are no analogue digits
}
#ifdef SERIAL_DEBUG
ESP_LOGD(TAG, "After digital->getReadout: ReturnRaw %s", NUMBERS[j]->ReturnRawValue.c_str());
#endif
// ------------------ start corrections --------------------------//
NUMBERS[j]->ReturnRawValue = ShiftDecimal(NUMBERS[j]->ReturnRawValue, NUMBERS[j]->DecimalShift);
#ifdef SERIAL_DEBUG
@@ -813,7 +960,7 @@ bool ClassFlowPostProcessing::doFlow(string zwtime)
{
if (PreValueUse && NUMBERS[j]->PreValueOkay)
{
NUMBERS[j]->ReturnValue = ErsetzteN(NUMBERS[j]->ReturnValue, NUMBERS[j]->PreValue);
NUMBERS[j]->ReturnValue = ErsetzteN(NUMBERS[j]->ReturnValue, NUMBERS[j]->PreValue);
}
else
{
@@ -826,6 +973,13 @@ bool ClassFlowPostProcessing::doFlow(string zwtime)
continue; // there is no number because there is still an N.
}
}
if (NUMBERS[j]->digit_roi && NUMBERS[j]->analog_roi)
{
// Synchronize potential misalignment between analog and digital part
NUMBERS[j]->ReturnValue = syncDigitalAnalog(NUMBERS[j]->ReturnValue, digitalPrecision, NUMBERS[j]->AnalogDigitalTransitionStart);
}
#ifdef SERIAL_DEBUG
ESP_LOGD(TAG, "After findDelimiterPos: ReturnValue %s", NUMBERS[j]->ReturnRawValue.c_str());
#endif
@@ -866,17 +1020,21 @@ bool ClassFlowPostProcessing::doFlow(string zwtime)
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "handleAllowNegativeRate for device: " + NUMBERS[j]->name);
if ((NUMBERS[j]->Value < NUMBERS[j]->PreValue))
{
#ifdef SERIAL_DEBUG
ESP_LOGD(TAG, "Neg: value=%f, preValue=%f, preToll%f", NUMBERS[j]->Value, NUMBERS[j]->PreValue,
NUMBERS[j]->PreValue-(2/pow(10, NUMBERS[j]->Nachkomma))
) ;
#endif
// Include inaccuracy of 0.2 for isExtendedResolution.
if (NUMBERS[j]->Value >= (NUMBERS[j]->PreValue-(2/pow(10, NUMBERS[j]->Nachkomma))) && NUMBERS[j]->isExtendedResolution) {
NUMBERS[j]->Value = NUMBERS[j]->PreValue;
NUMBERS[j]->ReturnValue = to_string(NUMBERS[j]->PreValue);
} else {
// more debug if extended resolution is on, see #2447
if (NUMBERS[j]->isExtendedResolution) {
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Neg: value=" + std::to_string(NUMBERS[j]->Value)
+ ", preValue=" + std::to_string(NUMBERS[j]->PreValue)
+ ", preToll=" + std::to_string(NUMBERS[j]->PreValue-(2/pow(10, NUMBERS[j]->Nachkomma))));
}
// Include inaccuracy of 0.2 for isExtendedResolution.
if ((NUMBERS[j]->Value >= (NUMBERS[j]->PreValue-(2/pow(10, NUMBERS[j]->Nachkomma))) && NUMBERS[j]->isExtendedResolution)
// not extended resolution allows -1 on the lowest digit
|| (NUMBERS[j]->Value >= (NUMBERS[j]->PreValue-(1/pow(10, NUMBERS[j]->Nachkomma))) && !NUMBERS[j]->isExtendedResolution)) {
NUMBERS[j]->Value = NUMBERS[j]->PreValue;
NUMBERS[j]->ReturnValue = to_string(NUMBERS[j]->PreValue);
}
else {
NUMBERS[j]->ErrorMessageText = NUMBERS[j]->ErrorMessageText + "Neg. Rate - Read: " + zwvalue + " - Raw: " + NUMBERS[j]->ReturnRawValue + " - Pre: " + RundeOutput(NUMBERS[j]->PreValue, NUMBERS[j]->Nachkomma) + " ";
NUMBERS[j]->Value = NUMBERS[j]->PreValue;
NUMBERS[j]->ReturnValue = "";

View File

@@ -230,7 +230,7 @@ esp_err_t handler_stream(httpd_req_t *req)
if (httpd_query_key_value(_query, "flashlight", _value, 10) == ESP_OK)
{
#ifdef DEBUG_DETAIL_ON
ESP_LOGD(TAG, "flashlight is found%s", _size);
ESP_LOGD(TAG, "flashlight is found%s", _value);
#endif
if (strlen(_value) > 0)
flashlightOn = true;
@@ -453,7 +453,7 @@ esp_err_t handler_wasserzaehler(httpd_req_t *req)
else {
/* Digital ROIs */
txt = "<body style=\"font-family: arial\">";
txt += "<h3>Recognized Digit ROIs (previous round)</h3>\n";
txt += "<hr><h3>Recognized Digit ROIs (previous round)</h3>\n";
txt += "<table style=\"border-spacing: 5px\"><tr style=\"text-align: center; vertical-align: top;\">\n";
std::vector<HTMLInfo*> htmlinfodig;
@@ -488,7 +488,7 @@ esp_err_t handler_wasserzaehler(httpd_req_t *req)
/* Analog ROIs */
txt = "<h3>Recognized Analog ROIs (previous round)</h3>\n";
txt = "<hr><h3>Recognized Analog ROIs (previous round)</h3>\n";
txt += "<table style=\"border-spacing: 5px\"><tr style=\"text-align: center; vertical-align: top;\">\n";
std::vector<HTMLInfo*> htmlinfoana;
@@ -510,7 +510,7 @@ esp_err_t handler_wasserzaehler(httpd_req_t *req)
/* Full Image
* Only show it after the image got taken and aligned */
txt = "<h3>Aligned Image (current round)</h3>\n";
txt = "<hr><h3>Aligned Image (current round)</h3>\n";
if ((*status == std::string("Initialization")) ||
(*status == std::string("Initialization (delayed)")) ||
(*status == std::string("Take Image"))) {
@@ -657,14 +657,7 @@ esp_err_t handler_editflow(httpd_req_t *req)
string out2 = out.substr(0, out.length() - 4) + "_org.jpg";
std::string state = *flowctrl.getActStatus();
/* To be able to provide the image, several conditions must be met due to the shared PSRAM usage:
- Ether the round most be completed or not started yet
- Or we must be in Setup Mode
- Additionally, the initialization of the shared PSRAM must be successful */
if (((state == "Flow finished") || (state == "Initialization") || (state == "Initialization (delayed)") || isSetupModusActive()) &&
psram_init_shared_memory_for_take_image_step()) {
if ((flowctrl.SetupModeActive || (*flowctrl.getActStatus() == "Flow finished")) && psram_init_shared_memory_for_take_image_step()) {
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Taking image for Alignment Mark Update...");
CAlignAndCutImage *caic = new CAlignAndCutImage("cutref", in);
@@ -687,7 +680,7 @@ esp_err_t handler_editflow(httpd_req_t *req)
}
else {
LogFile.WriteToFile(ESP_LOG_WARN, TAG, std::string("Taking image for Alignment Mark not possible while device") +
" is busy with a round (Current State: '" + state + "')!");
" is busy with a round (Current State: '" + *flowctrl.getActStatus() + "')!");
zw = "Device Busy";
}
@@ -897,7 +890,7 @@ esp_err_t handler_prevalue(httpd_req_t *req)
if (httpd_query_key_value(_query, "value", _value, 20) == ESP_OK) {
#ifdef DEBUG_DETAIL_ON
ESP_LOGD(TAG, "Value: %s", _size);
ESP_LOGD(TAG, "Value: %s", _value);
#endif
}
}

View File

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

View File

@@ -27,10 +27,10 @@ extern "C" {
#include <esp_timer.h>
#include "../../include/defines.h"
#include "ClassLogFile.h"
#include "esp_vfs_fat.h"
#include "../sdmmc_common.h"
static const char* TAG = "HELPER";
@@ -40,7 +40,7 @@ unsigned int systemStatus = 0;
sdmmc_cid_t SDCardCid;
sdmmc_csd_t SDCardCsd;
bool SDCardIsMMC;
// #define DEBUG_DETAIL_ON
@@ -139,6 +139,7 @@ string getSDCardPartitionAllocationSize(){
void SaveSDCardInfo(sdmmc_card_t* card) {
SDCardCid = card->cid;
SDCardCsd = card->csd;
SDCardIsMMC = card->is_mmc;
}
@@ -674,7 +675,7 @@ struct SDCard_Manufacturer_database {
/* Source: https://git.kernel.org/pub/scm/utils/mmc/mmc-utils.git/tree/lsmmc.c */
/* SD Card Manufacturer Database */
struct SDCard_Manufacturer_database database[] = {
struct SDCard_Manufacturer_database sd_database[] = {
{
.type = "sd",
.id = 0x01,
@@ -779,25 +780,124 @@ struct SDCard_Manufacturer_database database[] = {
.type = "sd",
.id = 0x89,
.manufacturer = "Unknown",
}
},
};
struct SDCard_Manufacturer_database mmc_database[] = {
{
.type = "mmc",
.id = 0x00,
.manufacturer = "SanDisk",
},
{
.type = "mmc",
.id = 0x02,
.manufacturer = "Kingston/SanDisk",
},
{
.type = "mmc",
.id = 0x03,
.manufacturer = "Toshiba",
},
{
.type = "mmc",
.id = 0x05,
.manufacturer = "Unknown",
},
{
.type = "mmc",
.id = 0x06,
.manufacturer = "Unknown",
},
{
.type = "mmc",
.id = 0x11,
.manufacturer = "Toshiba",
},
{
.type = "mmc",
.id = 0x13,
.manufacturer = "Micron",
},
{
.type = "mmc",
.id = 0x15,
.manufacturer = "Samsung/SanDisk/LG",
},
{
.type = "mmc",
.id = 0x37,
.manufacturer = "KingMax",
},
{
.type = "mmc",
.id = 0x44,
.manufacturer = "ATP",
},
{
.type = "mmc",
.id = 0x45,
.manufacturer = "SanDisk Corporation",
},
{
.type = "mmc",
.id = 0x2c,
.manufacturer = "Kingston",
},
{
.type = "mmc",
.id = 0x70,
.manufacturer = "Kingston",
},
{
.type = "mmc",
.id = 0xfe,
.manufacturer = "Micron",
},
};
/* Parse SD Card Manufacturer Database */
string SDCardParseManufacturerIDs(int id)
{
unsigned int id_cnt = sizeof(database) / sizeof(struct SDCard_Manufacturer_database);
if (SDCardIsMMC)
{
unsigned int id_cnt = sizeof(mmc_database) / sizeof(struct SDCard_Manufacturer_database);
string ret_val = "";
for (int i = 0; i < id_cnt; i++)
{
if (mmc_database[i].id == id)
{
return mmc_database[i].manufacturer;
}
else
{
ret_val = "ID unknown (not in DB)";
}
}
return ret_val;
}
else
{
unsigned int id_cnt = sizeof(sd_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)";
}
for (int i = 0; i < id_cnt; i++)
{
if (sd_database[i].id == id)
{
return sd_database[i].manufacturer;
}
else
{
ret_val = "ID unknown (not in DB)";
}
}
return ret_val;
}
}

View File

@@ -6,6 +6,7 @@
#include <string>
#include <fstream>
#include <vector>
#include "sdmmc_cmd.h"
using namespace std;

View File

@@ -3,6 +3,7 @@
#include <stdio.h>
#include <stdbool.h>
#include <stdint.h>
#include <unistd.h>
#include <inttypes.h>
#include <sys/stat.h>

View File

@@ -0,0 +1,651 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <stdlib.h>
#include <string.h>
#include "sdcard_init.h"
#include "esp_log.h"
#include "ffconf.h"
#include "esp_compiler.h"
#include "esp_vfs.h"
#include "vfs_fat_internal.h"
#include "diskio_impl.h"
#include "diskio_sdmmc.h"
#include "soc/soc_caps.h"
#include "driver/sdmmc_defs.h"
#if SOC_SDMMC_HOST_SUPPORTED
#include "driver/sdmmc_host.h"
#endif
static sdmmc_card_t* s_cards[FF_VOLUMES] = { NULL };
static bool s_disk_status_check_en[FF_VOLUMES] = { };
static const char* TAG = "sdcard_init";
#define CHECK_EXECUTE_RESULT(err, str) do { \
if ((err) !=ESP_OK) { \
ESP_LOGE(TAG, str" (0x%x).", err); \
goto cleanup; \
} \
} while(0)
typedef struct vfs_fat_sd_ctx_t {
BYTE pdrv; //Drive number that is mounted
esp_vfs_fat_mount_config_t mount_config; //Mount configuration
FATFS *fs; //FAT structure pointer that is registered
sdmmc_card_t *card; //Card info
char *base_path; //Path where partition is registered
} vfs_fat_sd_ctx_t;
static vfs_fat_sd_ctx_t *s_ctx[FF_VOLUMES] = {};
/**
* This `s_saved_ctx_id` is only used by `esp_vfs_fat_sdmmc_unmount`, which is deprecated.
* This variable together with `esp_vfs_fat_sdmmc_unmount` should be removed in next major version
*/
static uint32_t s_saved_ctx_id = FF_VOLUMES;
static void call_host_deinit_mh(const sdmmc_host_t *host_config);
static esp_err_t partition_card_mh(const esp_vfs_fat_mount_config_t *mount_config, const char *drv, sdmmc_card_t *card, BYTE pdrv);
//Check if SD/MMC card is present
static DSTATUS ff_sdmmc_card_available_mh(BYTE pdrv)
{
sdmmc_card_t* card = s_cards[pdrv];
assert(card);
esp_err_t err = sdmmc_get_status(card);
if (unlikely(err != ESP_OK)) {
ESP_LOGE(TAG, "Check status failed (0x%x)", err);
return STA_NOINIT;
}
return 0;
}
/**
* ff_sdmmc_status() and ff_sdmmc_initialize() return STA_NOINIT when sdmmc_get_status()
* fails. This error value is checked throughout the FATFS code.
* Both functions return 0 on success.
*/
DSTATUS ff_sdmmc_initialize_mh (BYTE pdrv)
{
return ff_sdmmc_card_available_mh(pdrv);
}
DSTATUS ff_sdmmc_status_mh(BYTE pdrv)
{
if (s_disk_status_check_en[pdrv]) {
return ff_sdmmc_card_available_mh(pdrv);
}
return 0;
}
DRESULT ff_sdmmc_read_mh (BYTE pdrv, BYTE* buff, DWORD sector, UINT count)
{
sdmmc_card_t* card = s_cards[pdrv];
assert(card);
esp_err_t err = sdmmc_read_sectors(card, buff, sector, count);
if (unlikely(err != ESP_OK)) {
ESP_LOGE(TAG, "sdmmc_read_blocks failed (%d)", err);
return RES_ERROR;
}
return RES_OK;
}
DRESULT ff_sdmmc_write_mh (BYTE pdrv, const BYTE* buff, DWORD sector, UINT count)
{
sdmmc_card_t* card = s_cards[pdrv];
assert(card);
esp_err_t err = sdmmc_write_sectors(card, buff, sector, count);
if (unlikely(err != ESP_OK)) {
ESP_LOGE(TAG, "sdmmc_write_blocks failed (%d)", err);
return RES_ERROR;
}
return RES_OK;
}
#if FF_USE_TRIM
DRESULT ff_sdmmc_trim_mh (BYTE pdrv, DWORD start_sector, DWORD sector_count)
{
sdmmc_card_t* card = s_cards[pdrv];
assert(card);
sdmmc_erase_arg_t arg;
arg = sdmmc_can_discard(card) == ESP_OK ? SDMMC_DISCARD_ARG : SDMMC_ERASE_ARG;
esp_err_t err = sdmmc_erase_sectors(card, start_sector, sector_count, arg);
if (unlikely(err != ESP_OK)) {
ESP_LOGE(TAG, "sdmmc_erase_sectors failed (%d)", err);
return RES_ERROR;
}
return RES_OK;
}
#endif //FF_USE_TRIM
DRESULT ff_sdmmc_ioctl_mh (BYTE pdrv, BYTE cmd, void* buff)
{
sdmmc_card_t* card = s_cards[pdrv];
assert(card);
switch(cmd) {
case CTRL_SYNC:
return RES_OK;
case GET_SECTOR_COUNT:
*((DWORD*) buff) = card->csd.capacity;
return RES_OK;
case GET_SECTOR_SIZE:
*((WORD*) buff) = card->csd.sector_size;
return RES_OK;
case GET_BLOCK_SIZE:
return RES_ERROR;
#if FF_USE_TRIM
case CTRL_TRIM:
if (sdmmc_can_trim(card) != ESP_OK) {
return RES_PARERR;
}
return ff_sdmmc_trim_mh (pdrv, *((DWORD*)buff), //start_sector
(*((DWORD*)buff + 1) - *((DWORD*)buff) + 1)); //sector_count
#endif //FF_USE_TRIM
}
return RES_ERROR;
}
void ff_sdmmc_set_disk_status_check_mh(BYTE pdrv, bool enable)
{
s_disk_status_check_en[pdrv] = enable;
}
void ff_diskio_register_sdmmc_mh(BYTE pdrv, sdmmc_card_t* card)
{
static const ff_diskio_impl_t sdmmc_impl = {
.init = &ff_sdmmc_initialize_mh,
.status = &ff_sdmmc_status_mh,
.read = &ff_sdmmc_read_mh,
.write = &ff_sdmmc_write_mh,
.ioctl = &ff_sdmmc_ioctl_mh
};
s_cards[pdrv] = card;
s_disk_status_check_en[pdrv] = false;
ff_diskio_register(pdrv, &sdmmc_impl);
}
BYTE ff_diskio_get_pdrv_card_mh(const sdmmc_card_t* card)
{
for (int i = 0; i < FF_VOLUMES; i++) {
if (card == s_cards[i]) {
return i;
}
}
return 0xff;
}
static bool s_get_context_id_by_card_mh(const sdmmc_card_t *card, uint32_t *out_id)
{
vfs_fat_sd_ctx_t *p_ctx = NULL;
for (int i = 0; i < FF_VOLUMES; i++) {
p_ctx = s_ctx[i];
if (p_ctx) {
if (p_ctx->card == card) {
*out_id = i;
return true;
}
}
}
return false;
}
static uint32_t s_get_unused_context_id_mh(void)
{
for (uint32_t i = 0; i < FF_VOLUMES; i++) {
if (!s_ctx[i]) {
return i;
}
}
return FF_VOLUMES;
}
static esp_err_t mount_prepare_mem_mh(const char *base_path, BYTE *out_pdrv, char **out_dup_path, sdmmc_card_t** out_card)
{
esp_err_t err = ESP_OK;
char* dup_path = NULL;
sdmmc_card_t* card = NULL;
// connect SDMMC driver to FATFS
BYTE pdrv = FF_DRV_NOT_USED;
if (ff_diskio_get_drive(&pdrv) != ESP_OK || pdrv == FF_DRV_NOT_USED) {
ESP_LOGD(TAG, "the maximum count of volumes is already mounted");
return ESP_ERR_NO_MEM;
}
// not using ff_memalloc here, as allocation in internal RAM is preferred
card = (sdmmc_card_t*)malloc(sizeof(sdmmc_card_t));
if (card == NULL) {
ESP_LOGD(TAG, "could not locate new sdmmc_card_t");
err = ESP_ERR_NO_MEM;
goto cleanup;
}
dup_path = strdup(base_path);
if(!dup_path){
ESP_LOGD(TAG, "could not copy base_path");
err = ESP_ERR_NO_MEM;
goto cleanup;
}
*out_card = card;
*out_pdrv = pdrv;
*out_dup_path = dup_path;
return ESP_OK;
cleanup:
free(card);
free(dup_path);
return err;
}
static esp_err_t s_f_mount_mh(sdmmc_card_t *card, FATFS *fs, const char *drv, uint8_t pdrv, const esp_vfs_fat_mount_config_t *mount_config)
{
esp_err_t err = ESP_OK;
FRESULT res = f_mount(fs, drv, 1);
if (res != FR_OK) {
err = ESP_FAIL;
ESP_LOGW(TAG, "failed to mount card (%d)", res);
bool need_mount_again = (res == FR_NO_FILESYSTEM || res == FR_INT_ERR) && mount_config->format_if_mount_failed;
if (!need_mount_again) {
return ESP_FAIL;
}
err = partition_card_mh(mount_config, drv, card, pdrv);
if (err != ESP_OK) {
return err;
}
ESP_LOGW(TAG, "mounting again");
res = f_mount(fs, drv, 0);
if (res != FR_OK) {
err = ESP_FAIL;
ESP_LOGD(TAG, "f_mount failed after formatting (%d)", res);
return err;
}
}
return ESP_OK;
}
static esp_err_t mount_to_vfs_fat_mh(const esp_vfs_fat_mount_config_t *mount_config, sdmmc_card_t *card, uint8_t pdrv, const char *base_path, FATFS **out_fs)
{
FATFS *fs = NULL;
esp_err_t err;
ff_diskio_register_sdmmc_mh(pdrv, card);
ff_sdmmc_set_disk_status_check_mh(pdrv, mount_config->disk_status_check_enable);
ESP_LOGD(TAG, "using pdrv=%i", pdrv);
char drv[3] = {(char)('0' + pdrv), ':', 0};
// connect FATFS to VFS
err = esp_vfs_fat_register(base_path, drv, mount_config->max_files, &fs);
*out_fs = fs;
if (err == ESP_ERR_INVALID_STATE) {
// it's okay, already registered with VFS
} else if (err != ESP_OK) {
ESP_LOGD(TAG, "esp_vfs_fat_register failed 0x(%x)", err);
goto fail;
}
// Try to mount partition
err = s_f_mount_mh(card, fs, drv, pdrv, mount_config);
if (err != ESP_OK) {
goto fail;
}
return ESP_OK;
fail:
if (fs) {
f_mount(NULL, drv, 0);
}
esp_vfs_fat_unregister_path(base_path);
ff_diskio_unregister(pdrv);
return err;
}
static esp_err_t partition_card_mh(const esp_vfs_fat_mount_config_t *mount_config, const char *drv, sdmmc_card_t *card, BYTE pdrv)
{
FRESULT res = FR_OK;
esp_err_t err;
const size_t workbuf_size = 4096;
void* workbuf = NULL;
ESP_LOGW(TAG, "partitioning card");
workbuf = ff_memalloc(workbuf_size);
if (workbuf == NULL) {
return ESP_ERR_NO_MEM;
}
LBA_t plist[] = {100, 0, 0, 0};
res = f_fdisk(pdrv, plist, workbuf);
if (res != FR_OK) {
err = ESP_FAIL;
ESP_LOGD(TAG, "f_fdisk failed (%d)", res);
goto fail;
}
size_t alloc_unit_size = esp_vfs_fat_get_allocation_unit_size(card->csd.sector_size, mount_config->allocation_unit_size);
ESP_LOGW(TAG, "formatting card, allocation unit size=%d", alloc_unit_size);
const MKFS_PARM opt = {(BYTE)FM_ANY, 0, 0, 0, alloc_unit_size};
res = f_mkfs(drv, &opt, workbuf, workbuf_size);
if (res != FR_OK) {
err = ESP_FAIL;
ESP_LOGD(TAG, "f_mkfs failed (%d)", res);
goto fail;
}
free(workbuf);
return ESP_OK;
fail:
free(workbuf);
return err;
}
#if SOC_SDMMC_HOST_SUPPORTED
static esp_err_t init_sdmmc_host_mh(int slot, const void *slot_config, int *out_slot)
{
*out_slot = slot;
return sdmmc_host_init_slot(slot, (const sdmmc_slot_config_t*) slot_config);
}
esp_err_t esp_vfs_fat_sdmmc_mount_mh(const char* base_path, const sdmmc_host_t* host_config, const void* slot_config, const esp_vfs_fat_mount_config_t* mount_config, sdmmc_card_t** out_card)
{
esp_err_t err;
vfs_fat_sd_ctx_t *ctx = NULL;
uint32_t ctx_id = FF_VOLUMES;
FATFS *fs = NULL;
int card_handle = -1; //uninitialized
sdmmc_card_t* card = NULL;
BYTE pdrv = FF_DRV_NOT_USED;
char* dup_path = NULL;
bool host_inited = false;
err = mount_prepare_mem_mh(base_path, &pdrv, &dup_path, &card);
if (err != ESP_OK) {
ESP_LOGE(TAG, "mount_prepare failed");
return err;
}
err = (*host_config->init)();
CHECK_EXECUTE_RESULT(err, "host init failed");
//deinit() needs to be called to revert the init
host_inited = true;
//If this failed (indicated by card_handle != -1), slot deinit needs to called()
//leave card_handle as is to indicate that (though slot deinit not implemented yet.
err = init_sdmmc_host_mh(host_config->slot, slot_config, &card_handle);
CHECK_EXECUTE_RESULT(err, "slot init failed");
// probe and initialize card
err = sdmmc_card_init(host_config, card);
CHECK_EXECUTE_RESULT(err, "sdmmc_card_init failed");
err = mount_to_vfs_fat_mh(mount_config, card, pdrv, dup_path, &fs);
CHECK_EXECUTE_RESULT(err, "mount_to_vfs failed");
if (out_card != NULL) {
*out_card = card;
}
//For deprecation backward compatibility
if (s_saved_ctx_id == FF_VOLUMES) {
s_saved_ctx_id = 0;
}
ctx = calloc(sizeof(vfs_fat_sd_ctx_t), 1);
if (!ctx) {
CHECK_EXECUTE_RESULT(ESP_ERR_NO_MEM, "no mem");
}
ctx->pdrv = pdrv;
memcpy(&ctx->mount_config, mount_config, sizeof(esp_vfs_fat_mount_config_t));
ctx->card = card;
ctx->base_path = dup_path;
ctx->fs = fs;
ctx_id = s_get_unused_context_id_mh();
assert(ctx_id != FF_VOLUMES);
s_ctx[ctx_id] = ctx;
return ESP_OK;
cleanup:
if (host_inited) {
call_host_deinit_mh(host_config);
}
free(card);
free(dup_path);
return err;
}
#endif
static esp_err_t init_sdspi_host_mh(int slot, const void *slot_config, int *out_slot)
{
esp_err_t err = sdspi_host_init_device((const sdspi_device_config_t*)slot_config, out_slot);
if (err != ESP_OK) {
ESP_LOGE(TAG,
"Failed to attach sdspi device onto an SPI bus (rc=0x%x), please initialize the \
bus first and check the device parameters."
, err);
}
return err;
}
esp_err_t esp_vfs_fat_sdspi_mount_mh(const char* base_path, const sdmmc_host_t* host_config_input, const sdspi_device_config_t* slot_config, const esp_vfs_fat_mount_config_t* mount_config, sdmmc_card_t** out_card)
{
const sdmmc_host_t* host_config = host_config_input;
esp_err_t err;
vfs_fat_sd_ctx_t *ctx = NULL;
uint32_t ctx_id = FF_VOLUMES;
FATFS *fs = NULL;
int card_handle = -1; //uninitialized
bool host_inited = false;
BYTE pdrv = FF_DRV_NOT_USED;
sdmmc_card_t* card = NULL;
char* dup_path = NULL;
err = mount_prepare_mem_mh(base_path, &pdrv, &dup_path, &card);
if (err != ESP_OK) {
ESP_LOGE(TAG, "mount_prepare failed");
return err;
}
//the init() function is usually empty, doesn't require any deinit to revert it
err = (*host_config->init)();
CHECK_EXECUTE_RESULT(err, "host init failed");
err = init_sdspi_host_mh(host_config->slot, slot_config, &card_handle);
CHECK_EXECUTE_RESULT(err, "slot init failed");
//Set `host_inited` to true to indicate that host_config->deinit() needs
//to be called to revert `init_sdspi_host`
host_inited = true;
//The `slot` argument inside host_config should be replaced by the SD SPI handled returned
//above. But the input pointer is const, so create a new variable.
sdmmc_host_t new_config;
if (card_handle != host_config->slot) {
new_config = *host_config_input;
host_config = &new_config;
new_config.slot = card_handle;
}
// probe and initialize card
err = sdmmc_card_init(host_config, card);
CHECK_EXECUTE_RESULT(err, "sdmmc_card_init failed");
err = mount_to_vfs_fat_mh(mount_config, card, pdrv, dup_path, &fs);
CHECK_EXECUTE_RESULT(err, "mount_to_vfs failed");
if (out_card != NULL) {
*out_card = card;
}
//For deprecation backward compatibility
if (s_saved_ctx_id == FF_VOLUMES) {
s_saved_ctx_id = 0;
}
ctx = calloc(sizeof(vfs_fat_sd_ctx_t), 1);
if (!ctx) {
CHECK_EXECUTE_RESULT(ESP_ERR_NO_MEM, "no mem");
}
ctx->pdrv = pdrv;
memcpy(&ctx->mount_config, mount_config, sizeof(esp_vfs_fat_mount_config_t));
ctx->card = card;
ctx->base_path = dup_path;
ctx->fs = fs;
ctx_id = s_get_unused_context_id_mh();
assert(ctx_id != FF_VOLUMES);
s_ctx[ctx_id] = ctx;
return ESP_OK;
cleanup:
if (host_inited) {
call_host_deinit_mh(host_config);
}
free(card);
free(dup_path);
return err;
}
static void call_host_deinit_mh(const sdmmc_host_t *host_config)
{
if (host_config->flags & SDMMC_HOST_FLAG_DEINIT_ARG) {
host_config->deinit_p(host_config->slot);
} else {
host_config->deinit();
}
}
static esp_err_t unmount_card_core_mh(const char *base_path, sdmmc_card_t *card)
{
BYTE pdrv = ff_diskio_get_pdrv_card_mh(card);
if (pdrv == 0xff) {
return ESP_ERR_INVALID_ARG;
}
// unmount
char drv[3] = {(char)('0' + pdrv), ':', 0};
f_mount(0, drv, 0);
// release SD driver
ff_diskio_unregister(pdrv);
call_host_deinit_mh(&card->host);
free(card);
esp_err_t err = esp_vfs_fat_unregister_path(base_path);
return err;
}
esp_err_t esp_vfs_fat_sdmmc_unmount_mh(void)
{
esp_err_t err = unmount_card_core_mh(s_ctx[s_saved_ctx_id]->base_path, s_ctx[s_saved_ctx_id]->card);
free(s_ctx[s_saved_ctx_id]);
s_ctx[s_saved_ctx_id] = NULL;
s_saved_ctx_id = FF_VOLUMES;
return err;
}
esp_err_t esp_vfs_fat_sdcard_unmount_mh(const char *base_path, sdmmc_card_t *card)
{
uint32_t id = FF_VOLUMES;
bool found = s_get_context_id_by_card_mh(card, &id);
if (!found) {
return ESP_ERR_INVALID_ARG;
}
free(s_ctx[id]);
s_ctx[id] = NULL;
esp_err_t err = unmount_card_core_mh(base_path, card);
return err;
}
esp_err_t esp_vfs_fat_sdcard_format_mh(const char *base_path, sdmmc_card_t *card)
{
esp_err_t ret = ESP_OK;
if (!card) {
ESP_LOGE(TAG, "card not initialized");
return ESP_ERR_INVALID_STATE;
}
BYTE pdrv = ff_diskio_get_pdrv_card_mh(card);
if (pdrv == 0xff) {
ESP_LOGE(TAG, "card driver not registered");
return ESP_ERR_INVALID_STATE;
}
const size_t workbuf_size = 4096;
void *workbuf = ff_memalloc(workbuf_size);
if (workbuf == NULL) {
return ESP_ERR_NO_MEM;
}
//unmount
char drv[3] = {(char)('0' + pdrv), ':', 0};
f_mount(0, drv, 0);
//format
uint32_t id = FF_VOLUMES;
bool found = s_get_context_id_by_card_mh(card, &id);
assert(found);
size_t alloc_unit_size = esp_vfs_fat_get_allocation_unit_size(card->csd.sector_size, s_ctx[id]->mount_config.allocation_unit_size);
ESP_LOGI(TAG, "Formatting card, allocation unit size=%d", alloc_unit_size);
const MKFS_PARM opt = {(BYTE)FM_ANY, 0, 0, 0, alloc_unit_size};
FRESULT res = f_mkfs(drv, &opt, workbuf, workbuf_size);
free(workbuf);
if (res != FR_OK) {
ret = ESP_FAIL;
ESP_LOGD(TAG, "f_mkfs failed (%d)", res);
}
//mount back
esp_err_t err = s_f_mount_mh(card, s_ctx[id]->fs, drv, pdrv, &s_ctx[id]->mount_config);
if (err != ESP_OK) {
unmount_card_core_mh(base_path, card);
ESP_LOGE(TAG, "failed to format, resources recycled, please mount again");
}
return ret;
}

View File

@@ -0,0 +1,111 @@
/*
* SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
#pragma once
#include <stddef.h>
#include "esp_err.h"
#include "driver/gpio.h"
#include "sdmmc_cmd.h"
#include "driver/sdmmc_types.h"
#include "driver/sdspi_host.h"
#include "ff.h"
#include "esp_vfs_fat.h"
#include "wear_levelling.h"
#ifdef __cplusplus
extern "C" {
#endif
/**
* @brief Convenience function to get FAT filesystem on SD card registered in VFS
*
* This is an all-in-one function which does the following:
* - initializes SDMMC driver or SPI driver with configuration in host_config
* - initializes SD card with configuration in slot_config
* - mounts FAT partition on SD card using FATFS library, with configuration in mount_config
* - registers FATFS library with VFS, with prefix given by base_prefix variable
*
* This function is intended to make example code more compact.
* For real world applications, developers should implement the logic of
* probing SD card, locating and mounting partition, and registering FATFS in VFS,
* with proper error checking and handling of exceptional conditions.
*
* @note Use this API to mount a card through SDSPI is deprecated. Please call
* `esp_vfs_fat_sdspi_mount()` instead for that case.
*
* @param base_path path where partition should be registered (e.g. "/sdcard")
* @param host_config Pointer to structure describing SDMMC host. When using
* SDMMC peripheral, this structure can be initialized using
* SDMMC_HOST_DEFAULT() macro. When using SPI peripheral,
* this structure can be initialized using SDSPI_HOST_DEFAULT()
* macro.
* @param slot_config Pointer to structure with slot configuration.
* For SDMMC peripheral, pass a pointer to sdmmc_slot_config_t
* structure initialized using SDMMC_SLOT_CONFIG_DEFAULT.
* @param mount_config pointer to structure with extra parameters for mounting FATFS
* @param[out] out_card if not NULL, pointer to the card information structure will be returned via this argument
* @return
* - ESP_OK on success
* - ESP_ERR_INVALID_STATE if esp_vfs_fat_sdmmc_mount was already called
* - ESP_ERR_NO_MEM if memory can not be allocated
* - ESP_FAIL if partition can not be mounted
* - other error codes from SDMMC or SPI drivers, SDMMC protocol, or FATFS drivers
*/
esp_err_t esp_vfs_fat_sdmmc_mount_mh(const char* base_path, const sdmmc_host_t* host_config, const void* slot_config, const esp_vfs_fat_mount_config_t* mount_config, sdmmc_card_t** out_card);
/**
* @brief Convenience function to get FAT filesystem on SD card registered in VFS
*
* This is an all-in-one function which does the following:
* - initializes an SPI Master device based on the SPI Master driver with configuration in
* slot_config, and attach it to an initialized SPI bus.
* - initializes SD card with configuration in host_config_input
* - mounts FAT partition on SD card using FATFS library, with configuration in mount_config
* - registers FATFS library with VFS, with prefix given by base_prefix variable
*
* This function is intended to make example code more compact.
* For real world applications, developers should implement the logic of
* probing SD card, locating and mounting partition, and registering FATFS in VFS,
* with proper error checking and handling of exceptional conditions.
*
* @note This function try to attach the new SD SPI device to the bus specified in host_config.
* Make sure the SPI bus specified in `host_config->slot` have been initialized by
* `spi_bus_initialize()` before.
*
* @param base_path path where partition should be registered (e.g. "/sdcard")
* @param host_config_input Pointer to structure describing SDMMC host. This structure can be
* initialized using SDSPI_HOST_DEFAULT() macro.
* @param slot_config Pointer to structure with slot configuration.
* For SPI peripheral, pass a pointer to sdspi_device_config_t
* structure initialized using SDSPI_DEVICE_CONFIG_DEFAULT().
* @param mount_config pointer to structure with extra parameters for mounting FATFS
* @param[out] out_card If not NULL, pointer to the card information structure will be returned via
* this argument. It is suggested to hold this handle and use it to unmount the card later if
* needed. Otherwise it's not suggested to use more than one card at the same time and unmount one
* of them in your application.
* @return
* - ESP_OK on success
* - ESP_ERR_INVALID_STATE if esp_vfs_fat_sdmmc_mount was already called
* - ESP_ERR_NO_MEM if memory can not be allocated
* - ESP_FAIL if partition can not be mounted
* - other error codes from SDMMC or SPI drivers, SDMMC protocol, or FATFS drivers
*/
esp_err_t esp_vfs_fat_sdspi_mount_mh(const char* base_path, const sdmmc_host_t* host_config_input, const sdspi_device_config_t* slot_config, const esp_vfs_fat_mount_config_t* mount_config, sdmmc_card_t** out_card);
#ifdef __cplusplus
}
#endif

View File

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

View File

@@ -5,6 +5,7 @@
#include <time.h>
#include "ClassLogFile.h"
#include "esp_http_client.h"
#include "time_sntp.h"
#include "../../include/defines.h"
@@ -16,21 +17,21 @@ std::string _influxDBUser;
std::string _influxDBPassword;
std::string _influxDB_V2_URI;
std::string _influxDB_V2_Database;
std::string _influxDB_V2_Bucket;
std::string _influxDB_V2_Token;
std::string _influxDB_V2_Org;
static esp_err_t http_event_handler(esp_http_client_event_t *evt);
void InfluxDB_V2_Init(std::string _uri, std::string _database, std::string _org, std::string _token)
void InfluxDB_V2_Init(std::string _uri, std::string _bucket, std::string _org, std::string _token)
{
_influxDB_V2_URI = _uri;
_influxDB_V2_Database = _database;
_influxDB_V2_Bucket = _bucket;
_influxDB_V2_Org = _org;
_influxDB_V2_Token = _token;
}
void InfluxDB_V2_Publish(std::string _measurement, std::string _key, std::string _content, std::string _timestamp)
void InfluxDB_V2_Publish(std::string _measurement, std::string _key, std::string _content, long int _timeUTC)
{
char response_buffer[MAX_HTTP_OUTPUT_BUFFER] = {0};
esp_http_client_config_t http_config = {
@@ -41,32 +42,20 @@ void InfluxDB_V2_Publish(std::string _measurement, std::string _key, std::string
.user_data = response_buffer
};
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "InfluxDB_V2_Publish - Key: " + _key + ", Content: " + _content + ", Timestamp: " + _timestamp);
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "InfluxDB_V2_Publish - Key: " + _key + ", Content: " + _content + ", timeUTC: " + std::to_string(_timeUTC));
std::string payload;
char nowTimestamp[21];
if (_timestamp.length() > 0)
if (_timeUTC > 0)
{
struct tm tm;
strptime(_timestamp.c_str(), PREVALUE_TIME_FORMAT_OUTPUT, &tm);
time_t t = mktime(&tm); // Time in Localtime (looks like timezone is not used by strptime)
// struct tm * ptm;
// ptm = gmtime ( &t );
// time_t utc = mktime(ptm);
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Use handover timestamp: " + _timestamp + " converted GMT timestamp: " + std::to_string(t));
// utc = 2*t - utc; // Take care of timezone (looks difficult, but is easy: t = t + (t - utc), weil t-utc = timezone)
// LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "time conversion utc after: " + std::to_string(utc));
sprintf(nowTimestamp,"%ld000000000", (long) t); // UTC
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Timestamp (UTC): " + std::to_string(_timeUTC));
sprintf(nowTimestamp,"%ld000000000", _timeUTC); // UTC
payload = _measurement + " " + _key + "=" + _content + " " + nowTimestamp;
}
else
{
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "no timestamp given");
payload = _measurement + " " + _key + "=" + _content;
}
@@ -74,7 +63,7 @@ void InfluxDB_V2_Publish(std::string _measurement, std::string _key, std::string
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "sending line to influxdb:" + payload);
std::string apiURI = _influxDB_V2_URI + "/api/v2/write?org=" + _influxDB_V2_Org + "&bucket=" + _influxDB_V2_Database;
std::string apiURI = _influxDB_V2_URI + "/api/v2/write?org=" + _influxDB_V2_Org + "&bucket=" + _influxDB_V2_Bucket;
apiURI.shrink_to_fit();
http_config.url = apiURI.c_str();
ESP_LOGI(TAG, "http_config: %s", http_config.url); // Add mark on log to see when it restarted
@@ -116,7 +105,7 @@ static esp_err_t http_event_handler(esp_http_client_event_t *evt)
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "HTTP Client Error encountered");
break;
case HTTP_EVENT_ON_CONNECTED:
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "HTTP Client Error encountered");
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "HTTP Client connected");
ESP_LOGI(TAG, "HTTP Client Connected");
break;
case HTTP_EVENT_HEADERS_SENT:
@@ -141,7 +130,7 @@ static esp_err_t http_event_handler(esp_http_client_event_t *evt)
return ESP_OK;
}
void InfluxDBPublish(std::string _measurement, std::string _key, std::string _content, std::string _timestamp) {
void InfluxDBPublish(std::string _measurement, std::string _key, std::string _content, long int _timeUTC) {
char response_buffer[MAX_HTTP_OUTPUT_BUFFER] = {0};
esp_http_client_config_t http_config = {
.user_agent = "ESP32 Meter reader",
@@ -160,29 +149,17 @@ void InfluxDBPublish(std::string _measurement, std::string _key, std::string _co
std::string payload;
char nowTimestamp[21];
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "InfluxDBPublish - Key: " + _key + ", Content: " + _content + ", Timestamp: " + _timestamp);
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "InfluxDBPublish - Key: " + _key + ", Content: " + _content + ", timeUTC: " + std::to_string(_timeUTC));
if (_timestamp.length() > 0)
if (_timeUTC > 0)
{
struct tm tm;
strptime(_timestamp.c_str(), PREVALUE_TIME_FORMAT_OUTPUT, &tm);
time_t t = mktime(&tm); // Time in Localtime (looks like timezone is not used by strptime)
// struct tm * ptm;
// ptm = gmtime ( &t );
// time_t utc = mktime(ptm);
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Use handover timestamp: " + _timestamp + " converted GMT timestamp: " + std::to_string(t));
// utc = 2*t - utc; // Take care of timezone (looks difficult, but is easy: t = t + (t - utc), weil t-utc = timezone)
// LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "time conversion utc after: " + std::to_string(utc));
sprintf(nowTimestamp,"%ld000000000", (long) t); // UTC
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Timestamp (UTC): " + std::to_string(_timeUTC));
sprintf(nowTimestamp,"%ld000000000", _timeUTC); // UTC
payload = _measurement + " " + _key + "=" + _content + " " + nowTimestamp;
}
else
{
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "no timestamp given");
payload = _measurement + " " + _key + "=" + _content;
}
@@ -191,7 +168,7 @@ void InfluxDBPublish(std::string _measurement, std::string _key, std::string _co
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "sending line to influxdb:" + payload);
// use the default retention policy of the database
// use the default retention policy of the bucket
std::string apiURI = _influxDBURI + "/write?db=" + _influxDBDatabase;
// std::string apiURI = _influxDBURI + "/api/v2/write?bucket=" + _influxDBDatabase + "/";

View File

@@ -10,11 +10,11 @@
// Interface to InfluxDB v1.x
void InfluxDBInit(std::string _influxDBURI, std::string _database, std::string _user, std::string _password);
void InfluxDBPublish(std::string _measurement, std::string _key, std::string _content, std::string _timestamp);
void InfluxDBPublish(std::string _measurement, std::string _key, std::string _content, long int _timeUTC);
// Interface to InfluxDB v2.x
void InfluxDB_V2_Init(std::string _uri, std::string _database, std::string _org, std::string _token);
void InfluxDB_V2_Publish(std::string _measurement, std::string _key, std::string _content, std::string _timestamp);
void InfluxDB_V2_Init(std::string _uri, std::string _bucket, std::string _org, std::string _token);
void InfluxDB_V2_Publish(std::string _measurement, std::string _key, std::string _content, long int _timeUTC);

View File

@@ -2,4 +2,4 @@ FILE(GLOB_RECURSE app_sources ${CMAKE_CURRENT_SOURCE_DIR}/*.*)
idf_component_register(SRCS ${app_sources}
INCLUDE_DIRS "."
REQUIRES esp_timer tflite-lib mqtt jomjol_tfliteclass jomjol_helper jomjol_mqtt jomjol_wlan json)
REQUIRES esp_timer esp-tflite-micro mqtt jomjol_tfliteclass jomjol_helper jomjol_mqtt jomjol_wlan json)

View File

@@ -2,6 +2,9 @@
#include "interface_mqtt.h"
#include "esp_log.h"
#if DEBUG_DETAIL_ON
#include "esp_timer.h"
#endif
#include "connect_wlan.h"
#include "mqtt_client.h"
#include "ClassLogFile.h"
@@ -9,6 +12,11 @@
#include "cJSON.h"
#include "../../include/defines.h"
#if DEBUG_DETAIL_ON
#include "esp_timer.h"
#endif
static const char *TAG = "MQTT IF";
std::map<std::string, std::function<void()>>* connectFunktionMap = NULL;
@@ -27,6 +35,7 @@ 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;
std::string caCert, clientCert, clientKey;
int keepalive;
bool SetRetainFlag;
void (*callbackOnConnected)(std::string, bool) = NULL;
@@ -54,7 +63,7 @@ bool MQTTPublish(std::string _key, std::string _content, int qos, bool retained_
#endif
int msg_id = esp_mqtt_client_publish(client, _key.c_str(), _content.c_str(), 0, qos, retained_flag);
#ifdef DEBUG_DETAIL_ON
ESP_LOGD(TAG, "Publish msg_id %d in %lld ms", msg_id, (esp_timer_get_time() - starttime)/1000);
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Publish msg_id " + std::to_string(msg_id) + " in " + std::to_string((esp_timer_get_time() - starttime)/1000) + " ms");
#endif
if (msg_id == -1) {
LogFile.WriteToFile(ESP_LOG_WARN, TAG, "Failed to publish topic '" + _key + "', re-trying...");
@@ -63,7 +72,7 @@ bool MQTTPublish(std::string _key, std::string _content, int qos, bool retained_
#endif
msg_id = esp_mqtt_client_publish(client, _key.c_str(), _content.c_str(), 0, qos, retained_flag);
#ifdef DEBUG_DETAIL_ON
ESP_LOGD(TAG, "Publish msg_id %d in %lld ms", msg_id, (esp_timer_get_time() - starttime)/1000);
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Publish msg_id " + std::to_string(msg_id) + " in " + std::to_string((esp_timer_get_time() - starttime)/1000) + " ms");
#endif
if (msg_id == -1) {
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Failed to publish topic '" + _key + "', skipping all MQTT publishings in this round!");
@@ -113,29 +122,32 @@ static esp_err_t mqtt_event_handler_cb(esp_mqtt_event_handle_t event) {
break;
case MQTT_EVENT_SUBSCRIBED:
ESP_LOGD(TAG, "MQTT_EVENT_SUBSCRIBED, msg_id=%d", event->msg_id);
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "MQTT_EVENT_SUBSCRIBED, msg_id=" + std::to_string(event->msg_id));
break;
case MQTT_EVENT_UNSUBSCRIBED:
ESP_LOGD(TAG, "MQTT_EVENT_UNSUBSCRIBED, msg_id=%d", event->msg_id);
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "MQTT_EVENT_UNSUBSCRIBED, msg_id=" + std::to_string(event->msg_id));
break;
case MQTT_EVENT_PUBLISHED:
ESP_LOGD(TAG, "MQTT_EVENT_PUBLISHED, msg_id=%d", event->msg_id);
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "MQTT_EVENT_PUBLISHED, msg_id=" + std::to_string(event->msg_id));
break;
case MQTT_EVENT_DATA:
ESP_LOGD(TAG, "MQTT_EVENT_DATA");
ESP_LOGD(TAG, "TOPIC=%.*s", event->topic_len, event->topic);
ESP_LOGD(TAG, "DATA=%.*s", event->data_len, event->data);
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "MQTT_EVENT_DATA");
char buf[100];
snprintf(buf, sizeof(buf), "%.*s", event->topic_len, event->topic);
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "TOPIC=" + std::string(buf));
snprintf(buf, sizeof(buf), "%.*s", event->data_len, event->data);
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "DATA=" + std::string(buf));
topic.assign(event->topic, event->topic_len);
if (subscribeFunktionMap != NULL) {
if (subscribeFunktionMap->find(topic) != subscribeFunktionMap->end()) {
ESP_LOGD(TAG, "call subcribe function for topic %s", topic.c_str());
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "call subcribe function for topic " + topic);
(*subscribeFunktionMap)[topic](topic, event->data, event->data_len);
}
} else {
ESP_LOGW(TAG, "no handler available\r\n");
LogFile.WriteToFile(ESP_LOG_WARN, TAG, "no handler available!");
}
break;
@@ -164,21 +176,24 @@ static esp_err_t mqtt_event_handler_cb(esp_mqtt_event_handle_t event) {
else if (event->error_handle->connect_return_code == MQTT_CONNECTION_REFUSE_NOT_AUTHORIZED) {
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Connection refused, not authorized. Check username/password (0x05)");
}
else {
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Other event id: " + std::to_string(event->error_handle->connect_return_code));
}
#ifdef DEBUG_DETAIL_ON
ESP_LOGD(TAG, "MQTT_EVENT_ERROR - esp_mqtt_error_codes:");
ESP_LOGD(TAG, "error_type:%d", event->error_handle->error_type);
ESP_LOGD(TAG, "connect_return_code:%d", event->error_handle->connect_return_code);
ESP_LOGD(TAG, "esp_transport_sock_errno:%d", event->error_handle->esp_transport_sock_errno);
ESP_LOGD(TAG, "esp_tls_last_esp_err:%d", event->error_handle->esp_tls_last_esp_err);
ESP_LOGD(TAG, "esp_tls_stack_err:%d", event->error_handle->esp_tls_stack_err);
ESP_LOGD(TAG, "esp_tls_cert_verify_flags:%d", event->error_handle->esp_tls_cert_verify_flags);
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "MQTT_EVENT_ERROR - esp_mqtt_error_codes:");
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "error_type: " + std::to_string(event->error_handle->error_type));
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "connect_return_code: " + std::to_string(event->error_handle->connect_return_code));
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "esp_transport_sock_errno: " + std::to_string(event->error_handle->esp_transport_sock_errno));
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "esp_tls_last_esp_err: " + std::to_string(event->error_handle->esp_tls_last_esp_err));
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "esp_tls_stack_err: " + std::to_string(event->error_handle->esp_tls_stack_err));
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "esp_tls_cert_verify_flags: " + std::to_string(event->error_handle->esp_tls_cert_verify_flags));
#endif
break;
default:
ESP_LOGD(TAG, "Other event id:%d", event->event_id);
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Other event id: " + std::to_string(event->event_id));
break;
}
return ESP_OK;
@@ -186,13 +201,14 @@ static esp_err_t mqtt_event_handler_cb(esp_mqtt_event_handle_t event) {
static void mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data) {
ESP_LOGD(TAG, "Event dispatched from event loop base=%s, event_id=%d", base, (int)event_id);
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Event dispatched from event loop base=" + std::string(base) + ", event_id=" + std::to_string(event_id));
mqtt_event_handler_cb((esp_mqtt_event_handle_t) event_data);
}
bool MQTT_Configure(std::string _mqttURI, std::string _clientid, std::string _user, std::string _password,
std::string _maintopic, std::string _lwt, std::string _lwt_connected, std::string _lwt_disconnected,
std::string _cacertfilename, std::string _clientcertfilename, std::string _clientkeyfilename,
int _keepalive, bool _SetRetainFlag, void *_callbackOnConnected) {
if ((_mqttURI.length() == 0) || (_maintopic.length() == 0) || (_clientid.length() == 0))
{
@@ -210,6 +226,25 @@ bool MQTT_Configure(std::string _mqttURI, std::string _clientid, std::string _us
maintopic = _maintopic;
callbackOnConnected = ( void (*)(std::string, bool) )(_callbackOnConnected);
if (_clientcertfilename.length() && _clientkeyfilename.length()){
std::ifstream cert_ifs(_clientcertfilename);
std::string cert_content((std::istreambuf_iterator<char>(cert_ifs)), (std::istreambuf_iterator<char>()));
clientCert = cert_content;
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "using clientCert: " + _clientcertfilename);
std::ifstream key_ifs(_clientkeyfilename);
std::string key_content((std::istreambuf_iterator<char>(key_ifs)), (std::istreambuf_iterator<char>()));
clientKey = key_content;
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "using clientKey: " + _clientkeyfilename);
}
if (_cacertfilename.length() ){
std::ifstream ifs(_cacertfilename);
std::string content((std::istreambuf_iterator<char>(ifs)), (std::istreambuf_iterator<char>()));
caCert = content;
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "using caCert: " + _cacertfilename);
}
if (_user.length() && _password.length()){
user = _user;
password = _password;
@@ -263,6 +298,20 @@ int MQTT_Init() {
mqtt_cfg.session.keepalive = keepalive;
mqtt_cfg.buffer.size = 1536; // size of MQTT send/receive buffer (Default: 1024)
if (caCert.length()){
mqtt_cfg.broker.verification.certificate = caCert.c_str();
mqtt_cfg.broker.verification.certificate_len = caCert.length() + 1;
mqtt_cfg.broker.verification.skip_cert_common_name_check = true;
}
if (clientCert.length() && clientKey.length()){
mqtt_cfg.credentials.authentication.certificate = clientCert.c_str();
mqtt_cfg.credentials.authentication.certificate_len = clientCert.length() + 1;
mqtt_cfg.credentials.authentication.key = clientKey.c_str();
mqtt_cfg.credentials.authentication.key_len = clientKey.length() + 1;
}
if (user.length() && password.length()){
mqtt_cfg.credentials.username = user.c_str();
mqtt_cfg.credentials.authentication.password = password.c_str();
@@ -339,7 +388,7 @@ bool getMQTTisConnected() {
bool mqtt_handler_flow_start(std::string _topic, char* _data, int _data_len)
{
ESP_LOGD(TAG, "Handler called: topic %s, data %.*s", _topic.c_str(), _data_len, _data);
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Handler called: topic='" + _topic + "', data='" + _data +"'");
if (_data_len > 0) {
MQTTCtrlFlowStart(_topic);
@@ -354,7 +403,7 @@ bool mqtt_handler_flow_start(std::string _topic, char* _data, int _data_len)
bool mqtt_handler_set_prevalue(std::string _topic, char* _data, int _data_len)
{
//ESP_LOGD(TAG, "Handler called: topic %s, data %.*s", _topic.c_str(), _data_len, _data);
//LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Handler called: topic='" + _topic + "', data='" + _data +"'");
//example: {"numbersname": "main", "value": 12345.1234567}
if (_data_len > 0) { // Check if data length > 0
@@ -366,8 +415,10 @@ bool mqtt_handler_set_prevalue(std::string _topic, char* _data, int _data_len)
if (cJSON_IsNumber(value)) { // Check if value is a number
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "handler_set_prevalue called: numbersname: " + std::string(numbersname->valuestring) +
", value: " + std::to_string(value->valuedouble));
if (flowctrl.UpdatePrevalue(std::to_string(value->valuedouble), std::string(numbersname->valuestring), true))
if (flowctrl.UpdatePrevalue(std::to_string(value->valuedouble), std::string(numbersname->valuestring), true)) {
cJSON_Delete(jsonData);
return ESP_OK;
}
}
else {
LogFile.WriteToFile(ESP_LOG_WARN, TAG, "handler_set_prevalue: value not a valid number (\"value\": 12345.12345)");
@@ -376,6 +427,7 @@ bool mqtt_handler_set_prevalue(std::string _topic, char* _data, int _data_len)
else {
LogFile.WriteToFile(ESP_LOG_WARN, TAG, "handler_set_prevalue: numbersname not a valid string (\"numbersname\": \"main\")");
}
cJSON_Delete(jsonData);
}
else {
LogFile.WriteToFile(ESP_LOG_WARN, TAG, "handler_set_prevalue: handler called, but no data received");
@@ -392,7 +444,7 @@ void MQTTconnected(){
if (connectFunktionMap != NULL) {
for(std::map<std::string, std::function<void()>>::iterator it = connectFunktionMap->begin(); it != connectFunktionMap->end(); ++it) {
it->second();
ESP_LOGD(TAG, "call connect function %s", it->first.c_str());
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "call connect function '" + it->first + "'");
}
}
@@ -421,13 +473,13 @@ void MQTTconnected(){
void MQTTregisterConnectFunction(std::string name, std::function<void()> func){
ESP_LOGD(TAG, "MQTTregisteronnectFunction %s\r\n", name.c_str());
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "MQTTregisteronnectFunction " + name);
if (connectFunktionMap == NULL) {
connectFunktionMap = new std::map<std::string, std::function<void()>>();
}
if ((*connectFunktionMap)[name] != NULL) {
ESP_LOGW(TAG, "connect function %s already registred", name.c_str());
LogFile.WriteToFile(ESP_LOG_WARN, TAG, "connect function '" + name + "' already registred!");
return;
}
@@ -440,7 +492,7 @@ void MQTTregisterConnectFunction(std::string name, std::function<void()> func){
void MQTTunregisterConnectFunction(std::string name){
ESP_LOGD(TAG, "unregisterConnnectFunction %s\r\n", name.c_str());
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "unregisterConnnectFunction '" + name + "'");
if ((connectFunktionMap != NULL) && (connectFunktionMap->find(name) != connectFunktionMap->end())) {
connectFunktionMap->erase(name);
}
@@ -448,13 +500,13 @@ void MQTTunregisterConnectFunction(std::string name){
void MQTTregisterSubscribeFunction(std::string topic, std::function<bool(std::string, char*, int)> func){
ESP_LOGD(TAG, "registerSubscribeFunction %s", topic.c_str());
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "registerSubscribeFunction '" + topic + "'");
if (subscribeFunktionMap == NULL) {
subscribeFunktionMap = new std::map<std::string, std::function<bool(std::string, char*, int)>>();
}
if ((*subscribeFunktionMap)[topic] != NULL) {
ESP_LOGW(TAG, "topic %s already registered for subscription", topic.c_str());
LogFile.WriteToFile(ESP_LOG_WARN, TAG, "topic '" + topic + "' already registered for subscription!");
return;
}
@@ -467,7 +519,7 @@ void MQTTdestroySubscribeFunction(){
if (mqtt_connected) {
for(std::map<std::string, std::function<bool(std::string, char*, int)>>::iterator it = subscribeFunktionMap->begin(); it != subscribeFunktionMap->end(); ++it) {
int msg_id = esp_mqtt_client_unsubscribe(client, it->first.c_str());
ESP_LOGD(TAG, "topic %s unsubscribe successful, msg_id=%d", it->first.c_str(), msg_id);
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "topic '" + it->first + "' unsubscribe successful, msg_id=" + std::to_string(msg_id));
}
}

View File

@@ -11,6 +11,7 @@
bool MQTT_Configure(std::string _mqttURI, std::string _clientid, std::string _user, std::string _password,
std::string _maintopic, std::string _lwt, std::string _lwt_connected, std::string _lwt_disconnected,
std::string _cacertfilename, std::string _clientcertfilename, std::string _clientkeyfilename,
int _keepalive, bool SetRetainFlag, void *callbackOnConnected);
int MQTT_Init();
void MQTTdestroy_client(bool _disable);

View File

@@ -21,6 +21,7 @@ static const char *TAG = "MQTT SERVER";
extern const char* libfive_git_version(void);
extern const char* libfive_git_revision(void);
extern const char* libfive_git_branch(void);
extern std::string getFwVersion(void);
std::vector<NumberPost*>* NUMBERS;
bool HomeassistantDiscovery = false;
@@ -151,6 +152,7 @@ bool MQTThomeassistantDiscovery(int qos) {
// Group | Field | User Friendly Name | Icon | Unit | Device Class | State Class | Entity Category
allSendsSuccessed |= sendHomeAssistantDiscoveryTopic("", "uptime", "Uptime", "clock-time-eight-outline", "s", "", "", "diagnostic", qos);
allSendsSuccessed |= sendHomeAssistantDiscoveryTopic("", "MAC", "MAC Address", "network-outline", "", "", "", "diagnostic", qos);
allSendsSuccessed |= sendHomeAssistantDiscoveryTopic("", "fwVersion", "Firmware Version", "application-outline", "", "", "", "diagnostic", qos);
allSendsSuccessed |= sendHomeAssistantDiscoveryTopic("", "hostname", "Hostname", "network-outline", "", "", "", "diagnostic", qos);
allSendsSuccessed |= sendHomeAssistantDiscoveryTopic("", "freeMem", "Free Memory", "memory", "B", "", "measurement", "diagnostic", qos);
allSendsSuccessed |= sendHomeAssistantDiscoveryTopic("", "wifiRSSI", "Wi-Fi RSSI", "wifi", "dBm", "signal_strength", "", "diagnostic", qos);
@@ -244,6 +246,7 @@ bool publishStaticData(int qos) {
int aFreeInternalHeapSizeBefore = heap_caps_get_free_size(MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL);
allSendsSuccessed |= MQTTPublish(maintopic + "/" + "fwVersion", getFwVersion().c_str(), qos, retainFlag);
allSendsSuccessed |= MQTTPublish(maintopic + "/" + "MAC", getMac(), qos, retainFlag);
allSendsSuccessed |= MQTTPublish(maintopic + "/" + "IP", *getIPAddress(), qos, retainFlag);
allSendsSuccessed |= MQTTPublish(maintopic + "/" + "hostname", wlan_config.hostname, qos, retainFlag);

View File

@@ -12,6 +12,22 @@
static const char *TAG = "TFLITE";
void CTfLiteClass::MakeStaticResolver()
{
resolver.AddFullyConnected();
resolver.AddReshape();
resolver.AddSoftmax();
resolver.AddConv2D();
resolver.AddMaxPool2D();
resolver.AddQuantize();
resolver.AddMul();
resolver.AddAdd();
resolver.AddLeakyRelu();
resolver.AddDequantize();
}
float CTfLiteClass::GetOutputValue(int nr)
{
TfLiteTensor* output2 = this->interpreter->output(0);
@@ -179,22 +195,22 @@ bool CTfLiteClass::LoadInputImageBasis(CImageBasis *rs)
}
bool CTfLiteClass::MakeAllocate()
{
static tflite::AllOpsResolver resolver;
MakeStaticResolver();
#ifdef DEBUG_DETAIL_ON
LogFile.WriteHeapInfo("CTLiteClass::Alloc start");
#endif
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "CTfLiteClass::MakeAllocate");
this->interpreter = new tflite::MicroInterpreter(this->model, resolver, this->tensor_arena, this->kTensorArenaSize, this->error_reporter);
this->interpreter = new tflite::MicroInterpreter(this->model, resolver, this->tensor_arena, this->kTensorArenaSize);
if (this->interpreter)
{
TfLiteStatus allocate_status = this->interpreter->AllocateTensors();
if (allocate_status != kTfLiteOk) {
TF_LITE_REPORT_ERROR(error_reporter, "AllocateTensors() failed");
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "AllocateTensors() failed");
this->GetInputDimension();
@@ -284,12 +300,6 @@ bool CTfLiteClass::ReadFileToModel(std::string _fn)
bool CTfLiteClass::LoadModel(std::string _fn)
{
#ifdef SUPRESS_TFLITE_ERRORS
this->error_reporter = new tflite::OwnMicroErrorReporter;
#else
this->error_reporter = new tflite::MicroErrorReporter;
#endif
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "CTfLiteClass::LoadModel");
if (!ReadFileToModel(_fn.c_str())) {
@@ -320,16 +330,6 @@ CTfLiteClass::CTfLiteClass()
CTfLiteClass::~CTfLiteClass()
{
delete this->interpreter;
delete this->error_reporter;
psram_free_shared_tensor_arena_and_model_memory();
}
namespace tflite
{
int OwnMicroErrorReporter::Report(const char* format, va_list args)
{
return 0;
}
}

View File

@@ -3,38 +3,23 @@
#ifndef CTFLITECLASS_H
#define CTFLITECLASS_H
#include "tensorflow/lite/micro/all_ops_resolver.h"
#include "tensorflow/lite/micro/micro_error_reporter.h"
#include "tensorflow/lite/micro/micro_mutable_op_resolver.h"
#include "tensorflow/lite/micro/micro_interpreter.h"
#include "tensorflow/lite/schema/schema_generated.h"
#include "tensorflow/lite/micro/kernels/micro_ops.h"
#include "esp_err.h"
#include "esp_log.h"
#include "CImageBasis.h"
#ifdef SUPRESS_TFLITE_ERRORS
#include "tensorflow/lite/core/api/error_reporter.h"
#include "tensorflow/lite/micro/compatibility.h"
#include "tensorflow/lite/micro/debug_log.h"
///// OwnErrorReporter to prevent printing of Errors (especially unavoidable in CalculateActivationRangeQuantized@kerne_util.cc)
namespace tflite {
class OwnMicroErrorReporter : public ErrorReporter {
public:
int Report(const char* format, va_list args) override;
};
} // namespace tflite
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#endif
class CTfLiteClass
{
protected:
tflite::ErrorReporter *error_reporter;
tflite::MicroMutableOpResolver<10> resolver;
const tflite::Model* model;
tflite::MicroInterpreter* interpreter;
TfLiteTensor* output = nullptr;
static tflite::AllOpsResolver resolver;
int kTensorArenaSize;
uint8_t *tensor_arena;
@@ -48,6 +33,7 @@ class CTfLiteClass
long GetFileSize(std::string filename);
bool ReadFileToModel(std::string _fn);
void MakeStaticResolver();
public:
CTfLiteClass();

View File

@@ -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 jomjol_configfile)
REQUIRES esp_netif esp-tflite-micro jomjol_logfile jomjol_configfile)

View File

@@ -10,7 +10,8 @@
#include "esp_log.h"
#include "esp_attr.h"
#include "esp_sleep.h"
#include "esp_sntp.h"
#include "esp_netif_sntp.h"
#include "../../include/defines.h"
#include "ClassLogFile.h"
@@ -31,6 +32,9 @@ std::string getNtpStatusText(sntp_sync_status_t status);
static void setTimeZone(std::string _tzstring);
static std::string getServerName(void);
int LocalTimeToUTCOffsetSeconds;
std::string ConvertTimeToString(time_t _time, const char * frm)
{
@@ -89,15 +93,51 @@ bool time_manual_reset_sync(void)
}
int getUTCOffsetSeconds(std::string &zeitzone)
{
int offset = 0;
int vorzeichen = 1;
int minuten = 0;
int stunden = 0;
time_t now;
struct tm timeinfo;
time (&now);
localtime_r(&now, &timeinfo);
char buffer[80];
strftime(buffer, 80, "%z", &timeinfo);
zeitzone = std::string(buffer);
if (zeitzone.length() == 5)
{
if (zeitzone[0] == '-')
vorzeichen = -1;
stunden = stoi(zeitzone.substr(1, 2));
minuten = stoi(zeitzone.substr(3, 2));
offset = ((stunden * 60) + minuten) * 60;
}
return offset;
}
void setTimeZone(std::string _tzstring)
{
setenv("TZ", _tzstring.c_str(), 1);
tzset();
_tzstring = "Time zone set to " + _tzstring;
LogFile.WriteToFile(ESP_LOG_INFO, TAG, _tzstring);
std::string zeitzone;
LocalTimeToUTCOffsetSeconds = getUTCOffsetSeconds(zeitzone);
// std::string zw = std::to_string(LocalTimeToUTCOffsetSeconds);
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "time zone: " + zeitzone + " Delta to UTC: " + std::to_string(LocalTimeToUTCOffsetSeconds) + " seconds");
}
std::string getNtpStatusText(sntp_sync_status_t status) {
if (status == SNTP_SYNC_STATUS_COMPLETED) {
return "Synchronized";
@@ -235,21 +275,13 @@ bool setupTime() {
if (useNtp) {
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Configuring NTP Client...");
sntp_setoperatingmode(SNTP_OPMODE_POLL);
sntp_setservername(0, timeServer.c_str());
sntp_set_time_sync_notification_cb(time_sync_notification_cb);
esp_sntp_config_t config = ESP_NETIF_SNTP_DEFAULT_CONFIG(timeServer.c_str());
config.sync_cb = time_sync_notification_cb;
esp_netif_sntp_init(&config);
setTimeZone(timeZone);
sntp_init();
/*
if (!wait_for_timesync())
{
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Timesync at startup failed.");
}
*/
}
/* The RTC keeps the time after a restart (Except on Power On or Pin Reset)
* There should only be a minor correction through NTP */
@@ -258,6 +290,7 @@ bool setupTime() {
localtime_r(&now, &timeinfo);
strftime(strftime_buf, sizeof(strftime_buf), "%Y-%m-%d %H:%M:%S", &timeinfo);
if (getTimeIsSet()) {
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Time is already set: " + std::string(strftime_buf));
}

View File

@@ -28,5 +28,7 @@ bool setupTime();
bool time_manual_reset_sync(void);
extern int LocalTimeToUTCOffsetSeconds;
#endif //TIMESNTP_H

View File

@@ -378,7 +378,7 @@ void wifi_scan(void)
else {
if (esp_wifi_scan_get_ap_records(&max_number_of_ap_found, wifi_ap_records) != ESP_OK) { // Retrieve results (and free internal heap)
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "wifi_scan: esp_wifi_scan_get_ap_records: Error retrieving datasets");
delete wifi_ap_records;
delete[] wifi_ap_records;
return;
}
}
@@ -401,7 +401,7 @@ void wifi_scan(void)
APWithBetterRSSI = true;
}
}
delete wifi_ap_records;
delete[] wifi_ap_records;
}

View File

@@ -174,10 +174,12 @@ int LoadWlanFromFile(std::string fn)
}
/* Check if password is empty (mandatory parameter) */
/* Disabled see issue #2393
if (wlan_config.password.empty()) {
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Password empty. Device init aborted!");
return -2;
}
*/
return 0;
}

View File

@@ -1,3 +1,3 @@
manifest_hash: 63f5c6c9f0bcebc7b9ca12d2aa8b26b2c5f5218d377dc4b2375d9b9ca1df7815
target: esp32
version: 1.0.0
version: 1.0.0

View File

@@ -53,7 +53,7 @@
//****************************************
//compiler optimization for tflite-micro-esp-examples
//compiler optimization for esp-tflite-micro
#define XTENSA
//#define CONFIG_IDF_TARGET_ARCH_XTENSA //not needed with platformio/espressif32 @ 5.2.0
@@ -167,15 +167,6 @@
#define LWT_DISCONNECTED "connection lost"
//CTfLiteClass
#define TFLITE_MINIMAL_CHECK(x) \
if (!(x)) { \
fprintf(stderr, "Error at %s:%d\n", __FILE__, __LINE__); \
exit(1); \
}
#define SUPRESS_TFLITE_ERRORS // use, to avoid error messages from TFLITE
// connect_wlan.cpp
//******************************
/* WIFI roaming functionalities 802.11k+v (uses ca. 6kB - 8kB internal RAM; if SCAN CACHE activated: + 1kB / beacon)

View File

@@ -3,12 +3,6 @@
#include <vector>
#include <regex>
//#include "freertos/FreeRTOS.h"
//#include "freertos/task.h"
//#include "freertos/event_groups.h"
//#include "driver/gpio.h"
//#include "sdkconfig.h"
#include "esp_psram.h"
#include "esp_pm.h"
@@ -16,17 +10,13 @@
#include "esp_chip_info.h"
// SD-Card ////////////////////
//#include "nvs_flash.h"
#include "sdcard_init.h"
#include "esp_vfs_fat.h"
//#include "sdmmc_cmd.h"
#include "ffconf.h"
#include "driver/sdmmc_host.h"
//#include "driver/sdmmc_defs.h"
///////////////////////////////
#include "ClassLogFile.h"
#include "connect_wlan.h"
@@ -38,7 +28,6 @@
#include "server_ota.h"
#include "time_sntp.h"
#include "configFile.h"
//#include "ClassControllCamera.h"
#include "server_main.h"
#include "server_camera.h"
#ifdef ENABLE_MQTT
@@ -49,7 +38,6 @@
#include "sdcard_check.h"
#include "../../include/defines.h"
//#include "server_GPIO.h"
#ifdef ENABLE_SOFTAP
#include "softAP.h"
@@ -101,6 +89,8 @@ bool setCpuFrequency(void);
static const char *TAG = "MAIN";
#define MOUNT_POINT "/sdcard"
bool Init_NVS_SDCard()
{
@@ -112,26 +102,30 @@ bool Init_NVS_SDCard()
ESP_LOGD(TAG, "Using SDMMC peripheral");
sdmmc_host_t host = SDMMC_HOST_DEFAULT();
host.max_freq_khz = SDMMC_FREQ_HIGHSPEED;
// This initializes the slot without card detect (CD) and write protect (WP) signals.
// Modify slot_config.gpio_cd and slot_config.gpio_wp if your board has these signals.
sdmmc_slot_config_t slot_config = SDMMC_SLOT_CONFIG_DEFAULT();
// To use 1-line SD mode, uncomment the following line:
#ifdef __SD_USE_ONE_LINE_MODE__
slot_config.width = 1;
#endif
// Set bus width to use:
#ifdef __SD_USE_ONE_LINE_MODE__
slot_config.width = 1;
#else
slot_config.width = 4;
#endif
// GPIOs 15, 2, 4, 12, 13 should have external 10k pull-ups.
// Internal pull-ups are not sufficient. However, enabling internal pull-ups
// does make a difference some boards, so we do that here.
gpio_set_pull_mode(GPIO_NUM_15, GPIO_PULLUP_ONLY); // CMD, needed in 4- and 1- line modes
gpio_set_pull_mode(GPIO_NUM_2, GPIO_PULLUP_ONLY); // D0, needed in 4- and 1-line modes
#ifndef __SD_USE_ONE_LINE_MODE__
gpio_set_pull_mode(GPIO_NUM_4, GPIO_PULLUP_ONLY); // D1, needed in 4-line mode only
gpio_set_pull_mode(GPIO_NUM_12, GPIO_PULLUP_ONLY); // D2, needed in 4-line mode only
#endif
gpio_set_pull_mode(GPIO_NUM_13, GPIO_PULLUP_ONLY); // D3, needed in 4- and 1-line modes
// Enable internal pullups on enabled pins. The internal pullups
// are insufficient however, please make sure 10k external pullups are
// connected on the bus. This is for debug / example purpose only.
slot_config.flags |= SDMMC_SLOT_FLAG_INTERNAL_PULLUP;
// Der PullUp des GPIO13 wird durch slot_config.flags |= SDMMC_SLOT_FLAG_INTERNAL_PULLUP;
// nicht gesetzt, da er eigentlich nicht benötigt wird,
// dies führt jedoch bei schlechten Kopien des AI_THINKER Boards
// zu Problemen mit der SD Initialisierung und eventuell sogar zur reboot-loops.
// Um diese Probleme zu kompensieren, wird der PullUp manuel gesetzt.
gpio_set_pull_mode(GPIO_NUM_13, GPIO_PULLUP_ONLY); // HS2_D3
// Options for mounting the filesystem.
// If format_if_mount_failed is set to true, SD card will be partitioned and
@@ -139,15 +133,18 @@ bool Init_NVS_SDCard()
esp_vfs_fat_sdmmc_mount_config_t mount_config = {
.format_if_mount_failed = false,
.max_files = 12, // previously -> 2022-09-21: 5, 2023-01-02: 7
.allocation_unit_size = 16 * 1024
.allocation_unit_size = 0, // 0 = auto
.disk_status_check_enable = 0
};
sdmmc_card_t* card;
const char mount_point[] = MOUNT_POINT;
// Use settings defined above to initialize SD card and mount FAT filesystem.
// Note: esp_vfs_fat_sdmmc_mount is an all-in-one convenience function.
// Please check its source code and implement error recovery when developing
// production applications.
ret = esp_vfs_fat_sdmmc_mount("/sdcard", &host, &slot_config, &mount_config, &card);
ret = esp_vfs_fat_sdmmc_mount_mh(mount_point, &host, &slot_config, &mount_config, &card);
if (ret != ESP_OK) {
if (ret == ESP_FAIL) {
@@ -642,7 +639,6 @@ void migrateConfiguration(void) {
/* Fieldname has a <NUMBER> as prefix! */
if (isInString(configLines[i], "Fieldname")) { // It is the parameter "Fieldname"
migrated = migrated | replaceString(configLines[i], "Fieldname", "Field"); // Rename it to Field
migrated = migrated | replaceString(configLines[i], ";", ""); // Enable it
}
}
@@ -650,7 +646,10 @@ void migrateConfiguration(void) {
/* Fieldname has a <NUMBER> as prefix! */
if (isInString(configLines[i], "Fieldname")) { // It is the parameter "Fieldname"
migrated = migrated | replaceString(configLines[i], "Fieldname", "Field"); // Rename it to Field
migrated = migrated | replaceString(configLines[i], ";", ""); // Enable it
}
/* Database got renamed to Bucket! */
if (isInString(configLines[i], "Database")) { // It is the parameter "Database"
migrated = migrated | replaceString(configLines[i], "Database", "Bucket"); // Rename it to Bucket
}
}
@@ -721,6 +720,7 @@ std::vector<std::string> splitString(const std::string& str) {
}
/*bool replace_all(std::string& s, std::string const& toReplace, std::string const& replaceWith) {
std::string buf;
std::size_t pos = 0;
@@ -813,4 +813,4 @@ bool setCpuFrequency(void) {
}
return true;
}
}

View File

@@ -17,6 +17,7 @@
#include "MainFlowControl.h"
#include "esp_log.h"
#include "esp_chip_info.h"
#include <stdio.h>
@@ -39,17 +40,21 @@ esp_err_t info_get_handler(httpd_req_t *req)
char _valuechar[30];
std::string _task;
if (httpd_req_get_url_query_str(req, _query, 200) == ESP_OK)
if (httpd_req_get_url_query_str(req, _query, 200) != ESP_OK)
{
ESP_LOGD(TAG, "Query: %s", _query);
if (httpd_query_key_value(_query, "type", _valuechar, 30) == ESP_OK)
{
ESP_LOGD(TAG, "type is found: %s", _valuechar);
_task = std::string(_valuechar);
}
return httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "invalid query string");
}
ESP_LOGD(TAG, "Query: %s", _query);
if (httpd_query_key_value(_query, "type", _valuechar, 30) != ESP_OK)
{
return httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "missing or invalid 'type' query parameter (too long value?)");
}
ESP_LOGD(TAG, "type is found: %s", _valuechar);
_task = std::string(_valuechar);
httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
if (_task.compare("GitBranch") == 0)
@@ -166,6 +171,33 @@ esp_err_t info_get_handler(httpd_req_t *req)
httpd_resp_sendstr(req, zw.c_str());
return ESP_OK;
}
else if (_task.compare("ChipCores") == 0)
{
esp_chip_info_t chipInfo;
esp_chip_info(&chipInfo);
httpd_resp_sendstr(req, to_string(chipInfo.cores).c_str());
return ESP_OK;
}
else if (_task.compare("ChipRevision") == 0)
{
esp_chip_info_t chipInfo;
esp_chip_info(&chipInfo);
httpd_resp_sendstr(req, to_string(chipInfo.revision).c_str());
return ESP_OK;
}
else if (_task.compare("ChipFeatures") == 0)
{
esp_chip_info_t chipInfo;
esp_chip_info(&chipInfo);
httpd_resp_sendstr(req, to_string(chipInfo.features).c_str());
return ESP_OK;
}
else
{
char formatted[256];
snprintf(formatted, sizeof(formatted), "Unknown value for parameter info 'type': '%s'\n", _task.c_str());
return httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, formatted);
}
return ESP_OK;
}

View File

@@ -19,7 +19,7 @@
[common:esp32-idf]
extends = common:idf
platform = platformio/espressif32 @ 6.2.0
platform = platformio/espressif32 @ 6.5.0
framework = espidf
lib_deps =
${common:idf.lib_deps}

View File

@@ -109,6 +109,11 @@ CONFIG_ESP_INT_WDT_TIMEOUT_MS=300
CONFIG_HTTPD_MAX_REQ_HDR_LEN=1024
CONFIG_HTTPD_PURGE_BUF_LEN=16
<<<<<<< Updated upstream
=======
CONFIG_HTTPD_WS_SUPPORT=y
CONFIG_LWIP_MAX_SOCKETS=12
>>>>>>> Stashed changes
CONFIG_ESP32_WIFI_DYNAMIC_RX_BUFFER_NUM=16
CONFIG_ESP32_WIFI_CACHE_TX_BUFFER_NUM=16

View File

@@ -41,6 +41,22 @@ void test_ZeigerEval()
/**
* @brief test if all combinations of digit
* evaluation are running correctly
*
* Desciption on call undertest.PointerEvalHybridNew(float number, float number_of_predecessors, int eval_predecessors, bool Analog_Predecessors, float digitalAnalogTransitionStart)
* @param number: is the current ROI as float value from recognition
* @param number_of_predecessors: is the last (lower) ROI as float from recognition
* @param eval_predecessors: is the evaluated number. Sometimes a much lower value can change higer values
* example: 9.8, 9.9, 0.1
* 0.1 => 0 (eval_predecessors)
* The 0 makes a 9.9 to 0 (eval_predecessors)
* The 0 makes a 9.8 to 0
* @param Analog_Predecessors false/true if the last ROI is an analog or digital ROI (default=false)
* runs in special handling because analog is much less precise
* @param digitalAnalogTransitionStart start of the transitionlogic begins on number_of_predecessor (default=9.2)
*
*
*
*
*/
void test_ZeigerEvalHybrid() {
UnderTestCNN undertest = UnderTestCNN(nullptr, Digital100);
@@ -55,11 +71,11 @@ void test_ZeigerEvalHybrid() {
printf("PointerEvalHybridNew(5.7, 0, -1)\n");
// the 5.7 and no previous should trunc to 5
TEST_ASSERT_EQUAL(6, undertest.PointerEvalHybridNew(5.7, 0, -1));
TEST_ASSERT_EQUAL(5, undertest.PointerEvalHybridNew(5.7, 0, -1, false, 9.2));
// the 5.8 and no previous should round up to 6
printf("PointerEvalHybridNew(5.8, 0, -1)\n");
TEST_ASSERT_EQUAL(6, undertest.PointerEvalHybridNew(5.8, 0, -1));
TEST_ASSERT_EQUAL(6, undertest.PointerEvalHybridNew(5.8, 8.0, 8, false, 8.0));
// the 5.7 with previous and the previous between 0.3-0.5 should round up to 6
TEST_ASSERT_EQUAL(6, undertest.PointerEvalHybridNew(5.7, 0.4, 1));
@@ -70,8 +86,9 @@ void test_ZeigerEvalHybrid() {
// the 5.3 with previous and the previous <=0.5 should trunc to 5
TEST_ASSERT_EQUAL(5, undertest.PointerEvalHybridNew(5.3, 0.1, 1));
// the 5.3 with previous and the previous >=9.5 should reduce to 4
TEST_ASSERT_EQUAL(4, undertest.PointerEvalHybridNew(5.3, 9.6, 9));
// the 5.2 with previous and the previous >=9.8 should reduce to 4
// the digit is already over transistion, but a analog pointer runs behind
TEST_ASSERT_EQUAL(4, undertest.PointerEvalHybridNew(5.2, 9.8, 9, false, 9.0));
// the 5.7 with previous and the previous >=9.5 should trunc to 5
TEST_ASSERT_EQUAL(5, undertest.PointerEvalHybridNew(5.7, 9.6, 9));

View File

@@ -33,7 +33,17 @@ std::string process_doFlow(UnderTestPost* _underTestPost) {
return _underTestPost->getReadout(0);
}
/**
* @brief setup flow like it runs after recognition.
*
* @param analog the analog recognitions as array begins with the highest ROI
* @param digits the digital regocnitions as array begins with the highest ROI
* @param digType type of the model defaults do Digital100
* @param checkConsistency for Digital type only. Not relvant for newer models
* @param extendedResolution the lowest ROI will directly used (9.7 => 9.7) if false 9.7 => 9
* @param decimal_shift the decimal point offset. -3 corresponds to x.yyy
* @return std::string the value result
*/
std::string process_doFlow(std::vector<float> analog, std::vector<float> digits, t_CNNType digType,
bool checkConsistency, bool extendedResolution, int decimal_shift) {
// setup the classundertest

View File

@@ -51,21 +51,32 @@ void testNegative() {
delete underTestPost;
// extendResolution=false
// value < preValue
preValue = 16.99; // zu groß
// value < (preValue -.01)
preValue = 17.00; // zu groß
underTestPost = init_do_flow(analogs, digits, Digital100, false, false, 0);
setAllowNegatives(underTestPost, false);
setPreValue(underTestPost, preValue_extended);
setPreValue(underTestPost, preValue);
result = process_doFlow(underTestPost);
TEST_ASSERT_EQUAL_STRING("Neg. Rate - Read: - Raw: 16.98 - Pre: 16.99 ", underTestPost->getReadoutError().c_str());
TEST_ASSERT_EQUAL_STRING("Neg. Rate - Read: - Raw: 16.98 - Pre: 17.00 ", underTestPost->getReadoutError().c_str());
TEST_ASSERT_EQUAL_STRING("", result.c_str());
delete underTestPost;
// extendResolution=false
// value > (preValue -.01)
// ist im Rahmen der Ungenauigkeit (-1 auf letzter Stelle)
preValue = 16.99; // zu groß
underTestPost = init_do_flow(analogs, digits, Digital100, false, false, 0);
setAllowNegatives(underTestPost, false);
setPreValue(underTestPost, preValue);
result = process_doFlow(underTestPost);
TEST_ASSERT_EQUAL_STRING("no error", underTestPost->getReadoutError().c_str());
TEST_ASSERT_EQUAL_STRING("16.99", result.c_str());
delete underTestPost;
// extendResolution=false
// value < preValue
// Aber Prüfung abgeschaltet => kein Fehler
preValue = 16.99; // zu groß
preValue = 17.99; // zu groß
underTestPost = init_do_flow(analogs, digits, Digital100, false, false, 0);
setAllowNegatives(underTestPost, true);
setPreValue(underTestPost, preValue_extended);
@@ -84,8 +95,8 @@ void testNegative_Issues() {
// Ohne decimal_shift
std::vector<float> digits = { 2.0, 2.0, 0.0, 1.0, 7.2, 9.0, 8.0};
std::vector<float> analogs = { };
double preValue_extended = 22018.080;
double preValue = 22018.08;
double preValue_extended = 22018.090;
double preValue = 22018.09;
const char* expected = "22017.98";
@@ -93,13 +104,15 @@ void testNegative_Issues() {
// extendResolution=false
// value < preValue
// Prüfung eingeschaltet => Fehler
preValue = 22018.08; // zu groß
preValue = 22018.09; // zu groß
UnderTestPost* underTestPost = init_do_flow(analogs, digits, Digital100, false, false, -2);
setAllowNegatives(underTestPost, false);
setPreValue(underTestPost, preValue_extended);
std::string result = process_doFlow(underTestPost);
TEST_ASSERT_EQUAL_STRING("Neg. Rate - Read: - Raw: 22017.98 - Pre: 22018.08 ", underTestPost->getReadoutError().c_str());
TEST_ASSERT_EQUAL_STRING(expected, result.c_str());
// if negativ no result any more
TEST_ASSERT_EQUAL_STRING("", result.c_str());
delete underTestPost;
}

View File

@@ -1,7 +1,6 @@
#include "test_flow_postrocess_helper.h"
#include <memory>
/**
* ACHTUNG! Die Test laufen aktuell nur mit ausgeschaltetem Debug in ClassFlowCNNGeneral
@@ -114,28 +113,28 @@ void test_doFlowPP1() {
// https://github.com/jomjol/AI-on-the-edge-device/issues/942#issuecomment-1226966346
std::vector<float> digits = { 0.0, 2.9, 3.0, 2.9, 3.5, 9.5};
std::vector<float> analogs = { };
const char* expected = "33330";
const char* expected = "33339";
std::string result = process_doFlow(analogs, digits);
TEST_ASSERT_EQUAL_STRING(expected, result.c_str());
// https://github.com/jomjol/AI-on-the-edge-device/issues/942#issuecomment-1226966346
digits = { 9.9, 2.8, 2.9, 2.9, 3.7, 9.7};
analogs = { };
expected = "33340";
expected = "33339";
result = process_doFlow(analogs, digits);
TEST_ASSERT_EQUAL_STRING(expected, result.c_str());
// https://github.com/jomjol/AI-on-the-edge-device/issues/942
digits = { 0.0, 9.9, 6.8, 9.9, 3.7, 0.8, 6.9, 8.7};
analogs = { };
expected = "704179";
expected = "704178";
result = process_doFlow(analogs, digits);
TEST_ASSERT_EQUAL_STRING(expected, result.c_str());
// https://github.com/jomjol/AI-on-the-edge-device/issues/942#issuecomment-1228343319
digits = { 9.9, 6.8, 1.1, 4.7, 2.7, 6.0, 9.0, 2.8}; // changed 3.7 --> 2.7 (see picture in issue)
analogs = { };
expected = "7153693";
expected = "7153692";
result = process_doFlow(analogs, digits);
TEST_ASSERT_EQUAL_STRING(expected, result.c_str());
@@ -185,7 +184,7 @@ void test_doFlowPP2() {
// https://github.com/jomjol/AI-on-the-edge-device/issues/921#issuecomment-1242730397
digits = { 3.0, 2.0, 2.0, 8.0, 9.0, 4.0, 1.7, 9.8}; // falscher Wert 32290.420
analogs = { };
expected = "32289.420";
expected = "32289.419";
const char* expected_extended= "32289.4198";
// FALSCH! wegen ungenügender Präzision von NUMBERS->Value
// expected_extended= "32289.4198";
@@ -230,7 +229,7 @@ void test_doFlowPP2() {
// https://github.com/jomjol/AI-on-the-edge-device/issues/994#issue-1368570945
digits = { 0.0, 0.0, 1.0, 2.0, 2.8, 1.9, 2.8, 5.6}; // 123245.6 als falsches Ergebnis
analogs = { };
expected = "123236";
expected = "123235";
expected_extended= "123235.6";
// checkConsistency=true
@@ -542,4 +541,64 @@ void test_doFlowPP4() {
}
std::string postProcess(std::vector<float> digits,
std::vector<float> analogs,
float analog2DigitalTransition=0.0)
{
std::unique_ptr<UnderTestPost> undertestPost(init_do_flow(std::move(analogs),
std::move(digits),
Digital100,
false, false));
setAnalogdigitTransistionStart(undertestPost.get(), analog2DigitalTransition);
return process_doFlow(undertestPost.get());
}
void test_doFlowLateTransition()
{
// in these test cases, the last digit before comma turns 3.6 too late
float a2dt = 3.6;
// meter shows 011.0210 but it already needs to be 012.0210, before transition
TEST_ASSERT_EQUAL_STRING("12.0210", postProcess({0.0, 1.0, 1.0}, {0.2, 2.2, 1.0, 0.0}, a2dt).c_str());
// meter shows 011.3210 but it already needs to be 012.3210, just before transition
TEST_ASSERT_EQUAL_STRING("12.3210", postProcess({0.0, 1.0, 1.2}, {3.3, 2.2, 1.0, 0.0}, a2dt).c_str());
// meter shows 012.4210 , this is after transition
TEST_ASSERT_EQUAL_STRING("12.4210", postProcess({0.0, 1.0, 2.0}, {4.3, 2.2, 1.0, 0.0}, a2dt).c_str());
// meter shows 012.987
TEST_ASSERT_EQUAL_STRING("12.9870", postProcess({0.0, 1.0, 2.0}, {9.8, 8.7, 7.0, 0.0}, a2dt).c_str());
// meter shows 0012.003
TEST_ASSERT_EQUAL_STRING("13.003", postProcess({0.0, 0.0, 1.0, 2.0}, {0.1, 0.3, 3.1}, a2dt).c_str());
// meter shows 0012.351
TEST_ASSERT_EQUAL_STRING("13.351", postProcess({0.0, 0.0, 1.0, 2.8}, {3.5, 5.2, 1.1}, a2dt).c_str());
// meter shows 0013.421
TEST_ASSERT_EQUAL_STRING("13.421", postProcess({0.0, 0.0, 1.0, 3.0}, {4.1, 2.2, 1.1}, a2dt).c_str());
}
void test_doFlowEarlyTransition()
{
// in these test cases, the last digit before comma turns at around 7.5
// start transition 7.0 end transition 8.0
float a2dt = 7.5;
// meter shows 011.0210 but it already needs to be 012.0210, before transition
TEST_ASSERT_EQUAL_STRING("12.6789", postProcess({0.0, 1.0, 2.0}, {6.7, 7.8, 8.9, 9.0}, a2dt).c_str());
TEST_ASSERT_EQUAL_STRING("12.7234", postProcess({0.0, 1.0, 2.4}, {7.2, 2.3, 3.4, 4.0}, a2dt).c_str());
TEST_ASSERT_EQUAL_STRING("12.7789", postProcess({0.0, 1.0, 2.7}, {7.7, 7.8, 8.9, 9.0}, a2dt).c_str());
TEST_ASSERT_EQUAL_STRING("12.8123", postProcess({0.0, 1.0, 3.0}, {8.1, 1.2, 2.3, 3.0}, a2dt).c_str());
TEST_ASSERT_EQUAL_STRING("13.1234", postProcess({0.0, 1.0, 3.0}, {1.2, 2.3, 3.4, 4.0}, a2dt).c_str());
}

View File

@@ -1,10 +1,5 @@
#include <unity.h>
#include "components/jomjol-flowcontroll/test_flow_postrocess_helper.cpp"
#include "components/jomjol-flowcontroll/test_flowpostprocessing.cpp"
#include "components/jomjol-flowcontroll/test_flow_pp_negative.cpp"
#include "components/jomjol-flowcontroll/test_PointerEvalAnalogToDigitNew.cpp"
#include "components/jomjol-flowcontroll/test_getReadoutRawString.cpp"
// SD-Card ////////////////////
#include "nvs_flash.h"
#include "esp_vfs_fat.h"
@@ -15,6 +10,18 @@
#define __SD_USE_ONE_LINE_MODE__
#include "server_GPIO.h"
//*****************************************************************************
// Include files with functions to test
//*****************************************************************************
#include "components/jomjol-flowcontroll/test_flow_postrocess_helper.cpp"
#include "components/jomjol-flowcontroll/test_flowpostprocessing.cpp"
#include "components/jomjol-flowcontroll/test_flow_pp_negative.cpp"
#include "components/jomjol-flowcontroll/test_PointerEvalAnalogToDigitNew.cpp"
#include "components/jomjol-flowcontroll/test_getReadoutRawString.cpp"
#include "components/jomjol-flowcontroll/test_cnnflowcontroll.cpp"
bool Init_NVS_SDCard()
{
esp_err_t ret = nvs_flash_init();
@@ -81,7 +88,6 @@ bool Init_NVS_SDCard()
}
void initGPIO()
{
gpio_config_t io_conf;
@@ -96,11 +102,51 @@ void initGPIO()
}
/**
* @brief startup the test. Like a test-suite
* all test methods must be called here
*/
void task_UnityTesting(void *pvParameter)
{
vTaskDelay( 5000 / portTICK_PERIOD_MS ); // 5s delay to ensure established serial connection
UNITY_BEGIN();
RUN_TEST(test_getReadoutRawString);
printf("---------------------------------------------------------------------------\n");
RUN_TEST(test_ZeigerEval);
printf("---------------------------------------------------------------------------\n");
RUN_TEST(test_ZeigerEvalHybrid);
printf("---------------------------------------------------------------------------\n");
RUN_TEST(testNegative_Issues);
printf("---------------------------------------------------------------------------\n");
RUN_TEST(testNegative);
printf("---------------------------------------------------------------------------\n");
RUN_TEST(test_analogToDigit_Standard);
printf("---------------------------------------------------------------------------\n");
RUN_TEST(test_analogToDigit_Transition);
printf("---------------------------------------------------------------------------\n");
RUN_TEST(test_doFlowPP);
printf("---------------------------------------------------------------------------\n");
RUN_TEST(test_doFlowPP1);
printf("---------------------------------------------------------------------------\n");
RUN_TEST(test_doFlowPP2);
printf("---------------------------------------------------------------------------\n");
RUN_TEST(test_doFlowPP3);
printf("---------------------------------------------------------------------------\n");
RUN_TEST(test_doFlowPP4);
UNITY_END();
while(1);
}
/**
* @brief main task
*/
extern "C" void app_main()
{
initGPIO();
@@ -109,8 +155,8 @@ extern "C" void app_main()
UNITY_BEGIN();
RUN_TEST(testNegative_Issues);
/* RUN_TEST(testNegative);
RUN_TEST(testNegative);
/*
RUN_TEST(test_analogToDigit_Standard);
RUN_TEST(test_analogToDigit_Transition);
RUN_TEST(test_doFlowPP);
@@ -118,6 +164,8 @@ extern "C" void app_main()
RUN_TEST(test_doFlowPP2);
RUN_TEST(test_doFlowPP3);
RUN_TEST(test_doFlowPP4);
RUN_TEST(test_doFlowLateTransition);
RUN_TEST(test_doFlowEarlyTransition);
// getReadoutRawString test
RUN_TEST(test_getReadoutRawString);

Binary file not shown.

View File

@@ -18,16 +18,19 @@
For further information about AI-on-the-edge-device please go to <a href=https://github.com/jomjol/AI-on-the-edge-device target=_blank>https://github.com/jomjol/AI-on-the-edge-device</a>.</p>
<p>Notes:</p>
<h2>Notes:</h2>
<ul>
<li>For the installation, make sure to switch the ESP32 to Bootloader mode!</li>
<li>The Webinstall will install the latest firmware (Version <b>$VERSION</b>).</li>
<li>For the installation, make sure to switch the ESP32 to Bootloader mode by keeping the <b>FLASH</b> button pressed while the <b>RESET</b> button gets relesed. if there is no <b>FLASH</b> button, you need to pull <b>GPIO0</b> low!</li>
<li>After the installation, a manual reset might be required!</li>
<li>Please note that not all webbrowsers and operating systems support the needed access to USB!</li>
<li>Please note that not all web browsers and operating systems support the necessary USB access needed for this Webinstaller!</li>
<li>Check the <a href=https://jomjol.github.io/AI-on-the-edge-device-docs/Installation target=_blank>documentation</a> for additional information.</li>
<li>The SD-Card still must be setup separately. This can be done manually or using the new <b>Remote Setup</b>. See the <a href=https://jomjol.github.io/AI-on-the-edge-device-docs/Installation/#3-sd-card target=_blank>documentation</a> for further instructions!</li>
<li>The SD card can be setup automatically after the firmware got installed. See the <a href=https://jomjol.github.io/AI-on-the-edge-device-docs/Installation/#remote-setup-using-the-built-in-access-point target=_blank>documentation</a> for details. For this to work, the SD card must be FAT formated (which is the default on a new SD card).
Alternatively the SD card still can be setup manually, see the <a href=https://jomjol.github.io/AI-on-the-edge-device-docs/Installation/#3-sd-card target=_blank>documentation</a> for details!</li>
</ul>
<hr>
<p><esp-web-install-button manifest="manifest.json"></esp-web-install-button></p>
<hr>
<p style="font-size: small;">Installer and Console powered by <a href=https://esphome.github.io/esp-web-tools/ target=_blank>ESP Web Tools</a></p>

View File

@@ -1,6 +1,6 @@
{
"name": "AI-on-the-edge",
"version": "13.0.8",
"version": "$VERSION",
"funding_url": "https://www.paypal.com/donate?hosted_button_id=8TRSVYNYKDSWL",
"new_install_prompt_erase": false,
"builds": [

View File

@@ -1,25 +0,0 @@
{
"name": "AI-on-the-edge",
"version": "VERSION",
"funding_url": "https://www.paypal.com/donate?hosted_button_id=8TRSVYNYKDSWL",
"new_install_prompt_erase": false,
"builds": [
{
"chipFamily": "ESP32",
"parts": [
{
"path": "binary/bootloader.bin",
"offset": 4096
},
{
"path": "binary/partitions.bin",
"offset": 32768
},
{
"path": "binary/firmware.bin",
"offset": 65536
}
]
}
]
}

View File

@@ -1,6 +0,0 @@
# Firmware
The firmware got moved to the [Release page](https://github.com/jomjol/AI-on-the-edge-device/releases).
# Installation Guide
You find the complete installation guide at https://jomjol.github.io/AI-on-the-edge-device-docs/Installation/

Binary file not shown.

Binary file not shown.

BIN
images/icon/logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

BIN
images/paypal.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

BIN
images/web-installer.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

3
param-docs/.idea/.gitignore generated vendored Normal file
View File

@@ -0,0 +1,3 @@
# Default ignored files
/shelf/
/workspace.xml

View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="PYTHON_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="jdk" jdkName="Python 3.10" jdkType="Python SDK" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

View File

@@ -0,0 +1,6 @@
<component name="InspectionProjectProfileManager">
<settings>
<option name="USE_PROJECT_PROFILE" value="false" />
<version value="1.0" />
</settings>
</component>

4
param-docs/.idea/misc.xml generated Normal file
View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.10" project-jdk-type="Python SDK" />
</project>

8
param-docs/.idea/modules.xml generated Normal file
View File

@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/generate-param-docs.iml" filepath="$PROJECT_DIR$/.idea/generate-param-docs.iml" />
</modules>
</component>
</project>

6
param-docs/.idea/vcs.xml generated Normal file
View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$/../.." vcs="Git" />
</component>
</project>

17
param-docs/README.md Normal file
View File

@@ -0,0 +1,17 @@
# Parameter Documentation
Each parameter which is listed in the [configfile](https://github.com/jomjol/AI-on-the-edge-device/blob/rolling/sd-card/config/config.ini) has its own description page in the folder `parameter-pages` (grouped by the config sections).
Those pages can be edited as needed.
During a Github action build, those parameter pages will be used to generate the tooltips in the web interface. And they also are used to build the [Online Documentation](https://jomjol.github.io/AI-on-the-edge-device-docs/Parameters).
If you create or rename a parameter, make sure to also update its description page!
## Template Generator
The script `generate-template-param-doc-pages.py` should be run whenever a new parameter gets added to the config file.
It then checks if there is already a page for each of the parameters.
- If no page exists yet, a templated page gets generated.
- Existing pages do not get modified.
If the parameter is listed in `expert-params.txt`, an **Expert warning** will be shown.
If the parameter is listed in `hidden-in-ui.txt`, a **Note** will be shown.

View File

@@ -0,0 +1,31 @@
demo
WaitBeforeTakingPicture
ImageQuality
ImageSize
LEDIntensity
Brightness
Contrast
Saturation
FixedExposure
SearchFieldX
SearchFieldY
AlignmentAlgo
InitialMirror
FlipImageSize
CNNGoodThreshold
PreValueAgeStartup
ErrorMessage
CheckDigitIncreaseConsistency
IO0
IO1
IO3
IO4
IO12
IO13
AutoStart
Hostname
RSSIThreshold
TimeServer
CACert
ClientCert
ClientKey

View File

@@ -0,0 +1,95 @@
"""
For each parameter which can be found in the config file,
create a markdown file with a templated content if it does not exist yet.
The files are grouped in sub folders representing the config sections.
"""
import os
import configparser
import urllib.request
configFileUrl = "https://raw.githubusercontent.com/jomjol/AI-on-the-edge-device/rolling/sd-card/config/config.ini"
parameterDocsFolder = "parameter-pages"
parameterTemplateFile = "./templates/parameter.md"
expertParameterListFile = "./expert-params.txt"
hiddenInUiParameterListFile = "./hidden-in-ui.txt"
# Fetch default config file from URL
print("Fetching %r..." % configFileUrl)
with urllib.request.urlopen(configFileUrl) as response:
content = response.read().decode("utf-8")
lines = str(content).split("\n")
for l in range(len(lines)):
lines[l] = lines[l].strip() + "\n"
if lines[l][0] == ";":
lines[l] = lines[l][1:] # Remove comment
content = "".join(lines)
# Fetch list of expert parameters
with open(expertParameterListFile) as f:
expertParameters = f.read().splitlines()
# Fetch list of parameters not available through the UI
with open(hiddenInUiParameterListFile) as f:
hiddenInUiParameters = f.read().splitlines()
config = configparser.ConfigParser(allow_no_value=True)
config.optionxform = str # Make it case-insensitive
config.read_string(content)
#shutil.rmtree(parameterDocsFolder)
if not os.path.exists(parameterDocsFolder):
os.mkdir(parameterDocsFolder)
with open(parameterTemplateFile, 'r') as parameterTemplateFileHandle:
parameterTemplate = parameterTemplateFileHandle.read()
print("For each section/parameter, check if there is already a documentation page in the folder %r..." % (os.getcwd() + "/" + parameterDocsFolder))
for section in config:
if section != "DEFAULT":
#print(section)
subFolder = parameterDocsFolder + "/" + section
if not os.path.exists(subFolder):
os.mkdir(subFolder)
for parameter in config[section]:
if not " " in parameter: # Ignore parameters with whitespaces in them (special format, not part of editable config)
value = config[section][parameter]
#print(" %s = %s" % (parameter, value))
if "main." in parameter:
parameter = parameter.replace("main.", "NUMBER.")
"""
For each config line, create a markdown file
"""
parameterDocFile = subFolder + '/' + parameter + ".md"
if not os.path.exists(parameterDocFile): # File does not exist yet, generate template
print("%r does not exit yet, generating a templated file for it" % (os.getcwd() + "/" + parameterDocFile))
with open(parameterDocFile, 'w') as paramFileHandle:
content = parameterTemplate
content = content.replace("$NAME", parameter)
content = content.replace("$DEFAULT", value)
if parameter in expertParameters:
content = content.replace("$EXPERT_PARAMETER", "!!! Warning\n This is an **Expert Parameter**! Only change it if you understand what it does!") # Note: Needs a 4 whitespace Intent!
else:
content = content.replace("$EXPERT_PARAMETER", "")
if parameter in hiddenInUiParameters:
content = content.replace("$HIDDEN_IN_UI", "!!! Note\n This parameter is not accessible through the Web Interface Configuration Page!") # Note: Needs a 4 whitespace Intent!
else:
content = content.replace("$HIDDEN_IN_UI", "")
paramFileHandle.write(content)

View File

@@ -0,0 +1,4 @@
InitialRotate
MainTopicMQTT
AutoAdjustSummertime
SetupMode

View File

@@ -0,0 +1,14 @@
# Parameter `AlignmentAlgo`
Default Value: `Default`
!!! Warning
This is an **Expert Parameter**! Only change it if you understand what it does!
Algorithm used for the alignment step.
Available options:
- `Default`: Use only red color channel
- `HighAccuracy`: Use all 3 color channels (3x slower)
- `Fast`: First time use `HighAccuracy`, then only check if the image is shifted
- `Off`: Disable alignment algorithm

View File

@@ -0,0 +1,11 @@
# Parameter `FlipImageSize`
Default Value: `false`
!!! Warning
This is an **Expert Parameter**! Only change it if you understand what it does!
!!! Note
This parameter can also be set on the Reference Image configuration.
This parameter can be used to rotate the viewport together with the alignment rotation:
![](img/flipImageSize.png)

View File

@@ -0,0 +1,10 @@
# Parameter `InitialMirror`
Default Value: `false`
!!! Warning
This is an **Expert Parameter**! Only change it if you understand what it does!
!!! Note
This parameter can also be set on the Reference Image configuration.
Option for initially mirroring the image on the original x-axis.

View File

@@ -0,0 +1,9 @@
# Parameter `InitialRotate`
Default Value: `179`
Unit: Degrees
Initial rotation of image before alignment in degree (0 .. 359)
!!! Note
This parameter is accessible on the Reference Image Page but not on the Config page!

View File

@@ -0,0 +1,14 @@
# Parameter `SearchFieldX`
Default Value: `20`
Unit: Pixels
!!! Warning
This is an **Expert Parameter**! Only change it if you understand what it does!
X-size (width) in which the reference is searched.
!!! Note
Since the alignment is one of the steps using a lot of computation time,
the search field should be as small as possible.
The calculation time goes quadratic with the search field size.

View File

@@ -0,0 +1,14 @@
# Parameter `SearchFieldY`
Default Value: `20`
Unit: Pixels
!!! Warning
This is an **Expert Parameter**! Only change it if you understand what it does!
Y-size (height) in which the reference is searched.
!!! Note
Since the alignment is one of the steps using a lot of computation time,
the search field should be as small as possible.
The calculation time goes quadratic with the search field size.

View File

@@ -0,0 +1,10 @@
# Parameter `CNNGoodThreshold`
Default Value: `0.5`
!!! Warning
This is an **Expert Parameter**! Only change it if you understand what it does!
Threshold above which the classification should be to accept the value (only meaningful for digits).
!!! Warning
This is only supported for the `ana-class100` models!

View File

@@ -0,0 +1,5 @@
# Parameter `ExtendedResolution`
!!! Warning
This parameter is unused!
Use [`NUMBER.ExtendedResolution`](../Parameters/#PostProcessing-NUMBER.ExtendedResolution) instead!

View File

@@ -0,0 +1,4 @@
# Parameter `Model`
Default Value: `/config/ana-cont_*.tflite` (See [/config/config.ini](https://github.com/jomjol/AI-on-the-edge-device/blob/master/sd-card/config/config.ini))
Path to CNN model file for image recognition. See [here](../Choosing-the-Model) for details.

View File

@@ -0,0 +1,7 @@
# Parameter `ROIImagesLocation`
Default Value: `/log/analog`
Location to store separated analog images on the SD-Card.
!!! Warning
A SD-Card has limited write cycles. Since the device does not do [Wear Leveling](https://en.wikipedia.org/wiki/Wear_leveling), this can wear out your SD-Card!

View File

@@ -0,0 +1,6 @@
# Parameter `ROIImagesRetention`
Default Value: `3`
Unit: Days
Days to keep the separated analog images (`0` = forever).

View File

@@ -0,0 +1,12 @@
# Parameter `AutoStart`
Default Value: `true`
!!! Warning
This is an **Expert Parameter**! Only change it if you understand what it does!
Automatically start the Flow (Digitization Rounds) immediately after power up.
!!! Note
Typically this is set to `true`.
The main reasons to set it to `false` is when you want to trigger it manually using the
[REST API](../REST-API) or [MQTT-API](../MQTT-API) or for debugging.

View File

@@ -0,0 +1,7 @@
# Parameter `Interval`
Default Value: `5`
Unit: Minutes
Interval in which the Flow (Digitization Round) is run.
If a round takes longer than this interval, the next round gets postponed until the current round completes.

View File

@@ -0,0 +1,6 @@
# Parameter `DataFilesRetention`
Default Value: `3`
Unit: Days
Number of days to keep the data files (`0` = forever).

View File

@@ -0,0 +1,8 @@
# Parameter `DataLogActive`
Default Value: `true`
Activate data logging to the SD-Card.
The files will be stored in `/log/data/data_YYYY-MM-DD.csv`. See [`Data Logging`](../data-logging) for details.
!!! Warning
A SD-Card has limited write cycles. Since the device does not do [Wear Leveling](https://en.wikipedia.org/wiki/Wear_leveling), this can wear out your SD-Card!

View File

@@ -0,0 +1,16 @@
# Parameter `LogLevel`
Default Value: `1` (`ERROR`)
Define the log level for the logging to the SD-Card.
Available options:
- `1`: `ERROR`
- `2`: `WARNING`
- `3`: `INFO`
- `4`: `DEBUG`
As higher the level, as more log messages get written to the SD-Card.
!!! Warning
`DEBUG` or `INFO` might damage the SD-Card if enabled long term due to excessive writes to the SD-Card!
A SD-Card has limited write cycles. Since the device does not do [Wear Leveling](https://en.wikipedia.org/wiki/Wear_leveling), this can wear out your SD-Card!

View File

@@ -0,0 +1,6 @@
# Parameter `LogfilesRetention`
Default Value: `3`
Unit: Days
Number of days to keep the log files (`0` = forever).

View File

@@ -0,0 +1,10 @@
# Parameter `CNNGoodThreshold`
Default Value: `0.5`
!!! Warning
This is an **Expert Parameter**! Only change it if you understand what it does!
Threshold above which the classification should be to accept the value (only meaningful for digits).
!!! Warning
This is only supported for the `dig-class100` models!

View File

@@ -0,0 +1,4 @@
# Parameter `Model`
Default Value: `/config/dig-cont_*.tflite` (See [/config/config.ini](https://github.com/jomjol/AI-on-the-edge-device/blob/master/sd-card/config/config.ini))
Path to CNN model file for image recognition. See [here](../Choosing-the-Model) for details.

View File

@@ -0,0 +1,7 @@
# Parameter `ROIImagesLocation`
Default Value: `/log/digit`
Location to store separated digit images on the SD-Card.
!!! Warning
A SD-Card has limited write cycles. Since the device does not do [Wear Leveling](https://en.wikipedia.org/wiki/Wear_leveling), this can wear out your SD-Card!

Some files were not shown because too many files have changed in this diff Show More