mirror of
https://github.com/jomjol/AI-on-the-edge-device.git
synced 2025-12-07 12:06:58 +03:00
Compare commits
269 Commits
v15.3.0
...
log-mqtt-c
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4e1df4a0db | ||
|
|
b34fdd937b | ||
|
|
775f9dcb14 | ||
|
|
c352e539bc | ||
|
|
47c5a92648 | ||
|
|
a0333d906f | ||
|
|
ec00e943da | ||
|
|
6175471a00 | ||
|
|
948e76876f | ||
|
|
f4edb206d8 | ||
|
|
a9db769595 | ||
|
|
f0497eb924 | ||
|
|
e53af6de0d | ||
|
|
3b7fe93d02 | ||
|
|
2f1d7e577c | ||
|
|
2a7247abfe | ||
|
|
37ba85717f | ||
|
|
97656114b6 | ||
|
|
6cf1d5ad98 | ||
|
|
fed729bcee | ||
|
|
89c36374b3 | ||
|
|
bb69929247 | ||
|
|
e1ea09c501 | ||
|
|
39a827258d | ||
|
|
1d8c6fa257 | ||
|
|
a9aadbdb06 | ||
|
|
a5927f98d2 | ||
|
|
c708e2374a | ||
|
|
4c3dcd8c29 | ||
|
|
be93567956 | ||
|
|
d4406f47ea | ||
|
|
52efedcfa0 | ||
|
|
28d93253f0 | ||
|
|
c7fdc46df2 | ||
|
|
74491e9bde | ||
|
|
a092142c65 | ||
|
|
f6a3dc5851 | ||
|
|
d027adf006 | ||
|
|
bd5be5c5ec | ||
|
|
ca01f5a38f | ||
|
|
3b3a3ebcc9 | ||
|
|
7d62cf67fe | ||
|
|
f6bdd48bca | ||
|
|
5496573369 | ||
|
|
4522ba087f | ||
|
|
d370ba5fe6 | ||
|
|
f39dacc1c5 | ||
|
|
aad1a0e78d | ||
|
|
276efef783 | ||
|
|
79476a8458 | ||
|
|
2b7da5b44e | ||
|
|
ebcec97d1d | ||
|
|
85375b6505 | ||
|
|
085c47b651 | ||
|
|
20a04b888f | ||
|
|
098b1bd025 | ||
|
|
d1c815ce69 | ||
|
|
67c3020d7d | ||
|
|
61bca4ebb8 | ||
|
|
3219202c53 | ||
|
|
cd29690b96 | ||
|
|
3a34564ee2 | ||
|
|
174743ae7f | ||
|
|
e5eca6a53f | ||
|
|
d8e37dce48 | ||
|
|
822753bb4f | ||
|
|
7225792b4b | ||
|
|
b4f6b1a4fb | ||
|
|
21ec58daa0 | ||
|
|
2c69e90fac | ||
|
|
5c57522b71 | ||
|
|
f8eb4db171 | ||
|
|
c9a3df4eec | ||
|
|
acf669900f | ||
|
|
cb3f082218 | ||
|
|
20980b2bcd | ||
|
|
773d21a875 | ||
|
|
3a9c9ac2a4 | ||
|
|
c7e340d3a5 | ||
|
|
0441753a33 | ||
|
|
fb6cb44728 | ||
|
|
ae69942dd9 | ||
|
|
65437727f7 | ||
|
|
ccefe57795 | ||
|
|
e3ff049720 | ||
|
|
39e84baf8b | ||
|
|
eb7d078a1a | ||
|
|
b6c6805a08 | ||
|
|
d567a5d7f2 | ||
|
|
6922970185 | ||
|
|
9a4b51d6de | ||
|
|
2546ab81ff | ||
|
|
7b7544079f | ||
|
|
17fe87b349 | ||
|
|
f99dc8fdfc | ||
|
|
cce992754c | ||
|
|
eefccf6e11 | ||
|
|
64bb4f0ff6 | ||
|
|
f534741205 | ||
|
|
ee38bc7dc6 | ||
|
|
132834c3fd | ||
|
|
d3d9c64f3b | ||
|
|
aa2a4edf7e | ||
|
|
8012b7f43e | ||
|
|
009ab4c896 | ||
|
|
c54ca18e4e | ||
|
|
beb09593eb | ||
|
|
1a76ae121c | ||
|
|
1300242d4a | ||
|
|
79543df23b | ||
|
|
4049d752ba | ||
|
|
dc90972659 | ||
|
|
32282ecfe2 | ||
|
|
ae6a94544b | ||
|
|
70b031eacc | ||
|
|
c3fadf5c2a | ||
|
|
7e5f6bf4a5 | ||
|
|
88b531ae8b | ||
|
|
8481cc4b26 | ||
|
|
ecaed38c1d | ||
|
|
d6a1838d47 | ||
|
|
5194c466be | ||
|
|
043de9265a | ||
|
|
08a350172d | ||
|
|
7e806df64d | ||
|
|
dccfb5e91e | ||
|
|
fbe4609bb9 | ||
|
|
3e85cfb456 | ||
|
|
5dff4ca8cf | ||
|
|
0d0b0187f4 | ||
|
|
4cf9ea6c45 | ||
|
|
1b76e0f449 | ||
|
|
d4a0ad20ff | ||
|
|
df72445e79 | ||
|
|
456cb93809 | ||
|
|
d968a7adc6 | ||
|
|
9a52b8b2f3 | ||
|
|
8caa852bbf | ||
|
|
4faca4c46c | ||
|
|
238fc5fae3 | ||
|
|
c32ca5a23c | ||
|
|
827d9d1700 | ||
|
|
0ea4b3b3ce | ||
|
|
3e26c6c743 | ||
|
|
fa5c99b3cb | ||
|
|
6feae4e239 | ||
|
|
ef64be3888 | ||
|
|
cc89d625f2 | ||
|
|
08ba754b88 | ||
|
|
6b38e44d7f | ||
|
|
141aea7fa7 | ||
|
|
bcd07761b6 | ||
|
|
fe4d861e15 | ||
|
|
71322c9fbe | ||
|
|
f8b4881a50 | ||
|
|
438d5696e4 | ||
|
|
0d391c8780 | ||
|
|
59de6319a1 | ||
|
|
3805687219 | ||
|
|
c6a789dc45 | ||
|
|
246f9cfc31 | ||
|
|
b2d8c60bb1 | ||
|
|
1d573cd18a | ||
|
|
b2e5cdd8a3 | ||
|
|
f7fde7c430 | ||
|
|
2c19080a66 | ||
|
|
35663c5fd4 | ||
|
|
5b449d5c45 | ||
|
|
3a5f3496d5 | ||
|
|
00434d01c3 | ||
|
|
3e0bb81e32 | ||
|
|
4f57f9eafd | ||
|
|
f24ec581e6 | ||
|
|
0d78bb78ea | ||
|
|
47aea007b3 | ||
|
|
284b3f428e | ||
|
|
92d45c7971 | ||
|
|
ff1d9d3b4f | ||
|
|
2b57dd0853 | ||
|
|
dd8f5eea22 | ||
|
|
60c5305378 | ||
|
|
8b1c65a38a | ||
|
|
4f5933c4f2 | ||
|
|
06c9bfb0de | ||
|
|
69f1a99b55 | ||
|
|
a8fb88a35d | ||
|
|
d418d22155 | ||
|
|
53e8cf49f9 | ||
|
|
ac4f823cbf | ||
|
|
444dc0fa39 | ||
|
|
5053a31245 | ||
|
|
44cf8933d4 | ||
|
|
35de56be04 | ||
|
|
80a6fc1dc3 | ||
|
|
d2c47fcde2 | ||
|
|
7b3a493587 | ||
|
|
217f543578 | ||
|
|
797fc5e764 | ||
|
|
7a4e82a44e | ||
|
|
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 |
@@ -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
|
||||
#######################################################################
|
||||
@@ -90,9 +115,9 @@
|
||||
labeled:
|
||||
issue:
|
||||
body: |
|
||||
See [Digital Digits](https://jomjol.github.io/neural-network-digital-counter-readout) resp. [Analogue Pointers](https://jomjol.github.io/neural-network-analog-needle-readout) for an overview of all trained data.
|
||||
See [Digits](https://jomjol.github.io/neural-network-digital-counter-readout) resp. [Analogue Pointers](https://jomjol.github.io/neural-network-analog-needle-readout) for an overview of all trained data.
|
||||
If your type is not contained it can be added to our training material, see [here](https://jomjol.github.io/AI-on-the-edge-device-docs/collect-new-images/).
|
||||
discussion:
|
||||
body: |
|
||||
See [Digital Digits](https://jomjol.github.io/neural-network-digital-counter-readout) resp. [Analogue Pointers](https://jomjol.github.io/neural-network-analog-needle-readout) for an overview of all trained data.
|
||||
See [Digits](https://jomjol.github.io/neural-network-digital-counter-readout) resp. [Analogue Pointers](https://jomjol.github.io/neural-network-analog-needle-readout) for an overview of all trained data.
|
||||
If your type is not contained it can be added to our training material, see [here](https://jomjol.github.io/AI-on-the-edge-device-docs/collect-new-images/).
|
||||
106
.github/workflows/build.yaml
vendored
106
.github/workflows/build.yaml
vendored
@@ -14,8 +14,8 @@ jobs:
|
||||
uses: fkirc/skip-duplicate-actions@v5
|
||||
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,14 +79,14 @@ 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/
|
||||
|
||||
echo "Replacing variables..."
|
||||
cd html; find . -type f -exec sed -i 's/$COMMIT_HASH/${{ steps.vars.outputs.sha_short }}/g' {} \;
|
||||
|
||||
|
||||
|
||||
#########################################################################################
|
||||
## Pack for Update
|
||||
@@ -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,12 +115,12 @@ 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 }}
|
||||
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: Set Variables
|
||||
id: vars
|
||||
run: |
|
||||
@@ -144,13 +144,12 @@ 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/*
|
||||
|
||||
|
||||
|
||||
#########################################################################################
|
||||
## Pack for Remote Setup
|
||||
#########################################################################################
|
||||
@@ -164,10 +163,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
|
||||
@@ -176,9 +175,9 @@ jobs:
|
||||
./html/*
|
||||
key: generated-files-${{ github.run_id }}
|
||||
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 +204,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 +219,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 +233,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 }}
|
||||
@@ -261,9 +260,9 @@ jobs:
|
||||
cp -r ./html ./sd-card/ # Overwrite the Web UI with the preprocessed files
|
||||
cd sd-card; zip -r ../manual_setup/sd-card.zip *; cd ..
|
||||
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 +283,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 }}
|
||||
@@ -332,21 +331,18 @@ jobs:
|
||||
|
||||
# extract the version used in next step
|
||||
- id: get_version
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
uses: Simply007/get-version-action@v2
|
||||
uses: drewg13/get-version-action@98dda2a47a257e202c2e6c2ed2e6072ec23f448e
|
||||
|
||||
# # the changelog [unreleased] will now be changed to the release version
|
||||
# - name: Update changelog
|
||||
# uses: thomaseizinger/keep-a-changelog-new-release@v1
|
||||
# if: startsWith(github.ref, 'refs/tags/')
|
||||
# with:
|
||||
# changelogPath: Changelog.md
|
||||
# version: ${{ steps.get_version.outputs.version-without-v }}
|
||||
|
||||
|
||||
# # the release notes will be extracted from changelog
|
||||
# - name: Extract release notes
|
||||
# id: extract-release-notes
|
||||
# if: startsWith(github.ref, 'refs/tags/')
|
||||
# uses: ffurrer2/extract-release-notes@v1
|
||||
# with:
|
||||
# changelog_file: Changelog.md
|
||||
@@ -354,12 +350,11 @@ jobs:
|
||||
# Releases should only be created on master by tagging the last commit.
|
||||
# all artifacts in firmware folder pushed to the release
|
||||
- name: Release
|
||||
uses: softprops/action-gh-release@v1
|
||||
uses: softprops/action-gh-release@v2.0.8
|
||||
# Note:
|
||||
# If you get the error "Resource not accessible by integration",
|
||||
# The access rights are not sufficient, see
|
||||
# https://github.com/softprops/action-gh-release/issues/232#issuecomment-1131379440
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
with:
|
||||
name: ${{ steps.get_version.outputs.version-without-v }}
|
||||
body: ${{ steps.extract-release-notes.outputs.release_notes }}
|
||||
@@ -368,7 +363,6 @@ jobs:
|
||||
|
||||
# # Commit&Push Changelog to master branch. Must be manually merged back to rolling
|
||||
# - name: Commit changes and push changes
|
||||
# if: startsWith(github.ref, 'refs/tags/')
|
||||
# run: |
|
||||
# git config user.name github-actions
|
||||
# git config user.email github-actions@github.com
|
||||
@@ -380,8 +374,9 @@ jobs:
|
||||
#########################################################################################
|
||||
## Update the Web Installer on a release
|
||||
#########################################################################################
|
||||
# This is the same as in the update-webinstaller.yml
|
||||
update-web-installer:
|
||||
# Make sure to also update update-webinstaller.yml!
|
||||
update-web-installer:
|
||||
if: github.event_name == 'release' && github.event.action == 'published' # Only run on release but not on prerelease
|
||||
needs: [release]
|
||||
environment:
|
||||
name: github-pages
|
||||
@@ -396,8 +391,8 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Get version of last release
|
||||
id: last_release
|
||||
uses: mindojo/get-latest-release@0b8ef1434d7468d6bffcc8263baff5c777f72321
|
||||
@@ -405,23 +400,26 @@ jobs:
|
||||
myToken: ${{ github.token }}
|
||||
exclude_types: "draft|prerelease"
|
||||
view_top: 1
|
||||
|
||||
|
||||
- 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!
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -12,7 +12,7 @@ on:
|
||||
# - rolling
|
||||
# paths:
|
||||
# - docs # The path filter somehow does not work, so lets run it on every change to rolling
|
||||
|
||||
|
||||
jobs:
|
||||
manually-update-web-installer:
|
||||
environment:
|
||||
@@ -29,7 +29,7 @@ jobs:
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
|
||||
|
||||
- name: Get version of last release
|
||||
id: last_release
|
||||
uses: mindojo/get-latest-release@0b8ef1434d7468d6bffcc8263baff5c777f72321
|
||||
@@ -37,15 +37,17 @@ jobs:
|
||||
myToken: ${{ github.token }}
|
||||
exclude_types: "draft|prerelease"
|
||||
view_top: 1
|
||||
|
||||
|
||||
- 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
|
||||
@@ -58,4 +60,3 @@ jobs:
|
||||
- name: Deploy to GitHub Pages
|
||||
id: deployment
|
||||
uses: actions/deploy-pages@v1
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# Reply Bot
|
||||
# It uses the configuration in .github/label-commenter-config.yml
|
||||
# It uses the configuration in .github/label-commenter-config.yaml
|
||||
# See https://github.com/peaceiris/actions-label-commenter
|
||||
|
||||
name: Reply-Bot
|
||||
@@ -20,12 +20,11 @@ jobs:
|
||||
comment:
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
|
||||
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
####################################################################
|
||||
## Remove labels again (issues only)
|
||||
## Make sure to also add the reply message to .github/label-commenter-config.yml!
|
||||
## Make sure to also add the reply message to .github/label-commenter-config.yaml!
|
||||
## This currently seems no longer to work due to changes on the actions-cool/issues-helper!
|
||||
####################################################################
|
||||
# - name: Remove 'Logfile' label again (issues only)
|
||||
@@ -69,11 +68,12 @@ jobs:
|
||||
# with:
|
||||
# actions: 'remove-labels'
|
||||
# labels: 'bot-reply Show Trained Digits/Pointers'
|
||||
|
||||
|
||||
####################################################################
|
||||
## Write the response
|
||||
####################################################################
|
||||
- name: Write Response
|
||||
uses: peaceiris/actions-label-commenter@c2d00660c86f2b9ed0fb35b372c451558eba85b3
|
||||
with:
|
||||
repo-token: "${{ secrets.GITHUB_TOKEN }}"
|
||||
github_token: "${{ secrets.GITHUB_TOKEN }}"
|
||||
config_file: .github/label-commenter-config.yaml
|
||||
6
.gitmodules
vendored
6
.gitmodules
vendored
@@ -4,9 +4,9 @@
|
||||
[submodule "code/components/esp-nn"]
|
||||
path = code/components/esp-nn
|
||||
url = https://github.com/espressif/esp-nn.git
|
||||
[submodule "code/components/tflite-micro-esp-examples"]
|
||||
path = code/components/tflite-micro-esp-examples
|
||||
url = https://github.com/espressif/tflite-micro-esp-examples.git
|
||||
[submodule "code/components/esp-tflite-micro"]
|
||||
path = code/components/esp-tflite-micro
|
||||
url = https://github.com/espressif/esp-tflite-micro.git
|
||||
[submodule "code/components/stb"]
|
||||
path = code/components/stb
|
||||
url = https://github.com/nothings/stb.git
|
||||
|
||||
198
Changelog.md
198
Changelog.md
@@ -1,8 +1,145 @@
|
||||
## [16.0.0-RC3] - 2024-10-05
|
||||
|
||||
For a full list of changes see [Full list of changes](https://github.com/jomjol/AI-on-the-edge-device/compare/v15.7.0...v16.0.0-RC1)
|
||||
|
||||
#### Known issues
|
||||
Please check the [issues](https://github.com/jomjol/AI-on-the-edge-device/issues) and
|
||||
[discussions](https://github.com/jomjol/AI-on-the-edge-device/discussions) before reporting a new issue.
|
||||
|
||||
#### Core Changes
|
||||
Only changes since RC2 are listed:
|
||||
- Renamed MQTT topic from `rate_per_digitalization_round` to `rate_per_digitization_round` (change happened already in RC1)
|
||||
|
||||
#### Bug Fixes
|
||||
Only changes since RC2 are listed:
|
||||
- Re-did revertion of TFlite submodule update as certain modules crash with it (#3269) (change was lost)
|
||||
|
||||
|
||||
## [16.0.0-RC2] - 2024-10-04
|
||||
|
||||
For a full list of changes see [Full list of changes](https://github.com/jomjol/AI-on-the-edge-device/compare/v15.7.0...v16.0.0-RC1)
|
||||
|
||||
#### Known issues
|
||||
Please check the [issues](https://github.com/jomjol/AI-on-the-edge-device/issues) and
|
||||
[discussions](https://github.com/jomjol/AI-on-the-edge-device/discussions) before reporting a new issue.
|
||||
|
||||
#### Core Changes
|
||||
Only changes since RC1 are listed:
|
||||
- Updated parameter documentation pages
|
||||
- Rename/remove unused parameters (#3291)
|
||||
- Migrate-cam-parameters (#3288)
|
||||
|
||||
#### Bug Fixes
|
||||
Only changes since RC1 are listed:
|
||||
- Reverted TFlite submodule update as certain modules crash with it (#3269)
|
||||
- Changed the webhook UploadImg to false (#3279)
|
||||
- Changed default value from boolean to numeric value in parameter camDenoise documentation
|
||||
- Updated config page
|
||||
|
||||
## [16.0.0-RC1] - 2024-09-24
|
||||
|
||||
For a full list of changes see [Full list of changes](https://github.com/jomjol/AI-on-the-edge-device/compare/v15.7.0...v16.0.0-RC1)
|
||||
|
||||
#### Known issues
|
||||
Please check the [issues](https://github.com/jomjol/AI-on-the-edge-device/issues) and
|
||||
[discussions](https://github.com/jomjol/AI-on-the-edge-device/discussions) before reporting a new issue.
|
||||
|
||||
#### Core Changes
|
||||
Those are just the major changes:
|
||||
- Add support for OV5640 camera (#3063)
|
||||
- New tflite-Models
|
||||
- Homeassistant service discovery: derive node_id when using nested topics (#3088)
|
||||
- Added Prometheus/OpenMetrics exporter (#3081)
|
||||
- Added Webhook (#3148, #3163, #3174)
|
||||
- Add rate threshold parameter (#3195)
|
||||
- Added a Delay between the WiFi reconnections (#3068)
|
||||
- Web UI improvements
|
||||
- Various minor changes
|
||||
- Update platformIO to 6.9.0 (Contains ESP IDF 5.3.1)
|
||||
|
||||
#### Bug Fixes
|
||||
Those are just the major changes:
|
||||
- Handle crash on corrupted model (#3220)
|
||||
- Bugfix for boot loop (#3175)
|
||||
- Bugfix for time stamp (#3180)
|
||||
- Handle empty prevalue.ini gracefully (#3162)
|
||||
- Added note about only TLS 1.2 is supported (#3213)
|
||||
|
||||
## [15.7.0] - 2024-02-17
|
||||
|
||||
For a full list of changes see [Full list of changes](https://github.com/jomjol/AI-on-the-edge-device/compare/v15.6.0...v15.7.0)
|
||||
|
||||
#### Core Changes
|
||||
- Added new camera settings (See `Settings > Alignment > Reference Image and Camera Settings`). You might need to re-create the reference image and alignment marks. Note worthy:
|
||||
- You can now crop the image
|
||||
- Support to configure sharpness, grayscale, negatoive and exposure
|
||||
- Enhanced various WebUI pages with better explanations and usability
|
||||
- Add Firmware Version to MQTT
|
||||
|
||||
#### Bug Fixes
|
||||
- Reverted "Implemented late analog / digit transition [#2778](https://github.com/jomjol/AI-on-the-edge-device/pull/2778) (introduced in `v15.5`) as is seems to cause issues for many users.
|
||||
|
||||
|
||||
## [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 / digit 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
|
||||
|
||||
- Added config entries for MQTT TLS
|
||||
|
||||
|
||||
#### Fixed
|
||||
|
||||
* InfluxDB: consider DST setting for UTC time conversion
|
||||
|
||||
* Minor html response bugfix
|
||||
|
||||
- Memory leakage (MQTT)
|
||||
|
||||
|
||||
## [15.3.0] - 2023-07-22
|
||||
|
||||
### Changes
|
||||
|
||||
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)
|
||||
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
|
||||
|
||||
@@ -11,13 +148,8 @@ For a full list of changes see [Full list of changes](https://github.com/jomjol/
|
||||
- ana-cont_1207_s2_q.tflite
|
||||
- dig-cont_0620_s3_q.tflite
|
||||
|
||||
|
||||
|
||||
|
||||
## [15.2.4] - 2023-05-02
|
||||
|
||||
### Changes
|
||||
|
||||
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
|
||||
@@ -41,8 +173,6 @@ For a full list of changes see [Full list of changes](https://github.com/jomjol/
|
||||
|
||||
## [15.2.0] - 2023-04-23
|
||||
|
||||
### Changes
|
||||
|
||||
For a full list of changes see [Full list of changes](https://github.com/jomjol/AI-on-the-edge-device/compare/v15.1.1...v15.2.0)
|
||||
|
||||
#### Added
|
||||
@@ -72,8 +202,6 @@ For a full list of changes see [Full list of changes](https://github.com/jomjol/
|
||||
|
||||
## [15.1.1] - 2023-03-23
|
||||
|
||||
### Changes
|
||||
|
||||
For a full list of changes see [Full list of changes](https://github.com/jomjol/AI-on-the-edge-device/compare/v15.1.0...v15.1.1)
|
||||
|
||||
#### Added
|
||||
@@ -128,7 +256,7 @@ For a full list of changes see [Full list of changes](https://github.com/jomjol/
|
||||
:bangbang: **Attention:** Update your configuration!
|
||||
- Hybrid CNN network to `dig-cont_0611_s3`
|
||||
- Analog CNN network to `ana-cont-11.0.5` and `ana-clas100-1.5.7`
|
||||
- Digital CNN network to `dig-class100-1.6.0`
|
||||
- Digit CNN network to `dig-class100-1.6.0`
|
||||
- Various Web interface Improvements/Enhancements:
|
||||
- Restructured Menu (Needs cache clearing to be applied)
|
||||
- Enhanced `Previous Value` page
|
||||
@@ -264,7 +392,7 @@ For a full list of changes see [Full list of changes](https://github.com/jomjol/
|
||||
- Improved OTA Update mechanism (only working after installation for next update)
|
||||
- Added data logging in `/log/data` - One day per file and each measurement is on one line
|
||||
- Format: csv - comma separated
|
||||
- Content: `time`, `name-of-number`, `raw-value`, `return-value`, `pre-value`, `change-rate`, `change-absolute`, `error-text`, `cnn-digital`, `cnn-analog`
|
||||
- Content: `time`, `name-of-number`, `raw-value`, `return-value`, `pre-value`, `change-rate`, `change-absolute`, `error-text`, `cnn-digit`, `cnn-analog`
|
||||
- Show graph of values direct in the user interface (thanks to [@rdmueller](https://github.com/rdmueller))
|
||||
|
||||
- Using new data logging (see above)
|
||||
@@ -282,10 +410,10 @@ For a full list of changes see [Full list of changes](https://github.com/jomjol/
|
||||
- Updated OTA functionality (more robust, but not fully bullet prove yet)
|
||||
- Updated Espressif library to `espressif32@v5.2.0`
|
||||
- [#1176](https://github.com/jomjol/AI-on-the-edge-device/discussions/1176) accept minor negative values (-0.2) if extended resolution is enabled
|
||||
- [#1143](https://github.com/jomjol/AI-on-the-edge-device/issues/1143) added config parameter `AnalogDigitalTransitionStart`. It can setup very early and very late digit transition starts.
|
||||
- [#1143](https://github.com/jomjol/AI-on-the-edge-device/issues/1143) added config parameter `AnalogDigTransitionStart`. It can setup very early and very late digit transition starts.
|
||||
- New version of `dig-class100` (v1.4.0): added images of heliowatt powermeter
|
||||
- NEW v13.0.2: Update Tool "Logfile downloader and combiner" to handle the new csv file format.
|
||||
- NEW v13.0.2: MQTT: Added MQTT topic `status` (Digitalization Status), Timezone to MQTT topic `timestamp`.#
|
||||
- NEW v13.0.2: MQTT: Added MQTT topic `status` (Digitization Status), Timezone to MQTT topic `timestamp`.#
|
||||
- NEW v13.0.2: Logging: Disable heap logs by default, cleanup
|
||||
- NEW v13.0.7:
|
||||
- log NTP server name
|
||||
@@ -410,7 +538,7 @@ Intermediate Digits
|
||||
|
||||
- Updated analog neural network file (`ana-cont_11.3.0_s2.tflite` - default, `ana-class100_0120_s1_q.tflite`)
|
||||
|
||||
- Updated digital neural network file (`dig-cont_0570_s3.tflite` - default, `dig-class100_0120_s2_q.tflite`)
|
||||
- Updated digit neural network file (`dig-cont_0570_s3.tflite` - default, `dig-class100_0120_s2_q.tflite`)
|
||||
|
||||
- Added automated filtering of tflite-file in the graphical configuration (thanks to @**[caco3](https://github.com/caco3)**)
|
||||
|
||||
@@ -422,8 +550,8 @@ Intermediate Digits
|
||||
|
||||
Intermediate Digits
|
||||
|
||||
- New and improved consistency check (especially with analog and digital counters mixed)
|
||||
- Bug Fix: digital counter algorithm
|
||||
- New and improved consistency check (especially with analog and digit counters mixed)
|
||||
- Bug Fix: digit counter algorithm
|
||||
|
||||
## [11.0.1](https://github.com/jomjol/AI-on-the-edge-device/releases/tag/v11.0.1), 2022-08-18
|
||||
|
||||
@@ -463,7 +591,7 @@ Stability Increase
|
||||
|
||||
- `config.ini`: removal of modelsize (readout from tflite)
|
||||
|
||||
- Updated analog neural network file (`ana1000s2.tflite`) & digital neural network file (`dig1400s2q.tflite`)
|
||||
- Updated analog neural network file (`ana1000s2.tflite`) & digit neural network file (`dig1400s2q.tflite`)
|
||||
|
||||
- TFMicro/Lite: Update (espressif Version 20220716)
|
||||
|
||||
@@ -499,7 +627,7 @@ Stability Increase
|
||||
- In the future the new files will also be copied to the `firmware` directory of the repository
|
||||
- Added Wifi RSSI to MQTT information
|
||||
- Updated analog neural network file (`ana-s3-q-20220105.tflite`)
|
||||
- Updated digital neural network file (`dig-s1-q-20220102.tflite`)
|
||||
- Updated digit neural network file (`dig-s1-q-20220102.tflite`)
|
||||
- Updated build environment to `Espressif 3.5.0`
|
||||
|
||||
## [10.3.0] - (2022-01-29)
|
||||
@@ -565,7 +693,7 @@ Stability Increase
|
||||
|
||||
- Update analog neural network (ana-s3-q-20220105.tflite)
|
||||
|
||||
- Update digital neural network (dig-s1-q-20220102.tflite)
|
||||
- Update digit neural network (dig-s1-q-20220102.tflite)
|
||||
|
||||
- Increased web-server buffers
|
||||
|
||||
@@ -602,7 +730,7 @@ External Illumination
|
||||
- Direct JSON access: `http://IP-ADRESS/json`
|
||||
- Error message in log file in case camera error during startup
|
||||
- Upgrade analog CNN to v9.1.0
|
||||
- Upgrade digital CNN to v13.3.0 (added new images)
|
||||
- Upgrade digit CNN to v13.3.0 (added new images)
|
||||
- html: support of different ports
|
||||
|
||||
## [9.1.1] - External Illumination (2021-11-16)
|
||||
@@ -627,7 +755,7 @@ External Illumination
|
||||
|
||||
### Changed
|
||||
|
||||
- Upgrade digital CNN to v13.1.0 (added new images)
|
||||
- Upgrade digit CNN to v13.1.0 (added new images)
|
||||
- bug fix: wlan password with space, double digit output
|
||||
|
||||
## [8.4.0] - Multi Meter Support (2021-09-25)
|
||||
@@ -657,7 +785,7 @@ External Illumination
|
||||
|
||||
### Changed
|
||||
|
||||
- Upgrade digital CNN to v12.1.0 (added new images)
|
||||
- Upgrade digit CNN to v12.1.0 (added new images)
|
||||
- Dedicated NaN handling, internal refactoring (CNN-Handling)
|
||||
- HTML: confirmation after config.ini update
|
||||
- Bug fixing
|
||||
@@ -679,7 +807,7 @@ External Illumination
|
||||
- GPIO: using the general mqtt main topic for GPIO
|
||||
|
||||
|
||||
- Upgrade digital CNN to v12.0.0 (added new images)
|
||||
- Upgrade digit CNN to v12.0.0 (added new images)
|
||||
- Update tfmicro to new master (2021-08-07)
|
||||
- Bug fix: remove text in mqtt value, remove connect limit in wlan reconnet
|
||||
|
||||
@@ -715,7 +843,7 @@ External Illumination
|
||||
|
||||
- Update wlan handling to esp-idf 4.1
|
||||
|
||||
- Upgrade digital CNN to v8.7.0 (added new images)
|
||||
- Upgrade digit CNN to v8.7.0 (added new images)
|
||||
|
||||
- Bug fix: MQTT, WLAN, LED-Controll, GPIO usage, fixed IP, calculation flow rate
|
||||
|
||||
@@ -726,7 +854,7 @@ External Illumination
|
||||
- NEW: 7.0.1: bug fix wlan password with "="
|
||||
|
||||
|
||||
- Upgrade digital CNN to v8.5.0 (added new images)
|
||||
- Upgrade digit CNN to v8.5.0 (added new images)
|
||||
|
||||
- New MQTT topics: flow rate (units/minute), time stamp (last correct read readout)
|
||||
|
||||
@@ -743,7 +871,7 @@ External Illumination
|
||||
|
||||
- NEW 6.7.1: Improved stability of camera (back to v6.6.1) - remove black strips and areas
|
||||
|
||||
- Upgrade digital CNN to v8.3.0 (added new type of digits)
|
||||
- Upgrade digit CNN to v8.3.0 (added new type of digits)
|
||||
|
||||
- Internal update: TFlite (v2.5), esp32cam, startup sequence
|
||||
|
||||
@@ -764,7 +892,7 @@ External Illumination
|
||||
|
||||
### Changed
|
||||
|
||||
- Upgrade digital CNN to v8.2.0 (added new type of digits)
|
||||
- Upgrade digit CNN to v8.2.0 (added new type of digits)
|
||||
|
||||
|
||||
- Supporting alignment structures in ROI definition
|
||||
@@ -800,7 +928,7 @@ External Illumination
|
||||
|
||||
- Determination of fixed illumination settings during startup - speed up of 5s in each run
|
||||
|
||||
- Update digital CNN to v8.1.1 (additional digital images trained)
|
||||
- Update digit CNN to v8.1.1 (additional digit images trained)
|
||||
|
||||
- Extended error message in MQTT error message
|
||||
|
||||
@@ -812,7 +940,7 @@ External Illumination
|
||||
|
||||
### Changed
|
||||
|
||||
- Disabling of analog / digital counters in configuration
|
||||
- Disabling of analog / digit counters in configuration
|
||||
|
||||
|
||||
- Improved Alignment Algorithm (`AlignmentAlgo` = `Default`, `Accurate` , `Fast`)
|
||||
@@ -832,7 +960,7 @@ External Illumination
|
||||
|
||||
- MQTT: Last Will Testament (LWT) implemented: "connection lost" in case of connection lost to `TopicError`
|
||||
- Disabled `CheckDigitIncreaseConsistency` in default configuration - must now be explicit enabled if needed
|
||||
- Update digital CNN to v7.2.1 (additional digital images trained)
|
||||
- Update digit CNN to v7.2.1 (additional digit images trained)
|
||||
- Setting of arbitrary time server in `config.ini`
|
||||
- Option for fixed IP-, DNS-Settings in `wlan.ini`
|
||||
- Increased stability (internal image and camera handling)
|
||||
@@ -866,7 +994,7 @@ External Illumination
|
||||
|
||||
- standardized access to current logfile via `http://IP-ADRESS/logfileact`
|
||||
|
||||
- Update digital CNN to v7.2.0, analog CNN to 6.3.0
|
||||
- Update digit CNN to v7.2.0, analog CNN to 6.3.0
|
||||
|
||||
- Bug fixing: truncation error, CheckDigitConsistency & PreValue implementation
|
||||
|
||||
@@ -885,7 +1013,7 @@ External Illumination
|
||||
|
||||
### Changed
|
||||
|
||||
- Update digital CNN to v6.5.0 and HTML (Info to hostname, IP, ssid)
|
||||
- Update digit CNN to v6.5.0 and HTML (Info to hostname, IP, ssid)
|
||||
|
||||
- New implementation of "checkDigitConsistency" also for digits
|
||||
|
||||
|
||||
@@ -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 preferred 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
File diff suppressed because it is too large
Load Diff
@@ -15,49 +15,99 @@
|
||||
#include "CImageBasis.h"
|
||||
#include "../../include/defines.h"
|
||||
|
||||
class CCamera {
|
||||
protected:
|
||||
int ActualQuality;
|
||||
framesize_t ActualResolution;
|
||||
int brightness, contrast, saturation;
|
||||
bool isFixedExposure;
|
||||
int waitbeforepicture_org;
|
||||
int led_intensity = 4095;
|
||||
typedef struct
|
||||
{
|
||||
uint16_t CamSensor_id;
|
||||
|
||||
void ledc_init(void);
|
||||
bool CameraInitSuccessful = false;
|
||||
bool demoMode = false;
|
||||
framesize_t ImageFrameSize = FRAMESIZE_VGA; // 0 - 10
|
||||
gainceiling_t ImageGainceiling; // Image gain (GAINCEILING_x2, x4, x8, x16, x32, x64 or x128)
|
||||
|
||||
bool loadNextDemoImage(camera_fb_t *fb);
|
||||
long GetFileSize(std::string filename);
|
||||
int ImageQuality; // 0 - 63
|
||||
int ImageBrightness; // (-2 to 2) - set brightness
|
||||
int ImageContrast; //-2 - 2
|
||||
int ImageSaturation; //-2 - 2
|
||||
int ImageSharpness; //-2 - 2
|
||||
bool ImageAutoSharpness;
|
||||
int ImageSpecialEffect; // 0 - 6
|
||||
int ImageWbMode; // 0 to 4 - if awb_gain enabled (0 - Auto, 1 - Sunny, 2 - Cloudy, 3 - Office, 4 - Home)
|
||||
int ImageAwb; // white balance enable (0 or 1)
|
||||
int ImageAwbGain; // Auto White Balance enable (0 or 1)
|
||||
int ImageAec; // auto exposure off (1 or 0)
|
||||
int ImageAec2; // automatic exposure sensor (0 or 1)
|
||||
int ImageAeLevel; // auto exposure levels (-2 to 2)
|
||||
int ImageAecValue; // set exposure manually (0-1200)
|
||||
int ImageAgc; // auto gain off (1 or 0)
|
||||
int ImageAgcGain; // set gain manually (0 - 30)
|
||||
int ImageBpc; // black pixel correction
|
||||
int ImageWpc; // white pixel correction
|
||||
int ImageRawGma; // (1 or 0)
|
||||
int ImageLenc; // lens correction (1 or 0)
|
||||
int ImageHmirror; // (0 or 1) flip horizontally
|
||||
int ImageVflip; // Invert image (0 or 1)
|
||||
int ImageDcw; // downsize enable (1 or 0)
|
||||
|
||||
public:
|
||||
int image_height, image_width;
|
||||
|
||||
CCamera();
|
||||
esp_err_t InitCam();
|
||||
int ImageDenoiseLevel; // The OV2640 does not support it, OV3660 and OV5640 (0 to 8)
|
||||
|
||||
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);
|
||||
void SetLEDIntensity(float _intrel);
|
||||
bool testCamera(void);
|
||||
void EnableAutoExposure(int flash_duration);
|
||||
bool getCameraInitSuccessful();
|
||||
void useDemoMode(void);
|
||||
|
||||
int ImageWidth;
|
||||
int ImageHeight;
|
||||
|
||||
framesize_t TextToFramesize(const char * text);
|
||||
int ImageLedIntensity;
|
||||
|
||||
esp_err_t CaptureToFile(std::string nm, int delay = 0);
|
||||
esp_err_t CaptureToBasisImage(CImageBasis *_Image, int delay = 0);
|
||||
bool ImageZoomEnabled;
|
||||
int ImageZoomOffsetX;
|
||||
int ImageZoomOffsetY;
|
||||
int ImageZoomSize;
|
||||
|
||||
int WaitBeforePicture;
|
||||
bool isImageSize;
|
||||
|
||||
bool CameraInitSuccessful;
|
||||
bool changedCameraSettings;
|
||||
bool DemoMode;
|
||||
bool SaveAllFiles;
|
||||
} camera_controll_config_temp_t;
|
||||
|
||||
extern camera_controll_config_temp_t CCstatus;
|
||||
|
||||
class CCamera
|
||||
{
|
||||
protected:
|
||||
void ledc_init(void);
|
||||
bool loadNextDemoImage(camera_fb_t *fb);
|
||||
long GetFileSize(std::string filename);
|
||||
void SetCamWindow(sensor_t *s, int frameSizeX, int frameSizeY, int xOffset, int yOffset, int xTotal, int yTotal, int xOutput, int yOutput, int imageVflip);
|
||||
void SetImageWidthHeightFromResolution(framesize_t resol);
|
||||
void SanitizeZoomParams(int imageSize, int frameSizeX, int frameSizeY, int &imageWidth, int &imageHeight, int &zoomOffsetX, int &zoomOffsetY);
|
||||
|
||||
public:
|
||||
CCamera(void);
|
||||
esp_err_t InitCam(void);
|
||||
|
||||
void LightOnOff(bool status);
|
||||
void LEDOnOff(bool status);
|
||||
|
||||
esp_err_t setSensorDatenFromCCstatus(void);
|
||||
esp_err_t getSensorDatenToCCstatus(void);
|
||||
|
||||
int ov5640_set_gainceiling(sensor_t *s, gainceiling_t level);
|
||||
|
||||
esp_err_t CaptureToHTTP(httpd_req_t *req, int delay = 0);
|
||||
esp_err_t CaptureToStream(httpd_req_t *req, bool FlashlightOn);
|
||||
|
||||
void SetQualityZoomSize(int qual, framesize_t resol, bool zoomEnabled, int zoomOffsetX, int zoomOffsetY, int imageSize, int imageVflip);
|
||||
void SetZoomSize(bool zoomEnabled, int zoomOffsetX, int zoomOffsetY, int imageSize, int imageVflip);
|
||||
void SetCamSharpness(bool _autoSharpnessEnabled, int _sharpnessLevel);
|
||||
|
||||
void SetLEDIntensity(float _intrel);
|
||||
bool testCamera(void);
|
||||
bool getCameraInitSuccessful(void);
|
||||
void useDemoMode(void);
|
||||
|
||||
framesize_t TextToFramesize(const char *text);
|
||||
|
||||
esp_err_t CaptureToFile(std::string nm, int delay = 0);
|
||||
esp_err_t CaptureToBasisImage(CImageBasis *_Image, int delay = 0);
|
||||
};
|
||||
|
||||
|
||||
extern CCamera Camera;
|
||||
|
||||
#endif
|
||||
152
code/components/jomjol_controlcamera/ov2640_sharpness.cpp
Normal file
152
code/components/jomjol_controlcamera/ov2640_sharpness.cpp
Normal file
@@ -0,0 +1,152 @@
|
||||
#include <stdint.h>
|
||||
#include "esp_camera.h"
|
||||
#include "ov2640_sharpness.h"
|
||||
|
||||
|
||||
const static uint8_t OV2640_SHARPNESS_AUTO[]=
|
||||
{
|
||||
//reg, val, mask
|
||||
0xFF, 0x00, 0xFF,
|
||||
0x92, 0x01, 0xFF,
|
||||
0x93, 0x20, 0x20,
|
||||
0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
const static uint8_t OV2640_SHARPNESS_MANUAL[]=
|
||||
{
|
||||
//reg, val, mask
|
||||
0xFF, 0x00, 0xFF,
|
||||
0x92, 0x01, 0xFF,
|
||||
0x93, 0x00, 0x20,
|
||||
0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
const static uint8_t OV2640_SHARPNESS_LEVEL0[]=
|
||||
{
|
||||
//reg, val, mask
|
||||
0xFF, 0x00, 0xFF,
|
||||
0x92, 0x01, 0xFF,
|
||||
0x93, 0xC0, 0x1F,
|
||||
0x00, 0x00, 0x00
|
||||
};
|
||||
const static uint8_t OV2640_SHARPNESS_LEVEL1[]=
|
||||
{
|
||||
//reg, val, mask
|
||||
0xFF, 0x00, 0xFF,
|
||||
0x92, 0x01, 0xFF,
|
||||
0x93, 0xC1, 0x1F,
|
||||
0x00, 0x00, 0x00
|
||||
};
|
||||
const static uint8_t OV2640_SHARPNESS_LEVEL2[]=
|
||||
{
|
||||
//reg, val, mask
|
||||
0xFF, 0x00, 0xFF,
|
||||
0x92, 0x01, 0xFF,
|
||||
0x93, 0xC2, 0x1F,
|
||||
0x00, 0x00, 0x00
|
||||
};
|
||||
const static uint8_t OV2640_SHARPNESS_LEVEL3[]=
|
||||
{
|
||||
//reg, val, mask
|
||||
0xFF, 0x00, 0xFF,
|
||||
0x92, 0x01, 0xFF,
|
||||
0x93, 0xC4, 0x1F,
|
||||
0x00, 0x00, 0x00
|
||||
};
|
||||
const static uint8_t OV2640_SHARPNESS_LEVEL4[]=
|
||||
{
|
||||
//reg, val, mask
|
||||
0xFF, 0x00, 0xFF,
|
||||
0x92, 0x01, 0xFF,
|
||||
0x93, 0xC8, 0x1F,
|
||||
0x00, 0x00, 0x00
|
||||
};
|
||||
const static uint8_t OV2640_SHARPNESS_LEVEL5[]=
|
||||
{
|
||||
//reg, val, mask
|
||||
0xFF, 0x00, 0xFF,
|
||||
0x92, 0x01, 0xFF,
|
||||
0x93, 0xD0, 0x1F,
|
||||
0x00, 0x00, 0x00
|
||||
};
|
||||
const static uint8_t OV2640_SHARPNESS_LEVEL6[]=
|
||||
{
|
||||
//reg, val, mask
|
||||
0xFF, 0x00, 0xFF,
|
||||
0x92, 0x01, 0xFF,
|
||||
0x93, 0xDF, 0x1F,
|
||||
0x00, 0x00, 0x00
|
||||
};
|
||||
|
||||
const static uint8_t *OV2640_SETTING_SHARPNESS[]=
|
||||
{
|
||||
OV2640_SHARPNESS_LEVEL0, // -3 sharpness
|
||||
OV2640_SHARPNESS_LEVEL1,
|
||||
OV2640_SHARPNESS_LEVEL2,
|
||||
OV2640_SHARPNESS_LEVEL3,
|
||||
OV2640_SHARPNESS_LEVEL4,
|
||||
OV2640_SHARPNESS_LEVEL5,
|
||||
OV2640_SHARPNESS_LEVEL6 // +3 sharpness
|
||||
};
|
||||
|
||||
#define OV2640_MAXLEVEL_SHARPNESS 6
|
||||
|
||||
|
||||
static int table_mask_write(sensor_t *sensor, const uint8_t* ptab)
|
||||
{
|
||||
uint8_t address;
|
||||
uint8_t value;
|
||||
uint8_t orgval;
|
||||
uint8_t mask;
|
||||
const uint8_t *pdata = ptab;
|
||||
|
||||
if (pdata == NULL)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
while (1)
|
||||
{
|
||||
address = *pdata++;
|
||||
value = *pdata++;
|
||||
mask = *pdata++;
|
||||
|
||||
if ((address == 0) && (value == 0) && (mask == 0))
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
sensor->set_reg(sensor, address, mask, value);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int ov2640_enable_auto_sharpness(sensor_t *sensor)
|
||||
{
|
||||
table_mask_write(sensor, OV2640_SHARPNESS_AUTO);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int ov2640_set_sharpness(sensor_t *sensor, int sharpness)
|
||||
{
|
||||
int sharpness_temp = 0;
|
||||
|
||||
if (sharpness < -3)
|
||||
{
|
||||
sharpness_temp = -3;
|
||||
}
|
||||
|
||||
if (sharpness > OV2640_MAXLEVEL_SHARPNESS - 3)
|
||||
{
|
||||
sharpness_temp = OV2640_MAXLEVEL_SHARPNESS - 3;
|
||||
}
|
||||
|
||||
table_mask_write(sensor, OV2640_SHARPNESS_MANUAL);
|
||||
table_mask_write(sensor, OV2640_SETTING_SHARPNESS[sharpness_temp + 3]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
11
code/components/jomjol_controlcamera/ov2640_sharpness.h
Normal file
11
code/components/jomjol_controlcamera/ov2640_sharpness.h
Normal file
@@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef OV2640_SHARPNESS_H
|
||||
#define OV2640_SHARPNESS_H
|
||||
|
||||
#include "esp_camera.h"
|
||||
|
||||
int ov2640_enable_auto_sharpness(sensor_t *sensor);
|
||||
int ov2640_set_sharpness(sensor_t *sensor, int sharpness); // -3 to +3, -4 for auto-sharpness
|
||||
|
||||
#endif
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
#include "esp_camera.h"
|
||||
#include "ClassControllCamera.h"
|
||||
#include "MainFlowControl.h"
|
||||
|
||||
#include "ClassLogFile.h"
|
||||
#include "esp_log.h"
|
||||
@@ -13,183 +14,187 @@
|
||||
|
||||
static const char *TAG = "server_cam";
|
||||
|
||||
void PowerResetCamera()
|
||||
{
|
||||
#if CAM_PIN_PWDN == GPIO_NUM_NC // Use reset only if pin is available
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "No power down pin availbale to reset camera");
|
||||
#else
|
||||
ESP_LOGD(TAG, "Resetting camera by power down line");
|
||||
gpio_config_t conf;
|
||||
conf.intr_type = GPIO_INTR_DISABLE;
|
||||
conf.pin_bit_mask = 1LL << CAM_PIN_PWDN;
|
||||
conf.mode = GPIO_MODE_OUTPUT;
|
||||
conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
|
||||
conf.pull_up_en = GPIO_PULLUP_DISABLE;
|
||||
gpio_config(&conf);
|
||||
|
||||
void PowerResetCamera(){
|
||||
|
||||
ESP_LOGD(TAG, "Resetting camera by power down line");
|
||||
gpio_config_t conf;
|
||||
conf.intr_type = GPIO_INTR_DISABLE;
|
||||
conf.pin_bit_mask = 1LL << GPIO_NUM_32;
|
||||
conf.mode = GPIO_MODE_OUTPUT;
|
||||
conf.pull_down_en = GPIO_PULLDOWN_DISABLE;
|
||||
conf.pull_up_en = GPIO_PULLUP_DISABLE;
|
||||
gpio_config(&conf);
|
||||
|
||||
// carefull, logic is inverted compared to reset pin
|
||||
gpio_set_level(GPIO_NUM_32, 1);
|
||||
vTaskDelay(1000 / portTICK_PERIOD_MS);
|
||||
gpio_set_level(GPIO_NUM_32, 0);
|
||||
vTaskDelay(1000 / portTICK_PERIOD_MS);
|
||||
// carefull, logic is inverted compared to reset pin
|
||||
gpio_set_level(CAM_PIN_PWDN, 1);
|
||||
vTaskDelay(1000 / portTICK_PERIOD_MS);
|
||||
gpio_set_level(CAM_PIN_PWDN, 0);
|
||||
vTaskDelay(1000 / portTICK_PERIOD_MS);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
esp_err_t handler_lightOn(httpd_req_t *req)
|
||||
{
|
||||
#ifdef DEBUG_DETAIL_ON
|
||||
LogFile.WriteHeapInfo("handler_lightOn - Start");
|
||||
ESP_LOGD(TAG, "handler_lightOn uri: %s", req->uri);
|
||||
#endif
|
||||
#ifdef DEBUG_DETAIL_ON
|
||||
LogFile.WriteHeapInfo("handler_lightOn - Start");
|
||||
ESP_LOGD(TAG, "handler_lightOn uri: %s", req->uri);
|
||||
#endif
|
||||
|
||||
if (Camera.getCameraInitSuccessful())
|
||||
if (Camera.getCameraInitSuccessful())
|
||||
{
|
||||
Camera.LightOnOff(true);
|
||||
const char* resp_str = (const char*) req->user_ctx;
|
||||
const char *resp_str = (const char *)req->user_ctx;
|
||||
httpd_resp_send(req, resp_str, strlen(resp_str));
|
||||
}
|
||||
else
|
||||
else
|
||||
{
|
||||
httpd_resp_send_err(req, HTTPD_403_FORBIDDEN, "Camera not initialized: REST API /lighton not available!");
|
||||
return ESP_ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_DETAIL_ON
|
||||
LogFile.WriteHeapInfo("handler_lightOn - Done");
|
||||
#endif
|
||||
#ifdef DEBUG_DETAIL_ON
|
||||
LogFile.WriteHeapInfo("handler_lightOn - Done");
|
||||
#endif
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
|
||||
esp_err_t handler_lightOff(httpd_req_t *req)
|
||||
{
|
||||
#ifdef DEBUG_DETAIL_ON
|
||||
LogFile.WriteHeapInfo("handler_lightOff - Start");
|
||||
ESP_LOGD(TAG, "handler_lightOff uri: %s", req->uri);
|
||||
#endif
|
||||
#ifdef DEBUG_DETAIL_ON
|
||||
LogFile.WriteHeapInfo("handler_lightOff - Start");
|
||||
ESP_LOGD(TAG, "handler_lightOff uri: %s", req->uri);
|
||||
#endif
|
||||
|
||||
if (Camera.getCameraInitSuccessful())
|
||||
if (Camera.getCameraInitSuccessful())
|
||||
{
|
||||
Camera.LightOnOff(false);
|
||||
const char* resp_str = (const char*) req->user_ctx;
|
||||
httpd_resp_send(req, resp_str, strlen(resp_str));
|
||||
const char *resp_str = (const char *)req->user_ctx;
|
||||
httpd_resp_send(req, resp_str, strlen(resp_str));
|
||||
}
|
||||
else
|
||||
else
|
||||
{
|
||||
httpd_resp_send_err(req, HTTPD_403_FORBIDDEN, "Camera not initialized: REST API /lightoff not available!");
|
||||
return ESP_ERR_NOT_FOUND;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_DETAIL_ON
|
||||
LogFile.WriteHeapInfo("handler_lightOff - Done");
|
||||
#endif
|
||||
#ifdef DEBUG_DETAIL_ON
|
||||
LogFile.WriteHeapInfo("handler_lightOff - Done");
|
||||
#endif
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
|
||||
esp_err_t handler_capture(httpd_req_t *req)
|
||||
{
|
||||
#ifdef DEBUG_DETAIL_ON
|
||||
LogFile.WriteHeapInfo("handler_capture - Start");
|
||||
#endif
|
||||
#ifdef DEBUG_DETAIL_ON
|
||||
LogFile.WriteHeapInfo("handler_capture - Start");
|
||||
#endif
|
||||
|
||||
if (Camera.getCameraInitSuccessful())
|
||||
if (Camera.getCameraInitSuccessful())
|
||||
{
|
||||
int quality;
|
||||
framesize_t res;
|
||||
// If the camera settings were changed by creating a new reference image, they must be reset
|
||||
if (CFstatus.changedCameraSettings)
|
||||
{
|
||||
Camera.setSensorDatenFromCCstatus(); // CCstatus >>> Kamera
|
||||
Camera.SetQualityZoomSize(CCstatus.ImageQuality, CCstatus.ImageFrameSize, CCstatus.ImageZoomEnabled, CCstatus.ImageZoomOffsetX, CCstatus.ImageZoomOffsetY, CCstatus.ImageZoomSize, CCstatus.ImageVflip);
|
||||
CFstatus.changedCameraSettings = false;
|
||||
}
|
||||
|
||||
Camera.GetCameraParameter(req, quality, res);
|
||||
|
||||
#ifdef DEBUG_DETAIL_ON
|
||||
ESP_LOGD(TAG, "Size: %d, Quality: %d", res, quality);
|
||||
#endif
|
||||
|
||||
Camera.SetQualitySize(quality, res);
|
||||
#ifdef DEBUG_DETAIL_ON
|
||||
ESP_LOGD(TAG, "Size: %d, Quality: %d", CCstatus.ImageFrameSize, CCstatus.ImageQuality);
|
||||
#endif
|
||||
|
||||
esp_err_t result;
|
||||
result = Camera.CaptureToHTTP(req);
|
||||
|
||||
#ifdef DEBUG_DETAIL_ON
|
||||
LogFile.WriteHeapInfo("handler_capture - Done");
|
||||
#endif
|
||||
#ifdef DEBUG_DETAIL_ON
|
||||
LogFile.WriteHeapInfo("handler_capture - Done");
|
||||
#endif
|
||||
|
||||
return result;
|
||||
}
|
||||
else
|
||||
else
|
||||
{
|
||||
httpd_resp_send_err(req, HTTPD_403_FORBIDDEN, "Camera not initialized: REST API /capture not available!");
|
||||
return ESP_ERR_NOT_FOUND;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
esp_err_t handler_capture_with_light(httpd_req_t *req)
|
||||
{
|
||||
#ifdef DEBUG_DETAIL_ON
|
||||
LogFile.WriteHeapInfo("handler_capture_with_light - Start");
|
||||
#endif
|
||||
|
||||
if (Camera.getCameraInitSuccessful())
|
||||
#ifdef DEBUG_DETAIL_ON
|
||||
LogFile.WriteHeapInfo("handler_capture_with_light - Start");
|
||||
#endif
|
||||
|
||||
if (Camera.getCameraInitSuccessful())
|
||||
{
|
||||
char _query[100];
|
||||
char _delay[10];
|
||||
|
||||
int quality;
|
||||
framesize_t res;
|
||||
int delay = 2500;
|
||||
|
||||
if (httpd_req_get_url_query_str(req, _query, 100) == ESP_OK)
|
||||
{
|
||||
ESP_LOGD(TAG, "Query: %s", _query);
|
||||
|
||||
if (httpd_query_key_value(_query, "delay", _delay, 10) == ESP_OK)
|
||||
{
|
||||
#ifdef DEBUG_DETAIL_ON
|
||||
ESP_LOGD(TAG, "Delay: %s", _delay);
|
||||
#endif
|
||||
#ifdef DEBUG_DETAIL_ON
|
||||
ESP_LOGD(TAG, "Delay: %s", _delay);
|
||||
#endif
|
||||
delay = atoi(_delay);
|
||||
|
||||
if (delay < 0)
|
||||
{
|
||||
delay = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Camera.GetCameraParameter(req, quality, res);
|
||||
// If the camera settings were changed by creating a new reference image, they must be reset
|
||||
if (CFstatus.changedCameraSettings)
|
||||
{
|
||||
Camera.setSensorDatenFromCCstatus(); // CCstatus >>> Kamera
|
||||
Camera.SetQualityZoomSize(CCstatus.ImageQuality, CCstatus.ImageFrameSize, CCstatus.ImageZoomEnabled, CCstatus.ImageZoomOffsetX, CCstatus.ImageZoomOffsetY, CCstatus.ImageZoomSize, CCstatus.ImageVflip);
|
||||
CFstatus.changedCameraSettings = false;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_DETAIL_ON
|
||||
ESP_LOGD(TAG, "Size: %d, Quality: %d", res, quality);
|
||||
#endif
|
||||
#ifdef DEBUG_DETAIL_ON
|
||||
ESP_LOGD(TAG, "Size: %d, Quality: %d", CCstatus.ImageFrameSize, CCstatus.ImageQuality);
|
||||
#endif
|
||||
|
||||
Camera.SetQualitySize(quality, res);
|
||||
Camera.LightOnOff(true);
|
||||
const TickType_t xDelay = delay / portTICK_PERIOD_MS;
|
||||
vTaskDelay( xDelay );
|
||||
vTaskDelay(xDelay);
|
||||
|
||||
esp_err_t result;
|
||||
result = Camera.CaptureToHTTP(req);
|
||||
result = Camera.CaptureToHTTP(req);
|
||||
|
||||
Camera.LightOnOff(false);
|
||||
|
||||
#ifdef DEBUG_DETAIL_ON
|
||||
LogFile.WriteHeapInfo("handler_capture_with_light - Done");
|
||||
#endif
|
||||
#ifdef DEBUG_DETAIL_ON
|
||||
LogFile.WriteHeapInfo("handler_capture_with_light - Done");
|
||||
#endif
|
||||
|
||||
return result;
|
||||
}
|
||||
else
|
||||
else
|
||||
{
|
||||
httpd_resp_send_err(req, HTTPD_403_FORBIDDEN, "Camera not initialized: REST API /capture_with_flashlight not available!");
|
||||
return ESP_ERR_NOT_FOUND;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
esp_err_t handler_capture_save_to_file(httpd_req_t *req)
|
||||
{
|
||||
#ifdef DEBUG_DETAIL_ON
|
||||
LogFile.WriteHeapInfo("handler_capture_save_to_file - Start");
|
||||
#endif
|
||||
#ifdef DEBUG_DETAIL_ON
|
||||
LogFile.WriteHeapInfo("handler_capture_save_to_file - Start");
|
||||
#endif
|
||||
|
||||
if (Camera.getCameraInitSuccessful())
|
||||
if (Camera.getCameraInitSuccessful())
|
||||
{
|
||||
char _query[100];
|
||||
char _delay[10];
|
||||
@@ -197,94 +202,102 @@ esp_err_t handler_capture_save_to_file(httpd_req_t *req)
|
||||
char filename[100];
|
||||
std::string fn = "/sdcard/";
|
||||
|
||||
|
||||
int quality;
|
||||
framesize_t res;
|
||||
|
||||
if (httpd_req_get_url_query_str(req, _query, 100) == ESP_OK)
|
||||
{
|
||||
ESP_LOGD(TAG, "Query: %s", _query);
|
||||
|
||||
if (httpd_query_key_value(_query, "filename", filename, 100) == ESP_OK)
|
||||
{
|
||||
fn.append(filename);
|
||||
#ifdef DEBUG_DETAIL_ON
|
||||
ESP_LOGD(TAG, "Filename: %s", fn.c_str());
|
||||
#endif
|
||||
#ifdef DEBUG_DETAIL_ON
|
||||
ESP_LOGD(TAG, "Filename: %s", fn.c_str());
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
fn.append("noname.jpg");
|
||||
}
|
||||
|
||||
if (httpd_query_key_value(_query, "delay", _delay, 10) == ESP_OK)
|
||||
{
|
||||
#ifdef DEBUG_DETAIL_ON
|
||||
ESP_LOGD(TAG, "Delay: %s", _delay);
|
||||
#endif
|
||||
#ifdef DEBUG_DETAIL_ON
|
||||
ESP_LOGD(TAG, "Delay: %s", _delay);
|
||||
#endif
|
||||
delay = atoi(_delay);
|
||||
|
||||
if (delay < 0)
|
||||
{
|
||||
delay = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
fn.append("noname.jpg");
|
||||
}
|
||||
|
||||
Camera.GetCameraParameter(req, quality, res);
|
||||
#ifdef DEBUG_DETAIL_ON
|
||||
ESP_LOGD(TAG, "Size: %d, Quality: %d", res, quality);
|
||||
#endif
|
||||
Camera.SetQualitySize(quality, res);
|
||||
// If the camera settings were changed by creating a new reference image, they must be reset
|
||||
if (CFstatus.changedCameraSettings)
|
||||
{
|
||||
Camera.setSensorDatenFromCCstatus(); // CCstatus >>> Kamera
|
||||
Camera.SetQualityZoomSize(CCstatus.ImageQuality, CCstatus.ImageFrameSize, CCstatus.ImageZoomEnabled, CCstatus.ImageZoomOffsetX, CCstatus.ImageZoomOffsetY, CCstatus.ImageZoomSize, CCstatus.ImageVflip);
|
||||
CFstatus.changedCameraSettings = false;
|
||||
}
|
||||
|
||||
#ifdef DEBUG_DETAIL_ON
|
||||
ESP_LOGD(TAG, "Size: %d, Quality: %d", CCstatus.ImageFrameSize, CCstatus.ImageQuality);
|
||||
#endif
|
||||
|
||||
esp_err_t result;
|
||||
result = Camera.CaptureToFile(fn, delay);
|
||||
result = Camera.CaptureToFile(fn, delay);
|
||||
|
||||
const char* resp_str = (const char*) fn.c_str();
|
||||
const char *resp_str = (const char *)fn.c_str();
|
||||
httpd_resp_send(req, resp_str, strlen(resp_str));
|
||||
|
||||
#ifdef DEBUG_DETAIL_ON
|
||||
LogFile.WriteHeapInfo("handler_capture_save_to_file - Done");
|
||||
#endif
|
||||
#ifdef DEBUG_DETAIL_ON
|
||||
LogFile.WriteHeapInfo("handler_capture_save_to_file - Done");
|
||||
#endif
|
||||
|
||||
return result;
|
||||
}
|
||||
else
|
||||
else
|
||||
{
|
||||
httpd_resp_send_err(req, HTTPD_403_FORBIDDEN, "Camera not initialized: REST API /save not available!");
|
||||
return ESP_ERR_NOT_FOUND;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void register_server_camera_uri(httpd_handle_t server)
|
||||
{
|
||||
#ifdef DEBUG_DETAIL_ON
|
||||
#ifdef DEBUG_DETAIL_ON
|
||||
ESP_LOGI(TAG, "server_part_camera - Registering URI handlers");
|
||||
#endif
|
||||
|
||||
httpd_uri_t camuri = { };
|
||||
camuri.method = HTTP_GET;
|
||||
httpd_uri_t camuri = {};
|
||||
camuri.method = HTTP_GET;
|
||||
|
||||
camuri.uri = "/lighton";
|
||||
camuri.handler = handler_lightOn;
|
||||
camuri.user_ctx = (void*) "Light On";
|
||||
camuri.uri = "/lighton";
|
||||
camuri.handler = handler_lightOn;
|
||||
camuri.user_ctx = (void *)"Light On";
|
||||
httpd_register_uri_handler(server, &camuri);
|
||||
|
||||
camuri.uri = "/lightoff";
|
||||
camuri.handler = handler_lightOff;
|
||||
camuri.user_ctx = (void*) "Light Off";
|
||||
httpd_register_uri_handler(server, &camuri);
|
||||
camuri.uri = "/lightoff";
|
||||
camuri.handler = handler_lightOff;
|
||||
camuri.user_ctx = (void *)"Light Off";
|
||||
httpd_register_uri_handler(server, &camuri);
|
||||
|
||||
camuri.uri = "/capture";
|
||||
camuri.handler = handler_capture;
|
||||
camuri.user_ctx = NULL;
|
||||
httpd_register_uri_handler(server, &camuri);
|
||||
camuri.uri = "/capture";
|
||||
camuri.handler = handler_capture;
|
||||
camuri.user_ctx = NULL;
|
||||
httpd_register_uri_handler(server, &camuri);
|
||||
|
||||
camuri.uri = "/capture_with_flashlight";
|
||||
camuri.handler = handler_capture_with_light;
|
||||
camuri.user_ctx = NULL;
|
||||
httpd_register_uri_handler(server, &camuri);
|
||||
camuri.uri = "/capture_with_flashlight";
|
||||
camuri.handler = handler_capture_with_light;
|
||||
camuri.user_ctx = NULL;
|
||||
httpd_register_uri_handler(server, &camuri);
|
||||
|
||||
camuri.uri = "/save";
|
||||
camuri.handler = handler_capture_save_to_file;
|
||||
camuri.user_ctx = NULL;
|
||||
httpd_register_uri_handler(server, &camuri);
|
||||
camuri.uri = "/save";
|
||||
camuri.handler = handler_capture_save_to_file;
|
||||
camuri.user_ctx = NULL;
|
||||
httpd_register_uri_handler(server, &camuri);
|
||||
}
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
//#include "ClassControllCamera.h"
|
||||
|
||||
void register_server_camera_uri(httpd_handle_t server);
|
||||
|
||||
void PowerResetCamera();
|
||||
|
||||
#endif
|
||||
@@ -2,6 +2,6 @@ FILE(GLOB_RECURSE app_sources ${CMAKE_CURRENT_SOURCE_DIR}/*.*)
|
||||
|
||||
idf_component_register(SRCS ${app_sources}
|
||||
INCLUDE_DIRS "." "../../include" "miniz"
|
||||
REQUIRES vfs tflite-lib esp_http_server app_update esp_http_client nvs_flash jomjol_tfliteclass jomjol_flowcontroll spiffs jomjol_helper jomjol_controlGPIO)
|
||||
REQUIRES vfs esp_http_server app_update esp_http_client nvs_flash jomjol_tfliteclass jomjol_flowcontroll spiffs jomjol_helper jomjol_controlGPIO)
|
||||
|
||||
|
||||
|
||||
@@ -153,7 +153,7 @@
|
||||
/*#define MINIZ_NO_MALLOC */
|
||||
|
||||
#ifdef MINIZ_NO_INFLATE_APIS
|
||||
#define MINIZ_NO_ARCHIVE_APIS
|
||||
//#define MINIZ_NO_ARCHIVE_APIS
|
||||
#endif
|
||||
|
||||
#ifdef MINIZ_NO_DEFLATE_APIS
|
||||
|
||||
@@ -4,5 +4,5 @@ It should be possible to include the repo directly as a submodule, how ever it c
|
||||
- https://github.com/richgel999/miniz/issues/145
|
||||
- https://github.com/espressif/esptool/pull/500#issuecomment-574879468
|
||||
|
||||
For sumplicity we therefore use the release files as suggested in the readme.
|
||||
Additionally we added the CMakeLists.txt and this readme.
|
||||
For simplicity we therefore use the release files as suggested in the readme.
|
||||
Additionally we added the CMakeLists.txt and this readme.
|
||||
|
||||
@@ -547,7 +547,7 @@ static esp_err_t download_get_handler(httpd_req_t *req)
|
||||
/* Get value of expected key from query string */
|
||||
if (httpd_query_key_value(buf, "readonly", param, sizeof(param)) == ESP_OK) {
|
||||
ESP_LOGI(TAG, "Found URL query parameter => readonly=%s", param);
|
||||
readonly = param && strcmp(param,"true")==0;
|
||||
readonly = (strcmp(param,"true") == 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -588,7 +588,9 @@ static esp_err_t download_get_handler(httpd_req_t *req)
|
||||
/* Read file in chunks into the scratch buffer */
|
||||
chunksize = fread(chunk, 1, SERVER_FILER_SCRATCH_BUFSIZE, fd);
|
||||
|
||||
/* Send the buffer contents as HTTP response chunk */
|
||||
/* Send buffer contents as HTTP chunk. If empty this functions as a
|
||||
* last-chunk message, signaling end-of-response, to the HTTP client.
|
||||
* See RFC 2616, section 3.6.1 for details on Chunked Transfer Encoding. */
|
||||
if (httpd_resp_send_chunk(req, chunk, chunksize) != ESP_OK) {
|
||||
fclose(fd);
|
||||
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "File sending failed!");
|
||||
@@ -606,8 +608,6 @@ static esp_err_t download_get_handler(httpd_req_t *req)
|
||||
fclose(fd);
|
||||
ESP_LOGD(TAG, "File successfully sent");
|
||||
|
||||
/* Respond with an empty chunk to signal HTTP response completion */
|
||||
httpd_resp_send_chunk(req, NULL, 0);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,6 +2,6 @@ FILE(GLOB_RECURSE app_sources ${CMAKE_CURRENT_SOURCE_DIR}/*.*)
|
||||
|
||||
idf_component_register(SRCS ${app_sources}
|
||||
INCLUDE_DIRS "."
|
||||
REQUIRES esp_timer esp_wifi 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_webhook jomjol_fileserver_ota jomjol_image_proc jomjol_wlan openmetrics)
|
||||
|
||||
|
||||
|
||||
@@ -67,11 +67,6 @@ string ClassFlow::getHTMLSingleStep(string host){
|
||||
return "";
|
||||
}
|
||||
|
||||
string ClassFlow::getReadout()
|
||||
{
|
||||
return string();
|
||||
}
|
||||
|
||||
std::string ClassFlow::GetParameterName(std::string _input)
|
||||
{
|
||||
string _param;
|
||||
|
||||
@@ -46,7 +46,6 @@ public:
|
||||
virtual bool ReadParameter(FILE* pfile, string &aktparamgraph);
|
||||
virtual bool doFlow(string time);
|
||||
virtual string getHTMLSingleStep(string host);
|
||||
virtual string getReadout();
|
||||
virtual string name(){return "ClassFlow";};
|
||||
|
||||
};
|
||||
|
||||
@@ -1,393 +1,374 @@
|
||||
#include "ClassFlowAlignment.h"
|
||||
#include "ClassFlowTakeImage.h"
|
||||
#include "ClassFlow.h"
|
||||
#include "MainFlowControl.h"
|
||||
|
||||
#include "CRotateImage.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
|
||||
#include "ClassLogFile.h"
|
||||
#include "psram.h"
|
||||
#include "../../include/defines.h"
|
||||
|
||||
|
||||
static const char *TAG = "ALIGN";
|
||||
|
||||
// #define DEBUG_DETAIL_ON
|
||||
|
||||
|
||||
void ClassFlowAlignment::SetInitialParameter(void)
|
||||
{
|
||||
initalrotate = 0;
|
||||
anz_ref = 0;
|
||||
initialmirror = false;
|
||||
use_antialiasing = false;
|
||||
initialflip = false;
|
||||
SaveAllFiles = false;
|
||||
namerawimage = "/sdcard/img_tmp/raw.jpg";
|
||||
FileStoreRefAlignment = "/sdcard/config/align.txt";
|
||||
ListFlowControll = NULL;
|
||||
AlignAndCutImage = NULL;
|
||||
ImageBasis = NULL;
|
||||
ImageTMP = NULL;
|
||||
#ifdef ALGROI_LOAD_FROM_MEM_AS_JPG
|
||||
AlgROI = (ImageData*)malloc_psram_heap(std::string(TAG) + "->AlgROI", sizeof(ImageData), MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM);
|
||||
#endif
|
||||
previousElement = NULL;
|
||||
disabled = false;
|
||||
SAD_criteria = 0.05;
|
||||
}
|
||||
|
||||
|
||||
ClassFlowAlignment::ClassFlowAlignment(std::vector<ClassFlow*>* lfc)
|
||||
{
|
||||
SetInitialParameter();
|
||||
ListFlowControll = lfc;
|
||||
|
||||
for (int i = 0; i < ListFlowControll->size(); ++i)
|
||||
{
|
||||
if (((*ListFlowControll)[i])->name().compare("ClassFlowTakeImage") == 0)
|
||||
{
|
||||
ImageBasis = ((ClassFlowTakeImage*) (*ListFlowControll)[i])->rawImage;
|
||||
}
|
||||
}
|
||||
|
||||
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("ImageBasis", namerawimage);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool ClassFlowAlignment::ReadParameter(FILE* pfile, string& aktparamgraph)
|
||||
{
|
||||
std::vector<string> splitted;
|
||||
int suchex = 40;
|
||||
int suchey = 40;
|
||||
int alg_algo = 0; //default=0; 1 =HIGHACCURACY; 2= FAST; 3= OFF //add disable aligment algo |01.2023
|
||||
|
||||
|
||||
aktparamgraph = trim(aktparamgraph);
|
||||
|
||||
if (aktparamgraph.size() == 0)
|
||||
if (!this->GetNextParagraph(pfile, aktparamgraph))
|
||||
return false;
|
||||
|
||||
if (aktparamgraph.compare("[Alignment]") != 0) //Paragraph does not fit Alignment
|
||||
return false;
|
||||
|
||||
while (this->getNextLine(pfile, &aktparamgraph) && !this->isNewParagraph(aktparamgraph))
|
||||
{
|
||||
splitted = ZerlegeZeile(aktparamgraph);
|
||||
if ((toUpper(splitted[0]) == "FLIPIMAGESIZE") && (splitted.size() > 1))
|
||||
{
|
||||
if (toUpper(splitted[1]) == "TRUE")
|
||||
initialflip = true;
|
||||
}
|
||||
if ((toUpper(splitted[0]) == "INITIALMIRROR") && (splitted.size() > 1))
|
||||
{
|
||||
if (toUpper(splitted[1]) == "TRUE")
|
||||
initialmirror = true;
|
||||
}
|
||||
if (((toUpper(splitted[0]) == "INITALROTATE") || (toUpper(splitted[0]) == "INITIALROTATE")) && (splitted.size() > 1))
|
||||
{
|
||||
this->initalrotate = std::stod(splitted[1]);
|
||||
}
|
||||
if ((toUpper(splitted[0]) == "SEARCHFIELDX") && (splitted.size() > 1))
|
||||
{
|
||||
suchex = std::stod(splitted[1]);
|
||||
}
|
||||
if ((toUpper(splitted[0]) == "SEARCHFIELDY") && (splitted.size() > 1))
|
||||
{
|
||||
suchey = std::stod(splitted[1]);
|
||||
}
|
||||
if ((toUpper(splitted[0]) == "ANTIALIASING") && (splitted.size() > 1))
|
||||
{
|
||||
if (toUpper(splitted[1]) == "TRUE")
|
||||
use_antialiasing = true;
|
||||
}
|
||||
if ((splitted.size() == 3) && (anz_ref < 2))
|
||||
{
|
||||
References[anz_ref].image_file = FormatFileName("/sdcard" + splitted[0]);
|
||||
References[anz_ref].target_x = std::stod(splitted[1]);
|
||||
References[anz_ref].target_y = std::stod(splitted[2]);
|
||||
anz_ref++;
|
||||
}
|
||||
|
||||
if ((toUpper(splitted[0]) == "SAVEALLFILES") && (splitted.size() > 1))
|
||||
{
|
||||
if (toUpper(splitted[1]) == "TRUE")
|
||||
SaveAllFiles = true;
|
||||
}
|
||||
if ((toUpper(splitted[0]) == "ALIGNMENTALGO") && (splitted.size() > 1))
|
||||
{
|
||||
#ifdef DEBUG_DETAIL_ON
|
||||
std::string zw2 = "Alignment mode selected: " + splitted[1];
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, zw2);
|
||||
#endif
|
||||
if (toUpper(splitted[1]) == "HIGHACCURACY")
|
||||
alg_algo = 1;
|
||||
if (toUpper(splitted[1]) == "FAST")
|
||||
alg_algo = 2;
|
||||
if (toUpper(splitted[1]) == "OFF") //no align algo if set to 3 = off => no draw ref //add disable aligment algo |01.2023
|
||||
alg_algo = 3;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < anz_ref; ++i)
|
||||
{
|
||||
References[i].search_x = suchex;
|
||||
References[i].search_y = suchey;
|
||||
References[i].fastalg_SAD_criteria = SAD_criteria;
|
||||
References[i].alignment_algo = alg_algo;
|
||||
#ifdef DEBUG_DETAIL_ON
|
||||
std::string zw2 = "Alignment mode written: " + std::to_string(alg_algo);
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, zw2);
|
||||
#endif
|
||||
}
|
||||
|
||||
//no align algo if set to 3 = off => no draw ref //add disable aligment algo |01.2023
|
||||
if(References[0].alignment_algo != 3){
|
||||
LoadReferenceAlignmentValues();
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
|
||||
string ClassFlowAlignment::getHTMLSingleStep(string host)
|
||||
{
|
||||
string result;
|
||||
|
||||
result = "<p>Rotated Image: </p> <p><img src=\"" + host + "/img_tmp/rot.jpg\"></p>\n";
|
||||
result = result + "<p>Found Alignment: </p> <p><img src=\"" + host + "/img_tmp/rot_roi.jpg\"></p>\n";
|
||||
result = result + "<p>Aligned Image: </p> <p><img src=\"" + host + "/img_tmp/alg.jpg\"></p>\n";
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
bool ClassFlowAlignment::doFlow(string time)
|
||||
{
|
||||
#ifdef ALGROI_LOAD_FROM_MEM_AS_JPG
|
||||
if (!AlgROI) // AlgROI needs to be allocated before ImageTMP to avoid heap fragmentation
|
||||
{
|
||||
AlgROI = (ImageData*)heap_caps_realloc(AlgROI, sizeof(ImageData), MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM);
|
||||
if (!AlgROI)
|
||||
{
|
||||
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Can't allocate AlgROI");
|
||||
LogFile.WriteHeapInfo("ClassFlowAlignment-doFlow");
|
||||
}
|
||||
}
|
||||
|
||||
if (AlgROI)
|
||||
{
|
||||
ImageBasis->writeToMemoryAsJPG((ImageData*)AlgROI, 90);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!ImageTMP)
|
||||
{
|
||||
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 tmpImage -> Exec this round aborted!");
|
||||
LogFile.WriteHeapInfo("ClassFlowAlignment-doFlow");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
delete AlignAndCutImage;
|
||||
AlignAndCutImage = new CAlignAndCutImage("AlignAndCutImage", ImageBasis, ImageTMP);
|
||||
if (!AlignAndCutImage)
|
||||
{
|
||||
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Can't allocate AlignAndCutImage -> Exec this round aborted!");
|
||||
LogFile.WriteHeapInfo("ClassFlowAlignment-doFlow");
|
||||
return false;
|
||||
}
|
||||
|
||||
CRotateImage rt("rawImage", AlignAndCutImage, ImageTMP, initialflip);
|
||||
if (initialflip)
|
||||
{
|
||||
int _zw = ImageBasis->height;
|
||||
ImageBasis->height = ImageBasis->width;
|
||||
ImageBasis->width = _zw;
|
||||
|
||||
_zw = ImageTMP->width;
|
||||
ImageTMP->width = ImageTMP->height;
|
||||
ImageTMP->height = _zw;
|
||||
}
|
||||
|
||||
if (initialmirror)
|
||||
{
|
||||
ESP_LOGD(TAG, "do mirror");
|
||||
rt.Mirror();
|
||||
|
||||
if (SaveAllFiles)
|
||||
AlignAndCutImage->SaveToFile(FormatFileName("/sdcard/img_tmp/mirror.jpg"));
|
||||
}
|
||||
|
||||
if ((initalrotate != 0) || initialflip)
|
||||
{
|
||||
if (use_antialiasing)
|
||||
rt.RotateAntiAliasing(initalrotate);
|
||||
else
|
||||
rt.Rotate(initalrotate);
|
||||
|
||||
if (SaveAllFiles)
|
||||
AlignAndCutImage->SaveToFile(FormatFileName("/sdcard/img_tmp/rot.jpg"));
|
||||
}
|
||||
|
||||
|
||||
//no align algo if set to 3 = off //add disable aligment algo |01.2023
|
||||
if(References[0].alignment_algo != 3){
|
||||
if (!AlignAndCutImage->Align(&References[0], &References[1]))
|
||||
{
|
||||
SaveReferenceAlignmentValues();
|
||||
}
|
||||
}// no align
|
||||
|
||||
|
||||
#ifdef ALGROI_LOAD_FROM_MEM_AS_JPG
|
||||
if (AlgROI) {
|
||||
//no align algo if set to 3 = off => no draw ref //add disable aligment algo |01.2023
|
||||
if(References[0].alignment_algo != 3){
|
||||
DrawRef(ImageTMP);
|
||||
}
|
||||
flowctrl.DigitalDrawROI(ImageTMP);
|
||||
flowctrl.AnalogDrawROI(ImageTMP);
|
||||
ImageTMP->writeToMemoryAsJPG((ImageData*)AlgROI, 90);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (SaveAllFiles)
|
||||
{
|
||||
AlignAndCutImage->SaveToFile(FormatFileName("/sdcard/img_tmp/alg.jpg"));
|
||||
ImageTMP->SaveToFile(FormatFileName("/sdcard/img_tmp/alg_roi.jpg"));
|
||||
}
|
||||
|
||||
// must be deleted to have memory space for loading tflite
|
||||
delete ImageTMP;
|
||||
ImageTMP = NULL;
|
||||
|
||||
//no align algo if set to 3 = off => no draw ref //add disable aligment algo |01.2023
|
||||
if(References[0].alignment_algo != 3){
|
||||
LoadReferenceAlignmentValues();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void ClassFlowAlignment::SaveReferenceAlignmentValues()
|
||||
{
|
||||
FILE* pFile;
|
||||
std::string zwtime, zwvalue;
|
||||
|
||||
pFile = fopen(FileStoreRefAlignment.c_str(), "w");
|
||||
|
||||
if (strlen(zwtime.c_str()) == 0)
|
||||
{
|
||||
time_t rawtime;
|
||||
struct tm* timeinfo;
|
||||
char buffer[80];
|
||||
|
||||
time(&rawtime);
|
||||
timeinfo = localtime(&rawtime);
|
||||
|
||||
strftime(buffer, 80, "%Y-%m-%dT%H:%M:%S", timeinfo);
|
||||
zwtime = std::string(buffer);
|
||||
}
|
||||
|
||||
fputs(zwtime.c_str(), pFile);
|
||||
fputs("\n", pFile);
|
||||
|
||||
zwvalue = std::to_string(References[0].fastalg_x) + "\t" + std::to_string(References[0].fastalg_y);
|
||||
zwvalue = zwvalue + "\t" +std::to_string(References[0].fastalg_SAD)+ "\t" +std::to_string(References[0].fastalg_min);
|
||||
zwvalue = zwvalue + "\t" +std::to_string(References[0].fastalg_max)+ "\t" +std::to_string(References[0].fastalg_avg);
|
||||
fputs(zwvalue.c_str(), pFile);
|
||||
fputs("\n", pFile);
|
||||
|
||||
zwvalue = std::to_string(References[1].fastalg_x) + "\t" + std::to_string(References[1].fastalg_y);
|
||||
zwvalue = zwvalue + "\t" +std::to_string(References[1].fastalg_SAD)+ "\t" +std::to_string(References[1].fastalg_min);
|
||||
zwvalue = zwvalue + "\t" +std::to_string(References[1].fastalg_max)+ "\t" +std::to_string(References[1].fastalg_avg);
|
||||
fputs(zwvalue.c_str(), pFile);
|
||||
fputs("\n", pFile);
|
||||
|
||||
fclose(pFile);
|
||||
}
|
||||
|
||||
|
||||
bool ClassFlowAlignment::LoadReferenceAlignmentValues(void)
|
||||
{
|
||||
FILE* pFile;
|
||||
char zw[1024];
|
||||
string zwvalue;
|
||||
std::vector<string> splitted;
|
||||
|
||||
|
||||
pFile = fopen(FileStoreRefAlignment.c_str(), "r");
|
||||
if (pFile == NULL)
|
||||
return false;
|
||||
|
||||
fgets(zw, 1024, pFile);
|
||||
ESP_LOGD(TAG, "%s", zw);
|
||||
|
||||
fgets(zw, 1024, pFile);
|
||||
splitted = ZerlegeZeile(std::string(zw), " \t");
|
||||
if (splitted.size() < 6)
|
||||
{
|
||||
fclose(pFile);
|
||||
return false;
|
||||
}
|
||||
|
||||
References[0].fastalg_x = stoi(splitted[0]);
|
||||
References[0].fastalg_y = stoi(splitted[1]);
|
||||
References[0].fastalg_SAD = stof(splitted[2]);
|
||||
References[0].fastalg_min = stoi(splitted[3]);
|
||||
References[0].fastalg_max = stoi(splitted[4]);
|
||||
References[0].fastalg_avg = stof(splitted[5]);
|
||||
|
||||
fgets(zw, 1024, pFile);
|
||||
splitted = ZerlegeZeile(std::string(zw));
|
||||
if (splitted.size() < 6)
|
||||
{
|
||||
fclose(pFile);
|
||||
return false;
|
||||
}
|
||||
|
||||
References[1].fastalg_x = stoi(splitted[0]);
|
||||
References[1].fastalg_y = stoi(splitted[1]);
|
||||
References[1].fastalg_SAD = stof(splitted[2]);
|
||||
References[1].fastalg_min = stoi(splitted[3]);
|
||||
References[1].fastalg_max = stoi(splitted[4]);
|
||||
References[1].fastalg_avg = stof(splitted[5]);
|
||||
|
||||
fclose(pFile);
|
||||
|
||||
|
||||
/*#ifdef DEBUG_DETAIL_ON
|
||||
std::string _zw = "\tLoadReferences[0]\tx,y:\t" + std::to_string(References[0].fastalg_x) + "\t" + std::to_string(References[0].fastalg_x);
|
||||
_zw = _zw + "\tSAD, min, max, avg:\t" + std::to_string(References[0].fastalg_SAD) + "\t" + std::to_string(References[0].fastalg_min);
|
||||
_zw = _zw + "\t" + std::to_string(References[0].fastalg_max) + "\t" + std::to_string(References[0].fastalg_avg);
|
||||
LogFile.WriteToDedicatedFile("/sdcard/alignment.txt", _zw);
|
||||
_zw = "\tLoadReferences[1]\tx,y:\t" + std::to_string(References[1].fastalg_x) + "\t" + std::to_string(References[1].fastalg_x);
|
||||
_zw = _zw + "\tSAD, min, max, avg:\t" + std::to_string(References[1].fastalg_SAD) + "\t" + std::to_string(References[1].fastalg_min);
|
||||
_zw = _zw + "\t" + std::to_string(References[1].fastalg_max) + "\t" + std::to_string(References[1].fastalg_avg);
|
||||
LogFile.WriteToDedicatedFile("/sdcard/alignment.txt", _zw);
|
||||
#endif*/
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void ClassFlowAlignment::DrawRef(CImageBasis *_zw)
|
||||
{
|
||||
if (_zw->ImageOkay())
|
||||
{
|
||||
_zw->drawRect(References[0].target_x, References[0].target_y, References[0].width, References[0].height, 255, 0, 0, 2);
|
||||
_zw->drawRect(References[1].target_x, References[1].target_y, References[1].width, References[1].height, 255, 0, 0, 2);
|
||||
}
|
||||
}
|
||||
#include "ClassFlowAlignment.h"
|
||||
#include "ClassFlowTakeImage.h"
|
||||
#include "ClassFlow.h"
|
||||
#include "MainFlowControl.h"
|
||||
|
||||
#include "CRotateImage.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
#include "ClassLogFile.h"
|
||||
#include "psram.h"
|
||||
#include "../../include/defines.h"
|
||||
|
||||
static const char *TAG = "ALIGN";
|
||||
|
||||
// #define DEBUG_DETAIL_ON
|
||||
|
||||
void ClassFlowAlignment::SetInitialParameter(void)
|
||||
{
|
||||
initialrotate = 0;
|
||||
anz_ref = 0;
|
||||
use_antialiasing = false;
|
||||
initialflip = false;
|
||||
SaveAllFiles = false;
|
||||
namerawimage = "/sdcard/img_tmp/raw.jpg";
|
||||
FileStoreRefAlignment = "/sdcard/config/align.txt";
|
||||
ListFlowControll = NULL;
|
||||
AlignAndCutImage = NULL;
|
||||
ImageBasis = NULL;
|
||||
ImageTMP = NULL;
|
||||
#ifdef ALGROI_LOAD_FROM_MEM_AS_JPG
|
||||
AlgROI = (ImageData *)malloc_psram_heap(std::string(TAG) + "->AlgROI", sizeof(ImageData), MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM);
|
||||
#endif
|
||||
previousElement = NULL;
|
||||
disabled = false;
|
||||
SAD_criteria = 0.05;
|
||||
}
|
||||
|
||||
ClassFlowAlignment::ClassFlowAlignment(std::vector<ClassFlow *> *lfc)
|
||||
{
|
||||
SetInitialParameter();
|
||||
ListFlowControll = lfc;
|
||||
|
||||
for (int i = 0; i < ListFlowControll->size(); ++i) {
|
||||
if (((*ListFlowControll)[i])->name().compare("ClassFlowTakeImage") == 0) {
|
||||
ImageBasis = ((ClassFlowTakeImage *)(*ListFlowControll)[i])->rawImage;
|
||||
}
|
||||
}
|
||||
|
||||
// the function take pictures does not exist --> must be created first ONLY FOR TEST PURPOSES
|
||||
if (!ImageBasis) {
|
||||
ESP_LOGD(TAG, "CImageBasis had to be created");
|
||||
ImageBasis = new CImageBasis("ImageBasis", namerawimage);
|
||||
}
|
||||
}
|
||||
|
||||
bool ClassFlowAlignment::ReadParameter(FILE *pfile, string &aktparamgraph)
|
||||
{
|
||||
std::vector<string> splitted;
|
||||
int suchex = 40;
|
||||
int suchey = 40;
|
||||
int alg_algo = 0; // default=0; 1 =HIGHACCURACY; 2= FAST; 3= OFF //add disable aligment algo |01.2023
|
||||
|
||||
aktparamgraph = trim(aktparamgraph);
|
||||
|
||||
if (aktparamgraph.size() == 0)
|
||||
{
|
||||
if (!this->GetNextParagraph(pfile, aktparamgraph)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (aktparamgraph.compare("[Alignment]") != 0)
|
||||
{
|
||||
// Paragraph does not fit Alignment
|
||||
return false;
|
||||
}
|
||||
|
||||
while (this->getNextLine(pfile, &aktparamgraph) && !this->isNewParagraph(aktparamgraph))
|
||||
{
|
||||
splitted = ZerlegeZeile(aktparamgraph);
|
||||
|
||||
if ((toUpper(splitted[0]) == "FLIPIMAGESIZE") && (splitted.size() > 1)) {
|
||||
initialflip = alphanumericToBoolean(splitted[1]);
|
||||
}
|
||||
else if (((toUpper(splitted[0]) == "initialrotate") || (toUpper(splitted[0]) == "INITIALROTATE")) && (splitted.size() > 1)) {
|
||||
if (isStringNumeric(splitted[1])) {
|
||||
this->initialrotate = std::stod(splitted[1]);
|
||||
}
|
||||
}
|
||||
else if ((toUpper(splitted[0]) == "SEARCHFIELDX") && (splitted.size() > 1)) {
|
||||
if (isStringNumeric(splitted[1])) {
|
||||
suchex = std::stod(splitted[1]);
|
||||
}
|
||||
}
|
||||
else if ((toUpper(splitted[0]) == "SEARCHFIELDY") && (splitted.size() > 1)) {
|
||||
if (isStringNumeric(splitted[1])) {
|
||||
suchey = std::stod(splitted[1]);
|
||||
}
|
||||
}
|
||||
else if ((toUpper(splitted[0]) == "ANTIALIASING") && (splitted.size() > 1)) {
|
||||
use_antialiasing = alphanumericToBoolean(splitted[1]);
|
||||
}
|
||||
else if ((splitted.size() == 3) && (anz_ref < 2)) {
|
||||
if ((isStringNumeric(splitted[1])) && (isStringNumeric(splitted[2])))
|
||||
{
|
||||
References[anz_ref].image_file = FormatFileName("/sdcard" + splitted[0]);
|
||||
References[anz_ref].target_x = std::stod(splitted[1]);
|
||||
References[anz_ref].target_y = std::stod(splitted[2]);
|
||||
anz_ref++;
|
||||
}
|
||||
else
|
||||
{
|
||||
References[anz_ref].image_file = FormatFileName("/sdcard" + splitted[0]);
|
||||
References[anz_ref].target_x = 10;
|
||||
References[anz_ref].target_y = 10;
|
||||
anz_ref++;
|
||||
}
|
||||
}
|
||||
|
||||
else if ((toUpper(splitted[0]) == "SAVEALLFILES") && (splitted.size() > 1)) {
|
||||
SaveAllFiles = alphanumericToBoolean(splitted[1]);
|
||||
}
|
||||
else if ((toUpper(splitted[0]) == "ALIGNMENTALGO") && (splitted.size() > 1)) {
|
||||
#ifdef DEBUG_DETAIL_ON
|
||||
std::string zw2 = "Alignment mode selected: " + splitted[1];
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, zw2);
|
||||
#endif
|
||||
if (toUpper(splitted[1]) == "HIGHACCURACY") {
|
||||
alg_algo = 1;
|
||||
}
|
||||
if (toUpper(splitted[1]) == "FAST") {
|
||||
alg_algo = 2;
|
||||
}
|
||||
if (toUpper(splitted[1]) == "OFF") {
|
||||
// no align algo if set to 3 = off => no draw ref //add disable aligment algo |01.2023
|
||||
alg_algo = 3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = 0; i < anz_ref; ++i) {
|
||||
References[i].search_x = suchex;
|
||||
References[i].search_y = suchey;
|
||||
References[i].fastalg_SAD_criteria = SAD_criteria;
|
||||
References[i].alignment_algo = alg_algo;
|
||||
#ifdef DEBUG_DETAIL_ON
|
||||
std::string zw2 = "Alignment mode written: " + std::to_string(alg_algo);
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, zw2);
|
||||
#endif
|
||||
}
|
||||
|
||||
// no align algo if set to 3 = off => no draw ref //add disable aligment algo |01.2023
|
||||
if (References[0].alignment_algo != 3) {
|
||||
return LoadReferenceAlignmentValues();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
string ClassFlowAlignment::getHTMLSingleStep(string host)
|
||||
{
|
||||
string result;
|
||||
|
||||
result = "<p>Rotated Image: </p> <p><img src=\"" + host + "/img_tmp/rot.jpg\"></p>\n";
|
||||
result = result + "<p>Found Alignment: </p> <p><img src=\"" + host + "/img_tmp/rot_roi.jpg\"></p>\n";
|
||||
result = result + "<p>Aligned Image: </p> <p><img src=\"" + host + "/img_tmp/alg.jpg\"></p>\n";
|
||||
return result;
|
||||
}
|
||||
|
||||
bool ClassFlowAlignment::doFlow(string time)
|
||||
{
|
||||
#ifdef ALGROI_LOAD_FROM_MEM_AS_JPG
|
||||
// AlgROI needs to be allocated before ImageTMP to avoid heap fragmentation
|
||||
if (!AlgROI) {
|
||||
AlgROI = (ImageData *)heap_caps_realloc(AlgROI, sizeof(ImageData), MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM);
|
||||
|
||||
if (!AlgROI) {
|
||||
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Can't allocate AlgROI");
|
||||
LogFile.WriteHeapInfo("ClassFlowAlignment-doFlow");
|
||||
}
|
||||
}
|
||||
|
||||
if (AlgROI) {
|
||||
ImageBasis->writeToMemoryAsJPG((ImageData *)AlgROI, 90);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!ImageTMP) {
|
||||
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 tmpImage -> Exec this round aborted!");
|
||||
LogFile.WriteHeapInfo("ClassFlowAlignment-doFlow");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
delete AlignAndCutImage;
|
||||
AlignAndCutImage = new CAlignAndCutImage("AlignAndCutImage", ImageBasis, ImageTMP);
|
||||
|
||||
if (!AlignAndCutImage) {
|
||||
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Can't allocate AlignAndCutImage -> Exec this round aborted!");
|
||||
LogFile.WriteHeapInfo("ClassFlowAlignment-doFlow");
|
||||
return false;
|
||||
}
|
||||
|
||||
CRotateImage rt("rawImage", AlignAndCutImage, ImageTMP, initialflip);
|
||||
|
||||
if (initialflip) {
|
||||
int _zw = ImageBasis->height;
|
||||
ImageBasis->height = ImageBasis->width;
|
||||
ImageBasis->width = _zw;
|
||||
|
||||
_zw = ImageTMP->width;
|
||||
ImageTMP->width = ImageTMP->height;
|
||||
ImageTMP->height = _zw;
|
||||
}
|
||||
|
||||
if ((initialrotate != 0) || initialflip) {
|
||||
if (use_antialiasing) {
|
||||
rt.RotateAntiAliasing(initialrotate);
|
||||
}
|
||||
else {
|
||||
rt.Rotate(initialrotate);
|
||||
}
|
||||
|
||||
if (SaveAllFiles) {
|
||||
AlignAndCutImage->SaveToFile(FormatFileName("/sdcard/img_tmp/rot.jpg"));
|
||||
}
|
||||
}
|
||||
|
||||
// no align algo if set to 3 = off //add disable aligment algo |01.2023
|
||||
if (References[0].alignment_algo != 3) {
|
||||
if (!AlignAndCutImage->Align(&References[0], &References[1])) {
|
||||
SaveReferenceAlignmentValues();
|
||||
}
|
||||
} // no align
|
||||
|
||||
#ifdef ALGROI_LOAD_FROM_MEM_AS_JPG
|
||||
if (AlgROI) {
|
||||
// no align algo if set to 3 = off => no draw ref //add disable aligment algo |01.2023
|
||||
if (References[0].alignment_algo != 3) {
|
||||
DrawRef(ImageTMP);
|
||||
}
|
||||
|
||||
flowctrl.DigitDrawROI(ImageTMP);
|
||||
flowctrl.AnalogDrawROI(ImageTMP);
|
||||
ImageTMP->writeToMemoryAsJPG((ImageData *)AlgROI, 90);
|
||||
}
|
||||
#endif
|
||||
|
||||
if (SaveAllFiles) {
|
||||
AlignAndCutImage->SaveToFile(FormatFileName("/sdcard/img_tmp/alg.jpg"));
|
||||
ImageTMP->SaveToFile(FormatFileName("/sdcard/img_tmp/alg_roi.jpg"));
|
||||
}
|
||||
|
||||
// must be deleted to have memory space for loading tflite
|
||||
delete ImageTMP;
|
||||
ImageTMP = NULL;
|
||||
|
||||
// no align algo if set to 3 = off => no draw ref //add disable aligment algo |01.2023
|
||||
if (References[0].alignment_algo != 3) {
|
||||
return LoadReferenceAlignmentValues();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ClassFlowAlignment::SaveReferenceAlignmentValues()
|
||||
{
|
||||
FILE *pFile;
|
||||
std::string zwtime, zwvalue;
|
||||
|
||||
pFile = fopen(FileStoreRefAlignment.c_str(), "w");
|
||||
|
||||
if (strlen(zwtime.c_str()) == 0) {
|
||||
time_t rawtime;
|
||||
struct tm *timeinfo;
|
||||
char buffer[80];
|
||||
|
||||
time(&rawtime);
|
||||
timeinfo = localtime(&rawtime);
|
||||
|
||||
strftime(buffer, 80, "%Y-%m-%dT%H:%M:%S", timeinfo);
|
||||
zwtime = std::string(buffer);
|
||||
}
|
||||
|
||||
fputs(zwtime.c_str(), pFile);
|
||||
fputs("\n", pFile);
|
||||
|
||||
zwvalue = std::to_string(References[0].fastalg_x) + "\t" + std::to_string(References[0].fastalg_y);
|
||||
zwvalue = zwvalue + "\t" + std::to_string(References[0].fastalg_SAD) + "\t" + std::to_string(References[0].fastalg_min);
|
||||
zwvalue = zwvalue + "\t" + std::to_string(References[0].fastalg_max) + "\t" + std::to_string(References[0].fastalg_avg);
|
||||
fputs(zwvalue.c_str(), pFile);
|
||||
fputs("\n", pFile);
|
||||
|
||||
zwvalue = std::to_string(References[1].fastalg_x) + "\t" + std::to_string(References[1].fastalg_y);
|
||||
zwvalue = zwvalue + "\t" + std::to_string(References[1].fastalg_SAD) + "\t" + std::to_string(References[1].fastalg_min);
|
||||
zwvalue = zwvalue + "\t" + std::to_string(References[1].fastalg_max) + "\t" + std::to_string(References[1].fastalg_avg);
|
||||
fputs(zwvalue.c_str(), pFile);
|
||||
fputs("\n", pFile);
|
||||
|
||||
fclose(pFile);
|
||||
}
|
||||
|
||||
bool ClassFlowAlignment::LoadReferenceAlignmentValues(void)
|
||||
{
|
||||
FILE *pFile;
|
||||
char zw[1024];
|
||||
string zwvalue;
|
||||
std::vector<string> splitted;
|
||||
|
||||
pFile = fopen(FileStoreRefAlignment.c_str(), "r");
|
||||
|
||||
if (pFile == NULL) {
|
||||
return false;
|
||||
}
|
||||
|
||||
fgets(zw, 1024, pFile);
|
||||
ESP_LOGD(TAG, "%s", zw);
|
||||
|
||||
fgets(zw, 1024, pFile);
|
||||
splitted = ZerlegeZeile(std::string(zw), " \t");
|
||||
|
||||
if (splitted.size() < 6) {
|
||||
fclose(pFile);
|
||||
return false;
|
||||
}
|
||||
|
||||
References[0].fastalg_x = stoi(splitted[0]);
|
||||
References[0].fastalg_y = stoi(splitted[1]);
|
||||
References[0].fastalg_SAD = stof(splitted[2]);
|
||||
References[0].fastalg_min = stoi(splitted[3]);
|
||||
References[0].fastalg_max = stoi(splitted[4]);
|
||||
References[0].fastalg_avg = stof(splitted[5]);
|
||||
|
||||
fgets(zw, 1024, pFile);
|
||||
splitted = ZerlegeZeile(std::string(zw));
|
||||
|
||||
if (splitted.size() < 6) {
|
||||
fclose(pFile);
|
||||
return false;
|
||||
}
|
||||
|
||||
References[1].fastalg_x = stoi(splitted[0]);
|
||||
References[1].fastalg_y = stoi(splitted[1]);
|
||||
References[1].fastalg_SAD = stof(splitted[2]);
|
||||
References[1].fastalg_min = stoi(splitted[3]);
|
||||
References[1].fastalg_max = stoi(splitted[4]);
|
||||
References[1].fastalg_avg = stof(splitted[5]);
|
||||
|
||||
fclose(pFile);
|
||||
|
||||
/*#ifdef DEBUG_DETAIL_ON
|
||||
std::string _zw = "\tLoadReferences[0]\tx,y:\t" + std::to_string(References[0].fastalg_x) + "\t" + std::to_string(References[0].fastalg_x);
|
||||
_zw = _zw + "\tSAD, min, max, avg:\t" + std::to_string(References[0].fastalg_SAD) + "\t" + std::to_string(References[0].fastalg_min);
|
||||
_zw = _zw + "\t" + std::to_string(References[0].fastalg_max) + "\t" + std::to_string(References[0].fastalg_avg);
|
||||
LogFile.WriteToDedicatedFile("/sdcard/alignment.txt", _zw);
|
||||
_zw = "\tLoadReferences[1]\tx,y:\t" + std::to_string(References[1].fastalg_x) + "\t" + std::to_string(References[1].fastalg_x);
|
||||
_zw = _zw + "\tSAD, min, max, avg:\t" + std::to_string(References[1].fastalg_SAD) + "\t" + std::to_string(References[1].fastalg_min);
|
||||
_zw = _zw + "\t" + std::to_string(References[1].fastalg_max) + "\t" + std::to_string(References[1].fastalg_avg);
|
||||
LogFile.WriteToDedicatedFile("/sdcard/alignment.txt", _zw);
|
||||
#endif*/
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void ClassFlowAlignment::DrawRef(CImageBasis *_zw)
|
||||
{
|
||||
if (_zw->ImageOkay()) {
|
||||
_zw->drawRect(References[0].target_x, References[0].target_y, References[0].width, References[0].height, 255, 0, 0, 2);
|
||||
_zw->drawRect(References[1].target_x, References[1].target_y, References[1].width, References[1].height, 255, 0, 0, 2);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,54 +1,51 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef CLASSFLOWALIGNMENT_H
|
||||
#define CLASSFLOWALIGNMENT_H
|
||||
|
||||
#include "ClassFlow.h"
|
||||
#include "Helper.h"
|
||||
#include "CAlignAndCutImage.h"
|
||||
#include "CFindTemplate.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
using namespace std;
|
||||
|
||||
class ClassFlowAlignment :
|
||||
public ClassFlow
|
||||
{
|
||||
protected:
|
||||
float initalrotate;
|
||||
bool initialmirror;
|
||||
bool initialflip;
|
||||
bool use_antialiasing;
|
||||
RefInfo References[2];
|
||||
int anz_ref;
|
||||
string namerawimage;
|
||||
bool SaveAllFiles;
|
||||
CAlignAndCutImage *AlignAndCutImage;
|
||||
std::string FileStoreRefAlignment;
|
||||
float SAD_criteria;
|
||||
|
||||
void SetInitialParameter(void);
|
||||
bool LoadReferenceAlignmentValues(void);
|
||||
void SaveReferenceAlignmentValues();
|
||||
|
||||
public:
|
||||
CImageBasis *ImageBasis, *ImageTMP;
|
||||
#ifdef ALGROI_LOAD_FROM_MEM_AS_JPG
|
||||
ImageData *AlgROI;
|
||||
#endif
|
||||
|
||||
ClassFlowAlignment(std::vector<ClassFlow*>* lfc);
|
||||
|
||||
CAlignAndCutImage* GetAlignAndCutImage(){return AlignAndCutImage;};
|
||||
|
||||
void DrawRef(CImageBasis *_zw);
|
||||
|
||||
bool ReadParameter(FILE* pfile, string& aktparamgraph);
|
||||
bool doFlow(string time);
|
||||
string getHTMLSingleStep(string host);
|
||||
string name(){return "ClassFlowAlignment";};
|
||||
};
|
||||
|
||||
|
||||
#endif //CLASSFLOWALIGNMENT_H
|
||||
#pragma once
|
||||
|
||||
#ifndef CLASSFLOWALIGNMENT_H
|
||||
#define CLASSFLOWALIGNMENT_H
|
||||
|
||||
#include "ClassFlow.h"
|
||||
#include "Helper.h"
|
||||
#include "CAlignAndCutImage.h"
|
||||
#include "CFindTemplate.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
using namespace std;
|
||||
|
||||
class ClassFlowAlignment : public ClassFlow
|
||||
{
|
||||
protected:
|
||||
float initialrotate;
|
||||
bool initialflip;
|
||||
bool use_antialiasing;
|
||||
RefInfo References[2];
|
||||
int anz_ref;
|
||||
string namerawimage;
|
||||
bool SaveAllFiles;
|
||||
CAlignAndCutImage *AlignAndCutImage;
|
||||
std::string FileStoreRefAlignment;
|
||||
float SAD_criteria;
|
||||
|
||||
void SetInitialParameter(void);
|
||||
bool LoadReferenceAlignmentValues(void);
|
||||
void SaveReferenceAlignmentValues();
|
||||
|
||||
public:
|
||||
CImageBasis *ImageBasis, *ImageTMP;
|
||||
#ifdef ALGROI_LOAD_FROM_MEM_AS_JPG
|
||||
ImageData *AlgROI;
|
||||
#endif
|
||||
|
||||
ClassFlowAlignment(std::vector<ClassFlow *> *lfc);
|
||||
|
||||
CAlignAndCutImage *GetAlignAndCutImage() { return AlignAndCutImage; };
|
||||
|
||||
void DrawRef(CImageBasis *_zw);
|
||||
|
||||
bool ReadParameter(FILE *pfile, string &aktparamgraph);
|
||||
bool doFlow(string time);
|
||||
string getHTMLSingleStep(string host);
|
||||
string name() { return "ClassFlowAlignment"; };
|
||||
};
|
||||
|
||||
#endif // CLASSFLOWALIGNMENT_H
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -11,10 +11,10 @@ enum t_CNNType {
|
||||
AutoDetect,
|
||||
Analogue,
|
||||
Analogue100,
|
||||
Digital,
|
||||
DigitalHyprid10,
|
||||
Digit,
|
||||
DigitHyprid10,
|
||||
DoubleHyprid10,
|
||||
Digital100,
|
||||
Digit100,
|
||||
None
|
||||
};
|
||||
|
||||
@@ -26,15 +26,6 @@ protected:
|
||||
std::vector<general*> GENERAL;
|
||||
float CNNGoodThreshold;
|
||||
|
||||
//moved to define.h
|
||||
//float Analog_error = 3.0;
|
||||
//float AnalogToDigtalFehler = 0.8;
|
||||
//float Digital_Uncertainty = 0.2;
|
||||
//int DigitalBand = 3;
|
||||
//float Digital_Transition_Range_Predecessor = 2;
|
||||
//float Digital_Transition_Area_Predecessor = 0.7; // 9.3 - 0.7
|
||||
//float Digital_Transition_Area_Forward = 9.7; // Pre-run zero crossing only happens from approx. 9.7 onwards
|
||||
|
||||
string cnnmodelfile;
|
||||
int modelxsize, modelysize, modelchannel;
|
||||
bool isLogImageSelect;
|
||||
@@ -44,8 +35,8 @@ protected:
|
||||
bool SaveAllFiles;
|
||||
|
||||
int PointerEvalAnalogNew(float zahl, int numeral_preceder);
|
||||
int PointerEvalAnalogToDigitNew(float zahl, float numeral_preceder, int eval_predecessors, float analogDigitalTransitionStart);
|
||||
int PointerEvalHybridNew(float zahl, float number_of_predecessors, int eval_predecessors, bool Analog_Predecessors = false, float analogDigitalTransitionStart=9.2);
|
||||
int PointerEvalAnalogToDigitNew(float zahl, float numeral_preceder, int eval_predecessors, float AnalogToDigitTransitionStart);
|
||||
int PointerEvalHybridNew(float zahl, float number_of_predecessors, int eval_predecessors, bool Analog_Predecessors = false, float AnalogToDigitTransitionStart=9.2);
|
||||
|
||||
|
||||
|
||||
@@ -61,7 +52,7 @@ public:
|
||||
bool doFlow(string time);
|
||||
|
||||
string getHTMLSingleStep(string host);
|
||||
string getReadout(int _analog, bool _extendedResolution = false, int prev = -1, float _before_narrow_Analog = -1, float analogDigitalTransitionStart=9.2);
|
||||
string getReadout(int _analog, bool _extendedResolution = false, int prev = -1, float _before_narrow_Analog = -1, float AnalogToDigitTransitionStart=9.2);
|
||||
|
||||
string getReadoutRawString(int _analog);
|
||||
|
||||
|
||||
@@ -32,7 +32,6 @@ static const char* TAG = "FLOWCTRL";
|
||||
|
||||
//#define DEBUG_DETAIL_ON
|
||||
|
||||
|
||||
std::string ClassFlowControll::doSingleStep(std::string _stepname, std::string _host){
|
||||
std::string _classname = "";
|
||||
std::string result = "";
|
||||
@@ -65,11 +64,19 @@ std::string ClassFlowControll::doSingleStep(std::string _stepname, std::string _
|
||||
_classname = "ClassFlowInfluxDBv2";
|
||||
}
|
||||
#endif //ENABLE_INFLUXDB
|
||||
#ifdef ENABLE_WEBHOOK
|
||||
if ((_stepname.compare("[Webhook]") == 0) || (_stepname.compare(";[Webhook]") == 0)){
|
||||
_classname = "ClassFlowWebhook";
|
||||
}
|
||||
#endif //ENABLE_WEBHOOK
|
||||
|
||||
for (int i = 0; i < FlowControll.size(); ++i)
|
||||
if (FlowControll[i]->name().compare(_classname) == 0){
|
||||
if (!(FlowControll[i]->name().compare("ClassFlowTakeImage") == 0)) // if it is a TakeImage, the image does not need to be included, this happens automatically with the html query.
|
||||
if (!(FlowControll[i]->name().compare("ClassFlowTakeImage") == 0)) {
|
||||
// if it is a TakeImage, the image does not need to be included, this happens automatically with the html query.
|
||||
FlowControll[i]->doFlow("");
|
||||
}
|
||||
|
||||
result = FlowControll[i]->getHTMLSingleStep(_host);
|
||||
}
|
||||
|
||||
@@ -78,37 +85,51 @@ std::string ClassFlowControll::doSingleStep(std::string _stepname, std::string _
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
std::string ClassFlowControll::TranslateAktstatus(std::string _input)
|
||||
{
|
||||
if (_input.compare("ClassFlowTakeImage") == 0)
|
||||
if (_input.compare("ClassFlowTakeImage") == 0) {
|
||||
return ("Take Image");
|
||||
if (_input.compare("ClassFlowAlignment") == 0)
|
||||
}
|
||||
|
||||
if (_input.compare("ClassFlowAlignment") == 0) {
|
||||
return ("Aligning");
|
||||
if (_input.compare("ClassFlowCNNGeneral") == 0)
|
||||
return ("Digitalization of ROIs");
|
||||
}
|
||||
|
||||
if (_input.compare("ClassFlowCNNGeneral") == 0) {
|
||||
return ("Digitization of ROIs");
|
||||
}
|
||||
|
||||
#ifdef ENABLE_MQTT
|
||||
if (_input.compare("ClassFlowMQTT") == 0)
|
||||
if (_input.compare("ClassFlowMQTT") == 0) {
|
||||
return ("Sending MQTT");
|
||||
}
|
||||
#endif //ENABLE_MQTT
|
||||
|
||||
#ifdef ENABLE_INFLUXDB
|
||||
if (_input.compare("ClassFlowInfluxDB") == 0)
|
||||
if (_input.compare("ClassFlowInfluxDB") == 0) {
|
||||
return ("Sending InfluxDB");
|
||||
if (_input.compare("ClassFlowInfluxDBv2") == 0)
|
||||
}
|
||||
|
||||
if (_input.compare("ClassFlowInfluxDBv2") == 0) {
|
||||
return ("Sending InfluxDBv2");
|
||||
}
|
||||
#endif //ENABLE_INFLUXDB
|
||||
if (_input.compare("ClassFlowPostProcessing") == 0)
|
||||
#ifdef ENABLE_WEBHOOK
|
||||
if (_input.compare("ClassFlowWebhook") == 0) {
|
||||
return ("Sending Webhook");
|
||||
}
|
||||
#endif //ENABLE_WEBHOOK
|
||||
if (_input.compare("ClassFlowPostProcessing") == 0) {
|
||||
return ("Post-Processing");
|
||||
}
|
||||
|
||||
return "Unkown Status";
|
||||
}
|
||||
|
||||
|
||||
std::vector<HTMLInfo*> ClassFlowControll::GetAllDigital()
|
||||
std::vector<HTMLInfo*> ClassFlowControll::GetAllDigit()
|
||||
{
|
||||
if (flowdigit)
|
||||
{
|
||||
ESP_LOGD(TAG, "ClassFlowControll::GetAllDigital - flowdigit != NULL");
|
||||
if (flowdigit) {
|
||||
ESP_LOGD(TAG, "ClassFlowControll::GetAllDigit - flowdigit != NULL");
|
||||
return flowdigit->GetHTMLInfo();
|
||||
}
|
||||
|
||||
@@ -116,65 +137,63 @@ std::vector<HTMLInfo*> ClassFlowControll::GetAllDigital()
|
||||
return empty;
|
||||
}
|
||||
|
||||
|
||||
std::vector<HTMLInfo*> ClassFlowControll::GetAllAnalog()
|
||||
{
|
||||
if (flowanalog)
|
||||
if (flowanalog) {
|
||||
return flowanalog->GetHTMLInfo();
|
||||
}
|
||||
|
||||
std::vector<HTMLInfo*> empty;
|
||||
return empty;
|
||||
}
|
||||
|
||||
|
||||
t_CNNType ClassFlowControll::GetTypeDigital()
|
||||
t_CNNType ClassFlowControll::GetTypeDigit()
|
||||
{
|
||||
if (flowdigit)
|
||||
if (flowdigit) {
|
||||
return flowdigit->getCNNType();
|
||||
}
|
||||
|
||||
return t_CNNType::None;
|
||||
}
|
||||
|
||||
|
||||
t_CNNType ClassFlowControll::GetTypeAnalog()
|
||||
{
|
||||
if (flowanalog)
|
||||
if (flowanalog) {
|
||||
return flowanalog->getCNNType();
|
||||
}
|
||||
|
||||
return t_CNNType::None;
|
||||
}
|
||||
|
||||
|
||||
#ifdef ALGROI_LOAD_FROM_MEM_AS_JPG
|
||||
void ClassFlowControll::DigitalDrawROI(CImageBasis *_zw)
|
||||
void ClassFlowControll::DigitDrawROI(CImageBasis *_zw)
|
||||
{
|
||||
if (flowdigit)
|
||||
if (flowdigit) {
|
||||
flowdigit->DrawROI(_zw);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void ClassFlowControll::AnalogDrawROI(CImageBasis *_zw)
|
||||
{
|
||||
if (flowanalog)
|
||||
if (flowanalog) {
|
||||
flowanalog->DrawROI(_zw);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef ENABLE_MQTT
|
||||
bool ClassFlowControll::StartMQTTService()
|
||||
{
|
||||
/* Start the MQTT service */
|
||||
for (int i = 0; i < FlowControll.size(); ++i) {
|
||||
if (FlowControll[i]->name().compare("ClassFlowMQTT") == 0) {
|
||||
return ((ClassFlowMQTT*) (FlowControll[i]))->Start(AutoInterval);
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < FlowControll.size(); ++i) {
|
||||
if (FlowControll[i]->name().compare("ClassFlowMQTT") == 0) {
|
||||
return ((ClassFlowMQTT*) (FlowControll[i]))->Start(AutoInterval);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
#endif //ENABLE_MQTT
|
||||
|
||||
|
||||
void ClassFlowControll::SetInitialParameter(void)
|
||||
{
|
||||
AutoStart = false;
|
||||
@@ -189,7 +208,6 @@ void ClassFlowControll::SetInitialParameter(void)
|
||||
aktstatusWithTime = aktstatus;
|
||||
}
|
||||
|
||||
|
||||
bool ClassFlowControll::getIsAutoStart(void)
|
||||
{
|
||||
return AutoStart;
|
||||
@@ -201,69 +219,81 @@ void ClassFlowControll::setAutoStartInterval(long &_interval)
|
||||
_interval = AutoInterval * 60 * 1000; // AutoInterval: minutes -> ms
|
||||
}
|
||||
|
||||
|
||||
ClassFlow* ClassFlowControll::CreateClassFlow(std::string _type)
|
||||
{
|
||||
ClassFlow* cfc = NULL;
|
||||
|
||||
_type = trim(_type);
|
||||
|
||||
if (toUpper(_type).compare("[TAKEIMAGE]") == 0)
|
||||
{
|
||||
if (toUpper(_type).compare("[TAKEIMAGE]") == 0) {
|
||||
cfc = new ClassFlowTakeImage(&FlowControll);
|
||||
flowtakeimage = (ClassFlowTakeImage*) cfc;
|
||||
}
|
||||
if (toUpper(_type).compare("[ALIGNMENT]") == 0)
|
||||
{
|
||||
|
||||
if (toUpper(_type).compare("[ALIGNMENT]") == 0) {
|
||||
cfc = new ClassFlowAlignment(&FlowControll);
|
||||
flowalignment = (ClassFlowAlignment*) cfc;
|
||||
}
|
||||
if (toUpper(_type).compare("[ANALOG]") == 0)
|
||||
{
|
||||
|
||||
if (toUpper(_type).compare("[ANALOG]") == 0) {
|
||||
cfc = new ClassFlowCNNGeneral(flowalignment);
|
||||
flowanalog = (ClassFlowCNNGeneral*) cfc;
|
||||
}
|
||||
if (toUpper(_type).compare(0, 7, "[DIGITS") == 0)
|
||||
{
|
||||
|
||||
if (toUpper(_type).compare(0, 7, "[DIGITS") == 0) {
|
||||
cfc = new ClassFlowCNNGeneral(flowalignment);
|
||||
flowdigit = (ClassFlowCNNGeneral*) cfc;
|
||||
}
|
||||
|
||||
#ifdef ENABLE_MQTT
|
||||
if (toUpper(_type).compare("[MQTT]") == 0)
|
||||
if (toUpper(_type).compare("[MQTT]") == 0) {
|
||||
cfc = new ClassFlowMQTT(&FlowControll);
|
||||
}
|
||||
#endif //ENABLE_MQTT
|
||||
|
||||
#ifdef ENABLE_INFLUXDB
|
||||
if (toUpper(_type).compare("[INFLUXDB]") == 0)
|
||||
if (toUpper(_type).compare("[INFLUXDB]") == 0) {
|
||||
cfc = new ClassFlowInfluxDB(&FlowControll);
|
||||
if (toUpper(_type).compare("[INFLUXDBV2]") == 0)
|
||||
cfc = new ClassFlowInfluxDBv2(&FlowControll);
|
||||
#endif //ENABLE_INFLUXDB
|
||||
}
|
||||
|
||||
if (toUpper(_type).compare("[POSTPROCESSING]") == 0)
|
||||
{
|
||||
if (toUpper(_type).compare("[INFLUXDBV2]") == 0) {
|
||||
cfc = new ClassFlowInfluxDBv2(&FlowControll);
|
||||
}
|
||||
#endif //ENABLE_INFLUXDB
|
||||
#ifdef ENABLE_WEBHOOK
|
||||
if (toUpper(_type).compare("[WEBHOOK]") == 0)
|
||||
cfc = new ClassFlowWebhook(&FlowControll);
|
||||
#endif //ENABLE_WEBHOOK
|
||||
|
||||
if (toUpper(_type).compare("[POSTPROCESSING]") == 0) {
|
||||
cfc = new ClassFlowPostProcessing(&FlowControll, flowanalog, flowdigit);
|
||||
flowpostprocessing = (ClassFlowPostProcessing*) cfc;
|
||||
}
|
||||
|
||||
if (cfc) // Attached only if it is not [AutoTimer], because this is for FlowControll
|
||||
if (cfc) {
|
||||
// Attached only if it is not [AutoTimer], because this is for FlowControll
|
||||
FlowControll.push_back(cfc);
|
||||
}
|
||||
|
||||
if (toUpper(_type).compare("[AUTOTIMER]") == 0)
|
||||
cfc = this;
|
||||
if (toUpper(_type).compare("[AUTOTIMER]") == 0) {
|
||||
cfc = this;
|
||||
}
|
||||
|
||||
if (toUpper(_type).compare("[DATALOGGING]") == 0)
|
||||
cfc = this;
|
||||
if (toUpper(_type).compare("[DATALOGGING]") == 0) {
|
||||
cfc = this;
|
||||
}
|
||||
|
||||
if (toUpper(_type).compare("[DEBUG]") == 0)
|
||||
cfc = this;
|
||||
if (toUpper(_type).compare("[DEBUG]") == 0) {
|
||||
cfc = this;
|
||||
}
|
||||
|
||||
if (toUpper(_type).compare("[SYSTEM]") == 0)
|
||||
cfc = this;
|
||||
if (toUpper(_type).compare("[SYSTEM]") == 0) {
|
||||
cfc = this;
|
||||
}
|
||||
|
||||
return cfc;
|
||||
}
|
||||
|
||||
|
||||
void ClassFlowControll::InitFlow(std::string config)
|
||||
{
|
||||
aktstatus = "Initialization";
|
||||
@@ -284,62 +314,55 @@ void ClassFlowControll::InitFlow(std::string config)
|
||||
line = "";
|
||||
|
||||
char zw[1024];
|
||||
if (pFile != NULL)
|
||||
{
|
||||
|
||||
if (pFile != NULL) {
|
||||
fgets(zw, 1024, pFile);
|
||||
ESP_LOGD(TAG, "%s", zw);
|
||||
line = std::string(zw);
|
||||
}
|
||||
|
||||
while ((line.size() > 0) && !(feof(pFile)))
|
||||
{
|
||||
while ((line.size() > 0) && !(feof(pFile))) {
|
||||
cfc = CreateClassFlow(line);
|
||||
// printf("Name: %s\n", cfc->name().c_str());
|
||||
if (cfc)
|
||||
{
|
||||
ESP_LOGD(TAG, "Start ReadParameter (%s)", line.c_str());
|
||||
// printf("Name: %s\n", cfc->name().c_str());
|
||||
|
||||
if (cfc) {
|
||||
ESP_LOGE(TAG, "Start ReadParameter (%s)", line.c_str());
|
||||
cfc->ReadParameter(pFile, line);
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
line = "";
|
||||
if (fgets(zw, 1024, pFile) && !feof(pFile))
|
||||
{
|
||||
ESP_LOGD(TAG, "Read: %s", zw);
|
||||
line = std::string(zw);
|
||||
}
|
||||
|
||||
if (fgets(zw, 1024, pFile) && !feof(pFile)) {
|
||||
ESP_LOGD(TAG, "Read: %s", zw);
|
||||
line = std::string(zw);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fclose(pFile);
|
||||
}
|
||||
|
||||
|
||||
std::string* ClassFlowControll::getActStatusWithTime()
|
||||
{
|
||||
return &aktstatusWithTime;
|
||||
}
|
||||
|
||||
|
||||
std::string* ClassFlowControll::getActStatus()
|
||||
{
|
||||
return &aktstatus;
|
||||
}
|
||||
|
||||
|
||||
void ClassFlowControll::setActStatus(std::string _aktstatus)
|
||||
{
|
||||
aktstatus = _aktstatus;
|
||||
aktstatusWithTime = aktstatus;
|
||||
}
|
||||
|
||||
|
||||
void ClassFlowControll::doFlowTakeImageOnly(string time)
|
||||
{
|
||||
std::string zw_time;
|
||||
|
||||
for (int i = 0; i < FlowControll.size(); ++i)
|
||||
{
|
||||
for (int i = 0; i < FlowControll.size(); ++i) {
|
||||
if (FlowControll[i]->name() == "ClassFlowTakeImage") {
|
||||
zw_time = getCurrentTimeString("%H:%M:%S");
|
||||
aktstatus = TranslateAktstatus(FlowControll[i]->name());
|
||||
@@ -353,7 +376,6 @@ void ClassFlowControll::doFlowTakeImageOnly(string time)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool ClassFlowControll::doFlow(string time)
|
||||
{
|
||||
bool result = true;
|
||||
@@ -373,8 +395,7 @@ bool ClassFlowControll::doFlow(string time)
|
||||
|
||||
//checkNtpStatus(0);
|
||||
|
||||
for (int i = 0; i < FlowControll.size(); ++i)
|
||||
{
|
||||
for (int i = 0; i < FlowControll.size(); ++i) {
|
||||
zw_time = getCurrentTimeString("%H:%M:%S");
|
||||
aktstatus = TranslateAktstatus(FlowControll[i]->name());
|
||||
aktstatusWithTime = aktstatus + " (" + zw_time + ")";
|
||||
@@ -391,7 +412,7 @@ bool ClassFlowControll::doFlow(string time)
|
||||
if (!FlowControll[i]->doFlow(time)){
|
||||
repeat++;
|
||||
LogFile.WriteToFile(ESP_LOG_WARN, TAG, "Fehler im vorheriger Schritt - wird zum " + to_string(repeat) + ". Mal wiederholt");
|
||||
if (i) i -= 1; // vPrevious step must be repeated (probably take pictures)
|
||||
if (i) { i -= 1; } // vPrevious step must be repeated (probably take pictures)
|
||||
result = false;
|
||||
if (repeat > 5) {
|
||||
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Wiederholung 5x nicht erfolgreich --> reboot");
|
||||
@@ -399,8 +420,7 @@ bool ClassFlowControll::doFlow(string time)
|
||||
//Step was repeated 5x --> reboot
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
else {
|
||||
result = true;
|
||||
}
|
||||
|
||||
@@ -424,27 +444,29 @@ bool ClassFlowControll::doFlow(string time)
|
||||
string ClassFlowControll::getReadoutAll(int _type)
|
||||
{
|
||||
std::string out = "";
|
||||
if (flowpostprocessing)
|
||||
{
|
||||
|
||||
if (flowpostprocessing) {
|
||||
std::vector<NumberPost*> *numbers = flowpostprocessing->GetNumbers();
|
||||
|
||||
for (int i = 0; i < (*numbers).size(); ++i)
|
||||
{
|
||||
for (int i = 0; i < (*numbers).size(); ++i) {
|
||||
out = out + (*numbers)[i]->name + "\t";
|
||||
|
||||
switch (_type) {
|
||||
case READOUT_TYPE_VALUE:
|
||||
out = out + (*numbers)[i]->ReturnValue;
|
||||
break;
|
||||
case READOUT_TYPE_PREVALUE:
|
||||
if (flowpostprocessing->PreValueUse)
|
||||
{
|
||||
if ((*numbers)[i]->PreValueOkay)
|
||||
if (flowpostprocessing->PreValueUse) {
|
||||
if ((*numbers)[i]->PreValueOkay) {
|
||||
out = out + (*numbers)[i]->ReturnPreValue;
|
||||
else
|
||||
out = out + "PreValue too old";
|
||||
}
|
||||
else {
|
||||
out = out + "PreValue too old";
|
||||
}
|
||||
}
|
||||
else
|
||||
else {
|
||||
out = out + "PreValue deactivated";
|
||||
}
|
||||
break;
|
||||
case READOUT_TYPE_RAWVALUE:
|
||||
out = out + (*numbers)[i]->ReturnRawValue;
|
||||
@@ -453,8 +475,10 @@ string ClassFlowControll::getReadoutAll(int _type)
|
||||
out = out + (*numbers)[i]->ErrorMessageText;
|
||||
break;
|
||||
}
|
||||
if (i < (*numbers).size()-1)
|
||||
|
||||
if (i < (*numbers).size()-1) {
|
||||
out = out + "\r\n";
|
||||
}
|
||||
}
|
||||
// ESP_LOGD(TAG, "OUT: %s", out.c_str());
|
||||
}
|
||||
@@ -462,43 +486,24 @@ string ClassFlowControll::getReadoutAll(int _type)
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
string ClassFlowControll::getReadout(bool _rawvalue = false, bool _noerror = false, int _number = 0)
|
||||
{
|
||||
if (flowpostprocessing)
|
||||
if (flowpostprocessing) {
|
||||
return flowpostprocessing->getReadoutParam(_rawvalue, _noerror, _number);
|
||||
|
||||
string zw = "";
|
||||
string result = "";
|
||||
|
||||
for (int i = 0; i < FlowControll.size(); ++i)
|
||||
{
|
||||
zw = FlowControll[i]->getReadout();
|
||||
if (zw.length() > 0)
|
||||
{
|
||||
if (result.length() == 0)
|
||||
result = zw;
|
||||
else
|
||||
result = result + "\t" + zw;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
return std::string("");
|
||||
}
|
||||
|
||||
|
||||
string ClassFlowControll::GetPrevalue(std::string _number)
|
||||
{
|
||||
if (flowpostprocessing)
|
||||
{
|
||||
if (flowpostprocessing) {
|
||||
return flowpostprocessing->GetPreValue(_number);
|
||||
}
|
||||
|
||||
|
||||
return std::string("");
|
||||
}
|
||||
|
||||
|
||||
bool ClassFlowControll::UpdatePrevalue(std::string _newvalue, std::string _numbers, bool _extern)
|
||||
{
|
||||
double newvalueAsDouble;
|
||||
@@ -519,10 +524,12 @@ bool ClassFlowControll::UpdatePrevalue(std::string _newvalue, std::string _numbe
|
||||
}
|
||||
|
||||
if (flowpostprocessing) {
|
||||
if (flowpostprocessing->SetPreValue(newvalueAsDouble, _numbers, _extern))
|
||||
if (flowpostprocessing->SetPreValue(newvalueAsDouble, _numbers, _extern)) {
|
||||
return true;
|
||||
else
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "UpdatePrevalue: ERROR - Class Post-Processing not initialized");
|
||||
@@ -530,93 +537,85 @@ bool ClassFlowControll::UpdatePrevalue(std::string _newvalue, std::string _numbe
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool ClassFlowControll::ReadParameter(FILE* pfile, string& aktparamgraph)
|
||||
{
|
||||
std::vector<string> splitted;
|
||||
|
||||
aktparamgraph = trim(aktparamgraph);
|
||||
|
||||
if (aktparamgraph.size() == 0)
|
||||
if (!this->GetNextParagraph(pfile, aktparamgraph))
|
||||
if (aktparamgraph.size() == 0) {
|
||||
if (!this->GetNextParagraph(pfile, aktparamgraph)) {
|
||||
return false;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
if ((toUpper(aktparamgraph).compare("[AUTOTIMER]") != 0) && (toUpper(aktparamgraph).compare("[DEBUG]") != 0) &&
|
||||
(toUpper(aktparamgraph).compare("[SYSTEM]") != 0 && (toUpper(aktparamgraph).compare("[DATALOGGING]") != 0))) // Paragraph passt nicht zu Debug oder DataLogging
|
||||
(toUpper(aktparamgraph).compare("[SYSTEM]") != 0 && (toUpper(aktparamgraph).compare("[DATALOGGING]") != 0))) {
|
||||
// Paragraph passt nicht zu Debug oder DataLogging
|
||||
return false;
|
||||
}
|
||||
|
||||
while (this->getNextLine(pfile, &aktparamgraph) && !this->isNewParagraph(aktparamgraph))
|
||||
{
|
||||
while (this->getNextLine(pfile, &aktparamgraph) && !this->isNewParagraph(aktparamgraph)) {
|
||||
splitted = ZerlegeZeile(aktparamgraph, " =");
|
||||
if ((toUpper(splitted[0]) == "AUTOSTART") && (splitted.size() > 1))
|
||||
{
|
||||
if (toUpper(splitted[1]) == "TRUE")
|
||||
|
||||
if ((toUpper(splitted[0]) == "AUTOSTART") && (splitted.size() > 1)) {
|
||||
AutoStart = alphanumericToBoolean(splitted[1]);
|
||||
}
|
||||
|
||||
if ((toUpper(splitted[0]) == "INTERVAL") && (splitted.size() > 1)) {
|
||||
if (isStringNumeric(splitted[1]))
|
||||
{
|
||||
AutoStart = true;
|
||||
AutoInterval = std::stof(splitted[1]);
|
||||
}
|
||||
}
|
||||
|
||||
if ((toUpper(splitted[0]) == "INTERVAL") && (splitted.size() > 1))
|
||||
{
|
||||
AutoInterval = std::stof(splitted[1]);
|
||||
if ((toUpper(splitted[0]) == "DATALOGACTIVE") && (splitted.size() > 1)) {
|
||||
LogFile.SetDataLogToSD(alphanumericToBoolean(splitted[1]));
|
||||
}
|
||||
|
||||
if ((toUpper(splitted[0]) == "DATALOGACTIVE") && (splitted.size() > 1))
|
||||
{
|
||||
if (toUpper(splitted[1]) == "TRUE")
|
||||
if ((toUpper(splitted[0]) == "DATAFILESRETENTION") && (splitted.size() > 1)) {
|
||||
if (isStringNumeric(splitted[1]))
|
||||
{
|
||||
LogFile.SetDataLogToSD(true);
|
||||
}
|
||||
else {
|
||||
LogFile.SetDataLogToSD(false);
|
||||
LogFile.SetDataLogRetention(std::stoi(splitted[1]));
|
||||
}
|
||||
}
|
||||
|
||||
if ((toUpper(splitted[0]) == "DATAFILESRETENTION") && (splitted.size() > 1))
|
||||
{
|
||||
LogFile.SetDataLogRetention(std::stoi(splitted[1]));
|
||||
}
|
||||
|
||||
if ((toUpper(splitted[0]) == "LOGLEVEL") && (splitted.size() > 1))
|
||||
{
|
||||
if ((toUpper(splitted[0]) == "LOGLEVEL") && (splitted.size() > 1)) {
|
||||
/* matches esp_log_level_t */
|
||||
if ((toUpper(splitted[1]) == "TRUE") || (toUpper(splitted[1]) == "2"))
|
||||
{
|
||||
if ((toUpper(splitted[1]) == "TRUE") || (toUpper(splitted[1]) == "2")) {
|
||||
LogFile.setLogLevel(ESP_LOG_WARN);
|
||||
}
|
||||
else if ((toUpper(splitted[1]) == "FALSE") || (toUpper(splitted[1]) == "0") || (toUpper(splitted[1]) == "1"))
|
||||
{
|
||||
else if ((toUpper(splitted[1]) == "FALSE") || (toUpper(splitted[1]) == "0") || (toUpper(splitted[1]) == "1")) {
|
||||
LogFile.setLogLevel(ESP_LOG_ERROR);
|
||||
}
|
||||
else if (toUpper(splitted[1]) == "3")
|
||||
{
|
||||
else if (toUpper(splitted[1]) == "3") {
|
||||
LogFile.setLogLevel(ESP_LOG_INFO);
|
||||
}
|
||||
else if (toUpper(splitted[1]) == "4")
|
||||
{
|
||||
else if (toUpper(splitted[1]) == "4") {
|
||||
LogFile.setLogLevel(ESP_LOG_DEBUG);
|
||||
}
|
||||
|
||||
/* If system reboot was not triggered by user and reboot was caused by execption -> keep log level to DEBUG */
|
||||
if (!getIsPlannedReboot() && (esp_reset_reason() == ESP_RST_PANIC))
|
||||
if (!getIsPlannedReboot() && (esp_reset_reason() == ESP_RST_PANIC)) {
|
||||
LogFile.setLogLevel(ESP_LOG_DEBUG);
|
||||
}
|
||||
}
|
||||
if ((toUpper(splitted[0]) == "LOGFILESRETENTION") && (splitted.size() > 1))
|
||||
{
|
||||
LogFile.SetLogFileRetention(std::stoi(splitted[1]));
|
||||
|
||||
if ((toUpper(splitted[0]) == "LOGFILESRETENTION") && (splitted.size() > 1)) {
|
||||
if (isStringNumeric(splitted[1]))
|
||||
{
|
||||
LogFile.SetLogFileRetention(std::stoi(splitted[1]));
|
||||
}
|
||||
}
|
||||
|
||||
/* TimeServer and TimeZone got already read from the config, see setupTime () */
|
||||
|
||||
#if (defined WLAN_USE_ROAMING_BY_SCANNING || (defined WLAN_USE_MESH_ROAMING && defined WLAN_USE_MESH_ROAMING_ACTIVATE_CLIENT_TRIGGERED_QUERIES))
|
||||
if ((toUpper(splitted[0]) == "RSSITHRESHOLD") && (splitted.size() > 1))
|
||||
{
|
||||
if ((toUpper(splitted[0]) == "RSSITHRESHOLD") && (splitted.size() > 1)) {
|
||||
int RSSIThresholdTMP = atoi(splitted[1].c_str());
|
||||
RSSIThresholdTMP = min(0, max(-100, RSSIThresholdTMP)); // Verify input limits (-100 - 0)
|
||||
|
||||
if (ChangeRSSIThreshold(WLAN_CONFIG_FILE, RSSIThresholdTMP))
|
||||
{
|
||||
if (ChangeRSSIThreshold(WLAN_CONFIG_FILE, RSSIThresholdTMP)) {
|
||||
// reboot necessary so that the new wlan.ini is also used !!!
|
||||
fclose(pfile);
|
||||
LogFile.WriteToFile(ESP_LOG_WARN, TAG, "Rebooting to activate new RSSITHRESHOLD ...");
|
||||
@@ -625,10 +624,8 @@ bool ClassFlowControll::ReadParameter(FILE* pfile, string& aktparamgraph)
|
||||
}
|
||||
#endif
|
||||
|
||||
if ((toUpper(splitted[0]) == "HOSTNAME") && (splitted.size() > 1))
|
||||
{
|
||||
if (ChangeHostName(WLAN_CONFIG_FILE, splitted[1]))
|
||||
{
|
||||
if ((toUpper(splitted[0]) == "HOSTNAME") && (splitted.size() > 1)) {
|
||||
if (ChangeHostName(WLAN_CONFIG_FILE, splitted[1])) {
|
||||
// reboot necessary so that the new wlan.ini is also used !!!
|
||||
fclose(pfile);
|
||||
LogFile.WriteToFile(ESP_LOG_WARN, TAG, "Rebooting to activate new HOSTNAME...");
|
||||
@@ -636,23 +633,19 @@ bool ClassFlowControll::ReadParameter(FILE* pfile, string& aktparamgraph)
|
||||
}
|
||||
}
|
||||
|
||||
if ((toUpper(splitted[0]) == "SETUPMODE") && (splitted.size() > 1))
|
||||
{
|
||||
if (toUpper(splitted[1]) == "TRUE")
|
||||
{
|
||||
SetupModeActive = true;
|
||||
}
|
||||
if ((toUpper(splitted[0]) == "SETUPMODE") && (splitted.size() > 1)) {
|
||||
SetupModeActive = alphanumericToBoolean(splitted[1]);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
int ClassFlowControll::CleanTempFolder() {
|
||||
const char* folderPath = "/sdcard/img_tmp";
|
||||
|
||||
ESP_LOGD(TAG, "Clean up temporary folder to avoid damage of sdcard sectors: %s", folderPath);
|
||||
DIR *dir = opendir(folderPath);
|
||||
|
||||
if (!dir) {
|
||||
ESP_LOGE(TAG, "Failed to stat dir: %s", folderPath);
|
||||
return -1;
|
||||
@@ -660,31 +653,33 @@ int ClassFlowControll::CleanTempFolder() {
|
||||
|
||||
struct dirent *entry;
|
||||
int deleted = 0;
|
||||
|
||||
while ((entry = readdir(dir)) != NULL) {
|
||||
std::string path = string(folderPath) + "/" + entry->d_name;
|
||||
if (entry->d_type == DT_REG) {
|
||||
if (unlink(path.c_str()) == 0) {
|
||||
deleted ++;
|
||||
} else {
|
||||
ESP_LOGE(TAG, "can't delete file: %s", path.c_str());
|
||||
}
|
||||
} else if (entry->d_type == DT_DIR) {
|
||||
deleted += removeFolder(path.c_str(), TAG);
|
||||
}
|
||||
if (entry->d_type == DT_REG) {
|
||||
if (unlink(path.c_str()) == 0) {
|
||||
deleted ++;
|
||||
}
|
||||
else {
|
||||
ESP_LOGE(TAG, "can't delete file: %s", path.c_str());
|
||||
}
|
||||
}
|
||||
else if (entry->d_type == DT_DIR) {
|
||||
deleted += removeFolder(path.c_str(), TAG);
|
||||
}
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
ESP_LOGD(TAG, "%d files deleted", deleted);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
esp_err_t ClassFlowControll::SendRawJPG(httpd_req_t *req)
|
||||
{
|
||||
return flowtakeimage != NULL ? flowtakeimage->SendRawJPG(req) : ESP_FAIL;
|
||||
}
|
||||
|
||||
|
||||
esp_err_t ClassFlowControll::GetJPGStream(std::string _fn, httpd_req_t *req)
|
||||
{
|
||||
ESP_LOGD(TAG, "ClassFlowControll::GetJPGStream %s", _fn.c_str());
|
||||
@@ -846,8 +841,8 @@ esp_err_t ClassFlowControll::GetJPGStream(std::string _fn, httpd_req_t *req)
|
||||
else {
|
||||
std::vector<HTMLInfo*> htmlinfo;
|
||||
|
||||
htmlinfo = GetAllDigital();
|
||||
ESP_LOGD(TAG, "After getClassFlowControll::GetAllDigital");
|
||||
htmlinfo = GetAllDigit();
|
||||
ESP_LOGD(TAG, "After getClassFlowControll::GetAllDigit");
|
||||
|
||||
for (int i = 0; i < htmlinfo.size(); ++i)
|
||||
{
|
||||
@@ -916,14 +911,20 @@ esp_err_t ClassFlowControll::GetJPGStream(std::string _fn, httpd_req_t *req)
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
string ClassFlowControll::getNumbersName()
|
||||
{
|
||||
return flowpostprocessing->getNumbersName();
|
||||
}
|
||||
|
||||
|
||||
string ClassFlowControll::getJSON()
|
||||
{
|
||||
return flowpostprocessing->GetJSON();
|
||||
}
|
||||
|
||||
/**
|
||||
* @returns a vector of all current sequences
|
||||
**/
|
||||
const std::vector<NumberPost*> &ClassFlowControll::getNumbers()
|
||||
{
|
||||
return *flowpostprocessing->GetNumbers();
|
||||
}
|
||||
|
||||
@@ -17,6 +17,9 @@
|
||||
#include "ClassFlowInfluxDB.h"
|
||||
#include "ClassFlowInfluxDBv2.h"
|
||||
#endif //ENABLE_INFLUXDB
|
||||
#ifdef ENABLE_WEBHOOK
|
||||
#include "ClassFlowWebhook.h"
|
||||
#endif //ENABLE_WEBHOOK
|
||||
#include "ClassFlowCNNGeneral.h"
|
||||
|
||||
class ClassFlowControll :
|
||||
@@ -52,12 +55,13 @@ public:
|
||||
string GetPrevalue(std::string _number = "");
|
||||
bool ReadParameter(FILE* pfile, string& aktparamgraph);
|
||||
string getJSON();
|
||||
const std::vector<NumberPost*> &getNumbers();
|
||||
string getNumbersName();
|
||||
|
||||
string TranslateAktstatus(std::string _input);
|
||||
|
||||
#ifdef ALGROI_LOAD_FROM_MEM_AS_JPG
|
||||
void DigitalDrawROI(CImageBasis *_zw);
|
||||
void DigitDrawROI(CImageBasis *_zw);
|
||||
void AnalogDrawROI(CImageBasis *_zw);
|
||||
#endif
|
||||
|
||||
@@ -73,10 +77,10 @@ public:
|
||||
std::string* getActStatus();
|
||||
void setActStatus(std::string _aktstatus);
|
||||
|
||||
std::vector<HTMLInfo*> GetAllDigital();
|
||||
std::vector<HTMLInfo*> GetAllDigit();
|
||||
std::vector<HTMLInfo*> GetAllAnalog();
|
||||
|
||||
t_CNNType GetTypeDigital();
|
||||
t_CNNType GetTypeDigit();
|
||||
t_CNNType GetTypeAnalog();
|
||||
|
||||
#ifdef ENABLE_MQTT
|
||||
|
||||
@@ -5,6 +5,10 @@
|
||||
|
||||
#include "ClassFlowImage.h"
|
||||
|
||||
/**
|
||||
* Properties of one ROI
|
||||
* FIXME: naming of members could use some refactoring to comply with common C++ coding style guidelines
|
||||
*/
|
||||
struct roi {
|
||||
int posx, posy, deltax, deltay;
|
||||
float result_float;
|
||||
@@ -14,55 +18,66 @@ struct roi {
|
||||
CImageBasis *image, *image_org;
|
||||
};
|
||||
|
||||
/**
|
||||
* FIXME: Why is this additional layer needed?
|
||||
*/
|
||||
struct general {
|
||||
string name;
|
||||
std::vector<roi*> ROI;
|
||||
};
|
||||
|
||||
enum t_RateType {
|
||||
AbsoluteChange,
|
||||
RateChange
|
||||
AbsoluteChange, // ignores the time difference; only the value difference is used comparison with NumberPost.maxRate
|
||||
RateChange // time difference is considered and a normalized rate is used for comparison with NumberPost.maxRate
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Holds all properties and settings of a sequence. A sequence is a set of digit and/or analog ROIs that are combined to
|
||||
* provide one meter reading (value).
|
||||
* FIXME: can be renamed to `Sequence`
|
||||
*/
|
||||
struct NumberPost {
|
||||
float MaxRateValue;
|
||||
bool useMaxRateValue;
|
||||
t_RateType RateType;
|
||||
bool ErrorMessage;
|
||||
bool PreValueOkay;
|
||||
bool AllowNegativeRates;
|
||||
bool checkDigitIncreaseConsistency;
|
||||
time_t lastvalue;
|
||||
string timeStamp;
|
||||
double FlowRateAct; // m3 / min
|
||||
double PreValue; // last value that was read out well
|
||||
double Value; // last value read out, incl. corrections
|
||||
string ReturnRateValue; // return value rate
|
||||
string ReturnChangeAbsolute; // return value rate
|
||||
string ReturnRawValue; // Raw value (with N & leading 0)
|
||||
string ReturnValue; // corrected return value, if necessary with error message
|
||||
string ReturnPreValue; // corrected return value without error message
|
||||
string ErrorMessageText; // Error message for consistency check
|
||||
int AnzahlAnalog;
|
||||
int AnzahlDigital;
|
||||
int DecimalShift;
|
||||
int DecimalShiftInitial;
|
||||
float AnalogDigitalTransitionStart; // When is the digit > x.1, i.e. when does it start to tilt?
|
||||
int Nachkomma;
|
||||
float MaxRateValue; // maxRate; upper bound for the difference between two consecutive readings; affected by maxRateType;
|
||||
bool useMaxRateValue; // consistencyChecksEnabled; enables consistency checks; uses maxRate and maxRateType
|
||||
t_RateType MaxRateType; // maxRateType; affects how the value of maxRate is used for comparing the current and previous value
|
||||
bool ErrorMessage; // FIXME: not used; can be removed
|
||||
int ChangeRateThreshold; // threshold parameter for negative rate detection
|
||||
bool PreValueOkay; // previousValueValid; indicates that the reading of the previous round has no errors
|
||||
bool AllowNegativeRates; // allowNegativeRate; defines if the consistency checks allow negative rates between consecutive meter readings.
|
||||
bool checkDigitIncreaseConsistency; // extendedConsistencyCheck; performs an additional consistency check to avoid wrong readings
|
||||
time_t timeStampLastValue; // Timestamp for the last read value; is used for the log
|
||||
time_t timeStampLastPreValue; // Timestamp for the last PreValue set; is used for useMaxRateValue
|
||||
time_t timeStampTimeUTC; // FIXME: not used; can be removed.
|
||||
string timeStamp; // localTimeStr; timestamp of last valid reading formatted as local time
|
||||
double FlowRateAct; // currentRate; ΔValue/min; since usage is not limited to water meters, the physical unit is not known.
|
||||
double PreValue; // lastValidValue; most recent value that could be read w/o any errors
|
||||
double Value; // value; most recent readout; may include corrections
|
||||
string ReturnRateValue; // currentRateStr; current normalized rate; ΔValue/min
|
||||
string ReturnChangeAbsolute; // currentChangeStr; absolute difference between current and previous measurement
|
||||
string ReturnRawValue; // rawValueStr; Raw value (with N & leading 0)
|
||||
string ReturnValue; // valueStr; corrected return value, if necessary with error message
|
||||
string ReturnPreValue; // lastValidValueStr; corrected return value without error message
|
||||
string ErrorMessageText; // errorMessage; Error message for consistency checks
|
||||
int AnzahlAnalog; // numAnalogRoi; number of analog ROIs used in this sequence
|
||||
int AnzahlDigit; // numDigitRoi; number of digit ROIs used in this sequence
|
||||
int DecimalShift; // decimalShift; each increment shifts the decimal separator by one digit; value=value*10^decimalShift; pos. value shifts to the right
|
||||
int DecimalShiftInitial; // decimalShiftInitial; same as decimalShift but is a const to reset decimalShift after calculations
|
||||
float AnalogToDigitTransitionStart; // AnalogToDigitTransitionStartValue; FIXME: need a better description; When is the digit > x.1, i.e. when does it start to tilt?
|
||||
int Nachkomma; // decimalPlaces; usually defined by the number of analog ROIs; affected by DecimalShift
|
||||
|
||||
string FieldV1; // Fieldname in InfluxDBv1
|
||||
string MeasurementV1; // Measurement in InfluxDBv1
|
||||
string FieldV1; // influxdbFieldName_v1; Name of the Field in InfluxDBv1
|
||||
string MeasurementV1; // influxdbMeasurementName_v1; Name of the Measurement in InfluxDBv1
|
||||
|
||||
string FieldV2; // Fieldname in InfluxDBv2
|
||||
string MeasurementV2; // Measurement in InfluxDBv2
|
||||
string FieldV2; // influxdbFieldName_v2; Name of the Field in InfluxDBv2
|
||||
string MeasurementV2; // influxdbMeasurementName_v2; Name of the Measurement in InfluxDBv2
|
||||
|
||||
bool isExtendedResolution;
|
||||
bool isExtendedResolution; // extendResolution; Adds the decimal place of the least significant analog ROI to the value
|
||||
|
||||
general *digit_roi;
|
||||
general *analog_roi;
|
||||
general *digit_roi; // digitRoi; set of digit ROIs for the sequence
|
||||
general *analog_roi; // analogRoi; set of analog ROIs for the sequence
|
||||
|
||||
string name;
|
||||
string name; // name; Designation for the sequence
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -137,6 +137,7 @@ bool ClassFlowInfluxDB::doFlow(string zwtime)
|
||||
std::string resultraw = "";
|
||||
std::string resultrate = "";
|
||||
std::string resulttimestamp = "";
|
||||
long int timeutc;
|
||||
string zw = "";
|
||||
string namenumber = "";
|
||||
|
||||
@@ -152,6 +153,7 @@ bool ClassFlowInfluxDB::doFlow(string zwtime)
|
||||
resulterror = (*NUMBERS)[i]->ErrorMessageText;
|
||||
resultrate = (*NUMBERS)[i]->ReturnRateValue;
|
||||
resulttimestamp = (*NUMBERS)[i]->timeStamp;
|
||||
timeutc = (*NUMBERS)[i]->timeStampTimeUTC;
|
||||
|
||||
if ((*NUMBERS)[i]->FieldV1.length() > 0)
|
||||
{
|
||||
@@ -167,7 +169,7 @@ bool ClassFlowInfluxDB::doFlow(string zwtime)
|
||||
}
|
||||
|
||||
if (result.length() > 0)
|
||||
InfluxDBPublish(measurement, namenumber, result, resulttimestamp);
|
||||
InfluxDBPublish(measurement, namenumber, result, timeutc);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ static const char* TAG = "INFLUXDBV2";
|
||||
void ClassFlowInfluxDBv2::SetInitialParameter(void)
|
||||
{
|
||||
uri = "";
|
||||
database = "";
|
||||
bucket = "";
|
||||
dborg = "";
|
||||
dbtoken = "";
|
||||
// dbfield = "";
|
||||
@@ -109,9 +109,9 @@ bool ClassFlowInfluxDBv2::ReadParameter(FILE* pfile, string& aktparamgraph)
|
||||
{
|
||||
handleMeasurement(splitted[0], splitted[1]);
|
||||
}
|
||||
if (((toUpper(splitted[0]) == "DATABASE")) && (splitted.size() > 1))
|
||||
if (((toUpper(splitted[0]) == "BUCKET")) && (splitted.size() > 1))
|
||||
{
|
||||
this->database = splitted[1];
|
||||
this->bucket = splitted[1];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,11 +119,11 @@ bool ClassFlowInfluxDBv2::ReadParameter(FILE* pfile, string& aktparamgraph)
|
||||
printf("org: %s\n", dborg.c_str());
|
||||
printf("token: %s\n", dbtoken.c_str());
|
||||
|
||||
if ((uri.length() > 0) && (database.length() > 0) && (dbtoken.length() > 0) && (dborg.length() > 0))
|
||||
if ((uri.length() > 0) && (bucket.length() > 0) && (dbtoken.length() > 0) && (dborg.length() > 0))
|
||||
{
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Init InfluxDB with uri: " + uri + ", org: " + dborg + ", token: *****");
|
||||
// printf("vor V2 Init\n");
|
||||
InfluxDB_V2_Init(uri, database, dborg, dbtoken);
|
||||
InfluxDB_V2_Init(uri, bucket, dborg, dbtoken);
|
||||
// printf("nach V2 Init\n");
|
||||
InfluxDBenable = true;
|
||||
} else {
|
||||
@@ -196,6 +196,7 @@ bool ClassFlowInfluxDBv2::doFlow(string zwtime)
|
||||
std::string resultraw = "";
|
||||
std::string resultrate = "";
|
||||
std::string resulttimestamp = "";
|
||||
long int resulttimeutc = 0;
|
||||
string zw = "";
|
||||
string namenumber = "";
|
||||
|
||||
@@ -212,6 +213,8 @@ bool ClassFlowInfluxDBv2::doFlow(string zwtime)
|
||||
resulterror = (*NUMBERS)[i]->ErrorMessageText;
|
||||
resultrate = (*NUMBERS)[i]->ReturnRateValue;
|
||||
resulttimestamp = (*NUMBERS)[i]->timeStamp;
|
||||
resulttimeutc = (*NUMBERS)[i]->timeStampTimeUTC;
|
||||
|
||||
|
||||
if ((*NUMBERS)[i]->FieldV2.length() > 0)
|
||||
{
|
||||
@@ -229,8 +232,7 @@ bool ClassFlowInfluxDBv2::doFlow(string zwtime)
|
||||
printf("vor sende Influx_DB_V2 - namenumber. %s, result: %s, timestampt: %s", namenumber.c_str(), result.c_str(), resulttimestamp.c_str());
|
||||
|
||||
if (result.length() > 0)
|
||||
InfluxDB_V2_Publish(measurement, namenumber, result, resulttimestamp);
|
||||
// InfluxDB_V2_Publish(namenumber, result, resulttimestamp);
|
||||
InfluxDB_V2_Publish(measurement, namenumber, result, resulttimeutc);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ class ClassFlowInfluxDBv2 :
|
||||
public ClassFlow
|
||||
{
|
||||
protected:
|
||||
std::string uri, database;
|
||||
std::string uri, bucket;
|
||||
std::string dborg, dbtoken, dbfield;
|
||||
std::string OldValue;
|
||||
ClassFlowPostProcessing* flowpostprocessing;
|
||||
|
||||
@@ -37,6 +37,9 @@ void ClassFlowMQTT::SetInitialParameter(void)
|
||||
topicUptime = "";
|
||||
topicFreeMem = "";
|
||||
|
||||
caCertFilename = "";
|
||||
clientCertFilename = "";
|
||||
clientKeyFilename = "";
|
||||
clientname = wlan_config.hostname;
|
||||
|
||||
OldValue = "";
|
||||
@@ -102,6 +105,18 @@ bool ClassFlowMQTT::ReadParameter(FILE* pfile, string& aktparamgraph)
|
||||
while (this->getNextLine(pfile, &aktparamgraph) && !this->isNewParagraph(aktparamgraph))
|
||||
{
|
||||
splitted = ZerlegeZeile(aktparamgraph);
|
||||
if ((toUpper(splitted[0]) == "CACERT") && (splitted.size() > 1))
|
||||
{
|
||||
this->caCertFilename = splitted[1];
|
||||
}
|
||||
if ((toUpper(splitted[0]) == "CLIENTCERT") && (splitted.size() > 1))
|
||||
{
|
||||
this->clientCertFilename = splitted[1];
|
||||
}
|
||||
if ((toUpper(splitted[0]) == "CLIENTKEY") && (splitted.size() > 1))
|
||||
{
|
||||
this->clientKeyFilename = splitted[1];
|
||||
}
|
||||
if ((toUpper(splitted[0]) == "USER") && (splitted.size() > 1))
|
||||
{
|
||||
this->user = splitted[1];
|
||||
@@ -196,7 +211,8 @@ bool ClassFlowMQTT::Start(float AutoInterval)
|
||||
mqttServer_setParameter(flowpostprocessing->GetNumbers(), keepAlive, roundInterval);
|
||||
|
||||
bool MQTTConfigCheck = MQTT_Configure(uri, clientname, user, password, maintopic, LWT_TOPIC, LWT_CONNECTED,
|
||||
LWT_DISCONNECTED, keepAlive, SetRetainFlag, (void *)&GotConnected);
|
||||
LWT_DISCONNECTED, caCertFilename, clientCertFilename, clientKeyFilename,
|
||||
keepAlive, SetRetainFlag, (void *)&GotConnected);
|
||||
|
||||
if (!MQTTConfigCheck) {
|
||||
return false;
|
||||
@@ -270,7 +286,7 @@ bool ClassFlowMQTT::doFlow(string zwtime)
|
||||
|
||||
if (resultchangabs.length() > 0) {
|
||||
success |= MQTTPublish(namenumber + "changeabsolut", resultchangabs, qos, SetRetainFlag); // Legacy API
|
||||
success |= MQTTPublish(namenumber + "rate_per_digitalization_round", resultchangabs, qos, SetRetainFlag);
|
||||
success |= MQTTPublish(namenumber + "rate_per_digitization_round", resultchangabs, qos, SetRetainFlag);
|
||||
}
|
||||
|
||||
if (resultraw.length() > 0)
|
||||
|
||||
@@ -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
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -21,11 +21,9 @@ protected:
|
||||
bool ErrorMessage;
|
||||
bool IgnoreLeadingNaN; // SPECIAL CASE for User Gustl ???
|
||||
|
||||
|
||||
ClassFlowCNNGeneral* flowAnalog;
|
||||
ClassFlowCNNGeneral* flowDigit;
|
||||
|
||||
|
||||
string FilePreValue;
|
||||
|
||||
ClassFlowTakeImage *flowTakeImage;
|
||||
@@ -41,21 +39,18 @@ protected:
|
||||
void handleMaxRateValue(string _decsep, string _value);
|
||||
void handleDecimalExtendedResolution(string _decsep, string _value);
|
||||
void handleMaxRateType(string _decsep, string _value);
|
||||
void handleAnalogDigitalTransitionStart(string _decsep, string _value);
|
||||
void handleAnalogToDigitTransitionStart(string _decsep, string _value);
|
||||
void handleAllowNegativeRate(string _decsep, string _value);
|
||||
void handleChangeRateThreshold(string _decsep, string _value);
|
||||
|
||||
std::string GetStringReadouts(general);
|
||||
|
||||
void WriteDataLog(int _index);
|
||||
|
||||
|
||||
|
||||
|
||||
public:
|
||||
bool PreValueUse;
|
||||
std::vector<NumberPost*> NUMBERS;
|
||||
|
||||
|
||||
ClassFlowPostProcessing(std::vector<ClassFlow*>* lfc, ClassFlowCNNGeneral *_analog, ClassFlowCNNGeneral *_digit);
|
||||
virtual ~ClassFlowPostProcessing(){};
|
||||
bool ReadParameter(FILE* pfile, string& aktparamgraph);
|
||||
|
||||
@@ -1,9 +1,15 @@
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <regex>
|
||||
|
||||
#include "ClassFlowTakeImage.h"
|
||||
#include "Helper.h"
|
||||
#include "ClassLogFile.h"
|
||||
|
||||
#include "CImageBasis.h"
|
||||
#include "ClassControllCamera.h"
|
||||
#include "MainFlowControl.h"
|
||||
|
||||
#include "esp_wifi.h"
|
||||
#include "esp_log.h"
|
||||
@@ -12,14 +18,14 @@
|
||||
|
||||
#include <time.h>
|
||||
|
||||
// #define DEBUG_DETAIL_ON
|
||||
|
||||
// #define DEBUG_DETAIL_ON
|
||||
// #define WIFITURNOFF
|
||||
|
||||
static const char* TAG = "TAKEIMAGE";
|
||||
static const char *TAG = "TAKEIMAGE";
|
||||
|
||||
esp_err_t ClassFlowTakeImage::camera_capture(){
|
||||
string nm = namerawimage;
|
||||
esp_err_t ClassFlowTakeImage::camera_capture(void)
|
||||
{
|
||||
string nm = namerawimage;
|
||||
Camera.CaptureToFile(nm);
|
||||
time(&TimeImageTaken);
|
||||
localtime(&TimeImageTaken);
|
||||
@@ -30,150 +36,500 @@ esp_err_t ClassFlowTakeImage::camera_capture(){
|
||||
void ClassFlowTakeImage::takePictureWithFlash(int flash_duration)
|
||||
{
|
||||
// in case the image is flipped, it must be reset here //
|
||||
rawImage->width = image_width;
|
||||
rawImage->height = image_height;
|
||||
/////////////////////////////////////////////////////////////////////////////////////
|
||||
rawImage->width = CCstatus.ImageWidth;
|
||||
rawImage->height = CCstatus.ImageHeight;
|
||||
|
||||
ESP_LOGD(TAG, "flash_duration: %d", flash_duration);
|
||||
|
||||
Camera.CaptureToBasisImage(rawImage, flash_duration);
|
||||
|
||||
time(&TimeImageTaken);
|
||||
localtime(&TimeImageTaken);
|
||||
|
||||
if (SaveAllFiles) rawImage->SaveToFile(namerawimage);
|
||||
if (CCstatus.SaveAllFiles)
|
||||
{
|
||||
rawImage->SaveToFile(namerawimage);
|
||||
}
|
||||
}
|
||||
|
||||
void ClassFlowTakeImage::SetInitialParameter(void)
|
||||
{
|
||||
waitbeforepicture = 5;
|
||||
isImageSize = false;
|
||||
ImageQuality = -1;
|
||||
TimeImageTaken = 0;
|
||||
ImageQuality = 5;
|
||||
rawImage = NULL;
|
||||
ImageSize = FRAMESIZE_VGA;
|
||||
SaveAllFiles = false;
|
||||
disabled = false;
|
||||
FixedExposure = false;
|
||||
namerawimage = "/sdcard/img_tmp/raw.jpg";
|
||||
}
|
||||
}
|
||||
|
||||
// auslesen der Kameraeinstellungen aus der config.ini
|
||||
// wird beim Start aufgerufen
|
||||
bool ClassFlowTakeImage::ReadParameter(FILE *pfile, string &aktparamgraph)
|
||||
{
|
||||
Camera.getSensorDatenToCCstatus(); // Kamera >>> CCstatus
|
||||
|
||||
ClassFlowTakeImage::ClassFlowTakeImage(std::vector<ClassFlow*>* lfc) : ClassFlowImage(lfc, TAG)
|
||||
std::vector<string> splitted;
|
||||
|
||||
aktparamgraph = trim(aktparamgraph);
|
||||
|
||||
if (aktparamgraph.size() == 0)
|
||||
{
|
||||
if (!this->GetNextParagraph(pfile, aktparamgraph))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (aktparamgraph.compare("[TakeImage]") != 0)
|
||||
{
|
||||
// Paragraph does not fit TakeImage
|
||||
return false;
|
||||
}
|
||||
|
||||
while (this->getNextLine(pfile, &aktparamgraph) && !this->isNewParagraph(aktparamgraph))
|
||||
{
|
||||
splitted = ZerlegeZeile(aktparamgraph);
|
||||
|
||||
if ((toUpper(splitted[0]) == "RAWIMAGESLOCATION") && (splitted.size() > 1))
|
||||
{
|
||||
imagesLocation = "/sdcard" + splitted[1];
|
||||
isLogImage = true;
|
||||
}
|
||||
|
||||
else if ((toUpper(splitted[0]) == "RAWIMAGESRETENTION") && (splitted.size() > 1))
|
||||
{
|
||||
if (isStringNumeric(splitted[1]))
|
||||
{
|
||||
this->imagesRetention = std::stod(splitted[1]);
|
||||
}
|
||||
}
|
||||
|
||||
else if ((toUpper(splitted[0]) == "SAVEALLFILES") && (splitted.size() > 1))
|
||||
{
|
||||
CCstatus.SaveAllFiles = alphanumericToBoolean(splitted[1]);
|
||||
}
|
||||
|
||||
else if ((toUpper(splitted[0]) == "WAITBEFORETAKINGPICTURE") && (splitted.size() > 1))
|
||||
{
|
||||
if (isStringNumeric(splitted[1]))
|
||||
{
|
||||
int _WaitBeforePicture = std::stoi(splitted[1]);
|
||||
if (_WaitBeforePicture != 0)
|
||||
{
|
||||
CCstatus.WaitBeforePicture = _WaitBeforePicture;
|
||||
}
|
||||
else
|
||||
{
|
||||
CCstatus.WaitBeforePicture = 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else if ((toUpper(splitted[0]) == "CAMGAINCEILING") && (splitted.size() > 1))
|
||||
{
|
||||
std::string _ImageGainceiling = toUpper(splitted[1]);
|
||||
|
||||
if (isStringNumeric(_ImageGainceiling))
|
||||
{
|
||||
int _ImageGainceiling_ = std::stoi(_ImageGainceiling);
|
||||
switch (_ImageGainceiling_)
|
||||
{
|
||||
case 1:
|
||||
CFstatus.ImageGainceiling = GAINCEILING_4X;
|
||||
break;
|
||||
case 2:
|
||||
CFstatus.ImageGainceiling = GAINCEILING_8X;
|
||||
break;
|
||||
case 3:
|
||||
CFstatus.ImageGainceiling = GAINCEILING_16X;
|
||||
break;
|
||||
case 4:
|
||||
CFstatus.ImageGainceiling = GAINCEILING_32X;
|
||||
break;
|
||||
case 5:
|
||||
CFstatus.ImageGainceiling = GAINCEILING_64X;
|
||||
break;
|
||||
case 6:
|
||||
CFstatus.ImageGainceiling = GAINCEILING_128X;
|
||||
break;
|
||||
default:
|
||||
CFstatus.ImageGainceiling = GAINCEILING_2X;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_ImageGainceiling == "X4")
|
||||
{
|
||||
CCstatus.ImageGainceiling = GAINCEILING_4X;
|
||||
}
|
||||
else if (_ImageGainceiling == "X8")
|
||||
{
|
||||
CCstatus.ImageGainceiling = GAINCEILING_8X;
|
||||
}
|
||||
else if (_ImageGainceiling == "X16")
|
||||
{
|
||||
CCstatus.ImageGainceiling = GAINCEILING_16X;
|
||||
}
|
||||
else if (_ImageGainceiling == "X32")
|
||||
{
|
||||
CCstatus.ImageGainceiling = GAINCEILING_32X;
|
||||
}
|
||||
else if (_ImageGainceiling == "X64")
|
||||
{
|
||||
CCstatus.ImageGainceiling = GAINCEILING_64X;
|
||||
}
|
||||
else if (_ImageGainceiling == "X128")
|
||||
{
|
||||
CCstatus.ImageGainceiling = GAINCEILING_128X;
|
||||
}
|
||||
else
|
||||
{
|
||||
CCstatus.ImageGainceiling = GAINCEILING_2X;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else if ((toUpper(splitted[0]) == "CAMQUALITY") && (splitted.size() > 1))
|
||||
{
|
||||
if (isStringNumeric(splitted[1]))
|
||||
{
|
||||
int _ImageQuality = std::stoi(splitted[1]);
|
||||
CCstatus.ImageQuality = clipInt(_ImageQuality, 63, 6);
|
||||
}
|
||||
}
|
||||
|
||||
else if ((toUpper(splitted[0]) == "CAMBRIGHTNESS") && (splitted.size() > 1))
|
||||
{
|
||||
if (isStringNumeric(splitted[1]))
|
||||
{
|
||||
int _ImageBrightness = std::stoi(splitted[1]);
|
||||
CCstatus.ImageBrightness = clipInt(_ImageBrightness, 2, -2);
|
||||
}
|
||||
}
|
||||
|
||||
else if ((toUpper(splitted[0]) == "CAMCONTRAST") && (splitted.size() > 1))
|
||||
{
|
||||
if (isStringNumeric(splitted[1]))
|
||||
{
|
||||
int _ImageContrast = std::stoi(splitted[1]);
|
||||
CCstatus.ImageContrast = clipInt(_ImageContrast, 2, -2);
|
||||
}
|
||||
}
|
||||
|
||||
else if ((toUpper(splitted[0]) == "CAMSATURATION") && (splitted.size() > 1))
|
||||
{
|
||||
if (isStringNumeric(splitted[1]))
|
||||
{
|
||||
int _ImageSaturation = std::stoi(splitted[1]);
|
||||
CCstatus.ImageSaturation = clipInt(_ImageSaturation, 2, -2);
|
||||
}
|
||||
}
|
||||
|
||||
else if ((toUpper(splitted[0]) == "CAMSHARPNESS") && (splitted.size() > 1))
|
||||
{
|
||||
if (isStringNumeric(splitted[1]))
|
||||
{
|
||||
int _ImageSharpness = std::stoi(splitted[1]);
|
||||
if (CCstatus.CamSensor_id == OV2640_PID)
|
||||
{
|
||||
CCstatus.ImageSharpness = clipInt(_ImageSharpness, 2, -2);
|
||||
}
|
||||
else
|
||||
{
|
||||
CCstatus.ImageSharpness = clipInt(_ImageSharpness, 3, -3);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else if ((toUpper(splitted[0]) == "CAMAUTOSHARPNESS") && (splitted.size() > 1))
|
||||
{
|
||||
CCstatus.ImageAutoSharpness = alphanumericToBoolean(splitted[1]);
|
||||
}
|
||||
|
||||
else if ((toUpper(splitted[0]) == "CAMSPECIALEFFECT") && (splitted.size() > 1))
|
||||
{
|
||||
std::string _ImageSpecialEffect = toUpper(splitted[1]);
|
||||
|
||||
if (isStringNumeric(_ImageSpecialEffect))
|
||||
{
|
||||
int _ImageSpecialEffect_ = std::stoi(_ImageSpecialEffect);
|
||||
CFstatus.ImageSpecialEffect = clipInt(_ImageSpecialEffect_, 6, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_ImageSpecialEffect == "NEGATIVE")
|
||||
{
|
||||
CCstatus.ImageSpecialEffect = 1;
|
||||
}
|
||||
else if (_ImageSpecialEffect == "GRAYSCALE")
|
||||
{
|
||||
CCstatus.ImageSpecialEffect = 2;
|
||||
}
|
||||
else if (_ImageSpecialEffect == "RED")
|
||||
{
|
||||
CCstatus.ImageSpecialEffect = 3;
|
||||
}
|
||||
else if (_ImageSpecialEffect == "GREEN")
|
||||
{
|
||||
CCstatus.ImageSpecialEffect = 4;
|
||||
}
|
||||
else if (_ImageSpecialEffect == "BLUE")
|
||||
{
|
||||
CCstatus.ImageSpecialEffect = 5;
|
||||
}
|
||||
else if (_ImageSpecialEffect == "RETRO")
|
||||
{
|
||||
CCstatus.ImageSpecialEffect = 6;
|
||||
}
|
||||
else
|
||||
{
|
||||
CCstatus.ImageSpecialEffect = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else if ((toUpper(splitted[0]) == "CAMWBMODE") && (splitted.size() > 1))
|
||||
{
|
||||
std::string _ImageWbMode = toUpper(splitted[1]);
|
||||
|
||||
if (isStringNumeric(_ImageWbMode))
|
||||
{
|
||||
int _ImageWbMode_ = std::stoi(_ImageWbMode);
|
||||
CFstatus.ImageWbMode = clipInt(_ImageWbMode_, 4, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (_ImageWbMode == "SUNNY")
|
||||
{
|
||||
CCstatus.ImageWbMode = 1;
|
||||
}
|
||||
else if (_ImageWbMode == "CLOUDY")
|
||||
{
|
||||
CCstatus.ImageWbMode = 2;
|
||||
}
|
||||
else if (_ImageWbMode == "OFFICE")
|
||||
{
|
||||
CCstatus.ImageWbMode = 3;
|
||||
}
|
||||
else if (_ImageWbMode == "HOME")
|
||||
{
|
||||
CCstatus.ImageWbMode = 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
CCstatus.ImageWbMode = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else if ((toUpper(splitted[0]) == "CAMAWB") && (splitted.size() > 1))
|
||||
{
|
||||
CCstatus.ImageAwb = alphanumericToBoolean(splitted[1]);
|
||||
}
|
||||
|
||||
else if ((toUpper(splitted[0]) == "CAMAWBGAIN") && (splitted.size() > 1))
|
||||
{
|
||||
CCstatus.ImageAwbGain = alphanumericToBoolean(splitted[1]);
|
||||
}
|
||||
|
||||
else if ((toUpper(splitted[0]) == "CAMAEC") && (splitted.size() > 1))
|
||||
{
|
||||
CCstatus.ImageAec = alphanumericToBoolean(splitted[1]);
|
||||
}
|
||||
|
||||
else if ((toUpper(splitted[0]) == "CAMAEC2") && (splitted.size() > 1))
|
||||
{
|
||||
CCstatus.ImageAec2 = alphanumericToBoolean(splitted[1]);
|
||||
}
|
||||
|
||||
else if ((toUpper(splitted[0]) == "CAMAELEVEL") && (splitted.size() > 1))
|
||||
{
|
||||
if (isStringNumeric(splitted[1]))
|
||||
{
|
||||
int _ImageAeLevel = std::stoi(splitted[1]);
|
||||
if (CCstatus.CamSensor_id == OV2640_PID)
|
||||
{
|
||||
CCstatus.ImageAeLevel = clipInt(_ImageAeLevel, 2, -2);
|
||||
}
|
||||
else
|
||||
{
|
||||
CCstatus.ImageAeLevel = clipInt(_ImageAeLevel, 5, -5);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else if ((toUpper(splitted[0]) == "CAMAECVALUE") && (splitted.size() > 1))
|
||||
{
|
||||
if (isStringNumeric(splitted[1]))
|
||||
{
|
||||
int _ImageAecValue = std::stoi(splitted[1]);
|
||||
CCstatus.ImageAecValue = clipInt(_ImageAecValue, 1200, 0);
|
||||
}
|
||||
}
|
||||
|
||||
else if ((toUpper(splitted[0]) == "CAMAGC") && (splitted.size() > 1))
|
||||
{
|
||||
CCstatus.ImageAgc = alphanumericToBoolean(splitted[1]);
|
||||
}
|
||||
|
||||
else if ((toUpper(splitted[0]) == "CAMAGCGAIN") && (splitted.size() > 1))
|
||||
{
|
||||
if (isStringNumeric(splitted[1]))
|
||||
{
|
||||
int _ImageAgcGain = std::stoi(splitted[1]);
|
||||
CCstatus.ImageAgcGain = clipInt(_ImageAgcGain, 30, 0);
|
||||
}
|
||||
}
|
||||
|
||||
else if ((toUpper(splitted[0]) == "CAMBPC") && (splitted.size() > 1))
|
||||
{
|
||||
CCstatus.ImageBpc = alphanumericToBoolean(splitted[1]);
|
||||
}
|
||||
|
||||
else if ((toUpper(splitted[0]) == "CAMWPC") && (splitted.size() > 1))
|
||||
{
|
||||
CCstatus.ImageWpc = alphanumericToBoolean(splitted[1]);
|
||||
}
|
||||
|
||||
else if ((toUpper(splitted[0]) == "CAMRAWGMA") && (splitted.size() > 1))
|
||||
{
|
||||
CCstatus.ImageRawGma = alphanumericToBoolean(splitted[1]);
|
||||
}
|
||||
|
||||
else if ((toUpper(splitted[0]) == "CAMLENC") && (splitted.size() > 1))
|
||||
{
|
||||
CCstatus.ImageLenc = alphanumericToBoolean(splitted[1]);
|
||||
}
|
||||
|
||||
else if ((toUpper(splitted[0]) == "CAMHMIRROR") && (splitted.size() > 1))
|
||||
{
|
||||
CCstatus.ImageHmirror = alphanumericToBoolean(splitted[1]);
|
||||
}
|
||||
|
||||
else if ((toUpper(splitted[0]) == "CAMVFLIP") && (splitted.size() > 1))
|
||||
{
|
||||
CCstatus.ImageVflip = alphanumericToBoolean(splitted[1]);
|
||||
}
|
||||
|
||||
else if ((toUpper(splitted[0]) == "CAMDCW") && (splitted.size() > 1))
|
||||
{
|
||||
CCstatus.ImageDcw = alphanumericToBoolean(splitted[1]);
|
||||
}
|
||||
|
||||
else if ((toUpper(splitted[0]) == "CAMDENOISE") && (splitted.size() > 1))
|
||||
{
|
||||
if (isStringNumeric(splitted[1]))
|
||||
{
|
||||
int _ImageDenoiseLevel = std::stoi(splitted[1]);
|
||||
if (CCstatus.CamSensor_id == OV2640_PID)
|
||||
{
|
||||
CCstatus.ImageDenoiseLevel = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
CCstatus.ImageDenoiseLevel = clipInt(_ImageDenoiseLevel, 8, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else if ((toUpper(splitted[0]) == "CAMZOOM") && (splitted.size() > 1))
|
||||
{
|
||||
CCstatus.ImageZoomEnabled = alphanumericToBoolean(splitted[1]);
|
||||
}
|
||||
|
||||
else if ((toUpper(splitted[0]) == "CAMZOOMOFFSETX") && (splitted.size() > 1))
|
||||
{
|
||||
if (isStringNumeric(splitted[1]))
|
||||
{
|
||||
int _ImageZoomOffsetX = std::stoi(splitted[1]);
|
||||
if (CCstatus.CamSensor_id == OV2640_PID)
|
||||
{
|
||||
CCstatus.ImageZoomOffsetX = clipInt(_ImageZoomOffsetX, 480, -480);
|
||||
}
|
||||
else if (CCstatus.CamSensor_id == OV3660_PID)
|
||||
{
|
||||
CCstatus.ImageZoomOffsetX = clipInt(_ImageZoomOffsetX, 704, -704);
|
||||
}
|
||||
else if (CCstatus.CamSensor_id == OV5640_PID)
|
||||
{
|
||||
CCstatus.ImageZoomOffsetX = clipInt(_ImageZoomOffsetX, 960, -960);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else if ((toUpper(splitted[0]) == "CAMZOOMOFFSETY") && (splitted.size() > 1))
|
||||
{
|
||||
if (isStringNumeric(splitted[1]))
|
||||
{
|
||||
int _ImageZoomOffsetY = std::stoi(splitted[1]);
|
||||
if (CCstatus.CamSensor_id == OV2640_PID)
|
||||
{
|
||||
CCstatus.ImageZoomOffsetY = clipInt(_ImageZoomOffsetY, 360, -360);
|
||||
}
|
||||
else if (CCstatus.CamSensor_id == OV3660_PID)
|
||||
{
|
||||
CCstatus.ImageZoomOffsetY = clipInt(_ImageZoomOffsetY, 528, -528);
|
||||
}
|
||||
else if (CCstatus.CamSensor_id == OV5640_PID)
|
||||
{
|
||||
CCstatus.ImageZoomOffsetY = clipInt(_ImageZoomOffsetY, 720, -720);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else if ((toUpper(splitted[0]) == "CAMZOOMSIZE") && (splitted.size() > 1))
|
||||
{
|
||||
if (isStringNumeric(splitted[1]))
|
||||
{
|
||||
int _ImageZoomSize = std::stoi(splitted[1]);
|
||||
if (CCstatus.CamSensor_id == OV2640_PID)
|
||||
{
|
||||
CCstatus.ImageZoomSize = clipInt(_ImageZoomSize, 29, 0);
|
||||
}
|
||||
else if (CCstatus.CamSensor_id == OV3660_PID)
|
||||
{
|
||||
CCstatus.ImageZoomSize = clipInt(_ImageZoomSize, 43, 0);
|
||||
}
|
||||
else if (CCstatus.CamSensor_id == OV5640_PID)
|
||||
{
|
||||
CCstatus.ImageZoomSize = clipInt(_ImageZoomSize, 59, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else if ((toUpper(splitted[0]) == "LEDINTENSITY") && (splitted.size() > 1))
|
||||
{
|
||||
if (isStringNumeric(splitted[1]))
|
||||
{
|
||||
float ledintensity = std::stof(splitted[1]);
|
||||
Camera.SetLEDIntensity(ledintensity);
|
||||
}
|
||||
}
|
||||
|
||||
else if ((toUpper(splitted[0]) == "DEMO") && (splitted.size() > 1))
|
||||
{
|
||||
CCstatus.DemoMode = alphanumericToBoolean(splitted[1]);
|
||||
if (CCstatus.DemoMode == true)
|
||||
{
|
||||
Camera.useDemoMode();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Camera.setSensorDatenFromCCstatus(); // CCstatus >>> Kamera
|
||||
Camera.SetQualityZoomSize(CCstatus.ImageQuality, CCstatus.ImageFrameSize, CCstatus.ImageZoomEnabled, CCstatus.ImageZoomOffsetX, CCstatus.ImageZoomOffsetY, CCstatus.ImageZoomSize, CCstatus.ImageVflip);
|
||||
|
||||
rawImage = new CImageBasis("rawImage");
|
||||
rawImage->CreateEmptyImage(CCstatus.ImageWidth, CCstatus.ImageHeight, 3);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
ClassFlowTakeImage::ClassFlowTakeImage(std::vector<ClassFlow *> *lfc) : ClassFlowImage(lfc, TAG)
|
||||
{
|
||||
imagesLocation = "/log/source";
|
||||
imagesRetention = 5;
|
||||
SetInitialParameter();
|
||||
}
|
||||
|
||||
|
||||
bool ClassFlowTakeImage::ReadParameter(FILE* pfile, string& aktparamgraph)
|
||||
{
|
||||
std::vector<string> splitted;
|
||||
|
||||
aktparamgraph = trim(aktparamgraph);
|
||||
int _brightness = -100;
|
||||
int _contrast = -100;
|
||||
int _saturation = -100;
|
||||
|
||||
if (aktparamgraph.size() == 0)
|
||||
if (!this->GetNextParagraph(pfile, aktparamgraph))
|
||||
return false;
|
||||
|
||||
if (aktparamgraph.compare("[TakeImage]") != 0) // Paragraph does not fit TakeImage
|
||||
return false;
|
||||
|
||||
while (this->getNextLine(pfile, &aktparamgraph) && !this->isNewParagraph(aktparamgraph))
|
||||
{
|
||||
splitted = ZerlegeZeile(aktparamgraph);
|
||||
if ((toUpper(splitted[0]) == "RAWIMAGESLOCATION") && (splitted.size() > 1))
|
||||
{
|
||||
imagesLocation = "/sdcard" + splitted[1];
|
||||
isLogImage = true;
|
||||
}
|
||||
if ((toUpper(splitted[0]) == "IMAGEQUALITY") && (splitted.size() > 1))
|
||||
ImageQuality = std::stod(splitted[1]);
|
||||
|
||||
if ((toUpper(splitted[0]) == "IMAGESIZE") && (splitted.size() > 1))
|
||||
{
|
||||
ImageSize = Camera.TextToFramesize(splitted[1].c_str());
|
||||
isImageSize = true;
|
||||
}
|
||||
|
||||
if ((toUpper(splitted[0]) == "SAVEALLFILES") && (splitted.size() > 1))
|
||||
{
|
||||
if (toUpper(splitted[1]) == "TRUE")
|
||||
SaveAllFiles = true;
|
||||
}
|
||||
|
||||
if ((toUpper(splitted[0]) == "WAITBEFORETAKINGPICTURE") && (splitted.size() > 1))
|
||||
{
|
||||
waitbeforepicture = stoi(splitted[1]);
|
||||
}
|
||||
|
||||
if ((toUpper(splitted[0]) == "RAWIMAGESRETENTION") && (splitted.size() > 1))
|
||||
{
|
||||
this->imagesRetention = std::stoi(splitted[1]);
|
||||
}
|
||||
|
||||
if ((toUpper(splitted[0]) == "BRIGHTNESS") && (splitted.size() > 1))
|
||||
{
|
||||
_brightness = stoi(splitted[1]);
|
||||
}
|
||||
|
||||
if ((toUpper(splitted[0]) == "CONTRAST") && (splitted.size() > 1))
|
||||
{
|
||||
_contrast = stoi(splitted[1]);
|
||||
}
|
||||
|
||||
if ((toUpper(splitted[0]) == "SATURATION") && (splitted.size() > 1))
|
||||
{
|
||||
_saturation = stoi(splitted[1]);
|
||||
}
|
||||
|
||||
if ((toUpper(splitted[0]) == "FIXEDEXPOSURE") && (splitted.size() > 1))
|
||||
{
|
||||
if (toUpper(splitted[1]) == "TRUE")
|
||||
FixedExposure = true;
|
||||
}
|
||||
|
||||
if ((toUpper(splitted[0]) == "LEDINTENSITY") && (splitted.size() > 1))
|
||||
{
|
||||
float ledintensity = stof(splitted[1]);
|
||||
ledintensity = min((float) 100, ledintensity);
|
||||
ledintensity = max((float) 0, ledintensity);
|
||||
Camera.SetLEDIntensity(ledintensity);
|
||||
}
|
||||
|
||||
if ((toUpper(splitted[0]) == "DEMO") && (splitted.size() > 1))
|
||||
{
|
||||
if (toUpper(splitted[1]) == "TRUE")
|
||||
Camera.useDemoMode();
|
||||
}
|
||||
}
|
||||
|
||||
Camera.SetBrightnessContrastSaturation(_brightness, _contrast, _saturation);
|
||||
Camera.SetQualitySize(ImageQuality, ImageSize);
|
||||
|
||||
image_width = Camera.image_width;
|
||||
image_height = Camera.image_height;
|
||||
rawImage = new CImageBasis("rawImage");
|
||||
rawImage->CreateEmptyImage(image_width, image_height, 3);
|
||||
|
||||
waitbeforepicture_store = waitbeforepicture;
|
||||
if (FixedExposure && (waitbeforepicture > 0))
|
||||
{
|
||||
// ESP_LOGD(TAG, "Fixed Exposure enabled!");
|
||||
int flash_duration = (int) (waitbeforepicture * 1000);
|
||||
Camera.EnableAutoExposure(flash_duration);
|
||||
waitbeforepicture = 0.2;
|
||||
// flash_duration = (int) (waitbeforepicture * 1000);
|
||||
// takePictureWithFlash(flash_duration);
|
||||
// rawImage->SaveToFile("/sdcard/init2.jpg");
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
string ClassFlowTakeImage::getHTMLSingleStep(string host)
|
||||
{
|
||||
string result;
|
||||
@@ -181,74 +537,78 @@ string ClassFlowTakeImage::getHTMLSingleStep(string host)
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
// wird bei jeder Auswertrunde aufgerufen
|
||||
bool ClassFlowTakeImage::doFlow(string zwtime)
|
||||
{
|
||||
psram_init_shared_memory_for_take_image_step();
|
||||
|
||||
string logPath = CreateLogFolder(zwtime);
|
||||
|
||||
int flash_duration = (int) (waitbeforepicture * 1000);
|
||||
|
||||
#ifdef DEBUG_DETAIL_ON
|
||||
LogFile.WriteHeapInfo("ClassFlowTakeImage::doFlow - Before takePictureWithFlash");
|
||||
#endif
|
||||
int flash_duration = (int)(CCstatus.WaitBeforePicture * 1000);
|
||||
|
||||
#ifdef DEBUG_DETAIL_ON
|
||||
LogFile.WriteHeapInfo("ClassFlowTakeImage::doFlow - Before takePictureWithFlash");
|
||||
#endif
|
||||
|
||||
#ifdef WIFITURNOFF
|
||||
esp_wifi_stop(); // to save power usage and
|
||||
#endif
|
||||
#ifdef WIFITURNOFF
|
||||
esp_wifi_stop(); // to save power usage and
|
||||
#endif
|
||||
|
||||
// wenn die Kameraeinstellungen durch Erstellen eines neuen Referenzbildes verändert wurden, müssen sie neu gesetzt werden
|
||||
if (CFstatus.changedCameraSettings)
|
||||
{
|
||||
Camera.setSensorDatenFromCCstatus(); // CCstatus >>> Kamera
|
||||
Camera.SetQualityZoomSize(CCstatus.ImageQuality, CCstatus.ImageFrameSize, CCstatus.ImageZoomEnabled, CCstatus.ImageZoomOffsetX, CCstatus.ImageZoomOffsetY, CCstatus.ImageZoomSize, CCstatus.ImageVflip);
|
||||
CFstatus.changedCameraSettings = false;
|
||||
}
|
||||
|
||||
takePictureWithFlash(flash_duration);
|
||||
|
||||
#ifdef WIFITURNOFF
|
||||
esp_wifi_start();
|
||||
#endif
|
||||
#ifdef WIFITURNOFF
|
||||
esp_wifi_start();
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef DEBUG_DETAIL_ON
|
||||
LogFile.WriteHeapInfo("ClassFlowTakeImage::doFlow - After takePictureWithFlash");
|
||||
#endif
|
||||
#ifdef DEBUG_DETAIL_ON
|
||||
LogFile.WriteHeapInfo("ClassFlowTakeImage::doFlow - After takePictureWithFlash");
|
||||
#endif
|
||||
|
||||
LogImage(logPath, "raw", NULL, NULL, zwtime, rawImage);
|
||||
|
||||
RemoveOldLogs();
|
||||
|
||||
#ifdef DEBUG_DETAIL_ON
|
||||
LogFile.WriteHeapInfo("ClassFlowTakeImage::doFlow - After RemoveOldLogs");
|
||||
#endif
|
||||
#ifdef DEBUG_DETAIL_ON
|
||||
LogFile.WriteHeapInfo("ClassFlowTakeImage::doFlow - After RemoveOldLogs");
|
||||
#endif
|
||||
|
||||
psram_deinit_shared_memory_for_take_image_step();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
esp_err_t ClassFlowTakeImage::SendRawJPG(httpd_req_t *req)
|
||||
{
|
||||
int flash_duration = (int) (waitbeforepicture * 1000);
|
||||
int flash_duration = (int)(CCstatus.WaitBeforePicture * 1000);
|
||||
time(&TimeImageTaken);
|
||||
localtime(&TimeImageTaken);
|
||||
|
||||
return Camera.CaptureToHTTP(req, flash_duration);
|
||||
}
|
||||
|
||||
|
||||
ImageData* ClassFlowTakeImage::SendRawImage()
|
||||
ImageData *ClassFlowTakeImage::SendRawImage(void)
|
||||
{
|
||||
CImageBasis *zw = new CImageBasis("SendRawImage", rawImage);
|
||||
ImageData *id;
|
||||
int flash_duration = (int) (waitbeforepicture * 1000);
|
||||
int flash_duration = (int)(CCstatus.WaitBeforePicture * 1000);
|
||||
Camera.CaptureToBasisImage(zw, flash_duration);
|
||||
time(&TimeImageTaken);
|
||||
localtime(&TimeImageTaken);
|
||||
|
||||
id = zw->writeToMemoryAsJPG();
|
||||
id = zw->writeToMemoryAsJPG();
|
||||
delete zw;
|
||||
return id;
|
||||
return id;
|
||||
}
|
||||
|
||||
time_t ClassFlowTakeImage::getTimeImageTaken()
|
||||
time_t ClassFlowTakeImage::getTimeImageTaken(void)
|
||||
{
|
||||
return TimeImageTaken;
|
||||
}
|
||||
@@ -257,4 +617,3 @@ ClassFlowTakeImage::~ClassFlowTakeImage(void)
|
||||
{
|
||||
delete rawImage;
|
||||
}
|
||||
|
||||
|
||||
@@ -9,47 +9,32 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
class ClassFlowTakeImage :
|
||||
public ClassFlowImage
|
||||
class ClassFlowTakeImage : public ClassFlowImage
|
||||
{
|
||||
protected:
|
||||
float waitbeforepicture;
|
||||
float waitbeforepicture_store;
|
||||
framesize_t ImageSize;
|
||||
bool isImageSize;
|
||||
int ImageQuality;
|
||||
time_t TimeImageTaken;
|
||||
string namerawimage;
|
||||
int image_height, image_width;
|
||||
bool SaveAllFiles;
|
||||
bool FixedExposure;
|
||||
|
||||
|
||||
|
||||
void CopyFile(string input, string output);
|
||||
|
||||
esp_err_t camera_capture();
|
||||
esp_err_t camera_capture(void);
|
||||
void takePictureWithFlash(int flash_duration);
|
||||
|
||||
|
||||
void SetInitialParameter(void);
|
||||
void SetInitialParameter(void);
|
||||
|
||||
public:
|
||||
CImageBasis *rawImage;
|
||||
|
||||
ClassFlowTakeImage(std::vector<ClassFlow*>* lfc);
|
||||
ClassFlowTakeImage(std::vector<ClassFlow *> *lfc);
|
||||
|
||||
bool ReadParameter(FILE* pfile, string& aktparamgraph);
|
||||
bool ReadParameter(FILE *pfile, string &aktparamgraph);
|
||||
bool doFlow(string time);
|
||||
string getHTMLSingleStep(string host);
|
||||
time_t getTimeImageTaken();
|
||||
string name(){return "ClassFlowTakeImage";};
|
||||
time_t getTimeImageTaken(void);
|
||||
string name() { return "ClassFlowTakeImage"; };
|
||||
|
||||
ImageData* SendRawImage();
|
||||
ImageData *SendRawImage(void);
|
||||
esp_err_t SendRawJPG(httpd_req_t *req);
|
||||
|
||||
~ClassFlowTakeImage(void);
|
||||
};
|
||||
|
||||
|
||||
#endif //CLASSFFLOWTAKEIMAGE_H
|
||||
#endif // CLASSFFLOWTAKEIMAGE_H
|
||||
171
code/components/jomjol_flowcontroll/ClassFlowWebhook.cpp
Normal file
171
code/components/jomjol_flowcontroll/ClassFlowWebhook.cpp
Normal file
@@ -0,0 +1,171 @@
|
||||
#ifdef ENABLE_WEBHOOK
|
||||
#include <sstream>
|
||||
#include "ClassFlowWebhook.h"
|
||||
#include "Helper.h"
|
||||
#include "connect_wlan.h"
|
||||
|
||||
#include "time_sntp.h"
|
||||
#include "interface_webhook.h"
|
||||
|
||||
#include "ClassFlowPostProcessing.h"
|
||||
#include "ClassFlowAlignment.h"
|
||||
#include "esp_log.h"
|
||||
#include "../../include/defines.h"
|
||||
|
||||
#include "ClassLogFile.h"
|
||||
|
||||
#include <time.h>
|
||||
|
||||
static const char* TAG = "WEBHOOK";
|
||||
|
||||
void ClassFlowWebhook::SetInitialParameter(void)
|
||||
{
|
||||
uri = "";
|
||||
flowpostprocessing = NULL;
|
||||
flowAlignment = NULL;
|
||||
previousElement = NULL;
|
||||
ListFlowControll = NULL;
|
||||
disabled = false;
|
||||
WebhookEnable = false;
|
||||
WebhookUploadImg = 0;
|
||||
}
|
||||
|
||||
ClassFlowWebhook::ClassFlowWebhook()
|
||||
{
|
||||
SetInitialParameter();
|
||||
}
|
||||
|
||||
ClassFlowWebhook::ClassFlowWebhook(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];
|
||||
}
|
||||
if (((*ListFlowControll)[i])->name().compare("ClassFlowAlignment") == 0)
|
||||
{
|
||||
flowAlignment = (ClassFlowAlignment*) (*ListFlowControll)[i];
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
ClassFlowWebhook::ClassFlowWebhook(std::vector<ClassFlow*>* lfc, ClassFlow *_prev)
|
||||
{
|
||||
SetInitialParameter();
|
||||
|
||||
previousElement = _prev;
|
||||
ListFlowControll = lfc;
|
||||
|
||||
for (int i = 0; i < ListFlowControll->size(); ++i)
|
||||
{
|
||||
if (((*ListFlowControll)[i])->name().compare("ClassFlowPostProcessing") == 0)
|
||||
{
|
||||
flowpostprocessing = (ClassFlowPostProcessing*) (*ListFlowControll)[i];
|
||||
}
|
||||
if (((*ListFlowControll)[i])->name().compare("ClassFlowAlignment") == 0)
|
||||
{
|
||||
flowAlignment = (ClassFlowAlignment*) (*ListFlowControll)[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool ClassFlowWebhook::ReadParameter(FILE* pfile, string& aktparamgraph)
|
||||
{
|
||||
std::vector<string> splitted;
|
||||
|
||||
aktparamgraph = trim(aktparamgraph);
|
||||
printf("akt param: %s\n", aktparamgraph.c_str());
|
||||
|
||||
if (aktparamgraph.size() == 0)
|
||||
if (!this->GetNextParagraph(pfile, aktparamgraph))
|
||||
return false;
|
||||
|
||||
if (toUpper(aktparamgraph).compare("[WEBHOOK]") != 0)
|
||||
return false;
|
||||
|
||||
|
||||
|
||||
while (this->getNextLine(pfile, &aktparamgraph) && !this->isNewParagraph(aktparamgraph))
|
||||
{
|
||||
ESP_LOGD(TAG, "while loop reading line: %s", aktparamgraph.c_str());
|
||||
splitted = ZerlegeZeile(aktparamgraph);
|
||||
std::string _param = GetParameterName(splitted[0]);
|
||||
|
||||
if ((toUpper(_param) == "URI") && (splitted.size() > 1))
|
||||
{
|
||||
this->uri = splitted[1];
|
||||
}
|
||||
if (((toUpper(_param) == "APIKEY")) && (splitted.size() > 1))
|
||||
{
|
||||
this->apikey = splitted[1];
|
||||
}
|
||||
if (((toUpper(_param) == "UPLOADIMG")) && (splitted.size() > 1))
|
||||
{
|
||||
if (toUpper(splitted[1]) == "1")
|
||||
{
|
||||
this->WebhookUploadImg = 1;
|
||||
} else if (toUpper(splitted[1]) == "2")
|
||||
{
|
||||
this->WebhookUploadImg = 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
WebhookInit(uri,apikey);
|
||||
WebhookEnable = true;
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Webhook Enabled for Uri " + uri);
|
||||
|
||||
printf("uri: %s\n", uri.c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
void ClassFlowWebhook::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 ClassFlowWebhook::doFlow(string zwtime)
|
||||
{
|
||||
if (!WebhookEnable)
|
||||
return true;
|
||||
|
||||
if (flowpostprocessing)
|
||||
{
|
||||
printf("vor sende WebHook");
|
||||
bool numbersWithError = WebhookPublish(flowpostprocessing->GetNumbers());
|
||||
|
||||
#ifdef ALGROI_LOAD_FROM_MEM_AS_JPG
|
||||
if ((WebhookUploadImg == 1 || (WebhookUploadImg != 0 && numbersWithError)) && flowAlignment && flowAlignment->AlgROI) {
|
||||
WebhookUploadPic(flowAlignment->AlgROI);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
#endif //ENABLE_WEBHOOK
|
||||
43
code/components/jomjol_flowcontroll/ClassFlowWebhook.h
Normal file
43
code/components/jomjol_flowcontroll/ClassFlowWebhook.h
Normal file
@@ -0,0 +1,43 @@
|
||||
#ifdef ENABLE_WEBHOOK
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef CLASSFWEBHOOK_H
|
||||
#define CLASSFWEBHOOK_H
|
||||
|
||||
#include "ClassFlow.h"
|
||||
|
||||
#include "ClassFlowPostProcessing.h"
|
||||
#include "ClassFlowAlignment.h"
|
||||
|
||||
#include <string>
|
||||
|
||||
class ClassFlowWebhook :
|
||||
public ClassFlow
|
||||
{
|
||||
protected:
|
||||
std::string uri, apikey;
|
||||
ClassFlowPostProcessing* flowpostprocessing;
|
||||
ClassFlowAlignment* flowAlignment;
|
||||
|
||||
bool WebhookEnable;
|
||||
int WebhookUploadImg;
|
||||
|
||||
void SetInitialParameter(void);
|
||||
|
||||
void handleFieldname(string _decsep, string _value);
|
||||
void handleMeasurement(string _decsep, string _value);
|
||||
|
||||
|
||||
public:
|
||||
ClassFlowWebhook();
|
||||
ClassFlowWebhook(std::vector<ClassFlow*>* lfc);
|
||||
ClassFlowWebhook(std::vector<ClassFlow*>* lfc, ClassFlow *_prev);
|
||||
|
||||
bool ReadParameter(FILE* pfile, string& aktparamgraph);
|
||||
bool doFlow(string time);
|
||||
string name(){return "ClassFlowWebhook";};
|
||||
};
|
||||
|
||||
#endif //CLASSFWEBHOOK_H
|
||||
#endif //ENABLE_WEBHOOK
|
||||
File diff suppressed because it is too large
Load Diff
@@ -9,26 +9,83 @@
|
||||
#include <esp_http_server.h>
|
||||
#include "CImageBasis.h"
|
||||
#include "ClassFlowControll.h"
|
||||
#include "openmetrics.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint16_t CamSensor_id;
|
||||
|
||||
framesize_t ImageFrameSize = FRAMESIZE_VGA; // 0 - 10
|
||||
gainceiling_t ImageGainceiling; // Image gain (GAINCEILING_x2, x4, x8, x16, x32, x64 or x128)
|
||||
|
||||
int ImageQuality; // 0 - 63
|
||||
int ImageBrightness; // (-2 to 2) - set brightness
|
||||
int ImageContrast; //-2 - 2
|
||||
int ImageSaturation; //-2 - 2
|
||||
int ImageSharpness; //-2 - 2
|
||||
bool ImageAutoSharpness;
|
||||
int ImageSpecialEffect; // 0 - 6
|
||||
int ImageWbMode; // 0 to 4 - if awb_gain enabled (0 - Auto, 1 - Sunny, 2 - Cloudy, 3 - Office, 4 - Home)
|
||||
int ImageAwb; // white balance enable (0 or 1)
|
||||
int ImageAwbGain; // Auto White Balance enable (0 or 1)
|
||||
int ImageAec; // auto exposure off (1 or 0)
|
||||
int ImageAec2; // automatic exposure sensor (0 or 1)
|
||||
int ImageAeLevel; // auto exposure levels (-2 to 2)
|
||||
int ImageAecValue; // set exposure manually (0-1200)
|
||||
int ImageAgc; // auto gain off (1 or 0)
|
||||
int ImageAgcGain; // set gain manually (0 - 30)
|
||||
int ImageBpc; // black pixel correction
|
||||
int ImageWpc; // white pixel correction
|
||||
int ImageRawGma; // (1 or 0)
|
||||
int ImageLenc; // lens correction (1 or 0)
|
||||
int ImageHmirror; // (0 or 1) flip horizontally
|
||||
int ImageVflip; // Invert image (0 or 1)
|
||||
int ImageDcw; // downsize enable (1 or 0)
|
||||
|
||||
int ImageDenoiseLevel; // The OV2640 does not support it, OV3660 and OV5640 (0 to 8)
|
||||
|
||||
int ImageWidth;
|
||||
int ImageHeight;
|
||||
|
||||
int ImageLedIntensity;
|
||||
|
||||
bool ImageZoomEnabled;
|
||||
int ImageZoomOffsetX;
|
||||
int ImageZoomOffsetY;
|
||||
int ImageZoomSize;
|
||||
|
||||
int WaitBeforePicture;
|
||||
bool isImageSize;
|
||||
|
||||
bool CameraInitSuccessful;
|
||||
bool changedCameraSettings;
|
||||
bool DemoMode;
|
||||
bool SaveAllFiles;
|
||||
} camera_flow_config_temp_t;
|
||||
|
||||
extern camera_flow_config_temp_t CFstatus;
|
||||
extern ClassFlowControll flowctrl;
|
||||
|
||||
esp_err_t setCCstatusToCFstatus(void); // CCstatus >>> CFstatus
|
||||
esp_err_t setCFstatusToCCstatus(void); // CFstatus >>> CCstatus
|
||||
esp_err_t setCFstatusToCam(void); // CFstatus >>> Kamera
|
||||
|
||||
void register_server_main_flow_task_uri(httpd_handle_t server);
|
||||
|
||||
void CheckIsPlannedReboot();
|
||||
bool getIsPlannedReboot();
|
||||
void CheckIsPlannedReboot(void);
|
||||
bool getIsPlannedReboot(void);
|
||||
|
||||
void InitializeFlowTask();
|
||||
void DeleteMainFlowTask();
|
||||
bool isSetupModusActive();
|
||||
void InitializeFlowTask(void);
|
||||
void DeleteMainFlowTask(void);
|
||||
bool isSetupModusActive(void);
|
||||
|
||||
int getCountFlowRounds();
|
||||
int getCountFlowRounds(void);
|
||||
|
||||
#ifdef ENABLE_MQTT
|
||||
esp_err_t MQTTCtrlFlowStart(std::string _topic);
|
||||
#endif //ENABLE_MQTT
|
||||
#endif // ENABLE_MQTT
|
||||
|
||||
esp_err_t GetRawJPG(httpd_req_t *req);
|
||||
esp_err_t GetJPG(std::string _filename, httpd_req_t *req);
|
||||
|
||||
#endif //MAINFLOWCONTROL_H
|
||||
#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 esp_timer tflite-lib jomjol_logfile fatfs sdmmc)
|
||||
REQUIRES esp_timer esp-tflite-micro jomjol_logfile fatfs sdmmc vfs)
|
||||
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -6,6 +6,7 @@
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
#include <vector>
|
||||
|
||||
#include "sdmmc_cmd.h"
|
||||
|
||||
using namespace std;
|
||||
@@ -20,7 +21,6 @@ bool RenameFile(string from, string to);
|
||||
bool MakeDir(std::string _what);
|
||||
bool FileExists(string filename);
|
||||
|
||||
|
||||
string RundeOutput(double _in, int _anzNachkomma);
|
||||
|
||||
size_t findDelimiterPos(string input, string delimiter);
|
||||
@@ -32,7 +32,6 @@ string getFileType(string filename);
|
||||
string getFileFullFileName(string filename);
|
||||
string getDirectory(string filename);
|
||||
|
||||
|
||||
int mkdir_r(const char *dir, const mode_t mode);
|
||||
int removeFolder(const char* folderPath, const char* logTag);
|
||||
|
||||
@@ -67,7 +66,6 @@ string getSDCardSectorSize();
|
||||
|
||||
string getMac(void);
|
||||
|
||||
|
||||
/* Error bit fields
|
||||
One bit per error
|
||||
Make sure it matches https://jomjol.github.io/AI-on-the-edge-device-docs/Error-Codes */
|
||||
@@ -97,8 +95,18 @@ const char* get404(void);
|
||||
|
||||
std::string UrlDecode(const std::string& value);
|
||||
|
||||
void replaceAll(std::string& s, const std::string& toReplace, const std::string& replaceWith);
|
||||
bool replaceString(std::string& s, std::string const& toReplace, std::string const& replaceWith);
|
||||
bool replaceString(std::string& s, std::string const& toReplace, std::string const& replaceWith, bool logIt);
|
||||
bool isInString(std::string& s, std::string const& toFind);
|
||||
|
||||
bool isStringNumeric(std::string &input);
|
||||
bool isStringAlphabetic(std::string &input);
|
||||
bool isStringAlphanumeric(std::string &input);
|
||||
bool alphanumericToBoolean(std::string &input);
|
||||
|
||||
int clipInt(int input, int high, int low);
|
||||
bool numericStrToBool(std::string input);
|
||||
bool stringToBoolean(std::string input);
|
||||
|
||||
#endif //HELPER_H
|
||||
|
||||
@@ -120,15 +120,15 @@ void psram_free_shared_temp_image_memory(void) {
|
||||
|
||||
|
||||
/*******************************************************************
|
||||
* Memory used in Digitalization Steps
|
||||
* Memory used in Digitization 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";
|
||||
if ((sharedMemoryInUseFor == "") || (sharedMemoryInUseFor == "Digitization_Model")) {
|
||||
sharedMemoryInUseFor = "Digitization_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
|
||||
}
|
||||
@@ -140,8 +140,8 @@ void *psram_get_shared_tensor_arena_memory(void) {
|
||||
|
||||
|
||||
void *psram_get_shared_model_memory(void) {
|
||||
if ((sharedMemoryInUseFor == "") || (sharedMemoryInUseFor == "Digitalization_Tensor")) {
|
||||
sharedMemoryInUseFor = "Digitalization_Model";
|
||||
if ((sharedMemoryInUseFor == "") || (sharedMemoryInUseFor == "Digitization_Tensor")) {
|
||||
sharedMemoryInUseFor = "Digitization_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
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ void psram_free_shared_stbi_memory(void *p);
|
||||
void *psram_reserve_shared_tmp_image_memory(void);
|
||||
void psram_free_shared_temp_image_memory(void);
|
||||
|
||||
/* Memory used in Digitalization Steps */
|
||||
/* Memory used in Digitization 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);
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <unistd.h>
|
||||
#include <inttypes.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
|
||||
646
code/components/jomjol_helper/sdcard_init.c
Normal file
646
code/components/jomjol_helper/sdcard_init.c
Normal file
@@ -0,0 +1,646 @@
|
||||
/*
|
||||
* 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 mh_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
|
||||
} mh_vfs_fat_sd_ctx_t;
|
||||
|
||||
static mh_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)
|
||||
{
|
||||
mh_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;
|
||||
mh_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(mh_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;
|
||||
mh_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(mh_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
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -443,7 +443,7 @@ void CImageBasis::LoadFromMemory(stbi_uc *_buffer, int len)
|
||||
//free_psram_heap(std::string(TAG) + "->rgb_image (LoadFromMemory)", rgb_image);
|
||||
}
|
||||
|
||||
rgb_image = stbi_load_from_memory(_buffer, len, &width, &height, &channels, 3);
|
||||
rgb_image = stbi_load_from_memory(_buffer, len, &width, &height, &channels, STBI_rgb);
|
||||
bpp = channels;
|
||||
ESP_LOGD(TAG, "Image loaded from memory: %d, %d, %d", width, height, channels);
|
||||
|
||||
@@ -459,6 +459,44 @@ void CImageBasis::LoadFromMemory(stbi_uc *_buffer, int len)
|
||||
}
|
||||
|
||||
|
||||
void CImageBasis::crop_image(unsigned short cropLeft, unsigned short cropRight, unsigned short cropTop, unsigned short cropBottom)
|
||||
{
|
||||
unsigned int maxTopIndex = cropTop * width * channels;
|
||||
unsigned int minBottomIndex = ((width*height) - (cropBottom * width)) * channels;
|
||||
unsigned short maxX = width - cropRight; // In pixels
|
||||
unsigned short newWidth = width - cropLeft - cropRight;
|
||||
unsigned short newHeight = height - cropTop - cropBottom;
|
||||
|
||||
unsigned int writeIndex = 0;
|
||||
// Loop over all bytes
|
||||
for (int i = 0; i < width * height * channels; i += channels) {
|
||||
// Calculate current X, Y pixel position
|
||||
int x = (i/channels) % width;
|
||||
|
||||
// Crop from the top
|
||||
if (i < maxTopIndex) { continue; }
|
||||
|
||||
// Crop from the bottom
|
||||
if (i > minBottomIndex) { continue; }
|
||||
|
||||
// Crop from the left
|
||||
if (x <= cropLeft) { continue; }
|
||||
|
||||
// Crop from the right
|
||||
if (x > maxX) { continue; }
|
||||
|
||||
// If we get here, keep the pixels
|
||||
for (int c = 0; c < channels; c++) {
|
||||
rgb_image[writeIndex++] = rgb_image[i+c];
|
||||
}
|
||||
}
|
||||
|
||||
// Set the new dimensions of the framebuffer for further use.
|
||||
width = newWidth;
|
||||
height = newHeight;
|
||||
}
|
||||
|
||||
|
||||
CImageBasis::CImageBasis(string _name, CImageBasis *_copyfrom)
|
||||
{
|
||||
name = _name;
|
||||
@@ -598,6 +636,20 @@ CImageBasis::CImageBasis(string _name, uint8_t* _rgb_image, int _channels, int _
|
||||
}
|
||||
|
||||
|
||||
void CImageBasis::Negative(void)
|
||||
{
|
||||
RGBImageLock();
|
||||
|
||||
for (int i = 0; i < width * height * channels; i += channels) {
|
||||
for (int c = 0; c < channels; c++) {
|
||||
rgb_image[i+c] = 255 - rgb_image[i+c];
|
||||
}
|
||||
}
|
||||
|
||||
RGBImageRelease();
|
||||
}
|
||||
|
||||
|
||||
void CImageBasis::Contrast(float _contrast) //input range [-100..100]
|
||||
{
|
||||
stbi_uc* p_source;
|
||||
|
||||
@@ -56,6 +56,7 @@ class CImageBasis
|
||||
void drawEllipse(int x1, int y1, int radx, int rady, int r, int g, int b, int thickness = 1);
|
||||
|
||||
void setPixelColor(int x, int y, int r, int g, int b);
|
||||
void Negative(void);
|
||||
void Contrast(float _contrast);
|
||||
bool ImageOkay();
|
||||
bool CopyFromMemory(uint8_t* _source, int _size);
|
||||
@@ -74,6 +75,7 @@ class CImageBasis
|
||||
|
||||
void Resize(int _new_dx, int _new_dy);
|
||||
void Resize(int _new_dx, int _new_dy, CImageBasis *_target);
|
||||
void crop_image(unsigned short cropLeft, unsigned short cropRight, unsigned short cropTop, unsigned short cropBottom);
|
||||
|
||||
void LoadFromMemory(stbi_uc *_buffer, int len);
|
||||
|
||||
|
||||
@@ -1,353 +1,309 @@
|
||||
#include <string>
|
||||
#include "CRotateImage.h"
|
||||
#include "psram.h"
|
||||
|
||||
static const char *TAG = "C ROTATE IMG";
|
||||
|
||||
CRotateImage::CRotateImage(std::string _name, CImageBasis *_org, CImageBasis *_temp, bool _flip) : CImageBasis(_name)
|
||||
{
|
||||
rgb_image = _org->rgb_image;
|
||||
channels = _org->channels;
|
||||
width = _org->width;
|
||||
height = _org->height;
|
||||
bpp = _org->bpp;
|
||||
externalImage = true;
|
||||
ImageTMP = _temp;
|
||||
ImageOrg = _org;
|
||||
islocked = false;
|
||||
doflip = _flip;
|
||||
}
|
||||
|
||||
|
||||
void CRotateImage::Mirror(){
|
||||
int memsize = width * height * channels;
|
||||
uint8_t* odata;
|
||||
if (ImageTMP)
|
||||
{
|
||||
odata = ImageTMP->RGBImageLock();
|
||||
}
|
||||
else
|
||||
{
|
||||
odata = (unsigned char*)malloc_psram_heap(std::string(TAG) + "->odata", memsize, MALLOC_CAP_SPIRAM);
|
||||
}
|
||||
|
||||
|
||||
int x_source, y_source;
|
||||
stbi_uc* p_target;
|
||||
stbi_uc* p_source;
|
||||
|
||||
RGBImageLock();
|
||||
|
||||
for (int x = 0; x < width; ++x)
|
||||
for (int y = 0; y < height; ++y)
|
||||
{
|
||||
p_target = odata + (channels * (y * width + x));
|
||||
|
||||
x_source = width - x;
|
||||
y_source = y;
|
||||
|
||||
p_source = rgb_image + (channels * (y_source * width + x_source));
|
||||
for (int _channels = 0; _channels < channels; ++_channels)
|
||||
p_target[_channels] = p_source[_channels];
|
||||
}
|
||||
|
||||
// memcpy(rgb_image, odata, memsize);
|
||||
memCopy(odata, rgb_image, memsize);
|
||||
if (!ImageTMP)
|
||||
free_psram_heap(std::string(TAG) + "->odata", odata);
|
||||
|
||||
if (ImageTMP)
|
||||
ImageTMP->RGBImageRelease();
|
||||
|
||||
RGBImageRelease();
|
||||
}
|
||||
|
||||
void CRotateImage::Rotate(float _angle, int _centerx, int _centery)
|
||||
{
|
||||
int org_width, org_height;
|
||||
float m[2][3];
|
||||
|
||||
float x_center = _centerx;
|
||||
float y_center = _centery;
|
||||
_angle = _angle / 180 * M_PI;
|
||||
|
||||
if (doflip)
|
||||
{
|
||||
org_width = width;
|
||||
org_height = height;
|
||||
height = org_width;
|
||||
width = org_height;
|
||||
x_center = x_center - (org_width/2) + (org_height/2);
|
||||
y_center = y_center + (org_width/2) - (org_height/2);
|
||||
if (ImageOrg)
|
||||
{
|
||||
ImageOrg->height = height;
|
||||
ImageOrg->width = width;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
org_width = width;
|
||||
org_height = height;
|
||||
}
|
||||
|
||||
m[0][0] = cos(_angle);
|
||||
m[0][1] = sin(_angle);
|
||||
m[0][2] = (1 - m[0][0]) * x_center - m[0][1] * y_center;
|
||||
|
||||
m[1][0] = -m[0][1];
|
||||
m[1][1] = m[0][0];
|
||||
m[1][2] = m[0][1] * x_center + (1 - m[0][0]) * y_center;
|
||||
|
||||
if (doflip)
|
||||
{
|
||||
m[0][2] = m[0][2] + (org_width/2) - (org_height/2);
|
||||
m[1][2] = m[1][2] - (org_width/2) + (org_height/2);
|
||||
}
|
||||
|
||||
int memsize = width * height * channels;
|
||||
uint8_t* odata;
|
||||
if (ImageTMP)
|
||||
{
|
||||
odata = ImageTMP->RGBImageLock();
|
||||
}
|
||||
else
|
||||
{
|
||||
odata = (unsigned char*)malloc_psram_heap(std::string(TAG) + "->odata", memsize, MALLOC_CAP_SPIRAM);
|
||||
}
|
||||
|
||||
|
||||
int x_source, y_source;
|
||||
stbi_uc* p_target;
|
||||
stbi_uc* p_source;
|
||||
|
||||
RGBImageLock();
|
||||
|
||||
for (int x = 0; x < width; ++x)
|
||||
for (int y = 0; y < height; ++y)
|
||||
{
|
||||
p_target = odata + (channels * (y * width + x));
|
||||
|
||||
x_source = int(m[0][0] * x + m[0][1] * y);
|
||||
y_source = int(m[1][0] * x + m[1][1] * y);
|
||||
|
||||
x_source += int(m[0][2]);
|
||||
y_source += int(m[1][2]);
|
||||
|
||||
if ((x_source >= 0) && (x_source < org_width) && (y_source >= 0) && (y_source < org_height))
|
||||
{
|
||||
p_source = rgb_image + (channels * (y_source * org_width + x_source));
|
||||
for (int _channels = 0; _channels < channels; ++_channels)
|
||||
p_target[_channels] = p_source[_channels];
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int _channels = 0; _channels < channels; ++_channels)
|
||||
p_target[_channels] = 255;
|
||||
}
|
||||
}
|
||||
|
||||
// memcpy(rgb_image, odata, memsize);
|
||||
memCopy(odata, rgb_image, memsize);
|
||||
|
||||
if (!ImageTMP)
|
||||
{
|
||||
free_psram_heap(std::string(TAG) + "->odata", odata);
|
||||
}
|
||||
if (ImageTMP)
|
||||
ImageTMP->RGBImageRelease();
|
||||
|
||||
RGBImageRelease();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void CRotateImage::RotateAntiAliasing(float _angle, int _centerx, int _centery)
|
||||
{
|
||||
int org_width, org_height;
|
||||
float m[2][3];
|
||||
|
||||
float x_center = _centerx;
|
||||
float y_center = _centery;
|
||||
_angle = _angle / 180 * M_PI;
|
||||
|
||||
if (doflip)
|
||||
{
|
||||
org_width = width;
|
||||
org_height = height;
|
||||
height = org_width;
|
||||
width = org_height;
|
||||
x_center = x_center - (org_width/2) + (org_height/2);
|
||||
y_center = y_center + (org_width/2) - (org_height/2);
|
||||
if (ImageOrg)
|
||||
{
|
||||
ImageOrg->height = height;
|
||||
ImageOrg->width = width;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
org_width = width;
|
||||
org_height = height;
|
||||
}
|
||||
|
||||
m[0][0] = cos(_angle);
|
||||
m[0][1] = sin(_angle);
|
||||
m[0][2] = (1 - m[0][0]) * x_center - m[0][1] * y_center;
|
||||
|
||||
m[1][0] = -m[0][1];
|
||||
m[1][1] = m[0][0];
|
||||
m[1][2] = m[0][1] * x_center + (1 - m[0][0]) * y_center;
|
||||
|
||||
if (doflip)
|
||||
{
|
||||
m[0][2] = m[0][2] + (org_width/2) - (org_height/2);
|
||||
m[1][2] = m[1][2] - (org_width/2) + (org_height/2);
|
||||
}
|
||||
|
||||
int memsize = width * height * channels;
|
||||
uint8_t* odata;
|
||||
if (ImageTMP)
|
||||
{
|
||||
odata = ImageTMP->RGBImageLock();
|
||||
}
|
||||
else
|
||||
{
|
||||
odata = (unsigned char*)malloc_psram_heap(std::string(TAG) + "->odata", memsize, MALLOC_CAP_SPIRAM);
|
||||
}
|
||||
|
||||
|
||||
int x_source_1, y_source_1, x_source_2, y_source_2;
|
||||
float x_source, y_source;
|
||||
float quad_ul, quad_ur, quad_ol, quad_or;
|
||||
stbi_uc* p_target;
|
||||
stbi_uc *p_source_ul, *p_source_ur, *p_source_ol, *p_source_or;
|
||||
|
||||
RGBImageLock();
|
||||
|
||||
for (int x = 0; x < width; ++x)
|
||||
for (int y = 0; y < height; ++y)
|
||||
{
|
||||
p_target = odata + (channels * (y * width + x));
|
||||
|
||||
x_source = (m[0][0] * x + m[0][1] * y);
|
||||
y_source = (m[1][0] * x + m[1][1] * y);
|
||||
|
||||
x_source += (m[0][2]);
|
||||
y_source += (m[1][2]);
|
||||
|
||||
x_source_1 = (int)x_source;
|
||||
x_source_2 = x_source_1 + 1;
|
||||
y_source_1 = (int)y_source;
|
||||
y_source_2 = y_source_1 + 1;
|
||||
|
||||
quad_ul = (x_source_2 - x_source) * (y_source_2 - y_source);
|
||||
quad_ur = (1- (x_source_2 - x_source)) * (y_source_2 - y_source);
|
||||
quad_or = (x_source_2 - x_source) * (1-(y_source_2 - y_source));
|
||||
quad_ol = (1- (x_source_2 - x_source)) * (1-(y_source_2 - y_source));
|
||||
|
||||
|
||||
if ((x_source_1 >= 0) && (x_source_2 < org_width) && (y_source_1 >= 0) && (y_source_2 < org_height))
|
||||
{
|
||||
p_source_ul = rgb_image + (channels * (y_source_1 * org_width + x_source_1));
|
||||
p_source_ur = rgb_image + (channels * (y_source_1 * org_width + x_source_2));
|
||||
p_source_or = rgb_image + (channels * (y_source_2 * org_width + x_source_1));
|
||||
p_source_ol = rgb_image + (channels * (y_source_2 * org_width + x_source_2));
|
||||
for (int _channels = 0; _channels < channels; ++_channels)
|
||||
{
|
||||
p_target[_channels] = (int)((float)p_source_ul[_channels] * quad_ul
|
||||
+ (float)p_source_ur[_channels] * quad_ur
|
||||
+ (float)p_source_or[_channels] * quad_or
|
||||
+ (float)p_source_ol[_channels] * quad_ol);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int _channels = 0; _channels < channels; ++_channels)
|
||||
p_target[_channels] = 255;
|
||||
}
|
||||
}
|
||||
|
||||
// memcpy(rgb_image, odata, memsize);
|
||||
memCopy(odata, rgb_image, memsize);
|
||||
|
||||
if (!ImageTMP)
|
||||
{
|
||||
free_psram_heap(std::string(TAG) + "->odata", odata);
|
||||
}
|
||||
if (ImageTMP)
|
||||
ImageTMP->RGBImageRelease();
|
||||
|
||||
RGBImageRelease();
|
||||
}
|
||||
|
||||
|
||||
void CRotateImage::Rotate(float _angle)
|
||||
{
|
||||
// ESP_LOGD(TAG, "width %d, height %d", width, height);
|
||||
Rotate(_angle, width / 2, height / 2);
|
||||
}
|
||||
|
||||
void CRotateImage::RotateAntiAliasing(float _angle)
|
||||
{
|
||||
// ESP_LOGD(TAG, "width %d, height %d", width, height);
|
||||
RotateAntiAliasing(_angle, width / 2, height / 2);
|
||||
}
|
||||
|
||||
void CRotateImage::Translate(int _dx, int _dy)
|
||||
{
|
||||
int memsize = width * height * channels;
|
||||
uint8_t* odata;
|
||||
if (ImageTMP)
|
||||
{
|
||||
odata = ImageTMP->RGBImageLock();
|
||||
}
|
||||
else
|
||||
{
|
||||
odata = (unsigned char*)malloc_psram_heap(std::string(TAG) + "->odata", memsize, MALLOC_CAP_SPIRAM);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int x_source, y_source;
|
||||
stbi_uc* p_target;
|
||||
stbi_uc* p_source;
|
||||
|
||||
RGBImageLock();
|
||||
|
||||
for (int x = 0; x < width; ++x)
|
||||
for (int y = 0; y < height; ++y)
|
||||
{
|
||||
p_target = odata + (channels * (y * width + x));
|
||||
|
||||
x_source = x - _dx;
|
||||
y_source = y - _dy;
|
||||
|
||||
if ((x_source >= 0) && (x_source < width) && (y_source >= 0) && (y_source < height))
|
||||
{
|
||||
p_source = rgb_image + (channels * (y_source * width + x_source));
|
||||
for (int _channels = 0; _channels < channels; ++_channels)
|
||||
p_target[_channels] = p_source[_channels];
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int _channels = 0; _channels < channels; ++_channels)
|
||||
p_target[_channels] = 255;
|
||||
}
|
||||
}
|
||||
|
||||
// memcpy(rgb_image, odata, memsize);
|
||||
memCopy(odata, rgb_image, memsize);
|
||||
if (!ImageTMP)
|
||||
{
|
||||
free_psram_heap(std::string(TAG) + "->odata", odata);
|
||||
}
|
||||
|
||||
if (ImageTMP)
|
||||
{
|
||||
ImageTMP->RGBImageRelease();
|
||||
}
|
||||
RGBImageRelease();
|
||||
|
||||
}
|
||||
|
||||
#include <string>
|
||||
#include "CRotateImage.h"
|
||||
#include "psram.h"
|
||||
|
||||
static const char *TAG = "C ROTATE IMG";
|
||||
|
||||
CRotateImage::CRotateImage(std::string _name, CImageBasis *_org, CImageBasis *_temp, bool _flip) : CImageBasis(_name)
|
||||
{
|
||||
rgb_image = _org->rgb_image;
|
||||
channels = _org->channels;
|
||||
width = _org->width;
|
||||
height = _org->height;
|
||||
bpp = _org->bpp;
|
||||
externalImage = true;
|
||||
ImageTMP = _temp;
|
||||
ImageOrg = _org;
|
||||
islocked = false;
|
||||
doflip = _flip;
|
||||
}
|
||||
|
||||
void CRotateImage::Rotate(float _angle, int _centerx, int _centery)
|
||||
{
|
||||
int org_width, org_height;
|
||||
float m[2][3];
|
||||
|
||||
float x_center = _centerx;
|
||||
float y_center = _centery;
|
||||
_angle = _angle / 180 * M_PI;
|
||||
|
||||
if (doflip)
|
||||
{
|
||||
org_width = width;
|
||||
org_height = height;
|
||||
height = org_width;
|
||||
width = org_height;
|
||||
x_center = x_center - (org_width/2) + (org_height/2);
|
||||
y_center = y_center + (org_width/2) - (org_height/2);
|
||||
if (ImageOrg)
|
||||
{
|
||||
ImageOrg->height = height;
|
||||
ImageOrg->width = width;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
org_width = width;
|
||||
org_height = height;
|
||||
}
|
||||
|
||||
m[0][0] = cos(_angle);
|
||||
m[0][1] = sin(_angle);
|
||||
m[0][2] = (1 - m[0][0]) * x_center - m[0][1] * y_center;
|
||||
|
||||
m[1][0] = -m[0][1];
|
||||
m[1][1] = m[0][0];
|
||||
m[1][2] = m[0][1] * x_center + (1 - m[0][0]) * y_center;
|
||||
|
||||
if (doflip)
|
||||
{
|
||||
m[0][2] = m[0][2] + (org_width/2) - (org_height/2);
|
||||
m[1][2] = m[1][2] - (org_width/2) + (org_height/2);
|
||||
}
|
||||
|
||||
int memsize = width * height * channels;
|
||||
uint8_t* odata;
|
||||
if (ImageTMP)
|
||||
{
|
||||
odata = ImageTMP->RGBImageLock();
|
||||
}
|
||||
else
|
||||
{
|
||||
odata = (unsigned char*)malloc_psram_heap(std::string(TAG) + "->odata", memsize, MALLOC_CAP_SPIRAM);
|
||||
}
|
||||
|
||||
|
||||
int x_source, y_source;
|
||||
stbi_uc* p_target;
|
||||
stbi_uc* p_source;
|
||||
|
||||
RGBImageLock();
|
||||
|
||||
for (int x = 0; x < width; ++x)
|
||||
for (int y = 0; y < height; ++y)
|
||||
{
|
||||
p_target = odata + (channels * (y * width + x));
|
||||
|
||||
x_source = int(m[0][0] * x + m[0][1] * y);
|
||||
y_source = int(m[1][0] * x + m[1][1] * y);
|
||||
|
||||
x_source += int(m[0][2]);
|
||||
y_source += int(m[1][2]);
|
||||
|
||||
if ((x_source >= 0) && (x_source < org_width) && (y_source >= 0) && (y_source < org_height))
|
||||
{
|
||||
p_source = rgb_image + (channels * (y_source * org_width + x_source));
|
||||
for (int _channels = 0; _channels < channels; ++_channels)
|
||||
p_target[_channels] = p_source[_channels];
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int _channels = 0; _channels < channels; ++_channels)
|
||||
p_target[_channels] = 255;
|
||||
}
|
||||
}
|
||||
|
||||
// memcpy(rgb_image, odata, memsize);
|
||||
memCopy(odata, rgb_image, memsize);
|
||||
|
||||
if (!ImageTMP)
|
||||
{
|
||||
free_psram_heap(std::string(TAG) + "->odata", odata);
|
||||
}
|
||||
if (ImageTMP)
|
||||
ImageTMP->RGBImageRelease();
|
||||
|
||||
RGBImageRelease();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void CRotateImage::RotateAntiAliasing(float _angle, int _centerx, int _centery)
|
||||
{
|
||||
int org_width, org_height;
|
||||
float m[2][3];
|
||||
|
||||
float x_center = _centerx;
|
||||
float y_center = _centery;
|
||||
_angle = _angle / 180 * M_PI;
|
||||
|
||||
if (doflip)
|
||||
{
|
||||
org_width = width;
|
||||
org_height = height;
|
||||
height = org_width;
|
||||
width = org_height;
|
||||
x_center = x_center - (org_width/2) + (org_height/2);
|
||||
y_center = y_center + (org_width/2) - (org_height/2);
|
||||
if (ImageOrg)
|
||||
{
|
||||
ImageOrg->height = height;
|
||||
ImageOrg->width = width;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
org_width = width;
|
||||
org_height = height;
|
||||
}
|
||||
|
||||
m[0][0] = cos(_angle);
|
||||
m[0][1] = sin(_angle);
|
||||
m[0][2] = (1 - m[0][0]) * x_center - m[0][1] * y_center;
|
||||
|
||||
m[1][0] = -m[0][1];
|
||||
m[1][1] = m[0][0];
|
||||
m[1][2] = m[0][1] * x_center + (1 - m[0][0]) * y_center;
|
||||
|
||||
if (doflip)
|
||||
{
|
||||
m[0][2] = m[0][2] + (org_width/2) - (org_height/2);
|
||||
m[1][2] = m[1][2] - (org_width/2) + (org_height/2);
|
||||
}
|
||||
|
||||
int memsize = width * height * channels;
|
||||
uint8_t* odata;
|
||||
if (ImageTMP)
|
||||
{
|
||||
odata = ImageTMP->RGBImageLock();
|
||||
}
|
||||
else
|
||||
{
|
||||
odata = (unsigned char*)malloc_psram_heap(std::string(TAG) + "->odata", memsize, MALLOC_CAP_SPIRAM);
|
||||
}
|
||||
|
||||
|
||||
int x_source_1, y_source_1, x_source_2, y_source_2;
|
||||
float x_source, y_source;
|
||||
float quad_ul, quad_ur, quad_ol, quad_or;
|
||||
stbi_uc* p_target;
|
||||
stbi_uc *p_source_ul, *p_source_ur, *p_source_ol, *p_source_or;
|
||||
|
||||
RGBImageLock();
|
||||
|
||||
for (int x = 0; x < width; ++x)
|
||||
for (int y = 0; y < height; ++y)
|
||||
{
|
||||
p_target = odata + (channels * (y * width + x));
|
||||
|
||||
x_source = (m[0][0] * x + m[0][1] * y);
|
||||
y_source = (m[1][0] * x + m[1][1] * y);
|
||||
|
||||
x_source += (m[0][2]);
|
||||
y_source += (m[1][2]);
|
||||
|
||||
x_source_1 = (int)x_source;
|
||||
x_source_2 = x_source_1 + 1;
|
||||
y_source_1 = (int)y_source;
|
||||
y_source_2 = y_source_1 + 1;
|
||||
|
||||
quad_ul = (x_source_2 - x_source) * (y_source_2 - y_source);
|
||||
quad_ur = (1- (x_source_2 - x_source)) * (y_source_2 - y_source);
|
||||
quad_or = (x_source_2 - x_source) * (1-(y_source_2 - y_source));
|
||||
quad_ol = (1- (x_source_2 - x_source)) * (1-(y_source_2 - y_source));
|
||||
|
||||
|
||||
if ((x_source_1 >= 0) && (x_source_2 < org_width) && (y_source_1 >= 0) && (y_source_2 < org_height))
|
||||
{
|
||||
p_source_ul = rgb_image + (channels * (y_source_1 * org_width + x_source_1));
|
||||
p_source_ur = rgb_image + (channels * (y_source_1 * org_width + x_source_2));
|
||||
p_source_or = rgb_image + (channels * (y_source_2 * org_width + x_source_1));
|
||||
p_source_ol = rgb_image + (channels * (y_source_2 * org_width + x_source_2));
|
||||
for (int _channels = 0; _channels < channels; ++_channels)
|
||||
{
|
||||
p_target[_channels] = (int)((float)p_source_ul[_channels] * quad_ul
|
||||
+ (float)p_source_ur[_channels] * quad_ur
|
||||
+ (float)p_source_or[_channels] * quad_or
|
||||
+ (float)p_source_ol[_channels] * quad_ol);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int _channels = 0; _channels < channels; ++_channels)
|
||||
p_target[_channels] = 255;
|
||||
}
|
||||
}
|
||||
|
||||
// memcpy(rgb_image, odata, memsize);
|
||||
memCopy(odata, rgb_image, memsize);
|
||||
|
||||
if (!ImageTMP)
|
||||
{
|
||||
free_psram_heap(std::string(TAG) + "->odata", odata);
|
||||
}
|
||||
if (ImageTMP)
|
||||
ImageTMP->RGBImageRelease();
|
||||
|
||||
RGBImageRelease();
|
||||
}
|
||||
|
||||
|
||||
void CRotateImage::Rotate(float _angle)
|
||||
{
|
||||
// ESP_LOGD(TAG, "width %d, height %d", width, height);
|
||||
Rotate(_angle, width / 2, height / 2);
|
||||
}
|
||||
|
||||
void CRotateImage::RotateAntiAliasing(float _angle)
|
||||
{
|
||||
// ESP_LOGD(TAG, "width %d, height %d", width, height);
|
||||
RotateAntiAliasing(_angle, width / 2, height / 2);
|
||||
}
|
||||
|
||||
void CRotateImage::Translate(int _dx, int _dy)
|
||||
{
|
||||
int memsize = width * height * channels;
|
||||
uint8_t* odata;
|
||||
if (ImageTMP)
|
||||
{
|
||||
odata = ImageTMP->RGBImageLock();
|
||||
}
|
||||
else
|
||||
{
|
||||
odata = (unsigned char*)malloc_psram_heap(std::string(TAG) + "->odata", memsize, MALLOC_CAP_SPIRAM);
|
||||
}
|
||||
|
||||
|
||||
|
||||
int x_source, y_source;
|
||||
stbi_uc* p_target;
|
||||
stbi_uc* p_source;
|
||||
|
||||
RGBImageLock();
|
||||
|
||||
for (int x = 0; x < width; ++x)
|
||||
for (int y = 0; y < height; ++y)
|
||||
{
|
||||
p_target = odata + (channels * (y * width + x));
|
||||
|
||||
x_source = x - _dx;
|
||||
y_source = y - _dy;
|
||||
|
||||
if ((x_source >= 0) && (x_source < width) && (y_source >= 0) && (y_source < height))
|
||||
{
|
||||
p_source = rgb_image + (channels * (y_source * width + x_source));
|
||||
for (int _channels = 0; _channels < channels; ++_channels)
|
||||
p_target[_channels] = p_source[_channels];
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int _channels = 0; _channels < channels; ++_channels)
|
||||
p_target[_channels] = 255;
|
||||
}
|
||||
}
|
||||
|
||||
// memcpy(rgb_image, odata, memsize);
|
||||
memCopy(odata, rgb_image, memsize);
|
||||
if (!ImageTMP)
|
||||
{
|
||||
free_psram_heap(std::string(TAG) + "->odata", odata);
|
||||
}
|
||||
|
||||
if (ImageTMP)
|
||||
{
|
||||
ImageTMP->RGBImageRelease();
|
||||
}
|
||||
RGBImageRelease();
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -1,29 +1,28 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef CROTATEIMAGE_H
|
||||
#define CROTATEIMAGE_H
|
||||
|
||||
#include "CImageBasis.h"
|
||||
|
||||
|
||||
class CRotateImage: public CImageBasis
|
||||
{
|
||||
|
||||
public:
|
||||
CImageBasis *ImageTMP, *ImageOrg;
|
||||
bool doflip;
|
||||
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);
|
||||
|
||||
void Rotate(float _angle, int _centerx, int _centery);
|
||||
void RotateAntiAliasing(float _angle, int _centerx, int _centery);
|
||||
|
||||
void Translate(int _dx, int _dy);
|
||||
void Mirror();
|
||||
};
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef CROTATEIMAGE_H
|
||||
#define CROTATEIMAGE_H
|
||||
|
||||
#include "CImageBasis.h"
|
||||
|
||||
|
||||
class CRotateImage: public CImageBasis
|
||||
{
|
||||
|
||||
public:
|
||||
CImageBasis *ImageTMP, *ImageOrg;
|
||||
bool doflip;
|
||||
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);
|
||||
|
||||
void Rotate(float _angle, int _centerx, int _centery);
|
||||
void RotateAntiAliasing(float _angle, int _centerx, int _centery);
|
||||
|
||||
void Translate(int _dx, int _dy);
|
||||
};
|
||||
|
||||
#endif //CROTATEIMAGE_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 esp_http_client jomjol_logfile)
|
||||
REQUIRES esp_http_client jomjol_logfile)
|
||||
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <time.h>
|
||||
#include "ClassLogFile.h"
|
||||
#include "esp_http_client.h"
|
||||
#include "time_sntp.h"
|
||||
#include "../../include/defines.h"
|
||||
|
||||
|
||||
@@ -16,21 +17,21 @@ std::string _influxDBUser;
|
||||
std::string _influxDBPassword;
|
||||
|
||||
std::string _influxDB_V2_URI;
|
||||
std::string _influxDB_V2_Database;
|
||||
std::string _influxDB_V2_Bucket;
|
||||
std::string _influxDB_V2_Token;
|
||||
std::string _influxDB_V2_Org;
|
||||
|
||||
static esp_err_t http_event_handler(esp_http_client_event_t *evt);
|
||||
|
||||
void InfluxDB_V2_Init(std::string _uri, std::string _database, std::string _org, std::string _token)
|
||||
void InfluxDB_V2_Init(std::string _uri, std::string _bucket, std::string _org, std::string _token)
|
||||
{
|
||||
_influxDB_V2_URI = _uri;
|
||||
_influxDB_V2_Database = _database;
|
||||
_influxDB_V2_Bucket = _bucket;
|
||||
_influxDB_V2_Org = _org;
|
||||
_influxDB_V2_Token = _token;
|
||||
}
|
||||
|
||||
void InfluxDB_V2_Publish(std::string _measurement, std::string _key, std::string _content, std::string _timestamp)
|
||||
void InfluxDB_V2_Publish(std::string _measurement, std::string _key, std::string _content, long int _timeUTC)
|
||||
{
|
||||
char response_buffer[MAX_HTTP_OUTPUT_BUFFER] = {0};
|
||||
esp_http_client_config_t http_config = {
|
||||
@@ -41,32 +42,20 @@ void InfluxDB_V2_Publish(std::string _measurement, std::string _key, std::string
|
||||
.user_data = response_buffer
|
||||
};
|
||||
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "InfluxDB_V2_Publish - Key: " + _key + ", Content: " + _content + ", Timestamp: " + _timestamp);
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "InfluxDB_V2_Publish - Key: " + _key + ", Content: " + _content + ", timeUTC: " + std::to_string(_timeUTC));
|
||||
|
||||
std::string payload;
|
||||
char nowTimestamp[21];
|
||||
|
||||
if (_timestamp.length() > 0)
|
||||
if (_timeUTC > 0)
|
||||
{
|
||||
struct tm tm;
|
||||
strptime(_timestamp.c_str(), PREVALUE_TIME_FORMAT_OUTPUT, &tm);
|
||||
time_t t = mktime(&tm); // Time in Localtime (looks like timezone is not used by strptime)
|
||||
|
||||
// struct tm * ptm;
|
||||
// ptm = gmtime ( &t );
|
||||
// time_t utc = mktime(ptm);
|
||||
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Use handover timestamp: " + _timestamp + " converted GMT timestamp: " + std::to_string(t));
|
||||
|
||||
// utc = 2*t - utc; // Take care of timezone (looks difficult, but is easy: t = t + (t - utc), weil t-utc = timezone)
|
||||
// LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "time conversion utc after: " + std::to_string(utc));
|
||||
|
||||
sprintf(nowTimestamp,"%ld000000000", (long) t); // UTC
|
||||
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Timestamp (UTC): " + std::to_string(_timeUTC));
|
||||
sprintf(nowTimestamp,"%ld000000000", _timeUTC); // UTC
|
||||
payload = _measurement + " " + _key + "=" + _content + " " + nowTimestamp;
|
||||
}
|
||||
else
|
||||
{
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "no timestamp given");
|
||||
payload = _measurement + " " + _key + "=" + _content;
|
||||
}
|
||||
|
||||
@@ -74,7 +63,7 @@ void InfluxDB_V2_Publish(std::string _measurement, std::string _key, std::string
|
||||
|
||||
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "sending line to influxdb:" + payload);
|
||||
|
||||
std::string apiURI = _influxDB_V2_URI + "/api/v2/write?org=" + _influxDB_V2_Org + "&bucket=" + _influxDB_V2_Database;
|
||||
std::string apiURI = _influxDB_V2_URI + "/api/v2/write?org=" + _influxDB_V2_Org + "&bucket=" + _influxDB_V2_Bucket;
|
||||
apiURI.shrink_to_fit();
|
||||
http_config.url = apiURI.c_str();
|
||||
ESP_LOGI(TAG, "http_config: %s", http_config.url); // Add mark on log to see when it restarted
|
||||
@@ -141,7 +130,7 @@ static esp_err_t http_event_handler(esp_http_client_event_t *evt)
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
void InfluxDBPublish(std::string _measurement, std::string _key, std::string _content, std::string _timestamp) {
|
||||
void InfluxDBPublish(std::string _measurement, std::string _key, std::string _content, long int _timeUTC) {
|
||||
char response_buffer[MAX_HTTP_OUTPUT_BUFFER] = {0};
|
||||
esp_http_client_config_t http_config = {
|
||||
.user_agent = "ESP32 Meter reader",
|
||||
@@ -160,29 +149,17 @@ void InfluxDBPublish(std::string _measurement, std::string _key, std::string _co
|
||||
std::string payload;
|
||||
char nowTimestamp[21];
|
||||
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "InfluxDBPublish - Key: " + _key + ", Content: " + _content + ", Timestamp: " + _timestamp);
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "InfluxDBPublish - Key: " + _key + ", Content: " + _content + ", timeUTC: " + std::to_string(_timeUTC));
|
||||
|
||||
if (_timestamp.length() > 0)
|
||||
if (_timeUTC > 0)
|
||||
{
|
||||
struct tm tm;
|
||||
strptime(_timestamp.c_str(), PREVALUE_TIME_FORMAT_OUTPUT, &tm);
|
||||
time_t t = mktime(&tm); // Time in Localtime (looks like timezone is not used by strptime)
|
||||
|
||||
// struct tm * ptm;
|
||||
// ptm = gmtime ( &t );
|
||||
// time_t utc = mktime(ptm);
|
||||
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Use handover timestamp: " + _timestamp + " converted GMT timestamp: " + std::to_string(t));
|
||||
|
||||
// utc = 2*t - utc; // Take care of timezone (looks difficult, but is easy: t = t + (t - utc), weil t-utc = timezone)
|
||||
// LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "time conversion utc after: " + std::to_string(utc));
|
||||
|
||||
sprintf(nowTimestamp,"%ld000000000", (long) t); // UTC
|
||||
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Timestamp (UTC): " + std::to_string(_timeUTC));
|
||||
sprintf(nowTimestamp,"%ld000000000", _timeUTC); // UTC
|
||||
payload = _measurement + " " + _key + "=" + _content + " " + nowTimestamp;
|
||||
}
|
||||
else
|
||||
{
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "no timestamp given");
|
||||
payload = _measurement + " " + _key + "=" + _content;
|
||||
}
|
||||
|
||||
@@ -191,7 +168,7 @@ void InfluxDBPublish(std::string _measurement, std::string _key, std::string _co
|
||||
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "sending line to influxdb:" + payload);
|
||||
|
||||
|
||||
// use the default retention policy of the database
|
||||
// use the default retention policy of the bucket
|
||||
std::string apiURI = _influxDBURI + "/write?db=" + _influxDBDatabase;
|
||||
// std::string apiURI = _influxDBURI + "/api/v2/write?bucket=" + _influxDBDatabase + "/";
|
||||
|
||||
|
||||
@@ -10,11 +10,11 @@
|
||||
|
||||
// Interface to InfluxDB v1.x
|
||||
void InfluxDBInit(std::string _influxDBURI, std::string _database, std::string _user, std::string _password);
|
||||
void InfluxDBPublish(std::string _measurement, std::string _key, std::string _content, std::string _timestamp);
|
||||
void InfluxDBPublish(std::string _measurement, std::string _key, std::string _content, long int _timeUTC);
|
||||
|
||||
// Interface to InfluxDB v2.x
|
||||
void InfluxDB_V2_Init(std::string _uri, std::string _database, std::string _org, std::string _token);
|
||||
void InfluxDB_V2_Publish(std::string _measurement, std::string _key, std::string _content, std::string _timestamp);
|
||||
void InfluxDB_V2_Init(std::string _uri, std::string _bucket, std::string _org, std::string _token);
|
||||
void InfluxDB_V2_Publish(std::string _measurement, std::string _key, std::string _content, long int _timeUTC);
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ void ClassLogFile::WriteHeapInfo(std::string _id)
|
||||
}
|
||||
|
||||
|
||||
void ClassLogFile::WriteToData(std::string _timestamp, std::string _name, std::string _ReturnRawValue, std::string _ReturnValue, std::string _ReturnPreValue, std::string _ReturnRateValue, std::string _ReturnChangeAbsolute, std::string _ErrorMessageText, std::string _digital, std::string _analog)
|
||||
void ClassLogFile::WriteToData(std::string _timestamp, std::string _name, std::string _ReturnRawValue, std::string _ReturnValue, std::string _ReturnPreValue, std::string _ReturnRateValue, std::string _ReturnChangeAbsolute, std::string _ErrorMessageText, std::string _digit, std::string _analog)
|
||||
{
|
||||
ESP_LOGD(TAG, "Start WriteToData");
|
||||
time_t rawtime;
|
||||
@@ -67,7 +67,7 @@ void ClassLogFile::WriteToData(std::string _timestamp, std::string _name, std::s
|
||||
fputs(_ReturnChangeAbsolute.c_str(), pFile);
|
||||
fputs(",", pFile);
|
||||
fputs(_ErrorMessageText.c_str(), pFile);
|
||||
fputs(_digital.c_str(), pFile);
|
||||
fputs(_digit.c_str(), pFile);
|
||||
fputs(_analog.c_str(), pFile);
|
||||
fputs("\n", pFile);
|
||||
|
||||
|
||||
@@ -39,8 +39,8 @@ public:
|
||||
void RemoveOldLogFile();
|
||||
void RemoveOldDataLog();
|
||||
|
||||
// void WriteToData(std::string _ReturnRawValue, std::string _ReturnValue, std::string _ReturnPreValue, std::string _ErrorMessageText, std::string _digital, std::string _analog);
|
||||
void WriteToData(std::string _timestamp, std::string _name, std::string _ReturnRawValue, std::string _ReturnValue, std::string _ReturnPreValue, std::string _ReturnRateValue, std::string _ReturnChangeAbsolute, std::string _ErrorMessageText, std::string _digital, std::string _analog);
|
||||
// void WriteToData(std::string _ReturnRawValue, std::string _ReturnValue, std::string _ReturnPreValue, std::string _ErrorMessageText, std::string _digit, std::string _analog);
|
||||
void WriteToData(std::string _timestamp, std::string _name, std::string _ReturnRawValue, std::string _ReturnValue, std::string _ReturnPreValue, std::string _ReturnRateValue, std::string _ReturnChangeAbsolute, std::string _ErrorMessageText, std::string _digit, std::string _analog);
|
||||
|
||||
|
||||
std::string GetCurrentFileName();
|
||||
|
||||
@@ -2,4 +2,4 @@ FILE(GLOB_RECURSE app_sources ${CMAKE_CURRENT_SOURCE_DIR}/*.*)
|
||||
|
||||
idf_component_register(SRCS ${app_sources}
|
||||
INCLUDE_DIRS "."
|
||||
REQUIRES esp_timer tflite-lib mqtt jomjol_tfliteclass jomjol_helper jomjol_mqtt jomjol_wlan json)
|
||||
REQUIRES esp_timer esp-tflite-micro mqtt jomjol_tfliteclass jomjol_helper jomjol_mqtt jomjol_wlan json)
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
#include "interface_mqtt.h"
|
||||
|
||||
#include "esp_log.h"
|
||||
#if DEBUG_DETAIL_ON
|
||||
#include "esp_timer.h"
|
||||
#endif
|
||||
#include "connect_wlan.h"
|
||||
#include "mqtt_client.h"
|
||||
#include "ClassLogFile.h"
|
||||
@@ -32,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;
|
||||
@@ -169,6 +173,9 @@ static esp_err_t mqtt_event_handler_cb(esp_mqtt_event_handle_t event) {
|
||||
else if (event->error_handle->connect_return_code == MQTT_CONNECTION_REFUSE_NOT_AUTHORIZED) {
|
||||
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Connection refused, not authorized. Check username/password (0x05)");
|
||||
}
|
||||
else {
|
||||
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Connection Refused with unknown 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:");
|
||||
@@ -198,6 +205,7 @@ static void mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_
|
||||
|
||||
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))
|
||||
{
|
||||
@@ -215,6 +223,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;
|
||||
@@ -268,6 +295,20 @@ int MQTT_Init() {
|
||||
mqtt_cfg.session.keepalive = keepalive;
|
||||
mqtt_cfg.buffer.size = 1536; // size of MQTT send/receive buffer (Default: 1024)
|
||||
|
||||
if (caCert.length()){
|
||||
mqtt_cfg.broker.verification.certificate = caCert.c_str();
|
||||
mqtt_cfg.broker.verification.certificate_len = caCert.length() + 1;
|
||||
mqtt_cfg.broker.verification.skip_cert_common_name_check = true;
|
||||
}
|
||||
|
||||
if (clientCert.length() && clientKey.length()){
|
||||
mqtt_cfg.credentials.authentication.certificate = clientCert.c_str();
|
||||
mqtt_cfg.credentials.authentication.certificate_len = clientCert.length() + 1;
|
||||
|
||||
mqtt_cfg.credentials.authentication.key = clientKey.c_str();
|
||||
mqtt_cfg.credentials.authentication.key_len = clientKey.length() + 1;
|
||||
}
|
||||
|
||||
if (user.length() && password.length()){
|
||||
mqtt_cfg.credentials.username = user.c_str();
|
||||
mqtt_cfg.credentials.authentication.password = password.c_str();
|
||||
@@ -371,8 +412,10 @@ bool mqtt_handler_set_prevalue(std::string _topic, char* _data, int _data_len)
|
||||
if (cJSON_IsNumber(value)) { // Check if value is a number
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "handler_set_prevalue called: numbersname: " + std::string(numbersname->valuestring) +
|
||||
", value: " + std::to_string(value->valuedouble));
|
||||
if (flowctrl.UpdatePrevalue(std::to_string(value->valuedouble), std::string(numbersname->valuestring), true))
|
||||
if (flowctrl.UpdatePrevalue(std::to_string(value->valuedouble), std::string(numbersname->valuestring), true)) {
|
||||
cJSON_Delete(jsonData);
|
||||
return ESP_OK;
|
||||
}
|
||||
}
|
||||
else {
|
||||
LogFile.WriteToFile(ESP_LOG_WARN, TAG, "handler_set_prevalue: value not a valid number (\"value\": 12345.12345)");
|
||||
@@ -381,6 +424,7 @@ bool mqtt_handler_set_prevalue(std::string _topic, char* _data, int _data_len)
|
||||
else {
|
||||
LogFile.WriteToFile(ESP_LOG_WARN, TAG, "handler_set_prevalue: numbersname not a valid string (\"numbersname\": \"main\")");
|
||||
}
|
||||
cJSON_Delete(jsonData);
|
||||
}
|
||||
else {
|
||||
LogFile.WriteToFile(ESP_LOG_WARN, TAG, "handler_set_prevalue: handler called, but no data received");
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
bool MQTT_Configure(std::string _mqttURI, std::string _clientid, std::string _user, std::string _password,
|
||||
std::string _maintopic, std::string _lwt, std::string _lwt_connected, std::string _lwt_disconnected,
|
||||
std::string _cacertfilename, std::string _clientcertfilename, std::string _clientkeyfilename,
|
||||
int _keepalive, bool SetRetainFlag, void *callbackOnConnected);
|
||||
int MQTT_Init();
|
||||
void MQTTdestroy_client(bool _disable);
|
||||
|
||||
@@ -21,6 +21,7 @@ static const char *TAG = "MQTT SERVER";
|
||||
extern const char* libfive_git_version(void);
|
||||
extern const char* libfive_git_revision(void);
|
||||
extern const char* libfive_git_branch(void);
|
||||
extern std::string getFwVersion(void);
|
||||
|
||||
std::vector<NumberPost*>* NUMBERS;
|
||||
bool HomeassistantDiscovery = false;
|
||||
@@ -48,6 +49,15 @@ void mqttServer_setMeterType(std::string _meterType, std::string _valueUnit, std
|
||||
rateUnit = _rateUnit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes any multi-level MQTT-topic and returns the last topic level as nodeId
|
||||
* see https://www.hivemq.com/blog/mqtt-essentials-part-5-mqtt-topics-best-practices/ for details about MQTT topics
|
||||
*/
|
||||
std::string createNodeId(std::string &topic) {
|
||||
auto splitPos = topic.find_last_of('/');
|
||||
return (splitPos == std::string::npos) ? topic : topic.substr(splitPos + 1);
|
||||
}
|
||||
|
||||
bool sendHomeAssistantDiscoveryTopic(std::string group, std::string field,
|
||||
std::string name, std::string icon, std::string unit, std::string deviceClass, std::string stateClass, std::string entityCategory,
|
||||
int qos) {
|
||||
@@ -68,11 +78,18 @@ bool sendHomeAssistantDiscoveryTopic(std::string group, std::string field,
|
||||
name = group + " " + name;
|
||||
}
|
||||
|
||||
/**
|
||||
* homeassistant needs the MQTT discovery topic according to the following structure:
|
||||
* <discovery_prefix>/<component>/[<node_id>/]<object_id>/config
|
||||
* if the main topic is embedded in a nested structure, we just use the last part as node_id
|
||||
* This means a maintopic "home/test/watermeter" is transformed to the discovery topic "homeassistant/sensor/watermeter/..."
|
||||
*/
|
||||
std::string node_id = createNodeId(maintopic);
|
||||
if (field == "problem") { // Special binary sensor which is based on error topic
|
||||
topicFull = "homeassistant/binary_sensor/" + maintopic + "/" + configTopic + "/config";
|
||||
topicFull = "homeassistant/binary_sensor/" + node_id + "/" + configTopic + "/config";
|
||||
}
|
||||
else {
|
||||
topicFull = "homeassistant/sensor/" + maintopic + "/" + configTopic + "/config";
|
||||
topicFull = "homeassistant/sensor/" + node_id + "/" + configTopic + "/config";
|
||||
}
|
||||
|
||||
/* See https://www.home-assistant.io/docs/mqtt/discovery/ */
|
||||
@@ -151,6 +168,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);
|
||||
@@ -170,10 +188,10 @@ bool MQTThomeassistantDiscovery(int qos) {
|
||||
allSendsSuccessed |= sendHomeAssistantDiscoveryTopic(group, "value", "Value", "gauge", valueUnit, meterType, "total_increasing", "", qos);
|
||||
allSendsSuccessed |= sendHomeAssistantDiscoveryTopic(group, "raw", "Raw Value", "raw", "", "", "", "diagnostic", qos);
|
||||
allSendsSuccessed |= sendHomeAssistantDiscoveryTopic(group, "error", "Error", "alert-circle-outline", "", "", "", "diagnostic", qos);
|
||||
/* Not announcing "rate" as it is better to use rate_per_time_unit resp. rate_per_digitalization_round */
|
||||
/* Not announcing "rate" as it is better to use rate_per_time_unit resp. rate_per_digitization_round */
|
||||
// allSendsSuccessed |= sendHomeAssistantDiscoveryTopic(group, "rate", "Rate (Unit/Minute)", "swap-vertical", "", "", "", ""); // Legacy, always Unit per Minute
|
||||
allSendsSuccessed |= sendHomeAssistantDiscoveryTopic(group, "rate_per_time_unit", "Rate (" + rateUnit + ")", "swap-vertical", rateUnit, "", "measurement", "", qos);
|
||||
allSendsSuccessed |= sendHomeAssistantDiscoveryTopic(group, "rate_per_digitalization_round", "Change since last digitalization round", "arrow-expand-vertical", valueUnit, "", "measurement", "", qos); // correctly the Unit is Unit/Interval!
|
||||
allSendsSuccessed |= sendHomeAssistantDiscoveryTopic(group, "rate_per_digitization_round", "Change since last Digitization round", "arrow-expand-vertical", valueUnit, "", "measurement", "", qos); // correctly the Unit is Unit/Interval!
|
||||
allSendsSuccessed |= sendHomeAssistantDiscoveryTopic(group, "timestamp", "Timestamp", "clock-time-eight-outline", "", "timestamp", "", "diagnostic", qos);
|
||||
allSendsSuccessed |= sendHomeAssistantDiscoveryTopic(group, "json", "JSON", "code-json", "", "", "", "diagnostic", qos);
|
||||
allSendsSuccessed |= sendHomeAssistantDiscoveryTopic(group, "problem", "Problem", "alert-outline", "", "problem", "", "", qos); // Special binary sensor which is based on error topic
|
||||
@@ -244,6 +262,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);
|
||||
|
||||
@@ -22,6 +22,7 @@ std::string getTimeUnit(void);
|
||||
void GotConnected(std::string maintopic, bool SetRetainFlag);
|
||||
esp_err_t sendDiscovery_and_static_Topics(void);
|
||||
|
||||
std::string createNodeId(std::string &topic);
|
||||
|
||||
#endif //SERVERMQTT_H
|
||||
#endif //ENABLE_MQTT
|
||||
@@ -12,6 +12,22 @@
|
||||
|
||||
static const char *TAG = "TFLITE";
|
||||
|
||||
|
||||
void CTfLiteClass::MakeStaticResolver()
|
||||
{
|
||||
resolver.AddFullyConnected();
|
||||
resolver.AddReshape();
|
||||
resolver.AddSoftmax();
|
||||
resolver.AddConv2D();
|
||||
resolver.AddMaxPool2D();
|
||||
resolver.AddQuantize();
|
||||
resolver.AddMul();
|
||||
resolver.AddAdd();
|
||||
resolver.AddLeakyRelu();
|
||||
resolver.AddDequantize();
|
||||
}
|
||||
|
||||
|
||||
float CTfLiteClass::GetOutputValue(int nr)
|
||||
{
|
||||
TfLiteTensor* output2 = this->interpreter->output(0);
|
||||
@@ -179,22 +195,23 @@ 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);
|
||||
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Trying to load the model. If it crashes here, it ist most likely due to a corrupted model!");
|
||||
|
||||
if (this->interpreter)
|
||||
{
|
||||
TfLiteStatus allocate_status = this->interpreter->AllocateTensors();
|
||||
if (allocate_status != kTfLiteOk) {
|
||||
TF_LITE_REPORT_ERROR(error_reporter, "AllocateTensors() failed");
|
||||
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "AllocateTensors() failed");
|
||||
|
||||
this->GetInputDimension();
|
||||
@@ -284,12 +301,6 @@ bool CTfLiteClass::ReadFileToModel(std::string _fn)
|
||||
|
||||
bool CTfLiteClass::LoadModel(std::string _fn)
|
||||
{
|
||||
#ifdef SUPRESS_TFLITE_ERRORS
|
||||
this->error_reporter = new tflite::OwnMicroErrorReporter;
|
||||
#else
|
||||
this->error_reporter = new tflite::MicroErrorReporter;
|
||||
#endif
|
||||
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "CTfLiteClass::LoadModel");
|
||||
|
||||
if (!ReadFileToModel(_fn.c_str())) {
|
||||
@@ -320,16 +331,6 @@ CTfLiteClass::CTfLiteClass()
|
||||
CTfLiteClass::~CTfLiteClass()
|
||||
{
|
||||
delete this->interpreter;
|
||||
delete this->error_reporter;
|
||||
|
||||
psram_free_shared_tensor_arena_and_model_memory();
|
||||
}
|
||||
|
||||
|
||||
namespace tflite
|
||||
{
|
||||
int OwnMicroErrorReporter::Report(const char* format, va_list args)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,38 +3,23 @@
|
||||
#ifndef CTFLITECLASS_H
|
||||
#define CTFLITECLASS_H
|
||||
|
||||
#include "tensorflow/lite/micro/all_ops_resolver.h"
|
||||
#include "tensorflow/lite/micro/micro_error_reporter.h"
|
||||
#include "tensorflow/lite/micro/micro_mutable_op_resolver.h"
|
||||
#include "tensorflow/lite/micro/micro_interpreter.h"
|
||||
#include "tensorflow/lite/schema/schema_generated.h"
|
||||
#include "tensorflow/lite/micro/kernels/micro_ops.h"
|
||||
|
||||
#include "esp_err.h"
|
||||
#include "esp_log.h"
|
||||
|
||||
#include "CImageBasis.h"
|
||||
|
||||
#ifdef SUPRESS_TFLITE_ERRORS
|
||||
#include "tensorflow/lite/core/api/error_reporter.h"
|
||||
#include "tensorflow/lite/micro/compatibility.h"
|
||||
#include "tensorflow/lite/micro/debug_log.h"
|
||||
///// OwnErrorReporter to prevent printing of Errors (especially unavoidable in CalculateActivationRangeQuantized@kerne_util.cc)
|
||||
namespace tflite {
|
||||
class OwnMicroErrorReporter : public ErrorReporter {
|
||||
public:
|
||||
int Report(const char* format, va_list args) override;
|
||||
};
|
||||
} // namespace tflite
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
#endif
|
||||
|
||||
class CTfLiteClass
|
||||
{
|
||||
protected:
|
||||
tflite::ErrorReporter *error_reporter;
|
||||
tflite::MicroMutableOpResolver<10> resolver;
|
||||
const tflite::Model* model;
|
||||
tflite::MicroInterpreter* interpreter;
|
||||
TfLiteTensor* output = nullptr;
|
||||
static tflite::AllOpsResolver resolver;
|
||||
|
||||
int kTensorArenaSize;
|
||||
uint8_t *tensor_arena;
|
||||
@@ -48,6 +33,7 @@ class CTfLiteClass
|
||||
|
||||
long GetFileSize(std::string filename);
|
||||
bool ReadFileToModel(std::string _fn);
|
||||
void MakeStaticResolver();
|
||||
|
||||
public:
|
||||
CTfLiteClass();
|
||||
|
||||
@@ -2,6 +2,6 @@ FILE(GLOB_RECURSE app_sources ${CMAKE_CURRENT_SOURCE_DIR}/*.*)
|
||||
|
||||
idf_component_register(SRCS ${app_sources}
|
||||
INCLUDE_DIRS "."
|
||||
REQUIRES tflite-lib jomjol_logfile jomjol_configfile)
|
||||
REQUIRES esp_netif esp-tflite-micro jomjol_logfile jomjol_configfile)
|
||||
|
||||
|
||||
|
||||
@@ -10,7 +10,8 @@
|
||||
#include "esp_log.h"
|
||||
#include "esp_attr.h"
|
||||
#include "esp_sleep.h"
|
||||
#include "esp_sntp.h"
|
||||
#include "esp_netif_sntp.h"
|
||||
|
||||
#include "../../include/defines.h"
|
||||
|
||||
#include "ClassLogFile.h"
|
||||
@@ -31,6 +32,9 @@ std::string getNtpStatusText(sntp_sync_status_t status);
|
||||
static void setTimeZone(std::string _tzstring);
|
||||
static std::string getServerName(void);
|
||||
|
||||
int LocalTimeToUTCOffsetSeconds;
|
||||
|
||||
|
||||
|
||||
std::string ConvertTimeToString(time_t _time, const char * frm)
|
||||
{
|
||||
@@ -89,15 +93,51 @@ bool time_manual_reset_sync(void)
|
||||
}
|
||||
|
||||
|
||||
int getUTCOffsetSeconds(std::string &zeitzone)
|
||||
{
|
||||
int offset = 0;
|
||||
int vorzeichen = 1;
|
||||
int minuten = 0;
|
||||
int stunden = 0;
|
||||
time_t now;
|
||||
struct tm timeinfo;
|
||||
|
||||
time (&now);
|
||||
localtime_r(&now, &timeinfo);
|
||||
char buffer[80];
|
||||
strftime(buffer, 80, "%z", &timeinfo);
|
||||
zeitzone = std::string(buffer);
|
||||
|
||||
if (zeitzone.length() == 5)
|
||||
{
|
||||
if (zeitzone[0] == '-')
|
||||
vorzeichen = -1;
|
||||
|
||||
stunden = stoi(zeitzone.substr(1, 2));
|
||||
minuten = stoi(zeitzone.substr(3, 2));
|
||||
|
||||
offset = ((stunden * 60) + minuten) * 60;
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
|
||||
void setTimeZone(std::string _tzstring)
|
||||
{
|
||||
setenv("TZ", _tzstring.c_str(), 1);
|
||||
tzset();
|
||||
|
||||
_tzstring = "Time zone set to " + _tzstring;
|
||||
LogFile.WriteToFile(ESP_LOG_INFO, TAG, _tzstring);
|
||||
|
||||
std::string zeitzone;
|
||||
LocalTimeToUTCOffsetSeconds = getUTCOffsetSeconds(zeitzone);
|
||||
// std::string zw = std::to_string(LocalTimeToUTCOffsetSeconds);
|
||||
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "time zone: " + zeitzone + " Delta to UTC: " + std::to_string(LocalTimeToUTCOffsetSeconds) + " seconds");
|
||||
}
|
||||
|
||||
|
||||
|
||||
std::string getNtpStatusText(sntp_sync_status_t status) {
|
||||
if (status == SNTP_SYNC_STATUS_COMPLETED) {
|
||||
return "Synchronized";
|
||||
@@ -235,21 +275,13 @@ bool setupTime() {
|
||||
|
||||
if (useNtp) {
|
||||
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Configuring NTP Client...");
|
||||
sntp_setoperatingmode(SNTP_OPMODE_POLL);
|
||||
sntp_setservername(0, timeServer.c_str());
|
||||
sntp_set_time_sync_notification_cb(time_sync_notification_cb);
|
||||
esp_sntp_config_t config = ESP_NETIF_SNTP_DEFAULT_CONFIG(timeServer.c_str());
|
||||
config.sync_cb = time_sync_notification_cb;
|
||||
esp_netif_sntp_init(&config);
|
||||
|
||||
setTimeZone(timeZone);
|
||||
|
||||
sntp_init();
|
||||
/*
|
||||
if (!wait_for_timesync())
|
||||
{
|
||||
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Timesync at startup failed.");
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
/* The RTC keeps the time after a restart (Except on Power On or Pin Reset)
|
||||
* There should only be a minor correction through NTP */
|
||||
|
||||
@@ -258,6 +290,7 @@ bool setupTime() {
|
||||
localtime_r(&now, &timeinfo);
|
||||
strftime(strftime_buf, sizeof(strftime_buf), "%Y-%m-%d %H:%M:%S", &timeinfo);
|
||||
|
||||
|
||||
if (getTimeIsSet()) {
|
||||
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Time is already set: " + std::string(strftime_buf));
|
||||
}
|
||||
|
||||
@@ -28,5 +28,7 @@ bool setupTime();
|
||||
|
||||
bool time_manual_reset_sync(void);
|
||||
|
||||
extern int LocalTimeToUTCOffsetSeconds;
|
||||
|
||||
|
||||
#endif //TIMESNTP_H
|
||||
7
code/components/jomjol_webhook/CMakeLists.txt
Normal file
7
code/components/jomjol_webhook/CMakeLists.txt
Normal file
@@ -0,0 +1,7 @@
|
||||
FILE(GLOB_RECURSE app_sources ${CMAKE_CURRENT_SOURCE_DIR}/*.*)
|
||||
|
||||
idf_component_register(SRCS ${app_sources}
|
||||
INCLUDE_DIRS "."
|
||||
REQUIRES esp_http_client jomjol_logfile jomjol_flowcontroll json)
|
||||
|
||||
|
||||
170
code/components/jomjol_webhook/interface_webhook.cpp
Normal file
170
code/components/jomjol_webhook/interface_webhook.cpp
Normal file
@@ -0,0 +1,170 @@
|
||||
#ifdef ENABLE_WEBHOOK
|
||||
#include "interface_webhook.h"
|
||||
|
||||
#include "esp_log.h"
|
||||
#include <time.h>
|
||||
#include "ClassLogFile.h"
|
||||
#include "esp_http_client.h"
|
||||
#include "time_sntp.h"
|
||||
#include "../../include/defines.h"
|
||||
#include <cJSON.h>
|
||||
#include <ClassFlowDefineTypes.h>
|
||||
|
||||
|
||||
static const char *TAG = "WEBHOOK";
|
||||
|
||||
std::string _webhookURI;
|
||||
std::string _webhookApiKey;
|
||||
long _lastTimestamp;
|
||||
|
||||
static esp_err_t http_event_handler(esp_http_client_event_t *evt);
|
||||
|
||||
void WebhookInit(std::string _uri, std::string _apiKey)
|
||||
{
|
||||
_webhookURI = _uri;
|
||||
_webhookApiKey = _apiKey;
|
||||
_lastTimestamp = 0L;
|
||||
}
|
||||
|
||||
bool WebhookPublish(std::vector<NumberPost*>* numbers)
|
||||
{
|
||||
bool numbersWithError = false;
|
||||
cJSON *jsonArray = cJSON_CreateArray();
|
||||
|
||||
for (int i = 0; i < (*numbers).size(); ++i)
|
||||
{
|
||||
string timezw = "";
|
||||
char buffer[80];
|
||||
time_t &lastPreValue = (*numbers)[i]->timeStampLastPreValue;
|
||||
struct tm* timeinfo = localtime(&lastPreValue);
|
||||
_lastTimestamp = static_cast<long>(lastPreValue);
|
||||
strftime(buffer, 80, PREVALUE_TIME_FORMAT_OUTPUT, timeinfo);
|
||||
timezw = std::string(buffer);
|
||||
|
||||
cJSON *json = cJSON_CreateObject();
|
||||
cJSON_AddStringToObject(json, "timestamp", timezw.c_str());
|
||||
cJSON_AddStringToObject(json, "timestampLong", std::to_string(_lastTimestamp).c_str());
|
||||
cJSON_AddStringToObject(json, "name", (*numbers)[i]->name.c_str());
|
||||
cJSON_AddStringToObject(json, "rawValue", (*numbers)[i]->ReturnRawValue.c_str());
|
||||
cJSON_AddStringToObject(json, "value", (*numbers)[i]->ReturnValue.c_str());
|
||||
cJSON_AddStringToObject(json, "preValue", (*numbers)[i]->ReturnPreValue.c_str());
|
||||
cJSON_AddStringToObject(json, "rate", (*numbers)[i]->ReturnRateValue.c_str());
|
||||
cJSON_AddStringToObject(json, "changeAbsolute", (*numbers)[i]->ReturnChangeAbsolute.c_str());
|
||||
cJSON_AddStringToObject(json, "error", (*numbers)[i]->ErrorMessageText.c_str());
|
||||
|
||||
cJSON_AddItemToArray(jsonArray, json);
|
||||
|
||||
if ((*numbers)[i]->ErrorMessage) {
|
||||
numbersWithError = true;
|
||||
}
|
||||
}
|
||||
|
||||
char *jsonString = cJSON_PrintUnformatted(jsonArray);
|
||||
|
||||
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "sending webhook");
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "sending JSON: " + std::string(jsonString));
|
||||
|
||||
char response_buffer[MAX_HTTP_OUTPUT_BUFFER] = {0};
|
||||
esp_http_client_config_t http_config = {
|
||||
.url = _webhookURI.c_str(),
|
||||
.user_agent = "ESP32 Meter reader",
|
||||
.method = HTTP_METHOD_POST,
|
||||
.event_handler = http_event_handler,
|
||||
.buffer_size = MAX_HTTP_OUTPUT_BUFFER,
|
||||
.user_data = response_buffer
|
||||
};
|
||||
|
||||
esp_http_client_handle_t http_client = esp_http_client_init(&http_config);
|
||||
|
||||
esp_http_client_set_header(http_client, "Content-Type", "application/json");
|
||||
esp_http_client_set_header(http_client, "APIKEY", _webhookApiKey.c_str());
|
||||
|
||||
ESP_ERROR_CHECK(esp_http_client_set_post_field(http_client, jsonString, strlen(jsonString)));
|
||||
|
||||
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_ERROR, TAG, "HTTP request failed");
|
||||
}
|
||||
|
||||
esp_http_client_cleanup(http_client);
|
||||
cJSON_Delete(jsonArray);
|
||||
free(jsonString);
|
||||
return numbersWithError;
|
||||
}
|
||||
|
||||
void WebhookUploadPic(ImageData *Img) {
|
||||
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Starting WebhookUploadPic");
|
||||
|
||||
std::string fullURI = _webhookURI + "?timestamp=" + std::to_string(_lastTimestamp);
|
||||
char response_buffer[MAX_HTTP_OUTPUT_BUFFER] = {0};
|
||||
esp_http_client_config_t http_config = {
|
||||
.url = fullURI.c_str(),
|
||||
.user_agent = "ESP32 Meter reader",
|
||||
.method = HTTP_METHOD_PUT,
|
||||
.event_handler = http_event_handler,
|
||||
.buffer_size = MAX_HTTP_OUTPUT_BUFFER,
|
||||
.user_data = response_buffer
|
||||
};
|
||||
|
||||
esp_http_client_handle_t http_client = esp_http_client_init(&http_config);
|
||||
|
||||
esp_http_client_set_header(http_client, "Content-Type", "image/jpeg");
|
||||
esp_http_client_set_header(http_client, "APIKEY", _webhookApiKey.c_str());
|
||||
|
||||
esp_err_t err = ESP_ERROR_CHECK_WITHOUT_ABORT(esp_http_client_set_post_field(http_client, (const char *)Img->data, Img->size));
|
||||
|
||||
err = ESP_ERROR_CHECK_WITHOUT_ABORT(esp_http_client_perform(http_client));
|
||||
|
||||
if (err == ESP_OK) {
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "HTTP PUT request was performed successfully");
|
||||
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_ERROR, TAG, "HTTP PUT request failed");
|
||||
}
|
||||
|
||||
esp_http_client_cleanup(http_client);
|
||||
|
||||
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "WebhookUploadPic finished");
|
||||
}
|
||||
|
||||
|
||||
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 connected");
|
||||
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;
|
||||
case HTTP_EVENT_REDIRECT:
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "HTTP Redirect");
|
||||
break;
|
||||
}
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
#endif //ENABLE_WEBHOOK
|
||||
17
code/components/jomjol_webhook/interface_webhook.h
Normal file
17
code/components/jomjol_webhook/interface_webhook.h
Normal file
@@ -0,0 +1,17 @@
|
||||
#ifdef ENABLE_WEBHOOK
|
||||
|
||||
#pragma once
|
||||
#ifndef INTERFACE_WEBHOOK_H
|
||||
#define INTERFACE_WEBHOOK_H
|
||||
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <functional>
|
||||
#include <ClassFlowDefineTypes.h>
|
||||
|
||||
void WebhookInit(std::string _webhookURI, std::string _apiKey);
|
||||
bool WebhookPublish(std::vector<NumberPost*>* numbers);
|
||||
void WebhookUploadPic(ImageData *Img);
|
||||
|
||||
#endif //INTERFACE_WEBHOOK_H
|
||||
#endif //ENABLE_WEBHOOK
|
||||
@@ -378,7 +378,7 @@ void wifi_scan(void)
|
||||
else {
|
||||
if (esp_wifi_scan_get_ap_records(&max_number_of_ap_found, wifi_ap_records) != ESP_OK) { // Retrieve results (and free internal heap)
|
||||
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "wifi_scan: esp_wifi_scan_get_ap_records: Error retrieving datasets");
|
||||
delete wifi_ap_records;
|
||||
delete[] wifi_ap_records;
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -401,7 +401,7 @@ void wifi_scan(void)
|
||||
APWithBetterRSSI = true;
|
||||
}
|
||||
}
|
||||
delete wifi_ap_records;
|
||||
delete[] wifi_ap_records;
|
||||
}
|
||||
|
||||
|
||||
@@ -480,7 +480,8 @@ static void event_handler(void* arg, esp_event_base_t event_base, int32_t event_
|
||||
if (WIFIReconnectCnt >= 10) {
|
||||
WIFIReconnectCnt = 0;
|
||||
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Disconnected, multiple reconnect attempts failed (" +
|
||||
std::to_string(disconn->reason) + "), still retrying...");
|
||||
std::to_string(disconn->reason) + "), retrying after 5s");
|
||||
vTaskDelay(5000 / portTICK_PERIOD_MS); // Delay between the reconnections
|
||||
}
|
||||
}
|
||||
else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_CONNECTED)
|
||||
|
||||
7
code/components/openmetrics/CMakeLists.txt
Normal file
7
code/components/openmetrics/CMakeLists.txt
Normal file
@@ -0,0 +1,7 @@
|
||||
FILE(GLOB_RECURSE app_sources ${CMAKE_CURRENT_SOURCE_DIR}/*.*)
|
||||
|
||||
idf_component_register(SRCS ${app_sources}
|
||||
INCLUDE_DIRS "."
|
||||
REQUIRES jomjol_image_proc)
|
||||
|
||||
|
||||
43
code/components/openmetrics/openmetrics.cpp
Normal file
43
code/components/openmetrics/openmetrics.cpp
Normal file
@@ -0,0 +1,43 @@
|
||||
#include "openmetrics.h"
|
||||
|
||||
/**
|
||||
* create a singe metric from the given input
|
||||
**/
|
||||
std::string createMetric(const std::string &metricName, const std::string &help, const std::string &type, const std::string &value)
|
||||
{
|
||||
return "# HELP " + metricName + " " + help + "\n" +
|
||||
"# TYPE " + metricName + " " + type + "\n" +
|
||||
metricName + " " + value + "\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the MetricFamily from all available sequences
|
||||
* @returns the string containing the text wire format of the MetricFamily
|
||||
**/
|
||||
std::string createSequenceMetrics(std::string prefix, const std::vector<NumberPost *> &numbers)
|
||||
{
|
||||
std::string res;
|
||||
|
||||
for (const auto &number : numbers)
|
||||
{
|
||||
// only valid data is reported (https://github.com/OpenObservability/OpenMetrics/blob/main/specification/OpenMetrics.md#missing-data)
|
||||
if (number->ReturnValue.length() > 0)
|
||||
{
|
||||
auto label = number->name;
|
||||
|
||||
// except newline, double quote, and backslash (https://github.com/OpenObservability/OpenMetrics/blob/main/specification/OpenMetrics.md#abnf)
|
||||
// to keep it simple, these characters are just removed from the label
|
||||
replaceAll(label, "\\", "");
|
||||
replaceAll(label, "\"", "");
|
||||
replaceAll(label, "\n", "");
|
||||
res += prefix + "_flow_value{sequence=\"" + label + "\"} " + number->ReturnValue + "\n";
|
||||
}
|
||||
}
|
||||
|
||||
// prepend metadata if a valid metric was created
|
||||
if (res.length() > 0)
|
||||
{
|
||||
res = "# HELP " + prefix + "_flow_value current value of meter readout\n# TYPE " + prefix + "_flow_value gauge\n" + res;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
15
code/components/openmetrics/openmetrics.h
Normal file
15
code/components/openmetrics/openmetrics.h
Normal file
@@ -0,0 +1,15 @@
|
||||
#pragma once
|
||||
|
||||
#ifndef OPENMETRICS_H
|
||||
#define OPENMETRICS_H
|
||||
|
||||
#include <string>
|
||||
#include <fstream>
|
||||
#include <vector>
|
||||
|
||||
#include "ClassFlowDefineTypes.h"
|
||||
|
||||
std::string createMetric(const std::string &metricName, const std::string &help, const std::string &type, const std::string &value);
|
||||
std::string createSequenceMetrics(std::string prefix, const std::vector<NumberPost *> &numbers);
|
||||
|
||||
#endif // OPENMETRICS_H
|
||||
Submodule code/components/tflite-micro-esp-examples deleted from 095f55a6ee
@@ -1,3 +1,16 @@
|
||||
manifest_hash: 63f5c6c9f0bcebc7b9ca12d2aa8b26b2c5f5218d377dc4b2375d9b9ca1df7815
|
||||
dependencies:
|
||||
espressif/esp-nn:
|
||||
component_hash: b32869798bdb40dec6bc99caca48cd65d42f8a9f506b9ab9c598a076f891ede9
|
||||
source:
|
||||
pre_release: true
|
||||
service_url: https://api.components.espressif.com/
|
||||
type: service
|
||||
version: 1.0.2
|
||||
idf:
|
||||
component_hash: null
|
||||
source:
|
||||
type: idf
|
||||
version: 5.3.0
|
||||
manifest_hash: 6995555b9b41e897235448c868ca92c0c3401fd2ff90df084be9bb8629958f2c
|
||||
target: esp32
|
||||
version: 1.0.0
|
||||
|
||||
@@ -53,24 +53,14 @@
|
||||
|
||||
//****************************************
|
||||
|
||||
//compiler optimization for tflite-micro-esp-examples
|
||||
//compiler optimization for esp-tflite-micro
|
||||
#define XTENSA
|
||||
//#define CONFIG_IDF_TARGET_ARCH_XTENSA //not needed with platformio/espressif32 @ 5.2.0
|
||||
|
||||
|
||||
//Statusled + ClassControllCamera
|
||||
#define BLINK_GPIO GPIO_NUM_33 // PIN for red board LED
|
||||
|
||||
|
||||
//ClassControllCamera
|
||||
#define FLASH_GPIO GPIO_NUM_4 // PIN for flashlight LED
|
||||
#define USE_PWM_LEDFLASH // if __LEDGLOBAL is defined, a global variable is used for LED control, otherwise locally and each time a new
|
||||
#define CAM_LIVESTREAM_REFRESHRATE 500 // Camera livestream feature: Waiting time in milliseconds to refresh image
|
||||
|
||||
|
||||
//ClassControllCamera + ClassFlowTakeImage
|
||||
#define CAMERA_MODEL_AI_THINKER
|
||||
#define BOARD_ESP32CAM_AITHINKER
|
||||
// #define GRAYSCALE_AS_DEFAULT
|
||||
|
||||
|
||||
//server_GPIO
|
||||
@@ -104,7 +94,7 @@
|
||||
#define LOGFILE_LAST_PART_BYTES 80 * 1024 // 80 kBytes // Size of partial log file to return
|
||||
|
||||
#define SERVER_FILER_SCRATCH_BUFSIZE 4096
|
||||
#define SERVER_HELPER_SCRATCH_BUFSIZE 8192
|
||||
#define SERVER_HELPER_SCRATCH_BUFSIZE 4096
|
||||
#define SERVER_OTA_SCRATCH_BUFSIZE 1024
|
||||
|
||||
|
||||
@@ -167,15 +157,6 @@
|
||||
#define LWT_DISCONNECTED "connection lost"
|
||||
|
||||
|
||||
//CTfLiteClass
|
||||
#define TFLITE_MINIMAL_CHECK(x) \
|
||||
if (!(x)) { \
|
||||
fprintf(stderr, "Error at %s:%d\n", __FILE__, __LINE__); \
|
||||
exit(1); \
|
||||
}
|
||||
#define SUPRESS_TFLITE_ERRORS // use, to avoid error messages from TFLITE
|
||||
|
||||
|
||||
// connect_wlan.cpp
|
||||
//******************************
|
||||
/* WIFI roaming functionalities 802.11k+v (uses ca. 6kB - 8kB internal RAM; if SCAN CACHE activated: + 1kB / beacon)
|
||||
@@ -195,15 +176,13 @@
|
||||
|
||||
//ClassFlowCNNGeneral
|
||||
#define Analog_error 3
|
||||
|
||||
#define AnalogToDigtalFehler 0.8
|
||||
#define Digital_Uncertainty 0.2
|
||||
#define DigitalBand 3
|
||||
#define Digital_Transition_Range_Predecessor 2
|
||||
#define Digital_Transition_Area_Predecessor 0.7 // 9.3 - 0.7
|
||||
#define Digital_Transition_Area_Forward 9.7 // Pre-run zero crossing only happens from approx. 9.7 onwards
|
||||
|
||||
|
||||
|
||||
#define Digit_Uncertainty 0.2
|
||||
#define DigitBand 3
|
||||
#define Digit_Transition_Range_Predecessor 2
|
||||
#define Digit_Transition_Area_Predecessor 0.7 // 9.3 - 0.7
|
||||
#define Digit_Transition_Area_Forward 9.7 // Pre-run zero crossing only happens from approx. 9.7 onwards
|
||||
|
||||
//#define DEBUG_DETAIL_ON
|
||||
|
||||
@@ -218,117 +197,124 @@
|
||||
//// Conditionnal definitions ////
|
||||
/////////////////////////////////////////////
|
||||
|
||||
//******* camera model
|
||||
#if defined(CAMERA_MODEL_WROVER_KIT)
|
||||
#define PWDN_GPIO_NUM -1
|
||||
#define RESET_GPIO_NUM -1
|
||||
#define XCLK_GPIO_NUM 21
|
||||
#define SIOD_GPIO_NUM 26
|
||||
#define SIOC_GPIO_NUM 27
|
||||
|
||||
#define Y9_GPIO_NUM 35
|
||||
#define Y8_GPIO_NUM 34
|
||||
#define Y7_GPIO_NUM 39
|
||||
#define Y6_GPIO_NUM 36
|
||||
#define Y5_GPIO_NUM 19
|
||||
#define Y4_GPIO_NUM 18
|
||||
#define Y3_GPIO_NUM 5
|
||||
#define Y2_GPIO_NUM 4
|
||||
#define VSYNC_GPIO_NUM 25
|
||||
#define HREF_GPIO_NUM 23
|
||||
#define PCLK_GPIO_NUM 22
|
||||
|
||||
#elif defined(CAMERA_MODEL_M5STACK_PSRAM)
|
||||
#define PWDN_GPIO_NUM -1
|
||||
#define RESET_GPIO_NUM 15
|
||||
#define XCLK_GPIO_NUM 27
|
||||
#define SIOD_GPIO_NUM 25
|
||||
#define SIOC_GPIO_NUM 23
|
||||
|
||||
#define Y9_GPIO_NUM 19
|
||||
#define Y8_GPIO_NUM 36
|
||||
#define Y7_GPIO_NUM 18
|
||||
#define Y6_GPIO_NUM 39
|
||||
#define Y5_GPIO_NUM 5
|
||||
#define Y4_GPIO_NUM 34
|
||||
#define Y3_GPIO_NUM 35
|
||||
#define Y2_GPIO_NUM 32
|
||||
#define VSYNC_GPIO_NUM 22
|
||||
#define HREF_GPIO_NUM 26
|
||||
#define PCLK_GPIO_NUM 21
|
||||
|
||||
#elif defined(CAMERA_MODEL_AI_THINKER)
|
||||
#define PWDN_GPIO_NUM GPIO_NUM_32
|
||||
#define RESET_GPIO_NUM -1
|
||||
#define XCLK_GPIO_NUM GPIO_NUM_0
|
||||
#define SIOD_GPIO_NUM GPIO_NUM_26
|
||||
#define SIOC_GPIO_NUM GPIO_NUM_27
|
||||
|
||||
#define Y9_GPIO_NUM GPIO_NUM_35
|
||||
#define Y8_GPIO_NUM GPIO_NUM_34
|
||||
#define Y7_GPIO_NUM GPIO_NUM_39
|
||||
#define Y6_GPIO_NUM GPIO_NUM_36
|
||||
#define Y5_GPIO_NUM GPIO_NUM_21
|
||||
#define Y4_GPIO_NUM GPIO_NUM_19
|
||||
#define Y3_GPIO_NUM GPIO_NUM_18
|
||||
#define Y2_GPIO_NUM GPIO_NUM_5
|
||||
#define VSYNC_GPIO_NUM GPIO_NUM_25
|
||||
#define HREF_GPIO_NUM GPIO_NUM_23
|
||||
#define PCLK_GPIO_NUM GPIO_NUM_22
|
||||
|
||||
#else
|
||||
#error "Camera model not selected"
|
||||
#endif //camera model
|
||||
|
||||
// ******* Board type
|
||||
#ifdef BOARD_WROVER_KIT // WROVER-KIT PIN Map
|
||||
#if defined(BOARD_WROVER_KIT) // WROVER-KIT PIN Map
|
||||
// SD card (operated with SDMMC peripheral)
|
||||
//-------------------------------------------------
|
||||
#define GPIO_SDCARD_CLK GPIO_NUM_14
|
||||
#define GPIO_SDCARD_CMD GPIO_NUM_15
|
||||
#define GPIO_SDCARD_D0 GPIO_NUM_2
|
||||
#ifndef __SD_USE_ONE_LINE_MODE__
|
||||
#define GPIO_SDCARD_D1 GPIO_NUM_4
|
||||
#define GPIO_SDCARD_D2 GPIO_NUM_12
|
||||
#define GPIO_SDCARD_D3 GPIO_NUM_13
|
||||
#else
|
||||
#define GPIO_SDCARD_D1 GPIO_NUM_NC
|
||||
#define GPIO_SDCARD_D2 GPIO_NUM_NC
|
||||
#define GPIO_SDCARD_D3 GPIO_NUM_13
|
||||
#endif
|
||||
|
||||
#define CAM_PIN_PWDN -1 //power down is not used
|
||||
#define CAM_PIN_RESET -1 //software reset will be performed
|
||||
#define CAM_PIN_XCLK 21
|
||||
#define CAM_PIN_SIOD 26
|
||||
#define CAM_PIN_SIOC 27
|
||||
#define CAM_PIN_PWDN GPIO_NUM_NC //power down is not used
|
||||
#define CAM_PIN_RESET GPIO_NUM_NC //software reset will be performed
|
||||
#define CAM_PIN_XCLK GPIO_NUM_21
|
||||
#define CAM_PIN_SIOD GPIO_NUM_26
|
||||
#define CAM_PIN_SIOC GPIO_NUM_27
|
||||
|
||||
#define CAM_PIN_D7 35
|
||||
#define CAM_PIN_D6 34
|
||||
#define CAM_PIN_D5 39
|
||||
#define CAM_PIN_D4 36
|
||||
#define CAM_PIN_D3 19
|
||||
#define CAM_PIN_D2 18
|
||||
#define CAM_PIN_D1 5
|
||||
#define CAM_PIN_D0 4
|
||||
#define CAM_PIN_VSYNC 25
|
||||
#define CAM_PIN_HREF 23
|
||||
#define CAM_PIN_PCLK 22
|
||||
#define CAM_PIN_D7 GPIO_NUM_35
|
||||
#define CAM_PIN_D6 GPIO_NUM_34
|
||||
#define CAM_PIN_D5 GPIO_NUM_39
|
||||
#define CAM_PIN_D4 GPIO_NUM_36
|
||||
#define CAM_PIN_D3 GPIO_NUM_19
|
||||
#define CAM_PIN_D2 GPIO_NUM_18
|
||||
#define CAM_PIN_D1 GPIO_NUM_5
|
||||
#define CAM_PIN_D0 GPIO_NUM_4
|
||||
#define CAM_PIN_VSYNC GPIO_NUM_25
|
||||
#define CAM_PIN_HREF GPIO_NUM_23
|
||||
#define CAM_PIN_PCLK GPIO_NUM_22
|
||||
|
||||
#endif //// WROVER-KIT PIN Map
|
||||
//Statusled + ClassControllCamera
|
||||
#define BLINK_GPIO GPIO_NUM_33 // PIN for red board LED, On the board the LED is on the IO2, but it is used for the SD
|
||||
|
||||
//ClassControllCamera
|
||||
#define FLASH_GPIO GPIO_NUM_12 // PIN for flashlight LED
|
||||
#define USE_PWM_LEDFLASH // if __LEDGLOBAL is defined, a global variable is used for LED control, otherwise locally and each time a new
|
||||
|
||||
|
||||
#ifdef BOARD_ESP32CAM_AITHINKER // ESP32Cam (AiThinker) PIN Map
|
||||
#elif defined(BOARD_M5STACK_PSRAM) // M5STACK PSRAM PIN Map
|
||||
#define CAM_PIN_PWDN GPIO_NUM_NC
|
||||
#define CAM_PIN_RESET GPIO_NUM_15
|
||||
#define CAM_PIN_XCLK GPIO_NUM_27
|
||||
#define CAM_PIN_SIOD GPIO_NUM_25
|
||||
#define CAM_PIN_SIOC GPIO_NUM_23
|
||||
|
||||
#define CAM_PIN_PWDN 32
|
||||
#define CAM_PIN_RESET -1 //software reset will be performed
|
||||
#define CAM_PIN_XCLK 0
|
||||
#define CAM_PIN_SIOD 26
|
||||
#define CAM_PIN_SIOC 27
|
||||
#define CAM_PIN_D7 GPIO_NUM_19
|
||||
#define CAM_PIN_D6 GPIO_NUM_36
|
||||
#define CAM_PIN_D5 GPIO_NUM_18
|
||||
#define CAM_PIN_D4 GPIO_NUM_39
|
||||
#define CAM_PIN_D3 GPIO_NUM_5
|
||||
#define CAM_PIN_D2 GPIO_NUM_34
|
||||
#define CAM_PIN_D1 GPIO_NUM_35
|
||||
#define CAM_PIN_D0 GPIO_NUM_32
|
||||
#define CAM_PIN_VSYNC GPIO_NUM_22
|
||||
#define CAM_PIN_HREF GPIO_NUM_26
|
||||
#define CAM_PIN_PCLK GPIO_NUM_21
|
||||
|
||||
#define CAM_PIN_D7 35
|
||||
#define CAM_PIN_D6 34
|
||||
#define CAM_PIN_D5 39
|
||||
#define CAM_PIN_D4 36
|
||||
#define CAM_PIN_D3 21
|
||||
#define CAM_PIN_D2 19
|
||||
#define CAM_PIN_D1 18
|
||||
#define CAM_PIN_D0 5
|
||||
#define CAM_PIN_VSYNC 25
|
||||
#define CAM_PIN_HREF 23
|
||||
#define CAM_PIN_PCLK 22
|
||||
//Statusled + ClassControllCamera
|
||||
#define BLINK_GPIO GPIO_NUM_33 // PIN for red board LED
|
||||
|
||||
//ClassControllCamera
|
||||
#define FLASH_GPIO GPIO_NUM_4 // PIN for flashlight LED
|
||||
#define USE_PWM_LEDFLASH // if __LEDGLOBAL is defined, a global variable is used for LED control, otherwise locally and each time a new
|
||||
|
||||
|
||||
#elif defined(BOARD_ESP32CAM_AITHINKER) // ESP32Cam (AiThinker) PIN Map
|
||||
// SD card (operated with SDMMC peripheral)
|
||||
//-------------------------------------------------
|
||||
#define GPIO_SDCARD_CLK GPIO_NUM_14
|
||||
#define GPIO_SDCARD_CMD GPIO_NUM_15
|
||||
#define GPIO_SDCARD_D0 GPIO_NUM_2
|
||||
#ifndef __SD_USE_ONE_LINE_MODE__
|
||||
#define GPIO_SDCARD_D1 GPIO_NUM_4
|
||||
#define GPIO_SDCARD_D2 GPIO_NUM_12
|
||||
#define GPIO_SDCARD_D3 GPIO_NUM_13
|
||||
#else
|
||||
#define GPIO_SDCARD_D1 GPIO_NUM_NC
|
||||
#define GPIO_SDCARD_D2 GPIO_NUM_NC
|
||||
#define GPIO_SDCARD_D3 GPIO_NUM_13
|
||||
#endif
|
||||
|
||||
#define CAM_PIN_PWDN GPIO_NUM_32
|
||||
#define CAM_PIN_RESET GPIO_NUM_NC //software reset will be performed
|
||||
#define CAM_PIN_XCLK GPIO_NUM_0
|
||||
#define CAM_PIN_SIOD GPIO_NUM_26
|
||||
#define CAM_PIN_SIOC GPIO_NUM_27
|
||||
|
||||
#define CAM_PIN_D7 GPIO_NUM_35
|
||||
#define CAM_PIN_D6 GPIO_NUM_34
|
||||
#define CAM_PIN_D5 GPIO_NUM_39
|
||||
#define CAM_PIN_D4 GPIO_NUM_36
|
||||
#define CAM_PIN_D3 GPIO_NUM_21
|
||||
#define CAM_PIN_D2 GPIO_NUM_19
|
||||
#define CAM_PIN_D1 GPIO_NUM_18
|
||||
#define CAM_PIN_D0 GPIO_NUM_5
|
||||
#define CAM_PIN_VSYNC GPIO_NUM_25
|
||||
#define CAM_PIN_HREF GPIO_NUM_23
|
||||
#define CAM_PIN_PCLK GPIO_NUM_22
|
||||
|
||||
//Statusled + ClassControllCamera
|
||||
#define BLINK_GPIO GPIO_NUM_33 // PIN for red board LED
|
||||
|
||||
//ClassControllCamera
|
||||
#define FLASH_GPIO GPIO_NUM_4 // PIN for flashlight LED
|
||||
#define USE_PWM_LEDFLASH // if __LEDGLOBAL is defined, a global variable is used for LED control, otherwise locally and each time a new
|
||||
|
||||
#else
|
||||
#error "Board not selected"
|
||||
#endif //Board PIN Map
|
||||
|
||||
#endif // ESP32Cam (AiThinker) PIN Map
|
||||
|
||||
// ******* LED definition
|
||||
#ifdef USE_PWM_LEDFLASH
|
||||
|
||||
//// PWM für Flash-LED
|
||||
#define LEDC_TIMER LEDC_TIMER_1 // LEDC_TIMER_0
|
||||
#define LEDC_MODE LEDC_LOW_SPEED_MODE
|
||||
@@ -340,6 +326,7 @@
|
||||
|
||||
#endif //USE_PWM_LEDFLASH
|
||||
|
||||
|
||||
//softAP
|
||||
#ifdef ENABLE_SOFTAP
|
||||
#define EXAMPLE_ESP_WIFI_SSID "AI-on-the-Edge"
|
||||
|
||||
@@ -3,12 +3,6 @@
|
||||
#include <vector>
|
||||
#include <regex>
|
||||
|
||||
//#include "freertos/FreeRTOS.h"
|
||||
//#include "freertos/task.h"
|
||||
//#include "freertos/event_groups.h"
|
||||
|
||||
//#include "driver/gpio.h"
|
||||
//#include "sdkconfig.h"
|
||||
#include "esp_psram.h"
|
||||
#include "esp_pm.h"
|
||||
|
||||
@@ -16,16 +10,15 @@
|
||||
|
||||
#include "esp_chip_info.h"
|
||||
|
||||
|
||||
|
||||
// SD-Card ////////////////////
|
||||
//#include "nvs_flash.h"
|
||||
#include "esp_vfs_fat.h"
|
||||
//#include "sdmmc_cmd.h"
|
||||
#include "ffconf.h"
|
||||
#include "driver/sdmmc_host.h"
|
||||
//#include "driver/sdmmc_defs.h"
|
||||
///////////////////////////////
|
||||
|
||||
#if (ESP_IDF_VERSION <= ESP_IDF_VERSION_VAL(5, 1, 2))
|
||||
#include "sdcard_init.h"
|
||||
#endif
|
||||
///////////////////////////////
|
||||
|
||||
#include "ClassLogFile.h"
|
||||
|
||||
@@ -38,7 +31,6 @@
|
||||
#include "server_ota.h"
|
||||
#include "time_sntp.h"
|
||||
#include "configFile.h"
|
||||
//#include "ClassControllCamera.h"
|
||||
#include "server_main.h"
|
||||
#include "server_camera.h"
|
||||
#ifdef ENABLE_MQTT
|
||||
@@ -49,7 +41,6 @@
|
||||
#include "sdcard_check.h"
|
||||
|
||||
#include "../../include/defines.h"
|
||||
//#include "server_GPIO.h"
|
||||
|
||||
#ifdef ENABLE_SOFTAP
|
||||
#include "softAP.h"
|
||||
@@ -101,10 +92,12 @@ bool setCpuFrequency(void);
|
||||
|
||||
static const char *TAG = "MAIN";
|
||||
|
||||
#define MOUNT_POINT "/sdcard"
|
||||
|
||||
bool Init_NVS_SDCard()
|
||||
{
|
||||
esp_err_t ret = nvs_flash_init();
|
||||
|
||||
if (ret == ESP_ERR_NVS_NO_FREE_PAGES) {
|
||||
ESP_ERROR_CHECK(nvs_flash_erase());
|
||||
ret = nvs_flash_init();
|
||||
@@ -112,26 +105,41 @@ bool Init_NVS_SDCard()
|
||||
|
||||
ESP_LOGD(TAG, "Using SDMMC peripheral");
|
||||
sdmmc_host_t host = SDMMC_HOST_DEFAULT();
|
||||
host.max_freq_khz = SDMMC_FREQ_HIGHSPEED;
|
||||
|
||||
// This initializes the slot without card detect (CD) and write protect (WP) signals.
|
||||
// Modify slot_config.gpio_cd and slot_config.gpio_wp if your board has these signals.
|
||||
sdmmc_slot_config_t slot_config = SDMMC_SLOT_CONFIG_DEFAULT();
|
||||
|
||||
// To use 1-line SD mode, uncomment the following line:
|
||||
#ifdef __SD_USE_ONE_LINE_MODE__
|
||||
slot_config.width = 1;
|
||||
#endif
|
||||
// Set bus width to use:
|
||||
#ifdef __SD_USE_ONE_LINE_MODE__
|
||||
slot_config.width = 1;
|
||||
#ifdef SOC_SDMMC_USE_GPIO_MATRIX
|
||||
slot_config.clk = GPIO_SDCARD_CLK;
|
||||
slot_config.cmd = GPIO_SDCARD_CMD;
|
||||
slot_config.d0 = GPIO_SDCARD_D0;
|
||||
#endif
|
||||
|
||||
// GPIOs 15, 2, 4, 12, 13 should have external 10k pull-ups.
|
||||
// Internal pull-ups are not sufficient. However, enabling internal pull-ups
|
||||
// does make a difference some boards, so we do that here.
|
||||
gpio_set_pull_mode(GPIO_NUM_15, GPIO_PULLUP_ONLY); // CMD, needed in 4- and 1- line modes
|
||||
gpio_set_pull_mode(GPIO_NUM_2, GPIO_PULLUP_ONLY); // D0, needed in 4- and 1-line modes
|
||||
#ifndef __SD_USE_ONE_LINE_MODE__
|
||||
gpio_set_pull_mode(GPIO_NUM_4, GPIO_PULLUP_ONLY); // D1, needed in 4-line mode only
|
||||
gpio_set_pull_mode(GPIO_NUM_12, GPIO_PULLUP_ONLY); // D2, needed in 4-line mode only
|
||||
#endif
|
||||
gpio_set_pull_mode(GPIO_NUM_13, GPIO_PULLUP_ONLY); // D3, needed in 4- and 1-line modes
|
||||
#else
|
||||
slot_config.width = 4;
|
||||
#ifdef SOC_SDMMC_USE_GPIO_MATRIX
|
||||
slot_config.d1 = GPIO_SDCARD_D1;
|
||||
slot_config.d2 = GPIO_SDCARD_D2;
|
||||
slot_config.d3 = GPIO_SDCARD_D3;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Enable internal pullups on enabled pins. The internal pullups
|
||||
// are insufficient however, please make sure 10k external pullups are
|
||||
// connected on the bus. This is for debug / example purpose only.
|
||||
slot_config.flags |= SDMMC_SLOT_FLAG_INTERNAL_PULLUP;
|
||||
|
||||
// Der PullUp des GPIO13 wird durch slot_config.flags |= SDMMC_SLOT_FLAG_INTERNAL_PULLUP;
|
||||
// nicht gesetzt, da er eigentlich nicht benötigt wird,
|
||||
// dies führt jedoch bei schlechten Kopien des AI_THINKER Boards
|
||||
// zu Problemen mit der SD Initialisierung und eventuell sogar zur reboot-loops.
|
||||
// Um diese Probleme zu kompensieren, wird der PullUp manuel gesetzt.
|
||||
gpio_set_pull_mode(GPIO_SDCARD_D3, GPIO_PULLUP_ONLY); // HS2_D3
|
||||
|
||||
// Options for mounting the filesystem.
|
||||
// If format_if_mount_failed is set to true, SD card will be partitioned and
|
||||
@@ -139,15 +147,22 @@ bool Init_NVS_SDCard()
|
||||
esp_vfs_fat_sdmmc_mount_config_t mount_config = {
|
||||
.format_if_mount_failed = false,
|
||||
.max_files = 12, // previously -> 2022-09-21: 5, 2023-01-02: 7
|
||||
.allocation_unit_size = 16 * 1024
|
||||
.allocation_unit_size = 0, // 0 = auto
|
||||
.disk_status_check_enable = 0
|
||||
};
|
||||
|
||||
sdmmc_card_t* card;
|
||||
const char mount_point[] = MOUNT_POINT;
|
||||
|
||||
// Use settings defined above to initialize SD card and mount FAT filesystem.
|
||||
// Note: esp_vfs_fat_sdmmc_mount is an all-in-one convenience function.
|
||||
// Please check its source code and implement error recovery when developing
|
||||
// production applications.
|
||||
ret = esp_vfs_fat_sdmmc_mount("/sdcard", &host, &slot_config, &mount_config, &card);
|
||||
#if (ESP_IDF_VERSION <= ESP_IDF_VERSION_VAL(5, 1, 2))
|
||||
ret = esp_vfs_fat_sdmmc_mount_mh(mount_point, &host, &slot_config, &mount_config, &card);
|
||||
#else
|
||||
ret = esp_vfs_fat_sdmmc_mount(mount_point, &host, &slot_config, &mount_config, &card);
|
||||
#endif
|
||||
|
||||
if (ret != ESP_OK) {
|
||||
if (ret == ESP_FAIL) {
|
||||
@@ -170,7 +185,6 @@ bool Init_NVS_SDCard()
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
extern "C" void app_main(void)
|
||||
{
|
||||
//#ifdef CONFIG_HEAP_TRACING_STANDALONE
|
||||
@@ -194,7 +208,6 @@ extern "C" void app_main(void)
|
||||
// ********************************************
|
||||
ESP_LOGI(TAG, "\n\n\n\n================ Start app_main =================");
|
||||
|
||||
|
||||
// Init SD card
|
||||
// ********************************************
|
||||
if (!Init_NVS_SDCard())
|
||||
@@ -215,7 +228,6 @@ extern "C" void app_main(void)
|
||||
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "==================== Start ======================");
|
||||
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "=================================================");
|
||||
|
||||
|
||||
// Init external PSRAM
|
||||
// ********************************************
|
||||
esp_err_t PSRAMStatus = esp_psram_init();
|
||||
@@ -264,7 +276,6 @@ extern "C" void app_main(void)
|
||||
ESP_LOGD(TAG, "After camera initialization: sleep for: %ldms", (long) xDelay * CONFIG_FREERTOS_HZ/portTICK_PERIOD_MS);
|
||||
vTaskDelay( xDelay );
|
||||
|
||||
|
||||
// Check camera init
|
||||
// ********************************************
|
||||
if (camStatus != ESP_OK) { // Camera init failed, retry to init
|
||||
@@ -313,7 +324,6 @@ extern "C" void app_main(void)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// SD card: basic R/W check
|
||||
// ********************************************
|
||||
int iSDCardStatus = SDCardCheckRW();
|
||||
@@ -338,12 +348,10 @@ extern "C" void app_main(void)
|
||||
// ********************************************
|
||||
setupTime(); // NTP time service: Status of time synchronization will be checked after every round (server_tflite.cpp)
|
||||
|
||||
|
||||
// Set CPU Frequency
|
||||
// ********************************************
|
||||
setCpuFrequency();
|
||||
|
||||
|
||||
// SD card: Create further mandatory directories (if not already existing)
|
||||
// Correct creation of these folders will be checked with function "SDCardCheckFolderFilePresence"
|
||||
// ********************************************
|
||||
@@ -435,7 +443,6 @@ extern "C" void app_main(void)
|
||||
ESP_LOGD(TAG, "main: sleep for: %ldms", (long) xDelay * CONFIG_FREERTOS_HZ/portTICK_PERIOD_MS);
|
||||
vTaskDelay( xDelay );
|
||||
|
||||
|
||||
// manual reset the time
|
||||
// ********************************************
|
||||
if (!time_manual_reset_sync())
|
||||
@@ -443,8 +450,6 @@ extern "C" void app_main(void)
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Manual Time Sync failed during startup" );
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Set log level for wifi component to WARN level (default: INFO; only relevant for serial console)
|
||||
// ********************************************
|
||||
esp_log_level_set("wifi", ESP_LOG_WARN);
|
||||
@@ -468,8 +473,6 @@ extern "C" void app_main(void)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
// Print Device info
|
||||
// ********************************************
|
||||
esp_chip_info_t chipInfo;
|
||||
@@ -525,30 +528,44 @@ extern "C" void app_main(void)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void migrateConfiguration(void) {
|
||||
std::vector<string> splitted;
|
||||
bool migrated = false;
|
||||
|
||||
bool CamZoom_found = false;
|
||||
int CamZoom_lines = 0;
|
||||
bool CamZoom_value = false;
|
||||
int CamZoomSize_lines = 0;
|
||||
int CamZoomSize_value = 0;
|
||||
int CamZoomOffsetX_lines = 0;
|
||||
int CamZoomOffsetX_value = 0;
|
||||
int CamZoomOffsetY_lines = 0;
|
||||
int CamZoomOffsetY_value = 0;
|
||||
|
||||
if (!FileExists(CONFIG_FILE)) {
|
||||
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Config file seems to be missing!");
|
||||
return;
|
||||
return;
|
||||
}
|
||||
|
||||
std::string section = "";
|
||||
std::ifstream ifs(CONFIG_FILE);
|
||||
std::string content((std::istreambuf_iterator<char>(ifs)), (std::istreambuf_iterator<char>()));
|
||||
|
||||
std::ifstream ifs(CONFIG_FILE);
|
||||
std::string content((std::istreambuf_iterator<char>(ifs)), (std::istreambuf_iterator<char>()));
|
||||
|
||||
/* Split config file it array of lines */
|
||||
std::vector<std::string> configLines = splitString(content);
|
||||
|
||||
/* Process each line */
|
||||
for (int i = 0; i < configLines.size(); i++) {
|
||||
//ESP_LOGI(TAG, "Line %d: %s", i, configLines[i].c_str());
|
||||
// ESP_LOGI(TAG, "Line %d: %s", i, configLines[i].c_str());
|
||||
|
||||
if (configLines[i].find("[") != std::string::npos) { // Start of new section
|
||||
if (configLines[i].find("[") != std::string::npos) {
|
||||
// Start of new section
|
||||
section = configLines[i];
|
||||
replaceString(section, ";", "", false); // Remove possible semicolon (just for the string comparison)
|
||||
//ESP_LOGI(TAG, "New section: %s", section.c_str());
|
||||
// ESP_LOGI(TAG, "New section: %s", section.c_str());
|
||||
}
|
||||
else {
|
||||
splitted = ZerlegeZeile(configLines[i]);
|
||||
}
|
||||
|
||||
/* Migrate parameters as needed
|
||||
@@ -566,113 +583,154 @@ void migrateConfiguration(void) {
|
||||
}
|
||||
|
||||
if (section == "[MakeImage]" || section == "[TakeImage]") {
|
||||
migrated = migrated | replaceString(configLines[i], "LogImageLocation", "RawImagesLocation");
|
||||
migrated = migrated | replaceString(configLines[i], "LogfileRetentionInDays", "RawImagesRetention");
|
||||
if ((isInString(configLines[i], "Brightness")) && (!isInString(configLines[i], "CamBrightness"))) {
|
||||
migrated = migrated | replaceString(configLines[i], "Brightness", "CamBrightness");
|
||||
}
|
||||
else if ((isInString(configLines[i], "Contrast")) && (!isInString(configLines[i], "CamContrast"))) {
|
||||
migrated = migrated | replaceString(configLines[i], "Contrast", "CamContrast");
|
||||
}
|
||||
else if ((isInString(configLines[i], "Saturation")) && (!isInString(configLines[i], "CamSaturation"))) {
|
||||
migrated = migrated | replaceString(configLines[i], "Saturation", "CamSaturation");
|
||||
}
|
||||
else if ((isInString(configLines[i], "Sharpness")) && (!isInString(configLines[i], "CamSharpness")) && (!isInString(configLines[i], "CamAutoSharpness"))) {
|
||||
migrated = migrated | replaceString(configLines[i], "Sharpness", "CamSharpness");
|
||||
}
|
||||
else if ((isInString(configLines[i], "Aec2")) && (!isInString(configLines[i], "CamAec")) && (!isInString(configLines[i], "CamAec2"))) {
|
||||
migrated = migrated | replaceString(configLines[i], "Aec2", "CamAec2");
|
||||
}
|
||||
else if ((isInString(configLines[i], "Zoom")) && (!isInString(configLines[i], "CamZoom")) && (!isInString(configLines[i], "ZoomMode")) && (!isInString(configLines[i], "ZoomOffsetX")) && (!isInString(configLines[i], "ZoomOffsetY"))) {
|
||||
CamZoom_lines = i;
|
||||
CamZoom_value = alphanumericToBoolean(splitted[1]);
|
||||
CamZoom_found = true;
|
||||
}
|
||||
else if ((isInString(configLines[i], "ZoomMode")) && (!isInString(configLines[i], "CamZoom"))) {
|
||||
CamZoomSize_lines = i;
|
||||
if (isStringNumeric(splitted[1])) {
|
||||
CamZoomSize_value = std::stof(splitted[1]);
|
||||
}
|
||||
CamZoom_found = true;
|
||||
}
|
||||
else if ((isInString(configLines[i], "ZoomOffsetX")) && (!isInString(configLines[i], "CamZoom")) && (!isInString(configLines[i], "ZoomOffsetY"))) {
|
||||
CamZoomOffsetX_lines = i;
|
||||
if (isStringNumeric(splitted[1])) {
|
||||
CamZoomOffsetX_value = std::stof(splitted[1]);
|
||||
}
|
||||
CamZoom_found = true;
|
||||
}
|
||||
else if ((isInString(configLines[i], "ZoomOffsetY")) && (!isInString(configLines[i], "CamZoom")) && (!isInString(configLines[i], "ZoomOffsetX"))) {
|
||||
CamZoomOffsetY_lines = i;
|
||||
if (isStringNumeric(splitted[1])) {
|
||||
CamZoomOffsetY_value = std::stof(splitted[1]);
|
||||
}
|
||||
CamZoom_found = true;
|
||||
}
|
||||
else {
|
||||
migrated = migrated | replaceString(configLines[i], "LogImageLocation", "RawImagesLocation");
|
||||
migrated = migrated | replaceString(configLines[i], "LogfileRetentionInDays", "RawImagesRetention");
|
||||
|
||||
migrated = migrated | replaceString(configLines[i], ";Demo = true", ";Demo = false"); // Set it to its default value
|
||||
migrated = migrated | replaceString(configLines[i], ";Demo", "Demo"); // Enable it
|
||||
migrated = migrated | replaceString(configLines[i], ";Demo = true", ";Demo = false"); // Set it to its default value
|
||||
migrated = migrated | replaceString(configLines[i], ";Demo", "Demo"); // Enable it
|
||||
|
||||
migrated = migrated | replaceString(configLines[i], ";FixedExposure = true", ";FixedExposure = false"); // Set it to its default value
|
||||
migrated = migrated | replaceString(configLines[i], ";FixedExposure", "FixedExposure"); // Enable it
|
||||
migrated = migrated | replaceString(configLines[i], "ImageQuality", "CamQuality");
|
||||
migrated = migrated | replaceString(configLines[i], "AutoExposureLevel", "CamAeLevel");
|
||||
migrated = migrated | replaceString(configLines[i], "FixedExposure", "CamAec");
|
||||
|
||||
migrated = migrated | replaceString(configLines[i], "ImageSize", ";UNUSED_PARAMETER"); // This parameter is no longer used
|
||||
migrated = migrated | replaceString(configLines[i], "Grayscale", ";UNUSED_PARAMETER"); // This parameter is no longer used
|
||||
migrated = migrated | replaceString(configLines[i], "Negative", ";UNUSED_PARAMETER"); // This parameter is no longer used
|
||||
}
|
||||
}
|
||||
|
||||
if (section == "[Alignment]") {
|
||||
migrated = migrated | replaceString(configLines[i], ";InitialMirror = true", ";InitialMirror = false"); // Set it to its default value
|
||||
migrated = migrated | replaceString(configLines[i], ";InitialMirror", "InitialMirror"); // Enable it
|
||||
|
||||
migrated = migrated | replaceString(configLines[i], ";FlipImageSize = true", ";FlipImageSize = false"); // Set it to its default value
|
||||
migrated = migrated | replaceString(configLines[i], ";FlipImageSize", "FlipImageSize"); // Enable it
|
||||
else if (section == "[Alignment]") {
|
||||
migrated = migrated | replaceString(configLines[i], "InitialMirror", ";UNUSED_PARAMETER"); // This parameter is no longer used
|
||||
migrated = migrated | replaceString(configLines[i], ";InitialMirror", ";UNUSED_PARAMETER"); // This parameter is no longer used
|
||||
migrated = migrated | replaceString(configLines[i], "FlipImageSize", ";UNUSED_PARAMETER"); // This parameter is no longer used
|
||||
migrated = migrated | replaceString(configLines[i], ";FlipImageSize", ";UNUSED_PARAMETER"); // This parameter is no longer used
|
||||
}
|
||||
|
||||
if (section == "[Digits]") {
|
||||
else if (section == "[Digits]") {
|
||||
migrated = migrated | replaceString(configLines[i], "LogImageLocation", "ROIImagesLocation");
|
||||
migrated = migrated | replaceString(configLines[i], "LogfileRetentionInDays", "ROIImagesRetention");
|
||||
}
|
||||
|
||||
if (section == "[Analog]") {
|
||||
else if (section == "[Analog]") {
|
||||
migrated = migrated | replaceString(configLines[i], "LogImageLocation", "ROIImagesLocation");
|
||||
migrated = migrated | replaceString(configLines[i], "LogfileRetentionInDays", "ROIImagesRetention");
|
||||
migrated = migrated | replaceString(configLines[i], "ExtendedResolution", ";UNUSED_PARAMETER"); // This parameter is no longer used
|
||||
}
|
||||
|
||||
if (section == "[PostProcessing]") {
|
||||
migrated = migrated | replaceString(configLines[i], ";PreValueUse = true", ";PreValueUse = false"); // Set it to its default value
|
||||
migrated = migrated | replaceString(configLines[i], ";PreValueUse", "PreValueUse"); // Enable it
|
||||
|
||||
else if (section == "[PostProcessing]") {
|
||||
/* AllowNegativeRates has a <NUMBER> as prefix! */
|
||||
if (isInString(configLines[i], "AllowNegativeRates") && isInString(configLines[i], ";")) { // It is the parameter "AllowNegativeRates" and it is commented out
|
||||
if (isInString(configLines[i], "AllowNegativeRates") && isInString(configLines[i], ";")) {
|
||||
// It is the parameter "AllowNegativeRates" and it is commented out
|
||||
migrated = migrated | replaceString(configLines[i], "true", "false"); // Set it to its default value
|
||||
migrated = migrated | replaceString(configLines[i], ";", ""); // Enable it
|
||||
migrated = migrated | replaceString(configLines[i], ";", ""); // Enable it
|
||||
}
|
||||
|
||||
/* IgnoreLeadingNaN has a <NUMBER> as prefix! */
|
||||
if (isInString(configLines[i], "IgnoreLeadingNaN") && isInString(configLines[i], ";")) { // It is the parameter "IgnoreLeadingNaN" and it is commented out
|
||||
else if (isInString(configLines[i], "IgnoreLeadingNaN") && isInString(configLines[i], ";")) {
|
||||
// It is the parameter "IgnoreLeadingNaN" and it is commented out
|
||||
migrated = migrated | replaceString(configLines[i], "true", "false"); // Set it to its default value
|
||||
migrated = migrated | replaceString(configLines[i], ";", ""); // Enable it
|
||||
migrated = migrated | replaceString(configLines[i], ";", ""); // Enable it
|
||||
}
|
||||
|
||||
/* ExtendedResolution has a <NUMBER> as prefix! */
|
||||
if (isInString(configLines[i], "ExtendedResolution") && isInString(configLines[i], ";")) { // It is the parameter "ExtendedResolution" and it is commented out
|
||||
else if (isInString(configLines[i], "ExtendedResolution") && isInString(configLines[i], ";")) {
|
||||
// It is the parameter "ExtendedResolution" and it is commented out
|
||||
migrated = migrated | replaceString(configLines[i], "true", "false"); // Set it to its default value
|
||||
migrated = migrated | replaceString(configLines[i], ";", ""); // Enable it
|
||||
migrated = migrated | replaceString(configLines[i], ";", ""); // Enable it
|
||||
}
|
||||
else {
|
||||
migrated = migrated | replaceString(configLines[i], ";PreValueUse = true", ";PreValueUse = false"); // Set it to its default value
|
||||
migrated = migrated | replaceString(configLines[i], ";PreValueUse", "PreValueUse"); // Enable it
|
||||
|
||||
migrated = migrated | replaceString(configLines[i], ";ErrorMessage = true", ";ErrorMessage = false"); // Set it to its default value
|
||||
migrated = migrated | replaceString(configLines[i], ";ErrorMessage", "ErrorMessage"); // Enable it
|
||||
migrated = migrated | replaceString(configLines[i], ";ErrorMessage = true", ";ErrorMessage = false"); // Set it to its default value
|
||||
migrated = migrated | replaceString(configLines[i], ";ErrorMessage", "ErrorMessage"); // Enable it
|
||||
|
||||
migrated = migrated | replaceString(configLines[i], ";CheckDigitIncreaseConsistency = true", ";CheckDigitIncreaseConsistency = false"); // Set it to its default value
|
||||
migrated = migrated | replaceString(configLines[i], ";CheckDigitIncreaseConsistency", "CheckDigitIncreaseConsistency"); // Enable it
|
||||
migrated = migrated | replaceString(configLines[i], ";CheckDigitIncreaseConsistency = true", ";CheckDigitIncreaseConsistency = false"); // Set it to its default value
|
||||
migrated = migrated | replaceString(configLines[i], ";CheckDigitIncreaseConsistency", "CheckDigitIncreaseConsistency"); // Enable it
|
||||
}
|
||||
}
|
||||
|
||||
if (section == "[MQTT]") {
|
||||
migrated = migrated | replaceString(configLines[i], "SetRetainFlag", "RetainMessages"); // First rename it, enable it with its default value
|
||||
else if (section == "[MQTT]") {
|
||||
migrated = migrated | replaceString(configLines[i], "SetRetainFlag", "RetainMessages"); // First rename it, enable it with its default value
|
||||
migrated = migrated | replaceString(configLines[i], ";RetainMessages = true", ";RetainMessages = false"); // Set it to its default value
|
||||
migrated = migrated | replaceString(configLines[i], ";RetainMessages", "RetainMessages"); // Enable it
|
||||
migrated = migrated | replaceString(configLines[i], ";RetainMessages", "RetainMessages"); // Enable it
|
||||
|
||||
migrated = migrated | replaceString(configLines[i], ";HomeassistantDiscovery = true", ";HomeassistantDiscovery = false"); // Set it to its default value
|
||||
migrated = migrated | replaceString(configLines[i], ";HomeassistantDiscovery", "HomeassistantDiscovery"); // Enable it
|
||||
migrated = migrated | replaceString(configLines[i], ";HomeassistantDiscovery", "HomeassistantDiscovery"); // Enable it
|
||||
|
||||
if (configLines[i].rfind("Topic", 0) != std::string::npos) // only if string starts with "Topic" (Was the naming in very old version)
|
||||
{
|
||||
// only if string starts with "Topic" (Was the naming in very old version)
|
||||
if (configLines[i].rfind("Topic", 0) != std::string::npos) {
|
||||
migrated = migrated | replaceString(configLines[i], "Topic", "MainTopic");
|
||||
}
|
||||
}
|
||||
|
||||
if (section == "[InfluxDB]") {
|
||||
else if (section == "[InfluxDB]") {
|
||||
/* Fieldname has a <NUMBER> as prefix! */
|
||||
if (isInString(configLines[i], "Fieldname")) { // It is the parameter "Fieldname"
|
||||
if (isInString(configLines[i], "Fieldname")) {
|
||||
// It is the parameter "Fieldname"
|
||||
migrated = migrated | replaceString(configLines[i], "Fieldname", "Field"); // Rename it to Field
|
||||
migrated = migrated | replaceString(configLines[i], ";", ""); // Enable it
|
||||
}
|
||||
}
|
||||
|
||||
if (section == "[InfluxDBv2]") {
|
||||
else if (section == "[InfluxDBv2]") {
|
||||
/* Fieldname has a <NUMBER> as prefix! */
|
||||
if (isInString(configLines[i], "Fieldname")) { // It is the parameter "Fieldname"
|
||||
if (isInString(configLines[i], "Fieldname")) {
|
||||
// It is the parameter "Fieldname"
|
||||
migrated = migrated | replaceString(configLines[i], "Fieldname", "Field"); // Rename it to Field
|
||||
migrated = migrated | replaceString(configLines[i], ";", ""); // Enable it
|
||||
}
|
||||
/* Database got renamed to Bucket! */
|
||||
else if (isInString(configLines[i], "Database")) {
|
||||
// It is the parameter "Database"
|
||||
migrated = migrated | replaceString(configLines[i], "Database", "Bucket"); // Rename it to Bucket
|
||||
}
|
||||
}
|
||||
|
||||
if (section == "[GPIO]") {
|
||||
|
||||
else if (section == "[GPIO]") {
|
||||
}
|
||||
|
||||
if (section == "[DataLogging]") {
|
||||
else if (section == "[DataLogging]") {
|
||||
migrated = migrated | replaceString(configLines[i], "DataLogRetentionInDays", "DataFilesRetention");
|
||||
/* DataLogActive is true by default! */
|
||||
migrated = migrated | replaceString(configLines[i], ";DataLogActive = false", ";DataLogActive = true"); // Set it to its default value
|
||||
migrated = migrated | replaceString(configLines[i], ";DataLogActive", "DataLogActive"); // Enable it
|
||||
migrated = migrated | replaceString(configLines[i], ";DataLogActive", "DataLogActive"); // Enable it
|
||||
}
|
||||
|
||||
if (section == "[AutoTimer]") {
|
||||
else if (section == "[AutoTimer]") {
|
||||
migrated = migrated | replaceString(configLines[i], "Intervall", "Interval");
|
||||
migrated = migrated | replaceString(configLines[i], ";AutoStart = true", ";AutoStart = false"); // Set it to its default value
|
||||
migrated = migrated | replaceString(configLines[i], ";AutoStart", "AutoStart"); // Enable it
|
||||
|
||||
migrated = migrated | replaceString(configLines[i], ";AutoStart", "AutoStart"); // Enable it
|
||||
}
|
||||
|
||||
if (section == "[Debug]") {
|
||||
else if (section == "[Debug]") {
|
||||
migrated = migrated | replaceString(configLines[i], "Logfile ", "LogLevel "); // Whitespace needed so it does not match `LogfileRetentionInDays`
|
||||
/* LogLevel (resp. LogFile) was originally a boolean, but we switched it to an int
|
||||
* For both cases (true/false), we set it to level 2 (WARNING) */
|
||||
@@ -680,33 +738,107 @@ void migrateConfiguration(void) {
|
||||
migrated = migrated | replaceString(configLines[i], "LogLevel = false", "LogLevel = 2");
|
||||
migrated = migrated | replaceString(configLines[i], "LogfileRetentionInDays", "LogfilesRetention");
|
||||
}
|
||||
|
||||
if (section == "[System]") {
|
||||
else if (section == "[System]") {
|
||||
migrated = migrated | replaceString(configLines[i], "RSSIThreashold", "RSSIThreshold");
|
||||
migrated = migrated | replaceString(configLines[i], "AutoAdjustSummertime", ";UNUSED_PARAMETER"); // This parameter is no longer used
|
||||
|
||||
migrated = migrated | replaceString(configLines[i], ";SetupMode = true", ";SetupMode = false"); // Set it to its default value
|
||||
migrated = migrated | replaceString(configLines[i], ";SetupMode", "SetupMode"); // Enable it
|
||||
migrated = migrated | replaceString(configLines[i], ";SetupMode", "SetupMode"); // Enable it
|
||||
}
|
||||
}
|
||||
|
||||
if (migrated) { // At least one replacement happened
|
||||
if (! RenameFile(CONFIG_FILE, CONFIG_FILE_BACKUP)) {
|
||||
if (CamZoom_found == true) {
|
||||
if (CamZoomSize_value == 0) {
|
||||
// mode0
|
||||
// 1600 - 640 = 960 / 2 = max-Offset (+/-) 480
|
||||
// 1200 - 480 = 720 / 2 = max-Offset (+/-) 360
|
||||
|
||||
if (CamZoomOffsetX_value > 960) {
|
||||
CamZoomOffsetX_value = 960;
|
||||
}
|
||||
else {
|
||||
CamZoomOffsetX_value = (floor((CamZoomOffsetX_value - 480) / 8) * 8);
|
||||
}
|
||||
|
||||
if (CamZoomOffsetY_value > 720) {
|
||||
CamZoomOffsetY_value = 720;
|
||||
}
|
||||
else {
|
||||
CamZoomOffsetY_value = (floor((CamZoomOffsetY_value - 360) / 8) * 8);
|
||||
}
|
||||
|
||||
CamZoomSize_value = 29;
|
||||
}
|
||||
else {
|
||||
// mode1
|
||||
// 800 - 640 = 160 / 2 = max-Offset (+/-) 80
|
||||
// 600 - 480 = 120 / 2 = max-Offset (+/-) 60
|
||||
|
||||
if (CamZoomOffsetX_value > 160) {
|
||||
CamZoomOffsetX_value = 160;
|
||||
}
|
||||
else {
|
||||
CamZoomOffsetX_value = (floor(((CamZoomOffsetX_value - 80) * 2) / 8) * 8);
|
||||
}
|
||||
|
||||
if (CamZoomOffsetY_value > 120) {
|
||||
CamZoomOffsetY_value = 120;
|
||||
}
|
||||
else {
|
||||
CamZoomOffsetY_value = (floor(((CamZoomOffsetY_value - 60) * 2) / 8) * 8);
|
||||
}
|
||||
|
||||
CamZoomSize_value = 9;
|
||||
}
|
||||
|
||||
if (CamZoom_lines > 0) {
|
||||
if (CamZoom_value) {
|
||||
configLines[CamZoom_lines] = ("CamZoom = true");
|
||||
}
|
||||
else {
|
||||
configLines[CamZoom_lines] = ("CamZoom = false");
|
||||
}
|
||||
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Migrated Configfile line 'Zoom' to 'CamZoom'");
|
||||
migrated = true;
|
||||
}
|
||||
if (CamZoomSize_lines > 0) {
|
||||
configLines[CamZoomSize_lines] = ("CamZoomSize = " + std::to_string(CamZoomSize_value));
|
||||
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Migrated Configfile line 'ZoomMode' to 'CamZoomSize'");
|
||||
migrated = true;
|
||||
}
|
||||
if (CamZoomOffsetX_lines > 0) {
|
||||
configLines[CamZoomOffsetX_lines] = ("CamZoomOffsetX = " + std::to_string(CamZoomOffsetX_value));
|
||||
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Migrated Configfile line 'ZoomOffsetX' to 'CamZoomOffsetX'");
|
||||
migrated = true;
|
||||
}
|
||||
if (CamZoomOffsetY_lines > 0) {
|
||||
configLines[CamZoomOffsetY_lines] = ("CamZoomOffsetY = " + std::to_string(CamZoomOffsetY_value));
|
||||
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Migrated Configfile line 'ZoomOffsetY' to 'CamZoomOffsetY'");
|
||||
migrated = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (migrated) {
|
||||
// At least one replacement happened
|
||||
if (!RenameFile(CONFIG_FILE, CONFIG_FILE_BACKUP)) {
|
||||
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Failed to create backup of Config file!");
|
||||
return;
|
||||
}
|
||||
|
||||
FILE* pfile = fopen(CONFIG_FILE, "w");
|
||||
FILE *pfile = fopen(CONFIG_FILE, "w");
|
||||
|
||||
for (int i = 0; i < configLines.size(); i++) {
|
||||
fwrite(configLines[i].c_str() , configLines[i].length(), 1, pfile);
|
||||
fwrite("\n" , 1, 1, pfile);
|
||||
if (!isInString(configLines[i], ";UNUSED_PARAMETER")) {
|
||||
fwrite(configLines[i].c_str(), configLines[i].length(), 1, pfile);
|
||||
fwrite("\n", 1, 1, pfile);
|
||||
}
|
||||
}
|
||||
|
||||
fclose(pfile);
|
||||
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Config file migrated. Saved backup to " + string(CONFIG_FILE_BACKUP));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
std::vector<std::string> splitString(const std::string& str) {
|
||||
std::vector<std::string> tokens;
|
||||
|
||||
@@ -720,7 +852,6 @@ std::vector<std::string> splitString(const std::string& str) {
|
||||
return tokens;
|
||||
}
|
||||
|
||||
|
||||
/*bool replace_all(std::string& s, std::string const& toReplace, std::string const& replaceWith) {
|
||||
std::string buf;
|
||||
std::size_t pos = 0;
|
||||
@@ -748,11 +879,10 @@ std::vector<std::string> splitString(const std::string& str) {
|
||||
return found;
|
||||
}*/
|
||||
|
||||
|
||||
bool setCpuFrequency(void) {
|
||||
ConfigFile configFile = ConfigFile(CONFIG_FILE);
|
||||
string cpuFrequency = "160";
|
||||
esp_pm_config_esp32_t pm_config;
|
||||
esp_pm_config_t pm_config;
|
||||
|
||||
if (!configFile.ConfigFileExists()){
|
||||
LogFile.WriteToFile(ESP_LOG_WARN, TAG, "No ConfigFile defined - exit setCpuFrequency()!");
|
||||
@@ -764,7 +894,6 @@ bool setCpuFrequency(void) {
|
||||
bool disabledLine = false;
|
||||
bool eof = false;
|
||||
|
||||
|
||||
/* Load config from config file */
|
||||
while ((!configFile.GetNextParagraph(line, disabledLine, eof) ||
|
||||
(line.compare("[System]") != 0)) && !eof) {}
|
||||
@@ -813,4 +942,4 @@ bool setCpuFrequency(void) {
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
|
||||
#include "MainFlowControl.h"
|
||||
#include "esp_log.h"
|
||||
#include "esp_chip_info.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
@@ -39,17 +40,21 @@ esp_err_t info_get_handler(httpd_req_t *req)
|
||||
char _valuechar[30];
|
||||
std::string _task;
|
||||
|
||||
if (httpd_req_get_url_query_str(req, _query, 200) == ESP_OK)
|
||||
if (httpd_req_get_url_query_str(req, _query, 200) != ESP_OK)
|
||||
{
|
||||
ESP_LOGD(TAG, "Query: %s", _query);
|
||||
|
||||
if (httpd_query_key_value(_query, "type", _valuechar, 30) == ESP_OK)
|
||||
{
|
||||
ESP_LOGD(TAG, "type is found: %s", _valuechar);
|
||||
_task = std::string(_valuechar);
|
||||
}
|
||||
return httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "invalid query string");
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, "Query: %s", _query);
|
||||
|
||||
if (httpd_query_key_value(_query, "type", _valuechar, 30) != ESP_OK)
|
||||
{
|
||||
return httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "missing or invalid 'type' query parameter (too long value?)");
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, "type is found: %s", _valuechar);
|
||||
_task = std::string(_valuechar);
|
||||
|
||||
httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
|
||||
|
||||
if (_task.compare("GitBranch") == 0)
|
||||
@@ -166,6 +171,33 @@ esp_err_t info_get_handler(httpd_req_t *req)
|
||||
httpd_resp_sendstr(req, zw.c_str());
|
||||
return ESP_OK;
|
||||
}
|
||||
else if (_task.compare("ChipCores") == 0)
|
||||
{
|
||||
esp_chip_info_t chipInfo;
|
||||
esp_chip_info(&chipInfo);
|
||||
httpd_resp_sendstr(req, to_string(chipInfo.cores).c_str());
|
||||
return ESP_OK;
|
||||
}
|
||||
else if (_task.compare("ChipRevision") == 0)
|
||||
{
|
||||
esp_chip_info_t chipInfo;
|
||||
esp_chip_info(&chipInfo);
|
||||
httpd_resp_sendstr(req, to_string(chipInfo.revision).c_str());
|
||||
return ESP_OK;
|
||||
}
|
||||
else if (_task.compare("ChipFeatures") == 0)
|
||||
{
|
||||
esp_chip_info_t chipInfo;
|
||||
esp_chip_info(&chipInfo);
|
||||
httpd_resp_sendstr(req, to_string(chipInfo.features).c_str());
|
||||
return ESP_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
char formatted[256];
|
||||
snprintf(formatted, sizeof(formatted), "Unknown value for parameter info 'type': '%s'\n", _task.c_str());
|
||||
return httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, formatted);
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
@@ -325,7 +357,7 @@ esp_err_t img_tmp_virtual_handler(httpd_req_t *req)
|
||||
if (filetosend == "raw.jpg")
|
||||
return GetRawJPG(req);
|
||||
|
||||
// Serve alg.jpg, alg_roi.jpg or digital and analog ROIs
|
||||
// Serve alg.jpg, alg_roi.jpg or digit and analog ROIs
|
||||
if (ESP_OK == GetJPG(filetosend, req))
|
||||
return ESP_OK;
|
||||
|
||||
@@ -419,7 +451,7 @@ void register_server_main_uri(httpd_handle_t server, const char *base_path)
|
||||
httpd_handle_t start_webserver(void)
|
||||
{
|
||||
httpd_handle_t server = NULL;
|
||||
httpd_config_t config = { };
|
||||
httpd_config_t config = HTTPD_DEFAULT_CONFIG();
|
||||
|
||||
config.task_priority = tskIDLE_PRIORITY+3; // previously -> 2022-12-11: tskIDLE_PRIORITY+1; 2021-09-24: tskIDLE_PRIORITY+5
|
||||
config.stack_size = 12288; // previously -> 2023-01-02: 32768
|
||||
@@ -427,7 +459,7 @@ httpd_handle_t start_webserver(void)
|
||||
config.server_port = 80;
|
||||
config.ctrl_port = 32768;
|
||||
config.max_open_sockets = 5; //20210921 --> previously 7
|
||||
config.max_uri_handlers = 39; // previously 24, 20220511: 35, 20221220: 37, 2023-01-02:38
|
||||
config.max_uri_handlers = 40; // Make sure this fits all URI handlers. Memory usage in bytes: 6*max_uri_handlers
|
||||
config.max_resp_headers = 8;
|
||||
config.backlog_conn = 5;
|
||||
config.lru_purge_enable = true; // this cuts old connections if new ones are needed.
|
||||
|
||||
@@ -19,7 +19,8 @@
|
||||
|
||||
[common:esp32-idf]
|
||||
extends = common:idf
|
||||
platform = platformio/espressif32 @ 6.3.2
|
||||
; PlatformIO releases, see https://github.com/platformio/platform-espressif32/releases
|
||||
platform = platformio/espressif32 @ 6.9.0
|
||||
framework = espidf
|
||||
lib_deps =
|
||||
${common:idf.lib_deps}
|
||||
@@ -29,7 +30,6 @@
|
||||
-DUSE_ESP32
|
||||
-DUSE_ESP32_FRAMEWORK_ESP_IDF
|
||||
|
||||
|
||||
[flags:runtime]
|
||||
build_flags =
|
||||
-Wno-nonnull-compare
|
||||
@@ -46,6 +46,7 @@
|
||||
;-Wshadow-compatible-local
|
||||
-fno-exceptions
|
||||
|
||||
|
||||
; The main env - default
|
||||
[env:esp32cam]
|
||||
extends = common:esp32-idf
|
||||
@@ -56,13 +57,14 @@ build_flags =
|
||||
${common:esp32-idf.build_flags}
|
||||
${flags:runtime.build_flags}
|
||||
; ### Sofware options : (can be set in defines.h)
|
||||
-D BOARD_ESP32CAM_AITHINKER
|
||||
-D ENABLE_MQTT
|
||||
-D ENABLE_INFLUXDB
|
||||
-D ENABLE_INFLUXDB
|
||||
-D ENABLE_WEBHOOK
|
||||
-D ENABLE_SOFTAP
|
||||
board_build.partitions = partitions.csv
|
||||
monitor_speed = 115200
|
||||
monitor_rts = 0
|
||||
monitor_dtr = 0
|
||||
|
||||
|
||||
; full standalone dev mode
|
||||
; As sample, the board is nod32s instead of esp32cam (do not change nothing in fact :)
|
||||
@@ -77,8 +79,10 @@ build_flags =
|
||||
${common:esp32-idf.build_flags}
|
||||
${flags:clangtidy.build_flags}
|
||||
; ### Sofware options : (can be set in defines.h)
|
||||
-D BOARD_ESP32CAM_AITHINKER
|
||||
-D ENABLE_MQTT
|
||||
-D ENABLE_INFLUXDB
|
||||
-D ENABLE_INFLUXDB
|
||||
-D ENABLE_WEBHOOK
|
||||
;-D ENABLE_SOFTAP
|
||||
; ### Debug options :
|
||||
;-D DEBUG_DETAIL_ON
|
||||
@@ -121,8 +125,6 @@ platform_packages =
|
||||
;;;;espressif/toolchain-xtensa-esp32 @ 8.4.0+2021r2-patch5
|
||||
board_build.partitions = partitions.csv
|
||||
monitor_speed = 115200
|
||||
monitor_rts = 0
|
||||
monitor_dtr = 0
|
||||
|
||||
|
||||
; Activate all debug mode
|
||||
@@ -210,5 +212,6 @@ build_flags =
|
||||
${flags:clangtidy.build_flags}
|
||||
; ### Sofware options :
|
||||
-D ENABLE_MQTT
|
||||
-D ENABLE_INFLUXDB
|
||||
-D ENABLE_INFLUXDB
|
||||
-D ENABLE_WEBHOOK
|
||||
;-D ENABLE_SOFTAP ; disabled
|
||||
|
||||
@@ -109,11 +109,6 @@ CONFIG_ESP_INT_WDT_TIMEOUT_MS=300
|
||||
|
||||
CONFIG_HTTPD_MAX_REQ_HDR_LEN=1024
|
||||
CONFIG_HTTPD_PURGE_BUF_LEN=16
|
||||
<<<<<<< Updated upstream
|
||||
=======
|
||||
CONFIG_HTTPD_WS_SUPPORT=y
|
||||
CONFIG_LWIP_MAX_SOCKETS=12
|
||||
>>>>>>> Stashed changes
|
||||
|
||||
CONFIG_ESP32_WIFI_DYNAMIC_RX_BUFFER_NUM=16
|
||||
CONFIG_ESP32_WIFI_CACHE_TX_BUFFER_NUM=16
|
||||
@@ -140,7 +135,8 @@ CONFIG_OV7670_SUPPORT=n
|
||||
CONFIG_OV7725_SUPPORT=n
|
||||
CONFIG_NT99141_SUPPORT=n
|
||||
CONFIG_OV3660_SUPPORT=n
|
||||
CONFIG_OV5640_SUPPORT=n
|
||||
CONFIG_OV2640_SUPPORT=y
|
||||
CONFIG_OV5640_SUPPORT=y
|
||||
CONFIG_GC2145_SUPPORT=n
|
||||
CONFIG_GC032A_SUPPORT=n
|
||||
CONFIG_GC0308_SUPPORT=n
|
||||
|
||||
@@ -20,7 +20,7 @@ class UnderTestCNNGeneral : public ClassFlowCNNGeneral {
|
||||
*/
|
||||
void test_analogToDigit_Standard() {
|
||||
|
||||
UnderTestCNNGeneral* undertest = new UnderTestCNNGeneral(nullptr, Digital100);
|
||||
UnderTestCNNGeneral* undertest = new UnderTestCNNGeneral(nullptr, Digit100);
|
||||
|
||||
// 4.8 is a "hanging" 5, i.e. it has not jumped over to 5.0.
|
||||
// A "hanging digit" should still be rounded from Transition.
|
||||
@@ -59,7 +59,7 @@ void test_analogToDigit_Standard() {
|
||||
}
|
||||
|
||||
void test_analogToDigit_Transition() {
|
||||
UnderTestCNNGeneral* undertest = new UnderTestCNNGeneral(nullptr, Digital100);
|
||||
UnderTestCNNGeneral* undertest = new UnderTestCNNGeneral(nullptr, Digit100);
|
||||
|
||||
// https://github.com/jomjol/AI-on-the-edge-device/issues/921#issuecomment-1222672175
|
||||
// Default: dig=3.9, ana=9.7 => erg=3
|
||||
|
||||
@@ -16,7 +16,7 @@ class UnderTestCNN : public ClassFlowCNNGeneral {
|
||||
*/
|
||||
void test_ZeigerEval()
|
||||
{
|
||||
UnderTestCNN undertest = UnderTestCNN(nullptr, Digital100);
|
||||
UnderTestCNN undertest = UnderTestCNN(nullptr, Digit100);
|
||||
|
||||
// the 5.2 is already above 5.0 and the previous digit too (3)
|
||||
printf("Test 5.2, 3\n");
|
||||
@@ -29,11 +29,11 @@ void test_ZeigerEval()
|
||||
TEST_ASSERT_EQUAL(4, undertest.PointerEvalAnalogNew(5.2, 9));
|
||||
|
||||
printf("Test 4.4, 9\n");
|
||||
// the 4.4 (digital100) is not above 5 and the previous digit (analog) too (9.3)
|
||||
// the 4.4 (Digit100) is not above 5 and the previous digit (analog) too (9.3)
|
||||
TEST_ASSERT_EQUAL(4, undertest.PointerEvalAnalogNew(4.4, 9));
|
||||
|
||||
printf("Test 4.5, 0\n");
|
||||
// the 4.5 (digital100) is not above 5 and the previous digit (analog) too (9.6)
|
||||
// the 4.5 (Digit100) is not above 5 and the previous digit (analog) too (9.6)
|
||||
TEST_ASSERT_EQUAL(4, undertest.PointerEvalAnalogNew(4.5, 0));
|
||||
|
||||
}
|
||||
@@ -41,9 +41,25 @@ void test_ZeigerEval()
|
||||
/**
|
||||
* @brief test if all combinations of digit
|
||||
* evaluation are running correctly
|
||||
*
|
||||
* Desciption on call undertest.PointerEvalHybridNew(float number, float number_of_predecessors, int eval_predecessors, bool Analog_Predecessors, float digitAnalogTransitionStart)
|
||||
* @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 digit ROI (default=false)
|
||||
* runs in special handling because analog is much less precise
|
||||
* @param digitAnalogTransitionStart start of the transitionlogic begins on number_of_predecessor (default=9.2)
|
||||
*
|
||||
*
|
||||
*
|
||||
*
|
||||
*/
|
||||
void test_ZeigerEvalHybrid() {
|
||||
UnderTestCNN undertest = UnderTestCNN(nullptr, Digital100);
|
||||
UnderTestCNN undertest = UnderTestCNN(nullptr, Digit100);
|
||||
|
||||
// the 5.2 and no previous should round down
|
||||
printf("PointerEvalHybridNew(5.2, 0, -1)\n");
|
||||
@@ -55,11 +71,11 @@ void test_ZeigerEvalHybrid() {
|
||||
|
||||
printf("PointerEvalHybridNew(5.7, 0, -1)\n");
|
||||
// the 5.7 and no previous should trunc to 5
|
||||
TEST_ASSERT_EQUAL(6, undertest.PointerEvalHybridNew(5.7, 0, -1));
|
||||
TEST_ASSERT_EQUAL(5, undertest.PointerEvalHybridNew(5.7, 0, -1, false, 9.2));
|
||||
|
||||
// the 5.8 and no previous should round up to 6
|
||||
printf("PointerEvalHybridNew(5.8, 0, -1)\n");
|
||||
TEST_ASSERT_EQUAL(6, undertest.PointerEvalHybridNew(5.8, 0, -1));
|
||||
TEST_ASSERT_EQUAL(6, undertest.PointerEvalHybridNew(5.8, 8.0, 8, false, 8.0));
|
||||
|
||||
// the 5.7 with previous and the previous between 0.3-0.5 should round up to 6
|
||||
TEST_ASSERT_EQUAL(6, undertest.PointerEvalHybridNew(5.7, 0.4, 1));
|
||||
@@ -70,23 +86,24 @@ void test_ZeigerEvalHybrid() {
|
||||
// the 5.3 with previous and the previous <=0.5 should trunc to 5
|
||||
TEST_ASSERT_EQUAL(5, undertest.PointerEvalHybridNew(5.3, 0.1, 1));
|
||||
|
||||
// the 5.3 with previous and the previous >=9.5 should reduce to 4
|
||||
TEST_ASSERT_EQUAL(4, undertest.PointerEvalHybridNew(5.3, 9.6, 9));
|
||||
// the 5.2 with previous and the previous >=9.8 should reduce to 4
|
||||
// the digit is already over transistion, but a analog pointer runs behind
|
||||
TEST_ASSERT_EQUAL(4, undertest.PointerEvalHybridNew(5.2, 9.8, 9, false, 9.0));
|
||||
|
||||
// the 5.7 with previous and the previous >=9.5 should trunc to 5
|
||||
TEST_ASSERT_EQUAL(5, undertest.PointerEvalHybridNew(5.7, 9.6, 9));
|
||||
|
||||
// the 4.5 (digital100) is not above 5 and the previous digit (analog) not over Zero (9.6)
|
||||
// the 4.5 (Digit100) is not above 5 and the previous digit (analog) not over Zero (9.6)
|
||||
TEST_ASSERT_EQUAL(4, undertest.PointerEvalHybridNew(4.5, 9.6, 0));
|
||||
|
||||
// the 4.5 (digital100) is not above 5 and the previous digit (analog) not over Zero (9.6)
|
||||
// the 4.5 (Digit100) is not above 5 and the previous digit (analog) not over Zero (9.6)
|
||||
TEST_ASSERT_EQUAL(4, undertest.PointerEvalHybridNew(4.5, 9.6, 9));
|
||||
// the 4.5 (digital100) is not above 5 and the previous digit (analog) not over Zero (9.5)
|
||||
// the 4.5 (Digit100) is not above 5 and the previous digit (analog) not over Zero (9.5)
|
||||
TEST_ASSERT_EQUAL(4, undertest.PointerEvalHybridNew(4.5, 9.5, 9));
|
||||
|
||||
// 59.96889 - Pre: 58.94888
|
||||
// 8.6 : 9.8 : 6.7
|
||||
// the 4.4 (digital100) is not above 5 and the previous digit (analog) not over Zero (9.5)
|
||||
// the 4.4 (Digit100) is not above 5 and the previous digit (analog) not over Zero (9.5)
|
||||
TEST_ASSERT_EQUAL(8, undertest.PointerEvalHybridNew(8.6, 9.8, 9));
|
||||
|
||||
// pre = 9.9 (0.0 raw)
|
||||
@@ -94,7 +111,7 @@ void test_ZeigerEvalHybrid() {
|
||||
TEST_ASSERT_EQUAL(2, undertest.PointerEvalHybridNew(1.8, 9.0, 9));
|
||||
|
||||
// if a digit have an early transition and the pointer is < 9.0
|
||||
// prev (pointer) = 6.2, but on digital readout = 6.0 (prev is int parameter)
|
||||
// prev (pointer) = 6.2, but on digit readout = 6.0 (prev is int parameter)
|
||||
// zahl = 4.6
|
||||
TEST_ASSERT_EQUAL(4, undertest.PointerEvalHybridNew(4.6, 6.0, 6));
|
||||
|
||||
|
||||
@@ -33,7 +33,17 @@ std::string process_doFlow(UnderTestPost* _underTestPost) {
|
||||
return _underTestPost->getReadout(0);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief setup flow like it runs after recognition.
|
||||
*
|
||||
* @param analog the analog recognitions as array begins with the highest ROI
|
||||
* @param digits the digit regocnitions as array begins with the highest ROI
|
||||
* @param digType type of the model defaults do Digit100
|
||||
* @param checkConsistency for Digit type only. Not relvant for newer models
|
||||
* @param extendedResolution the lowest ROI will directly used (9.7 => 9.7) if false 9.7 => 9
|
||||
* @param decimal_shift the decimal point offset. -3 corresponds to x.yyy
|
||||
* @return std::string the value result
|
||||
*/
|
||||
std::string process_doFlow(std::vector<float> analog, std::vector<float> digits, t_CNNType digType,
|
||||
bool checkConsistency, bool extendedResolution, int decimal_shift) {
|
||||
// setup the classundertest
|
||||
@@ -152,7 +162,7 @@ void setAnalogdigitTransistionStart(UnderTestPost* _underTestPost, float _analog
|
||||
std::vector<NumberPost*>* NUMBERS = _underTestPost->GetNumbers();
|
||||
for (int _n = 0; _n < (*NUMBERS).size(); ++_n) {
|
||||
ESP_LOGD(TAG, "Setting decimal shift on number: %d to %f", _n, _analogdigitTransistionStart);
|
||||
(*NUMBERS)[_n]->AnalogDigitalTransitionStart = _analogdigitTransistionStart;
|
||||
(*NUMBERS)[_n]->AnalogToDigitTransitionStart = _analogdigitTransistionStart;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,13 +33,13 @@ UnderTestPost* setUpClassFlowPostprocessing(t_CNNType digType, t_CNNType anaType
|
||||
*
|
||||
* @param analog the analog recognitions
|
||||
* @param digits the digit recognitions
|
||||
* @param digType the digit model type (default Digital100)
|
||||
* @param digType the digit model type (default Digit100)
|
||||
* @param checkConsistency sets property checkConsistency (default = false)
|
||||
* @param extendedResolution sets property extendedResolution (default = false)
|
||||
* @param decimal_shift set property decimal_shift (Nachkommastellen, default = 0)
|
||||
* @return UnderTestPost* the created testobject
|
||||
*/
|
||||
UnderTestPost* init_do_flow(std::vector<float> analog, std::vector<float> digits, t_CNNType digType = Digital100,
|
||||
UnderTestPost* init_do_flow(std::vector<float> analog, std::vector<float> digits, t_CNNType digType = Digit100,
|
||||
bool checkConsistency=false, bool extendedResolution=false, int decimal_shift=0);
|
||||
|
||||
/**
|
||||
@@ -47,13 +47,13 @@ UnderTestPost* init_do_flow(std::vector<float> analog, std::vector<float> digits
|
||||
*
|
||||
* @param analog the analog recognitions
|
||||
* @param digits the digit recognitions
|
||||
* @param digType the digit model type (default Digital100)
|
||||
* @param digType the digit model type (default Digit100)
|
||||
* @param checkConsistency sets property checkConsistency (default = false)
|
||||
* @param extendedResolution sets property extendedResolution (default = false)
|
||||
* @param decimal_shift set property decimal_shift (Nachkommastellen, default = 0)
|
||||
* @return std::string the return value of do_Flow is the Value as string
|
||||
*/
|
||||
std::string process_doFlow(std::vector<float> analog, std::vector<float> digits, t_CNNType digType = Digital100,
|
||||
std::string process_doFlow(std::vector<float> analog, std::vector<float> digits, t_CNNType digType = Digit100,
|
||||
bool checkConsistency=false, bool extendedResolution=false, int decimal_shift=0);
|
||||
|
||||
/**
|
||||
|
||||
@@ -20,7 +20,7 @@ void testNegative() {
|
||||
|
||||
// extendResolution=false
|
||||
// da kein negativ, sollte kein Error auftreten
|
||||
UnderTestPost* underTestPost = init_do_flow(analogs, digits, Digital100, false, false, 0);
|
||||
UnderTestPost* underTestPost = init_do_flow(analogs, digits, Digit100, false, false, 0);
|
||||
setAllowNegatives(underTestPost, false);
|
||||
setPreValue(underTestPost, preValue);
|
||||
std::string result = process_doFlow(underTestPost);
|
||||
@@ -31,7 +31,7 @@ void testNegative() {
|
||||
// extendResolution=true
|
||||
// da negativ im Rahmen (letzte Stelle -0.2 > ergebnis), kein Error
|
||||
// Aber der PreValue wird gesetzt
|
||||
underTestPost = init_do_flow(analogs, digits, Digital100, false, true, 0);
|
||||
underTestPost = init_do_flow(analogs, digits, Digit100, false, true, 0);
|
||||
setAllowNegatives(underTestPost, false);
|
||||
setPreValue(underTestPost, preValue_extended);
|
||||
result = process_doFlow(underTestPost);
|
||||
@@ -42,7 +42,7 @@ void testNegative() {
|
||||
// extendResolution=true
|
||||
// Tolleranz überschritten, Error wird gesetzt, kein ReturnValue
|
||||
preValue_extended = 16.988; // zu groß
|
||||
underTestPost = init_do_flow(analogs, digits, Digital100, false, true, 0);
|
||||
underTestPost = init_do_flow(analogs, digits, Digit100, false, true, 0);
|
||||
setAllowNegatives(underTestPost, false);
|
||||
setPreValue(underTestPost, preValue_extended);
|
||||
result = process_doFlow(underTestPost);
|
||||
@@ -51,22 +51,33 @@ void testNegative() {
|
||||
delete underTestPost;
|
||||
|
||||
// extendResolution=false
|
||||
// value < preValue
|
||||
preValue = 16.99; // zu groß
|
||||
underTestPost = init_do_flow(analogs, digits, Digital100, false, false, 0);
|
||||
// value < (preValue -.01)
|
||||
preValue = 17.00; // zu groß
|
||||
underTestPost = init_do_flow(analogs, digits, Digit100, false, false, 0);
|
||||
setAllowNegatives(underTestPost, false);
|
||||
setPreValue(underTestPost, preValue_extended);
|
||||
setPreValue(underTestPost, preValue);
|
||||
result = process_doFlow(underTestPost);
|
||||
TEST_ASSERT_EQUAL_STRING("Neg. Rate - Read: - Raw: 16.98 - Pre: 16.99 ", underTestPost->getReadoutError().c_str());
|
||||
TEST_ASSERT_EQUAL_STRING("Neg. Rate - Read: - Raw: 16.98 - Pre: 17.00 ", underTestPost->getReadoutError().c_str());
|
||||
TEST_ASSERT_EQUAL_STRING("", result.c_str());
|
||||
delete underTestPost;
|
||||
|
||||
// extendResolution=false
|
||||
// value > (preValue -.01)
|
||||
// ist im Rahmen der Ungenauigkeit (-1 auf letzter Stelle)
|
||||
preValue = 16.99; // zu groß
|
||||
underTestPost = init_do_flow(analogs, digits, Digit100, false, false, 0);
|
||||
setAllowNegatives(underTestPost, false);
|
||||
setPreValue(underTestPost, preValue);
|
||||
result = process_doFlow(underTestPost);
|
||||
TEST_ASSERT_EQUAL_STRING("no error", underTestPost->getReadoutError().c_str());
|
||||
TEST_ASSERT_EQUAL_STRING("16.99", result.c_str());
|
||||
delete underTestPost;
|
||||
|
||||
// extendResolution=false
|
||||
// value < preValue
|
||||
// Aber Prüfung abgeschaltet => kein Fehler
|
||||
preValue = 16.99; // zu groß
|
||||
underTestPost = init_do_flow(analogs, digits, Digital100, false, false, 0);
|
||||
preValue = 17.99; // zu groß
|
||||
underTestPost = init_do_flow(analogs, digits, Digit100, false, false, 0);
|
||||
setAllowNegatives(underTestPost, true);
|
||||
setPreValue(underTestPost, preValue_extended);
|
||||
result = process_doFlow(underTestPost);
|
||||
@@ -84,8 +95,8 @@ void testNegative_Issues() {
|
||||
// Ohne decimal_shift
|
||||
std::vector<float> digits = { 2.0, 2.0, 0.0, 1.0, 7.2, 9.0, 8.0};
|
||||
std::vector<float> analogs = { };
|
||||
double preValue_extended = 22018.080;
|
||||
double preValue = 22018.08;
|
||||
double preValue_extended = 22018.090;
|
||||
double preValue = 22018.09;
|
||||
|
||||
const char* expected = "22017.98";
|
||||
|
||||
@@ -93,13 +104,15 @@ void testNegative_Issues() {
|
||||
// extendResolution=false
|
||||
// value < preValue
|
||||
// Prüfung eingeschaltet => Fehler
|
||||
preValue = 22018.08; // zu groß
|
||||
UnderTestPost* underTestPost = init_do_flow(analogs, digits, Digital100, false, false, -2);
|
||||
preValue = 22018.09; // zu groß
|
||||
UnderTestPost* underTestPost = init_do_flow(analogs, digits, Digit100, false, false, -2);
|
||||
setAllowNegatives(underTestPost, false);
|
||||
setPreValue(underTestPost, preValue_extended);
|
||||
std::string result = process_doFlow(underTestPost);
|
||||
TEST_ASSERT_EQUAL_STRING("Neg. Rate - Read: - Raw: 22017.98 - Pre: 22018.08 ", underTestPost->getReadoutError().c_str());
|
||||
TEST_ASSERT_EQUAL_STRING(expected, result.c_str());
|
||||
TEST_ASSERT_EQUAL_STRING("Neg. Rate - Read: - Raw: 22017.98 - Pre: 22018.09 ", underTestPost->getReadoutError().c_str());
|
||||
// if negativ no result any more
|
||||
|
||||
TEST_ASSERT_EQUAL_STRING("", result.c_str());
|
||||
delete underTestPost;
|
||||
|
||||
}
|
||||
@@ -114,28 +114,28 @@ void test_doFlowPP1() {
|
||||
// https://github.com/jomjol/AI-on-the-edge-device/issues/942#issuecomment-1226966346
|
||||
std::vector<float> digits = { 0.0, 2.9, 3.0, 2.9, 3.5, 9.5};
|
||||
std::vector<float> analogs = { };
|
||||
const char* expected = "33330";
|
||||
const char* expected = "33339";
|
||||
std::string result = process_doFlow(analogs, digits);
|
||||
TEST_ASSERT_EQUAL_STRING(expected, result.c_str());
|
||||
|
||||
// https://github.com/jomjol/AI-on-the-edge-device/issues/942#issuecomment-1226966346
|
||||
digits = { 9.9, 2.8, 2.9, 2.9, 3.7, 9.7};
|
||||
analogs = { };
|
||||
expected = "33340";
|
||||
expected = "33339";
|
||||
result = process_doFlow(analogs, digits);
|
||||
TEST_ASSERT_EQUAL_STRING(expected, result.c_str());
|
||||
|
||||
// https://github.com/jomjol/AI-on-the-edge-device/issues/942
|
||||
digits = { 0.0, 9.9, 6.8, 9.9, 3.7, 0.8, 6.9, 8.7};
|
||||
analogs = { };
|
||||
expected = "704179";
|
||||
expected = "704178";
|
||||
result = process_doFlow(analogs, digits);
|
||||
TEST_ASSERT_EQUAL_STRING(expected, result.c_str());
|
||||
|
||||
// https://github.com/jomjol/AI-on-the-edge-device/issues/942#issuecomment-1228343319
|
||||
digits = { 9.9, 6.8, 1.1, 4.7, 2.7, 6.0, 9.0, 2.8}; // changed 3.7 --> 2.7 (see picture in issue)
|
||||
analogs = { };
|
||||
expected = "7153693";
|
||||
expected = "7153692";
|
||||
result = process_doFlow(analogs, digits);
|
||||
TEST_ASSERT_EQUAL_STRING(expected, result.c_str());
|
||||
|
||||
@@ -178,28 +178,28 @@ void test_doFlowPP2() {
|
||||
std::vector<float> digits = { 1.0, 9.0, 9.0}; // Übergang wurde um 1 erhöht (200, statt 199)
|
||||
std::vector<float> analogs = { 7.1, 4.8, 8.3};
|
||||
const char* expected = "199.748";
|
||||
std::string result = process_doFlow(analogs, digits, Digital);
|
||||
std::string result = process_doFlow(analogs, digits, Digit);
|
||||
TEST_ASSERT_EQUAL_STRING(expected, result.c_str());
|
||||
|
||||
// Fehler bei Rolling (2002-09-09)
|
||||
// https://github.com/jomjol/AI-on-the-edge-device/issues/921#issuecomment-1242730397
|
||||
digits = { 3.0, 2.0, 2.0, 8.0, 9.0, 4.0, 1.7, 9.8}; // falscher Wert 32290.420
|
||||
analogs = { };
|
||||
expected = "32289.420";
|
||||
expected = "32289.419";
|
||||
const char* expected_extended= "32289.4198";
|
||||
// FALSCH! wegen ungenügender Präzision von NUMBERS->Value
|
||||
// expected_extended= "32289.4198";
|
||||
|
||||
// extendResolution=false, checkConsistency=false
|
||||
result = process_doFlow(analogs, digits, Digital100, false, false, -3);
|
||||
result = process_doFlow(analogs, digits, Digit100, false, false, -3);
|
||||
TEST_ASSERT_EQUAL_STRING(expected, result.c_str());
|
||||
|
||||
// extendResolution=true
|
||||
result = process_doFlow(analogs, digits, Digital100, false, true, -3);
|
||||
result = process_doFlow(analogs, digits, Digit100, false, true, -3);
|
||||
TEST_ASSERT_EQUAL_STRING(expected_extended, result.c_str());
|
||||
|
||||
// checkConsistency=true und extendResolution=true
|
||||
result = process_doFlow(analogs, digits, Digital100, false, true, -3);
|
||||
result = process_doFlow(analogs, digits, Digit100, false, true, -3);
|
||||
TEST_ASSERT_EQUAL_STRING(expected_extended, result.c_str());
|
||||
|
||||
// Fehler Rolling (2022-09-10)
|
||||
@@ -210,40 +210,40 @@ void test_doFlowPP2() {
|
||||
expected_extended= "83.99401";
|
||||
|
||||
// checkConsistency=false
|
||||
result = process_doFlow(analogs, digits, Digital100, false);
|
||||
result = process_doFlow(analogs, digits, Digit100, false);
|
||||
TEST_ASSERT_EQUAL_STRING(expected, result.c_str());
|
||||
|
||||
|
||||
// checkConsistency=true
|
||||
result = process_doFlow(analogs, digits, Digital100, true);
|
||||
result = process_doFlow(analogs, digits, Digit100, true);
|
||||
TEST_ASSERT_EQUAL_STRING(expected, result.c_str());
|
||||
|
||||
// extendResolution=true
|
||||
result = process_doFlow(analogs, digits, Digital100, false, true);
|
||||
result = process_doFlow(analogs, digits, Digit100, false, true);
|
||||
TEST_ASSERT_EQUAL_STRING(expected_extended, result.c_str());
|
||||
|
||||
// checkConsistency=true und extendResolution=true
|
||||
result = process_doFlow(analogs, digits, Digital100, false, true);
|
||||
result = process_doFlow(analogs, digits, Digit100, false, true);
|
||||
TEST_ASSERT_EQUAL_STRING(expected_extended, result.c_str());
|
||||
|
||||
// Fehler Rolling (2022-09-10)
|
||||
// https://github.com/jomjol/AI-on-the-edge-device/issues/994#issue-1368570945
|
||||
digits = { 0.0, 0.0, 1.0, 2.0, 2.8, 1.9, 2.8, 5.6}; // 123245.6 als falsches Ergebnis
|
||||
analogs = { };
|
||||
expected = "123236";
|
||||
expected = "123235";
|
||||
expected_extended= "123235.6";
|
||||
|
||||
// checkConsistency=true
|
||||
result = process_doFlow(analogs, digits, Digital100, false, false);
|
||||
result = process_doFlow(analogs, digits, Digit100, false, false);
|
||||
TEST_ASSERT_EQUAL_STRING(expected, result.c_str());
|
||||
|
||||
|
||||
// checkConsistency=true
|
||||
result = process_doFlow(analogs, digits, Digital100, true, false);
|
||||
result = process_doFlow(analogs, digits, Digit100, true, false);
|
||||
TEST_ASSERT_EQUAL_STRING(expected, result.c_str());
|
||||
|
||||
// extendResolution=true
|
||||
result = process_doFlow(analogs, digits, Digital100, false, true);
|
||||
result = process_doFlow(analogs, digits, Digit100, false, true);
|
||||
TEST_ASSERT_EQUAL_STRING(expected_extended, result.c_str());
|
||||
|
||||
// Fehler bei V11.2.0
|
||||
@@ -254,11 +254,11 @@ void test_doFlowPP2() {
|
||||
expected_extended= "3249.4692";
|
||||
|
||||
// checkConsistency=true
|
||||
result = process_doFlow(analogs, digits, Digital100, false, false, -3);
|
||||
result = process_doFlow(analogs, digits, Digit100, false, false, -3);
|
||||
TEST_ASSERT_EQUAL_STRING(expected, result.c_str());
|
||||
|
||||
// extendResolution=true
|
||||
result = process_doFlow(analogs, digits, Digital100, false, true, -3);
|
||||
result = process_doFlow(analogs, digits, Digit100, false, true, -3);
|
||||
TEST_ASSERT_EQUAL_STRING(expected_extended, result.c_str());
|
||||
|
||||
// Fehler bei V11.2.0
|
||||
@@ -269,11 +269,11 @@ void test_doFlowPP2() {
|
||||
expected_extended= "269.92272";
|
||||
|
||||
// extendResolution=true
|
||||
result = process_doFlow(analogs, digits, Digital100, false, false);
|
||||
result = process_doFlow(analogs, digits, Digit100, false, false);
|
||||
TEST_ASSERT_EQUAL_STRING(expected, result.c_str());
|
||||
|
||||
// checkConsistency=false und extendResolution=true
|
||||
result = process_doFlow(analogs, digits, Digital100, false, true);
|
||||
result = process_doFlow(analogs, digits, Digit100, false, true);
|
||||
TEST_ASSERT_EQUAL_STRING(expected_extended, result.c_str());
|
||||
|
||||
// Fehler bei V11.3.1
|
||||
@@ -284,11 +284,11 @@ void test_doFlowPP2() {
|
||||
expected_extended= "169.35935";
|
||||
|
||||
// extendResolution=false
|
||||
result = process_doFlow(analogs, digits, Digital100, false, false, -3);
|
||||
result = process_doFlow(analogs, digits, Digit100, false, false, -3);
|
||||
TEST_ASSERT_EQUAL_STRING(expected, result.c_str());
|
||||
|
||||
// checkConsistency=false und extendResolution=true
|
||||
result = process_doFlow(analogs, digits, Digital100, false, true, -3);
|
||||
result = process_doFlow(analogs, digits, Digit100, false, true, -3);
|
||||
TEST_ASSERT_EQUAL_STRING(expected_extended, result.c_str());
|
||||
|
||||
// Fehler bei V12.0.1
|
||||
@@ -299,11 +299,11 @@ void test_doFlowPP2() {
|
||||
expected_extended= "211.03555";
|
||||
|
||||
// extendResolution=false
|
||||
result = process_doFlow(analogs, digits, Digital100, false, false, -3);
|
||||
result = process_doFlow(analogs, digits, Digit100, false, false, -3);
|
||||
TEST_ASSERT_EQUAL_STRING(expected, result.c_str());
|
||||
|
||||
// checkConsistency=false und extendResolution=true
|
||||
result = process_doFlow(analogs, digits, Digital100, false, true, -3);
|
||||
result = process_doFlow(analogs, digits, Digit100, false, true, -3);
|
||||
TEST_ASSERT_EQUAL_STRING(expected_extended, result.c_str());
|
||||
|
||||
// Fehler bei V12.0.1
|
||||
@@ -314,11 +314,11 @@ void test_doFlowPP2() {
|
||||
expected_extended= "245.9386";
|
||||
|
||||
// extendResolution=false
|
||||
result = process_doFlow(analogs, digits, Digital100, false, false, 0);
|
||||
result = process_doFlow(analogs, digits, Digit100, false, false, 0);
|
||||
TEST_ASSERT_EQUAL_STRING(expected, result.c_str());
|
||||
|
||||
// checkConsistency=false und extendResolution=true
|
||||
result = process_doFlow(analogs, digits, Digital100, false, true, 0);
|
||||
result = process_doFlow(analogs, digits, Digit100, false, true, 0);
|
||||
TEST_ASSERT_EQUAL_STRING(expected_extended, result.c_str());
|
||||
|
||||
// Fehler bei V12.0.1
|
||||
@@ -329,11 +329,11 @@ void test_doFlowPP2() {
|
||||
expected_extended= "245.9386";
|
||||
|
||||
// extendResolution=false
|
||||
result = process_doFlow(analogs, digits, Digital100, false, false, 0);
|
||||
result = process_doFlow(analogs, digits, Digit100, false, false, 0);
|
||||
TEST_ASSERT_EQUAL_STRING(expected, result.c_str());
|
||||
|
||||
// checkConsistency=false und extendResolution=true
|
||||
result = process_doFlow(analogs, digits, Digital100, false, true, 0);
|
||||
result = process_doFlow(analogs, digits, Digit100, false, true, 0);
|
||||
TEST_ASSERT_EQUAL_STRING(expected_extended, result.c_str());
|
||||
}
|
||||
|
||||
@@ -346,11 +346,11 @@ void test_doFlowPP3() {
|
||||
const char* expected_extended= "247.2045";
|
||||
|
||||
// extendResolution=false
|
||||
std::string result = process_doFlow(analogs, digits, Digital100, false, false, 0);
|
||||
std::string result = process_doFlow(analogs, digits, Digit100, false, false, 0);
|
||||
TEST_ASSERT_EQUAL_STRING(expected, result.c_str());
|
||||
|
||||
// checkConsistency=false und extendResolution=true
|
||||
result = process_doFlow(analogs, digits, Digital100, false, true, 0);
|
||||
result = process_doFlow(analogs, digits, Digit100, false, true, 0);
|
||||
TEST_ASSERT_EQUAL_STRING(expected_extended, result.c_str());
|
||||
|
||||
|
||||
@@ -362,11 +362,11 @@ void test_doFlowPP3() {
|
||||
expected_extended= "142.92690";
|
||||
|
||||
// extendResolution=false
|
||||
result = process_doFlow(analogs, digits, Digital100, false, false, 0);
|
||||
result = process_doFlow(analogs, digits, Digit100, false, false, 0);
|
||||
TEST_ASSERT_EQUAL_STRING(expected, result.c_str());
|
||||
|
||||
// checkConsistency=false und extendResolution=true
|
||||
result = process_doFlow(analogs, digits, Digital100, false, true, 0);
|
||||
result = process_doFlow(analogs, digits, Digit100, false, true, 0);
|
||||
TEST_ASSERT_EQUAL_STRING(expected_extended, result.c_str());
|
||||
|
||||
|
||||
@@ -379,14 +379,14 @@ void test_doFlowPP3() {
|
||||
expected_extended= "170.05287";
|
||||
|
||||
// extendResolution=false
|
||||
UnderTestPost* undertestPost = init_do_flow(analogs, digits, Digital100, false, false, -3);
|
||||
UnderTestPost* undertestPost = init_do_flow(analogs, digits, Digit100, false, false, -3);
|
||||
setAnalogdigitTransistionStart(undertestPost, 7.7);
|
||||
result = process_doFlow(undertestPost);
|
||||
TEST_ASSERT_EQUAL_STRING(expected, result.c_str());
|
||||
delete undertestPost;
|
||||
|
||||
// checkConsistency=false und extendResolution=true
|
||||
undertestPost = init_do_flow(analogs, digits, Digital100, false, true, -3);
|
||||
undertestPost = init_do_flow(analogs, digits, Digit100, false, true, -3);
|
||||
setAnalogdigitTransistionStart(undertestPost, 7.7);
|
||||
result = process_doFlow(undertestPost);
|
||||
TEST_ASSERT_EQUAL_STRING(expected_extended, result.c_str());
|
||||
@@ -400,11 +400,11 @@ void test_doFlowPP3() {
|
||||
expected_extended= "91.88174";
|
||||
|
||||
// extendResolution=false
|
||||
result = process_doFlow(analogs, digits, Digital100, false, false, 0);
|
||||
result = process_doFlow(analogs, digits, Digit100, false, false, 0);
|
||||
TEST_ASSERT_EQUAL_STRING(expected, result.c_str());
|
||||
|
||||
// checkConsistency=false und extendResolution=true
|
||||
result = process_doFlow(analogs, digits, Digital100, false, true, 0);
|
||||
result = process_doFlow(analogs, digits, Digit100, false, true, 0);
|
||||
TEST_ASSERT_EQUAL_STRING(expected_extended, result.c_str());
|
||||
|
||||
|
||||
@@ -416,11 +416,11 @@ void test_doFlowPP3() {
|
||||
expected_extended= "92.38320";
|
||||
|
||||
// extendResolution=false
|
||||
result = process_doFlow(analogs, digits, Digital100, false, false, 0);
|
||||
result = process_doFlow(analogs, digits, Digit100, false, false, 0);
|
||||
TEST_ASSERT_EQUAL_STRING(expected, result.c_str());
|
||||
|
||||
// checkConsistency=false und extendResolution=true
|
||||
result = process_doFlow(analogs, digits, Digital100, false, true, 0);
|
||||
result = process_doFlow(analogs, digits, Digit100, false, true, 0);
|
||||
TEST_ASSERT_EQUAL_STRING(expected_extended, result.c_str());
|
||||
|
||||
// Fehler V11.3.0
|
||||
@@ -431,11 +431,11 @@ void test_doFlowPP3() {
|
||||
expected_extended= "7472.7594";
|
||||
|
||||
// extendResolution=false
|
||||
result = process_doFlow(analogs, digits, Digital100, false, false, -3);
|
||||
result = process_doFlow(analogs, digits, Digit100, false, false, -3);
|
||||
TEST_ASSERT_EQUAL_STRING(expected, result.c_str());
|
||||
|
||||
// checkConsistency=false und extendResolution=true
|
||||
result = process_doFlow(analogs, digits, Digital100, false, true, -3);
|
||||
result = process_doFlow(analogs, digits, Digit100, false, true, -3);
|
||||
TEST_ASSERT_EQUAL_STRING(expected_extended, result.c_str());
|
||||
|
||||
// Fehler V12.0.1
|
||||
@@ -446,11 +446,11 @@ void test_doFlowPP3() {
|
||||
expected_extended= "577.86490";
|
||||
|
||||
// extendResolution=false
|
||||
result = process_doFlow(analogs, digits, Digital100, false, false, 0);
|
||||
result = process_doFlow(analogs, digits, Digit100, false, false, 0);
|
||||
TEST_ASSERT_EQUAL_STRING(expected, result.c_str());
|
||||
|
||||
// checkConsistency=false und extendResolution=true
|
||||
result = process_doFlow(analogs, digits, Digital100, false, true, 0);
|
||||
result = process_doFlow(analogs, digits, Digit100, false, true, 0);
|
||||
TEST_ASSERT_EQUAL_STRING(expected_extended, result.c_str());
|
||||
|
||||
|
||||
@@ -462,11 +462,11 @@ void test_doFlowPP3() {
|
||||
expected_extended= "211.03580";
|
||||
|
||||
// extendResolution=false
|
||||
result = process_doFlow(analogs, digits, Digital100, false, false, -3);
|
||||
result = process_doFlow(analogs, digits, Digit100, false, false, -3);
|
||||
TEST_ASSERT_EQUAL_STRING(expected, result.c_str());
|
||||
|
||||
// checkConsistency=false und extendResolution=true
|
||||
result = process_doFlow(analogs, digits, Digital100, false, true, -3);
|
||||
result = process_doFlow(analogs, digits, Digit100, false, true, -3);
|
||||
TEST_ASSERT_EQUAL_STRING(expected_extended, result.c_str());
|
||||
|
||||
// Fehler V12.0.1
|
||||
@@ -477,11 +477,11 @@ void test_doFlowPP3() {
|
||||
expected_extended= "126.9231";
|
||||
|
||||
// extendResolution=false
|
||||
result = process_doFlow(analogs, digits, Digital100, false, false, 0);
|
||||
result = process_doFlow(analogs, digits, Digit100, false, false, 0);
|
||||
TEST_ASSERT_EQUAL_STRING(expected, result.c_str());
|
||||
|
||||
// checkConsistency=false und extendResolution=true
|
||||
result = process_doFlow(analogs, digits, Digital100, false, true, 0);
|
||||
result = process_doFlow(analogs, digits, Digit100, false, true, 0);
|
||||
TEST_ASSERT_EQUAL_STRING(expected_extended, result.c_str());
|
||||
|
||||
// Fehler V12.0.1
|
||||
@@ -492,11 +492,11 @@ void test_doFlowPP3() {
|
||||
expected_extended= "386.05672";
|
||||
|
||||
// extendResolution=false
|
||||
result = process_doFlow(analogs, digits, Digital100, false, false, -3);
|
||||
result = process_doFlow(analogs, digits, Digit100, false, false, -3);
|
||||
TEST_ASSERT_EQUAL_STRING(expected, result.c_str());
|
||||
|
||||
// checkConsistency=false und extendResolution=true
|
||||
result = process_doFlow(analogs, digits, Digital100, false, true, -3);
|
||||
result = process_doFlow(analogs, digits, Digit100, false, true, -3);
|
||||
TEST_ASSERT_EQUAL_STRING(expected_extended, result.c_str());
|
||||
|
||||
// Fehler V12.0.1
|
||||
@@ -508,14 +508,14 @@ void test_doFlowPP3() {
|
||||
expected_extended= "171.24178";
|
||||
|
||||
// extendResolution=false
|
||||
undertestPost = init_do_flow(analogs, digits, Digital100, false, false, -3);
|
||||
undertestPost = init_do_flow(analogs, digits, Digit100, false, false, -3);
|
||||
setAnalogdigitTransistionStart(undertestPost, 7.7);
|
||||
result = process_doFlow(undertestPost);
|
||||
TEST_ASSERT_EQUAL_STRING(expected, result.c_str());
|
||||
delete undertestPost;
|
||||
|
||||
// checkConsistency=false und extendResolution=true
|
||||
undertestPost = init_do_flow(analogs, digits, Digital100, false, true, -3);
|
||||
undertestPost = init_do_flow(analogs, digits, Digit100, false, true, -3);
|
||||
setAnalogdigitTransistionStart(undertestPost, 7.7);
|
||||
result = process_doFlow(undertestPost);
|
||||
TEST_ASSERT_EQUAL_STRING(expected_extended, result.c_str());
|
||||
@@ -533,11 +533,11 @@ void test_doFlowPP4() {
|
||||
const char* expected_extended= "717.01658";
|
||||
|
||||
// extendResolution=false
|
||||
std::string result = process_doFlow(analogs, digits, Digital100, false, false);
|
||||
std::string result = process_doFlow(analogs, digits, Digit100, false, false);
|
||||
TEST_ASSERT_EQUAL_STRING(expected, result.c_str());
|
||||
|
||||
// checkConsistency=false und extendResolution=true
|
||||
result = process_doFlow(analogs, digits, Digital100, false, true);
|
||||
result = process_doFlow(analogs, digits, Digit100, false, true);
|
||||
TEST_ASSERT_EQUAL_STRING(expected_extended, result.c_str());
|
||||
|
||||
}
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
void test_getReadoutRawString() {
|
||||
|
||||
// no ROIs setted up
|
||||
UnderTestPost* _undertestPost = setUpClassFlowPostprocessing(Digital100, Analogue100);
|
||||
UnderTestPost* _undertestPost = setUpClassFlowPostprocessing(Digit100, Analogue100);
|
||||
|
||||
string result = _undertestPost->flowAnalog->getReadoutRawString(0);
|
||||
TEST_ASSERT_EQUAL_STRING("", result.c_str());
|
||||
|
||||
22
code/test/components/jomjol_mqtt/test_server_mqtt.cpp
Normal file
22
code/test/components/jomjol_mqtt/test_server_mqtt.cpp
Normal file
@@ -0,0 +1,22 @@
|
||||
#include <unity.h>
|
||||
#include <server_mqtt.h>
|
||||
|
||||
void test_createNodeId()
|
||||
{
|
||||
std::string topic = "watermeter";
|
||||
TEST_ASSERT_EQUAL_STRING("watermeter", createNodeId(topic).c_str());
|
||||
|
||||
topic = "/watermeter";
|
||||
TEST_ASSERT_EQUAL_STRING("watermeter", createNodeId(topic).c_str());
|
||||
|
||||
topic = "home/test/watermeter";
|
||||
TEST_ASSERT_EQUAL_STRING("watermeter", createNodeId(topic).c_str());
|
||||
|
||||
topic = "home/test/subtopic/something/test/watermeter";
|
||||
TEST_ASSERT_EQUAL_STRING("watermeter", createNodeId(topic).c_str());
|
||||
}
|
||||
|
||||
void test_mqtt()
|
||||
{
|
||||
test_createNodeId();
|
||||
}
|
||||
65
code/test/components/openmetrics/test_openmetrics.cpp
Normal file
65
code/test/components/openmetrics/test_openmetrics.cpp
Normal file
@@ -0,0 +1,65 @@
|
||||
#include <unity.h>
|
||||
#include <openmetrics.h>
|
||||
|
||||
void test_createMetric()
|
||||
{
|
||||
// simple happy path
|
||||
const char *expected = "# HELP metric_name short description\n# TYPE metric_name gauge\nmetric_name 123.456\n";
|
||||
std::string result = createMetric("metric_name", "short description", "gauge", "123.456");
|
||||
TEST_ASSERT_EQUAL_STRING(expected, result.c_str());
|
||||
}
|
||||
|
||||
/**
|
||||
* test the replaceString function as it's a dependency to sanitize sequence names
|
||||
*/
|
||||
void test_replaceString()
|
||||
{
|
||||
std::string sample = "hello\\world\\";
|
||||
replaceAll(sample, "\\", "");
|
||||
TEST_ASSERT_EQUAL_STRING("helloworld", sample.c_str());
|
||||
|
||||
sample = "hello\"world\"";
|
||||
replaceAll(sample, "\"", "");
|
||||
TEST_ASSERT_EQUAL_STRING("helloworld", sample.c_str());
|
||||
|
||||
sample = "hello\nworld\n";
|
||||
replaceAll(sample, "\n", "");
|
||||
TEST_ASSERT_EQUAL_STRING("helloworld", sample.c_str());
|
||||
|
||||
sample = "\\\\\\\\\\\\\\\\\\hello\\world\\\\\\\\\\\\\\\\\\\\";
|
||||
replaceAll(sample, "\\", "");
|
||||
TEST_ASSERT_EQUAL_STRING("helloworld", sample.c_str());
|
||||
}
|
||||
|
||||
void test_createSequenceMetrics()
|
||||
{
|
||||
std::vector<NumberPost *> NUMBERS;
|
||||
NumberPost *number_1 = new NumberPost;
|
||||
number_1->name = "main";
|
||||
number_1->ReturnValue = "123.456";
|
||||
NUMBERS.push_back(number_1);
|
||||
|
||||
const std::string metricNamePrefix = "ai_on_the_edge_device";
|
||||
const std::string metricName = metricNamePrefix + "_flow_value";
|
||||
|
||||
std::string expected1 = "# HELP " + metricName + " current value of meter readout\n# TYPE " + metricName + " gauge\n" +
|
||||
metricName + "{sequence=\"" + number_1->name + "\"} " + number_1->ReturnValue + "\n";
|
||||
TEST_ASSERT_EQUAL_STRING(expected1.c_str(), createSequenceMetrics(metricNamePrefix, NUMBERS).c_str());
|
||||
|
||||
NumberPost *number_2 = new NumberPost;
|
||||
number_2->name = "secondary";
|
||||
number_2->ReturnValue = "1.0";
|
||||
NUMBERS.push_back(number_2);
|
||||
|
||||
std::string expected2 = "# HELP " + metricName + " current value of meter readout\n# TYPE " + metricName + " gauge\n" +
|
||||
metricName + "{sequence=\"" + number_1->name + "\"} " + number_1->ReturnValue + "\n" +
|
||||
metricName + "{sequence=\"" + number_2->name + "\"} " + number_2->ReturnValue + "\n";
|
||||
TEST_ASSERT_EQUAL_STRING(expected2.c_str(), createSequenceMetrics(metricNamePrefix, NUMBERS).c_str());
|
||||
}
|
||||
|
||||
void test_openmetrics()
|
||||
{
|
||||
test_createMetric();
|
||||
test_replaceString();
|
||||
test_createSequenceMetrics();
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user