mirror of
https://github.com/jomjol/AI-on-the-edge-device.git
synced 2025-12-07 12:06:58 +03:00
Compare commits
152 Commits
add-websoc
...
mqtt-logfi
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3dd2a80fd9 | ||
|
|
0df0de3b16 | ||
|
|
ec08715919 | ||
|
|
9f6e711358 | ||
|
|
8f03ab04c4 | ||
|
|
9d8fade3d7 | ||
|
|
b6ab16ddd8 | ||
|
|
ba7d1ea320 | ||
|
|
c457e2fd20 | ||
|
|
dbd1f2a058 | ||
|
|
f2a1d97ba7 | ||
|
|
cd0268256f | ||
|
|
31385e16d1 | ||
|
|
beaaf3d6bb | ||
|
|
7b9b5c9066 | ||
|
|
a52c66054d | ||
|
|
8300e4473f | ||
|
|
b61f15b53a | ||
|
|
92485bcaba | ||
|
|
5053a31245 | ||
|
|
44cf8933d4 | ||
|
|
35de56be04 | ||
|
|
80a6fc1dc3 | ||
|
|
d2c47fcde2 | ||
|
|
7b3a493587 | ||
|
|
217f543578 | ||
|
|
797fc5e764 | ||
|
|
3127990ccd | ||
|
|
7a4e82a44e | ||
|
|
a82d9068c0 | ||
|
|
a014bdff39 | ||
|
|
238f452efb | ||
|
|
1aef8fa8a2 | ||
|
|
d31a318ab8 | ||
|
|
a21bd4c611 | ||
|
|
40ab0ee1ff | ||
|
|
13e7440e33 | ||
|
|
3696085ad6 | ||
|
|
68fbd7137b | ||
|
|
0b0381017a | ||
|
|
4c198e7eff | ||
|
|
fc7009bcc6 | ||
|
|
9084c35e92 | ||
|
|
4b3c0e0f4d | ||
|
|
d2ebca0902 | ||
|
|
d83e034b4f | ||
|
|
019069cd16 | ||
|
|
4de1152cf3 | ||
|
|
0e0fb459dc | ||
|
|
8410df6144 | ||
|
|
4990858101 | ||
|
|
fc1f8ee242 | ||
|
|
252c399a76 | ||
|
|
eb7f2b3705 | ||
|
|
2ed6fb0f0d | ||
|
|
b5213b01af | ||
|
|
473e458b85 | ||
|
|
4f3f3d9af2 | ||
|
|
b5a4cfed96 | ||
|
|
6fca4d8d95 | ||
|
|
a11e19fb0c | ||
|
|
09fa94c95f | ||
|
|
f01b4dbd13 | ||
|
|
dbf1770016 | ||
|
|
006f3aa063 | ||
|
|
24c46c38b4 | ||
|
|
9ced147d9c | ||
|
|
0808895bd6 | ||
|
|
d2dec9fa59 | ||
|
|
7e7bc3dd68 | ||
|
|
5b09cd0d59 | ||
|
|
74d4f20858 | ||
|
|
e790a14caa | ||
|
|
f023a6b739 | ||
|
|
1e463188ea | ||
|
|
9991196961 | ||
|
|
ecece0f7fc | ||
|
|
1b3b7595c1 | ||
|
|
6d10f712d1 | ||
|
|
b84a2db050 | ||
|
|
374462a7d8 | ||
|
|
4facd7be05 | ||
|
|
3baf5865ad | ||
|
|
02138c44ac | ||
|
|
1094c8a0a8 | ||
|
|
75b15b8e9d | ||
|
|
36c12b400b | ||
|
|
35d90cd0ee | ||
|
|
999a8d9374 | ||
|
|
8a4269c6a0 | ||
|
|
8f5579cca5 | ||
|
|
e58b3a2cf8 | ||
|
|
222ee0921c | ||
|
|
e2bfcd26c9 | ||
|
|
18917b2d82 | ||
|
|
f0dea3abcb | ||
|
|
bd2d8b4a15 | ||
|
|
80e3f50a5b | ||
|
|
f6ca32d69f | ||
|
|
49e919c481 | ||
|
|
de768c4f44 | ||
|
|
002fc033aa | ||
|
|
f4af8de699 | ||
|
|
e4d6707a0b | ||
|
|
9f03e68690 | ||
|
|
b1df7df580 | ||
|
|
ebc9be4a28 | ||
|
|
5d0fc73c13 | ||
|
|
40a1aa0430 | ||
|
|
d7a733512f | ||
|
|
dc9f1aad27 | ||
|
|
cd3e641bcc | ||
|
|
ad72ffa37c | ||
|
|
2d45a0ed26 | ||
|
|
e8065ef414 | ||
|
|
33893eb566 | ||
|
|
3fbff0ad33 | ||
|
|
28cabea7f2 | ||
|
|
5d06130a88 | ||
|
|
3497a86084 | ||
|
|
84707fb27a | ||
|
|
0b81af7cb8 | ||
|
|
61efe1a6ef | ||
|
|
09ecd722cc | ||
|
|
5615fd8137 | ||
|
|
7ebf68411f | ||
|
|
34835dca84 | ||
|
|
697ff4c4b6 | ||
|
|
0f7c685933 | ||
|
|
3ace5aeff1 | ||
|
|
d47ed060b0 | ||
|
|
e7dbebffa1 | ||
|
|
def13d46af | ||
|
|
f82a6bf513 | ||
|
|
05deecee00 | ||
|
|
8339b6788f | ||
|
|
4e5b084932 | ||
|
|
62fcefee78 | ||
|
|
14128ca3a7 | ||
|
|
431551fb45 | ||
|
|
ff52d785cd | ||
|
|
f5a7c082d6 | ||
|
|
f3e90c6293 | ||
|
|
cbd14a267f | ||
|
|
c30881f73c | ||
|
|
e75e720869 | ||
|
|
54cd7e511a | ||
|
|
c5a82e839f | ||
|
|
9f97a2b223 | ||
|
|
8d06de5792 | ||
|
|
1326585a33 | ||
|
|
d7a507ca05 |
27
.github/label-commenter-config.yml
vendored
27
.github/label-commenter-config.yml
vendored
@@ -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
|
||||
#######################################################################
|
||||
|
||||
@@ -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!
|
||||
10
.github/workflows/manual-update-webinstaller.yml
vendored
10
.github/workflows/manual-update-webinstaller.yml
vendored
@@ -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
6
.gitmodules
vendored
@@ -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
|
||||
|
||||
72
Changelog.md
72
Changelog.md
@@ -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
|
||||
|
||||
@@ -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~~
|
||||
|
||||
|
||||
|
||||
|
||||
98
README.md
98
README.md
@@ -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:
|
||||

|
||||
- 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
1
code/.gitignore
vendored
@@ -1,4 +1,5 @@
|
||||
.pio
|
||||
.idea
|
||||
.vscode/.browse.c_cpp.db*
|
||||
.vscode/c_cpp_properties.json
|
||||
.vscode/launch.json
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
Submodule code/components/esp-nn updated: 6b3ef8e226...34e97138de
1
code/components/esp-tflite-micro
Submodule
1
code/components/esp-tflite-micro
Submodule
Submodule code/components/esp-tflite-micro added at 13f26b8294
Submodule code/components/esp32-camera updated: 5c8349f4cf...dba8da9898
@@ -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)
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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());
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 = "";
|
||||
|
||||
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
#include <vector>
|
||||
|
||||
#include "sdmmc_cmd.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
#include <inttypes.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
|
||||
651
code/components/jomjol_helper/sdcard_init.c
Normal file
651
code/components/jomjol_helper/sdcard_init.c
Normal 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;
|
||||
}
|
||||
111
code/components/jomjol_helper/sdcard_init.h
Normal file
111
code/components/jomjol_helper/sdcard_init.h
Normal 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
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
|
||||
@@ -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 + "/";
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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)
|
||||
|
||||
|
||||
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -28,5 +28,7 @@ bool setupTime();
|
||||
|
||||
bool time_manual_reset_sync(void);
|
||||
|
||||
extern int LocalTimeToUTCOffsetSeconds;
|
||||
|
||||
|
||||
#endif //TIMESNTP_H
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Submodule code/components/tflite-micro-esp-examples deleted from 095f55a6ee
@@ -1,3 +1,3 @@
|
||||
manifest_hash: 63f5c6c9f0bcebc7b9ca12d2aa8b26b2c5f5218d377dc4b2375d9b9ca1df7815
|
||||
target: esp32
|
||||
version: 1.0.0
|
||||
version: 1.0.0
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
}
|
||||
@@ -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());
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -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.
@@ -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>
|
||||
|
||||
@@ -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": [
|
||||
|
||||
@@ -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
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -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.
Binary file not shown.
BIN
images/icon/logo.png
Normal file
BIN
images/icon/logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 36 KiB |
BIN
images/paypal.png
Normal file
BIN
images/paypal.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 69 KiB |
BIN
images/web-installer.png
Normal file
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
3
param-docs/.idea/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
8
param-docs/.idea/generate-param-docs.iml
generated
Normal file
8
param-docs/.idea/generate-param-docs.iml
generated
Normal 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>
|
||||
6
param-docs/.idea/inspectionProfiles/profiles_settings.xml
generated
Normal file
6
param-docs/.idea/inspectionProfiles/profiles_settings.xml
generated
Normal 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
4
param-docs/.idea/misc.xml
generated
Normal 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
8
param-docs/.idea/modules.xml
generated
Normal 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
6
param-docs/.idea/vcs.xml
generated
Normal 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
17
param-docs/README.md
Normal 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.
|
||||
31
param-docs/expert-params.txt
Normal file
31
param-docs/expert-params.txt
Normal 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
|
||||
95
param-docs/generate-template-param-doc-pages.py
Normal file
95
param-docs/generate-template-param-doc-pages.py
Normal 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)
|
||||
4
param-docs/hidden-in-ui.txt
Normal file
4
param-docs/hidden-in-ui.txt
Normal file
@@ -0,0 +1,4 @@
|
||||
InitialRotate
|
||||
MainTopicMQTT
|
||||
AutoAdjustSummertime
|
||||
SetupMode
|
||||
14
param-docs/parameter-pages/Alignment/AlignmentAlgo.md
Normal file
14
param-docs/parameter-pages/Alignment/AlignmentAlgo.md
Normal 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
|
||||
11
param-docs/parameter-pages/Alignment/FlipImageSize.md
Normal file
11
param-docs/parameter-pages/Alignment/FlipImageSize.md
Normal 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:
|
||||

|
||||
10
param-docs/parameter-pages/Alignment/InitialMirror.md
Normal file
10
param-docs/parameter-pages/Alignment/InitialMirror.md
Normal 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.
|
||||
9
param-docs/parameter-pages/Alignment/InitialRotate.md
Normal file
9
param-docs/parameter-pages/Alignment/InitialRotate.md
Normal 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!
|
||||
14
param-docs/parameter-pages/Alignment/SearchFieldX.md
Normal file
14
param-docs/parameter-pages/Alignment/SearchFieldX.md
Normal 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.
|
||||
14
param-docs/parameter-pages/Alignment/SearchFieldY.md
Normal file
14
param-docs/parameter-pages/Alignment/SearchFieldY.md
Normal 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.
|
||||
10
param-docs/parameter-pages/Analog/CNNGoodThreshold.md
Normal file
10
param-docs/parameter-pages/Analog/CNNGoodThreshold.md
Normal 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!
|
||||
5
param-docs/parameter-pages/Analog/ExtendedResolution.md
Normal file
5
param-docs/parameter-pages/Analog/ExtendedResolution.md
Normal file
@@ -0,0 +1,5 @@
|
||||
# Parameter `ExtendedResolution`
|
||||
|
||||
!!! Warning
|
||||
This parameter is unused!
|
||||
Use [`NUMBER.ExtendedResolution`](../Parameters/#PostProcessing-NUMBER.ExtendedResolution) instead!
|
||||
4
param-docs/parameter-pages/Analog/Model.md
Normal file
4
param-docs/parameter-pages/Analog/Model.md
Normal 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.
|
||||
7
param-docs/parameter-pages/Analog/ROIImagesLocation.md
Normal file
7
param-docs/parameter-pages/Analog/ROIImagesLocation.md
Normal 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!
|
||||
6
param-docs/parameter-pages/Analog/ROIImagesRetention.md
Normal file
6
param-docs/parameter-pages/Analog/ROIImagesRetention.md
Normal file
@@ -0,0 +1,6 @@
|
||||
# Parameter `ROIImagesRetention`
|
||||
Default Value: `3`
|
||||
|
||||
Unit: Days
|
||||
|
||||
Days to keep the separated analog images (`0` = forever).
|
||||
12
param-docs/parameter-pages/AutoTimer/AutoStart.md
Normal file
12
param-docs/parameter-pages/AutoTimer/AutoStart.md
Normal 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.
|
||||
7
param-docs/parameter-pages/AutoTimer/Interval.md
Normal file
7
param-docs/parameter-pages/AutoTimer/Interval.md
Normal 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.
|
||||
@@ -0,0 +1,6 @@
|
||||
# Parameter `DataFilesRetention`
|
||||
Default Value: `3`
|
||||
|
||||
Unit: Days
|
||||
|
||||
Number of days to keep the data files (`0` = forever).
|
||||
8
param-docs/parameter-pages/DataLogging/DataLogActive.md
Normal file
8
param-docs/parameter-pages/DataLogging/DataLogActive.md
Normal 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!
|
||||
16
param-docs/parameter-pages/Debug/LogLevel.md
Normal file
16
param-docs/parameter-pages/Debug/LogLevel.md
Normal 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!
|
||||
6
param-docs/parameter-pages/Debug/LogfilesRetention.md
Normal file
6
param-docs/parameter-pages/Debug/LogfilesRetention.md
Normal file
@@ -0,0 +1,6 @@
|
||||
# Parameter `LogfilesRetention`
|
||||
Default Value: `3`
|
||||
|
||||
Unit: Days
|
||||
|
||||
Number of days to keep the log files (`0` = forever).
|
||||
10
param-docs/parameter-pages/Digits/CNNGoodThreshold.md
Normal file
10
param-docs/parameter-pages/Digits/CNNGoodThreshold.md
Normal 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!
|
||||
4
param-docs/parameter-pages/Digits/Model.md
Normal file
4
param-docs/parameter-pages/Digits/Model.md
Normal 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.
|
||||
7
param-docs/parameter-pages/Digits/ROIImagesLocation.md
Normal file
7
param-docs/parameter-pages/Digits/ROIImagesLocation.md
Normal 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
Reference in New Issue
Block a user