mirror of
https://github.com/jomjol/AI-on-the-edge-device.git
synced 2025-12-07 12:06:58 +03:00
Compare commits
221 Commits
v15.1.0
...
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 | ||
|
|
ba7d6b3621 | ||
|
|
d4a492463b | ||
|
|
46589288e7 | ||
|
|
81a57d32a8 | ||
|
|
17994494c9 | ||
|
|
c581d64a26 | ||
|
|
70c2b88f8a | ||
|
|
13d01a6c96 | ||
|
|
331e3533cc | ||
|
|
5a00bdd7f6 | ||
|
|
db7ffb30c4 | ||
|
|
9a07f271ff | ||
|
|
6a45ab7693 | ||
|
|
9fc876853b | ||
|
|
c30881f73c | ||
|
|
e75e720869 | ||
|
|
43aae5a3cd | ||
|
|
54cd7e511a | ||
|
|
c5a82e839f | ||
|
|
9f97a2b223 | ||
|
|
8d06de5792 | ||
|
|
1326585a33 | ||
|
|
d7a507ca05 | ||
|
|
b24b7d5ce2 | ||
|
|
fc719da0ae | ||
|
|
9b1a83c8b4 | ||
|
|
6defcf8d4c | ||
|
|
c2a55e7c86 | ||
|
|
a636ce3679 | ||
|
|
a20fec1094 | ||
|
|
929796c87f | ||
|
|
e40ceb54ce | ||
|
|
eebdd7c6eb | ||
|
|
2a7f3b33a3 | ||
|
|
262d83ee6f | ||
|
|
de92c29245 | ||
|
|
19158c998f | ||
|
|
17ffd28c05 | ||
|
|
9ca02e0a7f | ||
|
|
7488d7bf23 | ||
|
|
e7bfba4b01 | ||
|
|
63ac38a52d | ||
|
|
e2cf8337d4 | ||
|
|
e995d6c498 | ||
|
|
0e3a50d0c1 | ||
|
|
df12deae00 | ||
|
|
b6bfeea936 | ||
|
|
f79e03faa2 | ||
|
|
de1dcc4d06 | ||
|
|
33bfef0af4 | ||
|
|
727b871fc5 | ||
|
|
03c84a1ff3 | ||
|
|
db36fe2522 | ||
|
|
9ffaf6e3f8 | ||
|
|
fa09680711 | ||
|
|
e2b66aa73a | ||
|
|
c4b990ada0 | ||
|
|
267782d083 | ||
|
|
e4a6fd33fe | ||
|
|
5db20d3687 | ||
|
|
58185a0569 | ||
|
|
b5e0d6ee66 | ||
|
|
d93c5daf14 | ||
|
|
6ff83445ac | ||
|
|
d944e8676b | ||
|
|
a8d7b29507 | ||
|
|
ab0fc72257 | ||
|
|
933215c116 | ||
|
|
e81a7eebe8 | ||
|
|
863856ca5d | ||
|
|
eefc41d6ff | ||
|
|
d1807a1b3d | ||
|
|
dfc45772b7 | ||
|
|
4dd41c486f | ||
|
|
ff81fcbd7f | ||
|
|
5e5d2e2f72 | ||
|
|
512d7f95b4 |
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
|
||||
|
||||
9
.gitmodules
vendored
9
.gitmodules
vendored
@@ -4,6 +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
|
||||
|
||||
146
Changelog.md
146
Changelog.md
@@ -1,3 +1,145 @@
|
||||
## [15.6.0] - 2024-02-09
|
||||
|
||||
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)
|
||||
|
||||
#### Changed
|
||||
- Updated PlatformIO to `6.2.0`
|
||||
- [#2376](https://github.com/jomjol/AI-on-the-edge-device/pull/2376) Improve logging if Autostart is not enabled
|
||||
|
||||
#### Fixed
|
||||
- [#2373](https://github.com/jomjol/AI-on-the-edge-device/pull/2373) Allow the Alignment Mark step while status is "Initializing" or "Initialization (delayed)" or while in setup mode
|
||||
- [#2381](https://github.com/jomjol/AI-on-the-edge-device/pull/2381) Fix broken sysinfo REST API
|
||||
|
||||
|
||||
## [15.2.1] - 2023-04-27
|
||||
|
||||
### Changes
|
||||
|
||||
For a full list of changes see [Full list of changes](https://github.com/jomjol/AI-on-the-edge-device/compare/v15.2.0...v15.2.1)
|
||||
|
||||
#### Fixed
|
||||
- [#2357](https://github.com/jomjol/AI-on-the-edge-device/pull/2357) Fix Alignment Mark issue
|
||||
|
||||
|
||||
## [15.2.0] - 2023-04-23
|
||||
|
||||
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
|
||||
|
||||
- [#2286](https://github.com/jomjol/AI-on-the-edge-device/pull/2286) Implement a camera livestream handler
|
||||
- [#2252](https://github.com/jomjol/AI-on-the-edge-device/pull/2252) Set prevalue using MQTT + set prevalue to RAW value (REST+MQTT)
|
||||
- [#2319](https://github.com/jomjol/AI-on-the-edge-device/pull/2319) Extend InfluxDBv1 with individual topic names
|
||||
|
||||
#### Changed
|
||||
|
||||
- [#2285](https://github.com/jomjol/AI-on-the-edge-device/pull/2285) Re-implemented PSRAM usage
|
||||
- [#2325](https://github.com/jomjol/AI-on-the-edge-device/pull/2325) Keep MainFlowTask alive to handle reboot
|
||||
- [#2233](https://github.com/jomjol/AI-on-the-edge-device/pull/2233) Remove trailing slash in influxDBv1
|
||||
- [#2305](https://github.com/jomjol/AI-on-the-edge-device/pull/2305) Migration of PlatformIO `5.2.0` to `6.1.0` (resp. ESP IDF from `4.4.2` to `5.0.1`)
|
||||
- Various cleanup and refactoring
|
||||
|
||||
#### Fixed
|
||||
|
||||
- [#2326](https://github.com/jomjol/AI-on-the-edge-device/pull/2326) Activate save button after Analogue ROI creationSet prevalue using MQTT + set prevalue to RAW value (REST+MQTT)
|
||||
- [#2283](https://github.com/jomjol/AI-on-the-edge-device/pull/2283) Fix Timezone issues on InfluxDB
|
||||
- Various minor fixes
|
||||
|
||||
#### Removed
|
||||
|
||||
- n.a.
|
||||
|
||||
|
||||
## [15.1.1] - 2023-03-23
|
||||
|
||||
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
|
||||
|
||||
- [#2206](https://github.com/jomjol/AI-on-the-edge-device/pull/2206) Log PSRAM usage
|
||||
- [#2216](https://github.com/jomjol/AI-on-the-edge-device/pull/2216) Log MQTT connection refused reasons
|
||||
|
||||
#### Changed
|
||||
|
||||
- n.a.
|
||||
|
||||
#### Fixed
|
||||
|
||||
- [#2224](https://github.com/jomjol/AI-on-the-edge-device/pull/2224), [#2213](https://github.com/jomjol/AI-on-the-edge-device/pull/2213) Reverted some of the PSRAM usage changes due to negative sideffects
|
||||
- [#2203](https://github.com/jomjol/AI-on-the-edge-device/issues/2203) Correct API for pure InfluxDB v1
|
||||
- [#2180](https://github.com/jomjol/AI-on-the-edge-device/pull/2180) Fixed links in Parameter Documentation
|
||||
- Various minor fixes
|
||||
|
||||
#### Removed
|
||||
|
||||
- n.a.
|
||||
|
||||
## [15.1.0] - 2023-03-12
|
||||
|
||||
### Update Procedure
|
||||
@@ -903,6 +1045,10 @@ External Illumination
|
||||
- Initial Version
|
||||
|
||||
|
||||
[15.2.4]: https://github.com/jomjol/AI-on-the-edge-device/compare/v15.2.1...v15.2.4
|
||||
[15.2.1]: https://github.com/jomjol/AI-on-the-edge-device/compare/v15.2.0...v15.2.1
|
||||
[15.2.0]: https://github.com/jomjol/AI-on-the-edge-device/compare/v15.1.1...v15.2.0
|
||||
[15.1.1]: https://github.com/jomjol/AI-on-the-edge-device/compare/v15.1.0...v15.1.1
|
||||
[15.1.0]: https://github.com/jomjol/AI-on-the-edge-device/compare/v15.0.3...v15.1.0
|
||||
[15.0.3]: https://github.com/jomjol/AI-on-the-edge-device/compare/v14.0.3...v15.0.3
|
||||
[14.0.3]: https://github.com/jomjol/AI-on-the-edge-device/compare/v13.0.8...v14.0.3
|
||||
|
||||
@@ -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
@@ -1,5 +1,32 @@
|
||||
#include "SmartLeds.h"
|
||||
|
||||
|
||||
/* PlatformIO 6 (ESP IDF 5) does no longer allow access to RMTMEM,
|
||||
see https://docs.espressif.com/projects/esp-idf/en/latest/esp32/migration-guides/release-5.x/5.0/peripherals.html?highlight=rmtmem#id5
|
||||
As a dirty workaround, we copy the needed structures from rmt_struct.h
|
||||
In the long run, this should be replaced! */
|
||||
typedef struct rmt_item32_s {
|
||||
union {
|
||||
struct {
|
||||
uint32_t duration0 :15;
|
||||
uint32_t level0 :1;
|
||||
uint32_t duration1 :15;
|
||||
uint32_t level1 :1;
|
||||
};
|
||||
uint32_t val;
|
||||
};
|
||||
} rmt_item32_t;
|
||||
|
||||
//Allow access to RMT memory using RMTMEM.chan[0].data32[8]
|
||||
typedef volatile struct rmt_mem_s {
|
||||
struct {
|
||||
rmt_item32_t data32[64];
|
||||
} chan[8];
|
||||
} rmt_mem_t;
|
||||
extern rmt_mem_t RMTMEM;
|
||||
|
||||
|
||||
|
||||
IsrCore SmartLed::_interruptCore = CoreCurrent;
|
||||
intr_handle_t SmartLed::_interruptHandle = NULL;
|
||||
|
||||
|
||||
@@ -35,6 +35,20 @@
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
|
||||
#include "esp_idf_version.h"
|
||||
#if (ESP_IDF_VERSION_MAJOR >= 5)
|
||||
#include "soc/periph_defs.h"
|
||||
#include "esp_private/periph_ctrl.h"
|
||||
#include "soc/gpio_sig_map.h"
|
||||
#include "soc/gpio_periph.h"
|
||||
#include "soc/io_mux_reg.h"
|
||||
#include "esp_rom_gpio.h"
|
||||
#define gpio_pad_select_gpio esp_rom_gpio_pad_select_gpio
|
||||
#define gpio_matrix_in(a,b,c) esp_rom_gpio_connect_in_signal(a,b,c)
|
||||
#define gpio_matrix_out(a,b,c,d) esp_rom_gpio_connect_out_signal(a,b,c,d)
|
||||
#define ets_delay_us(a) esp_rom_delay_us(a)
|
||||
#endif
|
||||
|
||||
#if defined ( ARDUINO )
|
||||
extern "C" { // ...someone forgot to put in the includes...
|
||||
#include "esp32-hal.h"
|
||||
@@ -65,6 +79,27 @@
|
||||
#include <stdio.h>
|
||||
#endif
|
||||
|
||||
#if (ESP_IDF_VERSION_MAJOR >= 4) && (ESP_IDF_VERSION_MINOR > 1)
|
||||
#include "hal/gpio_ll.h"
|
||||
#else
|
||||
#include "soc/gpio_periph.h"
|
||||
#define esp_rom_delay_us ets_delay_us
|
||||
static inline int gpio_ll_get_level(gpio_dev_t *hw, int gpio_num)
|
||||
{
|
||||
if (gpio_num < 32) {
|
||||
return (hw->in >> gpio_num) & 0x1;
|
||||
} else {
|
||||
return (hw->in1.data >> (gpio_num - 32)) & 0x1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(5, 0, 0))
|
||||
#if !(configENABLE_BACKWARD_COMPATIBILITY == 1)
|
||||
#define xSemaphoreHandle SemaphoreHandle_t
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include "Color.h"
|
||||
|
||||
namespace detail {
|
||||
|
||||
@@ -6,9 +6,6 @@
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_system.h"
|
||||
#include "esp_event.h"
|
||||
|
||||
#include "server_tflite.h"
|
||||
|
||||
#include "esp_log.h"
|
||||
|
||||
@@ -22,8 +19,10 @@
|
||||
#include "ClassLogFile.h"
|
||||
#include "configFile.h"
|
||||
#include "Helper.h"
|
||||
|
||||
#ifdef ENABLE_MQTT
|
||||
#include "interface_mqtt.h"
|
||||
#include "interface_mqtt.h"
|
||||
#include "server_mqtt.h"
|
||||
#endif //ENABLE_MQTT
|
||||
|
||||
|
||||
@@ -331,7 +330,7 @@ bool GpioHandler::readConfig()
|
||||
|
||||
#ifdef ENABLE_MQTT
|
||||
// std::string mainTopicMQTT = "";
|
||||
std::string mainTopicMQTT = GetMQTTMainTopic();
|
||||
std::string mainTopicMQTT = mqttServer_getMainTopic();
|
||||
if (mainTopicMQTT.length() > 0)
|
||||
{
|
||||
mainTopicMQTT = mainTopicMQTT + "/GPIO";
|
||||
|
||||
@@ -4,6 +4,6 @@ list(APPEND EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/proto
|
||||
|
||||
idf_component_register(SRCS ${app_sources}
|
||||
INCLUDE_DIRS "."
|
||||
REQUIRES esp32-camera esp_http_server jomjol_logfile jomjol_image_proc nvs_flash jomjol_fileserver_ota jomjol_controlGPIO)
|
||||
REQUIRES esp_timer esp32-camera esp_http_server jomjol_logfile jomjol_image_proc nvs_flash jomjol_fileserver_ota jomjol_controlGPIO)
|
||||
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include <nvs_flash.h>
|
||||
#include <sys/param.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
@@ -28,10 +29,31 @@
|
||||
#include "esp_camera.h"
|
||||
|
||||
#include "driver/ledc.h"
|
||||
#include "server_tflite.h"
|
||||
#include "MainFlowControl.h"
|
||||
|
||||
#if (ESP_IDF_VERSION_MAJOR >= 5)
|
||||
#include "soc/periph_defs.h"
|
||||
#include "esp_private/periph_ctrl.h"
|
||||
#include "soc/gpio_sig_map.h"
|
||||
#include "soc/gpio_periph.h"
|
||||
#include "soc/io_mux_reg.h"
|
||||
#include "esp_rom_gpio.h"
|
||||
#define gpio_pad_select_gpio esp_rom_gpio_pad_select_gpio
|
||||
#define gpio_matrix_in(a,b,c) esp_rom_gpio_connect_in_signal(a,b,c)
|
||||
#define gpio_matrix_out(a,b,c,d) esp_rom_gpio_connect_out_signal(a,b,c,d)
|
||||
#define ets_delay_us(a) esp_rom_delay_us(a)
|
||||
#endif
|
||||
|
||||
static const char *TAG = "CAM";
|
||||
|
||||
|
||||
/* Camera live stream */
|
||||
#define PART_BOUNDARY "123456789000000000000987654321"
|
||||
static const char* _STREAM_CONTENT_TYPE = "multipart/x-mixed-replace;boundary=" PART_BOUNDARY;
|
||||
static const char* _STREAM_BOUNDARY = "\r\n--" PART_BOUNDARY "\r\n";
|
||||
static const char* _STREAM_PART = "Content-Type: image/jpeg\r\nContent-Length: %u\r\n\r\n";
|
||||
|
||||
|
||||
static camera_config_t camera_config = {
|
||||
.pin_pwdn = CAM_PIN_PWDN,
|
||||
.pin_reset = CAM_PIN_RESET,
|
||||
@@ -311,7 +333,7 @@ esp_err_t CCamera::CaptureToBasisImage(CImageBasis *_Image, int delay)
|
||||
loadNextDemoImage(fb);
|
||||
}
|
||||
|
||||
CImageBasis* _zwImage = new CImageBasis();
|
||||
CImageBasis* _zwImage = new CImageBasis("zwImage");
|
||||
if (_zwImage) {
|
||||
_zwImage->LoadFromMemory(fb->buf, fb->len);
|
||||
}
|
||||
@@ -512,7 +534,7 @@ esp_err_t CCamera::CaptureToHTTP(httpd_req_t *req, int delay)
|
||||
esp_camera_fb_return(fb);
|
||||
int64_t fr_end = esp_timer_get_time();
|
||||
|
||||
ESP_LOGI(TAG, "JPG: %uKB %ums", (uint32_t)(fb_len/1024), (uint32_t)((fr_end - fr_start)/1000));
|
||||
ESP_LOGI(TAG, "JPG: %dKB %dms", (int)(fb_len/1024), (int)((fr_end - fr_start)/1000));
|
||||
|
||||
if (delay > 0)
|
||||
LightOnOff(false);
|
||||
@@ -521,6 +543,74 @@ esp_err_t CCamera::CaptureToHTTP(httpd_req_t *req, int delay)
|
||||
}
|
||||
|
||||
|
||||
esp_err_t CCamera::CaptureToStream(httpd_req_t *req, bool FlashlightOn)
|
||||
{
|
||||
esp_err_t res = ESP_OK;
|
||||
size_t fb_len = 0;
|
||||
int64_t fr_start;
|
||||
char * part_buf[64];
|
||||
|
||||
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Live stream started");
|
||||
|
||||
if (FlashlightOn) {
|
||||
LEDOnOff(true);
|
||||
LightOnOff(true);
|
||||
}
|
||||
|
||||
//httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*"); //stream is blocking web interface, only serving to local
|
||||
|
||||
httpd_resp_set_type(req, _STREAM_CONTENT_TYPE);
|
||||
httpd_resp_send_chunk(req, _STREAM_BOUNDARY, strlen(_STREAM_BOUNDARY));
|
||||
|
||||
while(1)
|
||||
{
|
||||
fr_start = esp_timer_get_time();
|
||||
camera_fb_t *fb = esp_camera_fb_get();
|
||||
esp_camera_fb_return(fb);
|
||||
fb = esp_camera_fb_get();
|
||||
if (!fb) {
|
||||
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "CaptureToStream: Camera framebuffer not available");
|
||||
break;
|
||||
}
|
||||
fb_len = fb->len;
|
||||
|
||||
if (res == ESP_OK){
|
||||
size_t hlen = snprintf((char *)part_buf, sizeof(part_buf), _STREAM_PART, fb_len);
|
||||
res = httpd_resp_send_chunk(req, (const char *)part_buf, hlen);
|
||||
}
|
||||
if (res == ESP_OK){
|
||||
res = httpd_resp_send_chunk(req, (const char *)fb->buf, fb_len);
|
||||
}
|
||||
if (res == ESP_OK){
|
||||
res = httpd_resp_send_chunk(req, _STREAM_BOUNDARY, strlen(_STREAM_BOUNDARY));
|
||||
}
|
||||
|
||||
esp_camera_fb_return(fb);
|
||||
|
||||
int64_t fr_end = esp_timer_get_time();
|
||||
ESP_LOGD(TAG, "JPG: %dKB %dms", (int)(fb_len/1024), (int)((fr_end - fr_start)/1000));
|
||||
|
||||
if (res != ESP_OK){ // Exit loop, e.g. also when closing the webpage
|
||||
break;
|
||||
}
|
||||
|
||||
int64_t fr_delta_ms = (fr_end - fr_start) / 1000;
|
||||
if (CAM_LIVESTREAM_REFRESHRATE > fr_delta_ms) {
|
||||
const TickType_t xDelay = (CAM_LIVESTREAM_REFRESHRATE - fr_delta_ms) / portTICK_PERIOD_MS;
|
||||
ESP_LOGD(TAG, "Stream: sleep for: %ldms", (long) xDelay*10);
|
||||
vTaskDelay(xDelay);
|
||||
}
|
||||
}
|
||||
|
||||
LEDOnOff(false);
|
||||
LightOnOff(false);
|
||||
|
||||
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Live stream stopped");
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
void CCamera::LightOnOff(bool status)
|
||||
{
|
||||
GpioHandler* gpioHandler = gpio_handler_get();
|
||||
|
||||
@@ -40,6 +40,7 @@ class CCamera {
|
||||
void LightOnOff(bool status);
|
||||
void LEDOnOff(bool status);
|
||||
esp_err_t CaptureToHTTP(httpd_req_t *req, int delay = 0);
|
||||
esp_err_t CaptureToStream(httpd_req_t *req, bool FlashlightOn);
|
||||
void SetQualitySize(int qual, framesize_t resol);
|
||||
bool SetBrightnessContrastSaturation(int _brightness, int _contrast, int _saturation);
|
||||
void GetCameraParameter(httpd_req_t *req, int &qual, framesize_t &resol);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
FILE(GLOB_RECURSE app_sources ${CMAKE_CURRENT_SOURCE_DIR}/*.*)
|
||||
|
||||
idf_component_register(SRCS ${app_sources}
|
||||
INCLUDE_DIRS "." "../../include"
|
||||
REQUIRES tflite-lib esp_http_server app_update esp_http_client nvs_flash jomjol_tfliteclass jomjol_flowcontroll spiffs jomjol_helper jomjol_controlGPIO miniz)
|
||||
INCLUDE_DIRS "." "../../include" "miniz"
|
||||
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
|
||||
@@ -36,7 +36,7 @@ extern "C" {
|
||||
#include "../../include/defines.h"
|
||||
#include "ClassLogFile.h"
|
||||
|
||||
#include "server_tflite.h"
|
||||
#include "MainFlowControl.h"
|
||||
|
||||
#include "server_help.h"
|
||||
#ifdef ENABLE_MQTT
|
||||
@@ -47,7 +47,6 @@ extern "C" {
|
||||
#include "Helper.h"
|
||||
#include "miniz.h"
|
||||
|
||||
|
||||
static const char *TAG = "OTA FILE";
|
||||
|
||||
struct file_server_data {
|
||||
@@ -74,7 +73,7 @@ static esp_err_t send_datafile(httpd_req_t *req, bool send_full_file);
|
||||
|
||||
esp_err_t get_numbers_file_handler(httpd_req_t *req)
|
||||
{
|
||||
std::string ret = tfliteflow.getNumbersName();
|
||||
std::string ret = flowctrl.getNumbersName();
|
||||
|
||||
// ESP_LOGI(TAG, "Result get_numbers_file_handler: %s", ret.c_str());
|
||||
|
||||
@@ -548,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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -589,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!");
|
||||
@@ -607,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;
|
||||
}
|
||||
|
||||
@@ -718,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("/");
|
||||
@@ -737,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;
|
||||
}
|
||||
@@ -838,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("/");
|
||||
@@ -864,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;
|
||||
@@ -930,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;
|
||||
{
|
||||
@@ -994,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);
|
||||
@@ -1098,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());
|
||||
|
||||
@@ -3,7 +3,10 @@
|
||||
#include <string>
|
||||
#include "string.h"
|
||||
|
||||
#include <esp_int_wdt.h>
|
||||
/* TODO Rethink the usage of the int watchdog. It is no longer to be used, see
|
||||
https://docs.espressif.com/projects/esp-idf/en/latest/esp32/migration-guides/release-5.x/5.0/system.html?highlight=esp_int_wdt */
|
||||
#include "esp_private/esp_int_wdt.h"
|
||||
|
||||
#include <esp_task_wdt.h>
|
||||
|
||||
|
||||
@@ -11,14 +14,13 @@
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_system.h"
|
||||
#include "esp_event.h"
|
||||
#include "esp_event.h"
|
||||
#include "esp_log.h"
|
||||
#include <esp_ota_ops.h>
|
||||
#include "esp_http_client.h"
|
||||
#include "esp_flash_partitions.h"
|
||||
#include "esp_partition.h"
|
||||
#include <nvs.h>
|
||||
#include "esp_app_format.h"
|
||||
#include "nvs_flash.h"
|
||||
#include "driver/gpio.h"
|
||||
// #include "protocol_examples_common.h"
|
||||
@@ -26,7 +28,7 @@
|
||||
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "server_tflite.h"
|
||||
#include "MainFlowControl.h"
|
||||
#include "server_file.h"
|
||||
#include "server_GPIO.h"
|
||||
#ifdef ENABLE_MQTT
|
||||
@@ -157,12 +159,12 @@ static bool ota_update_task(std::string fn)
|
||||
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "(This can happen if either the OTA boot data or preferred boot image become somehow corrupted.)");
|
||||
}
|
||||
ESP_LOGI(TAG, "Running partition type %d subtype %d (offset 0x%08x)",
|
||||
running->type, running->subtype, running->address);
|
||||
running->type, running->subtype, (unsigned int)running->address);
|
||||
|
||||
|
||||
update_partition = esp_ota_get_next_update_partition(NULL);
|
||||
ESP_LOGI(TAG, "Writing to partition subtype %d at offset 0x%x",
|
||||
update_partition->subtype, update_partition->address);
|
||||
update_partition->subtype, (unsigned int)update_partition->address);
|
||||
// assert(update_partition != NULL);
|
||||
|
||||
int binary_file_length = 0;
|
||||
@@ -467,7 +469,7 @@ esp_err_t handler_ota_update(httpd_req_t *req)
|
||||
{
|
||||
const char* resp_str;
|
||||
|
||||
KillTFliteTasks();
|
||||
DeleteMainFlowTask();
|
||||
gpio_handler_deinit();
|
||||
if (ota_update_task(fn))
|
||||
{
|
||||
@@ -546,7 +548,7 @@ esp_err_t handler_ota_update(httpd_req_t *req)
|
||||
/*
|
||||
const char* resp_str;
|
||||
|
||||
KillTFliteTasks();
|
||||
DeleteMainFlowTask();
|
||||
gpio_handler_deinit();
|
||||
if (ota_update_task(fn))
|
||||
{
|
||||
@@ -570,13 +572,19 @@ esp_err_t handler_ota_update(httpd_req_t *req)
|
||||
|
||||
void hard_restart()
|
||||
{
|
||||
esp_task_wdt_init(1,true);
|
||||
esp_task_wdt_config_t twdt_config = {
|
||||
.timeout_ms = 1,
|
||||
.idle_core_mask = (1 << portNUM_PROCESSORS) - 1, // Bitmask of all cores
|
||||
.trigger_panic = true,
|
||||
};
|
||||
ESP_ERROR_CHECK(esp_task_wdt_init(&twdt_config));
|
||||
|
||||
esp_task_wdt_add(NULL);
|
||||
while(true);
|
||||
}
|
||||
|
||||
|
||||
void task_reboot(void *KillAutoFlow)
|
||||
void task_reboot(void *DeleteMainFlow)
|
||||
{
|
||||
// write a reboot, to identify a reboot by purpouse
|
||||
FILE* pfile = fopen("/sdcard/reboot.txt", "w");
|
||||
@@ -586,8 +594,8 @@ void task_reboot(void *KillAutoFlow)
|
||||
|
||||
vTaskDelay(3000 / portTICK_PERIOD_MS);
|
||||
|
||||
if ((bool)KillAutoFlow) {
|
||||
KillTFliteTasks(); // Kill autoflow task if executed in extra task, if not don't kill parent task
|
||||
if ((bool)DeleteMainFlow) {
|
||||
DeleteMainFlowTask(); // Kill autoflow task if executed in extra task, if not don't kill parent task
|
||||
}
|
||||
|
||||
Camera.LightOnOff(false);
|
||||
@@ -617,7 +625,7 @@ void doReboot()
|
||||
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Reboot triggered by Software (5s)");
|
||||
LogFile.WriteToFile(ESP_LOG_WARN, TAG, "Reboot in 5sec");
|
||||
|
||||
BaseType_t xReturned = xTaskCreate(&task_reboot, "task_reboot", configMINIMAL_STACK_SIZE * 3, (void*) true, 10, NULL);
|
||||
BaseType_t xReturned = xTaskCreate(&task_reboot, "task_reboot", configMINIMAL_STACK_SIZE * 4, (void*) true, 10, NULL);
|
||||
if( xReturned != pdPASS )
|
||||
{
|
||||
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "task_reboot not created -> force reboot without killing flow");
|
||||
|
||||
@@ -2,6 +2,6 @@ FILE(GLOB_RECURSE app_sources ${CMAKE_CURRENT_SOURCE_DIR}/*.*)
|
||||
|
||||
idf_component_register(SRCS ${app_sources}
|
||||
INCLUDE_DIRS "."
|
||||
REQUIRES jomjol_tfliteclass jomjol_helper jomjol_controlcamera jomjol_mqtt jomjol_influxdb jomjol_fileserver_ota jomjol_image_proc jomjol_wlan)
|
||||
REQUIRES esp_timer esp_wifi jomjol_tfliteclass jomjol_helper jomjol_controlcamera jomjol_mqtt jomjol_influxdb jomjol_fileserver_ota jomjol_image_proc jomjol_wlan)
|
||||
|
||||
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
#include "ClassFlowAlignment.h"
|
||||
#include "ClassFlowTakeImage.h"
|
||||
#include "ClassFlow.h"
|
||||
#include "server_tflite.h"
|
||||
#include "MainFlowControl.h"
|
||||
|
||||
#include "CRotateImage.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
|
||||
#include "ClassLogFile.h"
|
||||
#include "psram.h"
|
||||
#include "../../include/defines.h"
|
||||
|
||||
|
||||
@@ -31,7 +32,7 @@ void ClassFlowAlignment::SetInitialParameter(void)
|
||||
ImageBasis = NULL;
|
||||
ImageTMP = NULL;
|
||||
#ifdef ALGROI_LOAD_FROM_MEM_AS_JPG
|
||||
AlgROI = (ImageData*)heap_caps_malloc(sizeof(ImageData), MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM);
|
||||
AlgROI = (ImageData*)malloc_psram_heap(std::string(TAG) + "->AlgROI", sizeof(ImageData), MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM);
|
||||
#endif
|
||||
previousElement = NULL;
|
||||
disabled = false;
|
||||
@@ -55,7 +56,7 @@ ClassFlowAlignment::ClassFlowAlignment(std::vector<ClassFlow*>* lfc)
|
||||
if (!ImageBasis) // the function take pictures does not exist --> must be created first ONLY FOR TEST PURPOSES
|
||||
{
|
||||
ESP_LOGD(TAG, "CImageBasis had to be created");
|
||||
ImageBasis = new CImageBasis(namerawimage);
|
||||
ImageBasis = new CImageBasis("ImageBasis", namerawimage);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -189,17 +190,17 @@ bool ClassFlowAlignment::doFlow(string time)
|
||||
|
||||
if (!ImageTMP)
|
||||
{
|
||||
ImageTMP = new CImageBasis(ImageBasis);
|
||||
ImageTMP = new CImageBasis("tmpImage", ImageBasis); // Make sure the name does not get change, it is relevant for the PSRAM allocation!
|
||||
if (!ImageTMP)
|
||||
{
|
||||
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Can't allocate ImageTMP -> Exec this round aborted!");
|
||||
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Can't allocate tmpImage -> Exec this round aborted!");
|
||||
LogFile.WriteHeapInfo("ClassFlowAlignment-doFlow");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
delete AlignAndCutImage;
|
||||
AlignAndCutImage = new CAlignAndCutImage(ImageBasis, ImageTMP);
|
||||
AlignAndCutImage = new CAlignAndCutImage("AlignAndCutImage", ImageBasis, ImageTMP);
|
||||
if (!AlignAndCutImage)
|
||||
{
|
||||
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Can't allocate AlignAndCutImage -> Exec this round aborted!");
|
||||
@@ -207,7 +208,7 @@ bool ClassFlowAlignment::doFlow(string time)
|
||||
return false;
|
||||
}
|
||||
|
||||
CRotateImage rt(AlignAndCutImage, ImageTMP, initialflip);
|
||||
CRotateImage rt("rawImage", AlignAndCutImage, ImageTMP, initialflip);
|
||||
if (initialflip)
|
||||
{
|
||||
int _zw = ImageBasis->height;
|
||||
@@ -255,8 +256,8 @@ bool ClassFlowAlignment::doFlow(string time)
|
||||
if(References[0].alignment_algo != 3){
|
||||
DrawRef(ImageTMP);
|
||||
}
|
||||
tfliteflow.DigitalDrawROI(ImageTMP);
|
||||
tfliteflow.AnalogDrawROI(ImageTMP);
|
||||
flowctrl.DigitalDrawROI(ImageTMP);
|
||||
flowctrl.AnalogDrawROI(ImageTMP);
|
||||
ImageTMP->writeToMemoryAsJPG((ImageData*)AlgROI, 90);
|
||||
}
|
||||
#endif
|
||||
|
||||
@@ -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));
|
||||
@@ -374,15 +389,20 @@ bool ClassFlowCNNGeneral::ReadParameter(FILE* pfile, string& aktparamgraph)
|
||||
}
|
||||
}
|
||||
|
||||
if (!getNetworkParameter())
|
||||
if (!getNetworkParameter()) {
|
||||
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "An error occured on setting up the Network -> Disabling it!");
|
||||
disabled = true; // An error occured, disable this CNN!
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
for (int _ana = 0; _ana < GENERAL.size(); ++_ana)
|
||||
for (int i = 0; i < GENERAL[_ana]->ROI.size(); ++i)
|
||||
{
|
||||
GENERAL[_ana]->ROI[i]->image = new CImageBasis(modelxsize, modelysize, modelchannel);
|
||||
GENERAL[_ana]->ROI[i]->image_org = new CImageBasis(GENERAL[_ana]->ROI[i]->deltax, GENERAL[_ana]->ROI[i]->deltay, 3);
|
||||
GENERAL[_ana]->ROI[i]->image = new CImageBasis("ROI " + GENERAL[_ana]->ROI[i]->name,
|
||||
modelxsize, modelysize, modelchannel);
|
||||
GENERAL[_ana]->ROI[i]->image_org = new CImageBasis("ROI " + GENERAL[_ana]->ROI[i]->name + " original",
|
||||
GENERAL[_ana]->ROI[i]->deltax, GENERAL[_ana]->ROI[i]->deltay, 3);
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -480,7 +500,7 @@ bool ClassFlowCNNGeneral::doFlow(string time)
|
||||
|
||||
if (!doAlignAndCut(time)){
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "doFlow after alignment");
|
||||
|
||||
@@ -848,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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -25,10 +25,10 @@ extern "C" {
|
||||
#endif //ENABLE_MQTT
|
||||
|
||||
#include "server_help.h"
|
||||
#include "server_tflite.h"
|
||||
#include "MainFlowControl.h"
|
||||
#include "../../include/defines.h"
|
||||
|
||||
static const char* TAG = "CTRL";
|
||||
static const char* TAG = "FLOWCTRL";
|
||||
|
||||
//#define DEBUG_DETAIL_ON
|
||||
|
||||
@@ -99,8 +99,6 @@ std::string ClassFlowControll::TranslateAktstatus(std::string _input)
|
||||
#endif //ENABLE_INFLUXDB
|
||||
if (_input.compare("ClassFlowPostProcessing") == 0)
|
||||
return ("Post-Processing");
|
||||
if (_input.compare("ClassFlowWriteList") == 0)
|
||||
return ("Writing List");
|
||||
|
||||
return "Unkown Status";
|
||||
}
|
||||
@@ -164,16 +162,8 @@ void ClassFlowControll::AnalogDrawROI(CImageBasis *_zw)
|
||||
|
||||
|
||||
#ifdef ENABLE_MQTT
|
||||
string ClassFlowControll::GetMQTTMainTopic()
|
||||
bool ClassFlowControll::StartMQTTService()
|
||||
{
|
||||
for (int i = 0; i < FlowControll.size(); ++i)
|
||||
if (FlowControll[i]->name().compare("ClassFlowMQTT") == 0)
|
||||
return ((ClassFlowMQTT*) (FlowControll[i]))->GetMQTTMainTopic();
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
bool ClassFlowControll::StartMQTTService() {
|
||||
/* Start the MQTT service */
|
||||
for (int i = 0; i < FlowControll.size(); ++i) {
|
||||
if (FlowControll[i]->name().compare("ClassFlowMQTT") == 0) {
|
||||
@@ -200,10 +190,15 @@ void ClassFlowControll::SetInitialParameter(void)
|
||||
}
|
||||
|
||||
|
||||
bool ClassFlowControll::isAutoStart(long &_interval)
|
||||
bool ClassFlowControll::getIsAutoStart(void)
|
||||
{
|
||||
return AutoStart;
|
||||
}
|
||||
|
||||
|
||||
void ClassFlowControll::setAutoStartInterval(long &_interval)
|
||||
{
|
||||
_interval = AutoInterval * 60 * 1000; // AutoInterval: minutes -> ms
|
||||
return AutoStart;
|
||||
}
|
||||
|
||||
|
||||
@@ -243,8 +238,6 @@ ClassFlow* ClassFlowControll::CreateClassFlow(std::string _type)
|
||||
if (toUpper(_type).compare("[INFLUXDBV2]") == 0)
|
||||
cfc = new ClassFlowInfluxDBv2(&FlowControll);
|
||||
#endif //ENABLE_INFLUXDB
|
||||
if (toUpper(_type).compare("[WRITELIST]") == 0)
|
||||
cfc = new ClassFlowWriteList(&FlowControll);
|
||||
|
||||
if (toUpper(_type).compare("[POSTPROCESSING]") == 0)
|
||||
{
|
||||
@@ -385,7 +378,7 @@ bool ClassFlowControll::doFlow(string time)
|
||||
zw_time = getCurrentTimeString("%H:%M:%S");
|
||||
aktstatus = TranslateAktstatus(FlowControll[i]->name());
|
||||
aktstatusWithTime = aktstatus + " (" + zw_time + ")";
|
||||
//LogFile.WriteToFile(ESP_LOG_INFO, TAG, aktstatusWithTime);
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Status: " + aktstatusWithTime);
|
||||
#ifdef ENABLE_MQTT
|
||||
MQTTPublish(mqttServer_getMainTopic() + "/" + "status", aktstatus, qos, false);
|
||||
#endif //ENABLE_MQTT
|
||||
@@ -470,10 +463,10 @@ string ClassFlowControll::getReadoutAll(int _type)
|
||||
}
|
||||
|
||||
|
||||
string ClassFlowControll::getReadout(bool _rawvalue = false, bool _noerror = false)
|
||||
string ClassFlowControll::getReadout(bool _rawvalue = false, bool _noerror = false, int _number = 0)
|
||||
{
|
||||
if (flowpostprocessing)
|
||||
return flowpostprocessing->getReadoutParam(_rawvalue, _noerror);
|
||||
return flowpostprocessing->getReadoutParam(_rawvalue, _noerror, _number);
|
||||
|
||||
string zw = "";
|
||||
string result = "";
|
||||
@@ -501,37 +494,40 @@ string ClassFlowControll::GetPrevalue(std::string _number)
|
||||
return flowpostprocessing->GetPreValue(_number);
|
||||
}
|
||||
|
||||
|
||||
return std::string("");
|
||||
}
|
||||
|
||||
|
||||
std::string ClassFlowControll::UpdatePrevalue(std::string _newvalue, std::string _numbers, bool _extern)
|
||||
bool ClassFlowControll::UpdatePrevalue(std::string _newvalue, std::string _numbers, bool _extern)
|
||||
{
|
||||
float zw;
|
||||
double newvalueAsDouble;
|
||||
char* p;
|
||||
|
||||
_newvalue = trim(_newvalue);
|
||||
// ESP_LOGD(TAG, "Input UpdatePreValue: %s", _newvalue.c_str());
|
||||
//ESP_LOGD(TAG, "Input UpdatePreValue: %s", _newvalue.c_str());
|
||||
|
||||
if (_newvalue.compare("0.0") == 0)
|
||||
{
|
||||
zw = 0;
|
||||
if (_newvalue.substr(0,8).compare("0.000000") == 0 || _newvalue.compare("0.0") == 0 || _newvalue.compare("0") == 0) {
|
||||
newvalueAsDouble = 0; // preset to value = 0
|
||||
}
|
||||
else
|
||||
{
|
||||
zw = strtof(_newvalue.c_str(), &p);
|
||||
if (zw == 0)
|
||||
return "- Error in String to Value Conversion!!! Must be of format value=123.456";
|
||||
else {
|
||||
newvalueAsDouble = strtod(_newvalue.c_str(), &p);
|
||||
if (newvalueAsDouble == 0) {
|
||||
LogFile.WriteToFile(ESP_LOG_WARN, TAG, "UpdatePrevalue: No valid value for processing: " + _newvalue);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (flowpostprocessing)
|
||||
{
|
||||
flowpostprocessing->SetPreValue(zw, _numbers, _extern);
|
||||
return _newvalue;
|
||||
if (flowpostprocessing) {
|
||||
if (flowpostprocessing->SetPreValue(newvalueAsDouble, _numbers, _extern))
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "UpdatePrevalue: ERROR - Class Post-Processing not initialized");
|
||||
return false;
|
||||
}
|
||||
|
||||
return std::string();
|
||||
}
|
||||
|
||||
|
||||
@@ -737,7 +733,7 @@ esp_err_t ClassFlowControll::GetJPGStream(std::string _fn, httpd_req_t *req)
|
||||
|
||||
httpd_resp_set_type(req, "image/jpeg");
|
||||
result = httpd_resp_send(req, (const char *)fileBuffer, fileSize);
|
||||
delete fileBuffer;
|
||||
free(fileBuffer);
|
||||
}
|
||||
else if (aktstatus.find("Initialization") != -1) {
|
||||
FILE* file = fopen("/sdcard/html/Flowstate_initialization.jpg", "rb");
|
||||
@@ -764,7 +760,7 @@ esp_err_t ClassFlowControll::GetJPGStream(std::string _fn, httpd_req_t *req)
|
||||
|
||||
httpd_resp_set_type(req, "image/jpeg");
|
||||
result = httpd_resp_send(req, (const char *)fileBuffer, fileSize);
|
||||
delete fileBuffer;
|
||||
free(fileBuffer);
|
||||
}
|
||||
else if (aktstatus.find("Take Image") != -1) {
|
||||
if (flowalignment && flowalignment->AlgROI) {
|
||||
@@ -826,7 +822,7 @@ esp_err_t ClassFlowControll::GetJPGStream(std::string _fn, httpd_req_t *req)
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
_send = new CImageBasis(flowalignment->ImageBasis);
|
||||
_send = new CImageBasis("alg_roi", flowalignment->ImageBasis);
|
||||
|
||||
if (_send->ImageOkay()) {
|
||||
if (flowalignment) flowalignment->DrawRef(_send);
|
||||
|
||||
@@ -18,7 +18,6 @@
|
||||
#include "ClassFlowInfluxDBv2.h"
|
||||
#endif //ENABLE_INFLUXDB
|
||||
#include "ClassFlowCNNGeneral.h"
|
||||
#include "ClassFlowWriteList.h"
|
||||
|
||||
class ClassFlowControll :
|
||||
public ClassFlow
|
||||
@@ -35,20 +34,21 @@ 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);
|
||||
bool getStatusSetupModus(){return SetupModeActive;};
|
||||
string getReadout(bool _rawvalue, bool _noerror);
|
||||
string getReadout(bool _rawvalue, bool _noerror, int _number);
|
||||
string getReadoutAll(int _type);
|
||||
string UpdatePrevalue(std::string _newvalue, std::string _numbers, bool _extern);
|
||||
bool UpdatePrevalue(std::string _newvalue, std::string _numbers, bool _extern);
|
||||
string GetPrevalue(std::string _number = "");
|
||||
bool ReadParameter(FILE* pfile, string& aktparamgraph);
|
||||
string getJSON();
|
||||
@@ -56,10 +56,6 @@ public:
|
||||
|
||||
string TranslateAktstatus(std::string _input);
|
||||
|
||||
#ifdef ENABLE_MQTT
|
||||
string GetMQTTMainTopic();
|
||||
#endif //ENABLE_MQTT
|
||||
|
||||
#ifdef ALGROI_LOAD_FROM_MEM_AS_JPG
|
||||
void DigitalDrawROI(CImageBasis *_zw);
|
||||
void AnalogDrawROI(CImageBasis *_zw);
|
||||
@@ -70,7 +66,8 @@ public:
|
||||
|
||||
std::string doSingleStep(std::string _stepname, std::string _host);
|
||||
|
||||
bool isAutoStart(long &_interval);
|
||||
bool getIsAutoStart();
|
||||
void setAutoStartInterval(long &_interval);
|
||||
|
||||
std::string* getActStatusWithTime();
|
||||
std::string* getActStatus();
|
||||
|
||||
@@ -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
|
||||
@@ -50,7 +51,12 @@ struct NumberPost {
|
||||
int DecimalShiftInitial;
|
||||
float AnalogDigitalTransitionStart; // When is the digit > x.1, i.e. when does it start to tilt?
|
||||
int Nachkomma;
|
||||
string Fieldname; // Fieldname in InfluxDB2
|
||||
|
||||
string FieldV1; // Fieldname in InfluxDBv1
|
||||
string MeasurementV1; // Measurement in InfluxDBv1
|
||||
|
||||
string FieldV2; // Fieldname in InfluxDBv2
|
||||
string MeasurementV2; // Measurement in InfluxDBv2
|
||||
|
||||
bool isExtendedResolution;
|
||||
|
||||
|
||||
@@ -17,7 +17,8 @@ extern "C" {
|
||||
#include "esp_log.h"
|
||||
#include "../../include/defines.h"
|
||||
|
||||
static const char* TAG = "IMG";
|
||||
static const char* TAG = "FLOWIMAGE";
|
||||
|
||||
|
||||
ClassFlowImage::ClassFlowImage(const char* logTag)
|
||||
{
|
||||
|
||||
@@ -15,13 +15,12 @@
|
||||
|
||||
#include <time.h>
|
||||
|
||||
static const char* TAG = "class_flow_influxDb";
|
||||
static const char* TAG = "INFLUXDB";
|
||||
|
||||
void ClassFlowInfluxDB::SetInitialParameter(void)
|
||||
{
|
||||
uri = "";
|
||||
database = "";
|
||||
measurement = "";
|
||||
|
||||
OldValue = "";
|
||||
flowpostprocessing = NULL;
|
||||
@@ -86,33 +85,39 @@ bool ClassFlowInfluxDB::ReadParameter(FILE* pfile, string& aktparamgraph)
|
||||
{
|
||||
ESP_LOGD(TAG, "while loop reading line: %s", aktparamgraph.c_str());
|
||||
splitted = ZerlegeZeile(aktparamgraph);
|
||||
if ((toUpper(splitted[0]) == "USER") && (splitted.size() > 1))
|
||||
std::string _param = GetParameterName(splitted[0]);
|
||||
|
||||
if ((toUpper(_param) == "USER") && (splitted.size() > 1))
|
||||
{
|
||||
this->user = splitted[1];
|
||||
}
|
||||
if ((toUpper(splitted[0]) == "PASSWORD") && (splitted.size() > 1))
|
||||
if ((toUpper(_param) == "PASSWORD") && (splitted.size() > 1))
|
||||
{
|
||||
this->password = splitted[1];
|
||||
}
|
||||
if ((toUpper(splitted[0]) == "URI") && (splitted.size() > 1))
|
||||
if ((toUpper(_param) == "URI") && (splitted.size() > 1))
|
||||
{
|
||||
this->uri = splitted[1];
|
||||
}
|
||||
if (((toUpper(splitted[0]) == "MEASUREMENT")) && (splitted.size() > 1))
|
||||
{
|
||||
this->measurement = splitted[1];
|
||||
}
|
||||
if (((toUpper(splitted[0]) == "DATABASE")) && (splitted.size() > 1))
|
||||
if (((toUpper(_param) == "DATABASE")) && (splitted.size() > 1))
|
||||
{
|
||||
this->database = splitted[1];
|
||||
}
|
||||
if (((toUpper(_param) == "MEASUREMENT")) && (splitted.size() > 1))
|
||||
{
|
||||
handleMeasurement(splitted[0], splitted[1]);
|
||||
}
|
||||
if (((toUpper(_param) == "FIELD")) && (splitted.size() > 1))
|
||||
{
|
||||
handleFieldname(splitted[0], splitted[1]);
|
||||
}
|
||||
}
|
||||
|
||||
if ((uri.length() > 0) && (database.length() > 0) && (measurement.length() > 0))
|
||||
if ((uri.length() > 0) && (database.length() > 0))
|
||||
{
|
||||
// ESP_LOGD(TAG, "Init InfluxDB with uri: %s, measurement: %s, user: %s, password: %s", uri.c_str(), measurement.c_str(), user.c_str(), password.c_str());
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Init InfluxDB with uri: " + uri + ", measurement: " + measurement + ", user: " + user + ", password: " + password);
|
||||
InfluxDBInit(uri, database, measurement, user, password);
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Init InfluxDB with uri: " + uri + ", user: " + user + ", password: " + password);
|
||||
InfluxDBInit(uri, database, user, password);
|
||||
InfluxDBenable = true;
|
||||
} else {
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "InfluxDB init skipped as we are missing some parameters");
|
||||
@@ -121,23 +126,18 @@ bool ClassFlowInfluxDB::ReadParameter(FILE* pfile, string& aktparamgraph)
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
string ClassFlowInfluxDB::GetInfluxDBMeasurement()
|
||||
{
|
||||
return measurement;
|
||||
}
|
||||
|
||||
|
||||
bool ClassFlowInfluxDB::doFlow(string zwtime)
|
||||
{
|
||||
if (!InfluxDBenable)
|
||||
return true;
|
||||
|
||||
std::string result;
|
||||
std::string measurement;
|
||||
std::string resulterror = "";
|
||||
std::string resultraw = "";
|
||||
std::string resultrate = "";
|
||||
std::string resulttimestamp = "";
|
||||
long int timeutc;
|
||||
string zw = "";
|
||||
string namenumber = "";
|
||||
|
||||
@@ -147,20 +147,29 @@ bool ClassFlowInfluxDB::doFlow(string zwtime)
|
||||
|
||||
for (int i = 0; i < (*NUMBERS).size(); ++i)
|
||||
{
|
||||
measurement = (*NUMBERS)[i]->MeasurementV1;
|
||||
result = (*NUMBERS)[i]->ReturnValue;
|
||||
resultraw = (*NUMBERS)[i]->ReturnRawValue;
|
||||
resulterror = (*NUMBERS)[i]->ErrorMessageText;
|
||||
resultrate = (*NUMBERS)[i]->ReturnRateValue;
|
||||
resulttimestamp = (*NUMBERS)[i]->timeStamp;
|
||||
timeutc = (*NUMBERS)[i]->timeStampTimeUTC;
|
||||
|
||||
namenumber = (*NUMBERS)[i]->name;
|
||||
if (namenumber == "default")
|
||||
namenumber = "value";
|
||||
if ((*NUMBERS)[i]->FieldV1.length() > 0)
|
||||
{
|
||||
namenumber = (*NUMBERS)[i]->FieldV1;
|
||||
}
|
||||
else
|
||||
namenumber = namenumber + "/value";
|
||||
{
|
||||
namenumber = (*NUMBERS)[i]->name;
|
||||
if (namenumber == "default")
|
||||
namenumber = "value";
|
||||
else
|
||||
namenumber = namenumber + "/value";
|
||||
}
|
||||
|
||||
if (result.length() > 0 && resulttimestamp.length() > 0)
|
||||
InfluxDBPublish(namenumber, result, resulttimestamp);
|
||||
if (result.length() > 0)
|
||||
InfluxDBPublish(measurement, namenumber, result, timeutc);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -169,4 +178,50 @@ bool ClassFlowInfluxDB::doFlow(string zwtime)
|
||||
return true;
|
||||
}
|
||||
|
||||
void ClassFlowInfluxDB::handleMeasurement(string _decsep, string _value)
|
||||
{
|
||||
string _digit, _decpos;
|
||||
int _pospunkt = _decsep.find_first_of(".");
|
||||
// ESP_LOGD(TAG, "Name: %s, Pospunkt: %d", _decsep.c_str(), _pospunkt);
|
||||
if (_pospunkt > -1)
|
||||
_digit = _decsep.substr(0, _pospunkt);
|
||||
else
|
||||
_digit = "default";
|
||||
for (int j = 0; j < flowpostprocessing->NUMBERS.size(); ++j)
|
||||
{
|
||||
if (_digit == "default") // Set to default first (if nothing else is set)
|
||||
{
|
||||
flowpostprocessing->NUMBERS[j]->MeasurementV1 = _value;
|
||||
}
|
||||
if (flowpostprocessing->NUMBERS[j]->name == _digit)
|
||||
{
|
||||
flowpostprocessing->NUMBERS[j]->MeasurementV1 = _value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ClassFlowInfluxDB::handleFieldname(string _decsep, string _value)
|
||||
{
|
||||
string _digit, _decpos;
|
||||
int _pospunkt = _decsep.find_first_of(".");
|
||||
// ESP_LOGD(TAG, "Name: %s, Pospunkt: %d", _decsep.c_str(), _pospunkt);
|
||||
if (_pospunkt > -1)
|
||||
_digit = _decsep.substr(0, _pospunkt);
|
||||
else
|
||||
_digit = "default";
|
||||
for (int j = 0; j < flowpostprocessing->NUMBERS.size(); ++j)
|
||||
{
|
||||
if (_digit == "default") // Set to default first (if nothing else is set)
|
||||
{
|
||||
flowpostprocessing->NUMBERS[j]->FieldV1 = _value;
|
||||
}
|
||||
if (flowpostprocessing->NUMBERS[j]->name == _digit)
|
||||
{
|
||||
flowpostprocessing->NUMBERS[j]->FieldV1 = _value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endif //ENABLE_INFLUXDB
|
||||
@@ -21,14 +21,19 @@ protected:
|
||||
std::string user, password;
|
||||
bool InfluxDBenable;
|
||||
|
||||
void SetInitialParameter(void);
|
||||
void SetInitialParameter(void);
|
||||
|
||||
void handleFieldname(string _decsep, string _value);
|
||||
void handleMeasurement(string _decsep, string _value);
|
||||
|
||||
|
||||
|
||||
public:
|
||||
ClassFlowInfluxDB();
|
||||
ClassFlowInfluxDB(std::vector<ClassFlow*>* lfc);
|
||||
ClassFlowInfluxDB(std::vector<ClassFlow*>* lfc, ClassFlow *_prev);
|
||||
|
||||
string GetInfluxDBMeasurement();
|
||||
// string GetInfluxDBMeasurement();
|
||||
|
||||
bool ReadParameter(FILE* pfile, string& aktparamgraph);
|
||||
bool doFlow(string time);
|
||||
|
||||
@@ -15,13 +15,12 @@
|
||||
|
||||
#include <time.h>
|
||||
|
||||
static const char* TAG = "class_flow_influxDbv2";
|
||||
static const char* TAG = "INFLUXDBV2";
|
||||
|
||||
void ClassFlowInfluxDBv2::SetInitialParameter(void)
|
||||
{
|
||||
uri = "";
|
||||
database = "";
|
||||
measurement = "";
|
||||
bucket = "";
|
||||
dborg = "";
|
||||
dbtoken = "";
|
||||
// dbfield = "";
|
||||
@@ -102,30 +101,29 @@ bool ClassFlowInfluxDBv2::ReadParameter(FILE* pfile, string& aktparamgraph)
|
||||
{
|
||||
this->uri = splitted[1];
|
||||
}
|
||||
if (((toUpper(_param) == "MEASUREMENT")) && (splitted.size() > 1))
|
||||
{
|
||||
this->measurement = splitted[1];
|
||||
}
|
||||
if (((toUpper(_param) == "FIELDNAME")) && (splitted.size() > 1))
|
||||
if (((toUpper(_param) == "FIELD")) && (splitted.size() > 1))
|
||||
{
|
||||
handleFieldname(splitted[0], splitted[1]);
|
||||
}
|
||||
if (((toUpper(splitted[0]) == "DATABASE")) && (splitted.size() > 1))
|
||||
if (((toUpper(_param) == "MEASUREMENT")) && (splitted.size() > 1))
|
||||
{
|
||||
this->database = splitted[1];
|
||||
handleMeasurement(splitted[0], splitted[1]);
|
||||
}
|
||||
if (((toUpper(splitted[0]) == "BUCKET")) && (splitted.size() > 1))
|
||||
{
|
||||
this->bucket = splitted[1];
|
||||
}
|
||||
}
|
||||
|
||||
printf("uri: %s\n", uri.c_str());
|
||||
printf("measurement: %s\n", measurement.c_str());
|
||||
printf("org: %s\n", dborg.c_str());
|
||||
printf("token: %s\n", dbtoken.c_str());
|
||||
|
||||
if ((uri.length() > 0) && (database.length() > 0) && (measurement.length() > 0) && (dbtoken.length() > 0) && (dborg.length() > 0))
|
||||
if ((uri.length() > 0) && (bucket.length() > 0) && (dbtoken.length() > 0) && (dborg.length() > 0))
|
||||
{
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Init InfluxDB with uri: " + uri + ", measurement: " + measurement + ", org: " + dborg + ", token: *****");
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Init InfluxDB with uri: " + uri + ", org: " + dborg + ", token: *****");
|
||||
// printf("vor V2 Init\n");
|
||||
InfluxDB_V2_Init(uri, database, measurement, dborg, dbtoken);
|
||||
InfluxDB_V2_Init(uri, bucket, dborg, dbtoken);
|
||||
// printf("nach V2 Init\n");
|
||||
InfluxDBenable = true;
|
||||
} else {
|
||||
@@ -135,11 +133,12 @@ bool ClassFlowInfluxDBv2::ReadParameter(FILE* pfile, string& aktparamgraph)
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
string ClassFlowInfluxDBv2::GetInfluxDBMeasurement()
|
||||
{
|
||||
return measurement;
|
||||
}
|
||||
*/
|
||||
|
||||
void ClassFlowInfluxDBv2::handleFieldname(string _decsep, string _value)
|
||||
{
|
||||
@@ -154,15 +153,36 @@ void ClassFlowInfluxDBv2::handleFieldname(string _decsep, string _value)
|
||||
{
|
||||
if (_digit == "default") // Set to default first (if nothing else is set)
|
||||
{
|
||||
flowpostprocessing->NUMBERS[j]->Fieldname = _value;
|
||||
flowpostprocessing->NUMBERS[j]->FieldV2 = _value;
|
||||
}
|
||||
if (flowpostprocessing->NUMBERS[j]->name == _digit)
|
||||
{
|
||||
flowpostprocessing->NUMBERS[j]->Fieldname = _value;
|
||||
flowpostprocessing->NUMBERS[j]->FieldV2 = _value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ClassFlowInfluxDBv2::handleMeasurement(string _decsep, string _value)
|
||||
{
|
||||
string _digit, _decpos;
|
||||
int _pospunkt = _decsep.find_first_of(".");
|
||||
// ESP_LOGD(TAG, "Name: %s, Pospunkt: %d", _decsep.c_str(), _pospunkt);
|
||||
if (_pospunkt > -1)
|
||||
_digit = _decsep.substr(0, _pospunkt);
|
||||
else
|
||||
_digit = "default";
|
||||
for (int j = 0; j < flowpostprocessing->NUMBERS.size(); ++j)
|
||||
{
|
||||
if (_digit == "default") // Set to default first (if nothing else is set)
|
||||
{
|
||||
flowpostprocessing->NUMBERS[j]->MeasurementV2 = _value;
|
||||
}
|
||||
if (flowpostprocessing->NUMBERS[j]->name == _digit)
|
||||
{
|
||||
flowpostprocessing->NUMBERS[j]->MeasurementV2 = _value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool ClassFlowInfluxDBv2::doFlow(string zwtime)
|
||||
@@ -170,29 +190,35 @@ bool ClassFlowInfluxDBv2::doFlow(string zwtime)
|
||||
if (!InfluxDBenable)
|
||||
return true;
|
||||
|
||||
std::string measurement;
|
||||
std::string result;
|
||||
std::string resulterror = "";
|
||||
std::string resultraw = "";
|
||||
std::string resultrate = "";
|
||||
std::string resulttimestamp = "";
|
||||
long int resulttimeutc = 0;
|
||||
string zw = "";
|
||||
string namenumber = "";
|
||||
|
||||
|
||||
if (flowpostprocessing)
|
||||
{
|
||||
std::vector<NumberPost*>* NUMBERS = flowpostprocessing->GetNumbers();
|
||||
|
||||
for (int i = 0; i < (*NUMBERS).size(); ++i)
|
||||
{
|
||||
measurement = (*NUMBERS)[i]->MeasurementV2;
|
||||
result = (*NUMBERS)[i]->ReturnValue;
|
||||
resultraw = (*NUMBERS)[i]->ReturnRawValue;
|
||||
resulterror = (*NUMBERS)[i]->ErrorMessageText;
|
||||
resultrate = (*NUMBERS)[i]->ReturnRateValue;
|
||||
resulttimestamp = (*NUMBERS)[i]->timeStamp;
|
||||
resulttimeutc = (*NUMBERS)[i]->timeStampTimeUTC;
|
||||
|
||||
if ((*NUMBERS)[i]->Fieldname.length() > 0)
|
||||
|
||||
if ((*NUMBERS)[i]->FieldV2.length() > 0)
|
||||
{
|
||||
namenumber = (*NUMBERS)[i]->Fieldname;
|
||||
namenumber = (*NUMBERS)[i]->FieldV2;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -206,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(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, measurement;
|
||||
std::string uri, bucket;
|
||||
std::string dborg, dbtoken, dbfield;
|
||||
std::string OldValue;
|
||||
ClassFlowPostProcessing* flowpostprocessing;
|
||||
@@ -24,13 +24,15 @@ protected:
|
||||
void SetInitialParameter(void);
|
||||
|
||||
void handleFieldname(string _decsep, string _value);
|
||||
void handleMeasurement(string _decsep, string _value);
|
||||
|
||||
|
||||
public:
|
||||
ClassFlowInfluxDBv2();
|
||||
ClassFlowInfluxDBv2(std::vector<ClassFlow*>* lfc);
|
||||
ClassFlowInfluxDBv2(std::vector<ClassFlow*>* lfc, ClassFlow *_prev);
|
||||
|
||||
string GetInfluxDBMeasurement();
|
||||
// string GetInfluxDBMeasurement();
|
||||
|
||||
bool ReadParameter(FILE* pfile, string& aktparamgraph);
|
||||
bool doFlow(string time);
|
||||
|
||||
@@ -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];
|
||||
@@ -183,12 +198,6 @@ bool ClassFlowMQTT::ReadParameter(FILE* pfile, string& aktparamgraph)
|
||||
}
|
||||
|
||||
|
||||
string ClassFlowMQTT::GetMQTTMainTopic()
|
||||
{
|
||||
return maintopic;
|
||||
}
|
||||
|
||||
|
||||
bool ClassFlowMQTT::Start(float AutoInterval)
|
||||
{
|
||||
roundInterval = AutoInterval; // Minutes
|
||||
@@ -202,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
|
||||
@@ -31,7 +32,6 @@ public:
|
||||
ClassFlowMQTT(std::vector<ClassFlow*>* lfc);
|
||||
ClassFlowMQTT(std::vector<ClassFlow*>* lfc, ClassFlow *_prev);
|
||||
|
||||
string GetMQTTMainTopic();
|
||||
bool Start(float AutoInterval);
|
||||
|
||||
bool ReadParameter(FILE* pfile, string& aktparamgraph);
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
#include <cassert>
|
||||
|
||||
#include <time.h>
|
||||
|
||||
@@ -96,27 +97,49 @@ string ClassFlowPostProcessing::GetPreValue(std::string _number)
|
||||
return result;
|
||||
}
|
||||
|
||||
void ClassFlowPostProcessing::SetPreValue(double zw, string _numbers, bool _extern)
|
||||
|
||||
bool ClassFlowPostProcessing::SetPreValue(double _newvalue, string _numbers, bool _extern)
|
||||
{
|
||||
ESP_LOGD(TAG, "SetPrevalue: %f, %s", zw, _numbers.c_str());
|
||||
for (int j = 0; j < NUMBERS.size(); ++j)
|
||||
{
|
||||
// ESP_LOGD(TAG, "Number %d, %s", j, NUMBERS[j]->name.c_str());
|
||||
if (NUMBERS[j]->name == _numbers)
|
||||
{
|
||||
NUMBERS[j]->PreValue = zw;
|
||||
NUMBERS[j]->ReturnPreValue = std::to_string(zw);
|
||||
//ESP_LOGD(TAG, "SetPrevalue: %f, %s", zw, _numbers.c_str());
|
||||
|
||||
for (int j = 0; j < NUMBERS.size(); ++j) {
|
||||
//ESP_LOGD(TAG, "Number %d, %s", j, NUMBERS[j]->name.c_str());
|
||||
if (NUMBERS[j]->name == _numbers) {
|
||||
if (_newvalue >= 0) { // if new value posivive, use provided value to preset PreValue
|
||||
NUMBERS[j]->PreValue = _newvalue;
|
||||
}
|
||||
else { // if new value negative, use last raw value to preset PreValue
|
||||
char* p;
|
||||
double ReturnRawValueAsDouble = strtod(NUMBERS[j]->ReturnRawValue.c_str(), &p);
|
||||
if (ReturnRawValueAsDouble == 0) {
|
||||
LogFile.WriteToFile(ESP_LOG_WARN, TAG, "SetPreValue: RawValue not a valid value for further processing: "
|
||||
+ NUMBERS[j]->ReturnRawValue);
|
||||
return false;
|
||||
}
|
||||
NUMBERS[j]->PreValue = ReturnRawValueAsDouble;
|
||||
}
|
||||
|
||||
NUMBERS[j]->ReturnPreValue = std::to_string(NUMBERS[j]->PreValue);
|
||||
NUMBERS[j]->PreValueOkay = true;
|
||||
|
||||
if (_extern)
|
||||
{
|
||||
time(&(NUMBERS[j]->lastvalue));
|
||||
localtime(&(NUMBERS[j]->lastvalue));
|
||||
}
|
||||
// ESP_LOGD(TAG, "Found %d! - set to %f", j, NUMBERS[j]->PreValue);
|
||||
//ESP_LOGD(TAG, "Found %d! - set to %.8f", j, NUMBERS[j]->PreValue);
|
||||
|
||||
UpdatePreValueINI = true; // Only update prevalue file if a new value is set
|
||||
SavePreValue();
|
||||
|
||||
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "SetPreValue: PreValue for " + NUMBERS[j]->name + " set to " +
|
||||
std::to_string(NUMBERS[j]->PreValue));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
UpdatePreValueINI = true;
|
||||
SavePreValue();
|
||||
|
||||
LogFile.WriteToFile(ESP_LOG_WARN, TAG, "SetPreValue: Numbersname not found or not valid");
|
||||
return false; // No new value was set (e.g. wrong numbersname, no numbers at all)
|
||||
}
|
||||
|
||||
|
||||
@@ -262,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";
|
||||
@@ -703,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 = "";
|
||||
@@ -746,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);
|
||||
@@ -759,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
|
||||
@@ -791,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
|
||||
{
|
||||
@@ -804,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
|
||||
@@ -844,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 = "";
|
||||
|
||||
@@ -68,7 +68,7 @@ public:
|
||||
void SavePreValue();
|
||||
string getJsonFromNumber(int i, std::string _lineend);
|
||||
string GetPreValue(std::string _number = "");
|
||||
void SetPreValue(double zw, string _numbers, bool _extern = false);
|
||||
bool SetPreValue(double zw, string _numbers, bool _extern = false);
|
||||
|
||||
std::string GetJSON(std::string _lineend = "\n");
|
||||
std::string getNumbersName();
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "esp_wifi.h"
|
||||
#include "esp_log.h"
|
||||
#include "../../include/defines.h"
|
||||
#include "psram.h"
|
||||
|
||||
#include <time.h>
|
||||
|
||||
@@ -15,7 +16,7 @@
|
||||
|
||||
// #define WIFITURNOFF
|
||||
|
||||
static const char* TAG = "flow_make_image";
|
||||
static const char* TAG = "TAKEIMAGE";
|
||||
|
||||
esp_err_t ClassFlowTakeImage::camera_capture(){
|
||||
string nm = namerawimage;
|
||||
@@ -154,7 +155,7 @@ bool ClassFlowTakeImage::ReadParameter(FILE* pfile, string& aktparamgraph)
|
||||
|
||||
image_width = Camera.image_width;
|
||||
image_height = Camera.image_height;
|
||||
rawImage = new CImageBasis();
|
||||
rawImage = new CImageBasis("rawImage");
|
||||
rawImage->CreateEmptyImage(image_width, image_height, 3);
|
||||
|
||||
waitbeforepicture_store = waitbeforepicture;
|
||||
@@ -183,6 +184,8 @@ string ClassFlowTakeImage::getHTMLSingleStep(string host)
|
||||
|
||||
bool ClassFlowTakeImage::doFlow(string zwtime)
|
||||
{
|
||||
psram_init_shared_memory_for_take_image_step();
|
||||
|
||||
string logPath = CreateLogFolder(zwtime);
|
||||
|
||||
int flash_duration = (int) (waitbeforepicture * 1000);
|
||||
@@ -215,6 +218,8 @@ bool ClassFlowTakeImage::doFlow(string zwtime)
|
||||
LogFile.WriteHeapInfo("ClassFlowTakeImage::doFlow - After RemoveOldLogs");
|
||||
#endif
|
||||
|
||||
psram_deinit_shared_memory_for_take_image_step();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -231,7 +236,7 @@ esp_err_t ClassFlowTakeImage::SendRawJPG(httpd_req_t *req)
|
||||
|
||||
ImageData* ClassFlowTakeImage::SendRawImage()
|
||||
{
|
||||
CImageBasis *zw = new CImageBasis(rawImage);
|
||||
CImageBasis *zw = new CImageBasis("SendRawImage", rawImage);
|
||||
ImageData *id;
|
||||
int flash_duration = (int) (waitbeforepicture * 1000);
|
||||
Camera.CaptureToBasisImage(zw, flash_duration);
|
||||
|
||||
@@ -1,91 +0,0 @@
|
||||
#include <sstream>
|
||||
#include "ClassFlowWriteList.h"
|
||||
#include "Helper.h"
|
||||
|
||||
#include "time_sntp.h"
|
||||
#include "../../include/defines.h"
|
||||
|
||||
#include <time.h>
|
||||
|
||||
void ClassFlowWriteList::SetInitialParameter(void)
|
||||
{
|
||||
flowpostprocessing = NULL;
|
||||
previousElement = NULL;
|
||||
ListFlowControll = NULL;
|
||||
disabled = false;
|
||||
}
|
||||
|
||||
ClassFlowWriteList::ClassFlowWriteList()
|
||||
{
|
||||
SetInitialParameter();
|
||||
}
|
||||
|
||||
ClassFlowWriteList::ClassFlowWriteList(std::vector<ClassFlow*>* lfc)
|
||||
{
|
||||
SetInitialParameter();
|
||||
|
||||
ListFlowControll = lfc;
|
||||
for (int i = 0; i < ListFlowControll->size(); ++i)
|
||||
{
|
||||
if (((*ListFlowControll)[i])->name().compare("ClassFlowPostProcessing") == 0)
|
||||
{
|
||||
flowpostprocessing = (ClassFlowPostProcessing*) (*ListFlowControll)[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool ClassFlowWriteList::ReadParameter(FILE* pfile, string& aktparamgraph)
|
||||
{
|
||||
std::vector<string> splitted;
|
||||
|
||||
aktparamgraph = trim(aktparamgraph);
|
||||
|
||||
if (aktparamgraph.size() == 0)
|
||||
if (!this->GetNextParagraph(pfile, aktparamgraph))
|
||||
return false;
|
||||
|
||||
if (toUpper(aktparamgraph).compare("[MQTT]") != 0)
|
||||
return false;
|
||||
|
||||
while (this->getNextLine(pfile, &aktparamgraph) && !this->isNewParagraph(aktparamgraph))
|
||||
{
|
||||
splitted = ZerlegeZeile(aktparamgraph);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool ClassFlowWriteList::doFlow(string zwtime)
|
||||
{
|
||||
std::string line = "";
|
||||
|
||||
std::string result;
|
||||
std::string resulterror = "";
|
||||
std::string resultraw = "";
|
||||
std::string resultrate = "";
|
||||
std::string resulttimestamp = "";
|
||||
string zw = "";
|
||||
string namenumber = "";
|
||||
|
||||
if (flowpostprocessing)
|
||||
{
|
||||
std::vector<NumberPost*>* NUMBERS = flowpostprocessing->GetNumbers();
|
||||
|
||||
for (int i = 0; i < (*NUMBERS).size(); ++i)
|
||||
{
|
||||
result = (*NUMBERS)[i]->ReturnValue;
|
||||
resultraw = (*NUMBERS)[i]->ReturnRawValue;
|
||||
resulterror = (*NUMBERS)[i]->ErrorMessageText;
|
||||
resultrate = (*NUMBERS)[i]->ReturnRateValue;
|
||||
resulttimestamp = (*NUMBERS)[i]->timeStamp;
|
||||
|
||||
line = line + resulttimestamp + "\t" + resultraw + "\t" + result + "\t" + resultraw + "\t" + resultrate + "\t" + resulttimestamp + "\t";
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef CLASSFFLOWPWRITELIST_H
|
||||
#define CLASSFFLOWPWRITELIST_H
|
||||
|
||||
#include "ClassFlow.h"
|
||||
#include "ClassFlowPostProcessing.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
class ClassFlowWriteList :
|
||||
public ClassFlow
|
||||
{
|
||||
protected:
|
||||
ClassFlowPostProcessing* flowpostprocessing;
|
||||
void SetInitialParameter(void);
|
||||
|
||||
public:
|
||||
ClassFlowWriteList();
|
||||
ClassFlowWriteList(std::vector<ClassFlow*>* lfc);
|
||||
|
||||
bool ReadParameter(FILE* pfile, string& aktparamgraph);
|
||||
bool doFlow(string time);
|
||||
string name(){return "ClassFlowWriteList";};
|
||||
};
|
||||
|
||||
#endif //CLASSFFLOWPWRITELIST_H
|
||||
@@ -1,9 +1,10 @@
|
||||
#include "server_tflite.h"
|
||||
#include "MainFlowControl.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "string.h"
|
||||
#include "esp_log.h"
|
||||
#include <esp_timer.h>
|
||||
|
||||
#include <iomanip>
|
||||
#include <sstream>
|
||||
@@ -25,9 +26,14 @@
|
||||
|
||||
#include "read_wlanini.h"
|
||||
#include "connect_wlan.h"
|
||||
#include "psram.h"
|
||||
|
||||
// support IDF 5.x
|
||||
#ifndef portTICK_RATE_MS
|
||||
#define portTICK_RATE_MS portTICK_PERIOD_MS
|
||||
#endif
|
||||
|
||||
ClassFlowControll tfliteflow;
|
||||
ClassFlowControll flowctrl;
|
||||
|
||||
TaskHandle_t xHandletask_autodoFlow = NULL;
|
||||
|
||||
@@ -35,12 +41,13 @@ bool bTaskAutoFlowCreated = false;
|
||||
bool flowisrunning = false;
|
||||
|
||||
long auto_interval = 0;
|
||||
bool auto_isrunning = false;
|
||||
bool autostartIsEnabled = false;
|
||||
|
||||
int countRounds = 0;
|
||||
bool isPlannedReboot = false;
|
||||
|
||||
static const char *TAG = "TFLITE SERVER";
|
||||
static const char *TAG = "MAINCTRL";
|
||||
|
||||
|
||||
//#define DEBUG_DETAIL_ON
|
||||
|
||||
@@ -74,26 +81,26 @@ int getCountFlowRounds()
|
||||
|
||||
esp_err_t GetJPG(std::string _filename, httpd_req_t *req)
|
||||
{
|
||||
return tfliteflow.GetJPGStream(_filename, req);
|
||||
return flowctrl.GetJPGStream(_filename, req);
|
||||
}
|
||||
|
||||
|
||||
esp_err_t GetRawJPG(httpd_req_t *req)
|
||||
{
|
||||
return tfliteflow.SendRawJPG(req);
|
||||
return flowctrl.SendRawJPG(req);
|
||||
}
|
||||
|
||||
|
||||
bool isSetupModusActive() {
|
||||
return tfliteflow.getStatusSetupModus();
|
||||
return false;
|
||||
bool isSetupModusActive()
|
||||
{
|
||||
return flowctrl.getStatusSetupModus();
|
||||
}
|
||||
|
||||
|
||||
void KillTFliteTasks()
|
||||
void DeleteMainFlowTask()
|
||||
{
|
||||
#ifdef DEBUG_DETAIL_ON
|
||||
ESP_LOGD(TAG, "KillTFliteTasks: xHandletask_autodoFlow: %ld", (long) xHandletask_autodoFlow);
|
||||
ESP_LOGD(TAG, "DeleteMainFlowTask: xHandletask_autodoFlow: %ld", (long) xHandletask_autodoFlow);
|
||||
#endif
|
||||
if( xHandletask_autodoFlow != NULL )
|
||||
{
|
||||
@@ -108,19 +115,19 @@ void KillTFliteTasks()
|
||||
|
||||
void doInit(void)
|
||||
{
|
||||
#ifdef DEBUG_DETAIL_ON
|
||||
ESP_LOGD(TAG, "Start tfliteflow.InitFlow(config);");
|
||||
#ifdef DEBUG_DETAIL_ON
|
||||
ESP_LOGD(TAG, "Start flowctrl.InitFlow(config);");
|
||||
#endif
|
||||
tfliteflow.InitFlow(CONFIG_FILE);
|
||||
#ifdef DEBUG_DETAIL_ON
|
||||
ESP_LOGD(TAG, "Finished tfliteflow.InitFlow(config);");
|
||||
flowctrl.InitFlow(CONFIG_FILE);
|
||||
#ifdef DEBUG_DETAIL_ON
|
||||
ESP_LOGD(TAG, "Finished flowctrl.InitFlow(config);");
|
||||
#endif
|
||||
|
||||
/* GPIO handler has to be initialized before MQTT init to ensure proper topic subscription */
|
||||
gpio_handler_init();
|
||||
|
||||
#ifdef ENABLE_MQTT
|
||||
tfliteflow.StartMQTTService();
|
||||
flowctrl.StartMQTTService();
|
||||
#endif //ENABLE_MQTT
|
||||
}
|
||||
|
||||
@@ -130,7 +137,7 @@ bool doflow(void)
|
||||
std::string zw_time = getCurrentTimeString(LOGFILE_TIME_FORMAT);
|
||||
ESP_LOGD(TAG, "doflow - start %s", zw_time.c_str());
|
||||
flowisrunning = true;
|
||||
tfliteflow.doFlow(zw_time);
|
||||
flowctrl.doFlow(zw_time);
|
||||
flowisrunning = false;
|
||||
|
||||
#ifdef DEBUG_DETAIL_ON
|
||||
@@ -151,12 +158,12 @@ esp_err_t handler_get_heap(httpd_req_t *req)
|
||||
std::string zw = "Heap info:<br>" + getESPHeapInfo();
|
||||
|
||||
#ifdef TASK_ANALYSIS_ON
|
||||
char* pcTaskList = (char*) heap_caps_calloc(1, sizeof(char) * 768, MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM);
|
||||
char* pcTaskList = (char*) calloc_psram_heap(std::string(TAG) + "->pcTaskList", 1, sizeof(char) * 768, MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM);
|
||||
if (pcTaskList) {
|
||||
vTaskList(pcTaskList);
|
||||
zw = zw + "<br><br>Task info:<br><pre>Name | State | Prio | Lowest stacksize | Creation order | CPU (-1=NoAffinity)<br>"
|
||||
+ std::string(pcTaskList) + "</pre>";
|
||||
heap_caps_free(pcTaskList);
|
||||
free_psram_heap(std::string(TAG) + "->pcTaskList", pcTaskList);
|
||||
}
|
||||
else {
|
||||
zw = zw + "<br><br>Task info:<br>ERROR - Allocation of TaskList buffer in PSRAM failed";
|
||||
@@ -206,6 +213,40 @@ esp_err_t handler_init(httpd_req_t *req)
|
||||
}
|
||||
|
||||
|
||||
esp_err_t handler_stream(httpd_req_t *req)
|
||||
{
|
||||
#ifdef DEBUG_DETAIL_ON
|
||||
LogFile.WriteHeapInfo("handler_stream - Start");
|
||||
ESP_LOGD(TAG, "handler_stream uri: %s", req->uri);
|
||||
#endif
|
||||
|
||||
char _query[50];
|
||||
char _value[10];
|
||||
bool flashlightOn = false;
|
||||
|
||||
if (httpd_req_get_url_query_str(req, _query, 50) == ESP_OK)
|
||||
{
|
||||
// ESP_LOGD(TAG, "Query: %s", _query);
|
||||
if (httpd_query_key_value(_query, "flashlight", _value, 10) == ESP_OK)
|
||||
{
|
||||
#ifdef DEBUG_DETAIL_ON
|
||||
ESP_LOGD(TAG, "flashlight is found%s", _value);
|
||||
#endif
|
||||
if (strlen(_value) > 0)
|
||||
flashlightOn = true;
|
||||
}
|
||||
}
|
||||
|
||||
Camera.CaptureToStream(req, flashlightOn);
|
||||
|
||||
#ifdef DEBUG_DETAIL_ON
|
||||
LogFile.WriteHeapInfo("handler_stream - Done");
|
||||
#endif
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
|
||||
esp_err_t handler_flow_start(httpd_req_t *req) {
|
||||
|
||||
#ifdef DEBUG_DETAIL_ON
|
||||
@@ -216,7 +257,7 @@ esp_err_t handler_flow_start(httpd_req_t *req) {
|
||||
|
||||
httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
|
||||
|
||||
if (auto_isrunning) {
|
||||
if (autostartIsEnabled) {
|
||||
xTaskAbortDelay(xHandletask_autodoFlow); // Delay will be aborted if task is in blocked (waiting) state. If task is already running, no action
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Flow start triggered by REST API /flow_start");
|
||||
const char* resp_str = "The flow is going to be started immediately or is already running";
|
||||
@@ -245,7 +286,7 @@ esp_err_t MQTTCtrlFlowStart(std::string _topic) {
|
||||
|
||||
ESP_LOGD(TAG, "MQTTCtrlFlowStart: topic %s", _topic.c_str());
|
||||
|
||||
if (auto_isrunning)
|
||||
if (autostartIsEnabled)
|
||||
{
|
||||
xTaskAbortDelay(xHandletask_autodoFlow); // Delay will be aborted if task is in blocked (waiting) state. If task is already running, no action
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Flow start triggered by MQTT topic " + _topic);
|
||||
@@ -277,7 +318,7 @@ esp_err_t handler_json(httpd_req_t *req)
|
||||
httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
|
||||
httpd_resp_set_type(req, "application/json");
|
||||
|
||||
std::string zw = tfliteflow.getJSON();
|
||||
std::string zw = flowctrl.getJSON();
|
||||
if (zw.length() > 0)
|
||||
{
|
||||
httpd_resp_send(req, zw.c_str(), zw.length());
|
||||
@@ -370,7 +411,7 @@ esp_err_t handler_wasserzaehler(httpd_req_t *req)
|
||||
_intype = READOUT_TYPE_ERROR;
|
||||
|
||||
|
||||
zw = tfliteflow.getReadoutAll(_intype);
|
||||
zw = flowctrl.getReadoutAll(_intype);
|
||||
ESP_LOGD(TAG, "ZW: %s", zw.c_str());
|
||||
if (zw.length() > 0)
|
||||
httpd_resp_send(req, zw.c_str(), zw.length());
|
||||
@@ -379,7 +420,7 @@ esp_err_t handler_wasserzaehler(httpd_req_t *req)
|
||||
}
|
||||
|
||||
|
||||
std::string *status = tfliteflow.getActStatus();
|
||||
std::string *status = flowctrl.getActStatus();
|
||||
string query = std::string(_query);
|
||||
// ESP_LOGD(TAG, "Query: %s, query.c_str());
|
||||
if (query.find("full") != std::string::npos)
|
||||
@@ -397,8 +438,7 @@ esp_err_t handler_wasserzaehler(httpd_req_t *req)
|
||||
httpd_resp_sendstr_chunk(req, txt.c_str());
|
||||
}
|
||||
|
||||
|
||||
zw = tfliteflow.getReadout(_rawValue, _noerror);
|
||||
zw = flowctrl.getReadout(_rawValue, _noerror, 0);
|
||||
if (zw.length() > 0)
|
||||
httpd_resp_sendstr_chunk(req, zw.c_str());
|
||||
|
||||
@@ -413,15 +453,15 @@ 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;
|
||||
htmlinfodig = tfliteflow.GetAllDigital();
|
||||
htmlinfodig = flowctrl.GetAllDigital();
|
||||
|
||||
for (int i = 0; i < htmlinfodig.size(); ++i)
|
||||
{
|
||||
if (tfliteflow.GetTypeDigital() == Digital)
|
||||
if (flowctrl.GetTypeDigital() == Digital)
|
||||
{
|
||||
if (htmlinfodig[i]->val == 10)
|
||||
zw = "NaN";
|
||||
@@ -448,11 +488,11 @@ 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;
|
||||
htmlinfoana = tfliteflow.GetAllAnalog();
|
||||
htmlinfoana = flowctrl.GetAllAnalog();
|
||||
for (int i = 0; i < htmlinfoana.size(); ++i)
|
||||
{
|
||||
std::stringstream stream;
|
||||
@@ -470,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"))) {
|
||||
@@ -617,20 +657,33 @@ esp_err_t handler_editflow(httpd_req_t *req)
|
||||
|
||||
string out2 = out.substr(0, out.length() - 4) + "_org.jpg";
|
||||
|
||||
CAlignAndCutImage *caic = new CAlignAndCutImage(in);
|
||||
caic->CutAndSave(out2, x, y, dx, dy);
|
||||
delete caic;
|
||||
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...");
|
||||
|
||||
CImageBasis *cim = new CImageBasis(out2);
|
||||
if (enhance)
|
||||
{
|
||||
cim->Contrast(90);
|
||||
CAlignAndCutImage *caic = new CAlignAndCutImage("cutref", in);
|
||||
caic->CutAndSave(out2, x, y, dx, dy);
|
||||
delete caic;
|
||||
|
||||
CImageBasis *cim = new CImageBasis("cutref", out2);
|
||||
if (enhance)
|
||||
{
|
||||
cim->Contrast(90);
|
||||
}
|
||||
|
||||
cim->SaveToFile(out);
|
||||
delete cim;
|
||||
|
||||
psram_deinit_shared_memory_for_take_image_step();
|
||||
|
||||
|
||||
zw = "CutImage Done";
|
||||
}
|
||||
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: '" + *flowctrl.getActStatus() + "')!");
|
||||
zw = "Device Busy";
|
||||
}
|
||||
|
||||
cim->SaveToFile(out);
|
||||
delete cim;
|
||||
|
||||
zw = "CutImage Done";
|
||||
httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
|
||||
httpd_resp_send(req, zw.c_str(), zw.length());
|
||||
|
||||
@@ -674,7 +727,7 @@ esp_err_t handler_editflow(httpd_req_t *req)
|
||||
Camera.SetBrightnessContrastSaturation(bri, con, sat);
|
||||
Camera.SetLEDIntensity(intens);
|
||||
ESP_LOGD(TAG, "test_take - vor TakeImage");
|
||||
std::string zw = tfliteflow.doSingleStep("[TakeImage]", _host);
|
||||
std::string zw = flowctrl.doSingleStep("[TakeImage]", _host);
|
||||
httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
|
||||
httpd_resp_send(req, zw.c_str(), zw.length());
|
||||
}
|
||||
@@ -689,7 +742,7 @@ esp_err_t handler_editflow(httpd_req_t *req)
|
||||
// ESP_LOGD(TAG, "Parameter host: %s", _host.c_str());
|
||||
|
||||
// string zwzw = "Do " + _task + " start\n"; ESP_LOGD(TAG, zwzw.c_str());
|
||||
std::string zw = tfliteflow.doSingleStep("[Alignment]", _host);
|
||||
std::string zw = flowctrl.doSingleStep("[Alignment]", _host);
|
||||
httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
|
||||
httpd_resp_send(req, zw.c_str(), zw.length());
|
||||
}
|
||||
@@ -705,7 +758,7 @@ esp_err_t handler_editflow(httpd_req_t *req)
|
||||
esp_err_t handler_statusflow(httpd_req_t *req)
|
||||
{
|
||||
#ifdef DEBUG_DETAIL_ON
|
||||
LogFile.WriteHeapInfo("handler_prevalue - Start");
|
||||
LogFile.WriteHeapInfo("handler_statusflow - Start");
|
||||
#endif
|
||||
|
||||
const char* resp_str;
|
||||
@@ -714,10 +767,10 @@ esp_err_t handler_statusflow(httpd_req_t *req)
|
||||
if (bTaskAutoFlowCreated)
|
||||
{
|
||||
#ifdef DEBUG_DETAIL_ON
|
||||
ESP_LOGD(TAG, "handler_prevalue: %s", req->uri);
|
||||
ESP_LOGD(TAG, "handler_statusflow: %s", req->uri);
|
||||
#endif
|
||||
|
||||
string* zw = tfliteflow.getActStatusWithTime();
|
||||
string* zw = flowctrl.getActStatusWithTime();
|
||||
resp_str = zw->c_str();
|
||||
|
||||
httpd_resp_send(req, resp_str, HTTPD_RESP_USE_STRLEN);
|
||||
@@ -729,7 +782,7 @@ esp_err_t handler_statusflow(httpd_req_t *req)
|
||||
}
|
||||
|
||||
#ifdef DEBUG_DETAIL_ON
|
||||
LogFile.WriteHeapInfo("handler_prevalue - Done");
|
||||
LogFile.WriteHeapInfo("handler_statusflow - Done");
|
||||
#endif
|
||||
|
||||
return ESP_OK;
|
||||
@@ -801,50 +854,81 @@ esp_err_t handler_uptime(httpd_req_t *req)
|
||||
esp_err_t handler_prevalue(httpd_req_t *req)
|
||||
{
|
||||
#ifdef DEBUG_DETAIL_ON
|
||||
LogFile.WriteHeapInfo("handler_prevalue - Start");
|
||||
#endif
|
||||
|
||||
const char* resp_str;
|
||||
string zw;
|
||||
|
||||
#ifdef DEBUG_DETAIL_ON
|
||||
LogFile.WriteHeapInfo("handler_prevalue - Start");
|
||||
ESP_LOGD(TAG, "handler_prevalue: %s", req->uri);
|
||||
#endif
|
||||
|
||||
char _query[100];
|
||||
char _size[10] = "";
|
||||
char _numbers[50] = "default";
|
||||
// Default usage message when handler gets called without any parameter
|
||||
const std::string RESTUsageInfo =
|
||||
"00: Handler usage:<br>"
|
||||
"- To retrieve actual PreValue, please provide only a numbersname, e.g. /setPreValue?numbers=main<br>"
|
||||
"- To set PreValue to a new value, please provide a numbersname and a value, e.g. /setPreValue?numbers=main&value=1234.5678<br>"
|
||||
"NOTE:<br>"
|
||||
"value >= 0.0: Set PreValue to provided value<br>"
|
||||
"value < 0.0: Set PreValue to actual RAW value (as long RAW value is a valid number, without N)";
|
||||
|
||||
if (httpd_req_get_url_query_str(req, _query, 100) == ESP_OK)
|
||||
{
|
||||
// Default return error message when no return is programmed
|
||||
std::string sReturnMessage = "E90: Uninitialized";
|
||||
|
||||
char _query[100];
|
||||
char _numbersname[50] = "default";
|
||||
char _value[20] = "";
|
||||
|
||||
httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
|
||||
|
||||
if (httpd_req_get_url_query_str(req, _query, 100) == ESP_OK) {
|
||||
#ifdef DEBUG_DETAIL_ON
|
||||
ESP_LOGD(TAG, "Query: %s", _query);
|
||||
#endif
|
||||
|
||||
if (httpd_query_key_value(_query, "value", _size, 10) == ESP_OK)
|
||||
{
|
||||
#ifdef DEBUG_DETAIL_ON
|
||||
ESP_LOGD(TAG, "Value: %s", _size);
|
||||
#endif
|
||||
if (httpd_query_key_value(_query, "numbers", _numbersname, 50) != ESP_OK) { // If request is incomplete
|
||||
sReturnMessage = "E91: Query parameter incomplete or not valid!<br> "
|
||||
"Call /setPreValue to show REST API usage info and/or check documentation";
|
||||
httpd_resp_send(req, sReturnMessage.c_str(), sReturnMessage.length());
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
httpd_query_key_value(_query, "numbers", _numbers, 50);
|
||||
}
|
||||
|
||||
if (strlen(_size) == 0)
|
||||
{
|
||||
zw = tfliteflow.GetPrevalue(std::string(_numbers));
|
||||
if (httpd_query_key_value(_query, "value", _value, 20) == ESP_OK) {
|
||||
#ifdef DEBUG_DETAIL_ON
|
||||
ESP_LOGD(TAG, "Value: %s", _value);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
zw = "SetPrevalue to " + tfliteflow.UpdatePrevalue(_size, _numbers, true);
|
||||
}
|
||||
|
||||
resp_str = zw.c_str();
|
||||
else { // if no parameter is provided, print handler usage
|
||||
httpd_resp_send(req, RESTUsageInfo.c_str(), RESTUsageInfo.length());
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
|
||||
|
||||
httpd_resp_send(req, resp_str, HTTPD_RESP_USE_STRLEN);
|
||||
if (strlen(_value) == 0) { // If no value is povided --> return actual PreValue
|
||||
sReturnMessage = flowctrl.GetPrevalue(std::string(_numbersname));
|
||||
|
||||
if (sReturnMessage.empty()) {
|
||||
sReturnMessage = "E92: Numbers name not found";
|
||||
httpd_resp_send(req, sReturnMessage.c_str(), sReturnMessage.length());
|
||||
return ESP_FAIL;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// New value is positive: Set PreValue to provided value and return value
|
||||
// New value is negative and actual RAW value is a valid number: Set PreValue to RAW value and return value
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "REST API handler_prevalue called: numbersname: " + std::string(_numbersname) +
|
||||
", value: " + std::string(_value));
|
||||
if (!flowctrl.UpdatePrevalue(_value, _numbersname, true)) {
|
||||
sReturnMessage = "E93: Update request rejected. Please check device logs for more details";
|
||||
httpd_resp_send(req, sReturnMessage.c_str(), sReturnMessage.length());
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
sReturnMessage = flowctrl.GetPrevalue(std::string(_numbersname));
|
||||
|
||||
if (sReturnMessage.empty()) {
|
||||
sReturnMessage = "E94: Numbers name not found";
|
||||
httpd_resp_send(req, sReturnMessage.c_str(), sReturnMessage.length());
|
||||
return ESP_FAIL;
|
||||
}
|
||||
}
|
||||
|
||||
httpd_resp_send(req, sReturnMessage.c_str(), sReturnMessage.length());
|
||||
|
||||
#ifdef DEBUG_DETAIL_ON
|
||||
LogFile.WriteHeapInfo("handler_prevalue - End");
|
||||
@@ -862,7 +946,7 @@ void task_autodoFlow(void *pvParameter)
|
||||
|
||||
if (!isPlannedReboot && (esp_reset_reason() == ESP_RST_PANIC))
|
||||
{
|
||||
tfliteflow.setActStatus("Initialization (delayed)");
|
||||
flowctrl.setActStatus("Initialization (delayed)");
|
||||
//#ifdef ENABLE_MQTT
|
||||
//MQTTPublish(mqttServer_getMainTopic() + "/" + "status", "Initialization (delayed)", false); // Right now, not possible -> MQTT Service is going to be started later
|
||||
//#endif //ENABLE_MQTT
|
||||
@@ -872,16 +956,25 @@ void task_autodoFlow(void *pvParameter)
|
||||
ESP_LOGD(TAG, "task_autodoFlow: start");
|
||||
doInit();
|
||||
|
||||
auto_isrunning = tfliteflow.isAutoStart(auto_interval);
|
||||
flowctrl.setAutoStartInterval(auto_interval);
|
||||
autostartIsEnabled = flowctrl.getIsAutoStart();
|
||||
|
||||
if (isSetupModusActive())
|
||||
{
|
||||
auto_isrunning = false;
|
||||
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "We are in Setup Mode -> Not starting Auto Flow!");
|
||||
autostartIsEnabled = false;
|
||||
std::string zw_time = getCurrentTimeString(LOGFILE_TIME_FORMAT);
|
||||
tfliteflow.doFlowTakeImageOnly(zw_time);
|
||||
flowctrl.doFlowTakeImageOnly(zw_time);
|
||||
}
|
||||
|
||||
if (autostartIsEnabled) {
|
||||
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Starting Flow...");
|
||||
}
|
||||
else {
|
||||
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Autostart is not enabled -> Not starting Flow");
|
||||
}
|
||||
|
||||
while (auto_isrunning)
|
||||
while (autostartIsEnabled)
|
||||
{
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "----------------------------------------------------------------"); // Clear separation between runs
|
||||
std::string _zw = "Round #" + std::to_string(++countRounds) + " started";
|
||||
@@ -943,13 +1036,19 @@ void task_autodoFlow(void *pvParameter)
|
||||
vTaskDelay( xDelay );
|
||||
}
|
||||
}
|
||||
|
||||
while(1) // Keep flow task running to handle necessary sub tasks like reboot handler, etc..
|
||||
{
|
||||
vTaskDelay(2000 / portTICK_PERIOD_MS);
|
||||
}
|
||||
|
||||
vTaskDelete(NULL); //Delete this task if it exits from the loop above
|
||||
xHandletask_autodoFlow = NULL;
|
||||
ESP_LOGD(TAG, "task_autodoFlow: end");
|
||||
}
|
||||
|
||||
|
||||
void TFliteDoAutoStart()
|
||||
void InitializeFlowTask()
|
||||
{
|
||||
BaseType_t xReturned;
|
||||
|
||||
@@ -966,17 +1065,9 @@ void TFliteDoAutoStart()
|
||||
}
|
||||
|
||||
|
||||
#ifdef ENABLE_MQTT
|
||||
std::string GetMQTTMainTopic()
|
||||
void register_server_main_flow_task_uri(httpd_handle_t server)
|
||||
{
|
||||
return tfliteflow.GetMQTTMainTopic();
|
||||
}
|
||||
#endif//ENABLE_MQTT
|
||||
|
||||
|
||||
void register_server_tflite_uri(httpd_handle_t server)
|
||||
{
|
||||
ESP_LOGI(TAG, "server_part_camera - Registering URI handlers");
|
||||
ESP_LOGI(TAG, "server_main_flow_task - Registering URI handlers");
|
||||
|
||||
httpd_uri_t camuri = { };
|
||||
camuri.method = HTTP_GET;
|
||||
@@ -1070,4 +1161,10 @@ void register_server_tflite_uri(httpd_handle_t server)
|
||||
camuri.handler = handler_get_heap;
|
||||
camuri.user_ctx = (void*) "Heap";
|
||||
httpd_register_uri_handler(server, &camuri);
|
||||
|
||||
camuri.uri = "/stream";
|
||||
camuri.handler = handler_stream;
|
||||
camuri.user_ctx = (void*) "stream";
|
||||
httpd_register_uri_handler(server, &camuri);
|
||||
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef SERVERTFLITE_H
|
||||
#define SERVERTFLITE_H
|
||||
#ifndef MAINFLOWCONTROL_H
|
||||
#define MAINFLOWCONTROL_H
|
||||
|
||||
#include <esp_log.h>
|
||||
#include <string>
|
||||
@@ -10,25 +10,25 @@
|
||||
#include "CImageBasis.h"
|
||||
#include "ClassFlowControll.h"
|
||||
|
||||
//#include "ClassControllCamera.h"
|
||||
extern ClassFlowControll flowctrl;
|
||||
|
||||
extern ClassFlowControll tfliteflow;
|
||||
void register_server_tflite_uri(httpd_handle_t server);
|
||||
|
||||
void KillTFliteTasks();
|
||||
void TFliteDoAutoStart();
|
||||
bool isSetupModusActive();
|
||||
int getCountFlowRounds();
|
||||
void register_server_main_flow_task_uri(httpd_handle_t server);
|
||||
|
||||
void CheckIsPlannedReboot();
|
||||
bool getIsPlannedReboot();
|
||||
|
||||
esp_err_t GetJPG(std::string _filename, httpd_req_t *req);
|
||||
esp_err_t GetRawJPG(httpd_req_t *req);
|
||||
void InitializeFlowTask();
|
||||
void DeleteMainFlowTask();
|
||||
bool isSetupModusActive();
|
||||
|
||||
int getCountFlowRounds();
|
||||
|
||||
#ifdef ENABLE_MQTT
|
||||
std::string GetMQTTMainTopic();
|
||||
esp_err_t MQTTCtrlFlowStart(std::string);
|
||||
esp_err_t MQTTCtrlFlowStart(std::string _topic);
|
||||
#endif //ENABLE_MQTT
|
||||
|
||||
#endif //SERVERTFLITE_H
|
||||
esp_err_t GetRawJPG(httpd_req_t *req);
|
||||
esp_err_t GetJPG(std::string _filename, httpd_req_t *req);
|
||||
|
||||
#endif //MAINFLOWCONTROL_H
|
||||
@@ -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 fatfs sdmmc)
|
||||
REQUIRES esp_timer esp-tflite-micro jomjol_logfile fatfs sdmmc vfs)
|
||||
|
||||
|
||||
|
||||
@@ -23,12 +23,14 @@ extern "C" {
|
||||
|
||||
#include <string.h>
|
||||
#include <esp_log.h>
|
||||
#include <esp_mac.h>
|
||||
#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";
|
||||
|
||||
@@ -38,7 +40,7 @@ unsigned int systemStatus = 0;
|
||||
|
||||
sdmmc_cid_t SDCardCid;
|
||||
sdmmc_csd_t SDCardCsd;
|
||||
|
||||
bool SDCardIsMMC;
|
||||
|
||||
// #define DEBUG_DETAIL_ON
|
||||
|
||||
@@ -64,14 +66,14 @@ string getESPHeapInfo(){
|
||||
|
||||
sprintf(aMsgBuf," | SPI Free: %ld", (long) aFreeSPIHeapSize);
|
||||
espInfoResultStr += string(aMsgBuf);
|
||||
sprintf(aMsgBuf," | SPI Larg Block: %ld", (long) aHeapLargestFreeBlockSize);
|
||||
sprintf(aMsgBuf," | SPI Large Block: %ld", (long) aHeapLargestFreeBlockSize);
|
||||
espInfoResultStr += string(aMsgBuf);
|
||||
sprintf(aMsgBuf," | SPI Min Free: %ld", (long) aMinFreeHeapSize);
|
||||
espInfoResultStr += string(aMsgBuf);
|
||||
|
||||
sprintf(aMsgBuf," | Int Free: %ld", (long) (aFreeInternalHeapSize));
|
||||
espInfoResultStr += string(aMsgBuf);
|
||||
sprintf(aMsgBuf," | Int Larg Block: %ld", (long) aHeapIntLargestFreeBlockSize);
|
||||
sprintf(aMsgBuf," | Int Large Block: %ld", (long) aHeapIntLargestFreeBlockSize);
|
||||
espInfoResultStr += string(aMsgBuf);
|
||||
sprintf(aMsgBuf," | Int Min Free: %ld", (long) (aMinFreeInternalHeapSize));
|
||||
espInfoResultStr += string(aMsgBuf);
|
||||
@@ -137,6 +139,7 @@ string getSDCardPartitionAllocationSize(){
|
||||
void SaveSDCardInfo(sdmmc_card_t* card) {
|
||||
SDCardCid = card->cid;
|
||||
SDCardCsd = card->csd;
|
||||
SDCardIsMMC = card->is_mmc;
|
||||
}
|
||||
|
||||
|
||||
@@ -672,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,
|
||||
@@ -777,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 @@
|
||||
#ifdef DEBUG_ENABLE_SYSINFO
|
||||
|
||||
#include "esp_sys.h"
|
||||
#include "esp_chip_info.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
@@ -121,7 +122,7 @@ std::string get_device_info()
|
||||
}
|
||||
|
||||
#ifdef USE_HIMEM_IF_AVAILABLE
|
||||
sprintf(aMsgBuf,"spiram size %u\n", esp_spiram_get_size());
|
||||
sprintf(aMsgBuf,"spiram size %u\n", esp_psram_get_size());
|
||||
espInfoResultStr += std::string(aMsgBuf);
|
||||
sprintf(aMsgBuf,"himem free %u\n", esp_himem_get_free_size());
|
||||
espInfoResultStr += std::string(aMsgBuf);
|
||||
|
||||
@@ -16,9 +16,9 @@
|
||||
#include <esp_spi_flash.h>
|
||||
#include <esp_heap_caps.h>
|
||||
|
||||
// for esp_spiram_get_size
|
||||
// for esp_psram_get_size
|
||||
extern "C" {
|
||||
#include <esp32/spiram.h>
|
||||
#include "esp_psram.h"
|
||||
#ifdef USE_HIMEM_IF_AVAILABLE
|
||||
#include <esp32/himem.h>
|
||||
#endif
|
||||
|
||||
211
code/components/jomjol_helper/psram.cpp
Normal file
211
code/components/jomjol_helper/psram.cpp
Normal file
@@ -0,0 +1,211 @@
|
||||
#include "ClassLogFile.h"
|
||||
#include "../../include/defines.h"
|
||||
#include "psram.h"
|
||||
|
||||
static const char* TAG = "PSRAM";
|
||||
|
||||
using namespace std;
|
||||
|
||||
|
||||
void *shared_region = NULL;
|
||||
uint32_t allocatedBytesForSTBI = 0;
|
||||
std::string sharedMemoryInUseFor = "";
|
||||
|
||||
|
||||
/** Reserve a large block in the PSRAM which will be shared between the different steps.
|
||||
* Each step uses it differently but only wiuthin itself. */
|
||||
bool reserve_psram_shared_region(void) {
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Allocating shared PSRAM region (" +
|
||||
std::to_string(TENSOR_ARENA_SIZE + MAX_MODEL_SIZE) + " bytes)...");
|
||||
shared_region = malloc_psram_heap("Shared PSRAM region", TENSOR_ARENA_SIZE + MAX_MODEL_SIZE,
|
||||
MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
|
||||
|
||||
if (shared_region == NULL) {
|
||||
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Failed to allocating shared PSRAM region!");
|
||||
return false;
|
||||
}
|
||||
else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************
|
||||
* Memory used in Take Image (STBI)
|
||||
*******************************************************************/
|
||||
bool psram_init_shared_memory_for_take_image_step(void) {
|
||||
if (sharedMemoryInUseFor != "") {
|
||||
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Shared memory in PSRAM already in use for " + sharedMemoryInUseFor + "!");
|
||||
return false;
|
||||
}
|
||||
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Init shared memory for step 'Take Image' (STBI buffers)");
|
||||
allocatedBytesForSTBI = 0;
|
||||
sharedMemoryInUseFor = "TakeImage";
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void psram_deinit_shared_memory_for_take_image_step(void) {
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Deinit shared memory for step 'Take Image' (STBI buffers)");
|
||||
allocatedBytesForSTBI = 0;
|
||||
sharedMemoryInUseFor = "";
|
||||
}
|
||||
|
||||
|
||||
void *psram_reserve_shared_stbi_memory(size_t size) {
|
||||
/* Only large buffers should be placed in the shared PSRAM
|
||||
* If we also place all smaller STBI buffers here, we get artefacts for some reasons. */
|
||||
if (size >= 100000) {
|
||||
if ((allocatedBytesForSTBI + size) > TENSOR_ARENA_SIZE + MAX_MODEL_SIZE) { // Check if it still fits in the shared region
|
||||
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Shared memory in PSRAM too small (STBI) to fit additional " +
|
||||
std::to_string(size) + " bytes! Available: " + std::to_string(TENSOR_ARENA_SIZE + MAX_MODEL_SIZE - allocatedBytesForSTBI) + " bytes!");
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Allocating memory (" + std::to_string(size) + " bytes) for STBI (use shared memory in PSRAM)...");
|
||||
allocatedBytesForSTBI += size;
|
||||
return (uint8_t *)shared_region + allocatedBytesForSTBI - size;
|
||||
}
|
||||
else { // Normal PSRAM
|
||||
return malloc_psram_heap("STBI", size, MALLOC_CAP_SPIRAM);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void *psram_reallocate_shared_stbi_memory(void *ptr, size_t newsize) {
|
||||
char buf[20];
|
||||
sprintf(buf, "%p", ptr);
|
||||
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "STBI requested realloc for " + std::string(buf) + " but this is currently unsupported!");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
void psram_free_shared_stbi_memory(void *p) {
|
||||
if ((p >= shared_region) && (p <= ((uint8_t *)shared_region + allocatedBytesForSTBI))) { // was allocated inside the shared memory
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Part of shared memory used for STBI (PSRAM, part of shared memory) is free again");
|
||||
}
|
||||
else { // Normal PSRAM
|
||||
free_psram_heap("STBI", p);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************
|
||||
* Memory used in Aligning Step
|
||||
* During this step we only use the shared part of the PSRAM
|
||||
* for the tmpImage.
|
||||
*******************************************************************/
|
||||
void *psram_reserve_shared_tmp_image_memory(void) {
|
||||
if (sharedMemoryInUseFor != "") {
|
||||
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Shared memory in PSRAM already in use for " + sharedMemoryInUseFor + "!");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Allocating tmpImage (" + std::to_string(IMAGE_SIZE) + " bytes, use shared memory in PSRAM)...");
|
||||
sharedMemoryInUseFor = "Aligning";
|
||||
return shared_region; // Use 1th part of the shared memory for the tmpImage (only user)
|
||||
}
|
||||
|
||||
|
||||
void psram_free_shared_temp_image_memory(void) {
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Shared memory used for tmpImage (PSRAM, part of shared memory) is free again");
|
||||
sharedMemoryInUseFor = "";
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************
|
||||
* Memory used in Digitalization Steps
|
||||
* During this step we only use the shared part of the PSRAM for the
|
||||
* Tensor Arena and one of the Models.
|
||||
* The shared memory is large enough for the largest model and the
|
||||
* Tensor Arena. Therefore we do not need to monitor the usage.
|
||||
*******************************************************************/
|
||||
void *psram_get_shared_tensor_arena_memory(void) {
|
||||
if ((sharedMemoryInUseFor == "") || (sharedMemoryInUseFor == "Digitalization_Model")) {
|
||||
sharedMemoryInUseFor = "Digitalization_Tensor";
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Allocating Tensor Arena (" + std::to_string(TENSOR_ARENA_SIZE) + " bytes, use shared memory in PSRAM)...");
|
||||
return shared_region; // Use 1th part of the shared memory for Tensor
|
||||
}
|
||||
else {
|
||||
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Shared memory in PSRAM already in use for " + sharedMemoryInUseFor + "!");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void *psram_get_shared_model_memory(void) {
|
||||
if ((sharedMemoryInUseFor == "") || (sharedMemoryInUseFor == "Digitalization_Tensor")) {
|
||||
sharedMemoryInUseFor = "Digitalization_Model";
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Allocating Model memory (" + std::to_string(MAX_MODEL_SIZE) + " bytes, use shared memory in PSRAM)...");
|
||||
return (uint8_t *)shared_region + TENSOR_ARENA_SIZE; // Use 2nd part of the shared memory (after Tensor Arena) for the model
|
||||
}
|
||||
else {
|
||||
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Shared memory in PSRAM already in use for " + sharedMemoryInUseFor + "!");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void psram_free_shared_tensor_arena_and_model_memory(void) {
|
||||
sharedMemoryInUseFor = "";
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Shared memory used for Tensor Arena and model (PSRAM, part of shared memory) is free again");
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*******************************************************************
|
||||
* General
|
||||
*******************************************************************/
|
||||
void *malloc_psram_heap(std::string name, size_t size, uint32_t caps) {
|
||||
void *ptr;
|
||||
|
||||
ptr = heap_caps_malloc(size, caps);
|
||||
if (ptr != NULL) {
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Allocated " + to_string(size) + " bytes in PSRAM for '" + name + "'");
|
||||
}
|
||||
else {
|
||||
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Failed to allocate " + to_string(size) + " bytes in PSRAM for '" + name + "'!");
|
||||
}
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
|
||||
void *realloc_psram_heap(std::string name, void *ptr, size_t size, uint32_t caps) {
|
||||
ptr = heap_caps_realloc(ptr, size, caps);
|
||||
if (ptr != NULL) {
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Reallocated " + to_string(size) + " bytes in PSRAM for '" + name + "'");
|
||||
}
|
||||
else {
|
||||
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Failed to reallocate " + to_string(size) + " bytes in PSRAM for '" + name + "'!");
|
||||
}
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
|
||||
void *calloc_psram_heap(std::string name, size_t n, size_t size, uint32_t caps) {
|
||||
void *ptr;
|
||||
|
||||
ptr = heap_caps_calloc(n, size, caps);
|
||||
if (ptr != NULL) {
|
||||
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Allocated " + to_string(size) + " bytes in PSRAM for '" + name + "'");
|
||||
}
|
||||
else {
|
||||
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Failed to allocate " + to_string(size) + " bytes in PSRAM for '" + name + "'!");
|
||||
}
|
||||
|
||||
return ptr;
|
||||
}
|
||||
|
||||
|
||||
void free_psram_heap(std::string name, void *ptr) {
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Freeing memory in PSRAM used for '" + name + "'...");
|
||||
heap_caps_free(ptr);
|
||||
}
|
||||
35
code/components/jomjol_helper/psram.h
Normal file
35
code/components/jomjol_helper/psram.h
Normal file
@@ -0,0 +1,35 @@
|
||||
#pragma once
|
||||
#ifndef PSRAM_h
|
||||
#define PSRAM_h
|
||||
|
||||
#include "esp_heap_caps.h"
|
||||
|
||||
|
||||
bool reserve_psram_shared_region(void);
|
||||
|
||||
|
||||
/* Memory used in Take Image Step */
|
||||
bool psram_init_shared_memory_for_take_image_step(void);
|
||||
void psram_deinit_shared_memory_for_take_image_step(void);
|
||||
void *psram_reserve_shared_stbi_memory(size_t size);
|
||||
void *psram_reallocate_shared_stbi_memory(void *ptr, size_t newsize);
|
||||
void psram_free_shared_stbi_memory(void *p);
|
||||
|
||||
|
||||
/* Memory used in Aligning Step */
|
||||
void *psram_reserve_shared_tmp_image_memory(void);
|
||||
void psram_free_shared_temp_image_memory(void);
|
||||
|
||||
/* Memory used in Digitalization Steps */
|
||||
void *psram_get_shared_tensor_arena_memory(void);
|
||||
void *psram_get_shared_model_memory(void);
|
||||
void psram_free_shared_tensor_arena_and_model_memory(void);
|
||||
|
||||
/* General */
|
||||
void *malloc_psram_heap(std::string name, size_t size, uint32_t caps);
|
||||
void *realloc_psram_heap(std::string name, void *ptr, size_t size, uint32_t caps);
|
||||
void *calloc_psram_heap(std::string name, size_t n, size_t size, uint32_t caps);
|
||||
|
||||
void free_psram_heap(std::string name, void *ptr);
|
||||
|
||||
#endif // PSRAM_h
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
#include <inttypes.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
@@ -147,12 +148,6 @@ bool SDCardCheckFolderFilePresence()
|
||||
bRetval = false;
|
||||
}
|
||||
|
||||
/* check if file exists: gethost.js */
|
||||
if (stat("/sdcard/html/gethost.js", &sb) != 0) {
|
||||
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Folder/file check: File /html/gethost.js not found");
|
||||
bRetval = false;
|
||||
}
|
||||
|
||||
/* check if file exists: version.txt */
|
||||
if (stat("/sdcard/html/version.txt", &sb) != 0) {
|
||||
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Folder/file check: File /html/version.txt not found");
|
||||
@@ -163,4 +158,4 @@ bool SDCardCheckFolderFilePresence()
|
||||
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Folder/file presence check successful");
|
||||
|
||||
return bRetval;
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -7,6 +7,11 @@
|
||||
#include "ClassLogFile.h"
|
||||
#include "../../include/defines.h"
|
||||
|
||||
// define `gpio_pad_select_gpip` for newer versions of IDF
|
||||
#if (ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 3, 0))
|
||||
#include "esp_rom_gpio.h"
|
||||
#define gpio_pad_select_gpio esp_rom_gpio_pad_select_gpio
|
||||
#endif
|
||||
|
||||
static const char* TAG = "STATUSLED";
|
||||
|
||||
|
||||
@@ -5,12 +5,14 @@
|
||||
#include <math.h>
|
||||
#include <algorithm>
|
||||
#include <esp_log.h>
|
||||
#include "psram.h"
|
||||
#include "../../include/defines.h"
|
||||
|
||||
static const char* TAG = "c_align_and_cut_image";
|
||||
|
||||
CAlignAndCutImage::CAlignAndCutImage(CImageBasis *_org, CImageBasis *_temp)
|
||||
CAlignAndCutImage::CAlignAndCutImage(std::string _name, CImageBasis *_org, CImageBasis *_temp) : CImageBasis(_name)
|
||||
{
|
||||
name = _name;
|
||||
rgb_image = _org->rgb_image;
|
||||
channels = _org->channels;
|
||||
width = _org->width;
|
||||
@@ -37,7 +39,7 @@ bool CAlignAndCutImage::Align(RefInfo *_temp1, RefInfo *_temp2)
|
||||
int r0_x, r0_y, r1_x, r1_y;
|
||||
bool isSimilar1, isSimilar2;
|
||||
|
||||
CFindTemplate* ft = new CFindTemplate(rgb_image, channels, width, height, bpp);
|
||||
CFindTemplate* ft = new CFindTemplate("align", rgb_image, channels, width, height, bpp);
|
||||
|
||||
r0_x = _temp1->target_x;
|
||||
r0_y = _temp1->target_y;
|
||||
@@ -81,7 +83,7 @@ bool CAlignAndCutImage::Align(RefInfo *_temp1, RefInfo *_temp2)
|
||||
LogFile.WriteToDedicatedFile("/sdcard/alignment.txt", zw);
|
||||
#endif*/
|
||||
|
||||
CRotateImage rt(this, ImageTMP);
|
||||
CRotateImage rt("Align", this, ImageTMP);
|
||||
rt.Translate(dx, dy);
|
||||
rt.Rotate(d_winkel, _temp1->target_x, _temp1->target_y);
|
||||
ESP_LOGD(TAG, "Alignment: dx %d - dy %d - rot %f", dx, dy, d_winkel);
|
||||
@@ -107,7 +109,7 @@ void CAlignAndCutImage::CutAndSave(std::string _template1, int x1, int y1, int d
|
||||
dy = y2 - y1;
|
||||
|
||||
int memsize = dx * dy * channels;
|
||||
uint8_t* odata = (unsigned char*) GET_MEMORY(memsize);
|
||||
uint8_t* odata = (unsigned char*) malloc_psram_heap(std::string(TAG) + "->odata", memsize, MALLOC_CAP_SPIRAM);
|
||||
|
||||
stbi_uc* p_target;
|
||||
stbi_uc* p_source;
|
||||
@@ -186,7 +188,7 @@ CImageBasis* CAlignAndCutImage::CutAndSave(int x1, int y1, int dx, int dy)
|
||||
dy = y2 - y1;
|
||||
|
||||
int memsize = dx * dy * channels;
|
||||
uint8_t* odata = (unsigned char*)GET_MEMORY(memsize);
|
||||
uint8_t* odata = (unsigned char*)malloc_psram_heap(std::string(TAG) + "->odata", memsize, MALLOC_CAP_SPIRAM);
|
||||
|
||||
stbi_uc* p_target;
|
||||
stbi_uc* p_source;
|
||||
@@ -202,7 +204,7 @@ CImageBasis* CAlignAndCutImage::CutAndSave(int x1, int y1, int dx, int dy)
|
||||
p_target[_channels] = p_source[_channels];
|
||||
}
|
||||
|
||||
CImageBasis* rs = new CImageBasis(odata, channels, dx, dy, bpp);
|
||||
CImageBasis* rs = new CImageBasis("CutAndSave", odata, channels, dx, dy, bpp);
|
||||
RGBImageRelease();
|
||||
rs->SetIndepended();
|
||||
return rs;
|
||||
|
||||
@@ -12,9 +12,9 @@ class CAlignAndCutImage : public CImageBasis
|
||||
public:
|
||||
int t0_dx, t0_dy, t1_dx, t1_dy;
|
||||
CImageBasis *ImageTMP;
|
||||
CAlignAndCutImage(std::string _image) : CImageBasis(_image) {ImageTMP = NULL;};
|
||||
CAlignAndCutImage(uint8_t* _rgb_image, int _channels, int _width, int _height, int _bpp) : CImageBasis(_rgb_image, _channels, _width, _height, _bpp) {ImageTMP = NULL;};
|
||||
CAlignAndCutImage(CImageBasis *_org, CImageBasis *_temp);
|
||||
CAlignAndCutImage(std::string name, std::string _image) : CImageBasis(name, _image) {ImageTMP = NULL;};
|
||||
CAlignAndCutImage(std::string name, uint8_t* _rgb_image, int _channels, int _width, int _height, int _bpp) : CImageBasis(name, _rgb_image, _channels, _width, _height, _bpp) {ImageTMP = NULL;};
|
||||
CAlignAndCutImage(std::string name, CImageBasis *_org, CImageBasis *_temp);
|
||||
|
||||
bool Align(RefInfo *_temp1, RefInfo *_temp2);
|
||||
// void Align(std::string _template1, int x1, int y1, std::string _template2, int x2, int y2, int deltax = 40, int deltay = 40, std::string imageROI = "");
|
||||
|
||||
@@ -32,7 +32,7 @@ class CFindTemplate : public CImageBasis
|
||||
{
|
||||
public:
|
||||
int tpl_width, tpl_height, tpl_bpp;
|
||||
CFindTemplate(uint8_t* _rgb_image, int _channels, int _width, int _height, int _bpp) : CImageBasis(_rgb_image, _channels, _width, _height, _bpp) {};
|
||||
CFindTemplate(std::string name, uint8_t* _rgb_image, int _channels, int _width, int _height, int _bpp) : CImageBasis(name, _rgb_image, _channels, _width, _height, _bpp) {};
|
||||
|
||||
bool FindTemplate(RefInfo *_ref);
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#include "CImageBasis.h"
|
||||
#include "Helper.h"
|
||||
#include "psram.h"
|
||||
#include "ClassLogFile.h"
|
||||
#include "server_ota.h"
|
||||
|
||||
@@ -360,8 +361,9 @@ void CImageBasis::drawCircle(int x1, int y1, int rad, int r, int g, int b, int t
|
||||
}
|
||||
|
||||
|
||||
CImageBasis::CImageBasis()
|
||||
CImageBasis::CImageBasis(string _name)
|
||||
{
|
||||
name = _name;
|
||||
externalImage = false;
|
||||
rgb_image = NULL;
|
||||
width = 0;
|
||||
@@ -384,8 +386,9 @@ void CImageBasis::CreateEmptyImage(int _width, int _height, int _channels)
|
||||
LogFile.WriteHeapInfo("CreateEmptyImage");
|
||||
#endif
|
||||
|
||||
int memsize = width * height * channels;
|
||||
rgb_image = (unsigned char*)GET_MEMORY(memsize);
|
||||
memsize = width * height * channels;
|
||||
|
||||
rgb_image = (unsigned char*)malloc_psram_heap(std::string(TAG) + "->CImageBasis (" + name + ")", memsize, MALLOC_CAP_SPIRAM);
|
||||
|
||||
if (rgb_image == NULL)
|
||||
{
|
||||
@@ -435,8 +438,10 @@ void CImageBasis::LoadFromMemory(stbi_uc *_buffer, int len)
|
||||
{
|
||||
RGBImageLock();
|
||||
|
||||
if (rgb_image)
|
||||
if (rgb_image != NULL) {
|
||||
stbi_image_free(rgb_image);
|
||||
//free_psram_heap(std::string(TAG) + "->rgb_image (LoadFromMemory)", rgb_image);
|
||||
}
|
||||
|
||||
rgb_image = stbi_load_from_memory(_buffer, len, &width, &height, &channels, 3);
|
||||
bpp = channels;
|
||||
@@ -454,8 +459,9 @@ void CImageBasis::LoadFromMemory(stbi_uc *_buffer, int len)
|
||||
}
|
||||
|
||||
|
||||
CImageBasis::CImageBasis(CImageBasis *_copyfrom)
|
||||
CImageBasis::CImageBasis(string _name, CImageBasis *_copyfrom)
|
||||
{
|
||||
name = _name;
|
||||
islocked = false;
|
||||
externalImage = false;
|
||||
channels = _copyfrom->channels;
|
||||
@@ -469,8 +475,15 @@ CImageBasis::CImageBasis(CImageBasis *_copyfrom)
|
||||
LogFile.WriteHeapInfo("CImageBasis_copyfrom - Start");
|
||||
#endif
|
||||
|
||||
int memsize = width * height * channels;
|
||||
rgb_image = (unsigned char*)GET_MEMORY(memsize);
|
||||
memsize = width * height * channels;
|
||||
|
||||
|
||||
if (name == "tmpImage") {
|
||||
rgb_image = (unsigned char*)psram_reserve_shared_tmp_image_memory();
|
||||
}
|
||||
else {
|
||||
rgb_image = (unsigned char*)malloc_psram_heap(std::string(TAG) + "->CImageBasis (" + name + ")", memsize, MALLOC_CAP_SPIRAM);
|
||||
}
|
||||
|
||||
if (rgb_image == NULL)
|
||||
{
|
||||
@@ -489,8 +502,9 @@ CImageBasis::CImageBasis(CImageBasis *_copyfrom)
|
||||
}
|
||||
|
||||
|
||||
CImageBasis::CImageBasis(int _width, int _height, int _channels)
|
||||
CImageBasis::CImageBasis(string _name, int _width, int _height, int _channels)
|
||||
{
|
||||
name = _name;
|
||||
islocked = false;
|
||||
externalImage = false;
|
||||
channels = _channels;
|
||||
@@ -504,8 +518,9 @@ CImageBasis::CImageBasis(int _width, int _height, int _channels)
|
||||
LogFile.WriteHeapInfo("CImageBasis_width,height,ch - Start");
|
||||
#endif
|
||||
|
||||
int memsize = width * height * channels;
|
||||
rgb_image = (unsigned char*)GET_MEMORY(memsize);
|
||||
memsize = width * height * channels;
|
||||
|
||||
rgb_image = (unsigned char*)malloc_psram_heap(std::string(TAG) + "->CImageBasis (" + name + ")", memsize, MALLOC_CAP_SPIRAM);
|
||||
|
||||
if (rgb_image == NULL)
|
||||
{
|
||||
@@ -523,8 +538,9 @@ CImageBasis::CImageBasis(int _width, int _height, int _channels)
|
||||
}
|
||||
|
||||
|
||||
CImageBasis::CImageBasis(std::string _image)
|
||||
CImageBasis::CImageBasis(string _name, std::string _image)
|
||||
{
|
||||
name = _name;
|
||||
islocked = false;
|
||||
channels = 3;
|
||||
externalImage = false;
|
||||
@@ -569,8 +585,9 @@ bool CImageBasis::ImageOkay(){
|
||||
}
|
||||
|
||||
|
||||
CImageBasis::CImageBasis(uint8_t* _rgb_image, int _channels, int _width, int _height, int _bpp)
|
||||
CImageBasis::CImageBasis(string _name, uint8_t* _rgb_image, int _channels, int _width, int _height, int _bpp)
|
||||
{
|
||||
name = _name;
|
||||
islocked = false;
|
||||
rgb_image = _rgb_image;
|
||||
channels = _channels;
|
||||
@@ -607,8 +624,21 @@ CImageBasis::~CImageBasis()
|
||||
{
|
||||
RGBImageLock();
|
||||
|
||||
if (!externalImage)
|
||||
stbi_image_free(rgb_image);
|
||||
|
||||
if (!externalImage) {
|
||||
if (name == "tmpImage") { // This image should be placed in the shared part of PSRAM
|
||||
psram_free_shared_temp_image_memory();
|
||||
}
|
||||
else { // All other images are much smaller and can go into the normal PSRAM region
|
||||
//stbi_image_free(rgb_image);
|
||||
if (memsize == 0) {
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Not freeing (" + name + " as there was never PSRAM allocated for it)");
|
||||
}
|
||||
else {
|
||||
free_psram_heap(std::string(TAG) + "->CImageBasis (" + name + ", " + to_string(memsize) + ")", rgb_image);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RGBImageRelease();
|
||||
}
|
||||
@@ -637,19 +667,19 @@ void CImageBasis::SaveToFile(std::string _imageout)
|
||||
|
||||
void CImageBasis::Resize(int _new_dx, int _new_dy)
|
||||
{
|
||||
int memsize = _new_dx * _new_dy * channels;
|
||||
uint8_t* odata = (unsigned char*)GET_MEMORY(memsize);
|
||||
memsize = _new_dx * _new_dy * channels;
|
||||
uint8_t* odata = (unsigned char*)malloc_psram_heap(std::string(TAG) + "->odata", memsize, MALLOC_CAP_SPIRAM);
|
||||
|
||||
RGBImageLock();
|
||||
|
||||
stbir_resize_uint8(rgb_image, width, height, 0, odata, _new_dx, _new_dy, 0, channels);
|
||||
stbi_image_free(rgb_image);
|
||||
|
||||
rgb_image = (unsigned char*)GET_MEMORY(memsize);
|
||||
rgb_image = (unsigned char*)malloc_psram_heap(std::string(TAG) + "->CImageBasis Resize (" + name + ")", memsize, MALLOC_CAP_SPIRAM);
|
||||
memCopy(odata, rgb_image, memsize);
|
||||
width = _new_dx;
|
||||
height = _new_dy;
|
||||
stbi_image_free(odata);
|
||||
|
||||
free_psram_heap(std::string(TAG) + "->odata", odata);
|
||||
|
||||
RGBImageRelease();
|
||||
}
|
||||
|
||||
@@ -11,9 +11,9 @@
|
||||
|
||||
#include <math.h>
|
||||
|
||||
#include "stb_image.h"
|
||||
#include "stb_image_write.h"
|
||||
#include "stb_image_resize.h"
|
||||
#include "../stb/stb_image.h"
|
||||
#include "../stb/stb_image_write.h"
|
||||
#include "../stb/stb_image_resize.h"
|
||||
|
||||
#include "esp_heap_caps.h"
|
||||
|
||||
@@ -30,6 +30,8 @@ class CImageBasis
|
||||
protected:
|
||||
bool externalImage;
|
||||
std::string filename;
|
||||
std::string name; // Just used for diagnostics
|
||||
int memsize = 0;
|
||||
|
||||
void memCopy(uint8_t* _source, uint8_t* _target, int _size);
|
||||
bool isInImage(int x, int y);
|
||||
@@ -37,7 +39,7 @@ class CImageBasis
|
||||
bool islocked;
|
||||
|
||||
public:
|
||||
uint8_t* rgb_image;
|
||||
uint8_t* rgb_image = NULL;
|
||||
int channels;
|
||||
int width, height, bpp;
|
||||
|
||||
@@ -64,11 +66,11 @@ class CImageBasis
|
||||
void EmptyImage();
|
||||
|
||||
|
||||
CImageBasis();
|
||||
CImageBasis(std::string _image);
|
||||
CImageBasis(uint8_t* _rgb_image, int _channels, int _width, int _height, int _bpp);
|
||||
CImageBasis(int _width, int _height, int _channels);
|
||||
CImageBasis(CImageBasis *_copyfrom);
|
||||
CImageBasis(std::string name);
|
||||
CImageBasis(std::string name, std::string _image);
|
||||
CImageBasis(std::string name, uint8_t* _rgb_image, int _channels, int _width, int _height, int _bpp);
|
||||
CImageBasis(std::string name, int _width, int _height, int _channels);
|
||||
CImageBasis(std::string name, CImageBasis *_copyfrom);
|
||||
|
||||
void Resize(int _new_dx, int _new_dy);
|
||||
void Resize(int _new_dx, int _new_dy, CImageBasis *_target);
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
#include <string>
|
||||
#include "CRotateImage.h"
|
||||
#include "psram.h"
|
||||
|
||||
static const char *TAG = "C ROTATE IMG";
|
||||
|
||||
CRotateImage::CRotateImage(CImageBasis *_org, CImageBasis *_temp, bool _flip)
|
||||
CRotateImage::CRotateImage(std::string _name, CImageBasis *_org, CImageBasis *_temp, bool _flip) : CImageBasis(_name)
|
||||
{
|
||||
rgb_image = _org->rgb_image;
|
||||
channels = _org->channels;
|
||||
@@ -15,6 +18,7 @@ CRotateImage::CRotateImage(CImageBasis *_org, CImageBasis *_temp, bool _flip)
|
||||
doflip = _flip;
|
||||
}
|
||||
|
||||
|
||||
void CRotateImage::Mirror(){
|
||||
int memsize = width * height * channels;
|
||||
uint8_t* odata;
|
||||
@@ -24,7 +28,7 @@ void CRotateImage::Mirror(){
|
||||
}
|
||||
else
|
||||
{
|
||||
odata = (unsigned char*)GET_MEMORY(memsize);
|
||||
odata = (unsigned char*)malloc_psram_heap(std::string(TAG) + "->odata", memsize, MALLOC_CAP_SPIRAM);
|
||||
}
|
||||
|
||||
|
||||
@@ -50,7 +54,7 @@ void CRotateImage::Mirror(){
|
||||
// memcpy(rgb_image, odata, memsize);
|
||||
memCopy(odata, rgb_image, memsize);
|
||||
if (!ImageTMP)
|
||||
stbi_image_free(odata);
|
||||
free_psram_heap(std::string(TAG) + "->odata", odata);
|
||||
|
||||
if (ImageTMP)
|
||||
ImageTMP->RGBImageRelease();
|
||||
@@ -109,7 +113,7 @@ void CRotateImage::Rotate(float _angle, int _centerx, int _centery)
|
||||
}
|
||||
else
|
||||
{
|
||||
odata = (unsigned char*)GET_MEMORY(memsize);
|
||||
odata = (unsigned char*)malloc_psram_heap(std::string(TAG) + "->odata", memsize, MALLOC_CAP_SPIRAM);
|
||||
}
|
||||
|
||||
|
||||
@@ -148,7 +152,7 @@ void CRotateImage::Rotate(float _angle, int _centerx, int _centery)
|
||||
|
||||
if (!ImageTMP)
|
||||
{
|
||||
stbi_image_free(odata);
|
||||
free_psram_heap(std::string(TAG) + "->odata", odata);
|
||||
}
|
||||
if (ImageTMP)
|
||||
ImageTMP->RGBImageRelease();
|
||||
@@ -209,7 +213,7 @@ void CRotateImage::RotateAntiAliasing(float _angle, int _centerx, int _centery)
|
||||
}
|
||||
else
|
||||
{
|
||||
odata = (unsigned char*)GET_MEMORY(memsize);
|
||||
odata = (unsigned char*)malloc_psram_heap(std::string(TAG) + "->odata", memsize, MALLOC_CAP_SPIRAM);
|
||||
}
|
||||
|
||||
|
||||
@@ -269,7 +273,7 @@ void CRotateImage::RotateAntiAliasing(float _angle, int _centerx, int _centery)
|
||||
|
||||
if (!ImageTMP)
|
||||
{
|
||||
stbi_image_free(odata);
|
||||
free_psram_heap(std::string(TAG) + "->odata", odata);
|
||||
}
|
||||
if (ImageTMP)
|
||||
ImageTMP->RGBImageRelease();
|
||||
@@ -300,7 +304,7 @@ void CRotateImage::Translate(int _dx, int _dy)
|
||||
}
|
||||
else
|
||||
{
|
||||
odata = (unsigned char*)GET_MEMORY(memsize);
|
||||
odata = (unsigned char*)malloc_psram_heap(std::string(TAG) + "->odata", memsize, MALLOC_CAP_SPIRAM);
|
||||
}
|
||||
|
||||
|
||||
@@ -336,7 +340,7 @@ void CRotateImage::Translate(int _dx, int _dy)
|
||||
memCopy(odata, rgb_image, memsize);
|
||||
if (!ImageTMP)
|
||||
{
|
||||
stbi_image_free(odata);
|
||||
free_psram_heap(std::string(TAG) + "->odata", odata);
|
||||
}
|
||||
|
||||
if (ImageTMP)
|
||||
|
||||
@@ -8,12 +8,13 @@
|
||||
|
||||
class CRotateImage: public CImageBasis
|
||||
{
|
||||
|
||||
public:
|
||||
CImageBasis *ImageTMP, *ImageOrg;
|
||||
bool doflip;
|
||||
CRotateImage(std::string _image, bool _flip = false) : CImageBasis(_image) {ImageTMP = NULL; ImageOrg = NULL; doflip = _flip;};
|
||||
CRotateImage(uint8_t* _rgb_image, int _channels, int _width, int _height, int _bpp, bool _flip = false) : CImageBasis(_rgb_image, _channels, _width, _height, _bpp) {ImageTMP = NULL; ImageOrg = NULL; doflip = _flip;};
|
||||
CRotateImage(CImageBasis *_org, CImageBasis *_temp, bool _flip = false);
|
||||
CRotateImage(std::string name, std::string _image, bool _flip = false) : CImageBasis(name, _image) {ImageTMP = NULL; ImageOrg = NULL; doflip = _flip;};
|
||||
CRotateImage(std::string name, uint8_t* _rgb_image, int _channels, int _width, int _height, int _bpp, bool _flip = false) : CImageBasis(name, _rgb_image, _channels, _width, _height, _bpp) {ImageTMP = NULL; ImageOrg = NULL; doflip = _flip;};
|
||||
CRotateImage(std::string name, CImageBasis *_org, CImageBasis *_temp, bool _flip = false);
|
||||
|
||||
void Rotate(float _angle);
|
||||
void RotateAntiAliasing(float _angle);
|
||||
|
||||
@@ -1,13 +1,28 @@
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
#include "psram.h"
|
||||
|
||||
#include "../../include/defines.h"
|
||||
|
||||
|
||||
#define USE_SHARED_PSRAM_FOR_STBI
|
||||
|
||||
#ifdef USE_SHARED_PSRAM_FOR_STBI
|
||||
#define STBI_MALLOC(sz) psram_reserve_shared_stbi_memory(sz)
|
||||
#define STBI_REALLOC(p,newsz) psram_reallocate_shared_stbi_memory(p, newsz)
|
||||
#define STBI_FREE(p) psram_free_shared_stbi_memory(p)
|
||||
#else // Use normal PSRAM
|
||||
#define STBI_MALLOC(sz) malloc_psram_heap("STBI", sz, MALLOC_CAP_SPIRAM)
|
||||
#define STBI_REALLOC(p,newsz) realloc_psram_heap("STBI", p, newsz, MALLOC_CAP_SPIRAM)
|
||||
#define STBI_FREE(p) free_psram_heap("STBI", p)
|
||||
#endif
|
||||
|
||||
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#include "stb_image.h"
|
||||
#include "../stb/stb_image.h"
|
||||
|
||||
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
||||
#include "stb_image_write.h"
|
||||
#include "../stb/stb_image_write.h"
|
||||
|
||||
#define STB_IMAGE_RESIZE_IMPLEMENTATION
|
||||
#include "stb_image_resize.h"
|
||||
#include "../stb/stb_image_resize.h"
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -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)
|
||||
|
||||
|
||||
|
||||
@@ -1,214 +0,0 @@
|
||||
#ifdef ENABLE_INFLUXDB
|
||||
#include "interface_influxdb.h"
|
||||
|
||||
#include "esp_log.h"
|
||||
#include <time.h>
|
||||
#include "ClassLogFile.h"
|
||||
#include "esp_http_client.h"
|
||||
#include "../../include/defines.h"
|
||||
|
||||
|
||||
static const char *TAG = "INFLUXDB";
|
||||
|
||||
std::string _influxDBURI;
|
||||
std::string _influxDBDatabase;
|
||||
std::string _influxDBMeasurement;
|
||||
std::string _influxDBUser;
|
||||
std::string _influxDBPassword;
|
||||
|
||||
static esp_err_t http_event_handler(esp_http_client_event_t *evt)
|
||||
{
|
||||
switch(evt->event_id)
|
||||
{
|
||||
case HTTP_EVENT_ERROR:
|
||||
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");
|
||||
ESP_LOGI(TAG, "HTTP Client Connected");
|
||||
break;
|
||||
case HTTP_EVENT_HEADERS_SENT:
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "HTTP Client sent all request headers");
|
||||
break;
|
||||
case HTTP_EVENT_ON_HEADER:
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Header: key=" + std::string(evt->header_key) + ", value=" + std::string(evt->header_value));
|
||||
break;
|
||||
case HTTP_EVENT_ON_DATA:
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "HTTP Client data recevied: len=" + std::to_string(evt->data_len));
|
||||
break;
|
||||
case HTTP_EVENT_ON_FINISH:
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "HTTP Client finished");
|
||||
break;
|
||||
case HTTP_EVENT_DISCONNECTED:
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "HTTP Client Disconnected");
|
||||
break;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
void InfluxDBPublish(std::string _key, std::string _content, std::string _timestamp) {
|
||||
char response_buffer[MAX_HTTP_OUTPUT_BUFFER] = {0};
|
||||
esp_http_client_config_t http_config = {
|
||||
.user_agent = "ESP32 Meter reader",
|
||||
.method = HTTP_METHOD_POST,
|
||||
.event_handler = http_event_handler,
|
||||
.buffer_size = MAX_HTTP_OUTPUT_BUFFER,
|
||||
.user_data = response_buffer
|
||||
};
|
||||
|
||||
if (_influxDBUser.length() && _influxDBPassword.length()){
|
||||
http_config.username = _influxDBUser.c_str();
|
||||
http_config.password = _influxDBPassword.c_str();
|
||||
http_config.auth_type = HTTP_AUTH_TYPE_BASIC;
|
||||
}
|
||||
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "InfluxDBPublish - Key: " + _key + ", Content: " + _content + ", Timestamp: " + _timestamp);
|
||||
|
||||
char nowTimestamp[21];
|
||||
std::string payload;
|
||||
|
||||
if (_timestamp.length() > 0)
|
||||
{
|
||||
struct tm tm;
|
||||
strptime(_timestamp.c_str(), PREVALUE_TIME_FORMAT_OUTPUT, &tm);
|
||||
time_t t = mktime(&tm); // Time in Localtime (looks like timezone is not used by strptime)
|
||||
|
||||
struct tm * ptm;
|
||||
ptm = gmtime ( &t );
|
||||
time_t utc = mktime(ptm);
|
||||
utc = 2*t - utc; // Take care of timezone (looks difficult, but is easy: t = t + (t - utc), weil t-utc = timezone)
|
||||
|
||||
sprintf(nowTimestamp,"%ld000000000", (long) utc); // UTC
|
||||
|
||||
payload = _influxDBMeasurement + " " + _key + "=" + _content + " " + nowTimestamp;
|
||||
// payload = _influxDBMeasurement + " " + _key + "=774 " + nowTimestamp;
|
||||
}
|
||||
else
|
||||
{
|
||||
payload = _influxDBMeasurement + " " + _key + "=" + _content;
|
||||
}
|
||||
|
||||
payload.shrink_to_fit();
|
||||
|
||||
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "sending line to influxdb:" + payload);
|
||||
|
||||
|
||||
// use the default retention policy of the database
|
||||
std::string apiURI = _influxDBURI + "/api/v2/write?bucket=" + _influxDBDatabase + "/";
|
||||
apiURI.shrink_to_fit();
|
||||
http_config.url = apiURI.c_str();
|
||||
|
||||
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "API URI: " + apiURI);
|
||||
|
||||
esp_http_client_handle_t http_client = esp_http_client_init(&http_config);
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "client is initialized");
|
||||
|
||||
esp_http_client_set_header(http_client, "Content-Type", "text/plain");
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "header is set");
|
||||
|
||||
ESP_ERROR_CHECK(esp_http_client_set_post_field(http_client, payload.c_str(), payload.length()));
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "post payload is set");
|
||||
|
||||
esp_err_t err = ESP_ERROR_CHECK_WITHOUT_ABORT(esp_http_client_perform(http_client));
|
||||
|
||||
if( err == ESP_OK ) {
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "HTTP request was performed");
|
||||
int status_code = esp_http_client_get_status_code(http_client);
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "HTTP status code" + std::to_string(status_code));
|
||||
} else {
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "HTTP request failed");
|
||||
}
|
||||
esp_http_client_cleanup(http_client);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
void InfluxDBPublish(std::string _key, std::string _content, std::string _timestamp) {
|
||||
char response_buffer[MAX_HTTP_OUTPUT_BUFFER] = {0};
|
||||
esp_http_client_config_t http_config = {
|
||||
.user_agent = "ESP32 Meter reader",
|
||||
.method = HTTP_METHOD_POST,
|
||||
.event_handler = http_event_handler,
|
||||
.buffer_size = MAX_HTTP_OUTPUT_BUFFER,
|
||||
.user_data = response_buffer
|
||||
};
|
||||
|
||||
if (_influxDBUser.length() && _influxDBPassword.length()){
|
||||
http_config.username = _influxDBUser.c_str();
|
||||
http_config.password = _influxDBPassword.c_str();
|
||||
http_config.auth_type = HTTP_AUTH_TYPE_BASIC;
|
||||
}
|
||||
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "InfluxDBPublish - Key: " + _key + ", Content: " + _content + ", Timestamp: " + _timestamp);
|
||||
|
||||
// Format: #define PREVALUE_TIME_FORMAT_OUTPUT "%Y-%m-%dT%H:%M:%S%z"
|
||||
struct tm tm;
|
||||
strptime(_timestamp.c_str(), PREVALUE_TIME_FORMAT_OUTPUT, &tm);
|
||||
time_t t = mktime(&tm); // t is now your desired time_t
|
||||
|
||||
struct tm * ptm;
|
||||
ptm = gmtime ( &t );
|
||||
time_t utc = mktime(ptm);
|
||||
|
||||
// time_t now;
|
||||
// time(&now);
|
||||
char nowTimestamp[21];
|
||||
// pad with zeroes to get nanoseconds
|
||||
// sprintf(nowTimestamp,"%ld000000000", (long) now);
|
||||
// sprintf(nowTimestamp,"%ld000000000", (long) t); // Localtime
|
||||
sprintf(nowTimestamp,"%ld000000000", (long) utc); // UTC
|
||||
|
||||
|
||||
// LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Test Time Conversion - t: " + std::to_string(t) + ", utc: " + std::to_string(utc));
|
||||
// LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Test Time Conversion - now: " + std::to_string(now) + ", timestamp: " + std::to_string(t) + "(correct time not used yet)");
|
||||
|
||||
std::string payload = _influxDBMeasurement + " " + _key + "=" + _content + " " + nowTimestamp;
|
||||
payload.shrink_to_fit();
|
||||
|
||||
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "sending line to influxdb:" + payload);
|
||||
|
||||
|
||||
// use the default retention policy of the database
|
||||
std::string apiURI = _influxDBURI + "/api/v2/write?bucket=" + _influxDBDatabase + "/";
|
||||
apiURI.shrink_to_fit();
|
||||
http_config.url = apiURI.c_str();
|
||||
|
||||
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "API URI: " + apiURI);
|
||||
|
||||
esp_http_client_handle_t http_client = esp_http_client_init(&http_config);
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "client is initialized");
|
||||
|
||||
esp_http_client_set_header(http_client, "Content-Type", "text/plain");
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "header is set");
|
||||
|
||||
ESP_ERROR_CHECK(esp_http_client_set_post_field(http_client, payload.c_str(), payload.length()));
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "post payload is set");
|
||||
|
||||
esp_err_t err = ESP_ERROR_CHECK_WITHOUT_ABORT(esp_http_client_perform(http_client));
|
||||
|
||||
if( err == ESP_OK ) {
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "HTTP request was performed");
|
||||
int status_code = esp_http_client_get_status_code(http_client);
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "HTTP status code" + std::to_string(status_code));
|
||||
} else {
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "HTTP request failed");
|
||||
}
|
||||
esp_http_client_cleanup(http_client);
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
void InfluxDBInit(std::string _uri, std::string _database, std::string _measurement, std::string _user, std::string _password){
|
||||
_influxDBURI = _uri;
|
||||
_influxDBDatabase = _database;
|
||||
_influxDBMeasurement = _measurement;
|
||||
_influxDBUser = _user;
|
||||
_influxDBPassword = _password;
|
||||
|
||||
}
|
||||
|
||||
void InfluxDBdestroy() {
|
||||
}
|
||||
|
||||
#endif //ENABLE_INFLUXDB
|
||||
@@ -1,24 +0,0 @@
|
||||
#ifdef ENABLE_INFLUXDB
|
||||
|
||||
#pragma once
|
||||
#ifndef INTERFACE_INFLUXDB_H
|
||||
#define INTERFACE_INFLUXDB_H
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <functional>
|
||||
|
||||
// Interface to InfluxDB v1.x
|
||||
void InfluxDBInit(std::string _influxDBURI, std::string _database, std::string _measurement, std::string _user, std::string _password);
|
||||
void InfluxDBPublish(std::string _key, std::string _content, std::string _timestamp);
|
||||
|
||||
// Interface to InfluxDB v2.x
|
||||
void InfluxDB_V2_Init(std::string _uri, std::string _database, std::string _measurement, std::string _org, std::string _token);
|
||||
void InfluxDB_V2_Publish(std::string _key, std::string _content, std::string _timestamp);
|
||||
|
||||
|
||||
|
||||
void InfluxDBdestroy();
|
||||
|
||||
#endif //INTERFACE_INFLUXDB_H
|
||||
#endif //ENABLE_INFLUXDB
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <time.h>
|
||||
#include "ClassLogFile.h"
|
||||
#include "esp_http_client.h"
|
||||
#include "time_sntp.h"
|
||||
#include "../../include/defines.h"
|
||||
|
||||
|
||||
@@ -12,28 +13,25 @@ static const char *TAG = "INFLUXDB";
|
||||
|
||||
std::string _influxDBURI;
|
||||
std::string _influxDBDatabase;
|
||||
std::string _influxDBMeasurement;
|
||||
std::string _influxDBUser;
|
||||
std::string _influxDBPassword;
|
||||
|
||||
std::string _influxDB_V2_URI;
|
||||
std::string _influxDB_V2_Database;
|
||||
std::string _influxDB_V2_Measurement;
|
||||
std::string _influxDB_V2_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 _measurement, 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_Measurement = _measurement;
|
||||
_influxDB_V2_Bucket = _bucket;
|
||||
_influxDB_V2_Org = _org;
|
||||
_influxDB_V2_Token = _token;
|
||||
}
|
||||
|
||||
void InfluxDB_V2_Publish(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 = {
|
||||
@@ -44,40 +42,28 @@ void InfluxDB_V2_Publish(std::string _key, std::string _content, std::string _ti
|
||||
.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));
|
||||
|
||||
// Format: #define PREVALUE_TIME_FORMAT_OUTPUT "%Y-%m-%dT%H:%M:%S%z"
|
||||
|
||||
char nowTimestamp[21];
|
||||
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);
|
||||
utc = 2*t - utc; // Take care of timezone (looks difficult, but is easy: t = t + (t - utc), weil t-utc = timezone)
|
||||
|
||||
sprintf(nowTimestamp,"%ld000000000", (long) utc); // UTC
|
||||
|
||||
payload = _influxDB_V2_Measurement + " " + _key + "=" + _content + " " + nowTimestamp;
|
||||
// payload = _influxDB_V2_Measurement + " " + _key + "=774 " + nowTimestamp;
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Timestamp (UTC): " + std::to_string(_timeUTC));
|
||||
sprintf(nowTimestamp,"%ld000000000", _timeUTC); // UTC
|
||||
payload = _measurement + " " + _key + "=" + _content + " " + nowTimestamp;
|
||||
}
|
||||
else
|
||||
{
|
||||
payload = _influxDB_V2_Measurement + " " + _key + "=" + _content;
|
||||
// payload = _influxDB_V2_Measurement + " " + _key + "=774";
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "no timestamp given");
|
||||
payload = _measurement + " " + _key + "=" + _content;
|
||||
}
|
||||
|
||||
payload.shrink_to_fit();
|
||||
|
||||
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "sending line to influxdb:" + payload);
|
||||
|
||||
std::string apiURI = _influxDB_V2_URI + "/api/v2/write?org=" + _influxDB_V2_Org + "&bucket=" + _influxDB_V2_Database;
|
||||
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
|
||||
@@ -119,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:
|
||||
@@ -137,11 +123,14 @@ static esp_err_t http_event_handler(esp_http_client_event_t *evt)
|
||||
case HTTP_EVENT_DISCONNECTED:
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "HTTP Client Disconnected");
|
||||
break;
|
||||
case HTTP_EVENT_REDIRECT:
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "HTTP Redirect");
|
||||
break;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
void InfluxDBPublish(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",
|
||||
@@ -157,30 +146,21 @@ void InfluxDBPublish(std::string _key, std::string _content, std::string _timest
|
||||
http_config.auth_type = HTTP_AUTH_TYPE_BASIC;
|
||||
}
|
||||
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "InfluxDBPublish - Key: " + _key + ", Content: " + _content + ", Timestamp: " + _timestamp);
|
||||
|
||||
char nowTimestamp[21];
|
||||
std::string payload;
|
||||
char nowTimestamp[21];
|
||||
|
||||
if (_timestamp.length() > 0)
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "InfluxDBPublish - Key: " + _key + ", Content: " + _content + ", timeUTC: " + std::to_string(_timeUTC));
|
||||
|
||||
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);
|
||||
utc = 2*t - utc; // Take care of timezone (looks difficult, but is easy: t = t + (t - utc), weil t-utc = timezone)
|
||||
|
||||
sprintf(nowTimestamp,"%ld000000000", (long) utc); // UTC
|
||||
|
||||
payload = _influxDBMeasurement + " " + _key + "=" + _content + " " + nowTimestamp;
|
||||
// payload = _influxDBMeasurement + " " + _key + "=774 " + nowTimestamp;
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Timestamp (UTC): " + std::to_string(_timeUTC));
|
||||
sprintf(nowTimestamp,"%ld000000000", _timeUTC); // UTC
|
||||
payload = _measurement + " " + _key + "=" + _content + " " + nowTimestamp;
|
||||
}
|
||||
else
|
||||
{
|
||||
payload = _influxDBMeasurement + " " + _key + "=" + _content;
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "no timestamp given");
|
||||
payload = _measurement + " " + _key + "=" + _content;
|
||||
}
|
||||
|
||||
payload.shrink_to_fit();
|
||||
@@ -188,8 +168,10 @@ void InfluxDBPublish(std::string _key, std::string _content, std::string _timest
|
||||
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "sending line to influxdb:" + payload);
|
||||
|
||||
|
||||
// use the default retention policy of the database
|
||||
std::string apiURI = _influxDBURI + "/api/v2/write?bucket=" + _influxDBDatabase + "/";
|
||||
// use the default retention policy of the bucket
|
||||
std::string apiURI = _influxDBURI + "/write?db=" + _influxDBDatabase;
|
||||
// std::string apiURI = _influxDBURI + "/api/v2/write?bucket=" + _influxDBDatabase + "/";
|
||||
|
||||
apiURI.shrink_to_fit();
|
||||
http_config.url = apiURI.c_str();
|
||||
|
||||
@@ -217,10 +199,9 @@ void InfluxDBPublish(std::string _key, std::string _content, std::string _timest
|
||||
}
|
||||
|
||||
|
||||
void InfluxDBInit(std::string _uri, std::string _database, std::string _measurement, std::string _user, std::string _password){
|
||||
void InfluxDBInit(std::string _uri, std::string _database, std::string _user, std::string _password){
|
||||
_influxDBURI = _uri;
|
||||
_influxDBDatabase = _database;
|
||||
_influxDBMeasurement = _measurement;
|
||||
_influxDBUser = _user;
|
||||
_influxDBPassword = _password;
|
||||
|
||||
|
||||
@@ -9,12 +9,12 @@
|
||||
#include <functional>
|
||||
|
||||
// Interface to InfluxDB v1.x
|
||||
void InfluxDBInit(std::string _influxDBURI, std::string _database, std::string _measurement, std::string _user, std::string _password);
|
||||
void InfluxDBPublish(std::string _key, std::string _content, std::string _timestamp);
|
||||
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, long int _timeUTC);
|
||||
|
||||
// Interface to InfluxDB v2.x
|
||||
void InfluxDB_V2_Init(std::string _uri, std::string _database, std::string _measurement, std::string _org, std::string _token);
|
||||
void InfluxDB_V2_Publish(std::string _key, std::string _content, std::string _timestamp);
|
||||
void 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 tflite-lib mqtt jomjol_tfliteclass jomjol_helper jomjol_mqtt jomjol_wlan)
|
||||
REQUIRES esp_timer esp-tflite-micro mqtt jomjol_tfliteclass jomjol_helper jomjol_mqtt jomjol_wlan json)
|
||||
|
||||
@@ -2,12 +2,21 @@
|
||||
#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"
|
||||
#include "server_tflite.h"
|
||||
#include "MainFlowControl.h"
|
||||
#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;
|
||||
@@ -26,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;
|
||||
@@ -53,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...");
|
||||
@@ -62,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!");
|
||||
@@ -112,47 +122,78 @@ 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;
|
||||
|
||||
case MQTT_EVENT_ERROR:
|
||||
// http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc398718033 --> chapter 3.2.2.3
|
||||
|
||||
// The server does not support the level of the MQTT protocol requested by the client
|
||||
// NOTE: Only protocol 3.1.1 is supported (refer to setting in sdkconfig)
|
||||
if (event->error_handle->connect_return_code == MQTT_CONNECTION_REFUSE_PROTOCOL) {
|
||||
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Connection refused, unacceptable protocol version (0x01)");
|
||||
}
|
||||
// The client identifier is correct UTF-8 but not allowed by the server
|
||||
// e.g. clientID empty (cannot be the case -> default set in firmware)
|
||||
else if (event->error_handle->connect_return_code == MQTT_CONNECTION_REFUSE_ID_REJECTED) {
|
||||
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Connection refused, identifier rejected (0x02)");
|
||||
}
|
||||
// The network connection has been made but the MQTT service is unavailable
|
||||
else if (event->error_handle->connect_return_code == MQTT_CONNECTION_REFUSE_SERVER_UNAVAILABLE) {
|
||||
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Connection refused, Server unavailable (0x03)");
|
||||
}
|
||||
// The data in the user name or password is malformed
|
||||
else if (event->error_handle->connect_return_code == MQTT_CONNECTION_REFUSE_BAD_USERNAME) {
|
||||
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Connection refused, malformed data in username or password (0x04)");
|
||||
}
|
||||
// The client is not authorized to connect
|
||||
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
|
||||
//mqtt_connected = false;
|
||||
|
||||
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;
|
||||
@@ -160,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, 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))
|
||||
{
|
||||
@@ -184,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;
|
||||
@@ -222,25 +283,38 @@ int MQTT_Init() {
|
||||
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Init");
|
||||
MQTTdestroy_client(false);
|
||||
|
||||
esp_mqtt_client_config_t mqtt_cfg = {
|
||||
.uri = uri.c_str(),
|
||||
.client_id = client_id.c_str(),
|
||||
.lwt_topic = lwt_topic.c_str(),
|
||||
.lwt_msg = lwt_disconnected.c_str(),
|
||||
.lwt_retain = 1,
|
||||
.lwt_msg_len = (int)(lwt_disconnected.length()),
|
||||
.keepalive = keepalive,
|
||||
.disable_auto_reconnect = false, // Reconnection routine active (Default: false)
|
||||
.buffer_size = 1536, // size of MQTT send/receive buffer (Default: 1024)
|
||||
.reconnect_timeout_ms = 15000, // Try to reconnect to broker (Default: 10000ms)
|
||||
.network_timeout_ms = 20000, // Network Timeout (Default: 10000ms)
|
||||
.message_retransmit_timeout = 3000 // Time after message resent when broker not acknowledged (QoS1, QoS2)
|
||||
esp_mqtt_client_config_t mqtt_cfg = { };
|
||||
|
||||
};
|
||||
mqtt_cfg.broker.address.uri = uri.c_str();
|
||||
mqtt_cfg.credentials.client_id = client_id.c_str();
|
||||
mqtt_cfg.network.disable_auto_reconnect = false; // Reconnection routine active (Default: false)
|
||||
mqtt_cfg.network.reconnect_timeout_ms = 15000; // Try to reconnect to broker (Default: 10000ms)
|
||||
mqtt_cfg.network.timeout_ms = 20000; // Network Timeout (Default: 10000ms)
|
||||
mqtt_cfg.session.message_retransmit_timeout = 3000; // Time after message resent when broker not acknowledged (QoS1, QoS2)
|
||||
mqtt_cfg.session.last_will.topic = lwt_topic.c_str();
|
||||
mqtt_cfg.session.last_will.retain = 1;
|
||||
mqtt_cfg.session.last_will.msg = lwt_disconnected.c_str();
|
||||
mqtt_cfg.session.last_will.msg_len = (int)(lwt_disconnected.length());
|
||||
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.username = user.c_str();
|
||||
mqtt_cfg.password = password.c_str();
|
||||
mqtt_cfg.credentials.username = user.c_str();
|
||||
mqtt_cfg.credentials.authentication.password = password.c_str();
|
||||
}
|
||||
|
||||
#ifdef DEBUG_DETAIL_ON
|
||||
@@ -312,17 +386,57 @@ 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);
|
||||
bool mqtt_handler_flow_start(std::string _topic, char* _data, int _data_len)
|
||||
{
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Handler called: topic='" + _topic + "', data='" + _data +"'");
|
||||
|
||||
if (_data_len > 0) {
|
||||
MQTTCtrlFlowStart(_topic);
|
||||
}
|
||||
else {
|
||||
LogFile.WriteToFile(ESP_LOG_WARN, TAG, "handler_flow_start: handler called, but no data");
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
|
||||
bool mqtt_handler_set_prevalue(std::string _topic, char* _data, int _data_len)
|
||||
{
|
||||
//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
|
||||
cJSON *jsonData = cJSON_Parse(_data);
|
||||
cJSON *numbersname = cJSON_GetObjectItemCaseSensitive(jsonData, "numbersname");
|
||||
cJSON *value = cJSON_GetObjectItemCaseSensitive(jsonData, "value");
|
||||
|
||||
if (cJSON_IsString(numbersname) && (numbersname->valuestring != NULL)) { // Check if numbersname is valid
|
||||
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)) {
|
||||
cJSON_Delete(jsonData);
|
||||
return ESP_OK;
|
||||
}
|
||||
}
|
||||
else {
|
||||
LogFile.WriteToFile(ESP_LOG_WARN, TAG, "handler_set_prevalue: value not a valid number (\"value\": 12345.12345)");
|
||||
}
|
||||
}
|
||||
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");
|
||||
}
|
||||
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
|
||||
void MQTTconnected(){
|
||||
if (mqtt_connected) {
|
||||
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Connected to broker");
|
||||
@@ -330,13 +444,18 @@ 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 + "'");
|
||||
}
|
||||
}
|
||||
|
||||
/* Subcribe to topics */
|
||||
std::function<bool(std::string topic, char* data, int data_len)> subHandler = mqtt_handler_flow_start;
|
||||
MQTTregisterSubscribeFunction(maintopic + "/ctrl/flow_start", subHandler); // subcribe to maintopic/ctrl/flow_start
|
||||
// Subcribe to topics
|
||||
// Note: Further subsriptions are handled in GPIO class
|
||||
//*****************************************
|
||||
std::function<bool(std::string topic, char* data, int data_len)> subHandler1 = mqtt_handler_flow_start;
|
||||
MQTTregisterSubscribeFunction(maintopic + "/ctrl/flow_start", subHandler1); // subcribe to maintopic/ctrl/flow_start
|
||||
|
||||
std::function<bool(std::string topic, char* data, int data_len)> subHandler2 = mqtt_handler_set_prevalue;
|
||||
MQTTregisterSubscribeFunction(maintopic + "/ctrl/set_prevalue", subHandler2); // subcribe to maintopic/ctrl/set_prevalue
|
||||
|
||||
if (subscribeFunktionMap != NULL) {
|
||||
for(std::map<std::string, std::function<bool(std::string, char*, int)>>::iterator it = subscribeFunktionMap->begin(); it != subscribeFunktionMap->end(); ++it) {
|
||||
@@ -354,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;
|
||||
}
|
||||
|
||||
@@ -373,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);
|
||||
}
|
||||
@@ -381,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;
|
||||
}
|
||||
|
||||
@@ -400,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);
|
||||
|
||||
@@ -8,6 +8,10 @@
|
||||
#include "esp_log.h"
|
||||
#include "esp_heap_caps.h"
|
||||
|
||||
/* Enable this to use the PSRAM for MQTT Publishing.
|
||||
* This saves 10 kBytes of RAM, see https://github.com/jomjol/AI-on-the-edge-device/pull/2113
|
||||
* However we can run into PSRAM fragmentation issues, leading to insufficient large blocks to load the model.
|
||||
* See https://github.com/jomjol/AI-on-the-edge-device/issues/2200 */
|
||||
#define USE_PSRAM
|
||||
|
||||
#ifdef CONFIG_MQTT_CUSTOM_OUTBOX
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -2,6 +2,6 @@ FILE(GLOB_RECURSE app_sources ${CMAKE_CURRENT_SOURCE_DIR}/*.*)
|
||||
|
||||
idf_component_register(SRCS ${app_sources}
|
||||
INCLUDE_DIRS "."
|
||||
REQUIRES jomjol_image_proc jomjol_logfile esp_http_server esp32-camera jomjol_controlcamera jomjol_flowcontroll jomjol_helper)
|
||||
REQUIRES jomjol_image_proc jomjol_logfile jomjol_flowcontroll jomjol_helper)
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
#include "CTfLiteClass.h"
|
||||
#include "ClassLogFile.h"
|
||||
#include "Helper.h"
|
||||
#include "psram.h"
|
||||
#include "esp_log.h"
|
||||
#include "../../include/defines.h"
|
||||
|
||||
@@ -11,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);
|
||||
@@ -178,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();
|
||||
@@ -242,15 +259,22 @@ bool CTfLiteClass::ReadFileToModel(std::string _fn)
|
||||
|
||||
if (size == -1)
|
||||
{
|
||||
ESP_LOGE(TAG, "CTfLiteClass::ReadFileToModel: Model file doesn't exist: %s", _fn.c_str());
|
||||
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Model file doesn't exist: " + _fn + "!");
|
||||
return false;
|
||||
}
|
||||
else if(size > MAX_MODEL_SIZE) {
|
||||
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Unable to load model '" + _fn + "'! It does not fit in the reserved shared memory in PSRAM!");
|
||||
return false;
|
||||
}
|
||||
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Loading Model " + _fn + " /size: " + std::to_string(size) + " bytes...");
|
||||
|
||||
|
||||
#ifdef DEBUG_DETAIL_ON
|
||||
LogFile.WriteHeapInfo("CTLiteClass::Alloc modelfile start");
|
||||
#endif
|
||||
|
||||
modelfile = (unsigned char*)GET_MEMORY(size);
|
||||
modelfile = (unsigned char*)psram_get_shared_model_memory();
|
||||
|
||||
if(modelfile != NULL)
|
||||
{
|
||||
@@ -276,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())) {
|
||||
@@ -303,26 +321,15 @@ CTfLiteClass::CTfLiteClass()
|
||||
this->modelfile = NULL;
|
||||
this->interpreter = nullptr;
|
||||
this->input = nullptr;
|
||||
this->output = nullptr;
|
||||
this->kTensorArenaSize = 800 * 1024; /// according to testfile: 108000 - so far 600;; 2021-09-11: 200 * 1024
|
||||
this->tensor_arena = (uint8_t*)GET_MEMORY(kTensorArenaSize);
|
||||
this->output = nullptr;
|
||||
this->kTensorArenaSize = TENSOR_ARENA_SIZE;
|
||||
this->tensor_arena = (uint8_t*)psram_get_shared_tensor_arena_memory();
|
||||
}
|
||||
|
||||
|
||||
CTfLiteClass::~CTfLiteClass()
|
||||
{
|
||||
free(modelfile);
|
||||
|
||||
free(this->tensor_arena);
|
||||
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)
|
||||
|
||||
|
||||
|
||||
@@ -7,11 +7,11 @@
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/event_groups.h"
|
||||
#include "esp_system.h"
|
||||
#include "esp_event.h"
|
||||
#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"
|
||||
@@ -32,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)
|
||||
{
|
||||
@@ -72,15 +75,69 @@ void time_sync_notification_cb(struct timeval *tv)
|
||||
}
|
||||
|
||||
|
||||
bool time_manual_reset_sync(void)
|
||||
{
|
||||
sntp_restart();
|
||||
// sntp_init();
|
||||
int retry = 0;
|
||||
const int retry_count = 10;
|
||||
while (sntp_get_sync_status() == SNTP_SYNC_STATUS_RESET && ++retry < retry_count) {
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Waiting for system time to be set... " + std::to_string(retry) + "/" + std::to_string(retry_count));
|
||||
vTaskDelay(2000 / portTICK_PERIOD_MS);
|
||||
}
|
||||
if (retry >= retry_count)
|
||||
return false;
|
||||
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Waiting for system time successfull with " + std::to_string(retry) + "/" + std::to_string(retry_count));
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
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";
|
||||
@@ -218,16 +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_init();
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
|
||||
/* The RTC keeps the time after a restart (Except on Power On or Pin Reset)
|
||||
* There should only be a minor correction through NTP */
|
||||
|
||||
@@ -236,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));
|
||||
}
|
||||
@@ -250,3 +305,5 @@ bool setupTime() {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
#include "freertos/task.h"
|
||||
#include "freertos/event_groups.h"
|
||||
#include "esp_system.h"
|
||||
#include "esp_event.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_attr.h"
|
||||
#include "esp_sleep.h"
|
||||
@@ -27,4 +26,9 @@ bool getTimeWasNotSetAtBoot(void);
|
||||
bool getUseNtp(void);
|
||||
bool setupTime();
|
||||
|
||||
bool time_manual_reset_sync(void);
|
||||
|
||||
extern int LocalTimeToUTCOffsetSeconds;
|
||||
|
||||
|
||||
#endif //TIMESNTP_H
|
||||
@@ -2,6 +2,6 @@ FILE(GLOB_RECURSE app_sources ${CMAKE_CURRENT_SOURCE_DIR}/*.*)
|
||||
|
||||
idf_component_register(SRCS ${app_sources}
|
||||
INCLUDE_DIRS "."
|
||||
REQUIRES nvs_flash jomjol_helper jomjol_mqtt wpa_supplicant)
|
||||
REQUIRES esp_wifi nvs_flash jomjol_helper jomjol_mqtt wpa_supplicant)
|
||||
|
||||
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
#include "esp_mbo.h"
|
||||
#include "esp_mac.h"
|
||||
#include "esp_netif.h"
|
||||
#include "esp_event.h"
|
||||
#include <netdb.h>
|
||||
#include "esp_log.h"
|
||||
#include "nvs_flash.h"
|
||||
|
||||
@@ -36,6 +36,18 @@
|
||||
|
||||
#include "../../include/defines.h"
|
||||
|
||||
#if (ESP_IDF_VERSION_MAJOR >= 5)
|
||||
#include "soc/periph_defs.h"
|
||||
#include "esp_private/periph_ctrl.h"
|
||||
#include "soc/gpio_sig_map.h"
|
||||
#include "soc/gpio_periph.h"
|
||||
#include "soc/io_mux_reg.h"
|
||||
#include "esp_rom_gpio.h"
|
||||
#define gpio_pad_select_gpio esp_rom_gpio_pad_select_gpio
|
||||
#define gpio_matrix_in(a,b,c) esp_rom_gpio_connect_in_signal(a,b,c)
|
||||
#define gpio_matrix_out(a,b,c,d) esp_rom_gpio_connect_out_signal(a,b,c,d)
|
||||
#define ets_delay_us(a) esp_rom_delay_us(a)
|
||||
#endif
|
||||
|
||||
static const char *TAG = "WIFI";
|
||||
|
||||
@@ -43,6 +55,7 @@ static bool APWithBetterRSSI = false;
|
||||
static bool WIFIConnected = false;
|
||||
static int WIFIReconnectCnt = 0;
|
||||
|
||||
esp_netif_t *my_sta;
|
||||
|
||||
|
||||
void strinttoip4(const char *ip, int &a, int &b, int &c, int &d) {
|
||||
@@ -173,7 +186,7 @@ static char * get_btm_neighbor_list(uint8_t *report, size_t report_len)
|
||||
pos += s_len;
|
||||
}
|
||||
|
||||
ESP_LOGI(TAG, "Roaming: RMM neigbor report bssid=" MACSTR
|
||||
ESP_LOGI(TAG, "Roaming: RMM neighbor report bssid=" MACSTR
|
||||
" info=0x%x op_class=%u chan=%u phy_type=%u%s%s%s%s",
|
||||
MAC2STR(nr), WPA_GET_LE32(nr + ETH_ALEN),
|
||||
nr[ETH_ALEN + 4], nr[ETH_ALEN + 5],
|
||||
@@ -182,7 +195,7 @@ static char * get_btm_neighbor_list(uint8_t *report, size_t report_len)
|
||||
civic[0] ? " civic=" : "", civic);
|
||||
|
||||
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Roaming: RMM neigbor report BSSID: " + BssidToString((char*)nr) +
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Roaming: RMM neighbor report BSSID: " + BssidToString((char*)nr) +
|
||||
", Channel: " + std::to_string(nr[ETH_ALEN + 5]));
|
||||
|
||||
/* neighbor start */
|
||||
@@ -365,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");
|
||||
free(wifi_ap_records);
|
||||
delete[] wifi_ap_records;
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -388,7 +401,7 @@ void wifi_scan(void)
|
||||
APWithBetterRSSI = true;
|
||||
}
|
||||
}
|
||||
free(wifi_ap_records);
|
||||
delete[] wifi_ap_records;
|
||||
}
|
||||
|
||||
|
||||
@@ -517,7 +530,7 @@ esp_err_t wifi_init_sta(void)
|
||||
return retval;
|
||||
}
|
||||
|
||||
esp_netif_t *my_sta = esp_netif_create_default_wifi_sta();
|
||||
my_sta = esp_netif_create_default_wifi_sta();
|
||||
|
||||
if (!wlan_config.ipaddress.empty() && !wlan_config.gateway.empty() && !wlan_config.netmask.empty())
|
||||
{
|
||||
@@ -636,7 +649,7 @@ esp_err_t wifi_init_sta(void)
|
||||
|
||||
if (!wlan_config.hostname.empty())
|
||||
{
|
||||
retval = tcpip_adapter_set_hostname(TCPIP_ADAPTER_IF_STA , wlan_config.hostname.c_str());
|
||||
retval = esp_netif_set_hostname(my_sta, wlan_config.hostname.c_str());
|
||||
if(retval != ESP_OK ) {
|
||||
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Failed to set hostname! Error: " + std::to_string(retval));
|
||||
}
|
||||
@@ -660,6 +673,20 @@ int get_WIFI_RSSI()
|
||||
}
|
||||
|
||||
|
||||
/*std::string getIp() {
|
||||
esp_netif_ip_info_t ip_info;
|
||||
ESP_ERROR_CHECK(esp_netif_get_ip_info(my_sta, ip_info));
|
||||
char ipFormated[4*3+3+1];
|
||||
sprintf(ipFormated, IPSTR, IP2STR(&ip_info.ip));
|
||||
return std::string(ipFormated);
|
||||
}*/
|
||||
|
||||
|
||||
std::string* getHostname() {
|
||||
return &wlan_config.hostname;
|
||||
}
|
||||
|
||||
|
||||
bool getWIFIisConnected()
|
||||
{
|
||||
return WIFIConnected;
|
||||
|
||||
@@ -9,6 +9,8 @@ int wifi_init_sta(void);
|
||||
std::string* getIPAddress();
|
||||
std::string* getSSID();
|
||||
int get_WIFI_RSSI();
|
||||
std::string* getHostname();
|
||||
|
||||
bool getWIFIisConnected();
|
||||
void WIFIDestroy();
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -1,6 +0,0 @@
|
||||
FILE(GLOB_RECURSE app_sources ${CMAKE_CURRENT_SOURCE_DIR}/*.*)
|
||||
|
||||
idf_component_register(SRCS ${app_sources}
|
||||
INCLUDE_DIRS "." "../../include")
|
||||
|
||||
|
||||
1
code/components/stb
Submodule
1
code/components/stb
Submodule
Submodule code/components/stb added at 5736b15f7e
Submodule code/components/tflite-micro-esp-examples deleted from 095f55a6ee
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user