diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml
index 5192cdef2..ea652db20 100644
--- a/.github/workflows/build.yaml
+++ b/.github/workflows/build.yaml
@@ -53,6 +53,7 @@ jobs:
./code/.pio/build/esp32cam/partitions.bin
./code/.pio/build/esp32cam/bootloader.bin
./html/*
+ ./demo/*
key: generated-files-${{ github.run_id }}
restore-keys: generated-files # This matches above key as it is only used as a prefix. it the restores the nearest cache, see https://github.com/restore-keys:/blob/main/tips-and-workarounds.md#update-a-cache
@@ -87,6 +88,11 @@ jobs:
echo "Replacing variables..."
cd html; find . -type f -exec sed -i 's/$COMMIT_HASH/${{ steps.vars.outputs.sha_short }}/g' {} \;
+ - name: Prepare Demo mode files
+ run: |
+ rm -rf ./demo
+ mkdir demo
+ cp -r ./sd-card/demo/* ./demo/
#########################################################################################
## Pack for Update
@@ -97,6 +103,7 @@ jobs:
# - /firmware.bin
# - (optional) /html/* (inkl. subfolders)
# - (optional) /config/*.tfl
+ # - (optional) /demo/*
runs-on: ubuntu-latest
needs: build
@@ -111,6 +118,7 @@ jobs:
./code/.pio/build/esp32cam/partitions.bin
./code/.pio/build/esp32cam/bootloader.bin
./html/*
+ ./demo/*
key: generated-files-${{ github.run_id }}
restore-keys: generated-files # This matches above key as it is only used as a prefix. it the restores the nearest cache, see https://github.com/restore-keys:/blob/main/tips-and-workarounds.md#update-a-cache
@@ -135,6 +143,9 @@ jobs:
- name: Add Web UI to update
run: cp -r ./html ./update/
+
+ - name: Add Demo mode files to update
+ run: cp -r ./demo ./update/
- name: Add CNN to update
run: |
@@ -158,6 +169,7 @@ jobs:
# remote_setup__version.zip file with following content:
# - /firmware.bin
# - /html/* (inkl. subfolders)
+ # - /demo/*
# - /config/*
runs-on: ubuntu-latest
needs: build
@@ -173,6 +185,7 @@ jobs:
./code/.pio/build/esp32cam/partitions.bin
./code/.pio/build/esp32cam/bootloader.bin
./html/*
+ ./demo/*
key: generated-files-${{ github.run_id }}
restore-keys: generated-files # This matches above key as it is only used as a prefix. it the restores the nearest cache, see https://github.com/restore-keys:/blob/main/tips-and-workarounds.md#update-a-cache
@@ -197,6 +210,9 @@ jobs:
- name: Add Web UI to remote_setup
run: cp -r ./html ./remote_setup/
+ - name: Add Demo mode files to update
+ run: cp -r ./demo ./update/
+
- name: Add whole config folder to remote_setup
run: |
rm -rf ./remote_setup/config/
@@ -229,6 +245,7 @@ jobs:
./code/.pio/build/esp32cam/partitions.bin
./code/.pio/build/esp32cam/bootloader.bin
./html/*
+ ./demo/*
key: generated-files-${{ github.run_id }}
restore-keys: generated-files # This matches above key as it is only used as a prefix. it the restores the nearest cache, see https://github.com/restore-keys:/blob/main/tips-and-workarounds.md#update-a-cache
@@ -257,7 +274,9 @@ jobs:
cp -f "./code/.pio/build/esp32cam/bootloader.bin" "manual_setup/bootloader.bin"
cp -f "./code/.pio/build/esp32cam/partitions.bin" "manual_setup/partitions.bin"
rm -rf ./sd-card/html
+ rm -rf ./sd-card/demo
cp -r ./html ./sd-card/ # Overwrite the Web UI with the preprocessed files
+ cp -r ./demo ./sd-card/
cd sd-card; zip -r ../manual_setup/sd-card.zip *; cd ..
cd ./manual_setup
@@ -271,7 +290,7 @@ jobs:
#########################################################################################
## Prepare and create release
#########################################################################################
- release:
+ prepare-release:
runs-on: ubuntu-latest
needs: [pack-for-update, pack-for-manual_setup, pack-for-remote_setup]
if: startsWith(github.ref, 'refs/tags/')
@@ -331,13 +350,11 @@ jobs:
# extract the version used in next step
- id: get_version
- if: startsWith(github.ref, 'refs/tags/')
- uses: Simply007/get-version-action@v2
+ uses: drewg13/get-version-action@98dda2a47a257e202c2e6c2ed2e6072ec23f448e
# # the changelog [unreleased] will now be changed to the release version
# - name: Update changelog
# uses: thomaseizinger/keep-a-changelog-new-release@v1
-# if: startsWith(github.ref, 'refs/tags/')
# with:
# changelogPath: Changelog.md
# version: ${{ steps.get_version.outputs.version-without-v }}
@@ -345,7 +362,6 @@ jobs:
# # the release notes will be extracted from changelog
# - name: Extract release notes
# id: extract-release-notes
-# if: startsWith(github.ref, 'refs/tags/')
# uses: ffurrer2/extract-release-notes@v1
# with:
# changelog_file: Changelog.md
@@ -353,12 +369,11 @@ jobs:
# Releases should only be created on master by tagging the last commit.
# all artifacts in firmware folder pushed to the release
- name: Release
- uses: softprops/action-gh-release@v1
+ uses: softprops/action-gh-release@v2.0.8
# Note:
# If you get the error "Resource not accessible by integration",
# The access rights are not sufficient, see
# https://github.com/softprops/action-gh-release/issues/232#issuecomment-1131379440
- if: startsWith(github.ref, 'refs/tags/')
with:
name: ${{ steps.get_version.outputs.version-without-v }}
body: ${{ steps.extract-release-notes.outputs.release_notes }}
@@ -367,7 +382,6 @@ jobs:
# # Commit&Push Changelog to master branch. Must be manually merged back to rolling
# - name: Commit changes and push changes
-# if: startsWith(github.ref, 'refs/tags/')
# run: |
# git config user.name github-actions
# git config user.email github-actions@github.com
@@ -380,8 +394,9 @@ jobs:
## Update the Web Installer on a release
#########################################################################################
# Make sure to also update update-webinstaller.yml!
- update-web-installer:
- needs: [release]
+ update-web-installer:
+ if: github.event_name == 'release' && github.event.action == 'published' # Only run on release but not on prerelease
+ needs: [prepare-release]
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
diff --git a/.github/workflows/manual-update-contributors-list.yaml b/.github/workflows/manual-update-contributors-list.yaml
new file mode 100644
index 000000000..aeb5b3df9
--- /dev/null
+++ b/.github/workflows/manual-update-contributors-list.yaml
@@ -0,0 +1,21 @@
+# This updates the Contributors list in the README.md
+# it only gets run on:
+# - Manually triggered
+
+name: Manually update contributors list
+
+on:
+ workflow_dispatch: # Run on manual trigger
+
+jobs:
+ manually-update-contributors-list:
+ runs-on: ubuntu-latest
+ name: A job to automatically update the contributors list in the README.md
+ permissions:
+ contents: write
+ pull-requests: write
+ steps:
+ - name: Contribute List
+ uses: akhilmhdh/contributors-readme-action@v2.3.10
+ env:
+ GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
diff --git a/Changelog.md b/Changelog.md
index 3fbb4c640..84aaf6a7c 100644
--- a/Changelog.md
+++ b/Changelog.md
@@ -1,3 +1,60 @@
+## [16.0.0-RC4] - 2024-10-06
+
+For a full list of changes see [Full list of changes](https://github.com/jomjol/AI-on-the-edge-device/compare/v15.7.0...v16.0.0-RC1)
+
+#### Known issues
+Please check the [issues](https://github.com/jomjol/AI-on-the-edge-device/issues) and
+[discussions](https://github.com/jomjol/AI-on-the-edge-device/discussions) before reporting a new issue.
+
+#### Core Changes
+Only changes since RC2 are listed:
+- Update esp32-camera submodule to `v2.0.13` (#3316)
+- Added contributor list (#3317)
+- Added files for demo mode (#3315)
+
+#### Bug Fixes
+Only changes since RC2 are listed:
+- Added delay in InitCam (#3313) to fix `Camera not detected` issues
+
+
+## [16.0.0-RC3] - 2024-10-05
+
+For a full list of changes see [Full list of changes](https://github.com/jomjol/AI-on-the-edge-device/compare/v15.7.0...v16.0.0-RC1)
+
+#### Known issues
+Please check the [issues](https://github.com/jomjol/AI-on-the-edge-device/issues) and
+[discussions](https://github.com/jomjol/AI-on-the-edge-device/discussions) before reporting a new issue.
+
+#### Core Changes
+Only changes since RC2 are listed:
+- Renamed MQTT topic from `rate_per_digitalization_round` to `rate_per_digitization_round` (change happened already in RC1)
+
+#### Bug Fixes
+Only changes since RC2 are listed:
+- Re-did revertion of TFlite submodule update as certain modules crash with it (#3269) (change was lost)
+
+
+## [16.0.0-RC2] - 2024-10-04
+
+For a full list of changes see [Full list of changes](https://github.com/jomjol/AI-on-the-edge-device/compare/v15.7.0...v16.0.0-RC1)
+
+#### Known issues
+Please check the [issues](https://github.com/jomjol/AI-on-the-edge-device/issues) and
+[discussions](https://github.com/jomjol/AI-on-the-edge-device/discussions) before reporting a new issue.
+
+#### Core Changes
+Only changes since RC1 are listed:
+- Updated parameter documentation pages
+- Rename/remove unused parameters (#3291)
+- Migrate-cam-parameters (#3288)
+
+#### Bug Fixes
+Only changes since RC1 are listed:
+- Reverted TFlite submodule update as certain modules crash with it (#3269)
+- Changed the webhook UploadImg to false (#3279)
+- Changed default value from boolean to numeric value in parameter camDenoise documentation
+- Updated config page
+
## [16.0.0-RC1] - 2024-09-24
For a full list of changes see [Full list of changes](https://github.com/jomjol/AI-on-the-edge-device/compare/v15.7.0...v16.0.0-RC1)
@@ -524,16 +581,16 @@ Intermediate Digits
- Implementation of new CNN types to detect intermediate values of digits with rolling numbers
- By default the old algo (0, 1, ..., 9, "N") is active (due to the limited types of digits trained so far)
- - Activation can be done by selection a tflite file with the new trained model in the 'config.ini'
+ - Activation can be done by selecting a tflite file with the new trained model in the 'config.ini'
- **Details can be found in the [wiki](https://github.com/jomjol/AI-on-the-edge-device/wiki/Neural-Network-Types)** (different types, trained image types, naming convention)
-- Updated neural network files (and adaption to new naming convention)
+- Updated neural network files (and adaptation to new naming convention)
-- Published a tool to download and combine log files - **Thanks to **
+- Published a tool to download and combine log files - Thanks to [Contributor]
- Files see ['/tools/logfile-tool'](tbd), How-to see [wiki](https://github.com/jomjol/AI-on-the-edge-device/wiki/Gasmeter-Log-Downloader)
-- Bug Fix: InfluxDB enabling in grahic configuration
+- Bug Fix: InfluxDB enabling in graphic configuration
## [10.6.2](https://github.com/jomjol/AI-on-the-edge-device/releases/tag/v10.6.2), 2022-07-24
@@ -547,7 +604,7 @@ Stability Increase
- **NEW 10.6.1**: Bug Fix: tflite-filename with ".", HTML spelling error
-- IndluxDB: direct injection into InfluxDB - thanks to **[wetneb](https://github.com/wetneb)**
+- InfluxDB: direct injection into InfluxDB - thanks to **[wetneb](https://github.com/wetneb)**
- MQTT: implemented "Retain Flag" and extend with absolute Change (in addition to rate)
@@ -1062,7 +1119,7 @@ External Illumination
- Bug in configuration of analog ROIs corrected
-- minor bug correction
+- minor Bug correction
## [1.0.1](2020-09-05)
@@ -1071,7 +1128,7 @@ External Illumination
- preValue.ini Bug corrected
-- minor bug correction
+- minor Bug correction
## [1.0.0](2020-09-04)
diff --git a/FeatureRequest.md b/FeatureRequest.md
index da9bc85d8..eb7c8509f 100644
--- a/FeatureRequest.md
+++ b/FeatureRequest.md
@@ -40,16 +40,16 @@ ____
Demo mode requires a working camera (if not, one receives a 'Cam bad' error). Would be nice to demo or play around on other ESP32 boards (or on ESP32-CAM boards when you broke the camera cable...).
#### #35 Use the same model, but provide the image from a Smartphone Camera
-as reading the Electricity or Water meter every few minutues only delivers apparent accuracy (DE: "Scheingenauigkeit") you could just as well take a picture with your Smartphone evey so often (e.g. once a week when you are in the Basement anyway), then with some "semi clever" tricks pass this image to the model developed here, and the values then on to who ever needs them e.g. via MQTT.
+as reading the Electricity or Water meter every few minutes only delivers apparent accuracy (DE: "Scheingenauigkeit") you could just as well take a picture with your Smartphone every so often (e.g. once a week when you are in the Basement anyway), then with some "semi clever" tricks pass this image to the model developed here, and the values than on to whoever needs them e.g. via MQTT.
IMO: It is not needed to have that many readings (datapoints) as our behaviour (Use of electricity or water) doesn't vary that much, say, over a weeks time. The interpolation between weekly readings will give sufficient information on the power and/or water usage.
#### #34 implement state and Roi for water leak detection
-for example see Roi on the next picture..
+for example see Roi in the next picture..
![grafik](https://user-images.githubusercontent.com/38385805/207858812-2a6ba41d-1a8c-4fa1-9b6a-53cdd113c106.png)
-in case of position change between the measurments set this state to true, if there is no change set it back to false.
+in case of position change between the measurements set this state to true, if there is no change set it back to false.
In a defined time window this movement can lead into an alarm state / water leak..
-haveing this state in the mqtt broker can trigger functions like closing the ater pipe walve and so on...
+having this state in the mqtt broker can trigger functions like closing the water pipe valve and so on...
@@ -65,7 +65,7 @@ haveing this state in the mqtt broker can trigger functions like closing the ate
#### #31 Implement InfluxDB v2.x interface
-* Currently only InfluxDB v1.x is supportet, extend to v2.x
+* Currently only InfluxDB v1.x is supported, extend to v2.x
* Remark: interface has changed
* see [#1160](https://github.com/jomjol/AI-on-the-edge-device/issues/1160)
@@ -82,7 +82,7 @@ haveing this state in the mqtt broker can trigger functions like closing the ate
#### #28 Improved error handling for ROIs
* In case a ROI is out of the image, there is no error message, but a non sense image is used
-* Implement a error message for wrong configuratioin of ROI
+* Implement a error message for wrong configuration of ROI
#### #27 Use Homie Spec for Mqtt binding
diff --git a/README.md b/README.md
index 60a72b571..5af9a1660 100644
--- a/README.md
+++ b/README.md
@@ -1,108 +1,551 @@
-# Welcome to the AI-on-the-edge-device
-
+# AI on the Edge Device: Digitizing Your non-digital meters with an ESP32-CAM
+
+
+
-Artificial intelligence based systems have become established in our everyday lives. Just think of speech or image recognition. Most of the systems rely on either powerful processors or a direct connection to the cloud for doing the calculations there. With the increasing power of modern processors, the AI systems are coming closer to the end user β which is usually called **edge computing**.
-Here, this edge computing is put into a practically oriented example, where an AI network is implemented on an ESP32 device so: **AI on the edge**.
+Artificial intelligence is everywhere, from speech to image recognition. While most AI systems rely on powerful processors or cloud computing, **edge computing** brings AI closer to the end user by utilizing the capabilities of modern processors.
+This project demonstrates edge computing using the **ESP32**, a low-cost, AI-capable device, to digitize your analog metersβwhether water, gas, or electricity. With affordable hardware and simple instructions, you can turn any standard meter into a smart device.
-This project allows you to digitize your **analog** water, gas, power and other meters using cheap and easily available hardware.
+Let's explore how to make **AI on the Edge** a reality! π
-All you need is an [ESP32 board with a supported camera](https://jomjol.github.io/AI-on-the-edge-device-docs/Hardware-Compatibility/) and something of a practical hand.
+All you need is an [ESP32 board with a supported camera](https://jomjol.github.io/AI-on-the-edge-device-docs/Hardware-Compatibility/) and some practical skills. π οΈ
-
+---
-## Key features
-- Tensorflow Lite (TFlite) integration β including easy-to-use wrapper
-- Inline image processing (feature detection, alignment, ROI extraction)
-- **Small** and **cheap** device (3 x 4.5 x 2 cmΒ³, < 10 EUR)
-- Integrated camera and illumination
-- Web interface for administration and control
-- OTA interface for updating directly via the web interface
-- Full integration into Homeassistant
-- Support for Influx DB 1 and 2
-- MQTT
-- REST API
+## Key Features π
+- π **Tensorflow Lite (TFLite) integration** β including an easy-to-use wrapper.
+- πΈ **Inline image processing** (feature detection, alignment, ROI extraction).
+- π‘ **Small** and **affordable** device (3 x 4.5 x 2 cmΒ³, less than 10 EUR).
+- π· Integrated camera and illumination.
+- π Web interface for administration and control.
+- π OTA interface for updating directly via the web interface.
+- π Full integration with Home Assistant.
+- π Support for **Influx DB 1** and **2**.
+- π‘ **MQTT protocol** support.
+- π₯ **REST API** available for data access.
-## Workflow
-The device takes a photo of your meter at a defined interval. It then extracts the Regions of Interest (ROIs) from the image and runs them through artificial intelligence. As a result, you get the digitized value of your meter.
+## Workflow π§
+The device captures a photo of your meter at set intervals. It then extracts the Regions of Interest (ROIs) from the image and runs them through artificial intelligence. As a result, you get the digitized value of your meter.
-There are several options for what to do with that value. Either send it to an MQTT broker, write it to an InfluxDb or simply provide access to it via a REST API.
+There are several options for what to do with that value:
+- π€ Send it to a **MQTT broker**.
+- π Write it to an **InfluxDb**.
+- π Provide access via a **REST API**.
-
+
+
+
-## Impressions
-### AI-on-the-edge-device on a Water Meter
-
+---
-### Web Interface (Water Meter)
-
+## Impressions π·
-### AI-on-the-edge-device on a Electrical Power Meter
-
+### AI-on-the-edge-device on a Water Meter π§
+
+
+
+### Web Interface (Water Meter) π»
+
+
+
-## Setup
-There is growing [documentation](https://jomjol.github.io/AI-on-the-edge-device-docs/) which provides you with a lot of information. Head there to get a start, set it up and configure it.
+### AI-on-the-edge-device on an Electrical Power Meter β‘
+
+
+
-There are also articles in the German Heise magazine "make:" about the setup and technical background (behind a paywall): [DIY - Setup](https://www.heise.de/select/make/2021/2/2103513300897420296)
+---
-A lot of people created useful Youtube videos which might help you getting started.
-Here a small selection:
+## Setup π οΈ
+There is growing [documentation](https://jomjol.github.io/AI-on-the-edge-device-docs/) which provides you with a lot of information. Head there to get started, set it up, and configure it.
-- [youtube.com/watch?v=HKBofb1cnNc](https://www.youtube.com/watch?v=HKBofb1cnNc)
-- [youtube.com/watch?v=yyf0ORNLCk4](https://www.youtube.com/watch?v=yyf0ORNLCk4)
-- [youtube.com/watch?v=XxmTubGek6M](https://www.youtube.com/watch?v=XxmTubGek6M)
-- [youtube.com/watch?v=mDIJEyElkAU](https://www.youtube.com/watch?v=mDIJEyElkAU)
-- [youtube.com/watch?v=SssiPkyKVVs](https://www.youtube.com/watch?v=SssiPkyKVVs)
-- [youtube.com/watch?v=MAHE_QyHZFQ](https://www.youtube.com/watch?v=MAHE_QyHZFQ)
-- [youtube.com/watch?v=Uap_6bwtILQ](https://www.youtube.com/watch?v=Uap_6bwtILQ)
+There are also articles in the German Heise magazine "make:" about the setup and technical background (behind a paywall): [DIY - Setup](https://www.heise.de/select/make/2021/2/2103513300897420296) π°
-For further background information, head to [Neural Networks](https://www.heise.de/select/make/2021/6/2126410443385102621), [Training Neural Networks](https://www.heise.de/select/make/2022/1/2134114065999161585) and [Programming on the ESP32](https://www.heise.de/select/make/2022/2/2204010051597422030).
+A lot of people have created useful YouTube videos that might help you get started:
+- π₯ [youtube.com/watch?v=HKBofb1cnNc](https://www.youtube.com/watch?v=HKBofb1cnNc)
+- π₯ [youtube.com/watch?v=yyf0ORNLCk4](https://www.youtube.com/watch?v=yyf0ORNLCk4)
+- π₯ [youtube.com/watch?v=XxmTubGek6M](https://www.youtube.com/watch?v=XxmTubGek6M)
+- π₯ [youtube.com/watch?v=mDIJEyElkAU](https://www.youtube.com/watch?v=mDIJEyElkAU)
+- π₯ [youtube.com/watch?v=SssiPkyKVVs](https://www.youtube.com/watch?v=SssiPkyKVVs)
+- π₯ [youtube.com/watch?v=MAHE_QyHZFQ](https://www.youtube.com/watch?v=MAHE_QyHZFQ)
+- π₯ [youtube.com/watch?v=Uap_6bwtILQ](https://www.youtube.com/watch?v=Uap_6bwtILQ)
-### Download
+For further background information, head to:
+- [Neural Networks](https://www.heise.de/select/make/2021/6/2126410443385102621)
+- [Training Neural Networks](https://www.heise.de/select/make/2022/1/2134114065999161585)
+- [Programming on the ESP32](https://www.heise.de/select/make/2022/2/2204010051597422030)
+
+---
+
+## Download π½
The latest available version can be found on the [Releases page](https://github.com/jomjol/AI-on-the-edge-device/releases).
-### Flashing the ESP32
-Initially you will have to flash the ESP32 via a USB connection. Later updates are possible directly over the air (OTA using WIFI).
+---
+
+## Flashing the ESP32 πΎ
+Initially, you will have to flash the ESP32 via a USB connection. Later updates are possible directly over the air (OTA using Wi-Fi).
There are different ways to flash your ESP32:
-- The prefered way is the [Web Installer and Console](https://jomjol.github.io/AI-on-the-edge-device/index.html) which is a browser-based tool to flash the ESP32 and extract the log over USB:
-![](images/web-installer.png)
+- The preferred way is the [Web Installer and Console](https://jomjol.github.io/AI-on-the-edge-device/index.html), a browser-based tool to flash the ESP32 and extract the log over USB:
+ ![](images/web-installer.png)
- Flash Tool from Espressif
- ESPtool (command-line tool)
See the [documentation](https://jomjol.github.io/AI-on-the-edge-device-docs/Installation/) for more information.
-### Flashing the SD Card
-The SD card can be setup automatically after the firmware got installed. See the [documentation](https://jomjol.github.io/AI-on-the-edge-device-docs/Installation/#remote-setup-using-the-built-in-access-point) for details. For this to work, the SD card must be FAT formated (which is the default on a new SD card).
-Alternatively the SD card still can be setup manually, see the [documentation](https://jomjol.github.io/AI-on-the-edge-device-docs/Installation/#3-sd-card) for details!
+---
+
+## Flashing the SD Card πΎ
+The SD card can be set up automatically after the firmware is installed. See the [documentation](https://jomjol.github.io/AI-on-the-edge-device-docs/Installation/#remote-setup-using-the-built-in-access-point) for details. For this to work, the SD card must be FAT formatted (which is the default on a new SD card).
+
+Alternatively, the SD card can still be set up manually. See the [documentation](https://jomjol.github.io/AI-on-the-edge-device-docs/Installation/#3-sd-card) for details.
+
+---
+
+## Casing π οΈ
+Various 3D-printable housings can be found here:
+- π§ [Water Meter](https://www.thingiverse.com/thing:4573481)
+- β‘ [Power Meter](https://www.thingiverse.com/thing:5028229)
+- π₯ [Gas Meter](https://www.thingiverse.com/thing:5224101)
+- π· [ESP32-cam housing only](https://www.thingiverse.com/thing:4571627)
+
+---
+
+## Donate β
+If you'd like to support the developer with a cup of coffee, you can do so via [PayPal](https://www.paypal.com/donate?hosted_button_id=8TRSVYNYKDSWL).
+
+
+
+
+
+---
+
+## Support π¬
+If you have any technical problems, please search the [discussions](https://github.com/jomjol/AI-on-the-edge-device/discussions). In case you find a bug or have a feature request, please open an [issue](https://github.com/jomjol/AI-on-the-edge-device/issues).
+
+For any other issues, you can contact the developer via email:
+
+
+
+
+---
-## Casing
-Various 3D-printable housing can be found here:
- - https://www.thingiverse.com/thing:4573481 (Water Meter)
- - https://www.thingiverse.com/thing:5028229 (Power Meter)
- - https://www.thingiverse.com/thing:5224101 (Gas Meter)
- - https://www.thingiverse.com/thing:4571627 (ESP32-cam housing only)
+## Changes and History π
+See the [Changelog](Changelog.md) for detailed information.
-## Donate
-If you would like to support the developer with a cup of coffee, you can do that via [PayPal](https://www.paypal.com/donate?hosted_button_id=8TRSVYNYKDSWL).
+---
-
+## Build It Yourself π¨
+See the [Build Instructions](code/README.md) for step-by-step guidance.
-## Support
-If you have any technical problems please search the [discussions](https://github.com/jomjol/AI-on-the-edge-device/discussions). In case you found a ug or have a feature request, please open an [issue](https://github.com/jomjol/AI-on-the-edge-device/issues).
+---
-In other cases you can contact the developer via email:
+## Tools π οΈ
+* Logfile downloader and combiner (Thanks to [reserve85](https://github.com/reserve85))
+ * Files can be found at ['/tools/logfile-tool'](tbd), and how-to instructions are in the [documentation](https://jomjol.github.io/AI-on-the-edge-device-docs/outdated--Gasmeter-Log-Downloader/).
-## Changes and History
-See [Changelog](Changelog.md).
+---
-## Build It Yourself
-See [Build Instructions](code/README.md).
+## Additional Ideas π‘
+There are some ideas and feature requests which are not currently being pursuedβmainly due to capacity constraints on the part of the developers. These features are collected in the [issues](https://github.com/jomjol/AI-on-the-edge-device/issues) and in [FeatureRequest.md](FeatureRequest.md).
-## Tools
-* Logfile downloader and combiner (Thx to [reserve85](https://github.com/reserve85))
- * Files see ['/tools/logfile-tool'](tbd), how-to see [documentation](https://jomjol.github.io/AI-on-the-edge-device-docs/outdated--Gasmeter-Log-Downloader/)
+---
-## Additional Ideas
-There are some ideas and feature requests which are not currently being pursued β mainly due to capacity reasons on the part of the developers.
-They features are collected in the [issues](https://github.com/jomjol/AI-on-the-edge-device/issues) and in [FeatureRequest.md](FeatureRequest.md).
+## Our Contributors β€οΈ
+
+
+
+
diff --git a/code/components/esp32-camera b/code/components/esp32-camera
index dba8da989..0054ab760 160000
--- a/code/components/esp32-camera
+++ b/code/components/esp32-camera
@@ -1 +1 @@
-Subproject commit dba8da9898928d9808d57a0b0cdcde9f130ed8fe
+Subproject commit 0054ab76046d2879ca9682edb2419b0613b06acd
diff --git a/code/components/jomjol_controlcamera/ClassControllCamera.cpp b/code/components/jomjol_controlcamera/ClassControllCamera.cpp
index bd830ed92..fb2ffe91c 100644
--- a/code/components/jomjol_controlcamera/ClassControllCamera.cpp
+++ b/code/components/jomjol_controlcamera/ClassControllCamera.cpp
@@ -122,12 +122,18 @@ esp_err_t CCamera::InitCam(void)
{
ESP_LOGD(TAG, "Init Camera");
+ TickType_t cam_xDelay = 100 / portTICK_PERIOD_MS;
+
CCstatus.ImageQuality = camera_config.jpeg_quality;
CCstatus.ImageFrameSize = camera_config.frame_size;
+ // De-init in case it was already initialized
+ esp_camera_deinit();
+ vTaskDelay(cam_xDelay);
+
// initialize the camera
- esp_camera_deinit(); // De-init in case it was already initialized
esp_err_t err = esp_camera_init(&camera_config);
+ vTaskDelay(cam_xDelay);
if (err != ESP_OK)
{
@@ -280,8 +286,8 @@ esp_err_t CCamera::setSensorDatenFromCCstatus(void)
s->set_dcw(s, CCstatus.ImageDcw); // 0 = disable , 1 = enable
- TickType_t xDelay2 = 100 / portTICK_PERIOD_MS;
- vTaskDelay(xDelay2);
+ TickType_t cam_xDelay = 100 / portTICK_PERIOD_MS;
+ vTaskDelay(cam_xDelay);
return ESP_OK;
}
diff --git a/code/components/jomjol_flowcontroll/ClassFlowMQTT.cpp b/code/components/jomjol_flowcontroll/ClassFlowMQTT.cpp
index b1162f837..d798d3eba 100644
--- a/code/components/jomjol_flowcontroll/ClassFlowMQTT.cpp
+++ b/code/components/jomjol_flowcontroll/ClassFlowMQTT.cpp
@@ -286,7 +286,7 @@ bool ClassFlowMQTT::doFlow(string zwtime)
if (resultchangabs.length() > 0) {
success |= MQTTPublish(namenumber + "changeabsolut", resultchangabs, qos, SetRetainFlag); // Legacy API
- success |= MQTTPublish(namenumber + "rate_per_Digitization_round", resultchangabs, qos, SetRetainFlag);
+ success |= MQTTPublish(namenumber + "rate_per_digitization_round", resultchangabs, qos, SetRetainFlag);
}
if (resultraw.length() > 0)
diff --git a/code/components/jomjol_mqtt/server_mqtt.cpp b/code/components/jomjol_mqtt/server_mqtt.cpp
index adc68e211..fd675a139 100644
--- a/code/components/jomjol_mqtt/server_mqtt.cpp
+++ b/code/components/jomjol_mqtt/server_mqtt.cpp
@@ -188,10 +188,10 @@ bool MQTThomeassistantDiscovery(int qos) {
allSendsSuccessed |= sendHomeAssistantDiscoveryTopic(group, "value", "Value", "gauge", valueUnit, meterType, "total_increasing", "", qos);
allSendsSuccessed |= sendHomeAssistantDiscoveryTopic(group, "raw", "Raw Value", "raw", "", "", "", "diagnostic", qos);
allSendsSuccessed |= sendHomeAssistantDiscoveryTopic(group, "error", "Error", "alert-circle-outline", "", "", "", "diagnostic", qos);
- /* Not announcing "rate" as it is better to use rate_per_time_unit resp. rate_per_Digitization_round */
+ /* Not announcing "rate" as it is better to use rate_per_time_unit resp. rate_per_digitization_round */
// allSendsSuccessed |= sendHomeAssistantDiscoveryTopic(group, "rate", "Rate (Unit/Minute)", "swap-vertical", "", "", "", ""); // Legacy, always Unit per Minute
allSendsSuccessed |= sendHomeAssistantDiscoveryTopic(group, "rate_per_time_unit", "Rate (" + rateUnit + ")", "swap-vertical", rateUnit, "", "measurement", "", qos);
- allSendsSuccessed |= sendHomeAssistantDiscoveryTopic(group, "rate_per_Digitization_round", "Change since last Digitization round", "arrow-expand-vertical", valueUnit, "", "measurement", "", qos); // correctly the Unit is Unit/Interval!
+ allSendsSuccessed |= sendHomeAssistantDiscoveryTopic(group, "rate_per_digitization_round", "Change since last Digitization round", "arrow-expand-vertical", valueUnit, "", "measurement", "", qos); // correctly the Unit is Unit/Interval!
allSendsSuccessed |= sendHomeAssistantDiscoveryTopic(group, "timestamp", "Timestamp", "clock-time-eight-outline", "", "timestamp", "", "diagnostic", qos);
allSendsSuccessed |= sendHomeAssistantDiscoveryTopic(group, "json", "JSON", "code-json", "", "", "", "diagnostic", qos);
allSendsSuccessed |= sendHomeAssistantDiscoveryTopic(group, "problem", "Problem", "alert-outline", "", "problem", "", "", qos); // Special binary sensor which is based on error topic
diff --git a/code/main/main.cpp b/code/main/main.cpp
index 0340e50f6..36e40d207 100644
--- a/code/main/main.cpp
+++ b/code/main/main.cpp
@@ -528,30 +528,44 @@ extern "C" void app_main(void)
}
}
-// FIXME: needs to be revised or removed!!!
void migrateConfiguration(void) {
+ std::vector splitted;
bool migrated = false;
+ bool CamZoom_found = false;
+ int CamZoom_lines = 0;
+ bool CamZoom_value = false;
+ int CamZoomSize_lines = 0;
+ int CamZoomSize_value = 0;
+ int CamZoomOffsetX_lines = 0;
+ int CamZoomOffsetX_value = 0;
+ int CamZoomOffsetY_lines = 0;
+ int CamZoomOffsetY_value = 0;
+
if (!FileExists(CONFIG_FILE)) {
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Config file seems to be missing!");
- return;
+ return;
}
std::string section = "";
- std::ifstream ifs(CONFIG_FILE);
- std::string content((std::istreambuf_iterator(ifs)), (std::istreambuf_iterator()));
-
+ std::ifstream ifs(CONFIG_FILE);
+ std::string content((std::istreambuf_iterator(ifs)), (std::istreambuf_iterator()));
+
/* Split config file it array of lines */
std::vector configLines = splitString(content);
/* Process each line */
for (int i = 0; i < configLines.size(); i++) {
- //ESP_LOGI(TAG, "Line %d: %s", i, configLines[i].c_str());
+ // ESP_LOGI(TAG, "Line %d: %s", i, configLines[i].c_str());
- if (configLines[i].find("[") != std::string::npos) { // Start of new section
+ if (configLines[i].find("[") != std::string::npos) {
+ // Start of new section
section = configLines[i];
replaceString(section, ";", "", false); // Remove possible semicolon (just for the string comparison)
- //ESP_LOGI(TAG, "New section: %s", section.c_str());
+ // ESP_LOGI(TAG, "New section: %s", section.c_str());
+ }
+ else {
+ splitted = ZerlegeZeile(configLines[i]);
}
/* Migrate parameters as needed
@@ -569,119 +583,154 @@ void migrateConfiguration(void) {
}
if (section == "[MakeImage]" || section == "[TakeImage]") {
- migrated = migrated | replaceString(configLines[i], "LogImageLocation", "RawImagesLocation");
- migrated = migrated | replaceString(configLines[i], "LogfileRetentionInDays", "RawImagesRetention");
+ if ((isInString(configLines[i], "Brightness")) && (!isInString(configLines[i], "CamBrightness"))) {
+ migrated = migrated | replaceString(configLines[i], "Brightness", "CamBrightness");
+ }
+ else if ((isInString(configLines[i], "Contrast")) && (!isInString(configLines[i], "CamContrast"))) {
+ migrated = migrated | replaceString(configLines[i], "Contrast", "CamContrast");
+ }
+ else if ((isInString(configLines[i], "Saturation")) && (!isInString(configLines[i], "CamSaturation"))) {
+ migrated = migrated | replaceString(configLines[i], "Saturation", "CamSaturation");
+ }
+ else if ((isInString(configLines[i], "Sharpness")) && (!isInString(configLines[i], "CamSharpness")) && (!isInString(configLines[i], "CamAutoSharpness"))) {
+ migrated = migrated | replaceString(configLines[i], "Sharpness", "CamSharpness");
+ }
+ else if ((isInString(configLines[i], "Aec2")) && (!isInString(configLines[i], "CamAec")) && (!isInString(configLines[i], "CamAec2"))) {
+ migrated = migrated | replaceString(configLines[i], "Aec2", "CamAec2");
+ }
+ else if ((isInString(configLines[i], "Zoom")) && (!isInString(configLines[i], "CamZoom")) && (!isInString(configLines[i], "ZoomMode")) && (!isInString(configLines[i], "ZoomOffsetX")) && (!isInString(configLines[i], "ZoomOffsetY"))) {
+ CamZoom_lines = i;
+ CamZoom_value = alphanumericToBoolean(splitted[1]);
+ CamZoom_found = true;
+ }
+ else if ((isInString(configLines[i], "ZoomMode")) && (!isInString(configLines[i], "CamZoom"))) {
+ CamZoomSize_lines = i;
+ if (isStringNumeric(splitted[1])) {
+ CamZoomSize_value = std::stof(splitted[1]);
+ }
+ CamZoom_found = true;
+ }
+ else if ((isInString(configLines[i], "ZoomOffsetX")) && (!isInString(configLines[i], "CamZoom")) && (!isInString(configLines[i], "ZoomOffsetY"))) {
+ CamZoomOffsetX_lines = i;
+ if (isStringNumeric(splitted[1])) {
+ CamZoomOffsetX_value = std::stof(splitted[1]);
+ }
+ CamZoom_found = true;
+ }
+ else if ((isInString(configLines[i], "ZoomOffsetY")) && (!isInString(configLines[i], "CamZoom")) && (!isInString(configLines[i], "ZoomOffsetX"))) {
+ CamZoomOffsetY_lines = i;
+ if (isStringNumeric(splitted[1])) {
+ CamZoomOffsetY_value = std::stof(splitted[1]);
+ }
+ CamZoom_found = true;
+ }
+ else {
+ migrated = migrated | replaceString(configLines[i], "LogImageLocation", "RawImagesLocation");
+ migrated = migrated | replaceString(configLines[i], "LogfileRetentionInDays", "RawImagesRetention");
- migrated = migrated | replaceString(configLines[i], ";Demo = true", ";Demo = false"); // Set it to its default value
- migrated = migrated | replaceString(configLines[i], ";Demo", "Demo"); // Enable it
+ migrated = migrated | replaceString(configLines[i], ";Demo = true", ";Demo = false"); // Set it to its default value
+ migrated = migrated | replaceString(configLines[i], ";Demo", "Demo"); // Enable it
- // Parameter is no longer used
- // migrated = migrated | replaceString(configLines[i], ";FixedExposure = true", ";FixedExposure = false"); // Set it to its default value
- // migrated = migrated | replaceString(configLines[i], ";FixedExposure", "FixedExposure"); // Enable it
- }
+ migrated = migrated | replaceString(configLines[i], "ImageQuality", "CamQuality");
+ migrated = migrated | replaceString(configLines[i], "AutoExposureLevel", "CamAeLevel");
+ migrated = migrated | replaceString(configLines[i], "FixedExposure", "CamAec");
- if (section == "[Alignment]") {
- // Parameter is no longer used
- // migrated = migrated | replaceString(configLines[i], ";InitialMirror = true", ";InitialMirror = false"); // Set it to its default value
- // migrated = migrated | replaceString(configLines[i], ";InitialMirror", "InitialMirror"); // Enable it
-
- // Parameter is no longer used
- // migrated = migrated | replaceString(configLines[i], ";FlipImageSize = true", ";FlipImageSize = false"); // Set it to its default value
- // migrated = migrated | replaceString(configLines[i], ";FlipImageSize", "FlipImageSize"); // Enable it
+ migrated = migrated | replaceString(configLines[i], "ImageSize", ";UNUSED_PARAMETER"); // This parameter is no longer used
+ migrated = migrated | replaceString(configLines[i], "Grayscale", ";UNUSED_PARAMETER"); // This parameter is no longer used
+ migrated = migrated | replaceString(configLines[i], "Negative", ";UNUSED_PARAMETER"); // This parameter is no longer used
+ }
}
-
- if (section == "[Digits]") {
+ else if (section == "[Alignment]") {
+ migrated = migrated | replaceString(configLines[i], "InitialMirror", ";UNUSED_PARAMETER"); // This parameter is no longer used
+ migrated = migrated | replaceString(configLines[i], ";InitialMirror", ";UNUSED_PARAMETER"); // This parameter is no longer used
+ migrated = migrated | replaceString(configLines[i], "FlipImageSize", ";UNUSED_PARAMETER"); // This parameter is no longer used
+ migrated = migrated | replaceString(configLines[i], ";FlipImageSize", ";UNUSED_PARAMETER"); // This parameter is no longer used
+ }
+ else if (section == "[Digits]") {
migrated = migrated | replaceString(configLines[i], "LogImageLocation", "ROIImagesLocation");
migrated = migrated | replaceString(configLines[i], "LogfileRetentionInDays", "ROIImagesRetention");
}
-
- if (section == "[Analog]") {
+ else if (section == "[Analog]") {
migrated = migrated | replaceString(configLines[i], "LogImageLocation", "ROIImagesLocation");
migrated = migrated | replaceString(configLines[i], "LogfileRetentionInDays", "ROIImagesRetention");
migrated = migrated | replaceString(configLines[i], "ExtendedResolution", ";UNUSED_PARAMETER"); // This parameter is no longer used
}
-
- if (section == "[PostProcessing]") {
- migrated = migrated | replaceString(configLines[i], "AnalogDigitalTransitionStart", "AnalogToDigitTransitionStart"); // Rename it
- migrated = migrated | replaceString(configLines[i], ";PreValueUse = true", ";PreValueUse = false"); // Set it to its default value
- migrated = migrated | replaceString(configLines[i], ";PreValueUse", "PreValueUse"); // Enable it
-
+ else if (section == "[PostProcessing]") {
/* AllowNegativeRates has a as prefix! */
- if (isInString(configLines[i], "AllowNegativeRates") && isInString(configLines[i], ";")) { // It is the parameter "AllowNegativeRates" and it is commented out
+ if (isInString(configLines[i], "AllowNegativeRates") && isInString(configLines[i], ";")) {
+ // It is the parameter "AllowNegativeRates" and it is commented out
migrated = migrated | replaceString(configLines[i], "true", "false"); // Set it to its default value
- migrated = migrated | replaceString(configLines[i], ";", ""); // Enable it
+ migrated = migrated | replaceString(configLines[i], ";", ""); // Enable it
}
-
/* IgnoreLeadingNaN has a as prefix! */
- if (isInString(configLines[i], "IgnoreLeadingNaN") && isInString(configLines[i], ";")) { // It is the parameter "IgnoreLeadingNaN" and it is commented out
+ else if (isInString(configLines[i], "IgnoreLeadingNaN") && isInString(configLines[i], ";")) {
+ // It is the parameter "IgnoreLeadingNaN" and it is commented out
migrated = migrated | replaceString(configLines[i], "true", "false"); // Set it to its default value
- migrated = migrated | replaceString(configLines[i], ";", ""); // Enable it
+ migrated = migrated | replaceString(configLines[i], ";", ""); // Enable it
}
-
/* ExtendedResolution has a as prefix! */
- if (isInString(configLines[i], "ExtendedResolution") && isInString(configLines[i], ";")) { // It is the parameter "ExtendedResolution" and it is commented out
+ else if (isInString(configLines[i], "ExtendedResolution") && isInString(configLines[i], ";")) {
+ // It is the parameter "ExtendedResolution" and it is commented out
migrated = migrated | replaceString(configLines[i], "true", "false"); // Set it to its default value
- migrated = migrated | replaceString(configLines[i], ";", ""); // Enable it
+ migrated = migrated | replaceString(configLines[i], ";", ""); // Enable it
}
+ else {
+ migrated = migrated | replaceString(configLines[i], ";PreValueUse = true", ";PreValueUse = false"); // Set it to its default value
+ migrated = migrated | replaceString(configLines[i], ";PreValueUse", "PreValueUse"); // Enable it
- migrated = migrated | replaceString(configLines[i], ";ErrorMessage = true", ";ErrorMessage = false"); // Set it to its default value
- migrated = migrated | replaceString(configLines[i], ";ErrorMessage", "ErrorMessage"); // Enable it
+ migrated = migrated | replaceString(configLines[i], ";ErrorMessage = true", ";ErrorMessage = false"); // Set it to its default value
+ migrated = migrated | replaceString(configLines[i], ";ErrorMessage", "ErrorMessage"); // Enable it
- migrated = migrated | replaceString(configLines[i], ";CheckDigitIncreaseConsistency = true", ";CheckDigitIncreaseConsistency = false"); // Set it to its default value
- migrated = migrated | replaceString(configLines[i], ";CheckDigitIncreaseConsistency", "CheckDigitIncreaseConsistency"); // Enable it
+ migrated = migrated | replaceString(configLines[i], ";CheckDigitIncreaseConsistency = true", ";CheckDigitIncreaseConsistency = false"); // Set it to its default value
+ migrated = migrated | replaceString(configLines[i], ";CheckDigitIncreaseConsistency", "CheckDigitIncreaseConsistency"); // Enable it
+ }
}
-
- if (section == "[MQTT]") {
- migrated = migrated | replaceString(configLines[i], "SetRetainFlag", "RetainMessages"); // First rename it, enable it with its default value
+ else if (section == "[MQTT]") {
+ migrated = migrated | replaceString(configLines[i], "SetRetainFlag", "RetainMessages"); // First rename it, enable it with its default value
migrated = migrated | replaceString(configLines[i], ";RetainMessages = true", ";RetainMessages = false"); // Set it to its default value
- migrated = migrated | replaceString(configLines[i], ";RetainMessages", "RetainMessages"); // Enable it
+ migrated = migrated | replaceString(configLines[i], ";RetainMessages", "RetainMessages"); // Enable it
migrated = migrated | replaceString(configLines[i], ";HomeassistantDiscovery = true", ";HomeassistantDiscovery = false"); // Set it to its default value
- migrated = migrated | replaceString(configLines[i], ";HomeassistantDiscovery", "HomeassistantDiscovery"); // Enable it
+ migrated = migrated | replaceString(configLines[i], ";HomeassistantDiscovery", "HomeassistantDiscovery"); // Enable it
- if (configLines[i].rfind("Topic", 0) != std::string::npos) // only if string starts with "Topic" (Was the naming in very old version)
- {
+ // only if string starts with "Topic" (Was the naming in very old version)
+ if (configLines[i].rfind("Topic", 0) != std::string::npos) {
migrated = migrated | replaceString(configLines[i], "Topic", "MainTopic");
}
}
-
- if (section == "[InfluxDB]") {
+ else if (section == "[InfluxDB]") {
/* Fieldname has a as prefix! */
- if (isInString(configLines[i], "Fieldname")) { // It is the parameter "Fieldname"
+ if (isInString(configLines[i], "Fieldname")) {
+ // It is the parameter "Fieldname"
migrated = migrated | replaceString(configLines[i], "Fieldname", "Field"); // Rename it to Field
}
}
-
- if (section == "[InfluxDBv2]") {
+ else if (section == "[InfluxDBv2]") {
/* Fieldname has a as prefix! */
- if (isInString(configLines[i], "Fieldname")) { // It is the parameter "Fieldname"
+ if (isInString(configLines[i], "Fieldname")) {
+ // It is the parameter "Fieldname"
migrated = migrated | replaceString(configLines[i], "Fieldname", "Field"); // Rename it to Field
}
/* Database got renamed to Bucket! */
- if (isInString(configLines[i], "Database")) { // It is the parameter "Database"
+ else if (isInString(configLines[i], "Database")) {
+ // It is the parameter "Database"
migrated = migrated | replaceString(configLines[i], "Database", "Bucket"); // Rename it to Bucket
}
}
-
- if (section == "[GPIO]") {
-
+ else if (section == "[GPIO]") {
}
-
- if (section == "[DataLogging]") {
+ else if (section == "[DataLogging]") {
migrated = migrated | replaceString(configLines[i], "DataLogRetentionInDays", "DataFilesRetention");
/* DataLogActive is true by default! */
migrated = migrated | replaceString(configLines[i], ";DataLogActive = false", ";DataLogActive = true"); // Set it to its default value
- migrated = migrated | replaceString(configLines[i], ";DataLogActive", "DataLogActive"); // Enable it
+ migrated = migrated | replaceString(configLines[i], ";DataLogActive", "DataLogActive"); // Enable it
}
-
- if (section == "[AutoTimer]") {
+ else if (section == "[AutoTimer]") {
migrated = migrated | replaceString(configLines[i], "Intervall", "Interval");
migrated = migrated | replaceString(configLines[i], ";AutoStart = true", ";AutoStart = false"); // Set it to its default value
- migrated = migrated | replaceString(configLines[i], ";AutoStart", "AutoStart"); // Enable it
-
+ migrated = migrated | replaceString(configLines[i], ";AutoStart", "AutoStart"); // Enable it
}
-
- if (section == "[Debug]") {
+ else if (section == "[Debug]") {
migrated = migrated | replaceString(configLines[i], "Logfile ", "LogLevel "); // Whitespace needed so it does not match `LogfileRetentionInDays`
/* LogLevel (resp. LogFile) was originally a boolean, but we switched it to an int
* For both cases (true/false), we set it to level 2 (WARNING) */
@@ -689,27 +738,102 @@ void migrateConfiguration(void) {
migrated = migrated | replaceString(configLines[i], "LogLevel = false", "LogLevel = 2");
migrated = migrated | replaceString(configLines[i], "LogfileRetentionInDays", "LogfilesRetention");
}
-
- if (section == "[System]") {
+ else if (section == "[System]") {
migrated = migrated | replaceString(configLines[i], "RSSIThreashold", "RSSIThreshold");
migrated = migrated | replaceString(configLines[i], "AutoAdjustSummertime", ";UNUSED_PARAMETER"); // This parameter is no longer used
migrated = migrated | replaceString(configLines[i], ";SetupMode = true", ";SetupMode = false"); // Set it to its default value
- migrated = migrated | replaceString(configLines[i], ";SetupMode", "SetupMode"); // Enable it
+ migrated = migrated | replaceString(configLines[i], ";SetupMode", "SetupMode"); // Enable it
}
}
- if (migrated) { // At least one replacement happened
- if (! RenameFile(CONFIG_FILE, CONFIG_FILE_BACKUP)) {
+ if (CamZoom_found == true) {
+ if (CamZoomSize_value == 0) {
+ // mode0
+ // 1600 - 640 = 960 / 2 = max-Offset (+/-) 480
+ // 1200 - 480 = 720 / 2 = max-Offset (+/-) 360
+
+ if (CamZoomOffsetX_value > 960) {
+ CamZoomOffsetX_value = 960;
+ }
+ else {
+ CamZoomOffsetX_value = (floor((CamZoomOffsetX_value - 480) / 8) * 8);
+ }
+
+ if (CamZoomOffsetY_value > 720) {
+ CamZoomOffsetY_value = 720;
+ }
+ else {
+ CamZoomOffsetY_value = (floor((CamZoomOffsetY_value - 360) / 8) * 8);
+ }
+
+ CamZoomSize_value = 29;
+ }
+ else {
+ // mode1
+ // 800 - 640 = 160 / 2 = max-Offset (+/-) 80
+ // 600 - 480 = 120 / 2 = max-Offset (+/-) 60
+
+ if (CamZoomOffsetX_value > 160) {
+ CamZoomOffsetX_value = 160;
+ }
+ else {
+ CamZoomOffsetX_value = (floor(((CamZoomOffsetX_value - 80) * 2) / 8) * 8);
+ }
+
+ if (CamZoomOffsetY_value > 120) {
+ CamZoomOffsetY_value = 120;
+ }
+ else {
+ CamZoomOffsetY_value = (floor(((CamZoomOffsetY_value - 60) * 2) / 8) * 8);
+ }
+
+ CamZoomSize_value = 9;
+ }
+
+ if (CamZoom_lines > 0) {
+ if (CamZoom_value) {
+ configLines[CamZoom_lines] = ("CamZoom = true");
+ }
+ else {
+ configLines[CamZoom_lines] = ("CamZoom = false");
+ }
+ LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Migrated Configfile line 'Zoom' to 'CamZoom'");
+ migrated = true;
+ }
+ if (CamZoomSize_lines > 0) {
+ configLines[CamZoomSize_lines] = ("CamZoomSize = " + std::to_string(CamZoomSize_value));
+ LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Migrated Configfile line 'ZoomMode' to 'CamZoomSize'");
+ migrated = true;
+ }
+ if (CamZoomOffsetX_lines > 0) {
+ configLines[CamZoomOffsetX_lines] = ("CamZoomOffsetX = " + std::to_string(CamZoomOffsetX_value));
+ LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Migrated Configfile line 'ZoomOffsetX' to 'CamZoomOffsetX'");
+ migrated = true;
+ }
+ if (CamZoomOffsetY_lines > 0) {
+ configLines[CamZoomOffsetY_lines] = ("CamZoomOffsetY = " + std::to_string(CamZoomOffsetY_value));
+ LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Migrated Configfile line 'ZoomOffsetY' to 'CamZoomOffsetY'");
+ migrated = true;
+ }
+ }
+
+ if (migrated) {
+ // At least one replacement happened
+ if (!RenameFile(CONFIG_FILE, CONFIG_FILE_BACKUP)) {
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Failed to create backup of Config file!");
return;
}
- FILE* pfile = fopen(CONFIG_FILE, "w");
+ FILE *pfile = fopen(CONFIG_FILE, "w");
+
for (int i = 0; i < configLines.size(); i++) {
- fwrite(configLines[i].c_str() , configLines[i].length(), 1, pfile);
- fwrite("\n" , 1, 1, pfile);
+ if (!isInString(configLines[i], ";UNUSED_PARAMETER")) {
+ fwrite(configLines[i].c_str(), configLines[i].length(), 1, pfile);
+ fwrite("\n", 1, 1, pfile);
+ }
}
+
fclose(pfile);
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Config file migrated. Saved backup to " + string(CONFIG_FILE_BACKUP));
}
diff --git a/code/main/softAP.cpp b/code/main/softAP.cpp
index 07a4506dd..fe903fd11 100644
--- a/code/main/softAP.cpp
+++ b/code/main/softAP.cpp
@@ -98,8 +98,8 @@ void wifi_init_softAP(void)
void SendHTTPResponse(httpd_req_t *req)
{
std::string message = "
AI-on-the-edge - BASIC SETUP
This is an access point with a minimal server to setup the minimum required files and information on the device and the SD-card. ";
- message += "This mode is always startet if one of the following files is missing: /wlan.ini or the /config/config.ini.
";
- message += "The setup is done in 3 steps: 1. upload full inital configuration (sd-card content), 2. store WLAN acces information, 3. reboot (and connect to WLANs)
";
+ message += "This mode is always started if one of the following files is missing: /wlan.ini or the /config/config.ini.
";
+ message += "The setup is done in 3 steps: 1. upload full inital configuration (sd-card content), 2. store WLAN access information, 3. reboot (and connect to WLANs)
";
message += "Please follow the below instructions.
";
message += "The configuration file config.ini is missing and most propably the full configuration and html folder on the sd-card. ";
- message += "This is normal after the first flashing of the firmware and an empty sd-card. Please upload \"remote_setup.zip\", which contains an full inital configuration.
";
+ message += "This is normal after the first flashing of the firmware and an empty sd-card. Please upload \"remote_setup.zip\", which contains a full inital configuration.
";
message += " ";
message += "
";
message += "The upload might take up to 60s. After a succesfull upload the page will be updated.";
@@ -135,7 +135,7 @@ void SendHTTPResponse(httpd_req_t *req)
message += "
WLAN-SSID
SSID of the WLAN
";
message += "
WLAN-Password
ATTENTION: the password will not be encrypted during the sending.
";
message += "
";
- message += "
ATTENTION:
Be sure about the WLAN settings. They cannot be reseted afterwards. If ssid or password is wrong, you need to take out the sd-card and manually change them in \"wlan.ini\"!
";
+ message += "
ATTENTION:
Be sure about the WLAN settings. They cannot be reset afterwards. If ssid or password is wrong, you need to take out the sd-card and manually change them in \"wlan.ini\"!