mirror of
https://github.com/jomjol/AI-on-the-edge-device.git
synced 2025-12-08 04:26:58 +03:00
Compare commits
11 Commits
clarify-pa
...
test
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1ceb47fbc7 | ||
|
|
a413d0228e | ||
|
|
e22eaa2736 | ||
|
|
154d159595 | ||
|
|
23a5458a2b | ||
|
|
89097fa5a2 | ||
|
|
6952db0298 | ||
|
|
550889c373 | ||
|
|
1200ee1289 | ||
|
|
fceccb90b0 | ||
|
|
d68c95d626 |
32
.github/workflows/build.yaml
vendored
32
.github/workflows/build.yaml
vendored
@@ -1,10 +1,6 @@
|
||||
name: Build and Pack
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
release:
|
||||
types: [released] # Only trigger on published releases (not drafts or pre-released)
|
||||
on: [push, pull_request]
|
||||
|
||||
jobs:
|
||||
#########################################################################################
|
||||
@@ -88,8 +84,7 @@ jobs:
|
||||
cd ../..
|
||||
|
||||
cp -r ./sd-card/html/* ./html/
|
||||
rm -f ./html/edit_config_template.html # Remove the config page template, it is no longer needed
|
||||
|
||||
|
||||
echo "Replacing variables..."
|
||||
cd html
|
||||
find . -type f -exec sed -i 's/$COMMIT_HASH/${{ steps.vars.outputs.sha_short }}/g' {} \;
|
||||
@@ -290,9 +285,8 @@ jobs:
|
||||
rm -rf ./sd-card/html
|
||||
rm -rf ./sd-card/demo
|
||||
cp -r ./html ./sd-card/ # Overwrite the Web UI with the preprocessed files
|
||||
rm -f ./sd-card/Readme.md
|
||||
cp -r ./demo ./sd-card/
|
||||
cd sd-card; rm -rf html/param-tooltips; zip -r ../manual_setup/sd-card.zip *; cd ..
|
||||
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)
|
||||
@@ -308,7 +302,7 @@ jobs:
|
||||
prepare-release:
|
||||
runs-on: ubuntu-latest
|
||||
needs: [pack-for-update, pack-for-manual_setup, pack-for-remote_setup]
|
||||
if: github.event_name == 'release' # Only run when the trigger is a release
|
||||
if: startsWith(github.ref, 'refs/tags/')
|
||||
|
||||
# Sets permissions of the GITHUB_TOKEN to allow updating the branches
|
||||
permissions:
|
||||
@@ -410,7 +404,7 @@ jobs:
|
||||
#########################################################################################
|
||||
# Make sure to also update update-webinstaller.yml!
|
||||
update-web-installer:
|
||||
if: github.event_name == 'release' # Only run when the trigger is a release
|
||||
if: github.event_name == 'release' && github.event.action == 'published' # Only run on release but not on prerelease
|
||||
needs: [prepare-release]
|
||||
environment:
|
||||
name: github-pages
|
||||
@@ -439,22 +433,22 @@ jobs:
|
||||
- name: Add binary to Web Installer and update manifest
|
||||
run: |
|
||||
echo "Updating Web installer to use firmware from ${{ steps.last_release.outputs.tag_name }}..."
|
||||
rm -f webinstaller/binary/firmware.bin
|
||||
rm -f docs/binary/firmware.bin
|
||||
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 webinstaller/binary/firmware.bin
|
||||
cp -f firmware.bin docs/binary/firmware.bin
|
||||
echo "Updating index and manifest file..."
|
||||
sed -i 's/$VERSION/${{ steps.last_release.outputs.tag_name }}/g' webinstaller/index.html
|
||||
sed -i 's/$VERSION/${{ steps.last_release.outputs.tag_name }}/g' webinstaller/manifest.json
|
||||
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@v5
|
||||
uses: actions/configure-pages@v4
|
||||
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-pages-artifact@v3
|
||||
uses: actions/upload-pages-artifact@v2
|
||||
with:
|
||||
path: 'webinstaller'
|
||||
path: 'docs'
|
||||
|
||||
- name: Deploy to GitHub Pages
|
||||
id: deployment
|
||||
uses: actions/deploy-pages@v4.0.5 # Note: v4 does not work!
|
||||
uses: actions/deploy-pages@v3 # Note: v4 does not work!
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# This updates the Web Installer with the files from the webinstaller folder and the binary of the latest release
|
||||
# This updates the Web Installer with the files from the docs folder and the binary of the latest release
|
||||
# it only gets run on:
|
||||
# - Manually triggered
|
||||
# Make sure to also update the lower part of build.yml!
|
||||
@@ -11,7 +11,7 @@ on:
|
||||
# branches:
|
||||
# - rolling
|
||||
# paths:
|
||||
# - webinstaller # The path filter somehow does not work, so lets run it on every change to rolling
|
||||
# - docs # The path filter somehow does not work, so lets run it on every change to rolling
|
||||
|
||||
jobs:
|
||||
manually-update-web-installer:
|
||||
@@ -42,13 +42,13 @@ jobs:
|
||||
- name: Add binary to Web Installer and update manifest
|
||||
run: |
|
||||
echo "Updating Web installer to use firmware from ${{ steps.last_release.outputs.tag_name }}..."
|
||||
rm -f webinstaller/binary/firmware.bin
|
||||
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
|
||||
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 webinstaller/binary/firmware.bin
|
||||
cp -f firmware.bin docs/binary/firmware.bin
|
||||
echo "Updating index and manifest file..."
|
||||
sed -i 's/$VERSION/${{ steps.last_release.outputs.tag_name }}/g' webinstaller/index.html
|
||||
sed -i 's/$VERSION/${{ steps.last_release.outputs.tag_name }}/g' webinstaller/manifest.json
|
||||
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@v5
|
||||
@@ -56,7 +56,7 @@ jobs:
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-pages-artifact@v3
|
||||
with:
|
||||
path: 'webinstaller'
|
||||
path: 'docs'
|
||||
|
||||
- name: Deploy to GitHub Pages
|
||||
id: deployment
|
||||
|
||||
2
.github/workflows/reply-bot.yaml
vendored
2
.github/workflows/reply-bot.yaml
vendored
@@ -18,7 +18,7 @@ permissions:
|
||||
|
||||
jobs:
|
||||
comment:
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: ubuntu-20.04
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
|
||||
|
||||
430
Changelog.md
430
Changelog.md
File diff suppressed because it is too large
Load Diff
82
README.md
82
README.md
@@ -250,13 +250,6 @@ There are some ideas and feature requests which are not currently being pursued
|
||||
<sub><b>Frank Haverland</b></sub>
|
||||
</a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://github.com/SybexX">
|
||||
<img src="https://avatars.githubusercontent.com/u/587201?v=4" width="100;" alt="SybexX"/>
|
||||
<br />
|
||||
<sub><b>michael</b></sub>
|
||||
</a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://github.com/Slider0007">
|
||||
<img src="https://avatars.githubusercontent.com/u/115730895?v=4" width="100;" alt="Slider0007"/>
|
||||
@@ -264,6 +257,13 @@ There are some ideas and feature requests which are not currently being pursued
|
||||
<sub><b>Slider0007</b></sub>
|
||||
</a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://github.com/SybexX">
|
||||
<img src="https://avatars.githubusercontent.com/u/587201?v=4" width="100;" alt="SybexX"/>
|
||||
<br />
|
||||
<sub><b>michael</b></sub>
|
||||
</a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://github.com/nliaudat">
|
||||
<img src="https://avatars.githubusercontent.com/u/6782613?v=4" width="100;" alt="nliaudat"/>
|
||||
@@ -368,13 +368,6 @@ There are some ideas and feature requests which are not currently being pursued
|
||||
<sub><b>parhedberg</b></sub>
|
||||
</a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://github.com/fsck-block">
|
||||
<img src="https://avatars.githubusercontent.com/u/58307481?v=4" width="100;" alt="fsck-block"/>
|
||||
<br />
|
||||
<sub><b>fsck-block</b></sub>
|
||||
</a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://github.com/slovdahl">
|
||||
<img src="https://avatars.githubusercontent.com/u/1417619?v=4" width="100;" alt="slovdahl"/>
|
||||
@@ -396,6 +389,13 @@ There are some ideas and feature requests which are not currently being pursued
|
||||
<sub><b>LordGuilly</b></sub>
|
||||
</a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://github.com/bilalmirza74">
|
||||
<img src="https://avatars.githubusercontent.com/u/84387676?v=4" width="100;" alt="bilalmirza74"/>
|
||||
<br />
|
||||
<sub><b>Bilal Mirza</b></sub>
|
||||
</a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://github.com/muggenhor">
|
||||
<img src="https://avatars.githubusercontent.com/u/484066?v=4" width="100;" alt="muggenhor"/>
|
||||
@@ -406,17 +406,10 @@ There are some ideas and feature requests which are not currently being pursued
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center">
|
||||
<a href="https://github.com/bilalmirza74">
|
||||
<img src="https://avatars.githubusercontent.com/u/84387676?v=4" width="100;" alt="bilalmirza74"/>
|
||||
<a href="https://github.com/ppisljar">
|
||||
<img src="https://avatars.githubusercontent.com/u/13629809?v=4" width="100;" alt="ppisljar"/>
|
||||
<br />
|
||||
<sub><b>Bilal Mirza</b></sub>
|
||||
</a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://github.com/AngryApostrophe">
|
||||
<img src="https://avatars.githubusercontent.com/u/89547888?v=4" width="100;" alt="AngryApostrophe"/>
|
||||
<br />
|
||||
<sub><b>AngryApostrophe</b></sub>
|
||||
<sub><b>Peter Pisljar</b></sub>
|
||||
</a>
|
||||
</td>
|
||||
<td align="center">
|
||||
@@ -433,13 +426,6 @@ There are some ideas and feature requests which are not currently being pursued
|
||||
<sub><b>Ranjana761</b></sub>
|
||||
</a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://github.com/SURYANSH-RAI">
|
||||
<img src="https://avatars.githubusercontent.com/u/79277130?v=4" width="100;" alt="SURYANSH-RAI"/>
|
||||
<br />
|
||||
<sub><b>SURYANSH RAI</b></sub>
|
||||
</a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://github.com/SkylightXD">
|
||||
<img src="https://avatars.githubusercontent.com/u/16561545?v=4" width="100;" alt="SkylightXD"/>
|
||||
@@ -447,8 +433,6 @@ There are some ideas and feature requests which are not currently being pursued
|
||||
<sub><b>SkylightXD</b></sub>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center">
|
||||
<a href="https://github.com/ottk3">
|
||||
<img src="https://avatars.githubusercontent.com/u/5236802?v=4" width="100;" alt="ottk3"/>
|
||||
@@ -463,6 +447,8 @@ There are some ideas and feature requests which are not currently being pursued
|
||||
<sub><b>Tobias Bieniek</b></sub>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center">
|
||||
<a href="https://github.com/tkopczuk">
|
||||
<img src="https://avatars.githubusercontent.com/u/101632?v=4" width="100;" alt="tkopczuk"/>
|
||||
@@ -491,8 +477,6 @@ There are some ideas and feature requests which are not currently being pursued
|
||||
<sub><b>flox_x</b></sub>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center">
|
||||
<a href="https://github.com/gneluka">
|
||||
<img src="https://avatars.githubusercontent.com/u/32097881?v=4" width="100;" alt="gneluka"/>
|
||||
@@ -507,6 +491,8 @@ There are some ideas and feature requests which are not currently being pursued
|
||||
<sub><b>kalwados</b></sub>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center">
|
||||
<a href="https://github.com/kub3let">
|
||||
<img src="https://avatars.githubusercontent.com/u/95883234?v=4" width="100;" alt="kub3let"/>
|
||||
@@ -535,8 +521,13 @@ There are some ideas and feature requests which are not currently being pursued
|
||||
<sub><b>smartboart</b></sub>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center">
|
||||
<a href="https://github.com/AngryApostrophe">
|
||||
<img src="https://avatars.githubusercontent.com/u/89547888?v=4" width="100;" alt="AngryApostrophe"/>
|
||||
<br />
|
||||
<sub><b>AngryApostrophe</b></sub>
|
||||
</a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://github.com/wetneb">
|
||||
<img src="https://avatars.githubusercontent.com/u/309908?v=4" width="100;" alt="wetneb"/>
|
||||
@@ -544,6 +535,8 @@ There are some ideas and feature requests which are not currently being pursued
|
||||
<sub><b>Antonin Delpeuch</b></sub>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center">
|
||||
<a href="https://github.com/adarazs">
|
||||
<img src="https://avatars.githubusercontent.com/u/6269603?v=4" width="100;" alt="adarazs"/>
|
||||
@@ -579,8 +572,6 @@ There are some ideas and feature requests which are not currently being pursued
|
||||
<sub><b>Dave</b></sub>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center">
|
||||
<a href="https://github.com/FarukhS52">
|
||||
<img src="https://avatars.githubusercontent.com/u/129654632?v=4" width="100;" alt="FarukhS52"/>
|
||||
@@ -588,6 +579,8 @@ There are some ideas and feature requests which are not currently being pursued
|
||||
<sub><b>Farookh Zaheer Siddiqui</b></sub>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center">
|
||||
<a href="https://github.com/hex7c0">
|
||||
<img src="https://avatars.githubusercontent.com/u/4419146?v=4" width="100;" alt="hex7c0"/>
|
||||
@@ -623,8 +616,6 @@ There are some ideas and feature requests which are not currently being pursued
|
||||
<sub><b>Joerg Rosenkranz</b></sub>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center">
|
||||
<a href="https://github.com/Innovatorcloudy">
|
||||
<img src="https://avatars.githubusercontent.com/u/183274513?v=4" width="100;" alt="Innovatorcloudy"/>
|
||||
@@ -632,6 +623,8 @@ There are some ideas and feature requests which are not currently being pursued
|
||||
<sub><b>KrishCode</b></sub>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td align="center">
|
||||
<a href="https://github.com/myxor">
|
||||
<img src="https://avatars.githubusercontent.com/u/1397377?v=4" width="100;" alt="myxor"/>
|
||||
@@ -659,13 +652,6 @@ There are some ideas and feature requests which are not currently being pursued
|
||||
<br />
|
||||
<sub><b>Michael Geissler</b></sub>
|
||||
</a>
|
||||
</td>
|
||||
<td align="center">
|
||||
<a href="https://github.com/ppisljar">
|
||||
<img src="https://avatars.githubusercontent.com/u/13629809?v=4" width="100;" alt="ppisljar"/>
|
||||
<br />
|
||||
<sub><b>Peter Pisljar</b></sub>
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tbody>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
```
|
||||
git clone https://github.com/jomjol/AI-on-the-edge-device.git
|
||||
cd AI-on-the-edge-device
|
||||
git checkout main
|
||||
git checkout rolling
|
||||
git submodule update --init
|
||||
```
|
||||
|
||||
@@ -12,10 +12,10 @@ git submodule update --init
|
||||
```
|
||||
cd /components/submodule-name (e.g. tflite-micro-example)
|
||||
git checkout VERSION (e.g. HASH of latest tflite-micro-example build)
|
||||
cd ../../ (at the code level)
|
||||
cd ../../ (auf Ebene von code)
|
||||
git submodule update --init
|
||||
```
|
||||
You may need to manually delete some directories in the 'components' folder beforehand, as they were not deleted during checkout (before 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.
|
||||
@@ -51,7 +51,7 @@ pio device monitor -p /dev/ttyUSB0
|
||||
```
|
||||
git clone https://github.com/jomjol/AI-on-the-edge-device.git
|
||||
cd AI-on-the-edge-device
|
||||
git checkout main
|
||||
git checkout rolling
|
||||
git submodule update --init
|
||||
```
|
||||
|
||||
|
||||
@@ -1,226 +0,0 @@
|
||||
/* Src: https://github.com/Zunawe/md5-c, commit: f3529b6
|
||||
* License: Unlicense */
|
||||
/*
|
||||
* Derived from the RSA Data Security, Inc. MD5 Message-Digest Algorithm
|
||||
* and modified slightly to be functionally identical but condensed into control structures.
|
||||
*/
|
||||
|
||||
#include "md5.h"
|
||||
|
||||
/*
|
||||
* Constants defined by the MD5 algorithm
|
||||
*/
|
||||
#define A 0x67452301
|
||||
#define B 0xefcdab89
|
||||
#define C 0x98badcfe
|
||||
#define D 0x10325476
|
||||
|
||||
static uint32_t S[] = {7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22,
|
||||
5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20,
|
||||
4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23,
|
||||
6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21};
|
||||
|
||||
static uint32_t K[] = {0xd76aa478, 0xe8c7b756, 0x242070db, 0xc1bdceee,
|
||||
0xf57c0faf, 0x4787c62a, 0xa8304613, 0xfd469501,
|
||||
0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be,
|
||||
0x6b901122, 0xfd987193, 0xa679438e, 0x49b40821,
|
||||
0xf61e2562, 0xc040b340, 0x265e5a51, 0xe9b6c7aa,
|
||||
0xd62f105d, 0x02441453, 0xd8a1e681, 0xe7d3fbc8,
|
||||
0x21e1cde6, 0xc33707d6, 0xf4d50d87, 0x455a14ed,
|
||||
0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a,
|
||||
0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c,
|
||||
0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70,
|
||||
0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05,
|
||||
0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665,
|
||||
0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039,
|
||||
0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1,
|
||||
0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1,
|
||||
0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391};
|
||||
|
||||
/*
|
||||
* Padding used to make the size (in bits) of the input congruent to 448 mod 512
|
||||
*/
|
||||
static uint8_t PADDING[] = {0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
|
||||
|
||||
/*
|
||||
* Bit-manipulation functions defined by the MD5 algorithm
|
||||
*/
|
||||
#define F(X, Y, Z) ((X & Y) | (~X & Z))
|
||||
#define G(X, Y, Z) ((X & Z) | (Y & ~Z))
|
||||
#define H(X, Y, Z) (X ^ Y ^ Z)
|
||||
#define I(X, Y, Z) (Y ^ (X | ~Z))
|
||||
|
||||
/*
|
||||
* Rotates a 32-bit word left by n bits
|
||||
*/
|
||||
uint32_t rotateLeft(uint32_t x, uint32_t n){
|
||||
return (x << n) | (x >> (32 - n));
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Initialize a context
|
||||
*/
|
||||
void md5Init(MD5Context *ctx){
|
||||
ctx->size = (uint64_t)0;
|
||||
|
||||
ctx->buffer[0] = (uint32_t)A;
|
||||
ctx->buffer[1] = (uint32_t)B;
|
||||
ctx->buffer[2] = (uint32_t)C;
|
||||
ctx->buffer[3] = (uint32_t)D;
|
||||
}
|
||||
|
||||
/*
|
||||
* Add some amount of input to the context
|
||||
*
|
||||
* If the input fills out a block of 512 bits, apply the algorithm (md5Step)
|
||||
* and save the result in the buffer. Also updates the overall size.
|
||||
*/
|
||||
void md5Update(MD5Context *ctx, uint8_t *input_buffer, size_t input_len){
|
||||
uint32_t input[16];
|
||||
unsigned int offset = ctx->size % 64;
|
||||
ctx->size += (uint64_t)input_len;
|
||||
|
||||
// Copy each byte in input_buffer into the next space in our context input
|
||||
for(unsigned int i = 0; i < input_len; ++i){
|
||||
ctx->input[offset++] = (uint8_t)*(input_buffer + i);
|
||||
|
||||
// If we've filled our context input, copy it into our local array input
|
||||
// then reset the offset to 0 and fill in a new buffer.
|
||||
// Every time we fill out a chunk, we run it through the algorithm
|
||||
// to enable some back and forth between cpu and i/o
|
||||
if(offset % 64 == 0){
|
||||
for(unsigned int j = 0; j < 16; ++j){
|
||||
// Convert to little-endian
|
||||
// The local variable `input` our 512-bit chunk separated into 32-bit words
|
||||
// we can use in calculations
|
||||
input[j] = (uint32_t)(ctx->input[(j * 4) + 3]) << 24 |
|
||||
(uint32_t)(ctx->input[(j * 4) + 2]) << 16 |
|
||||
(uint32_t)(ctx->input[(j * 4) + 1]) << 8 |
|
||||
(uint32_t)(ctx->input[(j * 4)]);
|
||||
}
|
||||
md5Step(ctx->buffer, input);
|
||||
offset = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Pad the current input to get to 448 bytes, append the size in bits to the very end,
|
||||
* and save the result of the final iteration into digest.
|
||||
*/
|
||||
void md5Finalize(MD5Context *ctx){
|
||||
uint32_t input[16];
|
||||
unsigned int offset = ctx->size % 64;
|
||||
unsigned int padding_length = offset < 56 ? 56 - offset : (56 + 64) - offset;
|
||||
|
||||
// Fill in the padding and undo the changes to size that resulted from the update
|
||||
md5Update(ctx, PADDING, padding_length);
|
||||
ctx->size -= (uint64_t)padding_length;
|
||||
|
||||
// Do a final update (internal to this function)
|
||||
// Last two 32-bit words are the two halves of the size (converted from bytes to bits)
|
||||
for(unsigned int j = 0; j < 14; ++j){
|
||||
input[j] = (uint32_t)(ctx->input[(j * 4) + 3]) << 24 |
|
||||
(uint32_t)(ctx->input[(j * 4) + 2]) << 16 |
|
||||
(uint32_t)(ctx->input[(j * 4) + 1]) << 8 |
|
||||
(uint32_t)(ctx->input[(j * 4)]);
|
||||
}
|
||||
input[14] = (uint32_t)(ctx->size * 8);
|
||||
input[15] = (uint32_t)((ctx->size * 8) >> 32);
|
||||
|
||||
md5Step(ctx->buffer, input);
|
||||
|
||||
// Move the result into digest (convert from little-endian)
|
||||
for(unsigned int i = 0; i < 4; ++i){
|
||||
ctx->digest[(i * 4) + 0] = (uint8_t)((ctx->buffer[i] & 0x000000FF));
|
||||
ctx->digest[(i * 4) + 1] = (uint8_t)((ctx->buffer[i] & 0x0000FF00) >> 8);
|
||||
ctx->digest[(i * 4) + 2] = (uint8_t)((ctx->buffer[i] & 0x00FF0000) >> 16);
|
||||
ctx->digest[(i * 4) + 3] = (uint8_t)((ctx->buffer[i] & 0xFF000000) >> 24);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Step on 512 bits of input with the main MD5 algorithm.
|
||||
*/
|
||||
void md5Step(uint32_t *buffer, uint32_t *input){
|
||||
uint32_t AA = buffer[0];
|
||||
uint32_t BB = buffer[1];
|
||||
uint32_t CC = buffer[2];
|
||||
uint32_t DD = buffer[3];
|
||||
|
||||
uint32_t E;
|
||||
|
||||
unsigned int j;
|
||||
|
||||
for(unsigned int i = 0; i < 64; ++i){
|
||||
switch(i / 16){
|
||||
case 0:
|
||||
E = F(BB, CC, DD);
|
||||
j = i;
|
||||
break;
|
||||
case 1:
|
||||
E = G(BB, CC, DD);
|
||||
j = ((i * 5) + 1) % 16;
|
||||
break;
|
||||
case 2:
|
||||
E = H(BB, CC, DD);
|
||||
j = ((i * 3) + 5) % 16;
|
||||
break;
|
||||
default:
|
||||
E = I(BB, CC, DD);
|
||||
j = (i * 7) % 16;
|
||||
break;
|
||||
}
|
||||
|
||||
uint32_t temp = DD;
|
||||
DD = CC;
|
||||
CC = BB;
|
||||
BB = BB + rotateLeft(AA + E + K[i] + input[j], S[i]);
|
||||
AA = temp;
|
||||
}
|
||||
|
||||
buffer[0] += AA;
|
||||
buffer[1] += BB;
|
||||
buffer[2] += CC;
|
||||
buffer[3] += DD;
|
||||
}
|
||||
|
||||
/*
|
||||
* Functions that run the algorithm on the provided input and put the digest into result.
|
||||
* result should be able to store 16 bytes.
|
||||
*/
|
||||
void md5String(char *input, uint8_t *result){
|
||||
MD5Context ctx;
|
||||
md5Init(&ctx);
|
||||
md5Update(&ctx, (uint8_t *)input, strlen(input));
|
||||
md5Finalize(&ctx);
|
||||
|
||||
memcpy(result, ctx.digest, 16);
|
||||
}
|
||||
|
||||
|
||||
void md5File(FILE *file, uint8_t *result){
|
||||
void *input_buffer = malloc(1024);
|
||||
size_t input_size = 0;
|
||||
|
||||
MD5Context ctx;
|
||||
md5Init(&ctx);
|
||||
|
||||
while((input_size = fread(input_buffer, 1, 1024, file)) > 0){
|
||||
md5Update(&ctx, (uint8_t *)input_buffer, input_size);
|
||||
}
|
||||
|
||||
md5Finalize(&ctx);
|
||||
|
||||
free(input_buffer);
|
||||
|
||||
memcpy(result, ctx.digest, 16);
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
/* Src: https://github.com/Zunawe/md5-c, commit: f3529b6
|
||||
* License: Unlicense */
|
||||
#pragma once
|
||||
|
||||
#ifndef MD5_H
|
||||
#define MD5_H
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
typedef struct{
|
||||
uint64_t size; // Size of input in bytes
|
||||
uint32_t buffer[4]; // Current accumulation of hash
|
||||
uint8_t input[64]; // Input to be used in the next step
|
||||
uint8_t digest[16]; // Result of algorithm
|
||||
}MD5Context;
|
||||
|
||||
void md5Init(MD5Context *ctx);
|
||||
void md5Update(MD5Context *ctx, uint8_t *input, size_t input_len);
|
||||
void md5Finalize(MD5Context *ctx);
|
||||
void md5Step(uint32_t *buffer, uint32_t *input);
|
||||
|
||||
void md5String(char *input, uint8_t *result);
|
||||
void md5File(FILE *file, uint8_t *result);
|
||||
|
||||
#endif // MD5_H
|
||||
@@ -36,7 +36,6 @@ extern "C" {
|
||||
#include "MainFlowControl.h"
|
||||
|
||||
#include "server_help.h"
|
||||
#include "md5.h"
|
||||
#ifdef ENABLE_MQTT
|
||||
#include "interface_mqtt.h"
|
||||
#endif //ENABLE_MQTT
|
||||
@@ -611,8 +610,6 @@ static esp_err_t upload_post_handler(httpd_req_t *req)
|
||||
FILE *fd = NULL;
|
||||
struct stat file_stat;
|
||||
|
||||
ESP_LOGI(TAG, "uri: %s", req->uri);
|
||||
|
||||
httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
|
||||
|
||||
/* Skip leading "/upload" from URI to get filename */
|
||||
@@ -714,77 +711,44 @@ static esp_err_t upload_post_handler(httpd_req_t *req)
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "File saved: " + string(filename));
|
||||
ESP_LOGI(TAG, "File reception completed");
|
||||
|
||||
string s = req->uri;
|
||||
if (isInString(s, "?md5")) {
|
||||
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Calculate and return MD5 sum...");
|
||||
|
||||
fd = fopen(filepath, "r");
|
||||
if (!fd) {
|
||||
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Failed to open file for reading: " + string(filepath));
|
||||
/* Respond with 500 Internal Server Error */
|
||||
httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Failed to open file for reading");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
std::string directory = std::string(filepath);
|
||||
size_t zw = directory.find("/");
|
||||
size_t found = zw;
|
||||
while (zw != std::string::npos)
|
||||
{
|
||||
zw = directory.find("/", found+1);
|
||||
if (zw != std::string::npos)
|
||||
found = zw;
|
||||
}
|
||||
|
||||
uint8_t result[16];
|
||||
string md5hex = "";
|
||||
string response = "{\"md5\":";
|
||||
char hex[3];
|
||||
int start_fn = strlen(((struct file_server_data *)req->user_ctx)->base_path);
|
||||
ESP_LOGD(TAG, "Directory: %s, start_fn: %d, found: %d", directory.c_str(), start_fn, found);
|
||||
directory = directory.substr(start_fn, found - start_fn + 1);
|
||||
directory = "/fileserver" + directory;
|
||||
// ESP_LOGD(TAG, "Directory danach 2: %s", directory.c_str());
|
||||
|
||||
md5File(fd, result);
|
||||
fclose(fd);
|
||||
|
||||
for (int i = 0; i < sizeof(result); i++) {
|
||||
snprintf(hex, sizeof(hex), "%02x", result[i]);
|
||||
md5hex.append(hex);
|
||||
}
|
||||
|
||||
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "MD5 of " + string(filepath) + ": " + md5hex);
|
||||
response.append("\"" + md5hex + "\"");
|
||||
response.append("}");
|
||||
|
||||
httpd_resp_sendstr(req, response.c_str());
|
||||
/* Redirect onto root to see the updated file list */
|
||||
if (strcmp(filename, "/config/config.ini") == 0 ||
|
||||
strcmp(filename, "/config/ref0.jpg") == 0 ||
|
||||
strcmp(filename, "/config/ref0_org.jpg") == 0 ||
|
||||
strcmp(filename, "/config/ref1.jpg") == 0 ||
|
||||
strcmp(filename, "/config/ref1_org.jpg") == 0 ||
|
||||
strcmp(filename, "/config/reference.jpg") == 0 ||
|
||||
strcmp(filename, "/img_tmp/ref0.jpg") == 0 ||
|
||||
strcmp(filename, "/img_tmp/ref0_org.jpg") == 0 ||
|
||||
strcmp(filename, "/img_tmp/ref1.jpg") == 0 ||
|
||||
strcmp(filename, "/img_tmp/ref1_org.jpg") == 0 ||
|
||||
strcmp(filename, "/img_tmp/reference.jpg") == 0 )
|
||||
{
|
||||
httpd_resp_set_status(req, HTTPD_200); // Avoid reloading of folder content
|
||||
}
|
||||
else { // Return file server page
|
||||
std::string directory = std::string(filepath);
|
||||
size_t zw = directory.find("/");
|
||||
size_t found = zw;
|
||||
while (zw != std::string::npos)
|
||||
{
|
||||
zw = directory.find("/", found+1);
|
||||
if (zw != std::string::npos)
|
||||
found = zw;
|
||||
}
|
||||
|
||||
int start_fn = strlen(((struct file_server_data *)req->user_ctx)->base_path);
|
||||
ESP_LOGD(TAG, "Directory: %s, start_fn: %d, found: %d", directory.c_str(), start_fn, found);
|
||||
directory = directory.substr(start_fn, found - start_fn + 1);
|
||||
directory = "/fileserver" + directory;
|
||||
// ESP_LOGD(TAG, "Directory danach 2: %s", directory.c_str());
|
||||
|
||||
/* Redirect onto root to see the updated file list */
|
||||
if (strcmp(filename, "/config/config.ini") == 0 ||
|
||||
strcmp(filename, "/config/ref0.jpg") == 0 ||
|
||||
strcmp(filename, "/config/ref0_org.jpg") == 0 ||
|
||||
strcmp(filename, "/config/ref1.jpg") == 0 ||
|
||||
strcmp(filename, "/config/ref1_org.jpg") == 0 ||
|
||||
strcmp(filename, "/config/reference.jpg") == 0 ||
|
||||
strcmp(filename, "/img_tmp/ref0.jpg") == 0 ||
|
||||
strcmp(filename, "/img_tmp/ref0_org.jpg") == 0 ||
|
||||
strcmp(filename, "/img_tmp/ref1.jpg") == 0 ||
|
||||
strcmp(filename, "/img_tmp/ref1_org.jpg") == 0 ||
|
||||
strcmp(filename, "/img_tmp/reference.jpg") == 0 )
|
||||
{
|
||||
httpd_resp_set_status(req, HTTPD_200); // Avoid reloading of folder content
|
||||
}
|
||||
else {
|
||||
httpd_resp_set_status(req, "303 See Other"); // Reload folder content after upload
|
||||
}
|
||||
|
||||
httpd_resp_set_hdr(req, "Location", directory.c_str());
|
||||
httpd_resp_sendstr(req, "File uploaded successfully");
|
||||
else {
|
||||
httpd_resp_set_status(req, "303 See Other"); // Reload folder content after upload
|
||||
}
|
||||
|
||||
httpd_resp_set_hdr(req, "Location", directory.c_str());
|
||||
httpd_resp_sendstr(req, "File uploaded successfully");
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -96,15 +96,15 @@ void task_do_Update_ZIP(void *pvParameter)
|
||||
|
||||
/* ZIP file got extracted, replace the old html folder with the new one */
|
||||
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Renaming folder " + outHtml + " to " + outHtmlOld + "...");
|
||||
RenameFolder(outHtml, outHtmlOld);
|
||||
::rename(outHtml.c_str(), outHtmlOld.c_str());
|
||||
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Renaming folder " + outHtmlTmp + " to " + outHtml + "...");
|
||||
RenameFolder(outHtmlTmp, outHtml);
|
||||
::rename(outHtmlTmp.c_str(), outHtml.c_str());
|
||||
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Deleting folder " + outHtmlOld + "...");
|
||||
removeFolder(outHtmlOld.c_str(), TAG);
|
||||
|
||||
if (retfirmware.length() > 0)
|
||||
{
|
||||
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Found firmware.bin");
|
||||
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Found firmware.bin");
|
||||
ota_update_task(retfirmware);
|
||||
}
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@ enum t_RateType {
|
||||
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).
|
||||
@@ -44,7 +45,6 @@ struct NumberPost {
|
||||
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 IgnoreLeadingNaN;
|
||||
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
|
||||
@@ -66,7 +66,7 @@ struct NumberPost {
|
||||
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 DomoticzIdx; // Domoticz counter Idx
|
||||
string DomoticzIdx; // Domoticz counter Idx
|
||||
|
||||
string FieldV1; // influxdbFieldName_v1; Name of the Field in InfluxDBv1
|
||||
string MeasurementV1; // influxdbMeasurementName_v1; Name of the Measurement in InfluxDBv1
|
||||
@@ -83,3 +83,4 @@ struct NumberPost {
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
@@ -156,7 +156,7 @@ bool ClassFlowMQTT::ReadParameter(FILE* pfile, string& aktparamgraph)
|
||||
mqttServer_setMeterType("water", "L", "h", "L/h");
|
||||
}
|
||||
else if (toUpper(splitted[1]) == "WATER_FT3") {
|
||||
mqttServer_setMeterType("water", "ft³", "min", "ft³/min"); // min = Minutes
|
||||
mqttServer_setMeterType("water", "ft³", "m", "ft³/m"); // m = Minutes
|
||||
}
|
||||
else if (toUpper(splitted[1]) == "WATER_GAL") {
|
||||
mqttServer_setMeterType("water", "gal", "h", "gal/h");
|
||||
@@ -165,7 +165,7 @@ bool ClassFlowMQTT::ReadParameter(FILE* pfile, string& aktparamgraph)
|
||||
mqttServer_setMeterType("gas", "m³", "h", "m³/h");
|
||||
}
|
||||
else if (toUpper(splitted[1]) == "GAS_FT3") {
|
||||
mqttServer_setMeterType("gas", "ft³", "min", "ft³/min"); // min = Minutes
|
||||
mqttServer_setMeterType("gas", "ft³", "m", "ft³/m"); // m = Minutes
|
||||
}
|
||||
else if (toUpper(splitted[1]) == "ENERGY_WH") {
|
||||
mqttServer_setMeterType("energy", "Wh", "h", "W");
|
||||
@@ -180,13 +180,13 @@ bool ClassFlowMQTT::ReadParameter(FILE* pfile, string& aktparamgraph)
|
||||
mqttServer_setMeterType("energy", "GJ", "h", "GJ/h");
|
||||
}
|
||||
else if (toUpper(splitted[1]) == "TEMPERATURE_C") {
|
||||
mqttServer_setMeterType("temperature", "°C", "min", "°C/min"); // min = Minutes
|
||||
mqttServer_setMeterType("temperature", "°C", "m", "°C/m"); // m = Minutes
|
||||
}
|
||||
else if (toUpper(splitted[1]) == "TEMPERATURE_F") {
|
||||
mqttServer_setMeterType("temperature", "°F", "min", "°F/min"); // min = Minutes
|
||||
mqttServer_setMeterType("temperature", "°F", "m", "°F/m"); // m = Minutes
|
||||
}
|
||||
else if (toUpper(splitted[1]) == "TEMPERATURE_K") {
|
||||
mqttServer_setMeterType("temperature", "K", "min", "K/m"); // min = Minutes
|
||||
mqttServer_setMeterType("temperature", "K", "m", "K/m"); // m = Minutes
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -320,6 +320,7 @@ ClassFlowPostProcessing::ClassFlowPostProcessing(std::vector<ClassFlow*>* lfc, C
|
||||
ListFlowControll = lfc;
|
||||
flowTakeImage = NULL;
|
||||
UpdatePreValueINI = false;
|
||||
IgnoreLeadingNaN = false;
|
||||
flowAnalog = _analog;
|
||||
flowDigit = _digit;
|
||||
|
||||
@@ -430,27 +431,6 @@ void ClassFlowPostProcessing::handleAllowNegativeRate(string _decsep, string _va
|
||||
}
|
||||
}
|
||||
|
||||
void ClassFlowPostProcessing::handleIgnoreLeadingNaN(string _decsep, string _value) {
|
||||
string _digit, _decpos;
|
||||
int _pospunkt = _decsep.find_first_of(".");
|
||||
|
||||
if (_pospunkt > -1) {
|
||||
_digit = _decsep.substr(0, _pospunkt);
|
||||
}
|
||||
else {
|
||||
_digit = "default";
|
||||
}
|
||||
|
||||
for (int j = 0; j < NUMBERS.size(); ++j) {
|
||||
bool _zwdc = alphanumericToBoolean(_value);
|
||||
|
||||
// Set to default first (if nothing else is set)
|
||||
if ((_digit == "default") || (NUMBERS[j]->name == _digit)) {
|
||||
NUMBERS[j]->IgnoreLeadingNaN = _zwdc;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ClassFlowPostProcessing::handleMaxRateType(string _decsep, string _value) {
|
||||
string _digit, _decpos;
|
||||
int _pospunkt = _decsep.find_first_of(".");
|
||||
@@ -529,7 +509,7 @@ void ClassFlowPostProcessing::handleChangeRateThreshold(string _decsep, string _
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
void ClassFlowPostProcessing::handlecheckDigitIncreaseConsistency(std::string _decsep, std::string _value)
|
||||
{
|
||||
std::string _digit;
|
||||
@@ -552,7 +532,7 @@ void ClassFlowPostProcessing::handlecheckDigitIncreaseConsistency(std::string _d
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
*/
|
||||
bool ClassFlowPostProcessing::ReadParameter(FILE* pfile, string& aktparamgraph) {
|
||||
std::vector<string> splitted;
|
||||
int _n;
|
||||
@@ -605,7 +585,12 @@ bool ClassFlowPostProcessing::ReadParameter(FILE* pfile, string& aktparamgraph)
|
||||
}
|
||||
|
||||
if ((toUpper(_param) == "CHECKDIGITINCREASECONSISTENCY") && (splitted.size() > 1)) {
|
||||
handlecheckDigitIncreaseConsistency(splitted[0], splitted[1]);
|
||||
// handlecheckDigitIncreaseConsistency(splitted[0], splitted[1]);
|
||||
if (alphanumericToBoolean(splitted[1])) {
|
||||
for (_n = 0; _n < NUMBERS.size(); ++_n) {
|
||||
NUMBERS[_n]->checkDigitIncreaseConsistency = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((toUpper(_param) == "ALLOWNEGATIVERATES") && (splitted.size() > 1)) {
|
||||
@@ -617,7 +602,7 @@ bool ClassFlowPostProcessing::ReadParameter(FILE* pfile, string& aktparamgraph)
|
||||
}
|
||||
|
||||
if ((toUpper(_param) == "IGNORELEADINGNAN") && (splitted.size() > 1)) {
|
||||
handleIgnoreLeadingNaN(splitted[0], splitted[1]);
|
||||
IgnoreLeadingNaN = alphanumericToBoolean(splitted[1]);
|
||||
}
|
||||
|
||||
if ((toUpper(_param) == "PREVALUEAGESTARTUP") && (splitted.size() > 1)) {
|
||||
@@ -685,7 +670,6 @@ void ClassFlowPostProcessing::InitNUMBERS() {
|
||||
_number->FlowRateAct = 0; // m3 / min
|
||||
_number->PreValueOkay = false;
|
||||
_number->AllowNegativeRates = false;
|
||||
_number->IgnoreLeadingNaN = false;
|
||||
_number->MaxRateValue = 0.1;
|
||||
_number->MaxRateType = AbsoluteChange;
|
||||
_number->useMaxRateValue = false;
|
||||
@@ -837,7 +821,7 @@ bool ClassFlowPostProcessing::doFlow(string zwtime) {
|
||||
ESP_LOGD(TAG, "After ShiftDecimal: ReturnRaw %s", NUMBERS[j]->ReturnRawValue.c_str());
|
||||
#endif
|
||||
|
||||
if (NUMBERS[j]->IgnoreLeadingNaN) {
|
||||
if (IgnoreLeadingNaN) {
|
||||
while ((NUMBERS[j]->ReturnRawValue.length() > 1) && (NUMBERS[j]->ReturnRawValue[0] == 'N')) {
|
||||
NUMBERS[j]->ReturnRawValue.erase(0, 1);
|
||||
}
|
||||
@@ -884,7 +868,12 @@ bool ClassFlowPostProcessing::doFlow(string zwtime) {
|
||||
|
||||
if (NUMBERS[j]->checkDigitIncreaseConsistency) {
|
||||
if (flowDigit) {
|
||||
NUMBERS[j]->Value = checkDigitConsistency(NUMBERS[j]->Value, NUMBERS[j]->DecimalShift, NUMBERS[j]->analog_roi != NULL, NUMBERS[j]->PreValue);
|
||||
if (flowDigit->getCNNType() != Digit) {
|
||||
ESP_LOGD(TAG, "checkDigitIncreaseConsistency = true - ignored due to wrong CNN-Type (not Digit Classification)");
|
||||
}
|
||||
else {
|
||||
NUMBERS[j]->Value = checkDigitConsistency(NUMBERS[j]->Value, NUMBERS[j]->DecimalShift, NUMBERS[j]->analog_roi != NULL, NUMBERS[j]->PreValue);
|
||||
}
|
||||
}
|
||||
else {
|
||||
#ifdef SERIAL_DEBUG
|
||||
@@ -898,7 +887,7 @@ bool ClassFlowPostProcessing::doFlow(string zwtime) {
|
||||
#endif
|
||||
|
||||
if (PreValueUse && NUMBERS[j]->PreValueOkay) {
|
||||
if ((NUMBERS[j]->Nachkomma > 0) && (NUMBERS[j]->ChangeRateThreshold > 0)) {
|
||||
if (NUMBERS[j]->Nachkomma > 0) {
|
||||
double _difference1 = (NUMBERS[j]->PreValue - (NUMBERS[j]->ChangeRateThreshold / pow(10, NUMBERS[j]->Nachkomma)));
|
||||
double _difference2 = (NUMBERS[j]->PreValue + (NUMBERS[j]->ChangeRateThreshold / pow(10, NUMBERS[j]->Nachkomma)));
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
|
||||
class ClassFlowPostProcessing :
|
||||
public ClassFlow
|
||||
{
|
||||
@@ -18,7 +19,8 @@ protected:
|
||||
|
||||
int PreValueAgeStartup;
|
||||
bool ErrorMessage;
|
||||
|
||||
bool IgnoreLeadingNaN; // SPECIAL CASE for User Gustl ???
|
||||
|
||||
ClassFlowCNNGeneral* flowAnalog;
|
||||
ClassFlowCNNGeneral* flowDigit;
|
||||
|
||||
@@ -33,16 +35,15 @@ protected:
|
||||
float checkDigitConsistency(double input, int _decilamshift, bool _isanalog, double _preValue);
|
||||
|
||||
void InitNUMBERS();
|
||||
|
||||
void handleDecimalSeparator(string _decsep, string _value);
|
||||
void handleMaxRateValue(string _decsep, string _value);
|
||||
void handleDecimalExtendedResolution(string _decsep, string _value);
|
||||
void handleMaxRateType(string _decsep, string _value);
|
||||
void handleAnalogToDigitTransitionStart(string _decsep, string _value);
|
||||
void handleAllowNegativeRate(string _decsep, string _value);
|
||||
void handleIgnoreLeadingNaN(string _decsep, string _value);
|
||||
void handleChangeRateThreshold(string _decsep, string _value);
|
||||
void handlecheckDigitIncreaseConsistency(std::string _decsep, std::string _value);
|
||||
|
||||
std::string GetStringReadouts(general);
|
||||
|
||||
void WriteDataLog(int _index);
|
||||
|
||||
@@ -74,4 +75,5 @@ public:
|
||||
string name(){return "ClassFlowPostProcessing";};
|
||||
};
|
||||
|
||||
|
||||
#endif //CLASSFFLOWPOSTPROCESSING_H
|
||||
|
||||
@@ -365,35 +365,19 @@ size_t findDelimiterPos(string input, string delimiter)
|
||||
|
||||
bool RenameFile(string from, string to)
|
||||
{
|
||||
// ESP_LOGI(logTag, "Renaming File: %s", from.c_str());
|
||||
// ESP_LOGI(logTag, "Deleting file: %s", fn.c_str());
|
||||
/* Delete file */
|
||||
FILE *fpSourceFile = fopen(from.c_str(), "rb");
|
||||
|
||||
// Sourcefile does not exist otherwise there is a mistake when renaming!
|
||||
// Sourcefile existiert nicht sonst gibt es einen Fehler beim Kopierversuch!
|
||||
if (!fpSourceFile)
|
||||
{
|
||||
ESP_LOGE(TAG, "RenameFile: File %s does not exist!", from.c_str());
|
||||
ESP_LOGE(TAG, "DeleteFile: File %s existiert nicht!", from.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
fclose(fpSourceFile);
|
||||
rename(from.c_str(), to.c_str());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool RenameFolder(string from, string to)
|
||||
{
|
||||
// ESP_LOGI(logTag, "Renaming Folder: %s", from.c_str());
|
||||
DIR *fpSourceFolder = opendir(from.c_str());
|
||||
|
||||
// Sourcefolder does not exist otherwise there is a mistake when renaming!
|
||||
if (!fpSourceFolder)
|
||||
{
|
||||
ESP_LOGE(TAG, "RenameFolder: Folder %s does not exist!", from.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
closedir(fpSourceFolder);
|
||||
rename(from.c_str(), to.c_str());
|
||||
|
||||
return true;
|
||||
@@ -403,7 +387,7 @@ bool FileExists(string filename)
|
||||
{
|
||||
FILE *fpSourceFile = fopen(filename.c_str(), "rb");
|
||||
|
||||
// Sourcefile does not exist
|
||||
// Sourcefile existiert nicht sonst gibt es einen Fehler beim Kopierversuch!
|
||||
if (!fpSourceFile)
|
||||
{
|
||||
return false;
|
||||
@@ -414,36 +398,22 @@ bool FileExists(string filename)
|
||||
return true;
|
||||
}
|
||||
|
||||
bool FolderExists(string foldername)
|
||||
bool DeleteFile(string fn)
|
||||
{
|
||||
DIR *fpSourceFolder = opendir(foldername.c_str());
|
||||
|
||||
// Sourcefolder does not exist
|
||||
if (!fpSourceFolder)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
closedir(fpSourceFolder);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool DeleteFile(string filename)
|
||||
{
|
||||
// ESP_LOGI(logTag, "Deleting file: %s", filename.c_str());
|
||||
// ESP_LOGI(logTag, "Deleting file: %s", fn.c_str());
|
||||
/* Delete file */
|
||||
FILE *fpSourceFile = fopen(filename.c_str(), "rb");
|
||||
FILE *fpSourceFile = fopen(fn.c_str(), "rb");
|
||||
|
||||
// Sourcefile does not exist otherwise there is a mistake in copying!
|
||||
// Sourcefile existiert nicht sonst gibt es einen Fehler beim Kopierversuch!
|
||||
if (!fpSourceFile)
|
||||
{
|
||||
ESP_LOGD(TAG, "DeleteFile: File %s existiert nicht!", filename.c_str());
|
||||
ESP_LOGD(TAG, "DeleteFile: File %s existiert nicht!", fn.c_str());
|
||||
return false;
|
||||
}
|
||||
|
||||
fclose(fpSourceFile);
|
||||
unlink(filename.c_str());
|
||||
|
||||
unlink(fn.c_str());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -16,12 +16,10 @@ std::size_t file_size(const std::string& file_name);
|
||||
void FindReplace(std::string& line, std::string& oldString, std::string& newString);
|
||||
|
||||
bool CopyFile(string input, string output);
|
||||
bool DeleteFile(string filename);
|
||||
bool DeleteFile(string fn);
|
||||
bool RenameFile(string from, string to);
|
||||
bool RenameFolder(string from, string to);
|
||||
bool MakeDir(std::string _what);
|
||||
bool FileExists(string filename);
|
||||
bool FolderExists(string foldername);
|
||||
|
||||
string RundeOutput(double _in, int _anzNachkomma);
|
||||
|
||||
|
||||
@@ -85,7 +85,7 @@ bool MQTTPublish(std::string _key, std::string _content, int qos, bool retained_
|
||||
_content.append("..");
|
||||
}
|
||||
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Published topic: " + _key + ", content: " + _content);
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Published topic: " + _key + ", content: " + _content + " (msg_id=" + std::to_string(msg_id) + ")");
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
@@ -465,7 +465,7 @@ void MQTTconnected(){
|
||||
if (subscribeFunktionMap != NULL) {
|
||||
for(std::map<std::string, std::function<bool(std::string, char*, int)>>::iterator it = subscribeFunktionMap->begin(); it != subscribeFunktionMap->end(); ++it) {
|
||||
int msg_id = esp_mqtt_client_subscribe(client, it->first.c_str(), 0);
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "topic " + it->first + " subscribe successful");
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "topic " + it->first + " subscribe successful, msg_id=" + std::to_string(msg_id));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -174,14 +174,14 @@ bool MQTThomeassistantDiscovery(int qos) {
|
||||
int aFreeInternalHeapSizeBefore = heap_caps_get_free_size(MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL);
|
||||
|
||||
// Group | Field | User Friendly Name | Icon | Unit | Device Class | State Class | Entity Category
|
||||
allSendsSuccessed |= sendHomeAssistantDiscoveryTopic("", "uptime", "Uptime", "progress-clock", "s", "duration", "measurement", "diagnostic", qos);
|
||||
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);
|
||||
allSendsSuccessed |= sendHomeAssistantDiscoveryTopic("", "CPUtemp", "CPU Temperature", "thermometer", "°C", "temperature", "measurement", "diagnostic", qos);
|
||||
allSendsSuccessed |= sendHomeAssistantDiscoveryTopic("", "interval", "Interval", "clock-time-eight-outline", "min", "", "measurement", "diagnostic", qos);
|
||||
allSendsSuccessed |= sendHomeAssistantDiscoveryTopic("", "interval", "Interval", "clock-time-eight-outline", "min", "" , "measurement", "diagnostic", qos);
|
||||
allSendsSuccessed |= sendHomeAssistantDiscoveryTopic("", "IP", "IP", "network-outline", "", "", "", "diagnostic", qos);
|
||||
allSendsSuccessed |= sendHomeAssistantDiscoveryTopic("", "status", "Status", "list-status", "", "", "", "diagnostic", qos);
|
||||
allSendsSuccessed |= sendHomeAssistantDiscoveryTopic("", "flowstart", "Manual Flow Start", "timer-play-outline", "", "", "", "", qos);
|
||||
@@ -195,12 +195,9 @@ bool MQTThomeassistantDiscovery(int qos) {
|
||||
|
||||
/* If "Allow neg. rate" is true, use "measurement" instead of "total_increasing" for the State Class, see https://github.com/jomjol/AI-on-the-edge-device/issues/3331 */
|
||||
std::string value_state_class = "total_increasing";
|
||||
if (meterType == "temperature") {
|
||||
if ((*NUMBERS)[i]->AllowNegativeRates) {
|
||||
value_state_class = "measurement";
|
||||
}
|
||||
else if ((*NUMBERS)[i]->AllowNegativeRates) {
|
||||
value_state_class = "total";
|
||||
}
|
||||
|
||||
/* Energy meters need a different Device Class, see https://github.com/jomjol/AI-on-the-edge-device/issues/3333 */
|
||||
std::string rate_device_class = "volume_flow_rate";
|
||||
@@ -208,17 +205,17 @@ bool MQTThomeassistantDiscovery(int qos) {
|
||||
rate_device_class = "power";
|
||||
}
|
||||
|
||||
// Group | Field | User Friendly Name | Icon | Unit | Device Class | State Class | Entity Category | QoS
|
||||
allSendsSuccessed |= sendHomeAssistantDiscoveryTopic(group, "value", "Value", "gauge", valueUnit, meterType, value_state_class, "", qos); // State Class = "total_increasing" if <NUMBERS>.AllowNegativeRates = false, "measurement" in case of a thermometer, else use "total".
|
||||
allSendsSuccessed |= sendHomeAssistantDiscoveryTopic(group, "raw", "Raw Value", "raw", valueUnit, meterType, value_state_class, "diagnostic", qos);
|
||||
allSendsSuccessed |= sendHomeAssistantDiscoveryTopic(group, "error", "Error", "alert-circle-outline", "", "", "", "diagnostic", qos);
|
||||
// Group | Field | User Friendly Name | Icon | Unit | Device Class | State Class | Entity Category
|
||||
allSendsSuccessed |= sendHomeAssistantDiscoveryTopic(group, "value", "Value", "gauge", valueUnit, meterType, value_state_class, "", qos); // State Class = "total_increasing" if <NUMBERS>.AllowNegativeRates = false, else use "measurement"
|
||||
allSendsSuccessed |= sendHomeAssistantDiscoveryTopic(group, "raw", "Raw Value", "raw", valueUnit, meterType, "measurement", "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_digitization_round */
|
||||
// allSendsSuccessed |= sendHomeAssistantDiscoveryTopic(group, "rate", "Rate (Unit/Minute)", "swap-vertical", "", "", "", "", qos); // Legacy, always Unit per Minute
|
||||
allSendsSuccessed |= sendHomeAssistantDiscoveryTopic(group, "rate_per_time_unit", "Rate (" + rateUnit + ")", "swap-vertical", rateUnit, rate_device_class, "measurement", "", qos);
|
||||
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
|
||||
// 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, rate_device_class, "measurement", "", qos);
|
||||
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
|
||||
}
|
||||
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Successfully published all Homeassistant Discovery MQTT topics");
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
#include "openmetrics.h"
|
||||
#include "functional"
|
||||
#include "esp_log.h"
|
||||
|
||||
/**
|
||||
* create a singe metric from the given input
|
||||
@@ -12,66 +10,10 @@ std::string createMetric(const std::string &metricName, const std::string &help,
|
||||
metricName + " " + value + "\n";
|
||||
}
|
||||
|
||||
typedef struct sequence_metric {
|
||||
const char *name;
|
||||
const char *help;
|
||||
const char *type;
|
||||
std::function<std::string(NumberPost *number)> valueFunc;
|
||||
} sequence_metric_t;
|
||||
|
||||
|
||||
sequence_metric_t sequenceMetrics[4] = {
|
||||
{ "flow_value", "current value of meter readout", "gauge", [](NumberPost *number)-> std::string {return number->ReturnValue;} },
|
||||
{ "flow_raw_value", "current raw value of meter readout", "gauge", [](NumberPost *number)-> std::string {return number->ReturnRawValue;} },
|
||||
{ "flow_pre_value", "previous value of meter readout", "gauge", [](NumberPost *number)-> std::string {return number->ReturnPreValue;} },
|
||||
{ "flow_error", "Error message text != 'no error'", "gauge", [](NumberPost *number)-> std::string {return number->ErrorMessageText.compare("no error") == 0 ? "0" : "1";} },
|
||||
};
|
||||
|
||||
std::string createSequenceMetrics(std::string prefix, const std::vector<NumberPost *> &numbers)
|
||||
{
|
||||
std::string result;
|
||||
for (int i = 0; i<sizeof(sequenceMetrics)/sizeof(sequence_metric_t);i++)
|
||||
{
|
||||
std::string res;
|
||||
for (const auto &number : numbers)
|
||||
{
|
||||
std::string value = sequenceMetrics[i].valueFunc(number);
|
||||
if (value.find("N") != std::string::npos) {
|
||||
value = "NaN";
|
||||
}
|
||||
ESP_LOGD("METRICS", "metric=%s, name=%s, value = %s ",sequenceMetrics[i].name,number->name.c_str(), value.c_str());
|
||||
|
||||
// only valid data is reported (https://github.com/OpenObservability/OpenMetrics/blob/main/specification/OpenMetrics.md#missing-data)
|
||||
if (value.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 + "_" + sequenceMetrics[i].name + "{sequence=\"" + label + "\"} " + value + "\n";
|
||||
}
|
||||
}
|
||||
// prepend metadata if a valid metric was created
|
||||
if (res.length() > 0)
|
||||
{
|
||||
res = "# HELP " + prefix + "_" + sequenceMetrics[i].name + " " + sequenceMetrics[i].help + "\n"
|
||||
+ "# TYPE " + prefix + "_" + sequenceMetrics[i].name + " " + sequenceMetrics[i].type + "\n"
|
||||
+ res;
|
||||
}
|
||||
result += res;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
@@ -99,4 +41,3 @@ std::string createSequenceMetrics(std::string prefix, const std::vector<NumberPo
|
||||
}
|
||||
return res;
|
||||
}
|
||||
*/
|
||||
@@ -254,35 +254,6 @@ extern "C" void app_main(void)
|
||||
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "==================== Start ======================");
|
||||
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "=================================================");
|
||||
|
||||
// SD card: basic R/W check
|
||||
// ********************************************
|
||||
int iSDCardStatus = SDCardCheckRW();
|
||||
if (iSDCardStatus < 0) {
|
||||
if (iSDCardStatus <= -1 && iSDCardStatus >= -2) { // write error
|
||||
StatusLED(SDCARD_CHECK, 1, true);
|
||||
}
|
||||
else if (iSDCardStatus <= -3 && iSDCardStatus >= -5) { // read error
|
||||
StatusLED(SDCARD_CHECK, 2, true);
|
||||
}
|
||||
else if (iSDCardStatus == -6) { // delete error
|
||||
StatusLED(SDCARD_CHECK, 3, true);
|
||||
}
|
||||
setSystemStatusFlag(SYSTEM_STATUS_SDCARD_CHECK_BAD); // reduced web interface going to be loaded
|
||||
}
|
||||
|
||||
// SD card: Create further mandatory directories (if not already existing)
|
||||
// Correct creation of these folders will be checked with function "SDCardCheckFolderFilePresence"
|
||||
// ********************************************
|
||||
MakeDir("/sdcard/firmware"); // mandatory for OTA firmware update
|
||||
MakeDir("/sdcard/img_tmp"); // mandatory for setting up alignment marks
|
||||
MakeDir("/sdcard/demo"); // mandatory for demo mode
|
||||
MakeDir("/sdcard/config/certs"); // mandatory for mqtt certificates
|
||||
|
||||
// Check for updates
|
||||
// ********************************************
|
||||
CheckOTAUpdate();
|
||||
CheckUpdate();
|
||||
|
||||
// Init external PSRAM
|
||||
// ********************************************
|
||||
esp_err_t PSRAMStatus = esp_psram_init();
|
||||
@@ -381,6 +352,22 @@ extern "C" void app_main(void)
|
||||
}
|
||||
}
|
||||
|
||||
// SD card: basic R/W check
|
||||
// ********************************************
|
||||
int iSDCardStatus = SDCardCheckRW();
|
||||
if (iSDCardStatus < 0) {
|
||||
if (iSDCardStatus <= -1 && iSDCardStatus >= -2) { // write error
|
||||
StatusLED(SDCARD_CHECK, 1, true);
|
||||
}
|
||||
else if (iSDCardStatus <= -3 && iSDCardStatus >= -5) { // read error
|
||||
StatusLED(SDCARD_CHECK, 2, true);
|
||||
}
|
||||
else if (iSDCardStatus == -6) { // delete error
|
||||
StatusLED(SDCARD_CHECK, 3, true);
|
||||
}
|
||||
setSystemStatusFlag(SYSTEM_STATUS_SDCARD_CHECK_BAD); // reduced web interface going to be loaded
|
||||
}
|
||||
|
||||
// Migrate parameter in config.ini to new naming (firmware 15.0 and newer)
|
||||
// ********************************************
|
||||
migrateConfiguration();
|
||||
@@ -393,6 +380,19 @@ extern "C" void app_main(void)
|
||||
// ********************************************
|
||||
setCpuFrequency();
|
||||
|
||||
// SD card: Create further mandatory directories (if not already existing)
|
||||
// Correct creation of these folders will be checked with function "SDCardCheckFolderFilePresence"
|
||||
// ********************************************
|
||||
MakeDir("/sdcard/firmware"); // mandatory for OTA firmware update
|
||||
MakeDir("/sdcard/img_tmp"); // mandatory for setting up alignment marks
|
||||
MakeDir("/sdcard/demo"); // mandatory for demo mode
|
||||
MakeDir("/sdcard/config/certs"); // mandatory for mqtt certificates
|
||||
|
||||
// Check for updates
|
||||
// ********************************************
|
||||
CheckOTAUpdate();
|
||||
CheckUpdate();
|
||||
|
||||
// Start SoftAP for initial remote setup
|
||||
// Note: Start AP if no wlan.ini and/or config.ini available, e.g. SD card empty; function does not exit anymore until reboot
|
||||
// ********************************************
|
||||
|
||||
@@ -37,58 +37,23 @@ void test_createSequenceMetrics()
|
||||
NumberPost *number_1 = new NumberPost;
|
||||
number_1->name = "main";
|
||||
number_1->ReturnValue = "123.456";
|
||||
number_1->ReturnRawValue = "N23.456";
|
||||
number_1->ReturnPreValue = "986.543";
|
||||
number_1->ErrorMessageText = "";
|
||||
NUMBERS.push_back(number_1);
|
||||
|
||||
const std::string metricNamePrefix = "ai_on_the_edge_device";
|
||||
const std::string metricName1 = metricNamePrefix + "_flow_value";
|
||||
const std::string metricName2 = metricNamePrefix + "_flow_raw_value";
|
||||
const std::string metricName3 = metricNamePrefix + "_flow_pre_value";
|
||||
const std::string metricName4 = metricNamePrefix + "_flow_error";
|
||||
|
||||
std::string expected1 ;
|
||||
expected1 = "# HELP " + metricName1 + " current value of meter readout\n# TYPE " + metricName1 + " gauge\n" +
|
||||
metricName1 + "{sequence=\"" + number_1->name + "\"} " + number_1->ReturnValue + "\n";
|
||||
|
||||
expected1 += "# HELP " + metricName2 + " current raw value of meter readout\n# TYPE " + metricName2 + " gauge\n" +
|
||||
metricName2 + "{sequence=\"" + number_1->name + "\"} " + "NaN" + "\n";
|
||||
|
||||
expected1 += "# HELP " + metricName3 + " previous value of meter readout\n# TYPE " + metricName3 + " gauge\n" +
|
||||
metricName3 + "{sequence=\"" + number_1->name + "\"} " + number_1->ReturnPreValue + "\n";
|
||||
|
||||
expected1 += "# HELP " + metricName4 + " Error message text != 'no error'\n# TYPE " + metricName4 + " gauge\n" +
|
||||
metricName4 + "{sequence=\"" + number_1->name + "\"} " + "1" + "\n";
|
||||
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";
|
||||
number_2->ReturnRawValue = "01.000";
|
||||
number_2->ReturnPreValue = "0.987";
|
||||
number_2->ErrorMessageText = "no error";
|
||||
NUMBERS.push_back(number_2);
|
||||
|
||||
std::string expected2 ;
|
||||
expected2 = "# HELP " + metricName1 + " current value of meter readout\n# TYPE " + metricName1 + " gauge\n" +
|
||||
metricName1 + "{sequence=\"" + number_1->name + "\"} " + number_1->ReturnValue + "\n" +
|
||||
metricName1 + "{sequence=\"" + number_2->name + "\"} " + number_2->ReturnValue + "\n";
|
||||
|
||||
expected2 += "# HELP " + metricName2 + " current raw value of meter readout\n# TYPE " + metricName2 + " gauge\n" +
|
||||
metricName2 + "{sequence=\"" + number_1->name + "\"} " + "NaN" + "\n" +
|
||||
metricName2 + "{sequence=\"" + number_2->name + "\"} " + number_2->ReturnRawValue + "\n";
|
||||
|
||||
expected2 += "# HELP " + metricName3 + " previous value of meter readout\n# TYPE " + metricName3 + " gauge\n" +
|
||||
metricName3 + "{sequence=\"" + number_1->name + "\"} " + number_1->ReturnPreValue + "\n" +
|
||||
metricName3 + "{sequence=\"" + number_2->name + "\"} " + number_2->ReturnPreValue + "\n";
|
||||
|
||||
expected2 += "# HELP " + metricName4 + " Error message text != 'no error'\n# TYPE " + metricName4 + " gauge\n" +
|
||||
metricName4 + "{sequence=\"" + number_1->name + "\"} " + "1" + "\n" +
|
||||
metricName4 + "{sequence=\"" + number_2->name + "\"} " + "0" + "\n";
|
||||
|
||||
|
||||
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());
|
||||
}
|
||||
|
||||
|
||||
@@ -67,19 +67,21 @@
|
||||
|
||||
<div class="footer">
|
||||
<div class="footer-section">
|
||||
<span>Support & Contact</span>
|
||||
<span>Support & Contact Us</span>
|
||||
<a href="https://github.com/jomjol/AI-on-the-edge-device" target="_blank" title="GitHub">
|
||||
<img src="https://raw.githubusercontent.com/jomjol/AI-on-the-edge-device/refs/heads/main/images/github-logo.png" alt="GitHub">
|
||||
<img src="https://github.com/jomjol/AI-on-the-edge-device/images/github-logo.png" alt="GitHub">
|
||||
</a>
|
||||
<img src="https://github.com/jomjol/AI-on-the-edge-device/images/gmail-logo.png" alt="Email">
|
||||
</a>
|
||||
<a href="https://github.com/jomjol/AI-on-the-edge-device/discussions" target="_blank" title="GitHub">
|
||||
<img src="https://raw.githubusercontent.com/jomjol/AI-on-the-edge-device/refs/heads/main/images/discussion-logo.png" alt="GitHub">
|
||||
<img src="https://github.com/jomjol/AI-on-the-edge-device/images/discussion-logo" alt="GitHub">
|
||||
</a>
|
||||
|
||||
</div>
|
||||
<div class="footer-section">
|
||||
<span>Donations</span>
|
||||
<a href="https://www.paypal.com/donate?hosted_button_id=8TRSVYNYKDSWL" target="_blank" title="Donate via PayPal">
|
||||
<img src="https://raw.githubusercontent.com/jomjol/AI-on-the-edge-device/refs/heads/main/images/paypal.png" alt="PayPal" style="width: 60px; height: auto;">
|
||||
<img src="https://github.com/jomjol/AI-on-the-edge-device/images/paypal.png" alt="PayPal" style="width: 60px; height: auto;">
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
@@ -31,6 +31,7 @@ AlignmentAlgo
|
||||
CNNGoodThreshold
|
||||
PreValueAgeStartup
|
||||
ErrorMessage
|
||||
CheckDigitIncreaseConsistency
|
||||
IO0
|
||||
IO1
|
||||
IO3
|
||||
|
||||
@@ -4,4 +4,4 @@ Default Value: `undefined`
|
||||
Dedicated definition of the field for InfluxDB use for saving in the Influx database (e.g.: "watermeter/value").
|
||||
|
||||
!!! Note
|
||||
If you edit the config file manually, you must prefix this parameter with `<NUMBER>` followed by a dot (eg. `main.Field`). The reason is that this parameter is specific for each `<NUMBER>` (`<NUMBER>` is the name of the number sequence defined in the ROI's).
|
||||
This parameter must be prefixed with `<NUMBER>` followed by a dot (eg. `main.Field`). `<NUMBER>` is the name of the number sequence defined in the ROI's.
|
||||
|
||||
@@ -4,4 +4,4 @@ Default Value: `undefined`
|
||||
Field for InfluxDB v2 to use for saving.
|
||||
|
||||
!!! Note
|
||||
If you edit the config file manually, you must prefix this parameter with `<NUMBER>` followed by a dot (eg. `main.Field`). The reason is that this parameter is specific for each `<NUMBER>` (`<NUMBER>` is the name of the number sequence defined in the ROI's).
|
||||
This parameter must be prefixed with `<NUMBER>` followed by a dot (eg. `main.Field`). `<NUMBER>` is the name of the number sequence defined in the ROI's.
|
||||
|
||||
@@ -3,26 +3,9 @@ Default Value: `other`
|
||||
|
||||
Select the Meter Type so the sensors have the right units in Homeassistant.
|
||||
|
||||
!!! Note
|
||||
For `Watermeter` you need to have Homeassistant 2022.11 or newer!
|
||||
|
||||
Please also make sure that the selected Meter Type matches the dimension of the value provided by the meter!
|
||||
Eg. if your meter provides `m³`, you need to also set it to `m³`.
|
||||
Alternatively you can set the parameter `DecimalShift` to `3` so the value is converted to `liters`!
|
||||
|
||||
List of supported options:
|
||||
|
||||
- `other`
|
||||
- `water_m3` (uses `m^3/h` as rate)
|
||||
- `water_l` (uses `l/h` as rate, not officially supported by Homeassistant!)
|
||||
- `water_gal` (uses `gal/h` as rate, not officially supported by Homeassistant!)
|
||||
- `water_ft3` (uses `ft^3/min` as rate)
|
||||
- `gas_m3` (uses `m^3/h` as rate)
|
||||
- `gas_ft3` (uses `ft^3/min` as rate)
|
||||
- `energy_wh` (uses `W` as rate)
|
||||
- `energy_kwh` (uses `KW` as rate)
|
||||
- `energy_mwh` (uses `MW` as rate)
|
||||
- `energy_gj` (uses `GJ/h` as rate, not officially supported by Homeassistant!)
|
||||
- `temperature_c` (uses `+C/min` as rate)
|
||||
- `temperature_f` (uses `°F/min` as rate)
|
||||
- `temperature_k` (uses `K/min` as rate)
|
||||
|
||||
!!! Note
|
||||
Not all options are supported by Homeassistant, see `SensorDeviceClass.VOLUME_FLOW_RATE` in [https://developers.home-assistant.io/docs/core/entity/sensor/#available-device-classes](https://developers.home-assistant.io/docs/core/entity/sensor/#available-device-classes)!
|
||||
|
||||
@@ -4,4 +4,4 @@ Default Value: `0`
|
||||
The Idx number for the counter device. Can be obtained from the devices setup page on the Domoticz system.
|
||||
|
||||
!!! Note
|
||||
If you edit the config file manually, you must prefix this parameter with `<NUMBER>` followed by a dot (eg. `main.DomoticzIDX`). The reason is that this parameter is specific for each `<NUMBER>` (`<NUMBER>` is the name of the number sequence defined in the ROI's).
|
||||
This parameter must be prefixed with `<NUMBER>` followed by a dot (eg. `main.DomoticzIDX`). `<NUMBER>` is the name of the number sequence defined in the ROI's.
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
# Parameter `CheckDigitIncreaseConsistency`
|
||||
Default Value: `false`
|
||||
|
||||
!!! Warning
|
||||
This is an **Expert Parameter**! Only change it if you understand what it does!
|
||||
|
||||
An additional consistency check.
|
||||
It especially improves the zero crossing check between digits.
|
||||
@@ -7,4 +7,4 @@ Allow a meter to count backwards (decreasing values).
|
||||
This is unusual (it means there is a negative rate) and not wanted in most cases!
|
||||
|
||||
!!! Note
|
||||
If you edit the config file manually, you must prefix this parameter with `<NUMBER>` followed by a dot (eg. `main.AllowNegativeRates`). The reason is that this parameter is specific for each `<NUMBER>` (`<NUMBER>` is the name of the number sequence defined in the ROI's).
|
||||
This parameter must be prefixed with `<NUMBER>` followed by a dot (eg. `main.AllowNegativeRates`). `<NUMBER>` is the name of the number sequence defined in the ROI's.
|
||||
|
||||
@@ -9,4 +9,4 @@ See [here](../Watermeter-specific-analog---digit-transition) for details.
|
||||
Range: `6.0` .. `9.9`.
|
||||
|
||||
!!! Note
|
||||
If you edit the config file manually, you must prefix this parameter with `<NUMBER>` followed by a dot (eg. `main.AnalogToDigitTransitionStart`). The reason is that this parameter is specific for each `<NUMBER>` (`<NUMBER>` is the name of the number sequence defined in the ROI's).
|
||||
This parameter must be prefixed with `<NUMBER>` followed by a dot (eg. `main.AnalogToDigitTransitionStart`). `<NUMBER>` is the name of the number sequence defined in the ROI's.
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
# Parameter `ChangeRateThreshold`
|
||||
Default Value: `2`
|
||||
|
||||
Range: `0` .. `9`.
|
||||
Range: `1` .. `9`.
|
||||
|
||||
Threshold parameter for change rate detection.<br>
|
||||
This parameter is intended to compensate for small reading fluctuations that occur when the meter does not change its value for a long time (e.g. at night) or slightly turns backwards. This can eg. happen on watermeters.
|
||||
@@ -10,18 +10,18 @@ It is only applied to the last digit of the read value (See example below).
|
||||
If the read value is within PreValue +/- Threshold, no further calculation is carried out and the Value/Prevalue remains at the old value.
|
||||
|
||||
!!! Note
|
||||
If you edit the config file manually, you must prefix this parameter with `<NUMBER>` followed by a dot (eg. `main.ChangeRateThreshold`). The reason is that this parameter is specific for each `<NUMBER>` (`<NUMBER>` is the name of the number sequence defined in the ROI's).
|
||||
This parameter must be prefixed with `<NUMBER>` followed by a dot (eg. `main.ChangeRateThreshold`). `<NUMBER>` is the name of the number sequence defined in the ROI's.
|
||||
|
||||
## Example
|
||||
|
||||
- Smallest ROI provides value for `0.000'x` (Eg. a water meter with 4 pointers behind the decimal point)
|
||||
- ChangeRateThreshold = 2
|
||||
|
||||
#### With `ExtendedResolution` **disabled**
|
||||
#### With `Extended Resolution` **disabled**
|
||||
PreValue: `123.456'7` -> Threshold = `+/-0.000'2`.<br>
|
||||
All changes between `123.456'5` and `123.456'9` get ignored
|
||||
|
||||
#### With `ExtendedResolution` **enabled**
|
||||
#### With `Extended Resolution` **enabled**
|
||||
PreValue: `123.456'78` -> Threshold = `+/-0.000'02`.<br>
|
||||
All changes between `123.456'76` and `123.456'80` get ignored.
|
||||
|
||||
|
||||
@@ -1,11 +0,0 @@
|
||||
# Parameter `CheckDigitIncreaseConsistency`
|
||||
Default Value: `false`
|
||||
|
||||
!!! Warning
|
||||
This is an **Expert Parameter**! Only change it if you understand what it does!
|
||||
|
||||
An additional consistency check.
|
||||
It especially improves the zero crossing check between digits.
|
||||
|
||||
!!! Note
|
||||
If you edit the config file manually, you must prefix this parameter with `<NUMBER>` followed by a dot (eg. `main.CheckDigitIncreaseConsistency`). The reason is that this parameter is specific for each `<NUMBER>` (`<NUMBER>` is the name of the number sequence defined in the ROI's).
|
||||
@@ -5,4 +5,4 @@ Shift the decimal separator (positiv or negativ).
|
||||
Eg. to move from `m³` to `liter` (`1 m³` equals `1000 liters`), you need to set it to `+3`.
|
||||
|
||||
!!! Note
|
||||
If you edit the config file manually, you must prefix this parameter with `<NUMBER>` followed by a dot (eg. `main.DecimalShift`). The reason is that this parameter is specific for each `<NUMBER>` (`<NUMBER>` is the name of the number sequence defined in the ROI's).
|
||||
This parameter must be prefixed with `<NUMBER>` followed by a dot (eg. `main.DecimalShift`). `<NUMBER>` is the name of the number sequence defined in the ROI's.
|
||||
|
||||
@@ -7,4 +7,4 @@ Use the decimal place of the last analog counter for increased accuracy.
|
||||
This parameter is only supported on the `*-class*` and `*-const` models! See [Choosing-the-Model](../Choosing-the-Model) for details.
|
||||
|
||||
!!! Note
|
||||
If you edit the config file manually, you must prefix this parameter with `<NUMBER>` followed by a dot (eg. `main.ExtendedResolution`). The reason is that this parameter is specific for each `<NUMBER>` (`<NUMBER>` is the name of the number sequence defined in the ROI's).
|
||||
This parameter must be prefixed with `<NUMBER>` followed by a dot (eg. `main.ExtendedResolution`). `<NUMBER>` is the name of the number sequence defined in the ROI's.
|
||||
|
||||
@@ -6,4 +6,4 @@ This is only relevant for models which use `N`!
|
||||
See [here](../Choosing-the-Model) for details.
|
||||
|
||||
!!! Note
|
||||
If you edit the config file manually, you must prefix this parameter with `<NUMBER>` followed by a dot (eg. `main.IgnoreLeadingNaN`). The reason is that this parameter is specific for each `<NUMBER>` (`<NUMBER>` is the name of the number sequence defined in the ROI's).
|
||||
This parameter must be prefixed with `<NUMBER>` followed by a dot (eg. `main.IgnoreLeadingNaN`). `<NUMBER>` is the name of the number sequence defined in the ROI's.
|
||||
|
||||
@@ -5,4 +5,4 @@ Defines if the **Change Rate** is calculated as the difference between the last
|
||||
as the difference normalized to the interval (`RateChange` = difference per minute).
|
||||
|
||||
!!! Note
|
||||
If you edit the config file manually, you must prefix this parameter with `<NUMBER>` followed by a dot (eg. `main.MaxRateType`). The reason is that this parameter is specific for each `<NUMBER>` (`<NUMBER>` is the name of the number sequence defined in the ROI's).
|
||||
This parameter must be prefixed with `<NUMBER>` followed by a dot (eg. `main.MaxRateType`). `<NUMBER>` is the name of the number sequence defined in the ROI's.
|
||||
|
||||
@@ -6,4 +6,4 @@ Maximum allowed change between two readings, if exceeded the last reading will b
|
||||
If negative rate is disallowed and no maximum rate value is set, one false high reading will lead to a period of missing measurements until the measurement reaches the previous false high reading. E.g. if the counter is at `600,00` and it's read incorrectly as` 610,00`, all measurements will be skipped until the counter reaches `610,00`. Setting the MaxRateValue to `0,05` leads to a rejection of all readings with a difference `> 0,05`, in this case `610,00`. The rejection also applies to correct readings with a difference `> 0,05`!
|
||||
|
||||
!!! Note
|
||||
If you edit the config file manually, you must prefix this parameter with `<NUMBER>` followed by a dot (eg. `main.MaxRateValue`). The reason is that this parameter is specific for each `<NUMBER>` (`<NUMBER>` is the name of the number sequence defined in the ROI's).
|
||||
This parameter must be prefixed with `<NUMBER>` followed by a dot (eg. `main.MaxRateValue`). `<NUMBER>` is the name of the number sequence defined in the ROI's.
|
||||
|
||||
@@ -1,5 +0,0 @@
|
||||
# SD Card content
|
||||
This folder contains the files which are required to setup the SD card.
|
||||
|
||||
❗ Do not directly copy this folder onto your SD card, **it will not work!** Instead, you can use any of the artifacts generaded in any of the Pipeline runs of the [Build-Pipeline](https://github.com/jomjol/AI-on-the-edge-device/actions/workflows/build.yaml).
|
||||
The files in the `html` folder here only serve as templates. The real `html` folder get generated using the Github actions.
|
||||
Binary file not shown.
@@ -43,7 +43,7 @@ AlignmentAlgo = default
|
||||
/config/ref1.jpg 442 142
|
||||
|
||||
[Digits]
|
||||
Model = /config/dig-cont_0900_s3_q.tflite
|
||||
Model = /config/dig-cont_0712_s3_q.tflite
|
||||
CNNGoodThreshold = 0.5
|
||||
;ROIImagesLocation = /log/digit
|
||||
;ROIImagesRetention = 3
|
||||
@@ -52,7 +52,7 @@ main.dig2 343 126 30 54 false
|
||||
main.dig3 391 126 30 54 false
|
||||
|
||||
[Analog]
|
||||
Model = /config/ana-cont_1500_s2_q.tflite
|
||||
Model = /config/ana-cont_1300_s2.tflite
|
||||
CNNGoodThreshold = 0.5
|
||||
;ROIImagesLocation = /log/analog
|
||||
;ROIImagesRetention = 3
|
||||
@@ -73,7 +73,7 @@ main.MaxRateValue = 0.05
|
||||
main.ExtendedResolution = false
|
||||
main.IgnoreLeadingNaN = false
|
||||
ErrorMessage = true
|
||||
main.CheckDigitIncreaseConsistency = false
|
||||
CheckDigitIncreaseConsistency = false
|
||||
|
||||
;[MQTT]
|
||||
;Uri = mqtt://IP-ADRESS:1883
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -43,14 +43,14 @@ AlignmentAlgo = default
|
||||
/config/ref1.jpg 536 113
|
||||
|
||||
[Digits]
|
||||
Model = /config/dig-cont_0810_s3_q.tflite
|
||||
Model = /config/dig-cont_0710_s3_q.tflite
|
||||
CNNGoodThreshold = 0.5
|
||||
;ROIImagesLocation = /log/digit
|
||||
;ROIImagesRetention = 3
|
||||
main.dig1 438 62 49 71 false
|
||||
|
||||
[Analog]
|
||||
Model = /config/ana-cont_1400_s2_q.tflite
|
||||
Model = /config/ana-cont_1300_s2.tflite
|
||||
;ROIImagesLocation = /log/analog
|
||||
;ROIImagesRetention = 3
|
||||
main.ana1 452 199 120 120 false
|
||||
@@ -67,7 +67,7 @@ main.AllowNegativeRates = true
|
||||
main.ExtendedResolution = true
|
||||
main.IgnoreLeadingNaN = false
|
||||
ErrorMessage = true
|
||||
main.CheckDigitIncreaseConsistency = false
|
||||
CheckDigitIncreaseConsistency = false
|
||||
|
||||
;[MQTT]
|
||||
;Uri = mqtt://IP-ADRESS:1883
|
||||
@@ -76,14 +76,11 @@ main.CheckDigitIncreaseConsistency = false
|
||||
;user = USERNAME
|
||||
;password = PASSWORD
|
||||
RetainMessages = false
|
||||
;DomoticzTopicIn = undefined
|
||||
;main.DomoticzIDX = undefined
|
||||
HomeassistantDiscovery = false
|
||||
;MeterType = other
|
||||
;CACert = /config/certs/RootCA.pem
|
||||
;ClientCert = /config/certs/client.pem.crt
|
||||
;ClientKey = /config/certs/client.pem.key
|
||||
;ValidateServerCert = true
|
||||
|
||||
;[InfluxDB]
|
||||
;Uri = undefined
|
||||
@@ -136,3 +133,4 @@ TimeZone = CET-1CEST,M3.5.0,M10.5.0/3
|
||||
RSSIThreshold = -75
|
||||
CPUFrequency = 160
|
||||
SetupMode = false
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
|
||||
/* The UI can also be run locally, but you have to set the IP of your device accordingly.
|
||||
/* The UI can also be run locally, but you have to set the IP of your devide accordingly.
|
||||
* And you also might have to disable CORS in your webbrowser!
|
||||
* Eg using https://chromewebstore.google.com/detail/allow-cors-access-control/lhobafahddgcelffkeicbaginigeejlf?utm_source=ext_app_menu on chrome
|
||||
* Keep empty to disable using it. Enabling it will break access through a forwared port, see
|
||||
* https://github.com/jomjol/AI-on-the-edge-device/issues/2681 */
|
||||
var domainname_for_testing = "";
|
||||
|
||||
@@ -79,18 +79,6 @@
|
||||
transform: translate(-50%,-50%);
|
||||
-ms-transform: translate(-50%,-50%);
|
||||
}
|
||||
|
||||
#reboot_button {
|
||||
float: none;
|
||||
background-color: #f44336;
|
||||
color: white;
|
||||
padding: 5px;
|
||||
border-radius:
|
||||
5px; font-weight: bold;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
display: inline-block;
|
||||
}
|
||||
</style>
|
||||
|
||||
<link href="firework.css?v=$COMMIT_HASH" rel="stylesheet">
|
||||
@@ -200,11 +188,13 @@
|
||||
param;
|
||||
|
||||
function doReboot() {
|
||||
var stringota = domainname + "/reboot";
|
||||
window.location = stringota;
|
||||
window.location.href = stringota;
|
||||
window.location.assign(stringota);
|
||||
window.location.replace(stringota);
|
||||
if (confirm("Are you sure you want to reboot? Did you save your changes?")) {
|
||||
var stringota = domainname + "/reboot";
|
||||
window.location = stringota;
|
||||
window.location.href = stringota;
|
||||
window.location.assign(stringota);
|
||||
window.location.replace(stringota);
|
||||
}
|
||||
}
|
||||
|
||||
function ChangeSelection(){
|
||||
@@ -225,45 +215,50 @@
|
||||
document.getElementById("overlay").style.display = "block";
|
||||
document.getElementById("overlaytext").innerHTML = "Save Alignment Marker...";
|
||||
|
||||
function sleep(ms) {
|
||||
return new Promise(resolve => setTimeout(resolve, ms));
|
||||
}
|
||||
|
||||
async function task() {
|
||||
while (true) {
|
||||
WriteConfigININew();
|
||||
|
||||
if (neueref1 == 1 && neueref2 == 1) {
|
||||
UpdateConfigReferences(domainname);
|
||||
}
|
||||
else if (neueref1 == 1) {
|
||||
var anzneueref = 1;
|
||||
UpdateConfigReference(anzneueref, domainname);
|
||||
}
|
||||
else if (neueref2 == 1) {
|
||||
var anzneueref = 2;
|
||||
UpdateConfigReference(anzneueref, domainname);
|
||||
}
|
||||
|
||||
SaveConfigToServer(domainname);
|
||||
|
||||
document.getElementById("updatemarker").disabled = false;
|
||||
// document.getElementById("savemarker").disabled = true;
|
||||
// document.getElementById("enhancecontrast").disabled = true;
|
||||
|
||||
EnDisableItem(false, "savemarker", true);
|
||||
EnDisableItem(false, "enhancecontrast", true);
|
||||
|
||||
document.getElementById("overlay").style.display = "none";
|
||||
firework.launch('Alignment marker saved. They will get applied after the next reboot!<br><br>\n<a id="reboot_button" onclick="doReboot()">reboot now</a>', 'success', 5000);
|
||||
return;
|
||||
if (confirm("Are you sure you want to save the new alignment marker configuration?")) {
|
||||
function sleep(ms) {
|
||||
return new Promise(resolve => setTimeout(resolve, ms));
|
||||
}
|
||||
}
|
||||
|
||||
setTimeout(function () {
|
||||
// Delay so the overlay gets shown
|
||||
task();
|
||||
}, 1);
|
||||
async function task() {
|
||||
while (true) {
|
||||
WriteConfigININew();
|
||||
|
||||
if (neueref1 == 1 && neueref2 == 1) {
|
||||
UpdateConfigReferences(domainname);
|
||||
}
|
||||
else if (neueref1 == 1) {
|
||||
var anzneueref = 1;
|
||||
UpdateConfigReference(anzneueref, domainname);
|
||||
}
|
||||
else if (neueref2 == 1) {
|
||||
var anzneueref = 2;
|
||||
UpdateConfigReference(anzneueref, domainname);
|
||||
}
|
||||
|
||||
SaveConfigToServer(domainname);
|
||||
|
||||
document.getElementById("updatemarker").disabled = false;
|
||||
// document.getElementById("savemarker").disabled = true;
|
||||
// document.getElementById("enhancecontrast").disabled = true;
|
||||
|
||||
EnDisableItem(false, "savemarker", true);
|
||||
EnDisableItem(false, "enhancecontrast", true);
|
||||
|
||||
document.getElementById("overlay").style.display = "none";
|
||||
firework.launch('Alignment marker saved. They will get applied after next reboot', 'success', 5000);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
setTimeout(function () {
|
||||
// Delay so the overlay gets shown
|
||||
task();
|
||||
}, 1);
|
||||
}
|
||||
else {
|
||||
document.getElementById("overlay").style.display = "none";
|
||||
}
|
||||
}
|
||||
|
||||
function EnhanceContrast() {
|
||||
|
||||
@@ -5,20 +5,6 @@
|
||||
<meta charset="UTF-8" />
|
||||
<title>Analog ROI</title>
|
||||
|
||||
<style>
|
||||
#reboot_button {
|
||||
float: none;
|
||||
background-color: #f44336;
|
||||
color: white;
|
||||
padding: 5px;
|
||||
border-radius:
|
||||
5px; font-weight: bold;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
display: inline-block;
|
||||
}
|
||||
</style>
|
||||
|
||||
<link href="edit_style.css" rel="stylesheet">
|
||||
<link href="firework.css?v=$COMMIT_HASH" rel="stylesheet">
|
||||
|
||||
@@ -199,11 +185,13 @@ The following settings are only used for easier setup, they are <b>not</b> persi
|
||||
domainname = getDomainname();
|
||||
|
||||
function doReboot() {
|
||||
var stringota = getDomainname() + "/reboot";
|
||||
window.location = stringota;
|
||||
window.location.href = stringota;
|
||||
window.location.assign(stringota);
|
||||
window.location.replace(stringota);
|
||||
if (confirm("Are you sure you want to reboot? Did you save your changes?")) {
|
||||
var stringota = getDomainname() + "/reboot";
|
||||
window.location = stringota;
|
||||
window.location.href = stringota;
|
||||
window.location.assign(stringota);
|
||||
window.location.replace(stringota);
|
||||
}
|
||||
}
|
||||
|
||||
function EnDisableAnalog() {
|
||||
@@ -343,14 +331,16 @@ The following settings are only used for easier setup, they are <b>not</b> persi
|
||||
}
|
||||
|
||||
function SaveToConfig() {
|
||||
//_zwcat = getConfigCategory();
|
||||
cofcat["Analog"]["enabled"] = document.getElementById("Category_Analog_enabled").checked;
|
||||
WriteConfigININew();
|
||||
SaveConfigToServer(domainname);
|
||||
UpdateROIs();
|
||||
document.getElementById("saveroi").disabled = true;
|
||||
if (confirm("Are you sure you want to save the new analog ROI configuration?")) {
|
||||
//_zwcat = getConfigCategory();
|
||||
cofcat["Analog"]["enabled"] = document.getElementById("Category_Analog_enabled").checked;
|
||||
WriteConfigININew();
|
||||
SaveConfigToServer(domainname);
|
||||
UpdateROIs();
|
||||
document.getElementById("saveroi").disabled = true;
|
||||
|
||||
firework.launch('Configuration saved. It will get applied after the next reboot!<br><br>\n<a id="reboot_button" onclick="doReboot()">reboot now</a>', 'success', 5000);
|
||||
firework.launch('Configuration saved. It will get applied after next reboot', 'success', 5000);
|
||||
}
|
||||
}
|
||||
|
||||
function ShowMultiplier() {
|
||||
|
||||
@@ -20,18 +20,6 @@
|
||||
textarea {
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
#reboot_button {
|
||||
float: none;
|
||||
background-color: #f44336;
|
||||
color: white;
|
||||
padding: 5px;
|
||||
border-radius:
|
||||
5px; font-weight: bold;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
display: inline-block;
|
||||
}
|
||||
</style>
|
||||
|
||||
<link href="firework.css?v=$COMMIT_HASH" rel="stylesheet">
|
||||
@@ -50,8 +38,15 @@
|
||||
</td>
|
||||
</table>
|
||||
|
||||
<hr>
|
||||
<button class="button" onclick="saveTextAsFile()">Save Config</button>
|
||||
<table>
|
||||
<td>
|
||||
<button class="button" onclick="saveTextAsFile()">Save Config</button>
|
||||
</td>
|
||||
<td>
|
||||
<button class="button" id="reboot" type="button" onclick="doReboot()">Reboot to activate changes</button>
|
||||
</td>
|
||||
</table>
|
||||
|
||||
|
||||
<script type="text/javascript" src="readconfigparam.js?v=$COMMIT_HASH"></script>
|
||||
<script type="text/javascript" src="readconfigcommon.js?v=$COMMIT_HASH"></script>
|
||||
@@ -69,19 +64,23 @@
|
||||
|
||||
function saveTextAsFile()
|
||||
{
|
||||
FileDeleteOnServer("/config/config.ini", domainname);
|
||||
var textToSave = document.getElementById("inputTextToSave").value;
|
||||
FileSendContent(textToSave, "/config/config.ini", domainname);
|
||||
if (confirm("Are you sure you want to save the configuration?")) {
|
||||
FileDeleteOnServer("/config/config.ini", domainname);
|
||||
var textToSave = document.getElementById("inputTextToSave").value;
|
||||
FileSendContent(textToSave, "/config/config.ini", domainname);
|
||||
|
||||
firework.launch('Configuration saved. It will get applied after the next reboot!<br><br>\n<a id="reboot_button" onclick="doReboot()">reboot now</a>', 'success', 5000);
|
||||
firework.launch('Configuration saved. It will get applied after next reboot', 'success', 5000);
|
||||
}
|
||||
}
|
||||
|
||||
function doReboot() {
|
||||
var stringota = "/reboot";
|
||||
window.location = stringota;
|
||||
window.location.href = stringota;
|
||||
window.location.assign(stringota);
|
||||
window.location.replace(stringota);
|
||||
if (confirm("Are you sure you want to reboot?")) {
|
||||
var stringota = "/reboot";
|
||||
window.location = stringota;
|
||||
window.location.href = stringota;
|
||||
window.location.assign(stringota);
|
||||
window.location.replace(stringota);
|
||||
}
|
||||
}
|
||||
|
||||
LoadConfigNeu();
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -4,19 +4,6 @@
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>Digit ROI</title>
|
||||
<style>
|
||||
#reboot_button {
|
||||
float: none;
|
||||
background-color: #f44336;
|
||||
color: white;
|
||||
padding: 5px;
|
||||
border-radius:
|
||||
5px; font-weight: bold;
|
||||
text-align: center;
|
||||
text-decoration: none;
|
||||
display: inline-block;
|
||||
}
|
||||
</style>
|
||||
|
||||
<link href="edit_style.css" rel="stylesheet">
|
||||
<link href="firework.css?v=$COMMIT_HASH" rel="stylesheet">
|
||||
@@ -217,11 +204,13 @@
|
||||
domainname = getDomainname();
|
||||
|
||||
function doReboot() {
|
||||
var stringota = getDomainname() + "/reboot";
|
||||
window.location = stringota;
|
||||
window.location.href = stringota;
|
||||
window.location.assign(stringota);
|
||||
window.location.replace(stringota);
|
||||
if (confirm("Are you sure you want to reboot? Did you save your changes?")) {
|
||||
var stringota = getDomainname() + "/reboot";
|
||||
window.location = stringota;
|
||||
window.location.href = stringota;
|
||||
window.location.assign(stringota);
|
||||
window.location.replace(stringota);
|
||||
}
|
||||
}
|
||||
|
||||
function EnDisableDigits() {
|
||||
@@ -370,14 +359,16 @@
|
||||
}
|
||||
|
||||
function SaveToConfig() {
|
||||
// _zwcat = getConfigCategory();
|
||||
cofcat["Digits"]["enabled"] = document.getElementById("Category_Digits_enabled").checked;
|
||||
WriteConfigININew();
|
||||
SaveConfigToServer(domainname);
|
||||
UpdateROIs();
|
||||
document.getElementById("saveroi").disabled = true;
|
||||
if (confirm("Are you sure you want to save the new digit ROI configuration?")) {
|
||||
// _zwcat = getConfigCategory();
|
||||
cofcat["Digits"]["enabled"] = document.getElementById("Category_Digits_enabled").checked;
|
||||
WriteConfigININew();
|
||||
SaveConfigToServer(domainname);
|
||||
UpdateROIs();
|
||||
document.getElementById("saveroi").disabled = true;
|
||||
|
||||
firework.launch('Configuration saved. It will get applied after the next reboot!<br><br>\n<a id="reboot_button" onclick="doReboot()">reboot now</a>', 'success', 5000);
|
||||
firework.launch('Configuration saved. It will get applied after next reboot', 'success', 5000);
|
||||
}
|
||||
}
|
||||
|
||||
function ShowMultiplier() {
|
||||
|
||||
@@ -395,12 +395,22 @@
|
||||
|
||||
<script type="text/javascript">
|
||||
var canvas = document.getElementById('canvas'),
|
||||
domainname = getDomainname(),
|
||||
context = canvas.getContext('2d'),
|
||||
imageObj = new Image(),
|
||||
isActReference = false,
|
||||
param,
|
||||
category;
|
||||
domainname = getDomainname(),
|
||||
context = canvas.getContext('2d'),
|
||||
imageObj = new Image(),
|
||||
isActReference = false,
|
||||
param,
|
||||
category;
|
||||
|
||||
function doReboot() {
|
||||
if (confirm("Are you sure you want to reboot? Did you save the config?")) {
|
||||
var stringota = domainname + "/reboot";
|
||||
window.location = stringota;
|
||||
window.location.href = stringota;
|
||||
window.location.assign(stringota);
|
||||
window.location.replace(stringota);
|
||||
}
|
||||
}
|
||||
|
||||
function cameraParameterChanged() {
|
||||
document.getElementById("savereferenceimage").disabled = true;
|
||||
@@ -728,7 +738,7 @@
|
||||
|
||||
if (xhttp.responseText == "CamSettingsSet") {
|
||||
document.getElementById("overlay").style.display = "none";
|
||||
firework.launch('Cam Settings saved', 'success', 5000);
|
||||
firework.launch('Cam Settings saved', 'success', 2000);
|
||||
return;
|
||||
}
|
||||
else {
|
||||
|
||||
17
sd-card/html/md5.min.js
vendored
17
sd-card/html/md5.min.js
vendored
File diff suppressed because one or more lines are too long
@@ -25,7 +25,6 @@
|
||||
</style>
|
||||
|
||||
<link href="firework.css?v=$COMMIT_HASH" rel="stylesheet">
|
||||
<script src="md5.min.js?v=$COMMIT_HASH"></script>
|
||||
<script type="text/javascript" src="jquery-3.6.0.min.js?v=$COMMIT_HASH"></script>
|
||||
<script type="text/javascript" src="common.js?v=$COMMIT_HASH"></script>
|
||||
<script type="text/javascript" src="firework.js?v=$COMMIT_HASH"></script>
|
||||
@@ -143,7 +142,7 @@
|
||||
|
||||
function doRebootAfterUpdate() {
|
||||
var xhttp = new XMLHttpRequest();
|
||||
xhttp.open("GET", domainname + "/reboot", true);
|
||||
xhttp.open("GET", "/reboot", true);
|
||||
xhttp.send();
|
||||
}
|
||||
|
||||
@@ -170,35 +169,15 @@
|
||||
}
|
||||
};
|
||||
|
||||
var url = domainname + "/ota?task=emptyfirmwaredir";
|
||||
xhttp.open("GET", url, true);
|
||||
var _toDo = domainname + "/ota?task=emptyfirmwaredir";
|
||||
xhttp.open("GET", _toDo, true);
|
||||
xhttp.send();
|
||||
}
|
||||
|
||||
|
||||
function validateMd5(md5_on_device, callback) {
|
||||
const reader = new FileReader();
|
||||
|
||||
reader.onload = (event) => {
|
||||
const fileContent = event.target.result;
|
||||
md5_on_webbrowser = md5(fileContent);
|
||||
console.log("MD5 on device: " + md5_on_device + ", MD5 on web browser: " + md5_on_webbrowser);
|
||||
if (md5_on_device == md5_on_webbrowser) {
|
||||
console.log("MD5 values are equal");
|
||||
callback(true);
|
||||
}
|
||||
else {
|
||||
console.log("MD5 values are NOT equal!");
|
||||
callback(false);
|
||||
}
|
||||
}
|
||||
|
||||
var fileInput = document.getElementById("file_selector").files;
|
||||
reader.readAsArrayBuffer(fileInput[0]);
|
||||
}
|
||||
|
||||
|
||||
function extract() {
|
||||
document.getElementById("status").innerText = "Status: Processing on device...";
|
||||
|
||||
var xhttp = new XMLHttpRequest();
|
||||
/* first delete the old firmware */
|
||||
xhttp.onreadystatechange = function() {
|
||||
@@ -207,9 +186,9 @@
|
||||
document.cookie = "page=overview.html?v=$COMMIT_HASH" + "; path=/"; // Make sure after the reboot we go to the overview page
|
||||
|
||||
if (xhttp.responseText.startsWith("reboot")) { // Reboot required
|
||||
console.log("The device will now reboot and install the update!");
|
||||
console.log("Upload completed, the device will now restart and install the update!");
|
||||
document.getElementById("status").innerText = "Status: Installing...";
|
||||
firework.launch('Upload completed and validated. The device will now reboot and install the update', 'success', 5000);
|
||||
firework.launch('Upload completed, the device will now restart and install the update', 'success', 5000);
|
||||
|
||||
/* Tell it to reboot */
|
||||
doRebootAfterUpdate();
|
||||
@@ -249,8 +228,8 @@
|
||||
|
||||
var file_name = document.getElementById("file_selector").value;
|
||||
filePath = file_name.split(/[\\\/]/).pop();
|
||||
var url = domainname + "/ota?task=update&file=" + filePath;
|
||||
xhttp.open("GET", url, true);
|
||||
var _toDo = domainname + "/ota?task=update&file=" + filePath;
|
||||
xhttp.open("GET", _toDo, true);
|
||||
xhttp.send();
|
||||
}
|
||||
|
||||
@@ -263,7 +242,7 @@
|
||||
function upload() {
|
||||
document.getElementById("status").innerText = "Status: Uploading...";
|
||||
|
||||
var url = domainname + "/upload/firmware/" + filePath + "?md5";
|
||||
var upload_path = "/upload/firmware/" + filePath;
|
||||
|
||||
var file = _("file_selector").files[0];
|
||||
var formdata = new FormData();
|
||||
@@ -274,7 +253,7 @@
|
||||
ajax.addEventListener("error", errorHandler, false);
|
||||
ajax.addEventListener("abort", abortHandler, false);
|
||||
|
||||
ajax.open("POST", url);
|
||||
ajax.open("POST", upload_path);
|
||||
ajax.send(file);
|
||||
}
|
||||
|
||||
@@ -284,43 +263,16 @@
|
||||
" MB of " + (event.total / 1024/ 1024).toFixed(2) + " MB";
|
||||
var percent = (event.loaded / event.total) * 100;
|
||||
_("progressBar").value = Math.round(percent);
|
||||
|
||||
if (Math.round(percent) == 100) {
|
||||
_("progressBar").value = 0; //will clear progress bar after successful upload
|
||||
_("loaded_n_total").innerHTML = "";
|
||||
_("status").innerHTML = "Status: Upload completed. Validating file...";
|
||||
}
|
||||
else {
|
||||
_("status").innerHTML = "Status: " + Math.round(percent) + "% uploaded...";
|
||||
}
|
||||
_("status").innerHTML = "Status: " + Math.round(percent) + "% uploaded. Please wait...";
|
||||
}
|
||||
|
||||
|
||||
function completeHandler(event) {
|
||||
console.log("Upload completed");
|
||||
console.log("Response: " + event.target.responseText);
|
||||
|
||||
try {
|
||||
md5_on_device = JSON.parse(event.target.responseText).md5;
|
||||
validateMd5(md5_on_device, (result) => {
|
||||
if (result == true) {
|
||||
_("status").innerHTML = "Status: The uploaded file is valid, installing it...";
|
||||
extract();
|
||||
}
|
||||
else {
|
||||
_("status").innerHTML = "Status: The file got corrupted! Please upload it again!";
|
||||
firework.launch('Upload failed, the file got corrupted! Please upload it again!', 'danger', 30000);
|
||||
document.getElementById("start_OTA_button").disabled = false;
|
||||
}
|
||||
});
|
||||
}
|
||||
catch (e) {
|
||||
// If the firmware is to old, it will return the file sever page instead of the JSON object with the MD5 sum.
|
||||
// In juch case just proceed to keep legacy support.
|
||||
console.log("It seems to be a legacy firmware, installing the update without validation!");
|
||||
_("status").innerHTML = "Status: It seems to be a legacy firmware, installing the update without validation...";
|
||||
extract();
|
||||
}
|
||||
_("status").innerHTML = "Status: " + event.target.responseText;
|
||||
_("progressBar").value = 0; //will clear progress bar after successful upload
|
||||
_("loaded_n_total").innerHTML = "";
|
||||
|
||||
extract();
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@ var ref = new Array(2);
|
||||
var NUMBERS = new Array(0);
|
||||
var REFERENCES = new Array(0);
|
||||
|
||||
|
||||
function getNUMBERSList() {
|
||||
_domainname = getDomainname();
|
||||
var namenumberslist = "";
|
||||
@@ -32,6 +33,7 @@ function getNUMBERSList() {
|
||||
return namenumberslist;
|
||||
}
|
||||
|
||||
|
||||
function getDATAList() {
|
||||
_domainname = getDomainname();
|
||||
datalist = "";
|
||||
@@ -60,6 +62,7 @@ function getDATAList() {
|
||||
return datalist;
|
||||
}
|
||||
|
||||
|
||||
function getTFLITEList() {
|
||||
_domainname = getDomainname();
|
||||
tflitelist = "";
|
||||
@@ -87,6 +90,7 @@ function getTFLITEList() {
|
||||
return tflitelist;
|
||||
}
|
||||
|
||||
|
||||
function ParseConfig() {
|
||||
config_split = config_gesamt.split("\n");
|
||||
var aktline = 0;
|
||||
@@ -168,7 +172,7 @@ function ParseConfig() {
|
||||
category[catname]["enabled"] = false;
|
||||
category[catname]["found"] = false;
|
||||
param[catname] = new Object();
|
||||
ParamAddValue(param, catname, "DecimalShift", 1, true, "0");
|
||||
ParamAddValue(param, catname, "DecimalShift", 1, true);
|
||||
ParamAddValue(param, catname, "AnalogToDigitTransitionStart", 1, true, "9.2");
|
||||
ParamAddValue(param, catname, "ChangeRateThreshold", 1, true, "2");
|
||||
// ParamAddValue(param, catname, "PreValueUse", 1, true, "true");
|
||||
@@ -181,7 +185,7 @@ function ParseConfig() {
|
||||
ParamAddValue(param, catname, "IgnoreLeadingNaN", 1, true, "false");
|
||||
// ParamAddValue(param, catname, "IgnoreAllNaN", 1, true, "false");
|
||||
ParamAddValue(param, catname, "ErrorMessage");
|
||||
ParamAddValue(param, catname, "CheckDigitIncreaseConsistency", 1, true, "false");
|
||||
ParamAddValue(param, catname, "CheckDigitIncreaseConsistency");
|
||||
|
||||
var catname = "MQTT";
|
||||
category[catname] = new Object();
|
||||
@@ -355,6 +359,7 @@ function ParseConfig() {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function ParamAddValue(param, _cat, _param, _anzParam = 1, _isNUMBER = false, _defaultValue = "", _checkRegExList = null) {
|
||||
param[_cat][_param] = new Object();
|
||||
param[_cat][_param]["found"] = false;
|
||||
@@ -366,6 +371,7 @@ function ParamAddValue(param, _cat, _param, _anzParam = 1, _isNUMBER = false, _d
|
||||
param[_cat][_param].checkRegExList = _checkRegExList;
|
||||
};
|
||||
|
||||
|
||||
function ParseConfigParamAll(_aktline, _catname) {
|
||||
++_aktline;
|
||||
|
||||
@@ -397,6 +403,7 @@ function ParseConfigParamAll(_aktline, _catname) {
|
||||
return _aktline;
|
||||
}
|
||||
|
||||
|
||||
function ParamExtractValue(_param, _linesplit, _catname, _paramname, _aktline, _iscom, _anzvalue = 1) {
|
||||
if ((_linesplit[0].toUpperCase() == _paramname.toUpperCase()) && (_linesplit.length > _anzvalue)) {
|
||||
_param[_catname][_paramname]["found"] = true;
|
||||
@@ -410,6 +417,7 @@ function ParamExtractValue(_param, _linesplit, _catname, _paramname, _aktline, _
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function ParamExtractValueAll(_param, _linesplit, _catname, _aktline, _iscom) {
|
||||
for (var paramname in _param[_catname]) {
|
||||
_AktROI = "default";
|
||||
@@ -467,6 +475,7 @@ function ParamExtractValueAll(_param, _linesplit, _catname, _aktline, _iscom) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function getCamConfig() {
|
||||
ParseConfig();
|
||||
|
||||
@@ -644,10 +653,12 @@ function getCamConfig() {
|
||||
return param;
|
||||
}
|
||||
|
||||
|
||||
function getConfigParameters() {
|
||||
return param;
|
||||
}
|
||||
|
||||
|
||||
function WriteConfigININew() {
|
||||
// Cleanup empty NUMBERS
|
||||
for (var j = 0; j < NUMBERS.length; ++j) {
|
||||
@@ -749,6 +760,7 @@ function WriteConfigININew() {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function isCommented(input) {
|
||||
let isComment = false;
|
||||
|
||||
@@ -760,6 +772,7 @@ function isCommented(input) {
|
||||
return [isComment, input];
|
||||
}
|
||||
|
||||
|
||||
function SaveConfigToServer(_domainname){
|
||||
// leere Zeilen am Ende löschen
|
||||
var zw = config_split.length - 1;
|
||||
@@ -779,14 +792,17 @@ function SaveConfigToServer(_domainname){
|
||||
FileSendContent(config_gesamt, "/config/config.ini", _domainname);
|
||||
}
|
||||
|
||||
|
||||
function getConfig() {
|
||||
return config_gesamt;
|
||||
}
|
||||
|
||||
|
||||
function getConfigCategory() {
|
||||
return category;
|
||||
}
|
||||
|
||||
|
||||
function ExtractROIs(_aktline, _type){
|
||||
var linesplit = ZerlegeZeile(_aktline);
|
||||
abc = getNUMBERS(linesplit[0], _type);
|
||||
@@ -803,6 +819,7 @@ function ExtractROIs(_aktline, _type){
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function getNUMBERS(_name, _type, _create = true) {
|
||||
_pospunkt = _name.indexOf (".");
|
||||
|
||||
@@ -862,6 +879,7 @@ function getNUMBERS(_name, _type, _create = true) {
|
||||
return neuroi;
|
||||
}
|
||||
|
||||
|
||||
function CopyReferenceToImgTmp(_domainname) {
|
||||
for (index = 0; index < 2; ++index) {
|
||||
_filenamevon = REFERENCES[index]["name"];
|
||||
@@ -876,10 +894,12 @@ function CopyReferenceToImgTmp(_domainname) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function GetReferencesInfo(){
|
||||
return REFERENCES;
|
||||
}
|
||||
|
||||
|
||||
function UpdateConfigReferences(_domainname){
|
||||
for (var index = 0; index < 2; ++index) {
|
||||
_filenamenach = REFERENCES[index]["name"];
|
||||
@@ -894,6 +914,7 @@ function UpdateConfigReferences(_domainname){
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function UpdateConfigReference(_anzneueref, _domainname){
|
||||
var index = 0;
|
||||
|
||||
@@ -918,10 +939,12 @@ function UpdateConfigReference(_anzneueref, _domainname){
|
||||
FileCopyOnServer(_filenamevon, _filenamenach, _domainname);
|
||||
}
|
||||
|
||||
|
||||
function getNUMBERInfo(){
|
||||
return NUMBERS;
|
||||
}
|
||||
|
||||
|
||||
function RenameNUMBER(_alt, _neu){
|
||||
if ((_neu.indexOf(".") >= 0) || (_neu.indexOf(",") >= 0) || (_neu.indexOf(" ") >= 0) || (_neu.indexOf("\"") >= 0)) {
|
||||
return "Number sequence name must not contain , . \" or a space";
|
||||
@@ -949,6 +972,7 @@ function RenameNUMBER(_alt, _neu){
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
function DeleteNUMBER(_delete){
|
||||
if (NUMBERS.length == 1) {
|
||||
return "One number sequence is mandatory. Therefore this cannot be deleted"
|
||||
@@ -969,6 +993,7 @@ function DeleteNUMBER(_delete){
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
function CreateNUMBER(_numbernew){
|
||||
found = false;
|
||||
|
||||
@@ -1016,6 +1041,7 @@ function CreateNUMBER(_numbernew){
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
function getROIInfo(_typeROI, _number){
|
||||
index = -1;
|
||||
|
||||
@@ -1033,6 +1059,7 @@ function getROIInfo(_typeROI, _number){
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function RenameROI(_number, _type, _alt, _neu){
|
||||
if ((_neu.includes("=")) || (_neu.includes(".")) || (_neu.includes(":")) || (_neu.includes(",")) || (_neu.includes(";")) || (_neu.includes(" ")) || (_neu.includes("\""))) {
|
||||
return "ROI name must not contain . : , ; = \" or space";
|
||||
@@ -1071,6 +1098,7 @@ function RenameROI(_number, _type, _alt, _neu){
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
function DeleteNUMBER(_delte) {
|
||||
if (NUMBERS.length == 1) {
|
||||
return "The last number cannot be deleted"
|
||||
@@ -1091,6 +1119,7 @@ function DeleteNUMBER(_delte) {
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
function CreateROI(_number, _type, _pos, _roinew, _x, _y, _dx, _dy, _CCW){
|
||||
_indexnumber = -1;
|
||||
|
||||
|
||||
@@ -34,11 +34,13 @@ p {font-size: 1em;}
|
||||
|
||||
<script>
|
||||
function doReboot() {
|
||||
var stringota = getDomainname() + "/reboot";
|
||||
window.location = stringota;
|
||||
window.location.href = stringota;
|
||||
window.location.assign(stringota);
|
||||
window.location.replace(stringota);
|
||||
// if (confirm("Are you sure you want to reboot the ESP32?")) {
|
||||
var stringota = getDomainname() + "/reboot";
|
||||
window.location = stringota;
|
||||
window.location.href = stringota;
|
||||
window.location.assign(stringota);
|
||||
window.location.replace(stringota);
|
||||
// }
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
// var xhttp = new XMLHttpRequest();
|
||||
// xhttp.onreadystatechange = function() {if (xhttp.readyState == 4) {if (xhttp.status == 200) {document.reload();}}};
|
||||
if (!file.name.includes("remote-setup")){
|
||||
if (!confirm("The zip file name should contain \"...remote-setup...\". Are you sure you have downloaded the correct file?"))
|
||||
if (!confirm("The zip file name should contain \"...remote-setup...\". Are you sure that you have downloaded the correct file?"))
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -41,7 +41,7 @@ if (!file.name.includes("remote-setup")){
|
||||
var file = document.getElementById("newfile").files[0];
|
||||
if (!file.name.includes("remote-setup"))
|
||||
{
|
||||
if (!confirm("The zip file name should contain \"...remote-setup...\". Are you sure you have downloaded the correct file?"))
|
||||
if (!confirm("The zip file name should contain \"...remote-setup...\". Are you sure that you have downloaded the correct file?"))
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
# Webinstaller
|
||||
This folder is used to provide the required files to generate the [Web-Installer](https://jomjol.github.io/AI-on-the-edge-device/).
|
||||
The Webinstaller gets automatically updated on a release using the Github actions.
|
||||
@@ -1,2 +0,0 @@
|
||||
# Binary folder of the webinstaller
|
||||
The firmware itself (`firmware.bin`) gets copied to this folder through the Github action.
|
||||
Reference in New Issue
Block a user