diff --git a/img/ana-class100.png b/img/ana-class100.png
index f7b7a9e..08111f3 100644
Binary files a/img/ana-class100.png and b/img/ana-class100.png differ
diff --git a/img/dig-class100.png b/img/dig-class100.png
index c7b5041..81a3920 100644
Binary files a/img/dig-class100.png and b/img/dig-class100.png differ
diff --git a/img/dig-class11.png b/img/dig-class11.png
index 3b7d3de..510c5cf 100644
Binary files a/img/dig-class11.png and b/img/dig-class11.png differ
diff --git a/search/search_index.json b/search/search_index.json
index 19c8814..ec94074 100644
--- a/search/search_index.json
+++ b/search/search_index.json
@@ -1 +1 @@
-{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"]},"docs":[{"location":"","title":"Welcome","text":"Welcome to the AI-on-the-edge-device project!
This is the documentation. For the source code, please head to github.com/jomjol/AI-on-the-edge-device.
Artificial intelligence based systems have been 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 up there. With the increasing power of modern processors the AI systems are coming closer to the end user - which is usually called edge computing. Here this edge computing is brought into a practice-oriented example, where a AI network is implemented on a ESP32 device so: AI on the edge.
"},{"location":"#key-features","title":"Key features","text":" - Tensorflow Lite (TFlite) integration - including easy to use wrapper
- Inline image processing (feature detection, alignment, ROI extraction)
- Small and cheap device (3x4.5x2 cm\u00b3, < 10 EUR)
- Camera and illumination integrated
- Web surface to administrate and control
- OTA-Interface to update directly through the web interface
- Full integration into Home Assistant
- Support for Influx DB 1 and 2
- MQTT
- REST API
"},{"location":"#idea","title":"Idea","text":""},{"location":"#hardware","title":"Hardware","text":""},{"location":"#web-interface","title":"Web interface","text":""},{"location":"#configuration-interface","title":"Configuration Interface","text":"Have fun in studying the new possibilities and ideas
This is about image recognition and digitization, done totally on a cheap ESP32 board using artificial intelligence in form of convolutional neural networks (CNN). Everything, from image capture (OV2640), image preprocessing (auto alignment, ROI identification) all the way down to the image recognition (CNN structure) and result plausibility is done on a cheap 10 EUR device.
This all is integrated in an easy to do setup and use environment, taking care for all the background processing and handling, including regular job scheduler. The user interface is an integrated web server, that can be easily adjusted and offers the data as an API in different options.
The task to be demonstrated here is an automated readout of an analog water meter. The water consumption is to be recorded within a house automatization and the water meter is totally analog without any electronic interface. Therefore, the task is solved by regularly taking an image of the water meter and digitizing the reading.
There are two types of CNN implemented, a classification network for reading the digit numbers and a single output network for digitize the analog pointers for the sub digit readings.
This project is an evolution of the water-meter-system-complete, which uses ESP32-CAM just for taking the image and a 1GB-Docker image to run the neural network's backbone. Here everything is integrated in an ESP32-CAM module with 8MB of RAM and a SD card as data storage.
"},{"location":"#additional-tutorials","title":"Additional Tutorials","text":"A lot of people created useful Youtube videos which might help you getting started. Here a small selection:
- youtube.com/watch?v=HKBofb1cnNc
- youtube.com/watch?v=yyf0ORNLCk4
- youtube.com/watch?v=XxmTubGek6M
- youtube.com/watch?v=mDIJEyElkAU
- youtube.com/watch?v=SssiPkyKVVs
- youtube.com/watch?v=MAHE_QyHZFQ
- youtube.com/watch?v=Uap_6bwtILQ
"},{"location":"Additional-Information/","title":"Additional Information","text":"The following links point to additional information in other repos:
"},{"location":"Additional-Information/#digits","title":"Digits","text":" - Training the CNN neural network
- Training and using a neural network to readout the value of a digit counter
"},{"location":"Additional-Information/#analog","title":"Analog","text":" - Training and using a neural network to read out the value of an analog display
- Training the CNN neural network
"},{"location":"Alignment/","title":"Alignment References","text":"The alignment references are used in every round to re-align the taken image to the reference coordinates. Two alignment structures must be defined and the taken image then in each round is shifted and rotated according to their position with the target to be in exactly the same position as the reference image.
Note
The alignment structures needs to be unique and have a good contrast. It is advised to have them as far apart as possible.
"},{"location":"Alignment/#precondition","title":"Precondition","text":"Please make sure to have setup your camera properly and taken a good Reference Image.
"},{"location":"Alignment/#define-two-reference-images","title":"Define two Reference Images","text":"You can switch between this two marks with (1).
Then define the reference area in the image by either directly drag and drop with the mouse or use the input boxes below. To apply the currently marked image part you need to push \"Update Reference\" (2).
In some cases it might be useful to use a reference with a higher contrast. This can be achieved by pushing Enhance Contrast\" (3). The result will be calculated on the ESP32 - so be a bit patient, before you see it active.
To save push \"Save to config.ini\" (4).
Note
A reboot is not required at this point of time.
As next you should define the Digit and Analog ROIs.
"},{"location":"Best-Practice/","title":"Best Practice","text":"This page shows some best practices:
"},{"location":"Best-Practice/#camera-placement","title":"Camera Placement","text":" - Move the Camera as close as possible (~4cm), this will help get rid of reflections. -> focus can be adjusted by turning the outer black ring of the camera.
- If the LED reflections are too strong, put tape over the LED to diffuse the light
- Change the ImageSize to QVGA under \"Expert mode\" configuration when close enough, this will be faster and is often good enough for digit recognition.
"},{"location":"Best-Practice/#reflections","title":"Reflections","text":" - Try to get rid of the reflections by rotating the camera, so that the reflections are at positions, where no number is.
- By using the external LED option, you can place WS2812 LEDs freely away from the main axis.
- Users report, that a handy cover foil could also help
"},{"location":"Best-Practice/#post-processing","title":"Post-processing","text":" - Filter out the Number \"9\", as \"3\" will often be misread for a \"9\" and void every number between 3 and 9 due to it being negative flow.
- Split the readings into two, while the decimal numbers might move to fast to be recognized, at least the slower moving part will produce a correct reading. -> keep in mind that the offset needs to be adjusted, a.e if you have a comma reading of \"3\", it needs to become \"0.3\". This can be done wherever the data ends up being sent, like home assistant using sensor templates.
- If you are using a low resolution and only digit mode, processing can often be done in <1 minute. Check the logs to confirm how fast it is and then set the interval accordingly under \"Expert mode\" in configuration, as the normal mode will lock you to 3+ minutes.
"},{"location":"Build-Instructions/","title":"Build the Project","text":"See README.md in the main repo.
"},{"location":"Choosing-the-Model/","title":"Model Selection","text":"Notes
See Neural Network Types for additional details.
In the Graphical Configuration Page, you can choose different models depending on your needs.
This page tries to help you on which model to select. For more technical/deeper explanations have a look on Neural-Network-Types.
"},{"location":"Choosing-the-Model/#digit-models","title":"Digit Models","text":"For digits on water meters, gas-meters or power meters you can select between two main types of models.
"},{"location":"Choosing-the-Model/#dig-class11","title":"dig-class11","text":"This model can recognize full digits. It was the first model version. All intermediate states shown a \"N\" for not a number. But in post process it uses older values to fill up the \"N\" values if possible.
It's possibly a good fallback, if dig-cont/dig-class100 results are not good.
"},{"location":"Choosing-the-Model/#main-features","title":"Main features","text":" - well suited for LCD digits
- the ExtendedResolution option is not supported. (Only in conjunction with ana-class100 / ana-cont)
"},{"location":"Choosing-the-Model/#dig-class100-dig-cont","title":"dig-class100 / dig-cont","text":"These models are used to get a continuous reading with intermediate states. To see what the models are doing, you can go to the Recognition page.
"},{"location":"Choosing-the-Model/#main-features_1","title":"Main features","text":" - suitable for all digit displays.
- Advantage over dig-class11 that results continue to be calculated in the transition between digits.
- With the ExtendedResolution option, higher accuracy is possible by adding another digit.
Look here for a list of digit images used for the training.
"},{"location":"Choosing-the-Model/#dig-class100-vs-dig-cont","title":"dig-class100 vs. dig-cont","text":"The difference is in the internal processing.
The dig-class100 is a standard classification model. Each tenth step is an output.
dig-cont uses two outputs and arctangent to get the result. You see very complicated.
Try both models on your device and take the one that gives you the best results.
"},{"location":"Choosing-the-Model/#analog-pointer-models","title":"Analog pointer models","text":""},{"location":"Choosing-the-Model/#ana-class100-ana-cont","title":"ana-class100 / ana-cont","text":"For pointers on water meters use the analog models. You can only choose between ana-class100 and ana-cont. Both do mainly the same.
"},{"location":"Choosing-the-Model/#main-features_2","title":"Main features","text":" - for all analogue pointers, especially for water meters.
- With the ExtendedResolution option, higher accuracy is possible by adding another digit.
Look here for a list of pointer images used for the training
"},{"location":"Choosing-the-Model/#ana-class100-vs-ana-cont","title":"ana-class100 vs. ana-cont","text":"The difference is in the internal processing.
Take the one that gives you the best results. Both models learn from the same data.
"},{"location":"Choosing-the-Model/#different-types-of-models-normal-vs-quantized","title":"Different types of models (normal vs. quantized)","text":"The normally trained network is calculating with internal floating point numbers. The saving of floating point numbers naturally takes more space than an integer type. Often the increased accuracy is not needed. Therefore there is the option, to \"quantize\" a neural network. In this case the internal values are rescaled to integer values, which is called \"quantization\". The stored tflite files are usually much smaller and runs faster on the edgeAI-device. Usually the models are distrusted therefore in both versions. They can be distinguished by a \"-q\" at the end of the logfile.
"},{"location":"Choosing-the-Model/#example","title":"Example:","text":"Type Name Normal dig-cont_0610_s3.tflite Quantized dig-cont_0610_s3-q.tflite"},{"location":"Configuration/","title":"Graphical Configuration","text":"Most of the settings can be modified on the Settings page:
It can be reached via the menu Settings > Configuration.
Note
- To activate the changes, the device needs to be restarted after saving the changes.
- Most of the commands need processing on the ESP32 device. This is not very fast - so please be patient.
All parameters are documented on the Parameters page and as tooltips on the config page.
"},{"location":"Configuration/#expert-parameters","title":"Expert Parameters","text":"Some parameters are treated as Expert Parameters and are hidden by default. Tick the checkbox in the top left corner to enable them:
The Expert Parameters then will be shown with a red background:
"},{"location":"Configuration/#manual-editing-of-the-config-file","title":"Manual Editing of the Config File","text":"Even more configuration parameters can be edited manually in the config.ini:
To edit the config.ini file directly, click on the Edit Config.ini directly button.
"},{"location":"Configuration/#background-information","title":"Background Information","text":"Note
You do not need to understand this! But you might be interested in it.
The principle is very simple and can most easily be described as a flow of processing steps. Each step has a dedicated parameter description in the config.ini, which is indicated by brackets [name_of_step]. The steps are processed in the order written in the config file. That means, that you first have to describe the image taking, then the aligning and cutting and only after that you can start to config a neural network. The last step is the post processing.
"},{"location":"Configuration/#processing-steps-overview","title":"Processing steps - Overview","text":"In the following you get a short overview over the available steps. This order is also the suggested order for the processing flow. Single steps can be left out, if not needed (e.g. omit the analog part, if only digits are present)
"},{"location":"Configuration/#1-takeimage","title":"1. [TakeImage]","text":"This steps parametrises the taking of the image by the ESP32-CAM. Size, quality and storage for logging and debugging can be set.
"},{"location":"Configuration/#2-alignment","title":"2. [Alignment]","text":"Image preprocessing, including image alignment with reference images
"},{"location":"Configuration/#3-digits","title":"3. [Digits]","text":"Neural network evaluation of an image for digits. The neural network is defined by a tflite formatted file and the output is a number between 0 .. 9 or NaN (if image is not unique enough)
"},{"location":"Configuration/#4-analog","title":"4. [Analog]","text":"Neural network evaluation of analog counter. The neural network is defined by a tflite formatted file and the output is a number between 0.0 .. 9.9, representing the position of the pointer.
"},{"location":"Configuration/#5-postprocessing","title":"5. [PostProcessing]","text":"Summarized the individually converted pictures to the overall result. It also implements some error corrections and consistency checks to filter wrong reading.
For more details look at Correction Algorithm).
"},{"location":"Configuration/#6-mqtt","title":"6. [MQTT]","text":"Transfer of the readings to a MQTT server.
"},{"location":"Configuration/#7-autotimer","title":"7. [AutoTimer]","text":"Configuration of the automated flow start at the start up of the ESP32.
"},{"location":"Configuration/#8-debug","title":"8. [Debug]","text":"Configuration for debugging details
"},{"location":"Correction%20Algorithm/","title":"Correction Algorithm","text":"After the digitization of the images and the composition to a number a checking and correction algorithm is applied. This is explained here.
There are several reasons, that a check might be necessary:
- In case of digits there is the output of \"N\" (=NaN = Not-a-Number) in case the digit cannot be detected correctly. This happens for example if the image shows a digit between to states
- The replacement of the \"N\" with a previous value could be not sufficient, due to the fact, that it might have changed.
- There is a misreading of one one of the numbers. This can always happen in case of neural network processing.
"},{"location":"Correction%20Algorithm/#terms-and-definitions","title":"Terms and definitions","text":""},{"location":"Correction%20Algorithm/#prevalue","title":"PreValue","text":"The last correct read value. PreValue is here a bit missleading, because normally it is the same as the last value. In the next round of reading it will be used to check nagtive rates, high rates (MaxRateValue / MaxRateType) and CCheckDigitIncreaseConsistency (dig-class11 only). Either from a previous correctly identified value or manual setting by the user.
"},{"location":"Correction%20Algorithm/#digits","title":"Digits","text":"Value that are digitized from a digit number. There are 11 allowed values for this:
- Digits: 0, 1, 2, ... 9
- N = Not-a-Number - representing a not unique state between two numbers
"},{"location":"Correction%20Algorithm/#analogs","title":"Analogs","text":"This are value derived from a pointer like meter. This never has the state \"N\".
"},{"location":"Correction%20Algorithm/#checkdigitincreaseconsistency","title":"CheckDigitIncreaseConsistency","text":"If this is enabled an \"intelligent\" algorithm is used to derive from zero-crossing of discrete digit positions, if the number should have been increased. This is relevant because in some of the digit meters, the increase of a digit to the next number can be seen, before the sub-digit has gone through zero.
For example: 16.6 --> 16.7 --> 1N.8 --> 17.9 corrected to 16.9 --> 17.0 --> 17.1
As you can see, the 17.9 is a false reading as the 7 is assumed to be already readable, although the sub-digit has not crossed the zero. In this case the CheckDigitIncreaseConsistency algorithm will correct this to 16.9
A detailed description of the algorithm can be found below (not yet ready!)
"},{"location":"Correction%20Algorithm/#allownegativerates","title":"AllowNegativeRates","text":"Most of the meters only have increasing numbers and do not count backwards. Therefore a negative rate (= negative change compared to the PreValue) is surely a false value. This can be checked an flagged as false reading
The AllowNegativeRates property ensures that the result does not become negative in the event of incorrect readings. This can happen, for example, if the alignment of the image did not work properly. But also the neural networks sometimes flip between two states for similar images.
If AllowNegativeRates = true, the result is discarded if it is smaller than the pre-value of the last readout and the output shows an error \"Negative rate..\"
If the ExtendedResolution setting is true, there is an exception where the value does not become smaller, but no error is output. This only applies if the value +/- 0.2 of the last digit is inaccurate.
"},{"location":"Correction%20Algorithm/#decimalshift","title":"DecimalShift","text":"The DecimalShift setting puts the decimal point in the right place. It acts like a shift. Negative values shift the decimal point to the left. Positive values move the decimal point to the right, filling with zero.
"},{"location":"Correction%20Algorithm/#analogtodigittransitionstart","title":"AnalogToDigitTransitionStart","text":"For detailed description see Analog-digit-transition.
"},{"location":"Correction%20Algorithm/#maxratevalue-and-maxratetype","title":"MaxRateValue and MaxRateType","text":"Here the maximum change from one to the next reading can be limited. If a false reading of the neural network results in a change larger than this, the reading is flagged as false. There a two types of comparisons possible
1) AbsolutChange: Here the difference between the PreValue and the current reading is compared directly, independent how much time has passed since the last reading. 2) RelativeRate: in this case a change rate in the unit of change/minute is calculated, taking the time between the last and the current reading into account. Be careful, that with increasing time, the absolute allowed change increases. Example: relative rate of 0.05 m\u00b3/minute --> after 20 minutes a maximum change of 20 minutes * 0.05 m\u00b3/minute = 1 m\u00b3 is possible. That means that a false reading of 1 m\u00b3 cannot be detected false after about 20 minutes in this case Assume, that there might be no change in the meter for hours (e.g. during the night) a much bigger change could also be accepted.
"},{"location":"Correction%20Algorithm/#extendedresolution","title":"ExtendedResolution","text":"Newer models such as dig-cont and dig-class100 have a high resolution of the values and can thus represent another digit by using the value of the last digit or pointer (ex. 7.8 in the last digit).
If the value is set to true, the result of the last digit is used completely.
When using dig-class11 models, the setting is ignored.
Due to inaccuracies of the neural networks, it sometimes happens that the results jump back and forth between two decimal places. Therefore, when using \u00c0llowNegatives= false, no error is output if the value is only off by 0.2. Nevertheless, the value then remains at the higher determined value.
"},{"location":"Correction%20Algorithm/#ignoreleadingnan","title":"IgnoreLeadingNaN","text":"The parameter is only be used, if a dig-class11 model is selected. \u00ccgnoreLeadingNaN removes in the CheckDigitIncreaseConsistency process the leading N values.
"},{"location":"Correction%20Algorithm/#flow-chart","title":"Flow Chart","text":""},{"location":"Correction%20Algorithm/#checkdigitincreaseconsistency-algorithm","title":"CheckDigitIncreaseConsistency Algorithm","text":"The check digit increase consistency algorithm is functional for the digits only. Due to the fact, that the rotation might be a little bit earlier or later compared to the zero crossing of the digit before, errors during the reading before and after a zero crossing can be wrong. Therefore a simple algorithm can be applied, checking the consistency of zero crossing and changes in the following digit. This is applied to one after the other digit, starting with the lowest priority digits.
"},{"location":"Demo-Mode/","title":"Demo Mode","text":"For Demo and Testing Purpose, the device can use pre-recorded raw images.
You need to enable it in the configuration (TakeImage > Demo) and also provide the needed files on the SD card.
For each round one image gets used, starting with the first image for the first round.
For the reference image and the alignment also the first image gets used.
Once the last image got reached, it starts again with the first one.
"},{"location":"Demo-Mode/#sd-card-structure","title":"SD Card Structure","text":"demo/\n\u251c\u2500\u2500 520.8983.jpg\n\u251c\u2500\u2500 520.9086.jpg\n\u251c\u2500\u2500 520.9351.jpg\n\u251c\u2500\u2500 ...\n\u2514\u2500\u2500 files.txt\n
"},{"location":"Demo-Mode/#collecting-images-of-your-device","title":"Collecting images of your device","text":"There are several ways to collect images from your device:
- Use the Parameter
RawImagesLocation to store them directly onto your SD card. - Use the Webhook to send the raw image on each round to a dedicated server, see Webhook resp. ../Parameter
UploadImg. -
Another option is to pull the images periodically from http://<IP>/img_tmp/raw.jpg. Eg. with an external service. Below is a (Linux)-Bash script to do it:
#!/bin/bash\nwhile [[ true ]]; do\n echo \"fetching value...\"\n wget -q http://192.168.1.151/value -O value.txt\n\n value=`cat value.txt`\n echo \"Value: $value\"\n\n diff=`diff value.txt value_previous.txt`\n changed=$?\n #echo \"Diff: $diff\"\n\n if [[ $changed -ne 0 ]]; then\n echo \"Value changed:\"\n echo $diff\n echo \"fetching image...\"\n wget -q http://192.168.1.151/img_tmp/raw.jpg -O $value.jpg\n else\n echo \"Value did not change, skipping image fetching!\"\n fi\n\n cp value.txt value_previous.txt\n\n echo \"waiting 60s...\"\n sleep 60\ndone\n
"},{"location":"Demo-Mode/#use-prepared-images","title":"Use prepared images","text":"Instead of recoding your own images, you can use one of the selections of prepared images below.
"},{"location":"Demo-Mode/#how-does-it-work","title":"How does it work","text":"The Demo Mode tries to interfere as less as possible with the normal behavior. Whenever a Cam framebuffer gets taken (esp_camera_fb_get()), it replaces the framebuffer with the image from the SD card.
"},{"location":"Demo-Mode/#example-data-of-a-water-meter","title":"Example Data of a Water Meter","text":"You can use the following demo images if you want:
It covers a meter range from 530.00688 to 531.85882.
"},{"location":"Demo-Mode/#animation","title":"Animation","text":"Animation of the watermeter (77 MB!)
"},{"location":"Demo-Mode/#selection-of-84-images","title":"Selection of 84 images","text":"Demo_Images_Watermeter_530.00688-532.08243_84_images.zip
"},{"location":"Demo-Mode/#selection-of-42-images","title":"Selection of 42 images","text":"Demo_Images_Watermeter_530.00688-532.08243_42_images.zip
"},{"location":"Demo-Mode/#all-images-843-images","title":"All images (843 images)","text":"Demo_Images_Watermeter_530.00688-532.08243_843_images.zip
"},{"location":"Error-Codes/","title":"Reduced webinterface (error indication and tracing)","text":"Whenever an error occurs during boot process which avoids loading of regular processing and regular webinterface, a reduced webinterface gets loaded to have at least some visual feedback and the possibilitiy to figure out the root cause by browsing the logfiles or trigger another OTA update.
The error code(s) get printed with specific error codes. This page lists the possible error codes, their meaning and possible solutions.
Notes
Here the error codes are defined in source code: error codes.
"},{"location":"Error-Codes/#critical-errors","title":"Critical Errors","text":"Those Errors make the normal operation of the device impossible. Most likely they are caused by a hardware issue!
"},{"location":"Error-Codes/#0x00000001-psram-bad","title":"0x00000001 PSRAM bad","text":"Your device most likely has no PSRAM at all or it is too small (needs to have at least 4 MBytes)! See Hardware Compatibility.
Usually the log shows something like this:
psram: PSRAM ID read error: 0xffffffff\ncpu_start: Failed to init external RAM!\n
"},{"location":"Error-Codes/#0x00000002-heap-too-small","title":"0x00000002 Heap too small","text":"The firmware failed to allocate enough memory. This most likely is a consequential error of a bad PSRAM!
"},{"location":"Error-Codes/#0x00000004-cam-bad","title":"0x00000004 Cam bad","text":"The attached camera can not be initialized. This usually is because on of the following reasons:
- The camera is not supported, see Hardware Compatibility
- The camera is not attached properly -> Try to remove and attach it again. Make sure you move the black part enough into the socket!
- The camera or the camera cable is damaged
"},{"location":"Error-Codes/#0x00000008-sd-card-basic-check-failed","title":"0x00000008 SD card basic check failed","text":"One or more basic SD card checks failed.
The following checks are performed during boot sequence:
- Write a file (sdcard/sdcheck.txt) to SD card with some generic text
- Read the written file back
- CRC verification
- Delete the file
Detailed error indication (write, rerad or delete error) can be derived from blinking code of red board status LED. Please refer to StatusLED-BlinkCodes
Recommendation: Reformat SD card and check again or try another SD card
"},{"location":"Error-Codes/#0x00000010-sd-folder-or-file-presence-check-failed","title":"0x00000010 SD folder or file presence check failed","text":"One or more mandatory folders and/or files are missing on SD card. To have early indication that SD card is potentially ready for operation, some folder and files, which are mandatory are presence checked. This is not a 100% check and a successful test does not mean everthing is OK.
The following folders / files get checked during boot sequence:
- /sdcard/config
- /sdcard/html
- /sdcard/demo --> created automatically in firmware
- /sdcard/firmware --> created automatically in firmware
- /sdcard/img_tmp --> created automatically in firmware
- /sdcard/log --> created automatically in firmware
- /sdcard/wlan.ini
- /sdcard/config/config.ini
- /sdcard/html/index.html
- /sdcard/html/ota_page.html
- /sdcard/html/log.html
- /sdcard/html/common.js
- /sdcard/html/version.txt
Notes
This list might be outdated, see the source code for the latest implementation: SDCardCheckRW()
Recommendation: Check logs and / or redo a Over-The-Air Update (OTA Update) to ensure proper SD card structure
"},{"location":"Error-Codes/#non-critical-errors","title":"Non-Critical Errors","text":"Those Errors can be caused by an error during initialization. It is possible that the error has no impact at all or that a reboot solves it.
"},{"location":"Error-Codes/#0x00000100-cam-framebuffer-bad","title":"0x00000100 Cam Framebuffer bad","text":"The firmware was unable to initialize the Camera Framebuffer. The firmware will continue to work, but other consequential error might arise. A reboot of the device might help.
This might also be caused by a corrupred SD-Card, see CAM is not working anymore\" on init #2390
"},{"location":"Error-Codes/#0x00000200-ntp-failed","title":"0x00000200 NTP failed","text":"The firmware failed to get the world time from an NTP server. The firmware will continue to work, but has a wrong time.
"},{"location":"Error-Debugging/","title":"Often observed issues","text":""},{"location":"Error-Debugging/#hardware-failure","title":"Hardware failure","text":" - Camera not working --> check the interface, test another module
- Low cost module with no or only 2MB memory instead of 4MB --> test another module
- SD card issues --> test another SD card
- Wifi reception bad / unstable --> bad antenna, test another module or use external antenna
More information in terms of hardware, component and basic configuration issues can be found here: Reboot reasons
"},{"location":"Error-Debugging/#roi-misaligned","title":"ROI misaligned","text":"This typically happens if you have suboptimal \"Alignment Marks\". A very simple and working solution is to put put higly contrasted stickers on your meter and put \"Alignment Marks\" on it (see picture below)
If after those adjustment you still have some issues, you can try to adjust your alignment settings in expert mode:
"},{"location":"Error-Debugging/#my-analog-meter-are-recognized-as-digit-counter-or-vice-versa","title":"My Analog Meter are recognized as Digit Counter or vice versa","text":" - First, check that your ROI are correctly defined (yey!)
- Second, verify that the name of your ROI analog and digit ROIs are different
"},{"location":"Error-Debugging/#recognition-is-working-well-but-number-arent-sorted-correctly","title":"Recognition is working well, but number aren't sorted correctly","text":"You have to sort your ROI correctly (Bigger to smaller). Select your ROI and click either \"move next\" or \"move previous\". Repeat until your ROI are correctly sorted
"},{"location":"External-LED/","title":"External LED","text":"The internal flash LED is very close to the camera axis. This results in reflection, especially in case of flat glass surfaces such as for power meters. To circumvent this problem, it is now possible to control external LEDs, which than can be places somewhere else in the setup. As not simples LEDs are used, but RGB LEDs with a digital interface like WS2812 not only the position, but also the color and intensity of the illumination can now be adjusted. The following image shows a direct comparison of the \"old\" internal flash LED and two off axis LEDs.
There is also a new meter adapter available. This has two features: designed for small clearings in front of the meter and prepared for WS2812 LEDs.
"},{"location":"External-LED/#1-hardware-installation-of-the-led-stripe","title":"1. Hardware installation of the LED stripe","text":"The control line of the LED stripe is connected with a 470 Ohm resistor to the GPIO12. For power supply stabilization a capacitor between 5V and ground is recommended. Here a 470\u00b5F polymer capacitor is used. As a power supply a 5V from the ESP32 is used like in the following wiring.
"},{"location":"External-LED/#2-software-configuration","title":"2. Software configuration","text":"The handling of the WS2812 LED controller needs some other libraries, therefore it is controlled within a dedicated section called GPIO Settings. The external LED stripe is connected to GPIO12. After activating the \"GPIO Settings\" section, the internal flash is per default disabled. In order to activate the external LED, you need to activate GPIO 12 state and select \"extern flash light ws281x ...\".
Parameter Meaning LED-Type There are several types of controller implemented: WS2812(B), WS2813, SK6812 Numbers of LED Number of LEDs on the LED stripe LED Color The color and intensity can be controlled directly by a red/green/blue value, each within the range from 0 (off) to 255 (full) Enabling the GPIO settings automatically disables the flash LED. Therefore you can enable it here manually by checking GPIO4 and choose \"build-in led flash light\". It is not recommended to use both illumination parallel.
"},{"location":"FAQs/","title":"Frequently Asked Questions","text":""},{"location":"FAQs/#my-device-reboots-frequently-what-can-i-do","title":"My device reboots frequently. What can I do?","text":"There are several reasons for frequent reboots:
- Frequent HTML requests
- Wrong configuration, missing configuration files
- Unstable hardware - see Hardware Compatibility.
There is a dedicated page about this: Frequent Reboots.
"},{"location":"FAQs/#bad-webui-responsiveness-what-can-i-do","title":"Bad WebUI responsiveness. What can I do?","text":"This is usually due to hardware or WLAN issues. There are already many entries in discussion section, some of which have good tipps.
Possible checks / ideas:
- ESP32CAM hardware antenna design is very poor in connection with camera frequency.
- Simple test: When the device is in operation, putting your thumb on the camera connector and the directly adjacent components should make the device respond more quickly.
- Possible optimization: Here, an attempt was made to dampen the frequency influences somewhat by shielding. Shielding Example
- WLAN channel: Preferably use channel 1, 6 or 11
- Performance can vary depending on the AP manufacturer. If necessary, check with a mobile hotspot or other device to exclude AP influence
- Try with an external antenna
- Avoid VLAN, currently not fully supported
- Temporarily deactivate virus scanner / firewall on the end device for testing purpose
- Use sufficiently dimensioned power supply
- Use a branded SD card (formatted with Windows, MAC often causes problems)
Check discussion section for possible further tipps.
"},{"location":"FAQs/#how-accurate-are-the-detections","title":"How accurate are the detections?","text":"It is hard to give a specific accuracy number. It depends on many factors, e.g.
- How in-focus is your camera?
- How sturdy is the camera mount? Does it slightly move over extended periods of time?
- What type of meter are you reading? Is the meter already in the training data set?
- Are you trying to read digits, an analog dial, or both?
- etc.
Anecdotally, the authors of this page have great success with the meter. While the AI algorithm itself is not perfect and sometimes returns NaN or incorrect values, other post-processing / prevalue / sanity checks help ensure such invalid values are filtered out. With the correct settings, one author has been running this device for 1 month without any incorrect values reported.
See the FAQs below for more details and configuration hints.
"},{"location":"FAQs/#my-numbers-are-not-correctly-detected-what-can-i-do","title":"My numbers are not correctly detected. What can I do?","text":" - There is a dedicated page about the correct setting ROI Configuration.
- This page also includes the instructions for gathering new images for the training.
"},{"location":"FAQs/#how-can-i-ensure-invalid-numbers-are-never-reported","title":"How can I ensure invalid numbers are never reported?","text":"As mentioned above, the AI algorithm is not perfect. Sometimes it may read an incorrect value.
We can tune the software to almost never report an incorrect value. There is a tradeoff though: the software may report stale values - i.e. it will drop incorrect values for a potentially long period of time, resulting in the meter reading being outdated by hours. If never receiving an incorrect value is important to you, consider tolerating this tradeoff.
You can change the following settings to reduce incorrect readings (but potentially increase staleness of data):
- Set a prevalue via the UI, then change
PostProcessing configuration option PreValueAgeStartup to a much larger number (e.g. 43200 = 30 days). - Change
PostProcessing configuration option MaxRateType to be time based instead of absolute. Set MaxRateValue to something realistic (e.g. 5 gal/min). You can often find the max flow rate your meter supports directly on the cover. - Reduce
AutoTimer configuration option Interval to the lowest it can be (e.g. 3 min). The more often you take readings, the less likely for data staleness to occur.
"},{"location":"FAQs/#even-after-i-have-setup-everything-perfect-there-is-a-false-reading-especially-around-the-zero-crossing-roll-over-to-next-number","title":"Even after I have setup everything perfect there is a false reading - especially around the zero crossing (roll over to next number)","text":" - The roll over behavior is different for the different meters. E.g.:
- Rolling over start with different previous position (e.g. at 7, 8 or 9)
-
The neutral position (no rolling) is not perfectly at zero, but rather at something like 7.9 or 8.1, even if it should be exactly 8
-
The \"PostProcessingAlgo\" is trying to judge out of the individual readings, what number it should be.
-
For example if the previous number is a \"1\", but the next number seems to be a \"8.9\", most probably there was a \"zero crossing\" and the number is a \"9\" and not still an \"8\"
-
Currently the setting of the algorithm is set to fit most of the meters and cases. But the parameters do not fit perfectly for all situations. Therefore there might be intermediate states, where the reading is false. This is especially the case, at the positions, where the roll over (zero crossing) is just starting.
- To prevent a sending of false parameters, there is the possibility to limit the maximum allowed change (MaxRateChange). Usually after some time and movement of the counters a bit further, the reading is getting back to a stable reading.
- To handle this, a parametrized setting would be needed. This is rather complicated to implement as subtle changes make a relevant difference. Currently this is not implemented. So please be a bit patient with your meter :-)
"},{"location":"FAQs/#pre-value","title":"Pre-Value","text":"PreValue is here a bit missleading, because normally it is the same as the last value. In the next round of reading it will be used to check nagtive rates, high rates (MaxRateValue / MaxRateType) and CheckDigitIncreaseConsistency (dig-class11 only). Either from a previous correctly identified value or manual setting by the user.
If you use post processes, enable the pre-value. The pre-value must be set at first time. Set it to the current raw value.
If the device runs in errors, the pre-value will not be updated, as long as the preValueAgeStartup time between the last valid value (or startup time) and current time is not exceeded. After it the preValue will be set again, if no other error occured. So the device can not run in an endless error, like high rate.
"},{"location":"FAQs/#rate-too-high-read","title":"\"Rate too high - Read: ...\"","text":"In configuration you can set the MaxRateValue and MaxRateType. The settings suppress improbably high values that can come from false readings. To do this, the value must be set correctly depending on your meter.
Before doing this, you should be clear about the type of rating you want to use.
Absolute change is the interval between two readings - no matter how often the readings happen. RateChange is the change per minute. This is calculated from the time difference between the last and the current reading.
If there is an interval of 5 minutes between readings and a MaxRateValue of 1, an error \"Rate too high - Read: ...\" if
- Absolute change: the difference is
> 1 - RateChange: the difference is
> 1 / 5
"},{"location":"FAQs/#train-on-my-own-images","title":"Train on my own images","text":"Look at Learn models with your own images and Cookbook running the jupyter notebook with my own data.
"},{"location":"FAQs/#what-does-aioted-mean","title":"What does AIOTED mean?","text":"This is just the abbreviation of AI-on-the-edge-device.
"},{"location":"Frequent-Reboots/","title":"Basic hardware / configuration issues","text":"If the device is behaving eratically or not running as expected you can use the following tools trying to identify the root cause:
- Internal logging (
config.ini) --> Set to DEBUG log level - Reduced web interface (only error indication visualization, Error codes on reduced webinterface)
- Red board LED: Status LED Blinkcodes
- Serial log of the UART interface (USB access needed, only local, same as for flashing the firmware)
There are in principle two reboots types:
- Sporadic random reboots (always different timing and situation)
- Repeating boot loops (reoccuring, always stop working after same precondition)
"},{"location":"Frequent-Reboots/#sporadic-random-reboots","title":"Sporadic random reboots","text":"Sporadic random reboots could have the following reasons:
- In general: Unstable system due to software issues (e.g. overload during HTML access, ...) --> Trying the figure out what's the root cause to fix the issue
- Bad power supply --> The power supply need to stable to ensure proper operation of the device. If it's not stable the device tents to sporadic reboots (brownout detection)
In general: There are several mechanisms in the firmware (like saving previous values), to have a \"smooth\" reboot without too many notable disturbance.
"},{"location":"Frequent-Reboots/#system-instabilities","title":"System instabilities","text":"If your system is sometimes running smoothly over several runs and sometimes reboots obviously randomly, you have an partially unstable device.
You can check this in the standard log file on the SD card:
2021-12-26T06:34:09: task_autodoFlow - round done\n2021-12-26T06:34:09: CPU Temperature: 56.1\n2021-12-26T06:38:00: task_autodoFlow - next round - Round #23\n
Here you see, that the round #23 is starting, so obviously there were no reboots in the last 22 rounds. There is hardware (ESP32CAM), where only 2-3 stable rounds are possible and others, where way more than 100 rounds without any reboots is possible. There is noting you can do about it, beside testing different hardware.
"},{"location":"Frequent-Reboots/#overload-during-html-access","title":"Overload during HTML access","text":"If you frequently access the web server over HTML requests, the firmware tends to reboot. This especially happens during the first run and when the ESP32 is busy with the digitization flow.
The reason for this are running out of memory during a flow, minor memory leakage in combination with missing error handling.
There is noting you can do about this kind of reboot, beside two thing:
- Support the firmware development with improved and tested part of code
- Be patient :-)
"},{"location":"Frequent-Reboots/#bad-or-insufficient-power-supply","title":"Bad or insufficient power supply","text":"A good and stabilized power supply is essential to have error free operation. The device is quite picky in terms of proper power supply. Especially the wifi module have some load spikes which the power supply needs to cover. If the power is not stable enough, the brwonout mechanism is protecting against strange behaviour and force a reboot whenever the voltage drops below a specific level. You can see this in random reboots which indication is logfile: --> Reset reason: Brownout
"},{"location":"Frequent-Reboots/#repeating-boot-loops","title":"Repeating boot loops","text":"Repeating boot loops at the same situation during the flow has a systematic problem either in the hardware or the configuration. It usually happens during initialization state or processing the first round as there all needed parts of the firmware have been loaded for the first time.
To identify the root cause the logfiles, the reduced web interface, the red board LED or the serial log of the UART interface (no remote access, USB access needed) is helpful.
Possible issues:
- SD card related issues
- RAM related issues
- Configuration related issues
"},{"location":"Frequent-Reboots/#sd-card-related-issues","title":"SD card related issues","text":"The ESP32CAM is a little bit \"picky\" with the supported SD cards. Due to the limited availability of GPIOs the SD card can only be accessed via 1-wire mode. Therefore not all SD cards are supported. The following error cases can occur:
"},{"location":"Frequent-Reboots/#sd-card-wrong-filesystem-only-fat32-is-supported","title":"SD card: Wrong filesystem (only FAT32 is supported)","text":"If this SD card error is detected only the following indications are available. No web interface will be accessible.
- Red board LED is blinking. The blinking codes are described here: Status LED Blinkcodes
- Error messages on serial log (UART interface)
"},{"location":"Frequent-Reboots/#sd-card-not-detected-not-supported","title":"SD card not detected / not supported","text":"If this SD card error is detected the following indication are available. No web interface will be accessible.
- Red board LED is blinking. The blinking codes are described here: Status LED Blinkcodes
- Error messages on serial log (UART interface)
"},{"location":"Frequent-Reboots/#sd-card-detected-but-files-are-not-readable-writeable","title":"SD card detected but files are not readable / writeable","text":"The SD card is detected, but the files cannot be read or written. A basic SD card check for SD reading / writing is performed on every boot. This not 100% guarantee that SD card is working but it's at least a indication.
If this SD card error is detected the following indications are available:
- The reduced web interface will be loaded to have visual feedback of error situation. Regualar processing is disabled, though. Within this reduced web interface logs can be viewed to have further indication what's the root cause. Error code desciption can be found here: Error codes on reduced webinterface
- Error messages in logfile
- Red board LED is blinking. The blinking codes are described here: Status LED Blinkcodes
- Error messages on serial log (UART interface)
"},{"location":"Frequent-Reboots/#ram-related-issues","title":"RAM related issues","text":"In order to run the firmware, 4 MB of external RAM (PSRAM) are mandatory. Usually, the ESP32CAM is equipped with 8MB (64Mbit) PSRAM chip, whereof only 4MB can be used effectively (direct addressable). Unfortunately, there is hardware around, where no PSRAM or only 2MB of PSRAM is present - even if you have bought a device where a 8MB PSRAM was promoted. These modules are not suiable for this firmware because the external RAM is needed to handle the CNN files and camera images. There is nothing to do, than to buy a new ESP32CAM with really 64MBit of PSRAM.
"},{"location":"Frequent-Reboots/#too-less-external-ram-psram","title":"Too less external RAM (PSRAM)","text":"During the boot process the available RAM is going to be checked.
If there is too less RAM (PSRAM or total HEAP < 4MB) detected, the follwoing indications are available:
- The reduced web interface will be loaded to have visual feedback of error situation. Regualar processing is disabled, though. Within this reduced web interface logs can be viewed to have further indication what's the root cause. Error code desciption can be found here: Error codes on reduced webinterface
- Error messages in logfile
- Red board LED is blinking. The blinking codes are described here: Status LED Blinkcodes
- Error messages on serial log (UART interface)
"},{"location":"Frequent-Reboots/#configuration-related-issues","title":"Configuration related issues","text":""},{"location":"Frequent-Reboots/#folders-and-files-missing","title":"Folders and files missing","text":"Most of the relevant folders and files are checked during boot. The complete list can be found here: Error codes on reduced webinterface
If a relevant folder or file is missing the following indications are available:
- The reduced web interface will be loaded to have visual feedback of error situation. Regualar processing is disabled, though. Within this reduced web interface logs can be viewed to have further indication what's the root cause. Error code desciption can be found here: Error codes on reduced webinterface
- Error messages in logfile
- Red board LED is blinking. The blinking codes are described here: Status LED Blinkcodes
- Error messages on serial log (UART interface)
"},{"location":"Frequent-Reboots/#cnn-model-file-not-available-corrupt","title":"CNN model file not available / corrupt","text":"Additionally for operation CNN model files on SD card are mandatory, one CNN model file for analog counter and for for digit numbers each.
/config/XXXXX.tflite (XXXXX is the file name, that is written in the config.ini)
If the files which are configured in config.ini are not present or corrupt, the process is going to be interrupted (or at worst case a device crash occurs). Please check logs files to have an indicator for the root cause.
This a logfile extract (DEBUB log level) where digit CNN model file is not present. The system is initializing the system and trying to load the model files:
[0d00h05m11s] 2023-03-27T12:25:14 [TFLITE] CTfLiteClass::LoadModel\n[0d00h05m11s] 2023-03-27T12:25:14 [TFLITE] CTfLiteClass::ReadFileToModel: /sdcard\n[0d00h05m11s] 2023-03-27T12:25:14 [PSRAM] Failed to allocate 0 bytes in PSRAM for 'TFLITE->modelfile'!\n[0d00h05m11s] 2023-03-27T12:25:14 [TFLITE] CTfLiteClass::ReadFileToModel: Can't allocate enough memory: 0\n[0d00h05m12s] 2023-03-27T12:25:14 [HEAP] CTfLiteClass::ReadFileToModel Heap Total: 2266214 | SPI Free: 2205939 | SPI Large Block: 2162688 | SPI Min Free: 2205423 | Int Free: 60275 | Int Large Block: 55296 | Int Min Free: 46451\n[0d00h05m12s] 2023-03-27T12:25:14 [CNN] Can't load tflite model -> Init aborted!\n[0d00h05m12s] 2023-03-27T12:25:14 [HEAP] getNetworkParameter-LoadModel Heap Total: 2266214 | SPI Free: 2205939 | SPI Large Block: 2162688 | SPI Min Free: 2205423 | Int Free: 60275 | Int Large Block: 55296 | Int Min Free: 46451\n[0d00h05m12s] 2023-03-27T12:25:14 [PSRAM] Freeing memory in PSRAM used for 'TFLITE->modelfile'...\n[0d00h05m12s] 2023-03-27T12:25:14 [PSRAM] Freeing memory in PSRAM used for 'TFLITE->tensor_arena'...\n[0d00h05m12s] 2023-03-27T12:25:14 [PSRAM] Allocated 819200 bytes in PSRAM for 'TFLITE->tensor_arena'\n[0d00h05m12s] 2023-03-27T12:25:14 [TFLITE] CTfLiteClass::LoadModel\n[0d00h05m12s] 2023-03-27T12:25:14 [TFLITE] CTfLiteClass::ReadFileToModel: /sdcard/config/ana-cont_1105_s2_q.tflite\n[0d00h05m12s] 2023-03-27T12:25:15 [PSRAM] Allocated 53328 bytes in PSRAM for 'TFLITE->modelfile'\n[0d00h05m12s] 2023-03-27T12:25:15 [TFLITE] CTfLiteClass::MakeAllocate\n[0d00h05m12s] 2023-03-27T12:25:15 [PSRAM] Freeing memory in PSRAM used for 'TFLITE->modelfile'...\n[0d00h05m12s] 2023-03-27T12:25:15 [PSRAM] Freeing memory in PSRAM used for 'TFLITE->tensor_arena'...\n
"},{"location":"Hardware-Compatibility/","title":"Hardware Compatibility","text":""},{"location":"Hardware-Compatibility/#general-remark","title":"General Remark","text":"Although a board looks similar, it can have major differences, e.g.:
- Processor
- Ram (Size! & Type) -> this Project needs at least 4MB RAM!
- Flashrom
- Camera Modules
- Onboard/External Antenna
- Quality of Components
- Manufacture Quality of the PCB and soldering
- Different Components
- \"Clone\" Components -> ESPxx
- etc.
This can cause different Power Consumption, Power Requirements, compatibility issues, etc.
Most manufacturers and sellers buy what's cheap today on the Asian markets. In the end, it looks like it is sometimes a trial and error approach which ESP32-CAM Module works reliably.
Below you find some remarks and experiences from the community:
"},{"location":"Hardware-Compatibility/#esp32-core-itself","title":"ESP32 core itself","text":"Chip Version Image Status ESP32-D0WDQ6 (revision 1) \u2714\ufe0f"},{"location":"Hardware-Compatibility/#psram","title":"PSRAM","text":"There seems to be a lot of \"fake\" chips, or maybe wrongly configured ESP32 Boards.
For AP MEMORY, all \"real\" APS6404*3SQR chips should work.
For ESP PSRAM, all \"real\" PSRAM64* should work.
64Mbit density = 8Mbyte PSRAM
This Table is just a snapshot of chips which worked
Labeling on PSRAM module Image Status IPUS / IPS640LS0 / 1815XBGN \u2714\ufe0f AP MEMORY / 6404L-3SOR / 1040H / 110089G \u2714\ufe0f AP MEMORY / 6404L-3SQR / 12205 / 150047G \u2714\ufe0f 8MB AP MEMORY / 6404L-3SQR / 12208 / 150047G \u2714\ufe0f 8MB AP MEMORY / 6404L-350R / 1120A / 130027G \u274c PSRAM not accessible AP MEMORY / 6404L-35QR / 11208 / 130025G \u274c PSRAM not accessible AP MEMORY / 6404L-3SQR / 13100 / 180026G \u274c PSRAM not accessible AP MEMORY / 6404L-3SQR / 11207 / 130024G \u274c PSRAM not accessible AP MEMORY / 6404L-3SQR / 1120A / 130027G \u2714\ufe0f 8MB AP MEMORY / 6404L-3SQR / 1120B / 130028G \u2714\ufe0f 8MB AP MEMORY / 6404L-3SQR / 1120D / 130030G \u2714\ufe0f 8MB AP MEMORY / 1604M-3SQR / 0280A / 070036G \u274c 2MB only! ESP PSRAM64H 462021 / 1B00286 \u2714\ufe0f ESP PSRAM64H 412021 / 1A0039G \u2714\ufe0f 8MB ESP PSRAM64H 402021 / 1A0017N \u274c PSRAM not accessible ESP PSRAM16M 302020 \u274c 2MB only! ESP PSRAM16H 202020 / 050022G \u274c 2MB only!"},{"location":"Hardware-Compatibility/#ov2640-camera","title":"OV2640 - Camera","text":"The experience with the camera only is based on single modules. It is well possible, that this module had a damage overall and other modules of the same type will work. Give it a try and report to me!
Labeling on Flex-Connector Image Status TY-OV2 / 640-V2.0 \u2714\ufe0f DCX-OV2 / 640-V2 \u2714\ufe0f DC-26 / 40-V3 \u2714\ufe0f 3x \u274c 1x"},{"location":"Hardware-Compatibility/#esp32-modules","title":"ESP32 Modules","text":"Module Image Status ESP32CAM / Different versions on the market!Especially the PSRAM is sometimes labeled wrong(Label: 4MB, Real: only 2 MB --> will not work!) \u2714\ufe0fwith >=4 MB PSRAM! ESP32-S3-EYENo Flash LED, pins different used (e.g. LCD display) NOT OKAY"},{"location":"Hardware-Compatibility/#sd-cards","title":"SD Cards","text":"Due to the limited free available GPIOs (due to all the extensions needed like: camera, SD card, LED-flash, ...) the SD card is connected in 1-wire mode. There are some cards, that are compatible with the esp32cam module for unknown reasons. It is observed, that smaller cards (up to 4 GB) tend to be more stable and larger cards have more problems. But quite some exceptions in the forums (4 GB cards not working, 16 GB cards working like a charm).
"},{"location":"Hardware-Compatibility/#devices-known-to-work","title":"Devices known to work","text":""},{"location":"Hardware-Compatibility/#modules-old-list-not-up-to-date-anymore","title":"Modules (Old list, not up-to-date anymore):","text":"See https://github.com/jomjol/AI-on-the-edge-device/discussions/1732 for a more recent list.
-
https://arduino-projekte.info/produkt/esp32-cam-v2-integriertem-ch340-mit-ov2640-kamera-modul/ (see https://github.com/jomjol/AI-on-the-edge-device/discussions/1041)
-
https://www.amazon.de/-/en/gp/product/B0B51CQ13R
-
https://www.reichelt.de/entwicklerboards-esp32-kamera-2mp-25--debo-cam-esp32-p266036.html?PROVID=2788&gclid=CjwKCAiAqaWdBhAvEiwAGAQlttJnV4azXWDYeaFUuNioMICh-jvxKp6Cifmcep9vvtoT2JRCDqBczRoC7Q0QAvD_BwE (27.12.2022)
"},{"location":"Hardware-Compatibility/#sd-card","title":"SD Card","text":" - Sandisk 2GB Micro SD Class 2 Sandisk 2GB AITRIP ESP32 and CAM ESP-32/CAM
- Amazon US - Aideepen ESP32-CAM W BT Board ESP32-CAM-MB Micro USB to Serial Port CH-340G with OV2640 2MP Camera Module Dual Mode with Amazon US - Cloudisk 5Pack 4GB Micro SD Card 4 GB MicroSD Memory Card Class6
"},{"location":"Hardware-Compatibility/#weak-wifi","title":"Weak Wifi","text":"The ESP32-CAM supports an external antenna. It requires some soldering skills but can improve the connection quality. See https://randomnerdtutorials.com/esp32-cam-connect-external-antenna/
"},{"location":"Influx-DB/","title":"Influx DB","text":"The device also supports direct sending of data to an Influx DB.
See also Influx Graph in Home Assistant.
"},{"location":"Installation/","title":"Installation","text":"The installation requires multiple steps:
- Get the right hardware and wire it up
- Flash the firmware onto the ESP32
- Write the data to the SD card
- Start it
For point 2 and 3 we provide multiple ways to do it. Pick the one that looks the easiest for you!
"},{"location":"Installation/#1-hardware","title":"1. Hardware","text":""},{"location":"Installation/#esp32-cam","title":"ESP32-CAM","text":" - OV2640 camera module
- Micro SD card slot
- 4 or 8 MB PSRAM.
It can be easily found on the typical internet stores, searching for ESP32-CAM for less than 10 EUR. How ever since the hardware is cheap and coming from China, you unluckily could pick a malfunctioning device. See Hardware Compatibility for further advice!
"},{"location":"Installation/#usb-uart-interface","title":"USB->UART interface","text":"For first time flashing the firmware a USB -> UART connector is needed. Later firmware upgrades than can be flashed via OTA.
"},{"location":"Installation/#power-supply","title":"Power supply","text":"For power supply a 5V source is needed. Most easily this can be done via a USB power supply. The power supply should support minimum 500mA. For buffering current peaks some users reported to use a large electrolytic capacitor like a 2200uF between ground and VCC.
Warning
In several internet forums there are problems reported, in case the ESP32-CAM is only supplied with 3.3V.
"},{"location":"Installation/#housing","title":"Housing","text":"A small 3D-printable example for a very small case can be found in Thingiverse here: https://www.thingiverse.com/thing:4571627
Warning
The focus of the OV2640 needs to be adjusted, as it is normally set from ~40cm to infinity. In order to get an image that is big enough, it needs to be changed to about 10cm. Therefore the sealing glue on the objective ring needs to be removed with a scalpel or sharp knife. Afterwards the objective can be rotated clockwise until the image is sharp again.
"},{"location":"Installation/#wiring","title":"Wiring","text":"Beside the 5V power supply, only for the first flashing a connection to the USB-UART connector, including a short cut of GPIO0 to GND for bootloader start.
A example for wiring can be found here:
It is also possible to use external LEDs for the illumination instead of the internal flash LED. This is described here
"},{"location":"Installation/#2-firmware","title":"2. Firmware","text":""},{"location":"Installation/#web-installer","title":"Web Installer","text":"There is a Web Installer available which will work right out of the web browser Edge and Chrome. You can access it with the following link: Web Installer
This is the preferred way for beginners as it also allows access to the USB Log:
"},{"location":"Installation/#manual-flashing","title":"Manual Flashing","text":""},{"location":"Installation/#files","title":"Files","text":"Grab the firmware from the
- Releases page (Stable, tested versions), or the
- Automatically build development branch (experimental, untested versions). Please have a look on Living on the Edge first!
You need:
- partitions.bin
- bootloader.bin
- firmware.bin
"},{"location":"Installation/#flashing-using-the-flash-tool-from-espressif-gui","title":"Flashing using the Flash Tool from Espressif (GUI)","text":"Get the Flash Download Tool from Espressif.
Download and extract the Flash tool, after starting choose \"Developer Mode\", then \"ESP32-DownloadTool\" and you are in the setup of the flashing tool. Connect the ESP32-CAM with the USB-UART connection and identify the COM-Port.
Warning
If you are re-flashing the code again, it is strongly recommended to erase the flash memory before flashing the firmware. Especially if you used OTA in between, which might cause remaining information on the flash, to still boot from an old image in the OTA-area, which is not erased by a normal flash.
Put your ESP32 in bootloader mode and push start, then it will identify the board and you can configure the bin-configuration according to the following table:
Filename Offset bootloader.bin 0x1000 partitions.bin 0x8000 firmware.bin 0x10000 "},{"location":"Installation/#flashing-using-the-python-based-esptool-console","title":"Flashing using the Python based esptool (Console)","text":"For this you need a python environment (e.g. Anaconda in Win10). Here you need to install the esptool:
pip install esptool\n
Then connect the ESP32 with the USB-UART connector to the system, put it in boot mode and with the following command you can erase the flash and flash bootloader, partitions and firmware in two steps: esptool erase_flash\nesptool write_flash 0x01000 bootloader.bin 0x08000 partitions.bin 0x10000 firmware.bin\n
- Maybe you need to specify the COM-port if it is not detected by default. - If the erase command throws the error A fatal error occurred: ESP32 ROM does not support function erase_flash., your esptool might be too old, see https://techoverflow.net/2022/02/08/how-to-fix-esp32-a-fatal-error-occurred-esp32-rom-does-not-support-function-erase_flash/ With some Python installations this may not work and you\u2019ll receive an error, try python -m pip install esptool or pip3 install esptool.
Further recommendations can be found on the espressif webpage.
"},{"location":"Installation/#3-sd-card","title":"3. SD Card","text":"The software expects an SD card prepared with certain directory and file structure in order to work properly. SD card most top directory should look like this:
This initial setup needs only to be done once as further updates (Firmware as well as SD card content) are possible with the Over-The-Air Update mechanism.
"},{"location":"Installation/#notes","title":"Notes","text":" - Due to the limited availability of GPIOs (OV2640, Flash-Light, PSRAM & SD card) the communication mode to the SD card is limited to 1-line SD-Mode. It showed up, that this results in problems with very large SD-Cards (64GB, sometimes 32 GB) and some no name low cost SD-cards.
- There must be no partition table on the SD-card (no GPT, but only MBR for the single partition)
- Following setting are necessary for formatting the SD-card: SINGLE PARTITION, MBR, FAT32 - 32K. NOT exFAT
- Some ESP32 devices share their SD-card and/or camera GPIOs with the pins for TX and RX. If you see errors like \u201cFailed to connect\u201d then your chip is probably not entering the bootloader properly. Remove the respective modules temporarily to free the GPIOs for flashing. You may find more information about troubleshooting on the homepage of Espressif.
The ESP32 indicates problems with the SD card during startup with a fast, endless blinking. In this case, please try another SD card.
"},{"location":"Installation/#manual-setup-with-an-sd-card-reader-on-a-pc","title":"Manual Setup with an SD Card Reader on a PC","text":" - Take the
AI-on-the-edge-device__manual-setup__*.zip from the Release page. - Open it and extract the
sd-card.zip. - Open it and extract all files onto onto your SD card.
- On the SD card, open the
wlan.ini file and configure it as needed: - Set the corresponding SSID and password
- The other parameters are optional
!!! Note The device provides a File Server which can be used to show, edit or delete the files on the SD card. For security reasons, the wlan.ini file is excluded from this and is hidden from external access to protect the password.
After this, you can insert the SD card into the ESP32 board and start it.
"},{"location":"Installation/#remote-setup-using-the-built-in-access-point","title":"Remote Setup using the built-in Access Point","text":"On startup of the ESP32, it checks if the wlan.ini or the config/config.ini are available on the SD card. If not, the ESP32 switches to a special mode. In this mode, it provides a Wifi Access Point which can be used to add the missing wlan.ini or the config/config.ini file.
- Take the
AI-on-the-edge-device__remote-setup__*.zip from the Release page. -
Connect to Access Point of the device. The SSID is \"AI-on-the-Edge\" and you can access it without any password:
The device has the following fixed IP: http://192.168.4.1.
-
Upload initial configuration to SD card
Use the select file and upload button to start the upload. A warning will show up if you have chosen a possible wrong file (without default configuration).
-
Store WLAN access information.
After the upload, a new page will be shown:
Enter your SSID and password.
Note
Only basic settings are supported. If you need advanced configuration (fixed ip, ...), you need to use the manual setup as documented above.
Warning
- Carefully check your wifi settings. To change them later on, you need to take out the SD card and edit the
wlan.ini manually (or delete it and start again). - The information is transferred without encryption!
Finish the step by pushing Write wlan.ini
-
Reboot
The final step is the reboot:
Warning
It will take up to 3 minutes. Afterwards you can find your device in the local network. Check your router for the IP. You can find it also in the USB Console output.
"},{"location":"Installation/#4-initial-startup","title":"4. Initial Startup","text":"After the firmware is flashed and the SD card is setup properly, you can start it. After power on the connection status is indicated by 3x blinking of the red on board LED.
WLAN-Status indication:
- 5 x fast blinking (< 1 second): connection still pending
- 3 x slow blinking (1 second on/off): WLAN connection established
Notes
It is normal that at first one or two times a pending connection is indicated.
"},{"location":"Integration-Home-Assistant/","title":"Integration into Home Assistant","text":"There are 3 ways to get the data into your Home Assistant:
- Using MQTT (Automatically Setup Entities using Home Assistant MQTT Discovery)
- Using MQTT (Manually Setup Entities)
- Using REST calls
The first one is the easier way if you already have MQTT in use.
"},{"location":"Integration-Home-Assistant/#using-mqtt-automatically-setup-entities-using-home-assistant-mqtt-discovery","title":"Using MQTT (Automatically Setup Entities using Home Assistant MQTT Discovery)","text":"Starting with Version >12.0.1, AI-on-the-edge-devices support Home Assistant Discovery.
- Check here to learn more about it and how to enable it in Homeassistant.
-
You also have to enable it in the MQTT settings of your device:
Make sure to select the right Meter Type to get the right units!
On the next start of the device, it will send discovery topics and Home Assistant should pick them up and show them under Settings > Integrations > MQTT:
"},{"location":"Integration-Home-Assistant/#using-mqtt-manually-setup-entities","title":"Using MQTT (Manually Setup Entities)","text":"First make sure with an MQTT client (for example MQTT Explorer) that MQTT works as expected and to get a list of the available topics!
Then add a sensor for each property:
mqtt:\n sensor:\n - state_topic: \"wasserzaehler/main/value\"\n name: \"Watermeter Value\"\n unique_id: watermeter_value\n unit_of_measurement: 'm\u00b3'\n state_class: total_increasing\n device_class: water # Needs Home Assistant 2022.11!\n icon: 'mdi:water-pump'\n availability_topic: wasserzaehler/connection\n payload_available: connected\n payload_not_available: connection lost\n\n - state_topic: \"wasserzaehler/main/rate\"\n name: \"Watermeter Rate\"\n unique_id: watermeter_rate\n unit_of_measurement: 'm\u00b3/min'\n state_class: measurement\n device_class: water # Needs Home Assistant 2022.11!\n icon: 'mdi:water-pump'\n availability_topic: wasserzaehler/connection\n payload_available: connected\n payload_not_available: connection lost\n\n - state_topic: \"wasserzaehler/main/error\"\n name: \"Watermeter Error\"\n unique_id: watermeter_error\n icon: \"mdi:water-alert\"\n availability_topic: wasserzaehler/connection\n payload_available: connected\n payload_not_available: connection lost \n\n - state_topic: \"wasserzaehler/uptime\"\n name: \"Watermeter Uptime\"\n unique_id: watermeter_uptime\n unit_of_measurement: 's'\n state_class: measurement\n device_class: duration\n entity_category: diagnostic\n icon: \"mdi:timer-outline\"\n availability_topic: wasserzaehler/connection\n payload_available: connected\n payload_not_available: connection lost\n
If you run the discovery once, you can also extract the information from there (MQTT Info, untested): mqtt: # Extracted form the Discovery but untested!\n sensor:\n - name: Value\n unique_id: wasserzaehler-main_value\n icon: mdi:gauge\n state_topic: wasserzaehler/main/value\n unit_of_measurement: m\u00b3\n device_class: water\n state_class: total_increasing\n availability_topic: wasserzaehler/connection\n payload_available: connected\n payload_not_available: connection lost\n
If you want to convert the m\u00b3 to l, use a template sensor:
template:\n - sensor:\n - name: \"Watermeter in l\"\n unique_id: watermeter_in_l\n icon: \"mdi:gauge\"\n state: \"{{ states('sensor.watermeter_value')|float(default=0) * 1000 }}\" # Convert 1 m3 => 1000 l\n unit_of_measurement: l\n availability: \"{{ states('sensor.watermeter_value') not in ['unknown', 'unavailable', 'none'] }}\"\n
If you you want to have the consumption per day, you can use an Utility Meter. it is a helper and can be used to reset the total increasing values once a day
utility_meter:\n utility_meter_gas_per_day:\n source: sensor.gasmeter_value\n cycle: daily\n\n utility_meter_water_per_day:\n source: sensor.watermeter_value\n cycle: daily\n
Note that you also can add it using the UI.
"},{"location":"Integration-Home-Assistant/#examples","title":"Examples","text":""},{"location":"Integration-Home-Assistant/#statistics-graph","title":"Statistics Graph","text":"Creating Statistics Graphs (e.g. usage per day) is easy using the Energy Dashboard:
Note that there seems to be a bug in the graph, see https://github.com/home-assistant/frontend/issues/13995!
"},{"location":"Integration-Home-Assistant/#influxdb-graphs","title":"InfluxDb Graphs","text":"See also Influx-DB.
If you have setup InfluxDB already, it is also possible to fetch statistics from there, e.g. daily usage:
from(bucket: \"HomeAssistant\")\n|> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"entity_id\"] == \"wasserverbrauch_tag\")\n |> filter(fn: (r) => r[\"_field\"] == \"value\")\n |> timeShift(duration: -1d)\n |> aggregateWindow(every: 1d, fn: max, createEmpty: false)\n |> yield(name: \"mean\")\n
"},{"location":"Integration-Home-Assistant/#using-rest","title":"Using REST","text":"When using REST, Home Assistant has to periodically call an URL on the ESP32 which in return provides the requested data.
See REST API for a list of available URLs.
The most practical one is the json entrypoint which provides the most relevant data JSON formatted: http://<IP>/json This would return:
{\n\"main\":\n {\n \"value\": \"512.3020\",\n \"raw\": \"0512.3020\",\n \"error\": \"no error\",\n \"rate\": 0.000000,\n \"timestamp\": \"2022-10-02T20:32:06\"\n [..]\n }\n}\n
To do such a REST call, you need to create a REST sensor:
sensor:\n\n- platform: rest\n name: \"Gasmeter JSON\" \n resource: http://<IP>/json\n json_attributes:\n - main\n value_template: '{{ value_json.value }}'\n headers:\n Content-Type: application/json\n scan_interval: 60\n\ntemplate:\n sensor:\n - name: \"Gasmeter Value from JSON\"\n unique_id: gas_meter_value_from_json\n state: \"{{ state_attr('sensor.gasmeter_json','main')['value'] }}\"\n unit_of_measurement: 'm\u00b3'\n\n - name: \"Watermeter Value from JSON\"\n unique_id: water_meter_value_from_json\n state: >-\n {{ state_attr('sensor.watermeter_json','main')['value'] | float }}\n unit_of_measurement: 'm\u00b3'\n device_class: water\n state_class: total_increasing\n icon: mdi:gauge\n
The 2nd way is to use the html api call from value.html :
sensor: - platform: rest resource: http://<IP>/value.html name: cold_water unique_id: cold_water_from_rest unit_of_measurement: \"L\" device_class: water state_class: total_increasing icon: mdi:gauge scan_interval : 120
See also https://community.home-assistant.io/t/rest-sensor-nested-json/243420/9
"},{"location":"Integration-Home-Assistant/#photo","title":"Photo","text":"REST can also be used to show the photo of the last round:
To access it, use http://<IP>/img_tmp/alg_roi.jpg resp http://<IP>/img_tmp/raw.jpg.
"},{"location":"Learn-models-with-your-own-images/","title":"Learn a model with your own images","text":"Once you have collected and selected your own images (see Collect images to improve the models), you can train your very own model with them.
This is an optional step and only suggested for advances users!
For training the model you will need a python and Jupyter installation.
All current labeled images you can find under ziffer_sortiert_raw
"},{"location":"Learn-models-with-your-own-images/#dig-class11-models-digits","title":"dig-class11 models (digits)","text":"Fork and checkout neural-network-digital-counter-readout.
Install all requirements for running the notebooks.
pip install -r requirements.txt\n
Put your labeled images into /ziffer_sortiert_raw folder and run
- Image_Preparation.ipynb
- Train_CNN_Digital-Readout-Small-v2.ipynb
It creates a dig-class11_xxxx_s2.tflite model, you can upload to the config folder on your device and test it.
"},{"location":"Learn-models-with-your-own-images/#dig-class100-dig-cont-models-digits","title":"dig-class100 / dig-cont models (digits)","text":"Fork and checkout neural-network-digital-counter-readout.
All labeled images you can find under Images
Install all requirements for running the notebooks.
pip install -r requirements.txt\n
Put your labeled images into images/collected/<typeofdevice>/<your_short>/
Run dig-class100-s2.ipynb. The model to upload to your device you can find under '/output'.
"},{"location":"Learn-models-with-your-own-images/#ana-class100ana-cont-models-analog-pointers","title":"ana-class100/ana-cont models (analog pointers)","text":"Fork and checkout neural-network-analog-needle-readout.
All labeled images you can find under data_raw_all
Install all requirements for running the notebooks.
pip install -r requirements.txt\n
Put your labeled images into images/collected/<typeofdevice>/<your_short>/
After every adding of images you need to run Image_Preparation.ipynb before you train the models.
Run Train_CNN_Analog-Readout_100-Small1_Dropout.ipynb and/or Train_CNN_Analog-Readout_Version-Small2.ipynb. The model to upload to your device you can find in the project folder.
"},{"location":"Learn-models-with-your-own-images/#share-your-images","title":"Share your images","text":"If the results are good you can share the images as pull-request. Please images only!
See Share your images for details.
"},{"location":"MQTT-API/","title":"MQTT API","text":"The device is capable to register to a MQTT broker to publish data and subscribe to specific topics.
Note
Only MQTT v3.1.1 is supported.
The MQTT service has to be enabled and configured properly in the device configuration via web interface (Settings -> Configuration -> section MQTT)
The following parameters have to be defined: * URI * MainTopic (optional, if not set, the hostname is used) * ClientID (optional, if not set, AIOTED- + the MAC address gets used to make sure the ID is unique) * User (optional) * Password (optional) * RetainFlag (optional)
"},{"location":"MQTT-API/#published-topics","title":"Published topics","text":""},{"location":"MQTT-API/#status","title":"Status","text":"The following overhead data are available under the main topic (i.e. watermeter):
Topic Description watermeter/MAC The MAC address of the ESP module. watermeter/IP The IP address of the ESP module. watermeter/Hostname The network host name of the ESP module. watermeter/Interval The round interval as configured during setup or in Parameters -> Interval. watermeter/Connection Network connection status. watermeter/Uptime Seconds up since last boot. watermeter/FreeMem Free memory in kB. watermeter/wifiRSSI Quality of WiFi signal. watermeter/CPUTemp Temperature of the ESP CPU in degrees celsius."},{"location":"MQTT-API/#result","title":"Result","text":"The following calculation data are available under the sup-topic main (i.e. watermeter/main):
Topic Description watermeter/main/error Informs about the flow status. On success, the value is no error. watermeter/main/raw The value before performing post processing. watermeter/main/value The value after performing post processing. watermeter/main/rate How much flow was consumed in one minute. watermeter/main/rate_per_time_unit How much flow was consumed in one minute. The time unit gets set with the Home Assistant Discovery, e.g. h (hours) or m (minutes). watermeter/main/changeabsolut Difference between the previous and actual read value. watermeter/main/rate_per_digitization_round How much flow was consumed in one minute. watermeter/main/timestamp Timestamp of the last valid reading (equal to timestamp of previous value) watermeter/main/Status Informs about the last performed step of the watermeter (i.e. Flow finished). watermeter/main/json This is a JSON formatted object containing the following values: value, raw, pre, error, rate, timestamp."},{"location":"MQTT-API/#gpio","title":"GPIO","text":"MainTopic/{GPIO topic}, e.g. watermeter/GPIO/GPIO12
"},{"location":"MQTT-API/#gpiogpiopinnumber","title":"GPIO/GPIO{PinNumber}","text":"Depending on device configuration (Settings --> Configuration --> section GPIO)
"},{"location":"MQTT-API/#subscribed-topics","title":"Subscribed topics","text":"MainTopic/{subscribed topic}, e.g. watermeter/ctrl/flow_start
"},{"location":"MQTT-API/#control","title":"Control","text":""},{"location":"MQTT-API/#ctrlflow_start","title":"ctrl/flow_start","text":"Trigger a flow start by publishing to this topic.
This will automatically reset the flow interval.
"},{"location":"MQTT-API/#ctrlset_prevalue","title":"ctrl/set_prevalue","text":"Note
This feature is available since version 15.2.0.
Set the last valid value (previous value) to given value or the actual RAW value. Payload needs to be provided in JSON notation.
Payload:
-
Set to given value (value >= 0): {\"numbersname\": \"<NUMBERSNAME>\", \"value\": <VALUE>}
\"numbersname\":Provide name of number sequence, e.g. \"main\" \"value\": provide the value to be set, eg. 12345.67890
-
Set to actual RAW value (value < 0, a valid RAW value is mandatory): {\"numbersname\": \"<NUMBERSNAME>\", \"value\": -1}
\"numbersname\": Provide name of number sequence, e.g. \"main\" \"value\": Provide any negative number
"},{"location":"MQTT-API/#gpiogpiopinnumber_1","title":"GPIO/GPIO{PinNumber}","text":"Depending on device configuration (Settings --> Configuration --> section GPIO)
"},{"location":"Neural-Network-Types/","title":"Neural Network Types","text":"Note
For an overview, see Choosing the Model.
This section is describing the different types of neural networks, that are used with the AI-on-the-edge approach and gives an introduction on how and where to use them.
"},{"location":"Neural-Network-Types/#overview-neural-network-type","title":"Overview neural network type","text":"There are two types of input:
There are two types of neural networks:
- classification networks with discrete output neurons for each result class:
- 11 classes for digits (0, 1, ... 8, 9 + \"Not-A-Number\")
- 100 classes for digits or analog pointers (0.1, 0.2, 0.3, ... , 9.7, 9.8, 9.9)
- continuous output networks with a continuous output in the interval [0, 10[
No setting of the type in the firmware is necessary. The type can detect by the output structure automatically.
Warning
- It is very important to choose the right network type (digits or analog pointers). Technically a wrong network will work and create output, but that would be totally arbitrary
- Not all type of pointers are trained in all networks.
- For the 11 classes digits network there many different types of digits trained. The reason is, that you 1) only need 20-30 training images and 2) the data collection is ongoing much longer
- For the continuous and 100 classes network especially for the digits, there are only a few types of digits trained up to now
- Therefore sometimes for the digits it is more effective to choose the simpler 11 classes network type (= default).
"},{"location":"Neural-Network-Types/#naming-convention","title":"Naming convention","text":"Classification11 classes0, 1, ... 9 + \"N\" Classification100 classes0.0, 0.1, ... 9.9 ContinuousInterval[0, 10[ Digits dig-class11_XXX.tflite dig-class100_XXX.tflite dig-cont_XXX.tflite Analog Pointers ana-class100_XXX.tflite ana-cont_XXX.tflite XXX contains the versioning and a parameter for different sizes with the following naming:
XXX = versioning_sY
-
versioning = version or in newer networks the training data
-
Y = Neural network size (typically s1, s2, ..., s4). Whereas s1 is the maximum sized neural network and s4 is the smallest.
Optional the naming ends with an \"_q\" to signal, that the tflite file has been quantized (size reduction with minimum accuracy loss).
Example: dig-class11_1410_s2_q.tflite
- Classification network for digits with 11 classes (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, N)
- Version 1410 = 14.1.0
- s2 = Size 2 (Medium)
- q = Quantized Version
"},{"location":"Neural-Network-Types/#overview-of-trained-types-and-details","title":"Overview of trained types and details","text":""},{"location":"Neural-Network-Types/#analog-pointer-ana-cont_xxxtflite-ana-class100_xxxtflite","title":"Analog Pointer (\"ana-cont_XXX.tflite\" & \"ana-class100_XXX.tflite\")","text":"This is to transfer the direction of a pointer into a continuous number between 0 and 1, whereas 0 (=1) is the upwards position (12 o'clock), 0.25 corresponds to the 3 o'clock positions and so on. This network is a envelop for all different types of pointers. Currently there are no dedicated network trainings for specific types of pointers.
There are two types of network structure, currently both are supported. The \"class100\" is a pure classification network, that might need a bit more accuracy in the labeling. \"cont\" is a no classic approach with a continuous output off only 2 neurons (details see below).
"},{"location":"Neural-Network-Types/#types-of-counters-trained","title":"Types of counters trained:","text":""},{"location":"Neural-Network-Types/#training-data-needs","title":"Training data needs","text":" - Quadratic images, minimum size: 32x32 pixel
- Typically 100 - 200 images with a resolution of 1/100 of the full rotation (every 0.1 value or 3.6\u00b0)
- Naming: x.y_ARBITRARY.jpg, where x.y = value 0.0 ... 9.9
"},{"location":"Neural-Network-Types/#cnn-technical-details","title":"CNN Technical details:","text":""},{"location":"Neural-Network-Types/#input","title":"Input","text":""},{"location":"Neural-Network-Types/#output","title":"Output","text":""},{"location":"Neural-Network-Types/#digits-with-11-classes-dig-class11_xxxtflite","title":"Digits with 11 classes (\"dig-class11_XXX.tflite\")","text":"The digit type is a classical classification network, with 11 classes representing the numbers 0, 1, ... 9 and the special class \"N\". It is trained for the rolling ring of gas and electric meters. As there is sometime a status between two images, the special class \"N\" is representing Not-A-Number for the case, that the image cannot be unique classified to one number e.g. because it is between two digits. For this type the lowest amount of training data per type is needed, resulting in a large variety of type being already part of the training set.
"},{"location":"Neural-Network-Types/#types-of-counters-trained_1","title":"Types of counters trained:","text":""},{"location":"Neural-Network-Types/#training-data-needs_1","title":"Training data needs","text":" - RGB images, with minimum size: 20x32 pixel
-
Typically 10 - 20 images (1-2 for each digit and an arbitrary number for the \"N\" class
-
Naming: x_ARBITRARY.jpg, where x = value 0 ... 9 + N
"},{"location":"Neural-Network-Types/#cnn-technical-details_1","title":"CNN Technical details:","text":""},{"location":"Neural-Network-Types/#input_1","title":"Input","text":""},{"location":"Neural-Network-Types/#output_1","title":"Output","text":" - 11 neurons for image classification (last layer normalized to 1)
- Neuron 0 to 9 represent the corresponding numbers \"0\" to \"9\"
- Neuron 10 represents the \"Not-A-Number\" class, telling, that the image is not uniquely classified
"},{"location":"Neural-Network-Types/#digits-with-rolling-results-dig-class100_xxxtflite-dig-cont_xxxtflite","title":"Digits with rolling results (\"dig-class100_XXX.tflite\" & \"dig-cont_XXX.tflite\")","text":"This type of network tries to overcome the problem, that there are intermediate values, when a rolling digit is between two numbers. Previous this was the \"N\" class. In this network type, there are also sub-digit values trained, so that the intermediate state can be used as additional information for the algorithms.
"},{"location":"Neural-Network-Types/#types-of-counters-trained_2","title":"Types of counters trained:","text":""},{"location":"Neural-Network-Types/#training-data-needs_2","title":"Training data needs","text":" - RGB images, with minimum size: 20x32 pixel
-
Typically 100 - 200 images (1-2 for each possible position)
-
Naming: x.y_ARBITRARY.jpg, where x.y = 0.0, 0.1, ... 9.9 representing the intermediate state
"},{"location":"Neural-Network-Types/#cnn-technical-details_2","title":"CNN Technical details:","text":""},{"location":"Neural-Network-Types/#input_2","title":"Input","text":""},{"location":"Neural-Network-Types/#output_2","title":"Output","text":""},{"location":"New-Releases-Notification/","title":"Notification about new Releases","text":"Do you want to get notified about a new release? There are several ways for it:
"},{"location":"New-Releases-Notification/#github-notifications","title":"Github Notifications","text":"You will need a Github Account for this!
- Log into your Github account on Github.
- Go to AI-on-the-edge-device.
- On the top right side, click onto
Watch and select Custom: - Select
Releases.
You will get an email when a new release gets created.
See also Github Documentation.
"},{"location":"New-Releases-Notification/#codereleaseio","title":"CodeRelease.io","text":"Alternatively or if you do not want to create a Github account, CodeRelease.io can be an alternative.
You also have to subscribe with an email address but no account is required.
"},{"location":"Parameters/","title":"Parameters","text":"This page lists all available Configuration Parameters. If a parameter or section has a tick box on its left side, you can disable it. In such case the functionality gets disabled respectively the default values will be used.
Note
This is an auto-generated page! See the README for details!
"},{"location":"Parameters/#section-takeimage","title":"Section TakeImage","text":""},{"location":"Parameters/#parameter-camaelevel","title":"Parameter CamAeLevel","text":"Auto-Exposure-Level
range on OV2640 (-2 .. 2) range on OV3660 and OV5640 (-5 .. 5)
Section: TakeImage
Default Value: 0
See here for the ov2640 camera datasheet. See here for the ov5640 camera datasheet.
Warning
This is an Expert Parameter! Only change it if you understand what it does!
After changing this parameter you need to update your reference image and alignment markers!
Note
The exposure offset for automatic exposure, lower values produce darker image.
Note
This parameter can also be set on the Reference Image configuration page!
"},{"location":"Parameters/#parameter-camaec","title":"Parameter CamAec","text":"Auto-Exposure-Control
- When true, the camera attempts to automatically control the exposure.
- When false, the CamAecValue setting is used instead.
Section: TakeImage
Default Value: true
See here for the ov2640 camera datasheet. See here for the ov5640 camera datasheet.
Warning
This is an Expert Parameter! Only change it if you understand what it does!
After changing this parameter you need to update your reference image and alignment markers!
Note
This parameter can also be set on the Reference Image configuration page!
"},{"location":"Parameters/#parameter-camaec2","title":"Parameter CamAec2","text":"Auto-Exposure-Control2
- When true, the sensor\u2019s \"night mode\" is enabled, extending the range of automatic gain control.
- When false, the sensor\u2019s \"night mode\" is disabled.
Section: TakeImage
Default Value: true
See here for the ov2640 camera datasheet. See here for the ov5640 camera datasheet.
Warning
This is an Expert Parameter! Only change it if you understand what it does!
After changing this parameter you need to update your reference image and alignment markers!
Note
This may resolve some over-exposure and under-exposure issues.
Note
This parameter can also be set on the Reference Image configuration page!
"},{"location":"Parameters/#parameter-camaecvalue","title":"Parameter CamAecValue","text":"Auto-Exposure-Value
Range (0 .. 1200)
Section: TakeImage
Default Value: 160
See here for the ov2640 camera datasheet. See here for the ov5640 camera datasheet.
Warning
This is an Expert Parameter! Only change it if you understand what it does!
After changing this parameter you need to update your reference image and alignment markers!
Note
Access the exposure value of the camera, higher values produce brighter images.
Note
This parameter can also be set on the Reference Image configuration page!
"},{"location":"Parameters/#parameter-camagc","title":"Parameter CamAgc","text":"Auto-Gain-Control
- When true, the camera attempts to automatically control the sensor gain, up to the value in the CamGainceiling property.
- When false, the CamAgcGain setting is used instead.
Section: TakeImage
Default Value: true
See here for the ov2640 camera datasheet. See here for the ov5640 camera datasheet.
Warning
This is an Expert Parameter! Only change it if you understand what it does!
After changing this parameter you need to update your reference image and alignment markers!
"},{"location":"Parameters/#parameter-camagcgain","title":"Parameter CamAgcGain","text":"Auto-Gain-Control-Value
Range (0 .. 30)
Section: TakeImage
Default Value: 15
See here for the ov2640 camera datasheet. See here for the ov5640 camera datasheet.
Warning
This is an Expert Parameter! Only change it if you understand what it does!
After changing this parameter you need to update your reference image and alignment markers!
Note
This is used when CamAgc is off.
Note
Access the gain level of the sensor, higher values produce brighter images.
"},{"location":"Parameters/#parameter-camautosharpness","title":"Parameter CamAutoSharpness","text":"Auto-Sharpness
- When true, the camera attempts to automatically adjusts the sharpness.
- When false, the CamSharpness setting is used instead.
Section: TakeImage
Default Value: false
See here for the ov2640 camera datasheet. See here for the ov5640 camera datasheet.
Warning
This is an Expert Parameter! Only change it if you understand what it does!
After changing this parameter you need to update your reference image and alignment markers!
Note
The OV2640 does not officially support auto sharpness, this is an experimental parameter!
Note
This parameter can also be set on the Reference Image configuration page!
"},{"location":"Parameters/#parameter-camawb","title":"Parameter CamAwb","text":"Auto-White-Balance
- When true, the camera attempts to automatically control white balance.
- When false, the CamWbMode setting is used instead.
Section: TakeImage
Default Value: true
See here for the ov2640 camera datasheet. See here for the ov5640 camera datasheet.
Warning
This is an Expert Parameter! Only change it if you understand what it does!
After changing this parameter you need to update your reference image and alignment markers!
"},{"location":"Parameters/#parameter-camawbgain","title":"Parameter CamAwbGain","text":"Auto-White-Balance-Gain
- Enable/Disable CamAwbGain control.
Section: TakeImage
Default Value: true
See here for the ov2640 camera datasheet. See here for the ov5640 camera datasheet.
Warning
This is an Expert Parameter! Only change it if you understand what it does!
After changing this parameter you need to update your reference image and alignment markers!
"},{"location":"Parameters/#parameter-cambpc","title":"Parameter CamBpc","text":"Black-Pixel-Correction
- Enable/Disable black point compensation, this can make black parts of the image darker.
Section: TakeImage
Default Value: true
See here for the ov2640 camera datasheet. See here for the ov5640 camera datasheet.
Warning
This is an Expert Parameter! Only change it if you understand what it does!
After changing this parameter you need to update your reference image and alignment markers!
"},{"location":"Parameters/#parameter-cambrightness","title":"Parameter CamBrightness","text":"Image-Brightness
Range (-2 .. 2)
Section: TakeImage
Default Value: 0
See here for the ov2640 camera datasheet. See here for the ov5640 camera datasheet.
Warning
After changing this parameter you need to update your reference image and alignment markers!
Note
This parameter can also be set on the Reference Image configuration page!
"},{"location":"Parameters/#parameter-camcolorbar","title":"Parameter CamColorbar","text":"Colorbar
currently not implemented.
Section: TakeImage
Default Value: false
See here for the ov2640 camera datasheet. See here for the ov5640 camera datasheet.
Warning
This is an Expert Parameter! Only change it if you understand what it does!
"},{"location":"Parameters/#parameter-camcontrast","title":"Parameter CamContrast","text":"Image-Contrast
Range (-2 .. 2)
Section: TakeImage
Default Value: 0
See here for the ov2640 camera datasheet. See here for the ov5640 camera datasheet.
Warning
After changing this parameter you need to update your reference image and alignment markers!
Note
This parameter can also be set on the Reference Image configuration page!
"},{"location":"Parameters/#parameter-camdcw","title":"Parameter CamDcw","text":"Image-Downsize
- When CamDcw is on, the image that you receive will be the size that you requested (VGA, QQVGA, etc).
- When CamDcw is off, the image that you receive will be one of UXGA, SVGA, or CIF.
Section: TakeImage
Default Value: true
See here for the ov2640 camera datasheet. See here for the ov5640 camera datasheet.
Warning
This is an Expert Parameter! Only change it if you understand what it does!
After changing this parameter you need to update your reference image and alignment markers!
If CamZoom is used, this must be activated.
Note
If CamDcw is off, and you pick a different image size, this implicitly turns CamDcw back on again.
"},{"location":"Parameters/#parameter-camdenoise","title":"Parameter CamDenoise","text":"Image-Denoise
- Denoise Image, is only supported by OV3660 and OV5640
range on OV3660 and OV5640 (0 .. 8)
Section: TakeImage
Default Value: 0
See here for the ov2640 camera datasheet. See here for the ov5640 camera datasheet.
Warning
This is an Expert Parameter! Only change it if you understand what it does!
"},{"location":"Parameters/#parameter-camgainceiling","title":"Parameter CamGainceiling","text":"Gain-Ceiling
Available options:
x2 x4 x8 x16 x32 x64 x128
Default Value for ov2640: x4 Default Value for ov5640: x8
See here for the ov2640 camera datasheet. See here for the ov5640 camera datasheet.
Warning
This is an Expert Parameter! Only change it if you understand what it does!
After changing this parameter you need to update your reference image and alignment markers!
Note
A higher gain means that the sensor has a greater response to light, but also makes sensor noise more visible.
This is used when CamAgc is on.
Note
The Gain is an analog multiplier applied to the raw sensor data. The Ceiling is the maximum gain value that the sensor will use.
"},{"location":"Parameters/#parameter-camhmirror","title":"Parameter CamHmirror","text":"Mirror-Image
- When true, the camera image is mirrored left-to-right.
Section: TakeImage
Default Value: false
See here for the ov2640 camera datasheet. See here for the ov5640 camera datasheet.
Warning
After changing this parameter you need to update your reference image and alignment markers!
Note
This parameter can also be set on the Reference Image configuration page!
"},{"location":"Parameters/#parameter-camlenc","title":"Parameter CamLenc","text":"Lens-Correction
- Enable/Disable lens correction.
Section: TakeImage
Default Value: true
See here for the ov2640 camera datasheet. See here for the ov5640 camera datasheet.
Warning
This is an Expert Parameter! Only change it if you understand what it does!
After changing this parameter you need to update your reference image and alignment markers!
Note
This can help compensate for light fall-off at the edge of the sensor area.
"},{"location":"Parameters/#parameter-camquality","title":"Parameter CamQuality","text":"Image-Quality
Range (8 .. 63)
Section: TakeImage
Default Value: 10
See here for the ov2640 camera datasheet. See here for the ov5640 camera datasheet.
Warning
This is an Expert Parameter! Only change it if you understand what it does!
After changing this parameter you need to update your reference image and alignment markers!
Value below 10 could result in system instabilities!
Note
Quality index for pictures: 8 (highest quality) ... 63 (lowest quality)
This is similar to the quality setting when exporting a jpeg image from photo editing software.
"},{"location":"Parameters/#parameter-camrawgma","title":"Parameter CamRawGma","text":"Raw-Gamma
- Enable/Disable raw gamma mode.
Section: TakeImage
Default Value: true
See here for the ov2640 camera datasheet. See here for the ov5640 camera datasheet.
Warning
This is an Expert Parameter! Only change it if you understand what it does!
After changing this parameter you need to update your reference image and alignment markers!
Note
The main purpose of the Gamma (GMA) function is to compensate for the non-linear characteristics of the sensor. GMA converts the pixel values according to the Gamma curve to compensate the sensor output under different light strengths. The non-linear gamma curve is approximately constructed with different linear functions. Raw gamma compensates the image in the RAW domain.
"},{"location":"Parameters/#parameter-camsaturation","title":"Parameter CamSaturation","text":"Image-Saturation
Range (-2 .. 2)
Section: TakeImage
Default Value: 0
See here for the ov2640 camera datasheet. See here for the ov5640 camera datasheet.
Warning
After changing this parameter you need to update your reference image and alignment markers!
Note
Positive values increase saturation (more vibrant colors), negative values lower it (more muted colors).
Note
This parameter can also be set on the Reference Image configuration page!
"},{"location":"Parameters/#parameter-camsharpness","title":"Parameter CamSharpness","text":"Image-Sharpness
Range (-2 .. 2)
Section: TakeImage
Default Value: 0
See here for the ov2640 camera datasheet. See here for the ov5640 camera datasheet.
Warning
This is an Expert Parameter! Only change it if you understand what it does!
After changing this parameter you need to update your reference image and alignment markers!
Note
The OV2640 does not officially support sharpness, this is an experimental parameter!
Note
Positive values increase sharpness (more defined edges), negative values lower it (softer edges).
This is used when CamAutoSharpness is off.
Note
This parameter can also be set on the Reference Image configuration page!
"},{"location":"Parameters/#parameter-camspecialeffect","title":"Parameter CamSpecialEffect","text":"Image-Special-Effect
Available options:
no_effect negative grayscale red green blue retro
Section: TakeImage
Default Value: no_effect
See here for the ov2640 camera datasheet. See here for the ov5640 camera datasheet.
Warning
This is an Expert Parameter! Only change it if you understand what it does!
After changing this parameter you need to update your reference image and alignment markers!
Note
This parameter can also be set on the Reference Image configuration page!
"},{"location":"Parameters/#parameter-camvflip","title":"Parameter CamVflip","text":"Flip-Image
- When true, the camera image is flipped top-to-bottom.
Section: TakeImage
Default Value: false
See here for the ov2640 camera datasheet. See here for the ov5640 camera datasheet.
Warning
After changing this parameter you need to update your reference image and alignment markers!
Note
On some OV5640 Cameras, the image becomes reddish when Vflip is used in conjunction with the zoom function!
Note
This parameter can also be set on the Reference Image configuration page!
"},{"location":"Parameters/#parameter-camwbmode","title":"Parameter CamWbMode","text":"White-Balance-Mode
Available options:
auto sunny cloudy office home
Section: TakeImage
Default Value: auto
See here for the ov2640 camera datasheet. See here for the ov5640 camera datasheet.
Warning
After changing this parameter you need to update your reference image and alignment markers!
Note
This is used when CamAwb is off.
Note
This parameter can also be set on the Reference Image configuration page!
"},{"location":"Parameters/#parameter-camwpc","title":"Parameter CamWpc","text":"White-Pixel-Correction
- Enable/Disable white point compensation, his can make white parts of the image whiter.
Section: TakeImage
Default Value: true
See here for the ov2640 camera datasheet. See here for the ov5640 camera datasheet.
Warning
After changing this parameter you need to update your reference image and alignment markers!
Note
This parameter can also be set on the Reference Image configuration page!
"},{"location":"Parameters/#parameter-camzoom","title":"Parameter CamZoom","text":"Digital-Zoom
- Enable/Disable digital zoom.
Section: TakeImage
Default Value: false
See here for the ov2640 camera datasheet. See here for the ov5640 camera datasheet.
Warning
This is an Expert Parameter! Only change it if you understand what it does!
After changing this parameter you need to update your reference image and alignment markers!
Note
It is always zoomed into the center of the image, if CamZoomOffsetX and CamZoomOffsetY are zero.
Note
This parameter can also be set on the Reference Image configuration page!
"},{"location":"Parameters/#parameter-camzoomoffsetx","title":"Parameter CamZoomOffsetX","text":"Digital-Zoom-OffsetX
range on OV2640 (-480 .. 480) range on OV3660 (-704 .. 704) range on OV5640 (-960 .. 960)
Section: TakeImage
Default Value: 0
See here for the ov2640 camera datasheet. See here for the ov5640 camera datasheet.
Warning
This is an Expert Parameter! Only change it if you understand what it does!
After changing this parameter you need to update your reference image and alignment markers!
Note
X displacement of the image from the center. Positive values \u200b\u200bshift the image to the right, negative values \u200b\u200bto the left. The maximum possible offset depends on the value of the CamZoomSize.
Note
This parameter can also be set on the Reference Image configuration page!
"},{"location":"Parameters/#parameter-camzoomoffsety","title":"Parameter CamZoomOffsetY","text":"Digital-Zoom-OffsetY
range on OV2640 (-360 .. 360) range on OV3660 (-528 .. 528) range on OV5640 (-720 .. 720)
Section: TakeImage
Default Value: 0
See here for the ov2640 camera datasheet. See here for the ov5640 camera datasheet.
Warning
This is an Expert Parameter! Only change it if you understand what it does!
After changing this parameter you need to update your reference image and alignment markers!
Note
Y displacement of the image from the center. Positive values \u200b\u200bmove the image up, negative values \u200b\u200bmove the image down. The maximum possible offset depends on the value of the CamZoomSize.
Note
This parameter can also be set on the Reference Image configuration page!
"},{"location":"Parameters/#parameter-camzoomsize","title":"Parameter CamZoomSize","text":"Digital-Zoom-Size
range on OV2640 (0 .. 29) range on OV3660 (0 .. 43) range on OV5640 (0 .. 59)
Section: TakeImage
Default Value: 0
See here for the ov2640 camera datasheet. See here for the ov5640 camera datasheet.
Warning
This is an Expert Parameter! Only change it if you understand what it does!
After changing this parameter you need to update your reference image and alignment markers!
Note
Zoom factor/level of the digital zoom, the larger the value, the more it zooms in.
Note
This parameter can also be set on the Reference Image configuration page!
"},{"location":"Parameters/#parameter-demo","title":"Parameter Demo","text":"Enable to use demo images instead of the real camera images. Make sure to have a /demo folder on your SD-Card and make sure it contains the expected files! Check here for details.
Section: TakeImage
Default Value: false
Warning
This is an Expert Parameter! Only change it if you understand what it does!
"},{"location":"Parameters/#parameter-ledintensity","title":"Parameter LEDIntensity","text":"Set the Flash LED Intensity: (0 .. 100)
Section: TakeImage
Default Value: 50
Note
After changing this parameter you need to update your reference image and alignment markers!
Note
This parameter can also be set on the Reference Image configuration page!
"},{"location":"Parameters/#parameter-rawimageslocation","title":"Parameter RawImagesLocation","text":"Location on the SD-Card to store the raw images.
Section: TakeImage
Default Value: /log/source
Warning
A SD-Card has limited write cycles. Since the device does not do Wear Leveling, this can wear out your SD-Card!
"},{"location":"Parameters/#parameter-rawimagesretention","title":"Parameter RawImagesRetention","text":"Number of days to keep the raw images (0 = forever)
Unit: Days
Section: TakeImage
Default Value: 15
"},{"location":"Parameters/#parameter-waitbeforetakingpicture","title":"Parameter WaitBeforeTakingPicture","text":"Waiting time between switching the flash light (onboard LED) on and taking the picture.
Unit: seconds
Section: TakeImage
Default Value: 5
Warning
This is an Expert Parameter! Only change it if you understand what it does!
"},{"location":"Parameters/#section-alignment","title":"Section Alignment","text":""},{"location":"Parameters/#parameter-alignmentalgo","title":"Parameter AlignmentAlgo","text":"Section: Alignment
Default Value: Default
Warning
This is an Expert Parameter! Only change it if you understand what it does!
Algorithm used for the alignment step.
Available options:
Default: Use only red color channel HighAccuracy: Use all 3 color channels (3x slower) Fast: First time use HighAccuracy, then only check if the image is shifted Off: Disable alignment algorithm
"},{"location":"Parameters/#parameter-initialrotate","title":"Parameter InitialRotate","text":"Section: Alignment
Default Value: 0
Unit: Degrees
Note
This parameter can also be set on the Reference Image configuration page!
Note
After changing this parameter you need to update your reference image and alignment markers!
Initial rotation of image before alignment in degree (-360 .. +360)
"},{"location":"Parameters/#parameter-searchfieldx","title":"Parameter SearchFieldX","text":"Section: Alignment
Default Value: 20
Unit: Pixels
Warning
This is an Expert Parameter! Only change it if you understand what it does!
X-size (width) in which the reference is searched.
Note
Since the alignment is one of the steps using a lot of computation time, the search field should be as small as possible. The calculation time goes quadratic with the search field size.
"},{"location":"Parameters/#parameter-searchfieldy","title":"Parameter SearchFieldY","text":"Section: Alignment
Default Value: 20
Unit: Pixels
Warning
This is an Expert Parameter! Only change it if you understand what it does!
Y-size (height) in which the reference is searched.
Note
Since the alignment is one of the steps using a lot of computation time, the search field should be as small as possible. The calculation time goes quadratic with the search field size.
"},{"location":"Parameters/#section-digits","title":"Section Digits","text":""},{"location":"Parameters/#parameter-cnngoodthreshold","title":"Parameter CNNGoodThreshold","text":"Section: Digits
Default Value: 0.5
Warning
This is an Expert Parameter! Only change it if you understand what it does!
Threshold above which the classification should be to accept the value (only meaningful for digits).
Warning
This is only supported for the dig-class100 models!
"},{"location":"Parameters/#parameter-model","title":"Parameter Model","text":"Section: Digits
Default Value: /config/dig-cont_*.tflite (See /config/config.ini)
Path to CNN model file for image recognition. See here for details.
"},{"location":"Parameters/#parameter-roiimageslocation","title":"Parameter ROIImagesLocation","text":"Section: Digits
Default Value: /log/digit
Location to store separated digit images on the SD-Card.
Warning
A SD-Card has limited write cycles. Since the device does not do Wear Leveling, this can wear out your SD-Card!
"},{"location":"Parameters/#parameter-roiimagesretention","title":"Parameter ROIImagesRetention","text":"Section: Digits
Default Value: 3
Unit: Days
Days to keep the separated digit images (0 = forever).
"},{"location":"Parameters/#section-analog","title":"Section Analog","text":""},{"location":"Parameters/#parameter-cnngoodthreshold_1","title":"Parameter CNNGoodThreshold","text":"Section: Analog
Default Value: 0.5
Warning
This is an Expert Parameter! Only change it if you understand what it does!
Threshold above which the classification should be to accept the value (only meaningful for digits).
Warning
This is only supported for the ana-class100 models!
"},{"location":"Parameters/#parameter-extendedresolution","title":"Parameter ExtendedResolution","text":"Warning
This parameter is unused! Use NUMBER.ExtendedResolution instead!
"},{"location":"Parameters/#parameter-model_1","title":"Parameter Model","text":"Section: Analog
Default Value: /config/ana-cont_*.tflite (See /config/config.ini)
Path to CNN model file for image recognition. See here for details.
"},{"location":"Parameters/#parameter-roiimageslocation_1","title":"Parameter ROIImagesLocation","text":"Section: Analog
Default Value: /log/analog
Location to store separated analog images on the SD-Card.
Warning
A SD-Card has limited write cycles. Since the device does not do Wear Leveling, this can wear out your SD-Card!
"},{"location":"Parameters/#parameter-roiimagesretention_1","title":"Parameter ROIImagesRetention","text":"Section: Analog
Default Value: 3
Unit: Days
Days to keep the separated analog images (0 = forever).
"},{"location":"Parameters/#section-postprocessing","title":"Section PostProcessing","text":""},{"location":"Parameters/#parameter-allownegativerates","title":"Parameter AllowNegativeRates","text":"Warning
This parameter is unused! Use NUMBER.AllowNegativeRates instead!
"},{"location":"Parameters/#parameter-errormessage","title":"Parameter ErrorMessage","text":"Section: PostProcessing
Default Value: true
Warning
This is an Expert Parameter! Only change it if you understand what it does!
Do not show error message in return value. In an error case, the last valid number will be used for the various transmission protocols (MQTT, InfluxDB, REST, ...).
"},{"location":"Parameters/#parameter-allownegativerates_1","title":"Parameter AllowNegativeRates","text":"Section: PostProcessing
Default Value: false
Allow a meter to count backwards (decreasing values).
Note
This is unusual (it means there is a negative rate) and not wanted in most cases!
Note
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.
"},{"location":"Parameters/#parameter-analogtodigittransitionstart","title":"Parameter AnalogToDigitTransitionStart","text":"Section: PostProcessing
Default Value: 9.2
This can be used if you have wrong values, but the recognition of the individual ROIs are correct. Look for the start of changing of the first digit and note the analog pointer value behind. Set it here. Only used on combination of digits and analog pointers. See here for details.
Range: 6.0 .. 9.9.
Note
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.
"},{"location":"Parameters/#parameter-changeratethreshold","title":"Parameter ChangeRateThreshold","text":"Section: PostProcessing
Default Value: 2
Range: 0 .. 9.
Threshold parameter for change rate detection. 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.
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
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.
"},{"location":"Parameters/#example","title":"Example","text":" - Smallest ROI provides value for
0.000'x (Eg. a water meter with 4 pointers behind the decimal point) - ChangeRateThreshold = 2
"},{"location":"Parameters/#with-extended-resolution-disabled","title":"With Extended Resolution disabled","text":"PreValue: 123.456'7 -> Threshold = +/-0.000'2. All changes between 123.456'5 and 123.456'9 get ignored
"},{"location":"Parameters/#with-extended-resolution-enabled","title":"With Extended Resolution enabled","text":"PreValue: 123.456'78 -> Threshold = +/-0.000'02. All changes between 123.456'76 and 123.456'80 get ignored.
"},{"location":"Parameters/#parameter-checkdigitincreaseconsistency","title":"Parameter CheckDigitIncreaseConsistency","text":"Section: PostProcessing
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
This parameter must be prefixed with <NUMBER> followed by a dot (eg. main.CheckDigitIncreaseConsistency). <NUMBER> is the name of the number sequence defined in the ROI's.
"},{"location":"Parameters/#parameter-decimalshift","title":"Parameter DecimalShift","text":"Section: PostProcessing
Default Value: 0
Shift the decimal separator (positiv or negativ). Eg. to move from m\u00b3 to liter (1 m\u00b3 equals 1000 liters), you need to set it to +3.
Note
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.
"},{"location":"Parameters/#parameter-extendedresolution_1","title":"Parameter ExtendedResolution","text":"Section: PostProcessing
Default Value: false
Use the decimal place of the last analog counter for increased accuracy.
Note
This parameter is only supported on the *-class* and *-const models! See Choosing-the-Model for details.
Note
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.
"},{"location":"Parameters/#parameter-ignoreleadingnan","title":"Parameter IgnoreLeadingNaN","text":"Section: PostProcessing
Default Value: true
Leading N's will be deleted before further processing. This is only relevant for models which use N! See here for details.
Note
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.
"},{"location":"Parameters/#parameter-maxratetype","title":"Parameter MaxRateType","text":"Section: PostProcessing
Default Value: AbsoluteChange
Defines if the Change Rate is calculated as the difference between the last two readings (AbsoluteChange = difference) or as the difference normalized to the interval (RateChange = difference per minute).
Note
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.
"},{"location":"Parameters/#parameter-maxratevalue","title":"Parameter MaxRateValue","text":"Section: PostProcessing
Default Value: 0,05
Maximum allowed change between two readings, if exceeded the last reading will be rejected. Depending on the settings of <NUMBER>.MaxRateType the MaxRateValue is either treated as the difference between the two measurements (AbsoluteChange = difference) not taking the set time interval into account or as the difference normalized to the interval (RateChange = difference per minute).
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 as610,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
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.
"},{"location":"Parameters/#parameter-prevalueagestartup","title":"Parameter PreValueAgeStartup","text":"Section: PostProcessing
Default Value: 720
Warning
This is an Expert Parameter! Only change it if you understand what it does!
Time in minutes, how long a previous read value is valid after reboot.
"},{"location":"Parameters/#parameter-prevalueuse","title":"Parameter PreValueUse","text":"Section: PostProcessing
Default Value: true
Use the previous value (value from previous round) for consistency checks. This also works through a reboot of the device!
"},{"location":"Parameters/#section-mqtt","title":"Section MQTT","text":""},{"location":"Parameters/#parameter-cacert","title":"Parameter CACert","text":"Section: MQTT
Default Value: \"\"
Example: /config/certs/RootCA.crt.
Warning
This is an Expert Parameter! Only change it if you understand what it does!
Path to the CA certificate file.
This is part of the configuration to enable TLS 1.2 for MQTT.
The CA Certificate is used by the client to validate the broker is who it claims to be. It allows the client to authenticate the server, which is the first part of the MTLS handshake.
Usually there is a common RootCA certificate for the MQTT broker. More information is available here.
For more information on how to create your own certificate, see: mosquitto.org or emqx.com.
Note
This also means that you might have to change the protocol and port in uri to mqtts://example.com:8883!
Only Certificates up to 4096 Bit are supported!
"},{"location":"Parameters/#parameter-clientcert","title":"Parameter ClientCert","text":"Section: MQTT
Default Value: \"\"
Example: /config/certs/client.crt.
Warning
This is an Expert Parameter! Only change it if you understand what it does!
Path to the Client Certificate file.
This is part of the configuration to enable TLS 1.2 for MQTT.
The Client Certificate is used by the client to prove its identity to the server, in conjunction with the Client Key. It is the second part of the MTLS handshake.
Usually there is a one pair of Client Certificate/Key for each client that connects to the MQTT broker. More information is available here.
For more information on how to create your own certificate, see: mosquitto.org or emqx.com.
Note
If set, ClientKey must be set too. This also means that you might have to change the protocol and port in uri to mqtts://example.com:8883!
"},{"location":"Parameters/#parameter-clientid","title":"Parameter ClientID","text":"Section: MQTT
Default Value: watermeter
Client ID used to connect to the MQTT broker. If disabled, the hostname will be used.
"},{"location":"Parameters/#parameter-clientkey","title":"Parameter ClientKey","text":"Section: MQTT
Default Value: \"\"
Example: /config/certs/client.key.
Warning
This is an Expert Parameter! Only change it if you understand what it does!
Path to the Client Key file.
This is part of the configuration to enable TLS 1.2 for MQTT.
The Client Key is used by the client to prove its identity to the server, in conjunction with the Client Certificate. It is the second part of the MTLS handshake.
Usually there is a one pair of Client Certificate/Key for each client that connects to the MQTT broker
For more information on how to create your own certificate, see: mosquitto.org or emqx.com.
Note
If set, ClientCert must be set too. This also means that you might have to change the protocol and port in uri to mqtts://example.com:8883!
"},{"location":"Parameters/#parameter-domoticztopicin","title":"Parameter DomoticzTopicIn","text":"Section: MQTT
Default Value: domoticz/in
Domoticz \"in\" topic as configured on the \"MQTT Client Gateway\" setup page on the Domoticz system. Used to publish counter/s value/s.
Parameter <NUMBER>.DomoticzIDX is required (see below).
"},{"location":"Parameters/#parameter-homeassistantdiscovery","title":"Parameter HomeassistantDiscovery","text":"Section: MQTT
Default Value: true
Enable or disable the Homeassistant Discovery. See here for details about the discovery.
"},{"location":"Parameters/#parameter-maintopic","title":"Parameter MainTopic","text":"Section: MQTT
Default Value: watermeter
MQTT main topic, under which the counters are published.
The single value will be published with the following key: MAINTOPIC/NUMBER/RESULT_TOPIC
With:
NUMBER: The name of the value (a meter might have more than one value). The names get defined in the analog and digit ROI configuration (defaults to main). RESULT_TOPIC: Automatically filled with the right name, eg. value, rate, timestamp, error, ....
The general connection status can be found in MAINTOPIC/CONNECTION. See MQTT Result Topics for a full list of topics.
Note
The main topic is allowed to contain / which can be used to split it into multiple levels, eg. /basement/meters/watermeter/1/ if you have multiple water meters in your basement.
The nodeId for the Home Assistant MQTT Service Discovery must follow the schema <discovery_prefix>/<component>/[<node_id>/]<object_id>/config. The node_id is not configurable but derived from the MainTopic by stripping any but the last topic level. A MainTopic with the value home/basement/watermeter is transformed into the node_id watermeter, resulting in the discovery topic homeassistant/sensor/watermeter/value/config for the current value.
"},{"location":"Parameters/#parameter-metertype","title":"Parameter MeterType","text":"Section: MQTT
Default Value: other
Select the Meter Type so the sensors have the right units in Homeassistant.
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\u00b3, you need to also set it to m\u00b3. 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/min 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/min 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 \u00b0F/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!
"},{"location":"Parameters/#parameter-domoticzidx","title":"Parameter DomoticzIDX","text":"Section: MQTT
Default Value: 0
The Idx number for the counter device. Can be obtained from the devices setup page on the Domoticz system.
Note
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.
"},{"location":"Parameters/#parameter-retainmessages","title":"Parameter RetainMessages","text":"Section: MQTT
Default Value: true
Enable or disable the Retain Flag for all MQTT entries.
Warning
Disabling (set to false) this does not clear the last retained value on the MQTT broker! This must be done manually, see How to Delete Retained Messages in MQTT? and this discussion!
"},{"location":"Parameters/#parameter-uri","title":"Parameter Uri","text":"Section: MQTT
Default Value: mqtt://example.com:1883
URI to the MQTT broker including the port. E.g. mqtt://192.168.1.1:1883.
"},{"location":"Parameters/#parameter-validateservercert","title":"Parameter ValidateServerCert","text":"Section: MQTT
Default Value: true
Warning
This is an Expert Parameter! Only change it if you understand what it does!
Enable or disable the validation of the server certificate CN field.
If enabled (true), the certificate sent by the server is validated using the configured Root CA Certificate file. The server name in uri is compared with the CN field of the server certificate. A connection is only established if they agree. It ensures the origin of the server.
If disabled (false), the ESP32 skipped any validation of server certificate CN field. This reduces the security of TLS and makes the MQTT client susceptible to MITM attacks.
Note
This also means that you might have to change the protocol and port in to mqtts://example.com:8883!
If you use public brokers, is recommended to set this parameter to \"enabled (true)\".
"},{"location":"Parameters/#parameter-password","title":"Parameter password","text":"Section: MQTT
Default Value: PASSWORD
Password for MQTT authentication.
"},{"location":"Parameters/#parameter-user","title":"Parameter user","text":"Section: MQTT
Default Value: USERNAME
Username for MQTT authentication.
"},{"location":"Parameters/#section-influxdb","title":"Section InfluxDB","text":""},{"location":"Parameters/#parameter-database","title":"Parameter Database","text":"Section: InfluxDB
Default Value: ''
Name of the InfluxDB v1 Database into which to publish the values.
Note
See section InfluxDBv2 for InfluxDB v2 support!
"},{"location":"Parameters/#parameter-field","title":"Parameter Field","text":"Section: InfluxDB
Default Value: undefined
Dedicated definition of the field for InfluxDB use for saving in the Influx database (e.g.: \"watermeter/value\").
Note
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.
"},{"location":"Parameters/#parameter-measurement","title":"Parameter Measurement","text":"Section: InfluxDB
Default Value: undefined
Name of the InfluxDB v1 Measurement to use to publish the value.
Note
See section InfluxDBv2 for InfluxDB v2 support!
"},{"location":"Parameters/#parameter-uri_1","title":"Parameter Uri","text":"Section: InfluxDB
Default Value: undefined
URI of the HTTP interface to InfluxDB v1, without trailing slash, e.g. http://192.168.1.1:8086.
Note
See section InfluxDBv2 for InfluxDB v2 support!
"},{"location":"Parameters/#parameter-password_1","title":"Parameter password","text":"Section: InfluxDB
Default Value: undefined
Password for the InfluxDB v1 authentication.
Note
See section InfluxDBv2 for InfluxDB v2 support!
"},{"location":"Parameters/#parameter-user_1","title":"Parameter user","text":"Section: InfluxDB
Default Value: undefined
Username for the InfluxDB v1 authentication.
Note
See section InfluxDBv2 for InfluxDB v2 support!
"},{"location":"Parameters/#section-influxdbv2","title":"Section InfluxDBv2","text":""},{"location":"Parameters/#parameter-bucket","title":"Parameter Bucket","text":"Section: InfluxDBv2
Default Value: ''
Name of the InfluxDB v2 Bucket into which to publish the values.
"},{"location":"Parameters/#parameter-database_1","title":"Parameter Database","text":"Warning
This parameter is unused! Use Basket instead!
"},{"location":"Parameters/#parameter-field_1","title":"Parameter Field","text":"Section: InfluxDBv2
Default Value: undefined
Field for InfluxDB v2 to use for saving.
Note
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.
"},{"location":"Parameters/#parameter-measurement_1","title":"Parameter Measurement","text":"Section: InfluxDBv2
Default Value: undefined
Name of the InfluxDB v2 Measurement to use to publish the value.
"},{"location":"Parameters/#parameter-org","title":"Parameter Org","text":"Section: InfluxDBv2
Default Value: undefined
Organisation (Org) for InfluxDB v2 authentication
"},{"location":"Parameters/#parameter-token","title":"Parameter Token","text":"Section: InfluxDBv2
Default Value: undefined
Token for InfluxDB v2 authentication
"},{"location":"Parameters/#parameter-uri_2","title":"Parameter Uri","text":"Section: InfluxDBv2
Default Value: undefined
URI of the HTTP interface to InfluxDB v2, without trailing slash, e.g. http://192.168.1.1:8086.
"},{"location":"Parameters/#section-gpio","title":"Section GPIO","text":""},{"location":"Parameters/#parameter-io0","title":"Parameter IO0","text":"Section: GPIO
Default Value: input disabled 10 false false
Warning
This is an Expert Parameter! Only change it if you understand what it does!
This parameter can be used to configure the GPIO IO0 pin.
Warning
This pin is only usable with restrictions! It must be disabled when the camera is used. Additionally, it is used to activate Bootloader mode and must therefore be HIGH after a reset!
Parameters:
GPIO 0 state: One of input, input pullup, input pulldown or output. GPIO 0 use interrupt: Enable interrupt trigger GPIO 0 PWM duty resolution: LEDC PWM duty resolution in bit GPIO 0 enable MQTT: Enable MQTT publishing/subscribing GPIO 0 enable HTTP: Enable HTTP write/read GPIO 0 name: MQTT topic name (empty = GPIO0). Allowed characters: a-z, A-Z, 0-9, _, -.
"},{"location":"Parameters/#parameter-io1","title":"Parameter IO1","text":"Section: GPIO
Default Value: input disabled 10 false false
Warning
This is an Expert Parameter! Only change it if you understand what it does!
This parameter can be used to configure the GPIO IO1 pin.
Warning
This pin is by default used for the serial communication as TX pin (USB logging)!
Parameters:
GPIO 1 state: One of input, input pullup, input pulldown or output. GPIO 1 use interrupt: Enable interrupt trigger GPIO 1 PWM duty resolution: LEDC PWM duty resolution in bit GPIO 1 enable MQTT: Enable MQTT publishing/subscribing GPIO 1 enable HTTP: Enable HTTP write/read GPIO 1 name: MQTT topic name (empty = GPIO1). Allowed characters: a-z, A-Z, 0-9, _, -.
"},{"location":"Parameters/#parameter-io12","title":"Parameter IO12","text":"Section: GPIO
Default Value: input-pullup disabled 10 false false
Warning
This is an Expert Parameter! Only change it if you understand what it does!
This parameter can be used to configure the GPIO IO12 pin.
Note
This pin is usable without known restrictions!
Parameters:
GPIO 12 state: One of external-flash-ws281x, input, input pullup, input pulldown or output. GPIO 12 use interrupt: Enable interrupt trigger GPIO 12 PWM duty resolution: LEDC PWM duty resolution in bit GPIO 12 enable MQTT: Enable MQTT publishing/subscribing GPIO 12 enable HTTP: Enable HTTP write/read GPIO 12 name: MQTT topic name (empty = GPIO12). Allowed characters: a-z, A-Z, 0-9, _, -.
"},{"location":"Parameters/#parameter-io13","title":"Parameter IO13","text":"Section: GPIO
Default Value: input-pullup disabled 10 false false
Warning
This is an Expert Parameter! Only change it if you understand what it does!
This parameter can be used to configure the GPIO IO13 pin.
Note
This pin is usable without known restrictions!
Parameters:
GPIO 13 state: One of input, input pullup, input pulldown or output. GPIO 13 use interrupt: Enable interrupt trigger GPIO 13 PWM duty resolution: LEDC PWM duty resolution in bit GPIO 13 enable MQTT: Enable MQTT publishing/subscribing GPIO 13 enable HTTP: Enable HTTP write/read GPIO 13 name: MQTT topic name (empty = GPIO13). Allowed characters: a-z, A-Z, 0-9, _, -.
"},{"location":"Parameters/#parameter-io3","title":"Parameter IO3","text":"Section: GPIO
Default Value: input disabled 10 false false
Warning
This is an Expert Parameter! Only change it if you understand what it does!
This parameter can be used to configure the GPIO IO3 pin.
Warning
This pin is by default used for the serial communication as RX pin (USB logging)!
Parameters:
GPIO 3 state: One of input, input pullup, input pulldown or output. GPIO 3 use interrupt: Enable interrupt trigger GPIO 3 PWM duty resolution: LEDC PWM duty resolution in bit GPIO 3 enable MQTT: Enable MQTT publishing/subscribing GPIO 3 enable HTTP: Enable HTTP write/read GPIO 3 name: MQTT topic name (empty = GPIO3). Allowed characters: a-z, A-Z, 0-9, _, -.
"},{"location":"Parameters/#parameter-io4","title":"Parameter IO4","text":"Section: GPIO
Default Value: built-in-led disabled 10 false false
Warning
This is an Expert Parameter! Only change it if you understand what it does!
This parameter can be used to configure the GPIO IO4 pin.
Warning
This pin is only usable with restrictions! By default, it is used for build-in flash light (onboard LED).
Parameters:
GPIO 4 state: One of built-in-led, input, input pullup, input pulldown or output. GPIO 4 use interrupt: Enable interrupt trigger GPIO 4 PWM duty resolution: LEDC PWM duty resolution in bit GPIO 4 enable MQTT: Enable MQTT publishing/subscribing GPIO 4 enable HTTP: Enable HTTP write/read GPIO 4 name: MQTT topic name (empty = GPIO4). Allowed characters: a-z, A-Z, 0-9, _, -.
"},{"location":"Parameters/#parameter-ledcolor","title":"Parameter LEDColor","text":"Section: GPIO
Default Value: 150 150 150
Color of the attached LEDs to GPIO12 in Red, Green Blue from 0 (full off) .. 255 (full on) (See IO12 parameter).
"},{"location":"Parameters/#parameter-lednumbers","title":"Parameter LEDNumbers","text":"Section: GPIO
Default Value: 2
Number of LEDs on the external LED-stripe attached to GPIO12 (See IO12 parameter).
"},{"location":"Parameters/#parameter-ledtype","title":"Parameter LEDType","text":"Section: GPIO
Default Value: WS2812 Type of the WS2812x which is connected to GPIO12 (See IO12 parameter).
"},{"location":"Parameters/#parameter-maintopicmqtt","title":"Parameter MainTopicMQTT","text":"Section: GPIO
Default Value: wasserzaehler/GPIO
Note
This parameter is not accessible through the Web Interface Configuration Page!
The GPIO Interface is prepared to report it's status and status changes as a MQTT topic. With this parameter you configure the MQTT main topic, under which the status is published. As this parameter is still experimental it can only be set manually in the config.ini itself and has not been tested in detail so far.
"},{"location":"Parameters/#section-autotimer","title":"Section AutoTimer","text":""},{"location":"Parameters/#parameter-autostart","title":"Parameter AutoStart","text":"Section: AutoTimer
Default Value: true
Warning
This parameter is no longer available. The flow is now always enabled. If you want it to be disabled, set an interval which is high enough (eg. 1440 = 24h).
"},{"location":"Parameters/#parameter-interval","title":"Parameter Interval","text":"Section: AutoTimer
Default Value: 5
Unit: Minutes
Interval in which the Flow (Digitization Round) is run. It will run immediately on startup and then the next time after the given interval. If a round takes longer than this interval, the next round gets postponed until the current round completes.
If the flow gets started by a MQTT message or the REST API call, the interval automatically gets reset.
Note
If you want the flow to be disabled, set an interval which is high enough (eg. 1440 = 24h).
"},{"location":"Parameters/#section-datalogging","title":"Section DataLogging","text":""},{"location":"Parameters/#parameter-datafilesretention","title":"Parameter DataFilesRetention","text":"Section: DataLogging
Default Value: 3
Unit: Days
Number of days to keep the data files (0 = forever).
"},{"location":"Parameters/#parameter-datalogactive","title":"Parameter DataLogActive","text":"Section: DataLogging
Default Value: true Activate data logging to the SD-Card.
The files will be stored in /log/data/data_YYYY-MM-DD.csv. See Data Logging for details.
Warning
A SD-Card has limited write cycles. Since the device does not do Wear Leveling, this can wear out your SD-Card!
"},{"location":"Parameters/#section-debug","title":"Section Debug","text":""},{"location":"Parameters/#parameter-loglevel","title":"Parameter LogLevel","text":"Section: Debug
Default Value: 1 (ERROR) Define the log level for the logging to the SD-Card.
Available options:
1: ERROR 2: WARNING 3: INFO 4: DEBUG
As higher the level, as more log messages get written to the SD-Card.
Warning
DEBUG or INFO might damage the SD-Card if enabled long term due to excessive writes to the SD-Card! A SD-Card has limited write cycles. Since the device does not do Wear Leveling, this can wear out your SD-Card!
"},{"location":"Parameters/#parameter-logfilesretention","title":"Parameter LogfilesRetention","text":"Section: Debug
Default Value: 3
Unit: Days
Number of days to keep the log files (0 = forever).
"},{"location":"Parameters/#section-system","title":"Section System","text":""},{"location":"Parameters/#parameter-cpufrequency","title":"Parameter CPUFrequency","text":"Section: System
Default Value: 160
Set the CPU Frequency.
Warning
Setting it to 240 will lead to a faster device, but it will also require a stronger power supply! Additionally, depending on the quality of your ESP32-CAM, it might run unstable!
Possible values:
"},{"location":"Parameters/#parameter-hostname","title":"Parameter Hostname","text":"Section: System
Default Value: undefined
Warning
This is an Expert Parameter! Only change it if you understand what it does!
Hostname for the device. It gets automatically transferred to /wlan.ini on the SD-Card at the next startup.
"},{"location":"Parameters/#parameter-rssithreshold","title":"Parameter RSSIThreshold","text":"Section: System
Default Value: 0
Possible values: -100 .. 0 (0 = disabled).
Warning
This is an Expert Parameter! Only change it if you understand what it does!
This parameter activates a client triggered AP switching functionality (simplified roaming). If actual RSSI value is lower (more negative) than RSSIThreshold, all WIFI channels will be scanned for configured access point SSID. If an access point is in range which has better RSSI value (less negative) than actual RSSI value + 5 dBm, the device is trying to connect to this access point with the better RSSI value.
Note
The RSSI check only gets initiated at the end of each round to avoid any disturbance of processing.
Note
It gets automatically transferred to /wlan.ini on the SD-Card at next startup.
"},{"location":"Parameters/#parameter-setupmode","title":"Parameter SetupMode","text":"Section: System
Default Value: true
Note
This parameter is not accessible through the Web Interface Configuration Page!
Set this parameter to true to stay in the Setup Mode after the next start of the device.
"},{"location":"Parameters/#parameter-timeserver","title":"Parameter TimeServer","text":"Section: System
Default Value: pool.ntp.org
Warning
This is an Expert Parameter! Only change it if you understand what it does!
Time server to synchronize system time. If it is disabled or undefined, pool.ntp.org will be used. You can also set it to the IP of your router. Many routers like Fritzboxes can act as a local NTP server. To disable NTP, you need to activate it but set the TimeServer config to be empty (\"\"). In such case the time always starts at 01.01.1970 after each power cycle!
"},{"location":"Parameters/#parameter-timezone","title":"Parameter TimeZone","text":"Section: System
Default Value: CET-1CEST,M3.5.0,M10.5.0/3
Time zone in POSIX syntax (Europe/Berlin = CET-1CEST,M3.5.0,M10.5.0/3 - incl. daylight saving) Check the table on http://<DEVICE IP>/timezones.html to find the settings for your region.
"},{"location":"Parameters/#section-webhook","title":"Section Webhook","text":""},{"location":"Parameters/#parameter-apikey","title":"Parameter ApiKey","text":"Section: Webhook
Default Value: undefined
ApiKey sent as Header
"},{"location":"Parameters/#parameter-uploadimg","title":"Parameter UploadImg","text":"Section: Webhook
Default Value: 0 (NEVER)
Available options:
0: NEVER 1: ALWAYS 2: ON_ERROR
"},{"location":"Parameters/#parameter-uri_3","title":"Parameter Uri","text":"Section: Webhook
Default Value: undefined
URI of the HTTP Endpoint receiving requests, e.g. http://192.168.1.1/watermeter/webhook.
"},{"location":"Password-Protection/","title":"Password Protection","text":"The Web Interface and the REST API can be protected by a password.
To do so, you have to set the username and password in the wlan.ini file on the SD-Card. Uncomment (remove the leading ;) and update the two lines with http_username and http_password:
http_username = \"myusername\"\nhttp_password = \"mypassword\"\n
Warning
This is be a WEAK and INSECURE way to protect the Web Interface and the REST API. There was no audit nor a security review to check the correct implementation of the protection! The password gets transmitted unencrypted (plain text), this means it is very easy to extract it for somebody who has access to your WIFI!
USE AT YOUR OWN RISK!
Notes
The file wlan.ini file on the SD-Card can not be accessed through the Web interface.
"},{"location":"REST-API/","title":"REST API","text":"Various information is directly accessible over specific REST calls.
To use it, just append them to the IP, separated with a /, e.g. http://192.168.1.1/json
Note
For more detailed information to the REST handler, have a look to the code in the repository: registered handlers
"},{"location":"REST-API/#control","title":"Control","text":""},{"location":"REST-API/#flow_start","title":"flow_start","text":"Trigger the next flow + Payload: - No payload needed
This will automatically reset the flow interval.
"},{"location":"REST-API/#setprevalue","title":"setPreValue","text":"Set the last valid value (previous value) to given value or the actual RAW value. + Payload: - Set to given value (value >= 0), e.g. /setPreValue?numbers=main&value=1234.5678 * numbers= Provide name of number sequence, e.g. main * value= provide the value to be set
- Set to actual RAW value (value < 0, a valid RAW value is mandatory), e.g. `/setPreValue?numbers=main&value=-1`\n * `numbers=` Provide name of number sequence, e.g. main\n * `value=` provide yna negative number\n
"},{"location":"REST-API/#gpio","title":"GPIO","text":" -
Control a GPIO output
- The
GPIO entrypoint also support parameters: /GPIO?GPIO={PinNumber}&Status=high /GPIO?GPIO={PinNumber}&Status=low - Example:
/GPIO?GPIO=12&Status=high
-
Read a GPIO input
- The
GPIO entrypoint also support parameters: /GPIO?GPIO={PinNumber} - Example:
/GPIO?GPIO=12
"},{"location":"REST-API/#reboot","title":"reboot","text":"Trigger a reboot of the device
"},{"location":"REST-API/#mqtt_publish_discovery","title":"mqtt_publish_discovery","text":"Trigger re-sending of the Home Assistant discovery topics. The topics will get send at the end of the next round.
"},{"location":"REST-API/#results","title":"Results","text":""},{"location":"REST-API/#json","title":"json","text":"Show result in JSON syntax - Example: { \"main\": { \"value\": \"521.17108\", \"raw\": \"521.17108\", \"pre\": \"521.17108\", \"error\": \"no error\", \"rate\": \"0.023780\", \"timestamp\": \"2023-01-13T16:00:42+0100\" } }
"},{"location":"REST-API/#value","title":"value","text":"Show single result values - The value entrypoint also support parameters: - http://<IP>/value?all=true&type=value - http://<IP>/value?all=true&type=raw - http://<IP>/value?all=true&type=error - http://<IP>/value?all=true&type=prevalue
"},{"location":"REST-API/#img_tmprawjpg","title":"img_tmp/raw.jpg","text":"Capture and show a new raw image
"},{"location":"REST-API/#img_tmpalgjpg","title":"img_tmp/alg.jpg","text":"Show last aligned image
"},{"location":"REST-API/#img_tmpalg_roijpg","title":"img_tmp/alg_roi.jpg","text":"Show last aligned image including ROI overlay
"},{"location":"REST-API/#status","title":"Status","text":""},{"location":"REST-API/#statusflow","title":"statusflow","text":"Show the actual step of the flow incl. timestamp - Example: Take Image (15:56:34)
"},{"location":"REST-API/#rssi","title":"rssi","text":"Show the WIFI signal strength (Unit: dBm) - Example: -51
"},{"location":"REST-API/#cpu_temperature","title":"cpu_temperature","text":"Show the CPU temperature (Unit: \u00b0C) - Example: 38
"},{"location":"REST-API/#sysinfo","title":"sysinfo","text":"Show system infos in JSON syntax - Example: [{\"firmware\": \"\",\"buildtime\": \"2023-01-25 12:41\",\"gitbranch\": \"HEAD\",\"gittag\": \"\",\"gitrevision\": \"af13c68+\",\"html\": \"Development-Branch: HEAD (Commit: af13c68+)\",\"cputemp\": \"64\",\"hostname\": \"WaterMeterTest\",\"IPv4\": \"192.168.xxx.xxx\",\"freeHeapMem\": \"2818330\"}]
"},{"location":"REST-API/#starttime","title":"starttime","text":"Show starttime - Example: 20230113-154634
"},{"location":"REST-API/#uptime","title":"uptime","text":"Show uptime - Example: 0d 00h 15m 50s
"},{"location":"REST-API/#camera","title":"Camera","text":""},{"location":"REST-API/#lighton","title":"lighton","text":"Switch the camera flashlight on
"},{"location":"REST-API/#lightoff","title":"lightoff","text":"Switch the camera flashlight off
"},{"location":"REST-API/#capture","title":"capture","text":"Capture a new image (without flashlight)
"},{"location":"REST-API/#capture_with_flashlight","title":"capture_with_flashlight","text":"Capture a new image with flashlight
"},{"location":"REST-API/#stream","title":"stream","text":"Stream a live video of the camera.
It has a slow refresh rate of only 2 FPS to avoid stressing the system. Flow processing continues to work in the background, albeit possibly a bit slower.
When the flashlight parameter is set, it turns on the flaslight. Both http://<IP>/stream?flashlight=true and http://<IP>/stream?flashlight turn on the flashlight.
LIMITATION: To avoid using extra memory, no additional dedicated stream webserver is implemented for this feature (instead, the web interface server is reused in a kind of \"blocking way\"). This means that either the web interface is fully functional or the stream is active, but not both at the same time. However, this is sufficient for the intended use case.
"},{"location":"REST-API/#save","title":"save","text":"Save a new image to SD card - The save entrypoint also support parameters: - http://<IP>/save?filename=test.jpg&delay=1000
"},{"location":"REST-API/#logs","title":"Logs","text":""},{"location":"REST-API/#log","title":"log","text":"Last part of todays log (last 80 kBytes))
"},{"location":"REST-API/#logfileact","title":"logfileact","text":"Full log of today
"},{"location":"REST-API/#loghtml","title":"log.html","text":"Opens the log html page
"},{"location":"REST-API/#diagnostics","title":"Diagnostics","text":""},{"location":"REST-API/#heap","title":"heap","text":"print relevant memory (heap) information - Example: Heap info: Heap Total: 1888926 | SPI Free: 1827431 | SPI Larg Block: 1802240 | SPI Min Free: 758155 | Int Free: 61495 | Int Larg Block: 55296 | Int Min Free: 36427
"},{"location":"REST-API/#prometheusopenmetrics","title":"Prometheus/OpenMetrics","text":""},{"location":"REST-API/#metrics","title":"metrics","text":"Provides a set of metrics that can be scraped by prometheus. See Prometheus/OpenMetrics for details.
"},{"location":"REST-API/#password-protection","title":"Password Protection","text":"The Web Interface and the REST API can be protected by a password, see Password-Protection.
"},{"location":"ROI-Configuration/","title":"ROIs (Regions of Interest)","text":"Notes
You are using a neural network approach which is trained to fit as many different type of meters as possible. The accuracy will never be 100%. It is normal to see a missing reading once in a while. There are several precautions to detect this. For details see the section PostProcessing on the configuration page.
The most critical components for an accurate detection are:
-
Correct setting of the Regions Of Interest (ROIs) for detection of the image.
This must be done manually for each device/installation!
-
Using a well trained Model.
Have a look on the Digit Counters resp. Analog Needles to check if your types are contained. If your number types are not contained, you should take the effort to record them so we can add them to the training data. See Collect images to improve the models on how to collect new training data.
"},{"location":"ROI-Configuration/#precondition","title":"Precondition","text":"Please make sure to have:
- Setup your camera properly and taken a good Reference Image.
- Selected good Alignment References.
"},{"location":"ROI-Configuration/#define-the-rois","title":"Define the ROIs","text":"For each digit or analog pointer, a ROI must be defined.
You can even have multiple independent Numbers (eg. electerical meters mostly have 2 numbers for the high and low tariff).
Depending if you have only one of those types, you can enable/disable (1) it on the top left corner:
You can switch between the individual ROIs with the Drop down box (2). If you need additional ROIs or delete them you can do this with the control at (3). Like for the Alignment References, you can change the position, size and name of a ROI in the text fields or define them via drag and drop through the mouse button. Make sure the ROIs are in the right order, matching the significance of a digit/analog counter!
Warning
The order of the ROIs defines how the individual digits are combined to the total number. The first ROI is the digit with the highest order (left side), then the second and so on. You can control the order in the selector tab and change it with the buttons \"move Next\" or \"move Previous\".
In most cases digits are ordered equidistantly (have the same distance between each other) and have the same size. Because of this, the Web Interface keeps their sizes and distance the same. If you need individual sizes or distances, untick the settings (4).
In almost all cases the sizes and y values should be identical! The ratio between x and y might need adjustment. But make sure it is the same for all digits.
Same for the analog counters, the sizes should be identical and the x and y as well.
Note
Don't forget to save the settings with \"Save\" and do not reboot at this stage.
"},{"location":"ROI-Configuration/#analog-counters","title":"Analog Counters","text":"For analog counters the ROI setting is rather straight forward as the meter is usually quadratic with a clear center. The circle should exactly fit to the outer size of the meter and the cross should be in the middle of the pointer.
Here is an example with the details for the ROI ana1:
"},{"location":"ROI-Configuration/#digits","title":"Digits","text":"For the Digit Meters it is a little bit more complicated, as there are different options of digit models which can be choosen.
"},{"location":"ROI-Configuration/#correct-size-for-roi","title":"Correct Size for ROI","text":"First of all, choose the right size of the ROI. The configuration of ROIs differs a bit on the selected model (see below).
If you are in the initial setup, the model will be selectable in the next step. By default it is a dig-cont resp. ana-cont model.
In Model Selection you find the differences between the different available models. Pick the one you think fits best your purpose. If you don't get to good result, try another model.
Here we only show the different configuration of the ROIs.
-
Digit Meters with only recognized full digits (0, 1, 2, 3, ... 9)
Suggested Model: dig-class11-*.tfl
Advantage: broad variety of types included in the training.
Disadvantage: partially rotated numbers cannot be detected.
-
Digit Meters with sub-digit resolution (0.0, 0.1, 0.2, .... 9.8, 9.9)
Suggested Model: dig-cont-*.tfl or dig-class100-*.tfl
Advantage: partial numbers can be detected and a better post processing is possible.
Disadvantage: only limited types of meter types are trained due to the high effort for the training data.
"},{"location":"ROI-Configuration/#how-to-setup-the-digit-rois-perfectly","title":"How to setup the digit ROIs perfectly","text":"Details and the corresponding \"perfect\" setting is explained below. For a first run you can choose the following general settings:
- There is an inner and an outer frame for the ROIs.
- Make the inner frame exactly the size of the number.
Example 1 Example 2 \u2714\ufe0f Okay \u274c Not Okay \u274c Not Okay"},{"location":"ROI-Configuration/#setup-using-dig-class11-models","title":"Setup using dig-class11 models","text":"dig-class11 - Models recognize the complete digit only. Here it is not relevant if the ROI fits the Border of the digit window.
For this model, there should be a border of 20% of the image size around the number itself. This border is shown in the ROI setup image by the inner thinner rectangle. This rectangle should fit perfectly around the number when the number has not started to rotate to the next position:
Example 1 Example 2 \u2714\ufe0f Okay \u274c Not Okay \u274c Not Okay If you have perfect alignment and still are not getting satisfying results, most probably your numbers are not part of the training data yet. See Collect images to improve the models on how to collect new training data.
"},{"location":"ROI-Configuration/#setup-using-dig-class100-or-dig-cont-models","title":"Setup using dig-class100 or dig-cont Models","text":"These models recognize the tenths (fractions) between the numbers. Those models require a different ROI setup; the height must be set differently and more accurately.
First, the width can be set like for a dig-class11 model, i.e. 20% margin left and right.
The height of the outer rectangle should be set to the upper and lower edge of the number window. To achieve this, you might need to unlock the aspect ratio:
Here an example:
Example 1 \u2714\ufe0f Okay \u274c Not Okay"},{"location":"ROI-Configuration/#saving","title":"Saving","text":"Once you are done, push Save to persist your setup.
A reboot is required to apply the changed configuration!
"},{"location":"Reference-Image/","title":"Reference Image","text":"Note
The Reference Image is the basis for the coordinate system of the ROIs. Therefore it is very important, to have a well aligned image, that is not rotated.
At first an example image is shown. To define a new reference image push the button \"Create new Reference\" (2) and afterwards \"Take Image\" (2). It might take some seconds for processing, then your actual camera image should be shown. Then play with the provided parameters to get a good result.
"},{"location":"Reference-Image/#focus","title":"Focus","text":"This is the first time, where you have access to the camera image. It most likely is out of focus and not sharp! Ensure a sharp image of the camera by adjusting the focal length of the ESP OV2640 camera.
Note
Try to adjust the focus for the clearest possible image!
In order to use it for reading a meter, the focal-length of the OV2640 camera has to be manipulated. By default it only results in sharp image for distance bigger than around ~40cm which is not ideal for our purpose.
Therefore you need to remove the fixing glue of the OV2640 lens with a sharp knife. After this you can rotate the lens in and out. Rotating it by about a quarter of a turn counterclockwise results in a focus plane shift of about 10cm. You need to figure out your best setting with a little bit of trial and error for your specific environment.
Error
Be very carefully when rotating the lens. Best is to held the camera itself with one hand or a plier and rotate the lens with the other hand. Make sure not to rotate the whole camera as this can damage the ribbon cable!
Warning
This modification will void any warranty, as the sealing of the lens objective is broken!
Warning
This modification will render the camera unsuitable for general, web-cam type applications unless the focal length is changed back to the original setting.
"},{"location":"Reference-Image/#correct-horizontal-alignment","title":"Correct Horizontal Alignment","text":"Ensure an exact horizontal alignment of the number:
\u2714\ufe0f Okay \u274c Not Okay Warning
Updating the reference image also means that all alignment images and ROIs needs to be configured again. Therefore do this step later only with caution.
If everything is done, you can save the result with \"Update Reference Image\" (4).
Note
A reboot is not required at this point of time.
As next you should update the Alignment References.
"},{"location":"Reference-Image/#dealing-with-reflections","title":"Dealing with Reflections","text":"Reflections can be caused by the flash LED and make it hard to provide a reliable detection. There are various ways to deal with them:
- Attach a diffusor in front of the LED, eg. a filt (Filz) or parchment paper. Also white paper can do the job.
- Rotate the ESP-CAM so the LED is on another place.
- Reduce the LED intensity.
- Use external LED stripes, eg
WS2812x.
"},{"location":"Release-creation/","title":"Release Procedure","text":"Follow these steps to create a release:
- Document all relevant changes in the Changelog in the
main branch. To get a list of commits, you can call git log --oneline or check commits/main/. Summarize the relevant changes since the last release. - Wait for the GitHub action to run successfully.
- Test it to see if everything worsk as expected.
- Update the contributors list in the README.md by triggering the Manually update contributors list action.
-
Go to releases/new to create a new release. Fill in a new tag and select \"Create new tag: xxx on publish\". A tag should have the format x.y.z. It is suggested to first select \"Set as a pre-release\" at the bottom.
-
Wait for the GitHub-Action of release creation. After all is done:
- the release should be created
- the artifacts are downloadable from release
- The documented changes were applied to the release
- In case of a full release (not a pre-release), check that the Web Installer shows the right version. If needed, run he action manually: github.com/jomjol/AI-on-the-edge-device/actions/workflows/manual-update-webinstaller.yml.
"},{"location":"StatusLED-BlinkCodes/","title":"Board status LED (blink codes)","text":"This page lists possible blink codes of the red LED located on the ESP32-CAM board, their meaning and possible solutions.
The error code source definition can be found here.
"},{"location":"StatusLED-BlinkCodes/#general-design-approach","title":"General design approach:","text":" - 250ms blink code to identify source
- 500ms defined LED off
- 250ms blink code to identify error / status code
- 1,5s defined LED off to signal repetition
- Repetition blink code: infinite for critical errors and status indication or 2x for warning indication
- e.g. 3x blinks | 500ms LED off | 2x blinks --> error: SD card not found
source source blink count error / warning / status status blink count repeat infinite WLAN_CONN 1 Disconnected (No Access Point) 1 WLAN_CONN 1 Disconnected (Authentication failure) 2 WLAN_CONN 1 Disconnected (Timeout) 3 WLAN_CONN 1 Disconnected (further reasons) 4 WLAN_INIT 2 wlan.ini empty or not readable 1 X WLAN_INIT 2 SSID or password empty 2 X WLAN_INIT 2 WIFI init error (details console) 3 X SDCARD_INIT 3 SD card filesystem mount failed 1 X SDCARD_INIT 3 SD card not found (0x107) 2 X SDCARD_INIT 3 SD card init failed (details console) 3 X SDCARD_CHECK 4 Basic check: file creation/write error 1 X SDCARD_CHECK 4 Basic check: file read/CRC error 2 X SDCARD_CHECK 4 Basic check: file delete error 3 X SDCARD_CHECK 4 Basic check: folder/file presence 4 X CAM_INIT 5 Camera init failed (details console) 1 X CAM_INIT 5 Camera framebuffer check failed 2 PSRAM_INIT 6 RAM init failed: Not found/defective 1 X PSRAM_INIT 6 External SPI RAM < 4MB 2 X PSRAM_INIT 6 Total heap < 4MB 3 X TIME_CHECK 7 Missing time sync (check every round) 1 OTA_OR_AP 8 OTA process ongoing 1 X OTA_OR_AP 8 Soft AP started (for remote config) 2 X FLASHLIGHT N/A LED on when flashlight is on solid, no blink"},{"location":"StatusLED-BlinkCodes/#error-warning","title":"ERROR / WARNING","text":""},{"location":"StatusLED-BlinkCodes/#source-wlan_conn-wlan-disconnected","title":"Source WLAN_CONN: WLAN disconnected","text":"Note
Only warning indication, blink code repetition: 2x --> General info: WLAN disconnect reason code description
"},{"location":"StatusLED-BlinkCodes/#wlan-disconnected-no-access-point","title":"WLAN disconnected (No Access Point)","text":"WLAN connection is interrupted due to no access point in range.
"},{"location":"StatusLED-BlinkCodes/#wlan-disconnected-authentication-failure","title":"WLAN Disconnected (Authentication failure)","text":"WLAN connection is interrupted due to an authentication failure. If error repeats check WLAN config in wlan.ini (username, password)
"},{"location":"StatusLED-BlinkCodes/#wlan-disconnected-timeout","title":"WLAN Disconnected (Timeout)","text":"WLAN connection is interrupted due to an timeout because no beacon from AP is received in a timely manner. Most probably access point is not available anymore or connection is not reliable.
"},{"location":"StatusLED-BlinkCodes/#wlan-disconnected-further-reasons","title":"WLAN Disconnected (Further reasons)","text":"WLAN connection is interrupted due to further reasons. Disconnect reason is printed in warining message. Please check serial console output or logfile from sd card (using another device to retrieve logfile /sdcard/log/message/). Please refer to this page to have additional infos in terms of WLAN disconnect reasons --> WLAN disconnect reason code description
"},{"location":"StatusLED-BlinkCodes/#source-wlan_init-wlan-initialization","title":"Source WLAN_INIT: WLAN initialization","text":"Note
All critical errors, regular boot not possible
"},{"location":"StatusLED-BlinkCodes/#wlanini-empty-or-not-readable","title":"wlan.ini empty or not readable","text":"The wlan.ini file is present but content is either not readable or no content present. Please check for further errors in terms of SD card readability or content of wlan.ini which is located in /sdcard (most top folder od SD card)
"},{"location":"StatusLED-BlinkCodes/#ssid-or-password-empty","title":"SSID or password empty","text":"The mandatory parameters SSID (name of WIFI network) and / or password is empty. Please configure those parameters in wlan.ini and try again.
"},{"location":"StatusLED-BlinkCodes/#wifi-init-error-details-console","title":"WIFI init error (details console)","text":"A general WIFI initialization error occured. Please check serial console output or logfile from sd card (using another device to retrieve logfile /sdcard/log/message/)
"},{"location":"StatusLED-BlinkCodes/#source-sdcard_init-sd-card-initialization","title":"Source SDCARD_INIT: SD card initialization","text":"Note
All critical errors, regular boot not possible
"},{"location":"StatusLED-BlinkCodes/#sd-card-filesystem-mount-failed","title":"SD card filesystem mount failed","text":"Failed to mount FAT filesystem on SD card. Check SD card filesystem (only FAT supported) or try another card. Possible further infos: Please check serial console output.
"},{"location":"StatusLED-BlinkCodes/#sd-card-not-found-error-code-0x107","title":"SD card not found (Error code 0x107)","text":"SD card init failed. Check if SD card is properly inserted into SD card slot or try another card. Possible further infos: Please check serial console output.
"},{"location":"StatusLED-BlinkCodes/#sd-card-init-failed-details-console","title":"SD card init failed (details console)","text":"A general SD card initialization error occured. Please check serial console output.
"},{"location":"StatusLED-BlinkCodes/#source-sdcard_check-sd-card-basic-check","title":"Source SDCARD_CHECK: SD card basic check","text":"Note
All critical errors, normal boot not possible. Reduced WebUI is going to be loaded for further diagnostic possibilities or redo firmware update.
"},{"location":"StatusLED-BlinkCodes/#file-creation-write-error","title":"File creation / write error","text":"A basic check of SD card is performed at boot. Failed to create the test file or writing content to the file failed. Most likely SD card is defective or not supported. Please check logs with log viewer in reduced web interface, serial console output or try another card.
Recommendation: Format or try another card
"},{"location":"StatusLED-BlinkCodes/#file-read-crc-verfication-error","title":"File read / CRC verfication error","text":"A basic check of SD card is performed at boot. Failed to read the test file or CRC of read back content failed. Most likely SD card is defective. Please check logs with log viewer in reduced web interface or serial console output for further error indication or try another card.
Recommendation: Format or try another card
"},{"location":"StatusLED-BlinkCodes/#file-delete-error","title":"File delete error","text":"A basic check of SD card is performed at boot. Failed to delelte the test file. Most likely SD card is defective. Please check logs with log viewer in reduced web interface or serial console output for further error indication or try another card.
Recommendation: Format or try another card
"},{"location":"StatusLED-BlinkCodes/#folder-file-presence-failed","title":"Folder / File presence failed","text":"A basic check of SD card is performed at boot. One or more menadatory folder / file are not found on SD card. Please check logs with log viewer in reduced web interface or serial console output for further error indication.
Recommendation: Repeat installation using AI-on-the-edge-device__update__*.zip
"},{"location":"StatusLED-BlinkCodes/#source-cam_init-camera-initialization","title":"Source CAM_INIT: Camera initialization","text":""},{"location":"StatusLED-BlinkCodes/#camera-init-failed-details-console","title":"Camera init failed (details console)","text":"Note
Critical error, normal boot not possible. Reduced WebUI is going to be loaded for further diagnostic possibilities or redo firmware update.
A general camera initialization error occured. Please check logs with log viewer in reduced web interface or serial console output for further error indication.
Recommendation: Check for proper electrical connection, whether camera model is supported and whether power supply is sufficient.
"},{"location":"StatusLED-BlinkCodes/#camera-framebuffer-check-failed","title":"Camera framebuffer check failed","text":"The framebuffer of the camera was not readable. The firmware will trying to continue regular boot, but further errors can occur which block regular processing. Please check logs with logfile viewer if processing is behaving irregular.
Recommendation: Check for proper electrical commenection, wether camera model is supported and wether power supply is suffcient.
"},{"location":"StatusLED-BlinkCodes/#source-psram_init-external-ram-spi-ram-initialization","title":"Source PSRAM_INIT: External RAM (SPI RAM) initialization","text":"Note
A critical errors, normal boot not possible. Reduced WebUI is going to be loaded for further diagnostic possibilities or redo firmware update.
"},{"location":"StatusLED-BlinkCodes/#spi-ram-init-failed-not-founddefective","title":"SPI RAM init failed: Not found/defective","text":"External RAM (SPI RAM) initialization failed. Most likely external RAM not accessable or defective. Normal operation is not possible without having external RAM.
"},{"location":"StatusLED-BlinkCodes/#external-spi-ram-4mb","title":"External SPI RAM < 4MB","text":"External RAM (SPI RAM) initialization successful, but external RAM size is too small. A size of >= 4MB is necessary to run this firmware.
"},{"location":"StatusLED-BlinkCodes/#total-heap-4mb","title":"Total heap < 4MB","text":"Total available system memory (heap) is too small. A size of >= 4MB is necessary to run this firmware.
"},{"location":"StatusLED-BlinkCodes/#source-time_check-external-ram-spi-ram-initialization","title":"Source TIME_CHECK: External RAM (SPI RAM) initialization","text":""},{"location":"StatusLED-BlinkCodes/#missing-time-sync-check-every-round","title":"Missing time sync (check every round)","text":"Note
Only warning indication, blink code repetition: 2x
If system is configured to be synced with a NTP server the sync status is checked after every round (in state: \"Flow finished\". An warming message is also printed to log). If the time is not synced after serveral rounds, please check for proper configuration.
"},{"location":"StatusLED-BlinkCodes/#status","title":"STATUS","text":"Note
All only status indication
"},{"location":"StatusLED-BlinkCodes/#source-ota_or_ap-ota-update-access-point-mode","title":"Source OTA_OR_AP: OTA Update / Access point mode","text":""},{"location":"StatusLED-BlinkCodes/#ota-process-ongoing","title":"OTA process ongoing","text":"An OTA is performed right now. Please wait until OTA is completed. System is rebooting automatically. If system is not coming up, please check serial console output.
"},{"location":"StatusLED-BlinkCodes/#soft-ap-started-for-remote-config","title":"Soft AP started (for remote config)","text":"The built-in access point functionality is started to perform initial remote remote setup. Further description: Installtion --> Section Remote Setup using the built-in Access Point
"},{"location":"StatusLED-BlinkCodes/#source-flashlight-flashlight","title":"Source FLASHLIGHT: Flashlight","text":""},{"location":"StatusLED-BlinkCodes/#led-on-when-flashlight-is-on","title":"LED on when flashlight is on","text":"The LED is solid on as long the flashlight is on. This feature has lower priority than the other LED codes. Whenever another code occurs this feature will be overrided.
"},{"location":"Testing/","title":"Testing Option for VSCode","text":"You can test your functions directly on the device.
"},{"location":"Testing/#structure","title":"Structure","text":"All tests are under directory \"test\" in the project and not compiled with default build option of platformio. The main function is in file test_suite_controlflow.cpp. In method app_main() you can add your own tests.
"},{"location":"Testing/#include-my-own-test","title":"Include my own test","text":"In method app_main() of test_suite_controlflow.cpp you can add your own tests. Include your test-file in the top like
#include \"components/jomjol-flowcontroll/test_flow_postrocess_helper.cpp\"
components is a subfolder of tests here. Not the components directory of root source.
In the bottom add your test function.
RUN_TEST(testNegative);
Your test function should have a TEST_ASSERT_EQUAL_*. For more information look at unity-testing.
"},{"location":"Testing/#run-tests","title":"Run tests","text":"You will need a testing device. best with usb adapter. Before you upload your tests you will need to setup the device with initial setup procedure described in [[Installation]]
Now you can use Visual Studio Code or a standard console to upload the test code. In VS Code (tab platformio) open Advanced and select Test.
Alternatively you can run it in console/terminal with platformio test --environment esp32cam.
In my environment the serial terminal not opens. I have to do it for myself. You will see much logging. If any test fails it logs it out. Else it logs all test passed in the end.
"},{"location":"Testing/#troubleshooting","title":"Troubleshooting","text":"If you test very much cases in one function, the device runs in Stack Overflow and an endless boot. Reduce the count of test cases or split the test function in multiple functions.
"},{"location":"Upload-files-by-script/","title":"Scripted File Upload","text":"To upload a file e.g. using curl, you first have to delete it and then upload it:
curl -d '' http://192.168.1.153/delete/html/index.html\ncurl --data-binary @ota_page.html http://192.168.1.153/upload/html/index.html\n
"},{"location":"WLAN-disconnect-reason/","title":"WLAN disconnect reasons","text":"In the logfile the WLAN disconnect reason code are printed whenever a disconnect event occurs (WARNING LEVEL or higher).
Further information and additional description of reason codes can be found here: WLAN disconnect reason code description
"},{"location":"Watermeter-specific-analog---digit-transition/","title":"Analog/Digit Transition on Water Meters","text":"At first, for the most water meters the default configuration should be work. But the digit, especially the last digit differs in some devices.
"},{"location":"Watermeter-specific-analog---digit-transition/#normal-transition","title":"\"Normal\" transition","text":"In most cases, the transition of the last digit starts when the analogue pointer is > 9.
Often the last digit \"hangs\" a bit on this devices and comes not over zero. So it is not easy to see which digit is correct. In the first example 4 or still 3? (3 is correct).
"},{"location":"Watermeter-specific-analog---digit-transition/#early-transition","title":"Early transition","text":"Some units start the transition very early or run with the analogue pointer. In the third example, is it a 3 or a 2?
"},{"location":"Watermeter-specific-analog---digit-transition/#inaccuracies-in-image-recognition","title":"Inaccuracies in image recognition","text":"The models for image recognition are good, but have inaccuracies in the range +/- 0.2. In order to obtain as many correct results as possible, a treatment is carried out in the post process in the range of 9.8-0.2 for the analogue pointer, which must start differently depending on the type of counter.
"},{"location":"Watermeter-specific-analog---digit-transition/#how-to-configure-for-my-meter-type","title":"How to configure for my meter type","text":"If you have a devices with \"normal\" transition you should not have any issues. On devices with \"early\" transition, you can set the option AnalogToDigitTransitionStart to a value between 6 and 8. See the parameter documentation for details.
"},{"location":"Webhook/","title":"Webhook","text":""},{"location":"Webhook/#purpose","title":"Purpose","text":"The idea behind this webhook feature is to provide an alternative to MQTT and InfluxDB for transmitting data, such as water meter readings from a vacation home, to a standard PHP webspace.
You can call the webhook to upload the data or the raw image of a round to a server.
"},{"location":"Webhook/#configuration","title":"Configuration","text":"To configure the webhook feature, you only need to define a URI and an API key. The URI is where the webhook will send the data, and the API key is used to authenticate the requests, ensuring that only authorized devices can send data to your server. Optionally, \"Upload Image\" can be used to configure whether an additional PUT request should be sent to the same URI with the current image. A parameter timestamp is appended to establish a correlation.
"},{"location":"Webhook/#example-of-a-post-request","title":"Example of a POST Request","text":"Below is an example of the JSON payload that might be sent in a POST request to the webhook:
"},{"location":"Webhook/#request-headers","title":"Request Headers","text":"APIKEY: your-api-key-here\n
"},{"location":"Webhook/#json-payload","title":"JSON Payload","text":"[\n {\n \"timestamp\": \"2024-08-09T11:44:44+0200\",\n \"timestampLong\": 1723196684,\n \"name\": \"main\",\n \"rawValue\": \"0345.42647\",\n \"value\": \"345.42648\",\n \"preValue\": \"345.42648\",\n \"rate\": \"0.000000\",\n \"changeAbsolute\": \"0.00000\",\n \"error\": \"no error\"\n },\n {\n \"timestamp\": \"2024-08-09T11:44:44+0200\",\n \"timestampLong\": 1723196684,\n \"name\": \"test\",\n \"rawValue\": \"34\",\n \"value\": \"34\",\n \"preValue\": \"34\",\n \"rate\": \"0.000000\",\n \"changeAbsolute\": \"0\",\n \"error\": \"no error\"\n }\n]\n
"},{"location":"Webhook/#basic-example-of-a-server-using-php","title":"Basic Example of a server using PHP","text":"<?php\n$expectedApiKey = 'your-api-key-here';\n\n$receivedApiKey = isset($_SERVER['HTTP_APIKEY']) ? $_SERVER['HTTP_APIKEY'] : '';\n\nif ($receivedApiKey !== $expectedApiKey) {\n http_response_code(403); // 403 Forbidden\n echo json_encode(['status' => 'error', 'message' => 'Invalid API key']);\n exit;\n}\n\n$method = $_SERVER['REQUEST_METHOD'];\n\nif ($method === 'POST') {\n // Handle POST request: Write data to CSV\n $csvFile = 'webhook_log.csv';\n\n $jsonData = file_get_contents('php://input');\n\n $dataArray = json_decode($jsonData, true);\n if (!$jsonData || !is_array($dataArray)) {\n http_response_code(400); // 400 Bad Request\n echo json_encode(['status' => 'error', 'message' => 'Invalid JSON data']);\n exit;\n }\n\n $csvHandle = fopen($csvFile, 'a');\n if ($csvHandle === false) {\n http_response_code(500); // 500 Internal Server Error\n echo json_encode(['status' => 'error', 'message' => 'Unable to open CSV file']);\n exit;\n }\n\n foreach ($dataArray as $data) {\n $csvRow = [\n $data['timestampLong'], \n $data['name'], \n $data['rawValue'], \n $data['value'], \n $data['preValue'], \n $data['rate'], \n $data['changeAbsolute'], \n $data['error']\n ];\n fputcsv($csvHandle, $csvRow);\n }\n\n fclose($csvHandle);\n\n http_response_code(200); // 200 OK\n echo json_encode(['status' => 'success', 'message' => 'Data written to CSV file']);\n} elseif ($method === 'PUT') {\n // Handle PUT request: Save image\n $timestamp = $_GET['timestamp'];\n\n if (!ctype_digit($timestamp) || $timestamp < 0 || $timestamp > PHP_INT_MAX) {\n http_response_code(400); // 400 Bad Request\n echo json_encode(['status' => 'error', 'message' => 'Invalid timestamp']);\n exit;\n }\n\n $imageFilePath = 'uploaded_image_' . $timestamp . '.jpg';\n\n $imageData = file_get_contents('php://input');\n\n if (!$imageData) {\n http_response_code(400); // 400 Bad Request\n echo json_encode(['status' => 'error', 'message' => 'No image data received']);\n exit;\n }\n\n if (file_put_contents($imageFilePath, $imageData) === false) {\n http_response_code(500); // 500 Internal Server Error\n echo json_encode(['status' => 'error', 'message' => 'Unable to save the image']);\n exit;\n }\n\n http_response_code(200); // 200 OK\n echo json_encode(['status' => 'success', 'message' => 'Image uploaded successfully']);\n} else {\n // Handle unsupported HTTP methods\n http_response_code(405); // 405 Method Not Allowed\n echo json_encode(['status' => 'error', 'message' => 'Method not allowed']);\n}\n?>\n
"},{"location":"Webhook/#basic-example-of-a-server-using-python","title":"Basic Example of a server using Python","text":"from flask import Flask, request, jsonify\nimport csv\nimport os\n\napp = Flask(__name__)\n\n# List of allowed API keys\nALLOWED_API_KEYS = {\n '123',\n '456',\n '789'\n}\n\n@app.before_request\ndef check_api_key():\n # Get the API key from the request headers\n received_api_key = request.headers.get('APIKEY')\n\n # Check if the received API key is in the allowed list\n if received_api_key not in ALLOWED_API_KEYS:\n return jsonify({'status': 'error', 'message': 'Invalid API key'}), 403\n\n # Attach the API key to the request object for later use\n request.api_key = received_api_key\n\n@app.route('/webhook', methods=['POST', 'PUT'])\ndef webhook():\n # Create a directory for the API key if it doesn't exist\n api_key_dir = os.path.join('data', request.api_key)\n os.makedirs(api_key_dir, exist_ok=True)\n\n if request.method == 'POST':\n # Handle POST request: Write data to CSV\n data = request.get_json()\n if not data or not isinstance(data, list):\n return jsonify({'status': 'error', 'message': 'Invalid JSON data'}), 400\n\n csv_file = os.path.join(api_key_dir, 'webhook_log.csv')\n try:\n with open(csv_file, 'a', newline='') as csvfile:\n csv_writer = csv.writer(csvfile)\n for item in data:\n csv_writer.writerow([\n item.get('timestampLong'),\n item.get('name'),\n item.get('rawValue'),\n item.get('value'),\n item.get('preValue'),\n item.get('rate'),\n item.get('changeAbsolute'),\n item.get('error')\n ])\n return jsonify({'status': 'success', 'message': 'Data written to CSV file'}), 200\n except Exception as e:\n return jsonify({'status': 'error', 'message': 'Unable to open CSV file'}), 500\n\n elif request.method == 'PUT':\n # Handle PUT request: Save image\n timestamp = request.args.get('timestamp')\n if not timestamp or not timestamp.isdigit() or int(timestamp) < 0:\n return jsonify({'status': 'error', 'message': 'Invalid timestamp'}), 400\n\n image_data = request.data\n if not image_data:\n return jsonify({'status': 'error', 'message': 'No image data received'}), 400\n\n image_file_path = os.path.join(api_key_dir, f'{timestamp}.jpg')\n try:\n with open(image_file_path, 'wb') as image_file:\n image_file.write(image_data)\n return jsonify({'status': 'success', 'message': 'Image uploaded successfully'}), 200\n except Exception as e:\n return jsonify({'status': 'error', 'message': 'Unable to save the image'}), 500\n\n else:\n # Handle unsupported HTTP methods\n return jsonify({'status': 'error', 'message': 'Method not allowed'}), 405\n\nif __name__ == '__main__':\n app.run(host='0.0.0.0', port=5001)\n
"},{"location":"collect-new-images/","title":"Collect images to improve the models","text":"If your device has new, different digits or pointers it might be that the existing models don't recognize them well. In such case you can collect your images and so we can train the model better. This helps you and also others as the models get more accurate. Adding more images also helps if you have a model that is already known, but the neural models do not produce good results.
Experienced users can do the training also by themselves, see Learn a model with your own images.
"},{"location":"collect-new-images/#before-you-start","title":"Before you start","text":"Before you go ahead, please check if your digits/pointers are not yet contained in the training data. A visual overview is available at digits resp. pointers.
Poor recognition is often caused by blurred images, low contrast or incorrect setting of the ROIs. Therefore, check these possibilities first, as additional training will bring little improvement here. See ROI Configuration for details.
"},{"location":"collect-new-images/#collecting-images","title":"Collecting images","text":"The neural network is trained based on a set of images that have already been collected over time. If your digits are included or at least very similar to included images, the chance is very high that the neural network is working fine for you as well.
The neural network configuration is stored in the TensorFlow Lite format as *.tfl or *.tflite in the /config directory on the SD card. A model can be updated (or a new one added) by uploading the new file and activating it on the configuration page or in the config file /config/config.ini.
In order to incorporate new digits a training set of images is required. The training images needs to be collected in the final setup with the help of the Digits or Analog log settings (not to be confused with the Data or Debug log). Enable the logging of the images on the configuration page or in the config file /config/config.ini:
Now be patient! You have to wait until it has collected an image of each digit of every type. They will be placed on the SD card in the folder /log/digit/ resp. /log/analog/.
After some days, there will be a lot of images, many of them very similar. Because of this, it is important to select only a subset of them for the model training.
The tools shown below can help you with that.
"},{"location":"collect-new-images/#collecting-images-for-dig-class100dig-contana-class100","title":"Collecting images for dig-class100/dig-cont/ana-class100","text":"For digits use Collectmeterdigits resp. for pointers use collectmeteranalog to fetch the images from the device and select a subset of them. Please read the detailed instructions on the mentioned links for details!
If the fetching of the images is too slow for you, a faster way to get the images to your PC is to remove the SD-card from the ESP32 module and insert it into the card reader of yur PC. Then search for two..three images of each digit (not more! :-)). You will have to make sure to label the images yourself matching the effective value they are supposed to show.
"},{"location":"collect-new-images/#share-your-images","title":"Share your images","text":"In most cases we will integrate your images in the training dataset of the models. Only if we fear a degradation of the models or you need a different behavior, we might not include the data in the standard models (see at bottom of page for reasons).
To provide your images to us for training the model, open an Github Issue and append the zipped images ito it.
"},{"location":"collect-new-images/#images-can-be-rejected-if","title":"Images can be rejected if","text":" - You provide too many images. More than 1000 images of your device are really to much.
- Images which are not good enough (see ROI Configuration) will be rejected. It would reduce the accuracy of the networks.
- Images with too little focus will be rejected.
- Images with too much blur are rejected.
Our models are to small to recognize everything in any quality. So we use only images of medium or good quality.
"},{"location":"data-logging/","title":"Data Logging","text":"When Data Logging is enabled (See parameter DataLogActive), the results of every round gets written to the SD-Card.
The data files are stored in /log/data on the SD-Card.
"},{"location":"data-logging/#data-format","title":"Data Format","text":"The data is stored as CSV with the following columns: time, name-of-number, raw-value, return-value, pre-value, change-rate, change-absolute, error-text, cnn-digit, cnn-analog
"},{"location":"initial-setup/","title":"Initial Setup","text":"After setting up the device (firmware, SD card, WLAN) the device will connect to the wifi access point and start in an initial setup configuration:
With the buttons on the top you can navigate through 5 steps which guide you through the necessary setup:
- Create the Reference Image. It is the base for the position referencing and the identification of the digits and counters.
- Define two unique Reference Marks. They is used to align the individual camera images and identify the absolute positions.
- Define ROIs for the Digits. They will be used to digitize the digit part of your meter. If your meter has no digits, this step can be skipped.
- Define ROIs for the Analog Counters. (Only required in case your meter has analog counters)
- General Settings. Further configuration of your device.
All settings can be accessed later in the normal operation mode.
Note
Don't forget to save each step with \"Save\", and do not reboot at this stage.
"},{"location":"initial-setup/#finish-the-setup-and-change-to-the-normal-operation-mode","title":"Finish the Setup and change to the Normal Operation mode","text":"With the last step (1) you leave the Setup Mode and reboot to the Normal Operation mode.
"},{"location":"initial-setup/#access-to-the-setup-pages-in-the-normal-operation-mode","title":"Access to the Setup Pages in the Normal Operation mode","text":"You always can access all the settings during the normal operation mode via the Settings menu:
(1) Access to the General Settings. (2) Update of the Reference Image. (3) Update of the Alignment Marks. (4)/(5) Update of the ROIs.
"},{"location":"ota/","title":"Over-The-Air (OTA) Update","text":"You can do an OTA (over-the-air) update via the Web Interface. Grab the firmware from the
- Releases page (Stable, tested versions), or the
- Automatically build development branch (experimental, untested versions). Please inform yourself on Living on the Edge first!
"},{"location":"ota/#update-procedure","title":"Update Procedure","text":" - Create a backup of your configuration. Either use the Backup/Restore function of your device for this (menu
System > Backup/Restore) or back the files manually up using the File Server (menu File Server, folder config). It is recommended to at least save the config file config.ini! - Head to the menu
System > OTA Update and follow the instructions there.
If you do an update between major versions, it might be needed to modify the config file config.ini as it's syntax or context has changed. To do so, go to the menu Settings > Configuration (after the update completed and the device restarted) and check if it warns you about an unset parameter.
"},{"location":"ota/#update-from-version-v1200-or-newer","title":"Update from version v12.0.0 or newer","text":"You can use the over the air update mechanism, which uploads the update via a ZIP files.
The update file is located on the release page. Please choose the zip file with the following naming: AI-on-the-edge-device__update__*.zip
Go to the menu System --> OTA Update and follow the instructions there. After a final automatic reboot you should have the new version running.
"},{"location":"ota/#update-from-version-older-than-v1200","title":"Update from version older than v12.0.0","text":"If you update from an version older than 12.0.1, you should firstly update to version 12.0.1. Background are not fully backward compatible changes in the config.ini, that are taken care of in this version.
Warning
Make sure to read the instructions below carefully!
-
Backup your configuration (use the System -> Backup/Restore page)!
-
Upload and update the update-*.zip file from the release 12.0.1 see here .
-
Let it restart and check on the System -> Info page that the Firmware as well as the Web UI got updated. If only one got updated, redo the update. If it fails several times, you also can update the Firmware and the Web UI separately.
-
Safe way:
- Update first the
firmware.bin (extract it from one of the provided zip files) and do the Reboot - Update with the full zip file (
update-*.zip, ignore the version warning after the reboot)
-
Please go to Settings -> Configuration and address the changed parameters:
- DataLogging (storing the values for data graph)
- Debug (extended by different debug reporting levels)
-
Make sure it starts to do the digitization (check the Error field on the overview page). If it does not start a round within a minute, restart the device.
Note
If the system is working now without any issues, please open the configuration editor once and save the config.ini. This will update the file to the newest content.
Now you can safely update to the newest version.
"},{"location":"outdated--Integrated-Functions/","title":"Integrated Functions","text":"Warning
This page no longer is maintained!
"},{"location":"outdated--Integrated-Functions/#wasserzaehler","title":"wasserzaehler","text":"http://IP-ESP32/wasserzaehler.html
This is the main purpose of this device. It returns the converted image as a number with different option. The output can be modified either by the configuration parameters or by HTML parameters.
Details can be found here: tbd
"},{"location":"outdated--Integrated-Functions/#picture-server","title":"Picture Server","text":"http://IP-ESP32/capture
http://IP-ESP32/capture_with_flashlight
This is a implementation of the camera interface of https://github.com/jomjol/water-meter-picture-provider
It is fully compatible including the parameters (quality=..., size=... ) . This allows to use this ESP32 system in parallel to the corresponding docker system: https://github.com/jomjol/water-meter-system-complete, from which this project is basically the successor.
"},{"location":"outdated--Integrated-Functions/#file-server","title":"File server","text":"Access: http://IP-ESP32/fileserver/
Simple file server, that allows viewing, upload, download and deleting of single files of the SD-card content.
The usage is self explaining. The file path or file can directly be accessed by the URL after file server.
Example for config.ini : http://IP-ESP/fileserver/config/config.ini
"},{"location":"outdated--Integrated-Functions/#ota-update","title":"OTA-Update","text":"http://IP-ESP32/ota?file=firmware.bin
Here an over the air update can be triggered. The firmware file is expected to be located in the sub directory /firmware/ and can be uploaded with the file server. By the parameter file the name of the firmware file needs to be given.
"},{"location":"outdated--Integrated-Functions/#reboot","title":"Reboot","text":"http://IP-ESP32/reboot
A reboot with a delay of 5 seconds is initiated, e.g. after firmware update.
ATTENTION: currently this is not working properly - hardware power off is needed instead. Work in progress!
"},{"location":"outdated--Integrated-Functions/#simple-web-server","title":"Simple Web Server","text":"If none of the above URLs are fitting, a very simple web server checks, if there is a fitting file from the sub directory /html This can be used for a very simple web server for information or simple web pages.
"},{"location":"prometheus-openmetrics/","title":"Prometheus/OpenMetrics","text":"A set of metrics is exported via the /metrics REST API path on the device. Besides the current value, a set of device properties are exported. Multiple sequences (aka numbers) are supported via a label. The metrics are provided in text wire format.
Example:
$ curl http://<IP>/metrics\n# HELP ai_on_the_edge_device_flow_value current value of meter readout\n# TYPE ai_on_the_edge_device_flow_value gauge\nai_on_the_edge_device_flow_value{sequence=\"main\"} 240.7064\n# HELP ai_on_the_edge_device_cpu_temperature_celsius current cpu temperature in celsius\n# TYPE ai_on_the_edge_device_cpu_temperature_celsius gauge\nai_on_the_edge_device_cpu_temperature_celsius 41\n# HELP ai_on_the_edge_device_rssi_dbm current WiFi signal strength in dBm\n# TYPE ai_on_the_edge_device_rssi_dbm gauge\nai_on_the_edge_device_rssi_dbm -67\n# HELP ai_on_the_edge_device_memory_heap_free_bytes available heap memory\n# TYPE ai_on_the_edge_device_memory_heap_free_bytes gauge\nai_on_the_edge_device_memory_heap_free_bytes 716303\n# HELP ai_on_the_edge_device_uptime_seconds device uptime in seconds\n# TYPE ai_on_the_edge_device_uptime_seconds gauge\nai_on_the_edge_device_uptime_seconds 214267\n# HELP ai_on_the_edge_device_rounds_total data aquisition rounds since device startup\n# TYPE ai_on_the_edge_device_rounds_total counter\nai_on_the_edge_device_rounds_total 239\n
"},{"location":"prometheus-openmetrics/#prometheus-scrape-config","title":"Prometheus Scrape Config","text":"The following scrape config (add to prometheus.yml) can be used as an example to ingest available metrics with prometheus:
scrape_configs:\n - job_name: watermeter\n scrape_interval: 300s\n metrics_path: /metrics\n static_configs:\n - targets: ['<IP>']\n
"},{"location":"prometheus-openmetrics/#references","title":"References","text":""},{"location":"unstable-installation/","title":"Living on the Edge","text":" - The main branch contains the latest version of the Firmware and the Web Interface. It might already contain a fix for your issue. But it is work in progress, don't expect it to work stable or be an improvement for your AI-on-the-edge-device! Also it might break the OTA Update and thus require manual flashing over USB! For normal users it is better tu use a release.
- Any other branch is used to develop a feature or fix, only use them when you know what it is about!
"},{"location":"unstable-installation/#i-still-want-to-try-it","title":"I still want to try it","text":"Ok, then grab the latest main build from Github Actions Page and proceed as following:
- Pick the most top successful (green) build:
- Scroll down and download the
AI-on-the-edge-device__update__*.zip: - Flash the zip file using the OTA Update page of your device.
"}]}
\ No newline at end of file
+{"config":{"lang":["en"],"separator":"[\\s\\-]+","pipeline":["stopWordFilter"]},"docs":[{"location":"","title":"Welcome","text":"Welcome to the AI-on-the-edge-device project!
This is the documentation. For the source code, please head to github.com/jomjol/AI-on-the-edge-device.
Artificial intelligence based systems have been 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 up there. With the increasing power of modern processors the AI systems are coming closer to the end user - which is usually called edge computing. Here this edge computing is brought into a practice-oriented example, where a AI network is implemented on a ESP32 device so: AI on the edge.
"},{"location":"#key-features","title":"Key features","text":" - Tensorflow Lite (TFlite) integration - including easy to use wrapper
- Inline image processing (feature detection, alignment, ROI extraction)
- Small and cheap device (3x4.5x2 cm\u00b3, < 10 EUR)
- Camera and illumination integrated
- Web surface to administrate and control
- OTA-Interface to update directly through the web interface
- Full integration into Home Assistant
- Support for Influx DB 1 and 2
- MQTT
- REST API
"},{"location":"#idea","title":"Idea","text":""},{"location":"#hardware","title":"Hardware","text":""},{"location":"#web-interface","title":"Web interface","text":""},{"location":"#configuration-interface","title":"Configuration Interface","text":"Have fun in studying the new possibilities and ideas
This is about image recognition and digitization, done totally on a cheap ESP32 board using artificial intelligence in form of convolutional neural networks (CNN). Everything, from image capture (OV2640), image preprocessing (auto alignment, ROI identification) all the way down to the image recognition (CNN structure) and result plausibility is done on a cheap 10 EUR device.
This all is integrated in an easy to do setup and use environment, taking care for all the background processing and handling, including regular job scheduler. The user interface is an integrated web server, that can be easily adjusted and offers the data as an API in different options.
The task to be demonstrated here is an automated readout of an analog water meter. The water consumption is to be recorded within a house automatization and the water meter is totally analog without any electronic interface. Therefore, the task is solved by regularly taking an image of the water meter and digitizing the reading.
There are two types of CNN implemented, a classification network for reading the digit numbers and a single output network for digitize the analog pointers for the sub digit readings.
This project is an evolution of the water-meter-system-complete, which uses ESP32-CAM just for taking the image and a 1GB-Docker image to run the neural network's backbone. Here everything is integrated in an ESP32-CAM module with 8MB of RAM and a SD card as data storage.
"},{"location":"#additional-tutorials","title":"Additional Tutorials","text":"A lot of people created useful Youtube videos which might help you getting started. Here a small selection:
- youtube.com/watch?v=HKBofb1cnNc
- youtube.com/watch?v=yyf0ORNLCk4
- youtube.com/watch?v=XxmTubGek6M
- youtube.com/watch?v=mDIJEyElkAU
- youtube.com/watch?v=SssiPkyKVVs
- youtube.com/watch?v=MAHE_QyHZFQ
- youtube.com/watch?v=Uap_6bwtILQ
"},{"location":"Additional-Information/","title":"Additional Information","text":"The following links point to additional information in other repos:
"},{"location":"Additional-Information/#digits","title":"Digits","text":" - Training the CNN neural network
- Training and using a neural network to readout the value of a digit counter
"},{"location":"Additional-Information/#analog","title":"Analog","text":" - Training and using a neural network to read out the value of an analog display
- Training the CNN neural network
"},{"location":"Alignment/","title":"Alignment References","text":"The alignment references are used in every round to re-align the taken image to the reference coordinates. Two alignment structures must be defined and the taken image then in each round is shifted and rotated according to their position with the target to be in exactly the same position as the reference image.
Note
The alignment structures needs to be unique and have a good contrast. It is advised to have them as far apart as possible.
"},{"location":"Alignment/#precondition","title":"Precondition","text":"Please make sure to have setup your camera properly and taken a good Reference Image.
"},{"location":"Alignment/#define-two-reference-images","title":"Define two Reference Images","text":"You can switch between this two marks with (1).
Then define the reference area in the image by either directly drag and drop with the mouse or use the input boxes below. To apply the currently marked image part you need to push \"Update Reference\" (2).
In some cases it might be useful to use a reference with a higher contrast. This can be achieved by pushing Enhance Contrast\" (3). The result will be calculated on the ESP32 - so be a bit patient, before you see it active.
To save push \"Save to config.ini\" (4).
Note
A reboot is not required at this point of time.
As next you should define the Digit and Analog ROIs.
"},{"location":"Best-Practice/","title":"Best Practice","text":"This page shows some best practices:
"},{"location":"Best-Practice/#camera-placement","title":"Camera Placement","text":" - Move the Camera as close as possible (~4cm), this will help get rid of reflections. -> focus can be adjusted by turning the outer black ring of the camera.
- If the LED reflections are too strong, put tape over the LED to diffuse the light
- Change the ImageSize to QVGA under \"Expert mode\" configuration when close enough, this will be faster and is often good enough for digit recognition.
"},{"location":"Best-Practice/#reflections","title":"Reflections","text":" - Try to get rid of the reflections by rotating the camera, so that the reflections are at positions, where no number is.
- By using the external LED option, you can place WS2812 LEDs freely away from the main axis.
- Users report, that a handy cover foil could also help
"},{"location":"Best-Practice/#post-processing","title":"Post-processing","text":" - Filter out the Number \"9\", as \"3\" will often be misread for a \"9\" and void every number between 3 and 9 due to it being negative flow.
- Split the readings into two, while the decimal numbers might move to fast to be recognized, at least the slower moving part will produce a correct reading. -> keep in mind that the offset needs to be adjusted, a.e if you have a comma reading of \"3\", it needs to become \"0.3\". This can be done wherever the data ends up being sent, like home assistant using sensor templates.
- If you are using a low resolution and only digit mode, processing can often be done in <1 minute. Check the logs to confirm how fast it is and then set the interval accordingly under \"Expert mode\" in configuration, as the normal mode will lock you to 3+ minutes.
"},{"location":"Build-Instructions/","title":"Build the Project","text":"See README.md in the main repo.
"},{"location":"Choosing-the-Model/","title":"Model Selection","text":"Notes
See Neural Network Types for additional details.
In the Graphical Configuration Page, you can choose different models depending on your needs.
This page tries to help you on which model to select. For more technical/deeper explanations have a look on Neural-Network-Types.
"},{"location":"Choosing-the-Model/#digit-models","title":"Digit Models","text":"For digits on water meters, gas-meters or power meters you can select between two main types of models:
dig-class11 dig-class100 and dig-cont
"},{"location":"Choosing-the-Model/#dig-class11","title":"dig-class11","text":"This model can recognize full digits. It was the first model version. All intermediate states shown a N for not a number. But in post process it uses older values to fill up the N values if possible.
It's possibly a good fallback, if dig-cont or dig-class100 results are not good.
Main features:
- well suited for LCD digits
- the ExtendedResolution option is not supported. (Only in conjunction with
ana-class100 or ana-cont)
"},{"location":"Choosing-the-Model/#dig-class100-and-dig-cont","title":"dig-class100 and dig-cont","text":"These models are used to get a continuous reading with intermediate states. To see what the models are doing, you can go to the Recognition page of your device.
Main features:
- suitable for all digit displays.
- Advantage over
dig-class11 that results continue to be calculated in the transition between digits. - With the ExtendedResolution option, higher accuracy is possible by adding another digit.
The difference between dig-class100 and dig-cont is in the internal processing. The dig-class100 is a standard classification model. Each tenth step is an output. dig-cont uses two outputs and arctangent to get the result. You see very complicated.
Note
Try both models on your device and take the one that gives you the best results.
Look here for a list of digit images used for the training.
"},{"location":"Choosing-the-Model/#analog-pointer-models","title":"Analog pointer models","text":""},{"location":"Choosing-the-Model/#ana-class100-and-ana-cont","title":"ana-class100 and ana-cont","text":"For pointers on water meters use the analog models:
You can choose between two models:
Both do mainly the same.
Main features:
- for all analogue pointers, especially for water meters.
- With the ExtendedResolution option, higher accuracy is possible by adding another digit.
Again, the difference between ana-class100 and ana-cont is in the internal processing.
Note
Take the one that gives you the best results. Both models learn from the same data.
Look here for a list of pointer images used for the training
"},{"location":"Choosing-the-Model/#different-types-of-models-normal-vs-quantized","title":"Different types of models (normal vs. quantized)","text":"The normally trained network is calculating with internal floating point numbers. The saving of floating point numbers naturally takes more space than an integer type. Often the increased accuracy is not needed. Therefore there is the option, to \"quantize\" a neural network. In this case the internal values are rescaled to integer values, which is called \"quantization\". The stored tflite files are usually much smaller and runs faster on the edgeAI-device. Usually the models are distrusted therefore in both versions. They can be distinguished by a q at the end of the logfile.
Example:
Type Name Normal dig-cont_0610_s3.tflite Quantized dig-cont_0610_s3-q.tflite"},{"location":"Configuration/","title":"Graphical Configuration","text":"Most of the settings can be modified on the Settings page:
It can be reached via the menu Settings > Configuration.
Note
- To activate the changes, the device needs to be restarted after saving the changes.
- Most of the commands need processing on the ESP32 device. This is not very fast - so please be patient.
All parameters are documented on the Parameters page and as tooltips on the config page.
"},{"location":"Configuration/#expert-parameters","title":"Expert Parameters","text":"Some parameters are treated as Expert Parameters and are hidden by default. Tick the checkbox in the top left corner to enable them:
The Expert Parameters then will be shown with a red background:
"},{"location":"Configuration/#manual-editing-of-the-config-file","title":"Manual Editing of the Config File","text":"Even more configuration parameters can be edited manually in the config.ini:
To edit the config.ini file directly, click on the Edit Config.ini directly button.
"},{"location":"Configuration/#background-information","title":"Background Information","text":"Note
You do not need to understand this! But you might be interested in it.
The principle is very simple and can most easily be described as a flow of processing steps. Each step has a dedicated parameter description in the config.ini, which is indicated by brackets [name_of_step]. The steps are processed in the order written in the config file. That means, that you first have to describe the image taking, then the aligning and cutting and only after that you can start to config a neural network. The last step is the post processing.
"},{"location":"Configuration/#processing-steps-overview","title":"Processing steps - Overview","text":"In the following you get a short overview over the available steps. This order is also the suggested order for the processing flow. Single steps can be left out, if not needed (e.g. omit the analog part, if only digits are present)
"},{"location":"Configuration/#1-takeimage","title":"1. [TakeImage]","text":"This steps parametrises the taking of the image by the ESP32-CAM. Size, quality and storage for logging and debugging can be set.
"},{"location":"Configuration/#2-alignment","title":"2. [Alignment]","text":"Image preprocessing, including image alignment with reference images
"},{"location":"Configuration/#3-digits","title":"3. [Digits]","text":"Neural network evaluation of an image for digits. The neural network is defined by a tflite formatted file and the output is a number between 0 .. 9 or NaN (if image is not unique enough)
"},{"location":"Configuration/#4-analog","title":"4. [Analog]","text":"Neural network evaluation of analog counter. The neural network is defined by a tflite formatted file and the output is a number between 0.0 .. 9.9, representing the position of the pointer.
"},{"location":"Configuration/#5-postprocessing","title":"5. [PostProcessing]","text":"Summarized the individually converted pictures to the overall result. It also implements some error corrections and consistency checks to filter wrong reading.
For more details look at Correction Algorithm).
"},{"location":"Configuration/#6-mqtt","title":"6. [MQTT]","text":"Transfer of the readings to a MQTT server.
"},{"location":"Configuration/#7-autotimer","title":"7. [AutoTimer]","text":"Configuration of the automated flow start at the start up of the ESP32.
"},{"location":"Configuration/#8-debug","title":"8. [Debug]","text":"Configuration for debugging details
"},{"location":"Correction%20Algorithm/","title":"Correction Algorithm","text":"After the digitization of the images and the composition to a number a checking and correction algorithm is applied. This is explained here.
There are several reasons, that a check might be necessary:
- In case of digits there is the output of \"N\" (=NaN = Not-a-Number) in case the digit cannot be detected correctly. This happens for example if the image shows a digit between to states
- The replacement of the \"N\" with a previous value could be not sufficient, due to the fact, that it might have changed.
- There is a misreading of one one of the numbers. This can always happen in case of neural network processing.
"},{"location":"Correction%20Algorithm/#terms-and-definitions","title":"Terms and definitions","text":""},{"location":"Correction%20Algorithm/#prevalue","title":"PreValue","text":"The last correct read value. PreValue is here a bit missleading, because normally it is the same as the last value. In the next round of reading it will be used to check nagtive rates, high rates (MaxRateValue / MaxRateType) and CCheckDigitIncreaseConsistency (dig-class11 only). Either from a previous correctly identified value or manual setting by the user.
"},{"location":"Correction%20Algorithm/#digits","title":"Digits","text":"Value that are digitized from a digit number. There are 11 allowed values for this:
- Digits: 0, 1, 2, ... 9
- N = Not-a-Number - representing a not unique state between two numbers
"},{"location":"Correction%20Algorithm/#analogs","title":"Analogs","text":"This are value derived from a pointer like meter. This never has the state \"N\".
"},{"location":"Correction%20Algorithm/#checkdigitincreaseconsistency","title":"CheckDigitIncreaseConsistency","text":"If this is enabled an \"intelligent\" algorithm is used to derive from zero-crossing of discrete digit positions, if the number should have been increased. This is relevant because in some of the digit meters, the increase of a digit to the next number can be seen, before the sub-digit has gone through zero.
For example: 16.6 --> 16.7 --> 1N.8 --> 17.9 corrected to 16.9 --> 17.0 --> 17.1
As you can see, the 17.9 is a false reading as the 7 is assumed to be already readable, although the sub-digit has not crossed the zero. In this case the CheckDigitIncreaseConsistency algorithm will correct this to 16.9
A detailed description of the algorithm can be found below (not yet ready!)
"},{"location":"Correction%20Algorithm/#allownegativerates","title":"AllowNegativeRates","text":"Most of the meters only have increasing numbers and do not count backwards. Therefore a negative rate (= negative change compared to the PreValue) is surely a false value. This can be checked an flagged as false reading
The AllowNegativeRates property ensures that the result does not become negative in the event of incorrect readings. This can happen, for example, if the alignment of the image did not work properly. But also the neural networks sometimes flip between two states for similar images.
If AllowNegativeRates = true, the result is discarded if it is smaller than the pre-value of the last readout and the output shows an error \"Negative rate..\"
If the ExtendedResolution setting is true, there is an exception where the value does not become smaller, but no error is output. This only applies if the value +/- 0.2 of the last digit is inaccurate.
"},{"location":"Correction%20Algorithm/#decimalshift","title":"DecimalShift","text":"The DecimalShift setting puts the decimal point in the right place. It acts like a shift. Negative values shift the decimal point to the left. Positive values move the decimal point to the right, filling with zero.
"},{"location":"Correction%20Algorithm/#analogtodigittransitionstart","title":"AnalogToDigitTransitionStart","text":"For detailed description see Analog-digit-transition.
"},{"location":"Correction%20Algorithm/#maxratevalue-and-maxratetype","title":"MaxRateValue and MaxRateType","text":"Here the maximum change from one to the next reading can be limited. If a false reading of the neural network results in a change larger than this, the reading is flagged as false. There a two types of comparisons possible
1) AbsolutChange: Here the difference between the PreValue and the current reading is compared directly, independent how much time has passed since the last reading. 2) RelativeRate: in this case a change rate in the unit of change/minute is calculated, taking the time between the last and the current reading into account. Be careful, that with increasing time, the absolute allowed change increases. Example: relative rate of 0.05 m\u00b3/minute --> after 20 minutes a maximum change of 20 minutes * 0.05 m\u00b3/minute = 1 m\u00b3 is possible. That means that a false reading of 1 m\u00b3 cannot be detected false after about 20 minutes in this case Assume, that there might be no change in the meter for hours (e.g. during the night) a much bigger change could also be accepted.
"},{"location":"Correction%20Algorithm/#extendedresolution","title":"ExtendedResolution","text":"Newer models such as dig-cont and dig-class100 have a high resolution of the values and can thus represent another digit by using the value of the last digit or pointer (ex. 7.8 in the last digit).
If the value is set to true, the result of the last digit is used completely.
When using dig-class11 models, the setting is ignored.
Due to inaccuracies of the neural networks, it sometimes happens that the results jump back and forth between two decimal places. Therefore, when using \u00c0llowNegatives= false, no error is output if the value is only off by 0.2. Nevertheless, the value then remains at the higher determined value.
"},{"location":"Correction%20Algorithm/#ignoreleadingnan","title":"IgnoreLeadingNaN","text":"The parameter is only be used, if a dig-class11 model is selected. \u00ccgnoreLeadingNaN removes in the CheckDigitIncreaseConsistency process the leading N values.
"},{"location":"Correction%20Algorithm/#flow-chart","title":"Flow Chart","text":""},{"location":"Correction%20Algorithm/#checkdigitincreaseconsistency-algorithm","title":"CheckDigitIncreaseConsistency Algorithm","text":"The check digit increase consistency algorithm is functional for the digits only. Due to the fact, that the rotation might be a little bit earlier or later compared to the zero crossing of the digit before, errors during the reading before and after a zero crossing can be wrong. Therefore a simple algorithm can be applied, checking the consistency of zero crossing and changes in the following digit. This is applied to one after the other digit, starting with the lowest priority digits.
"},{"location":"Demo-Mode/","title":"Demo Mode","text":"For Demo and Testing Purpose, the device can use pre-recorded raw images.
You need to enable it in the configuration (TakeImage > Demo) and also provide the needed files on the SD card.
For each round one image gets used, starting with the first image for the first round.
For the reference image and the alignment also the first image gets used.
Once the last image got reached, it starts again with the first one.
"},{"location":"Demo-Mode/#sd-card-structure","title":"SD Card Structure","text":"demo/\n\u251c\u2500\u2500 520.8983.jpg\n\u251c\u2500\u2500 520.9086.jpg\n\u251c\u2500\u2500 520.9351.jpg\n\u251c\u2500\u2500 ...\n\u2514\u2500\u2500 files.txt\n
"},{"location":"Demo-Mode/#collecting-images-of-your-device","title":"Collecting images of your device","text":"There are several ways to collect images from your device:
- Use the Parameter
RawImagesLocation to store them directly onto your SD card. - Use the Webhook to send the raw image on each round to a dedicated server, see Webhook resp. ../Parameter
UploadImg. -
Another option is to pull the images periodically from http://<IP>/img_tmp/raw.jpg. Eg. with an external service. Below is a (Linux)-Bash script to do it:
#!/bin/bash\nwhile [[ true ]]; do\n echo \"fetching value...\"\n wget -q http://192.168.1.151/value -O value.txt\n\n value=`cat value.txt`\n echo \"Value: $value\"\n\n diff=`diff value.txt value_previous.txt`\n changed=$?\n #echo \"Diff: $diff\"\n\n if [[ $changed -ne 0 ]]; then\n echo \"Value changed:\"\n echo $diff\n echo \"fetching image...\"\n wget -q http://192.168.1.151/img_tmp/raw.jpg -O $value.jpg\n else\n echo \"Value did not change, skipping image fetching!\"\n fi\n\n cp value.txt value_previous.txt\n\n echo \"waiting 60s...\"\n sleep 60\ndone\n
"},{"location":"Demo-Mode/#use-prepared-images","title":"Use prepared images","text":"Instead of recoding your own images, you can use one of the selections of prepared images below.
"},{"location":"Demo-Mode/#how-does-it-work","title":"How does it work","text":"The Demo Mode tries to interfere as less as possible with the normal behavior. Whenever a Cam framebuffer gets taken (esp_camera_fb_get()), it replaces the framebuffer with the image from the SD card.
"},{"location":"Demo-Mode/#example-data-of-a-water-meter","title":"Example Data of a Water Meter","text":"You can use the following demo images if you want:
It covers a meter range from 530.00688 to 531.85882.
"},{"location":"Demo-Mode/#animation","title":"Animation","text":"Animation of the watermeter (77 MB!)
"},{"location":"Demo-Mode/#selection-of-84-images","title":"Selection of 84 images","text":"Demo_Images_Watermeter_530.00688-532.08243_84_images.zip
"},{"location":"Demo-Mode/#selection-of-42-images","title":"Selection of 42 images","text":"Demo_Images_Watermeter_530.00688-532.08243_42_images.zip
"},{"location":"Demo-Mode/#all-images-843-images","title":"All images (843 images)","text":"Demo_Images_Watermeter_530.00688-532.08243_843_images.zip
"},{"location":"Error-Codes/","title":"Reduced webinterface (error indication and tracing)","text":"Whenever an error occurs during boot process which avoids loading of regular processing and regular webinterface, a reduced webinterface gets loaded to have at least some visual feedback and the possibilitiy to figure out the root cause by browsing the logfiles or trigger another OTA update.
The error code(s) get printed with specific error codes. This page lists the possible error codes, their meaning and possible solutions.
Notes
Here the error codes are defined in source code: error codes.
"},{"location":"Error-Codes/#critical-errors","title":"Critical Errors","text":"Those Errors make the normal operation of the device impossible. Most likely they are caused by a hardware issue!
"},{"location":"Error-Codes/#0x00000001-psram-bad","title":"0x00000001 PSRAM bad","text":"Your device most likely has no PSRAM at all or it is too small (needs to have at least 4 MBytes)! See Hardware Compatibility.
Usually the log shows something like this:
psram: PSRAM ID read error: 0xffffffff\ncpu_start: Failed to init external RAM!\n
"},{"location":"Error-Codes/#0x00000002-heap-too-small","title":"0x00000002 Heap too small","text":"The firmware failed to allocate enough memory. This most likely is a consequential error of a bad PSRAM!
"},{"location":"Error-Codes/#0x00000004-cam-bad","title":"0x00000004 Cam bad","text":"The attached camera can not be initialized. This usually is because on of the following reasons:
- The camera is not supported, see Hardware Compatibility
- The camera is not attached properly -> Try to remove and attach it again. Make sure you move the black part enough into the socket!
- The camera or the camera cable is damaged
"},{"location":"Error-Codes/#0x00000008-sd-card-basic-check-failed","title":"0x00000008 SD card basic check failed","text":"One or more basic SD card checks failed.
The following checks are performed during boot sequence:
- Write a file (sdcard/sdcheck.txt) to SD card with some generic text
- Read the written file back
- CRC verification
- Delete the file
Detailed error indication (write, rerad or delete error) can be derived from blinking code of red board status LED. Please refer to StatusLED-BlinkCodes
Recommendation: Reformat SD card and check again or try another SD card
"},{"location":"Error-Codes/#0x00000010-sd-folder-or-file-presence-check-failed","title":"0x00000010 SD folder or file presence check failed","text":"One or more mandatory folders and/or files are missing on SD card. To have early indication that SD card is potentially ready for operation, some folder and files, which are mandatory are presence checked. This is not a 100% check and a successful test does not mean everthing is OK.
The following folders / files get checked during boot sequence:
- /sdcard/config
- /sdcard/html
- /sdcard/demo --> created automatically in firmware
- /sdcard/firmware --> created automatically in firmware
- /sdcard/img_tmp --> created automatically in firmware
- /sdcard/log --> created automatically in firmware
- /sdcard/wlan.ini
- /sdcard/config/config.ini
- /sdcard/html/index.html
- /sdcard/html/ota_page.html
- /sdcard/html/log.html
- /sdcard/html/common.js
- /sdcard/html/version.txt
Notes
This list might be outdated, see the source code for the latest implementation: SDCardCheckRW()
Recommendation: Check logs and / or redo a Over-The-Air Update (OTA Update) to ensure proper SD card structure
"},{"location":"Error-Codes/#non-critical-errors","title":"Non-Critical Errors","text":"Those Errors can be caused by an error during initialization. It is possible that the error has no impact at all or that a reboot solves it.
"},{"location":"Error-Codes/#0x00000100-cam-framebuffer-bad","title":"0x00000100 Cam Framebuffer bad","text":"The firmware was unable to initialize the Camera Framebuffer. The firmware will continue to work, but other consequential error might arise. A reboot of the device might help.
This might also be caused by a corrupred SD-Card, see CAM is not working anymore\" on init #2390
"},{"location":"Error-Codes/#0x00000200-ntp-failed","title":"0x00000200 NTP failed","text":"The firmware failed to get the world time from an NTP server. The firmware will continue to work, but has a wrong time.
"},{"location":"Error-Debugging/","title":"Often observed issues","text":""},{"location":"Error-Debugging/#hardware-failure","title":"Hardware failure","text":" - Camera not working --> check the interface, test another module
- Low cost module with no or only 2MB memory instead of 4MB --> test another module
- SD card issues --> test another SD card
- Wifi reception bad / unstable --> bad antenna, test another module or use external antenna
More information in terms of hardware, component and basic configuration issues can be found here: Reboot reasons
"},{"location":"Error-Debugging/#roi-misaligned","title":"ROI misaligned","text":"This typically happens if you have suboptimal \"Alignment Marks\". A very simple and working solution is to put put higly contrasted stickers on your meter and put \"Alignment Marks\" on it (see picture below)
If after those adjustment you still have some issues, you can try to adjust your alignment settings in expert mode:
"},{"location":"Error-Debugging/#my-analog-meter-are-recognized-as-digit-counter-or-vice-versa","title":"My Analog Meter are recognized as Digit Counter or vice versa","text":" - First, check that your ROI are correctly defined (yey!)
- Second, verify that the name of your ROI analog and digit ROIs are different
"},{"location":"Error-Debugging/#recognition-is-working-well-but-number-arent-sorted-correctly","title":"Recognition is working well, but number aren't sorted correctly","text":"You have to sort your ROI correctly (Bigger to smaller). Select your ROI and click either \"move next\" or \"move previous\". Repeat until your ROI are correctly sorted
"},{"location":"External-LED/","title":"External LED","text":"The internal flash LED is very close to the camera axis. This results in reflection, especially in case of flat glass surfaces such as for power meters. To circumvent this problem, it is now possible to control external LEDs, which than can be places somewhere else in the setup. As not simples LEDs are used, but RGB LEDs with a digital interface like WS2812 not only the position, but also the color and intensity of the illumination can now be adjusted. The following image shows a direct comparison of the \"old\" internal flash LED and two off axis LEDs.
There is also a new meter adapter available. This has two features: designed for small clearings in front of the meter and prepared for WS2812 LEDs.
"},{"location":"External-LED/#1-hardware-installation-of-the-led-stripe","title":"1. Hardware installation of the LED stripe","text":"The control line of the LED stripe is connected with a 470 Ohm resistor to the GPIO12. For power supply stabilization a capacitor between 5V and ground is recommended. Here a 470\u00b5F polymer capacitor is used. As a power supply a 5V from the ESP32 is used like in the following wiring.
"},{"location":"External-LED/#2-software-configuration","title":"2. Software configuration","text":"The handling of the WS2812 LED controller needs some other libraries, therefore it is controlled within a dedicated section called GPIO Settings. The external LED stripe is connected to GPIO12. After activating the \"GPIO Settings\" section, the internal flash is per default disabled. In order to activate the external LED, you need to activate GPIO 12 state and select \"extern flash light ws281x ...\".
Parameter Meaning LED-Type There are several types of controller implemented: WS2812(B), WS2813, SK6812 Numbers of LED Number of LEDs on the LED stripe LED Color The color and intensity can be controlled directly by a red/green/blue value, each within the range from 0 (off) to 255 (full) Enabling the GPIO settings automatically disables the flash LED. Therefore you can enable it here manually by checking GPIO4 and choose \"build-in led flash light\". It is not recommended to use both illumination parallel.
"},{"location":"FAQs/","title":"Frequently Asked Questions","text":""},{"location":"FAQs/#my-device-reboots-frequently-what-can-i-do","title":"My device reboots frequently. What can I do?","text":"There are several reasons for frequent reboots:
- Frequent HTML requests
- Wrong configuration, missing configuration files
- Unstable hardware - see Hardware Compatibility.
There is a dedicated page about this: Frequent Reboots.
"},{"location":"FAQs/#bad-webui-responsiveness-what-can-i-do","title":"Bad WebUI responsiveness. What can I do?","text":"This is usually due to hardware or WLAN issues. There are already many entries in discussion section, some of which have good tipps.
Possible checks / ideas:
- ESP32CAM hardware antenna design is very poor in connection with camera frequency.
- Simple test: When the device is in operation, putting your thumb on the camera connector and the directly adjacent components should make the device respond more quickly.
- Possible optimization: Here, an attempt was made to dampen the frequency influences somewhat by shielding. Shielding Example
- WLAN channel: Preferably use channel 1, 6 or 11
- Performance can vary depending on the AP manufacturer. If necessary, check with a mobile hotspot or other device to exclude AP influence
- Try with an external antenna
- Avoid VLAN, currently not fully supported
- Temporarily deactivate virus scanner / firewall on the end device for testing purpose
- Use sufficiently dimensioned power supply
- Use a branded SD card (formatted with Windows, MAC often causes problems)
Check discussion section for possible further tipps.
"},{"location":"FAQs/#how-accurate-are-the-detections","title":"How accurate are the detections?","text":"It is hard to give a specific accuracy number. It depends on many factors, e.g.
- How in-focus is your camera?
- How sturdy is the camera mount? Does it slightly move over extended periods of time?
- What type of meter are you reading? Is the meter already in the training data set?
- Are you trying to read digits, an analog dial, or both?
- etc.
Anecdotally, the authors of this page have great success with the meter. While the AI algorithm itself is not perfect and sometimes returns NaN or incorrect values, other post-processing / prevalue / sanity checks help ensure such invalid values are filtered out. With the correct settings, one author has been running this device for 1 month without any incorrect values reported.
See the FAQs below for more details and configuration hints.
"},{"location":"FAQs/#my-numbers-are-not-correctly-detected-what-can-i-do","title":"My numbers are not correctly detected. What can I do?","text":" - There is a dedicated page about the correct setting ROI Configuration.
- This page also includes the instructions for gathering new images for the training.
"},{"location":"FAQs/#how-can-i-ensure-invalid-numbers-are-never-reported","title":"How can I ensure invalid numbers are never reported?","text":"As mentioned above, the AI algorithm is not perfect. Sometimes it may read an incorrect value.
We can tune the software to almost never report an incorrect value. There is a tradeoff though: the software may report stale values - i.e. it will drop incorrect values for a potentially long period of time, resulting in the meter reading being outdated by hours. If never receiving an incorrect value is important to you, consider tolerating this tradeoff.
You can change the following settings to reduce incorrect readings (but potentially increase staleness of data):
- Set a prevalue via the UI, then change
PostProcessing configuration option PreValueAgeStartup to a much larger number (e.g. 43200 = 30 days). - Change
PostProcessing configuration option MaxRateType to be time based instead of absolute. Set MaxRateValue to something realistic (e.g. 5 gal/min). You can often find the max flow rate your meter supports directly on the cover. - Reduce
AutoTimer configuration option Interval to the lowest it can be (e.g. 3 min). The more often you take readings, the less likely for data staleness to occur.
"},{"location":"FAQs/#even-after-i-have-setup-everything-perfect-there-is-a-false-reading-especially-around-the-zero-crossing-roll-over-to-next-number","title":"Even after I have setup everything perfect there is a false reading - especially around the zero crossing (roll over to next number)","text":" - The roll over behavior is different for the different meters. E.g.:
- Rolling over start with different previous position (e.g. at 7, 8 or 9)
-
The neutral position (no rolling) is not perfectly at zero, but rather at something like 7.9 or 8.1, even if it should be exactly 8
-
The \"PostProcessingAlgo\" is trying to judge out of the individual readings, what number it should be.
-
For example if the previous number is a \"1\", but the next number seems to be a \"8.9\", most probably there was a \"zero crossing\" and the number is a \"9\" and not still an \"8\"
-
Currently the setting of the algorithm is set to fit most of the meters and cases. But the parameters do not fit perfectly for all situations. Therefore there might be intermediate states, where the reading is false. This is especially the case, at the positions, where the roll over (zero crossing) is just starting.
- To prevent a sending of false parameters, there is the possibility to limit the maximum allowed change (MaxRateChange). Usually after some time and movement of the counters a bit further, the reading is getting back to a stable reading.
- To handle this, a parametrized setting would be needed. This is rather complicated to implement as subtle changes make a relevant difference. Currently this is not implemented. So please be a bit patient with your meter :-)
"},{"location":"FAQs/#pre-value","title":"Pre-Value","text":"PreValue is here a bit missleading, because normally it is the same as the last value. In the next round of reading it will be used to check nagtive rates, high rates (MaxRateValue / MaxRateType) and CheckDigitIncreaseConsistency (dig-class11 only). Either from a previous correctly identified value or manual setting by the user.
If you use post processes, enable the pre-value. The pre-value must be set at first time. Set it to the current raw value.
If the device runs in errors, the pre-value will not be updated, as long as the preValueAgeStartup time between the last valid value (or startup time) and current time is not exceeded. After it the preValue will be set again, if no other error occured. So the device can not run in an endless error, like high rate.
"},{"location":"FAQs/#rate-too-high-read","title":"\"Rate too high - Read: ...\"","text":"In configuration you can set the MaxRateValue and MaxRateType. The settings suppress improbably high values that can come from false readings. To do this, the value must be set correctly depending on your meter.
Before doing this, you should be clear about the type of rating you want to use.
Absolute change is the interval between two readings - no matter how often the readings happen. RateChange is the change per minute. This is calculated from the time difference between the last and the current reading.
If there is an interval of 5 minutes between readings and a MaxRateValue of 1, an error \"Rate too high - Read: ...\" if
- Absolute change: the difference is
> 1 - RateChange: the difference is
> 1 / 5
"},{"location":"FAQs/#train-on-my-own-images","title":"Train on my own images","text":"Look at Learn models with your own images and Cookbook running the jupyter notebook with my own data.
"},{"location":"FAQs/#what-does-aioted-mean","title":"What does AIOTED mean?","text":"This is just the abbreviation of AI-on-the-edge-device.
"},{"location":"Frequent-Reboots/","title":"Basic hardware / configuration issues","text":"If the device is behaving eratically or not running as expected you can use the following tools trying to identify the root cause:
- Internal logging (
config.ini) --> Set to DEBUG log level - Reduced web interface (only error indication visualization, Error codes on reduced webinterface)
- Red board LED: Status LED Blinkcodes
- Serial log of the UART interface (USB access needed, only local, same as for flashing the firmware)
There are in principle two reboots types:
- Sporadic random reboots (always different timing and situation)
- Repeating boot loops (reoccuring, always stop working after same precondition)
"},{"location":"Frequent-Reboots/#sporadic-random-reboots","title":"Sporadic random reboots","text":"Sporadic random reboots could have the following reasons:
- In general: Unstable system due to software issues (e.g. overload during HTML access, ...) --> Trying the figure out what's the root cause to fix the issue
- Bad power supply --> The power supply need to stable to ensure proper operation of the device. If it's not stable the device tents to sporadic reboots (brownout detection)
In general: There are several mechanisms in the firmware (like saving previous values), to have a \"smooth\" reboot without too many notable disturbance.
"},{"location":"Frequent-Reboots/#system-instabilities","title":"System instabilities","text":"If your system is sometimes running smoothly over several runs and sometimes reboots obviously randomly, you have an partially unstable device.
You can check this in the standard log file on the SD card:
2021-12-26T06:34:09: task_autodoFlow - round done\n2021-12-26T06:34:09: CPU Temperature: 56.1\n2021-12-26T06:38:00: task_autodoFlow - next round - Round #23\n
Here you see, that the round #23 is starting, so obviously there were no reboots in the last 22 rounds. There is hardware (ESP32CAM), where only 2-3 stable rounds are possible and others, where way more than 100 rounds without any reboots is possible. There is noting you can do about it, beside testing different hardware.
"},{"location":"Frequent-Reboots/#overload-during-html-access","title":"Overload during HTML access","text":"If you frequently access the web server over HTML requests, the firmware tends to reboot. This especially happens during the first run and when the ESP32 is busy with the digitization flow.
The reason for this are running out of memory during a flow, minor memory leakage in combination with missing error handling.
There is noting you can do about this kind of reboot, beside two thing:
- Support the firmware development with improved and tested part of code
- Be patient :-)
"},{"location":"Frequent-Reboots/#bad-or-insufficient-power-supply","title":"Bad or insufficient power supply","text":"A good and stabilized power supply is essential to have error free operation. The device is quite picky in terms of proper power supply. Especially the wifi module have some load spikes which the power supply needs to cover. If the power is not stable enough, the brwonout mechanism is protecting against strange behaviour and force a reboot whenever the voltage drops below a specific level. You can see this in random reboots which indication is logfile: --> Reset reason: Brownout
"},{"location":"Frequent-Reboots/#repeating-boot-loops","title":"Repeating boot loops","text":"Repeating boot loops at the same situation during the flow has a systematic problem either in the hardware or the configuration. It usually happens during initialization state or processing the first round as there all needed parts of the firmware have been loaded for the first time.
To identify the root cause the logfiles, the reduced web interface, the red board LED or the serial log of the UART interface (no remote access, USB access needed) is helpful.
Possible issues:
- SD card related issues
- RAM related issues
- Configuration related issues
"},{"location":"Frequent-Reboots/#sd-card-related-issues","title":"SD card related issues","text":"The ESP32CAM is a little bit \"picky\" with the supported SD cards. Due to the limited availability of GPIOs the SD card can only be accessed via 1-wire mode. Therefore not all SD cards are supported. The following error cases can occur:
"},{"location":"Frequent-Reboots/#sd-card-wrong-filesystem-only-fat32-is-supported","title":"SD card: Wrong filesystem (only FAT32 is supported)","text":"If this SD card error is detected only the following indications are available. No web interface will be accessible.
- Red board LED is blinking. The blinking codes are described here: Status LED Blinkcodes
- Error messages on serial log (UART interface)
"},{"location":"Frequent-Reboots/#sd-card-not-detected-not-supported","title":"SD card not detected / not supported","text":"If this SD card error is detected the following indication are available. No web interface will be accessible.
- Red board LED is blinking. The blinking codes are described here: Status LED Blinkcodes
- Error messages on serial log (UART interface)
"},{"location":"Frequent-Reboots/#sd-card-detected-but-files-are-not-readable-writeable","title":"SD card detected but files are not readable / writeable","text":"The SD card is detected, but the files cannot be read or written. A basic SD card check for SD reading / writing is performed on every boot. This not 100% guarantee that SD card is working but it's at least a indication.
If this SD card error is detected the following indications are available:
- The reduced web interface will be loaded to have visual feedback of error situation. Regualar processing is disabled, though. Within this reduced web interface logs can be viewed to have further indication what's the root cause. Error code desciption can be found here: Error codes on reduced webinterface
- Error messages in logfile
- Red board LED is blinking. The blinking codes are described here: Status LED Blinkcodes
- Error messages on serial log (UART interface)
"},{"location":"Frequent-Reboots/#ram-related-issues","title":"RAM related issues","text":"In order to run the firmware, 4 MB of external RAM (PSRAM) are mandatory. Usually, the ESP32CAM is equipped with 8MB (64Mbit) PSRAM chip, whereof only 4MB can be used effectively (direct addressable). Unfortunately, there is hardware around, where no PSRAM or only 2MB of PSRAM is present - even if you have bought a device where a 8MB PSRAM was promoted. These modules are not suiable for this firmware because the external RAM is needed to handle the CNN files and camera images. There is nothing to do, than to buy a new ESP32CAM with really 64MBit of PSRAM.
"},{"location":"Frequent-Reboots/#too-less-external-ram-psram","title":"Too less external RAM (PSRAM)","text":"During the boot process the available RAM is going to be checked.
If there is too less RAM (PSRAM or total HEAP < 4MB) detected, the follwoing indications are available:
- The reduced web interface will be loaded to have visual feedback of error situation. Regualar processing is disabled, though. Within this reduced web interface logs can be viewed to have further indication what's the root cause. Error code desciption can be found here: Error codes on reduced webinterface
- Error messages in logfile
- Red board LED is blinking. The blinking codes are described here: Status LED Blinkcodes
- Error messages on serial log (UART interface)
"},{"location":"Frequent-Reboots/#configuration-related-issues","title":"Configuration related issues","text":""},{"location":"Frequent-Reboots/#folders-and-files-missing","title":"Folders and files missing","text":"Most of the relevant folders and files are checked during boot. The complete list can be found here: Error codes on reduced webinterface
If a relevant folder or file is missing the following indications are available:
- The reduced web interface will be loaded to have visual feedback of error situation. Regualar processing is disabled, though. Within this reduced web interface logs can be viewed to have further indication what's the root cause. Error code desciption can be found here: Error codes on reduced webinterface
- Error messages in logfile
- Red board LED is blinking. The blinking codes are described here: Status LED Blinkcodes
- Error messages on serial log (UART interface)
"},{"location":"Frequent-Reboots/#cnn-model-file-not-available-corrupt","title":"CNN model file not available / corrupt","text":"Additionally for operation CNN model files on SD card are mandatory, one CNN model file for analog counter and for for digit numbers each.
/config/XXXXX.tflite (XXXXX is the file name, that is written in the config.ini)
If the files which are configured in config.ini are not present or corrupt, the process is going to be interrupted (or at worst case a device crash occurs). Please check logs files to have an indicator for the root cause.
This a logfile extract (DEBUB log level) where digit CNN model file is not present. The system is initializing the system and trying to load the model files:
[0d00h05m11s] 2023-03-27T12:25:14 [TFLITE] CTfLiteClass::LoadModel\n[0d00h05m11s] 2023-03-27T12:25:14 [TFLITE] CTfLiteClass::ReadFileToModel: /sdcard\n[0d00h05m11s] 2023-03-27T12:25:14 [PSRAM] Failed to allocate 0 bytes in PSRAM for 'TFLITE->modelfile'!\n[0d00h05m11s] 2023-03-27T12:25:14 [TFLITE] CTfLiteClass::ReadFileToModel: Can't allocate enough memory: 0\n[0d00h05m12s] 2023-03-27T12:25:14 [HEAP] CTfLiteClass::ReadFileToModel Heap Total: 2266214 | SPI Free: 2205939 | SPI Large Block: 2162688 | SPI Min Free: 2205423 | Int Free: 60275 | Int Large Block: 55296 | Int Min Free: 46451\n[0d00h05m12s] 2023-03-27T12:25:14 [CNN] Can't load tflite model -> Init aborted!\n[0d00h05m12s] 2023-03-27T12:25:14 [HEAP] getNetworkParameter-LoadModel Heap Total: 2266214 | SPI Free: 2205939 | SPI Large Block: 2162688 | SPI Min Free: 2205423 | Int Free: 60275 | Int Large Block: 55296 | Int Min Free: 46451\n[0d00h05m12s] 2023-03-27T12:25:14 [PSRAM] Freeing memory in PSRAM used for 'TFLITE->modelfile'...\n[0d00h05m12s] 2023-03-27T12:25:14 [PSRAM] Freeing memory in PSRAM used for 'TFLITE->tensor_arena'...\n[0d00h05m12s] 2023-03-27T12:25:14 [PSRAM] Allocated 819200 bytes in PSRAM for 'TFLITE->tensor_arena'\n[0d00h05m12s] 2023-03-27T12:25:14 [TFLITE] CTfLiteClass::LoadModel\n[0d00h05m12s] 2023-03-27T12:25:14 [TFLITE] CTfLiteClass::ReadFileToModel: /sdcard/config/ana-cont_1105_s2_q.tflite\n[0d00h05m12s] 2023-03-27T12:25:15 [PSRAM] Allocated 53328 bytes in PSRAM for 'TFLITE->modelfile'\n[0d00h05m12s] 2023-03-27T12:25:15 [TFLITE] CTfLiteClass::MakeAllocate\n[0d00h05m12s] 2023-03-27T12:25:15 [PSRAM] Freeing memory in PSRAM used for 'TFLITE->modelfile'...\n[0d00h05m12s] 2023-03-27T12:25:15 [PSRAM] Freeing memory in PSRAM used for 'TFLITE->tensor_arena'...\n
"},{"location":"Hardware-Compatibility/","title":"Hardware Compatibility","text":""},{"location":"Hardware-Compatibility/#general-remark","title":"General Remark","text":"Although a board looks similar, it can have major differences, e.g.:
- Processor
- Ram (Size! & Type) -> this Project needs at least 4MB RAM!
- Flashrom
- Camera Modules
- Onboard/External Antenna
- Quality of Components
- Manufacture Quality of the PCB and soldering
- Different Components
- \"Clone\" Components -> ESPxx
- etc.
This can cause different Power Consumption, Power Requirements, compatibility issues, etc.
Most manufacturers and sellers buy what's cheap today on the Asian markets. In the end, it looks like it is sometimes a trial and error approach which ESP32-CAM Module works reliably.
Below you find some remarks and experiences from the community:
"},{"location":"Hardware-Compatibility/#esp32-core-itself","title":"ESP32 core itself","text":"Chip Version Image Status ESP32-D0WDQ6 (revision 1) \u2714\ufe0f"},{"location":"Hardware-Compatibility/#psram","title":"PSRAM","text":"There seems to be a lot of \"fake\" chips, or maybe wrongly configured ESP32 Boards.
For AP MEMORY, all \"real\" APS6404*3SQR chips should work.
For ESP PSRAM, all \"real\" PSRAM64* should work.
64Mbit density = 8Mbyte PSRAM
This Table is just a snapshot of chips which worked
Labeling on PSRAM module Image Status IPUS / IPS640LS0 / 1815XBGN \u2714\ufe0f AP MEMORY / 6404L-3SOR / 1040H / 110089G \u2714\ufe0f AP MEMORY / 6404L-3SQR / 12205 / 150047G \u2714\ufe0f 8MB AP MEMORY / 6404L-3SQR / 12208 / 150047G \u2714\ufe0f 8MB AP MEMORY / 6404L-350R / 1120A / 130027G \u274c PSRAM not accessible AP MEMORY / 6404L-35QR / 11208 / 130025G \u274c PSRAM not accessible AP MEMORY / 6404L-3SQR / 13100 / 180026G \u274c PSRAM not accessible AP MEMORY / 6404L-3SQR / 11207 / 130024G \u274c PSRAM not accessible AP MEMORY / 6404L-3SQR / 1120A / 130027G \u2714\ufe0f 8MB AP MEMORY / 6404L-3SQR / 1120B / 130028G \u2714\ufe0f 8MB AP MEMORY / 6404L-3SQR / 1120D / 130030G \u2714\ufe0f 8MB AP MEMORY / 1604M-3SQR / 0280A / 070036G \u274c 2MB only! ESP PSRAM64H 462021 / 1B00286 \u2714\ufe0f ESP PSRAM64H 412021 / 1A0039G \u2714\ufe0f 8MB ESP PSRAM64H 402021 / 1A0017N \u274c PSRAM not accessible ESP PSRAM16M 302020 \u274c 2MB only! ESP PSRAM16H 202020 / 050022G \u274c 2MB only!"},{"location":"Hardware-Compatibility/#ov2640-camera","title":"OV2640 - Camera","text":"The experience with the camera only is based on single modules. It is well possible, that this module had a damage overall and other modules of the same type will work. Give it a try and report to me!
Labeling on Flex-Connector Image Status TY-OV2 / 640-V2.0 \u2714\ufe0f DCX-OV2 / 640-V2 \u2714\ufe0f DC-26 / 40-V3 \u2714\ufe0f 3x \u274c 1x"},{"location":"Hardware-Compatibility/#esp32-modules","title":"ESP32 Modules","text":"Module Image Status ESP32CAM / Different versions on the market!Especially the PSRAM is sometimes labeled wrong(Label: 4MB, Real: only 2 MB --> will not work!) \u2714\ufe0fwith >=4 MB PSRAM! ESP32-S3-EYENo Flash LED, pins different used (e.g. LCD display) NOT OKAY"},{"location":"Hardware-Compatibility/#sd-cards","title":"SD Cards","text":"Due to the limited free available GPIOs (due to all the extensions needed like: camera, SD card, LED-flash, ...) the SD card is connected in 1-wire mode. There are some cards, that are compatible with the esp32cam module for unknown reasons. It is observed, that smaller cards (up to 4 GB) tend to be more stable and larger cards have more problems. But quite some exceptions in the forums (4 GB cards not working, 16 GB cards working like a charm).
"},{"location":"Hardware-Compatibility/#devices-known-to-work","title":"Devices known to work","text":""},{"location":"Hardware-Compatibility/#modules-old-list-not-up-to-date-anymore","title":"Modules (Old list, not up-to-date anymore):","text":"See https://github.com/jomjol/AI-on-the-edge-device/discussions/1732 for a more recent list.
-
https://arduino-projekte.info/produkt/esp32-cam-v2-integriertem-ch340-mit-ov2640-kamera-modul/ (see https://github.com/jomjol/AI-on-the-edge-device/discussions/1041)
-
https://www.amazon.de/-/en/gp/product/B0B51CQ13R
-
https://www.reichelt.de/entwicklerboards-esp32-kamera-2mp-25--debo-cam-esp32-p266036.html?PROVID=2788&gclid=CjwKCAiAqaWdBhAvEiwAGAQlttJnV4azXWDYeaFUuNioMICh-jvxKp6Cifmcep9vvtoT2JRCDqBczRoC7Q0QAvD_BwE (27.12.2022)
"},{"location":"Hardware-Compatibility/#sd-card","title":"SD Card","text":" - Sandisk 2GB Micro SD Class 2 Sandisk 2GB AITRIP ESP32 and CAM ESP-32/CAM
- Amazon US - Aideepen ESP32-CAM W BT Board ESP32-CAM-MB Micro USB to Serial Port CH-340G with OV2640 2MP Camera Module Dual Mode with Amazon US - Cloudisk 5Pack 4GB Micro SD Card 4 GB MicroSD Memory Card Class6
"},{"location":"Hardware-Compatibility/#weak-wifi","title":"Weak Wifi","text":"The ESP32-CAM supports an external antenna. It requires some soldering skills but can improve the connection quality. See https://randomnerdtutorials.com/esp32-cam-connect-external-antenna/
"},{"location":"Influx-DB/","title":"Influx DB","text":"The device also supports direct sending of data to an Influx DB.
See also Influx Graph in Home Assistant.
"},{"location":"Installation/","title":"Installation","text":"The installation requires multiple steps:
- Get the right hardware and wire it up
- Flash the firmware onto the ESP32
- Write the data to the SD card
- Start it
For point 2 and 3 we provide multiple ways to do it. Pick the one that looks the easiest for you!
"},{"location":"Installation/#1-hardware","title":"1. Hardware","text":""},{"location":"Installation/#esp32-cam","title":"ESP32-CAM","text":" - OV2640 camera module
- Micro SD card slot
- 4 or 8 MB PSRAM.
It can be easily found on the typical internet stores, searching for ESP32-CAM for less than 10 EUR. How ever since the hardware is cheap and coming from China, you unluckily could pick a malfunctioning device. See Hardware Compatibility for further advice!
"},{"location":"Installation/#usb-uart-interface","title":"USB->UART interface","text":"For first time flashing the firmware a USB -> UART connector is needed. Later firmware upgrades than can be flashed via OTA.
"},{"location":"Installation/#power-supply","title":"Power supply","text":"For power supply a 5V source is needed. Most easily this can be done via a USB power supply. The power supply should support minimum 500mA. For buffering current peaks some users reported to use a large electrolytic capacitor like a 2200uF between ground and VCC.
Warning
In several internet forums there are problems reported, in case the ESP32-CAM is only supplied with 3.3V.
"},{"location":"Installation/#housing","title":"Housing","text":"A small 3D-printable example for a very small case can be found in Thingiverse here: https://www.thingiverse.com/thing:4571627
Warning
The focus of the OV2640 needs to be adjusted, as it is normally set from ~40cm to infinity. In order to get an image that is big enough, it needs to be changed to about 10cm. Therefore the sealing glue on the objective ring needs to be removed with a scalpel or sharp knife. Afterwards the objective can be rotated clockwise until the image is sharp again.
"},{"location":"Installation/#wiring","title":"Wiring","text":"Beside the 5V power supply, only for the first flashing a connection to the USB-UART connector, including a short cut of GPIO0 to GND for bootloader start.
A example for wiring can be found here:
It is also possible to use external LEDs for the illumination instead of the internal flash LED. This is described here
"},{"location":"Installation/#2-firmware","title":"2. Firmware","text":""},{"location":"Installation/#web-installer","title":"Web Installer","text":"There is a Web Installer available which will work right out of the web browser Edge and Chrome. You can access it with the following link: Web Installer
This is the preferred way for beginners as it also allows access to the USB Log:
"},{"location":"Installation/#manual-flashing","title":"Manual Flashing","text":""},{"location":"Installation/#files","title":"Files","text":"Grab the firmware from the
- Releases page (Stable, tested versions), or the
- Automatically build development branch (experimental, untested versions). Please have a look on Living on the Edge first!
You need:
- partitions.bin
- bootloader.bin
- firmware.bin
"},{"location":"Installation/#flashing-using-the-flash-tool-from-espressif-gui","title":"Flashing using the Flash Tool from Espressif (GUI)","text":"Get the Flash Download Tool from Espressif.
Download and extract the Flash tool, after starting choose \"Developer Mode\", then \"ESP32-DownloadTool\" and you are in the setup of the flashing tool. Connect the ESP32-CAM with the USB-UART connection and identify the COM-Port.
Warning
If you are re-flashing the code again, it is strongly recommended to erase the flash memory before flashing the firmware. Especially if you used OTA in between, which might cause remaining information on the flash, to still boot from an old image in the OTA-area, which is not erased by a normal flash.
Put your ESP32 in bootloader mode and push start, then it will identify the board and you can configure the bin-configuration according to the following table:
Filename Offset bootloader.bin 0x1000 partitions.bin 0x8000 firmware.bin 0x10000 "},{"location":"Installation/#flashing-using-the-python-based-esptool-console","title":"Flashing using the Python based esptool (Console)","text":"For this you need a python environment (e.g. Anaconda in Win10). Here you need to install the esptool:
pip install esptool\n
Then connect the ESP32 with the USB-UART connector to the system, put it in boot mode and with the following command you can erase the flash and flash bootloader, partitions and firmware in two steps: esptool erase_flash\nesptool write_flash 0x01000 bootloader.bin 0x08000 partitions.bin 0x10000 firmware.bin\n
- Maybe you need to specify the COM-port if it is not detected by default. - If the erase command throws the error A fatal error occurred: ESP32 ROM does not support function erase_flash., your esptool might be too old, see https://techoverflow.net/2022/02/08/how-to-fix-esp32-a-fatal-error-occurred-esp32-rom-does-not-support-function-erase_flash/ With some Python installations this may not work and you\u2019ll receive an error, try python -m pip install esptool or pip3 install esptool.
Further recommendations can be found on the espressif webpage.
"},{"location":"Installation/#3-sd-card","title":"3. SD Card","text":"The software expects an SD card prepared with certain directory and file structure in order to work properly. SD card most top directory should look like this:
This initial setup needs only to be done once as further updates (Firmware as well as SD card content) are possible with the Over-The-Air Update mechanism.
"},{"location":"Installation/#notes","title":"Notes","text":" - Due to the limited availability of GPIOs (OV2640, Flash-Light, PSRAM & SD card) the communication mode to the SD card is limited to 1-line SD-Mode. It showed up, that this results in problems with very large SD-Cards (64GB, sometimes 32 GB) and some no name low cost SD-cards.
- There must be no partition table on the SD-card (no GPT, but only MBR for the single partition)
- Following setting are necessary for formatting the SD-card: SINGLE PARTITION, MBR, FAT32 - 32K. NOT exFAT
- Some ESP32 devices share their SD-card and/or camera GPIOs with the pins for TX and RX. If you see errors like \u201cFailed to connect\u201d then your chip is probably not entering the bootloader properly. Remove the respective modules temporarily to free the GPIOs for flashing. You may find more information about troubleshooting on the homepage of Espressif.
The ESP32 indicates problems with the SD card during startup with a fast, endless blinking. In this case, please try another SD card.
"},{"location":"Installation/#manual-setup-with-an-sd-card-reader-on-a-pc","title":"Manual Setup with an SD Card Reader on a PC","text":" - Take the
AI-on-the-edge-device__manual-setup__*.zip from the Release page. - Open it and extract the
sd-card.zip. - Open it and extract all files onto onto your SD card.
- On the SD card, open the
wlan.ini file and configure it as needed: - Set the corresponding SSID and password
- The other parameters are optional
!!! Note The device provides a File Server which can be used to show, edit or delete the files on the SD card. For security reasons, the wlan.ini file is excluded from this and is hidden from external access to protect the password.
After this, you can insert the SD card into the ESP32 board and start it.
"},{"location":"Installation/#remote-setup-using-the-built-in-access-point","title":"Remote Setup using the built-in Access Point","text":"On startup of the ESP32, it checks if the wlan.ini or the config/config.ini are available on the SD card. If not, the ESP32 switches to a special mode. In this mode, it provides a Wifi Access Point which can be used to add the missing wlan.ini or the config/config.ini file.
- Take the
AI-on-the-edge-device__remote-setup__*.zip from the Release page. -
Connect to Access Point of the device. The SSID is \"AI-on-the-Edge\" and you can access it without any password:
The device has the following fixed IP: http://192.168.4.1.
-
Upload initial configuration to SD card
Use the select file and upload button to start the upload. A warning will show up if you have chosen a possible wrong file (without default configuration).
-
Store WLAN access information.
After the upload, a new page will be shown:
Enter your SSID and password.
Note
Only basic settings are supported. If you need advanced configuration (fixed ip, ...), you need to use the manual setup as documented above.
Warning
- Carefully check your wifi settings. To change them later on, you need to take out the SD card and edit the
wlan.ini manually (or delete it and start again). - The information is transferred without encryption!
Finish the step by pushing Write wlan.ini
-
Reboot
The final step is the reboot:
Warning
It will take up to 3 minutes. Afterwards you can find your device in the local network. Check your router for the IP. You can find it also in the USB Console output.
"},{"location":"Installation/#4-initial-startup","title":"4. Initial Startup","text":"After the firmware is flashed and the SD card is setup properly, you can start it. After power on the connection status is indicated by 3x blinking of the red on board LED.
WLAN-Status indication:
- 5 x fast blinking (< 1 second): connection still pending
- 3 x slow blinking (1 second on/off): WLAN connection established
Notes
It is normal that at first one or two times a pending connection is indicated.
"},{"location":"Integration-Home-Assistant/","title":"Integration into Home Assistant","text":"There are 3 ways to get the data into your Home Assistant:
- Using MQTT (Automatically Setup Entities using Home Assistant MQTT Discovery)
- Using MQTT (Manually Setup Entities)
- Using REST calls
The first one is the easier way if you already have MQTT in use.
"},{"location":"Integration-Home-Assistant/#using-mqtt-automatically-setup-entities-using-home-assistant-mqtt-discovery","title":"Using MQTT (Automatically Setup Entities using Home Assistant MQTT Discovery)","text":"Starting with Version >12.0.1, AI-on-the-edge-devices support Home Assistant Discovery.
- Check here to learn more about it and how to enable it in Homeassistant.
-
You also have to enable it in the MQTT settings of your device:
Make sure to select the right Meter Type to get the right units!
On the next start of the device, it will send discovery topics and Home Assistant should pick them up and show them under Settings > Integrations > MQTT:
"},{"location":"Integration-Home-Assistant/#using-mqtt-manually-setup-entities","title":"Using MQTT (Manually Setup Entities)","text":"First make sure with an MQTT client (for example MQTT Explorer) that MQTT works as expected and to get a list of the available topics!
Then add a sensor for each property:
mqtt:\n sensor:\n - state_topic: \"wasserzaehler/main/value\"\n name: \"Watermeter Value\"\n unique_id: watermeter_value\n unit_of_measurement: 'm\u00b3'\n state_class: total_increasing\n device_class: water # Needs Home Assistant 2022.11!\n icon: 'mdi:water-pump'\n availability_topic: wasserzaehler/connection\n payload_available: connected\n payload_not_available: connection lost\n\n - state_topic: \"wasserzaehler/main/rate\"\n name: \"Watermeter Rate\"\n unique_id: watermeter_rate\n unit_of_measurement: 'm\u00b3/min'\n state_class: measurement\n device_class: water # Needs Home Assistant 2022.11!\n icon: 'mdi:water-pump'\n availability_topic: wasserzaehler/connection\n payload_available: connected\n payload_not_available: connection lost\n\n - state_topic: \"wasserzaehler/main/error\"\n name: \"Watermeter Error\"\n unique_id: watermeter_error\n icon: \"mdi:water-alert\"\n availability_topic: wasserzaehler/connection\n payload_available: connected\n payload_not_available: connection lost \n\n - state_topic: \"wasserzaehler/uptime\"\n name: \"Watermeter Uptime\"\n unique_id: watermeter_uptime\n unit_of_measurement: 's'\n state_class: measurement\n device_class: duration\n entity_category: diagnostic\n icon: \"mdi:timer-outline\"\n availability_topic: wasserzaehler/connection\n payload_available: connected\n payload_not_available: connection lost\n
If you run the discovery once, you can also extract the information from there (MQTT Info, untested): mqtt: # Extracted form the Discovery but untested!\n sensor:\n - name: Value\n unique_id: wasserzaehler-main_value\n icon: mdi:gauge\n state_topic: wasserzaehler/main/value\n unit_of_measurement: m\u00b3\n device_class: water\n state_class: total_increasing\n availability_topic: wasserzaehler/connection\n payload_available: connected\n payload_not_available: connection lost\n
If you want to convert the m\u00b3 to l, use a template sensor:
template:\n - sensor:\n - name: \"Watermeter in l\"\n unique_id: watermeter_in_l\n icon: \"mdi:gauge\"\n state: \"{{ states('sensor.watermeter_value')|float(default=0) * 1000 }}\" # Convert 1 m3 => 1000 l\n unit_of_measurement: l\n availability: \"{{ states('sensor.watermeter_value') not in ['unknown', 'unavailable', 'none'] }}\"\n
If you you want to have the consumption per day, you can use an Utility Meter. it is a helper and can be used to reset the total increasing values once a day
utility_meter:\n utility_meter_gas_per_day:\n source: sensor.gasmeter_value\n cycle: daily\n\n utility_meter_water_per_day:\n source: sensor.watermeter_value\n cycle: daily\n
Note that you also can add it using the UI.
"},{"location":"Integration-Home-Assistant/#examples","title":"Examples","text":""},{"location":"Integration-Home-Assistant/#statistics-graph","title":"Statistics Graph","text":"Creating Statistics Graphs (e.g. usage per day) is easy using the Energy Dashboard:
Note that there seems to be a bug in the graph, see https://github.com/home-assistant/frontend/issues/13995!
"},{"location":"Integration-Home-Assistant/#influxdb-graphs","title":"InfluxDb Graphs","text":"See also Influx-DB.
If you have setup InfluxDB already, it is also possible to fetch statistics from there, e.g. daily usage:
from(bucket: \"HomeAssistant\")\n|> range(start: v.timeRangeStart, stop: v.timeRangeStop)\n |> filter(fn: (r) => r[\"entity_id\"] == \"wasserverbrauch_tag\")\n |> filter(fn: (r) => r[\"_field\"] == \"value\")\n |> timeShift(duration: -1d)\n |> aggregateWindow(every: 1d, fn: max, createEmpty: false)\n |> yield(name: \"mean\")\n
"},{"location":"Integration-Home-Assistant/#using-rest","title":"Using REST","text":"When using REST, Home Assistant has to periodically call an URL on the ESP32 which in return provides the requested data.
See REST API for a list of available URLs.
The most practical one is the json entrypoint which provides the most relevant data JSON formatted: http://<IP>/json This would return:
{\n\"main\":\n {\n \"value\": \"512.3020\",\n \"raw\": \"0512.3020\",\n \"error\": \"no error\",\n \"rate\": 0.000000,\n \"timestamp\": \"2022-10-02T20:32:06\"\n [..]\n }\n}\n
To do such a REST call, you need to create a REST sensor:
sensor:\n\n- platform: rest\n name: \"Gasmeter JSON\" \n resource: http://<IP>/json\n json_attributes:\n - main\n value_template: '{{ value_json.value }}'\n headers:\n Content-Type: application/json\n scan_interval: 60\n\ntemplate:\n sensor:\n - name: \"Gasmeter Value from JSON\"\n unique_id: gas_meter_value_from_json\n state: \"{{ state_attr('sensor.gasmeter_json','main')['value'] }}\"\n unit_of_measurement: 'm\u00b3'\n\n - name: \"Watermeter Value from JSON\"\n unique_id: water_meter_value_from_json\n state: >-\n {{ state_attr('sensor.watermeter_json','main')['value'] | float }}\n unit_of_measurement: 'm\u00b3'\n device_class: water\n state_class: total_increasing\n icon: mdi:gauge\n
The 2nd way is to use the html api call from value.html :
sensor: - platform: rest resource: http://<IP>/value.html name: cold_water unique_id: cold_water_from_rest unit_of_measurement: \"L\" device_class: water state_class: total_increasing icon: mdi:gauge scan_interval : 120
See also https://community.home-assistant.io/t/rest-sensor-nested-json/243420/9
"},{"location":"Integration-Home-Assistant/#photo","title":"Photo","text":"REST can also be used to show the photo of the last round:
To access it, use http://<IP>/img_tmp/alg_roi.jpg resp http://<IP>/img_tmp/raw.jpg.
"},{"location":"Learn-models-with-your-own-images/","title":"Learn a model with your own images","text":"Once you have collected and selected your own images (see Collect images to improve the models), you can train your very own model with them.
This is an optional step and only suggested for advances users!
For training the model you will need a python and Jupyter installation.
All current labeled images you can find under ziffer_sortiert_raw
"},{"location":"Learn-models-with-your-own-images/#dig-class11-models-digits","title":"dig-class11 models (digits)","text":"Fork and checkout neural-network-digital-counter-readout.
Install all requirements for running the notebooks.
pip install -r requirements.txt\n
Put your labeled images into /ziffer_sortiert_raw folder and run
- Image_Preparation.ipynb
- Train_CNN_Digital-Readout-Small-v2.ipynb
It creates a dig-class11_xxxx_s2.tflite model, you can upload to the config folder on your device and test it.
"},{"location":"Learn-models-with-your-own-images/#dig-class100-dig-cont-models-digits","title":"dig-class100 / dig-cont models (digits)","text":"Fork and checkout neural-network-digital-counter-readout.
All labeled images you can find under Images
Install all requirements for running the notebooks.
pip install -r requirements.txt\n
Put your labeled images into images/collected/<typeofdevice>/<your_short>/
Run dig-class100-s2.ipynb. The model to upload to your device you can find under '/output'.
"},{"location":"Learn-models-with-your-own-images/#ana-class100ana-cont-models-analog-pointers","title":"ana-class100/ana-cont models (analog pointers)","text":"Fork and checkout neural-network-analog-needle-readout.
All labeled images you can find under data_raw_all
Install all requirements for running the notebooks.
pip install -r requirements.txt\n
Put your labeled images into images/collected/<typeofdevice>/<your_short>/
After every adding of images you need to run Image_Preparation.ipynb before you train the models.
Run Train_CNN_Analog-Readout_100-Small1_Dropout.ipynb and/or Train_CNN_Analog-Readout_Version-Small2.ipynb. The model to upload to your device you can find in the project folder.
"},{"location":"Learn-models-with-your-own-images/#share-your-images","title":"Share your images","text":"If the results are good you can share the images as pull-request. Please images only!
See Share your images for details.
"},{"location":"MQTT-API/","title":"MQTT API","text":"The device is capable to register to a MQTT broker to publish data and subscribe to specific topics.
Note
Only MQTT v3.1.1 is supported.
The MQTT service has to be enabled and configured properly in the device configuration via web interface (Settings -> Configuration -> section MQTT)
The following parameters have to be defined: * URI * MainTopic (optional, if not set, the hostname is used) * ClientID (optional, if not set, AIOTED- + the MAC address gets used to make sure the ID is unique) * User (optional) * Password (optional) * RetainFlag (optional)
"},{"location":"MQTT-API/#published-topics","title":"Published topics","text":""},{"location":"MQTT-API/#status","title":"Status","text":"The following overhead data are available under the main topic (i.e. watermeter):
Topic Description watermeter/MAC The MAC address of the ESP module. watermeter/IP The IP address of the ESP module. watermeter/Hostname The network host name of the ESP module. watermeter/Interval The round interval as configured during setup or in Parameters -> Interval. watermeter/Connection Network connection status. watermeter/Uptime Seconds up since last boot. watermeter/FreeMem Free memory in kB. watermeter/wifiRSSI Quality of WiFi signal. watermeter/CPUTemp Temperature of the ESP CPU in degrees celsius."},{"location":"MQTT-API/#result","title":"Result","text":"The following calculation data are available under the sup-topic main (i.e. watermeter/main):
Topic Description watermeter/main/error Informs about the flow status. On success, the value is no error. watermeter/main/raw The value before performing post processing. watermeter/main/value The value after performing post processing. watermeter/main/rate How much flow was consumed in one minute. watermeter/main/rate_per_time_unit How much flow was consumed in one minute. The time unit gets set with the Home Assistant Discovery, e.g. h (hours) or m (minutes). watermeter/main/changeabsolut Difference between the previous and actual read value. watermeter/main/rate_per_digitization_round How much flow was consumed in one minute. watermeter/main/timestamp Timestamp of the last valid reading (equal to timestamp of previous value) watermeter/main/Status Informs about the last performed step of the watermeter (i.e. Flow finished). watermeter/main/json This is a JSON formatted object containing the following values: value, raw, pre, error, rate, timestamp."},{"location":"MQTT-API/#gpio","title":"GPIO","text":"MainTopic/{GPIO topic}, e.g. watermeter/GPIO/GPIO12
"},{"location":"MQTT-API/#gpiogpiopinnumber","title":"GPIO/GPIO{PinNumber}","text":"Depending on device configuration (Settings --> Configuration --> section GPIO)
"},{"location":"MQTT-API/#subscribed-topics","title":"Subscribed topics","text":"MainTopic/{subscribed topic}, e.g. watermeter/ctrl/flow_start
"},{"location":"MQTT-API/#control","title":"Control","text":""},{"location":"MQTT-API/#ctrlflow_start","title":"ctrl/flow_start","text":"Trigger a flow start by publishing to this topic.
This will automatically reset the flow interval.
"},{"location":"MQTT-API/#ctrlset_prevalue","title":"ctrl/set_prevalue","text":"Note
This feature is available since version 15.2.0.
Set the last valid value (previous value) to given value or the actual RAW value. Payload needs to be provided in JSON notation.
Payload:
-
Set to given value (value >= 0): {\"numbersname\": \"<NUMBERSNAME>\", \"value\": <VALUE>}
\"numbersname\":Provide name of number sequence, e.g. \"main\" \"value\": provide the value to be set, eg. 12345.67890
-
Set to actual RAW value (value < 0, a valid RAW value is mandatory): {\"numbersname\": \"<NUMBERSNAME>\", \"value\": -1}
\"numbersname\": Provide name of number sequence, e.g. \"main\" \"value\": Provide any negative number
"},{"location":"MQTT-API/#gpiogpiopinnumber_1","title":"GPIO/GPIO{PinNumber}","text":"Depending on device configuration (Settings --> Configuration --> section GPIO)
"},{"location":"Neural-Network-Types/","title":"Neural Network Types","text":"Note
For an overview, see Choosing the Model.
This section is describing the different types of neural networks, that are used with the AI-on-the-edge approach and gives an introduction on how and where to use them.
"},{"location":"Neural-Network-Types/#overview-neural-network-type","title":"Overview neural network type","text":"There are two types of input:
There are two types of neural networks:
- classification networks with discrete output neurons for each result class:
- 11 classes for digits (0, 1, ... 8, 9 + \"Not-A-Number\")
- 100 classes for digits or analog pointers (0.1, 0.2, 0.3, ... , 9.7, 9.8, 9.9)
- continuous output networks with a continuous output in the interval [0, 10[
No setting of the type in the firmware is necessary. The type can detect by the output structure automatically.
Warning
- It is very important to choose the right network type (digits or analog pointers). Technically a wrong network will work and create output, but that would be totally arbitrary
- Not all type of pointers are trained in all networks.
- For the 11 classes digits network there many different types of digits trained. The reason is, that you 1) only need 20-30 training images and 2) the data collection is ongoing much longer
- For the continuous and 100 classes network especially for the digits, there are only a few types of digits trained up to now
- Therefore sometimes for the digits it is more effective to choose the simpler 11 classes network type (= default).
"},{"location":"Neural-Network-Types/#naming-convention","title":"Naming convention","text":"Classification11 classes0, 1, ... 9 + \"N\" Classification100 classes0.0, 0.1, ... 9.9 ContinuousInterval[0, 10[ Digits dig-class11_XXX.tflite dig-class100_XXX.tflite dig-cont_XXX.tflite Analog Pointers ana-class100_XXX.tflite ana-cont_XXX.tflite XXX contains the versioning and a parameter for different sizes with the following naming:
XXX = versioning_sY
-
versioning = version or in newer networks the training data
-
Y = Neural network size (typically s1, s2, ..., s4). Whereas s1 is the maximum sized neural network and s4 is the smallest.
Optional the naming ends with an \"_q\" to signal, that the tflite file has been quantized (size reduction with minimum accuracy loss).
Example: dig-class11_1410_s2_q.tflite
- Classification network for digits with 11 classes (0, 1, 2, 3, 4, 5, 6, 7, 8, 9, N)
- Version 1410 = 14.1.0
- s2 = Size 2 (Medium)
- q = Quantized Version
"},{"location":"Neural-Network-Types/#overview-of-trained-types-and-details","title":"Overview of trained types and details","text":""},{"location":"Neural-Network-Types/#analog-pointer-ana-cont_xxxtflite-ana-class100_xxxtflite","title":"Analog Pointer (\"ana-cont_XXX.tflite\" & \"ana-class100_XXX.tflite\")","text":"This is to transfer the direction of a pointer into a continuous number between 0 and 1, whereas 0 (=1) is the upwards position (12 o'clock), 0.25 corresponds to the 3 o'clock positions and so on. This network is a envelop for all different types of pointers. Currently there are no dedicated network trainings for specific types of pointers.
There are two types of network structure, currently both are supported. The \"class100\" is a pure classification network, that might need a bit more accuracy in the labeling. \"cont\" is a no classic approach with a continuous output off only 2 neurons (details see below).
"},{"location":"Neural-Network-Types/#types-of-counters-trained","title":"Types of counters trained:","text":""},{"location":"Neural-Network-Types/#training-data-needs","title":"Training data needs","text":" - Quadratic images, minimum size: 32x32 pixel
- Typically 100 - 200 images with a resolution of 1/100 of the full rotation (every 0.1 value or 3.6\u00b0)
- Naming: x.y_ARBITRARY.jpg, where x.y = value 0.0 ... 9.9
"},{"location":"Neural-Network-Types/#cnn-technical-details","title":"CNN Technical details:","text":""},{"location":"Neural-Network-Types/#input","title":"Input","text":""},{"location":"Neural-Network-Types/#output","title":"Output","text":""},{"location":"Neural-Network-Types/#digits-with-11-classes-dig-class11_xxxtflite","title":"Digits with 11 classes (\"dig-class11_XXX.tflite\")","text":"The digit type is a classical classification network, with 11 classes representing the numbers 0, 1, ... 9 and the special class \"N\". It is trained for the rolling ring of gas and electric meters. As there is sometime a status between two images, the special class \"N\" is representing Not-A-Number for the case, that the image cannot be unique classified to one number e.g. because it is between two digits. For this type the lowest amount of training data per type is needed, resulting in a large variety of type being already part of the training set.
"},{"location":"Neural-Network-Types/#types-of-counters-trained_1","title":"Types of counters trained:","text":""},{"location":"Neural-Network-Types/#training-data-needs_1","title":"Training data needs","text":" - RGB images, with minimum size: 20x32 pixel
-
Typically 10 - 20 images (1-2 for each digit and an arbitrary number for the \"N\" class
-
Naming: x_ARBITRARY.jpg, where x = value 0 ... 9 + N
"},{"location":"Neural-Network-Types/#cnn-technical-details_1","title":"CNN Technical details:","text":""},{"location":"Neural-Network-Types/#input_1","title":"Input","text":""},{"location":"Neural-Network-Types/#output_1","title":"Output","text":" - 11 neurons for image classification (last layer normalized to 1)
- Neuron 0 to 9 represent the corresponding numbers \"0\" to \"9\"
- Neuron 10 represents the \"Not-A-Number\" class, telling, that the image is not uniquely classified
"},{"location":"Neural-Network-Types/#digits-with-rolling-results-dig-class100_xxxtflite-dig-cont_xxxtflite","title":"Digits with rolling results (\"dig-class100_XXX.tflite\" & \"dig-cont_XXX.tflite\")","text":"This type of network tries to overcome the problem, that there are intermediate values, when a rolling digit is between two numbers. Previous this was the \"N\" class. In this network type, there are also sub-digit values trained, so that the intermediate state can be used as additional information for the algorithms.
"},{"location":"Neural-Network-Types/#types-of-counters-trained_2","title":"Types of counters trained:","text":""},{"location":"Neural-Network-Types/#training-data-needs_2","title":"Training data needs","text":" - RGB images, with minimum size: 20x32 pixel
-
Typically 100 - 200 images (1-2 for each possible position)
-
Naming: x.y_ARBITRARY.jpg, where x.y = 0.0, 0.1, ... 9.9 representing the intermediate state
"},{"location":"Neural-Network-Types/#cnn-technical-details_2","title":"CNN Technical details:","text":""},{"location":"Neural-Network-Types/#input_2","title":"Input","text":""},{"location":"Neural-Network-Types/#output_2","title":"Output","text":""},{"location":"New-Releases-Notification/","title":"Notification about new Releases","text":"Do you want to get notified about a new release? There are several ways for it:
"},{"location":"New-Releases-Notification/#github-notifications","title":"Github Notifications","text":"You will need a Github Account for this!
- Log into your Github account on Github.
- Go to AI-on-the-edge-device.
- On the top right side, click onto
Watch and select Custom: - Select
Releases.
You will get an email when a new release gets created.
See also Github Documentation.
"},{"location":"New-Releases-Notification/#codereleaseio","title":"CodeRelease.io","text":"Alternatively or if you do not want to create a Github account, CodeRelease.io can be an alternative.
You also have to subscribe with an email address but no account is required.
"},{"location":"Parameters/","title":"Parameters","text":"This page lists all available Configuration Parameters. If a parameter or section has a tick box on its left side, you can disable it. In such case the functionality gets disabled respectively the default values will be used.
Note
This is an auto-generated page! See the README for details!
"},{"location":"Parameters/#section-takeimage","title":"Section TakeImage","text":""},{"location":"Parameters/#parameter-camaelevel","title":"Parameter CamAeLevel","text":"Auto-Exposure-Level
range on OV2640 (-2 .. 2) range on OV3660 and OV5640 (-5 .. 5)
Section: TakeImage
Default Value: 0
See here for the ov2640 camera datasheet. See here for the ov5640 camera datasheet.
Warning
This is an Expert Parameter! Only change it if you understand what it does!
After changing this parameter you need to update your reference image and alignment markers!
Note
The exposure offset for automatic exposure, lower values produce darker image.
Note
This parameter can also be set on the Reference Image configuration page!
"},{"location":"Parameters/#parameter-camaec","title":"Parameter CamAec","text":"Auto-Exposure-Control
- When true, the camera attempts to automatically control the exposure.
- When false, the CamAecValue setting is used instead.
Section: TakeImage
Default Value: true
See here for the ov2640 camera datasheet. See here for the ov5640 camera datasheet.
Warning
This is an Expert Parameter! Only change it if you understand what it does!
After changing this parameter you need to update your reference image and alignment markers!
Note
This parameter can also be set on the Reference Image configuration page!
"},{"location":"Parameters/#parameter-camaec2","title":"Parameter CamAec2","text":"Auto-Exposure-Control2
- When true, the sensor\u2019s \"night mode\" is enabled, extending the range of automatic gain control.
- When false, the sensor\u2019s \"night mode\" is disabled.
Section: TakeImage
Default Value: true
See here for the ov2640 camera datasheet. See here for the ov5640 camera datasheet.
Warning
This is an Expert Parameter! Only change it if you understand what it does!
After changing this parameter you need to update your reference image and alignment markers!
Note
This may resolve some over-exposure and under-exposure issues.
Note
This parameter can also be set on the Reference Image configuration page!
"},{"location":"Parameters/#parameter-camaecvalue","title":"Parameter CamAecValue","text":"Auto-Exposure-Value
Range (0 .. 1200)
Section: TakeImage
Default Value: 160
See here for the ov2640 camera datasheet. See here for the ov5640 camera datasheet.
Warning
This is an Expert Parameter! Only change it if you understand what it does!
After changing this parameter you need to update your reference image and alignment markers!
Note
Access the exposure value of the camera, higher values produce brighter images.
Note
This parameter can also be set on the Reference Image configuration page!
"},{"location":"Parameters/#parameter-camagc","title":"Parameter CamAgc","text":"Auto-Gain-Control
- When true, the camera attempts to automatically control the sensor gain, up to the value in the CamGainceiling property.
- When false, the CamAgcGain setting is used instead.
Section: TakeImage
Default Value: true
See here for the ov2640 camera datasheet. See here for the ov5640 camera datasheet.
Warning
This is an Expert Parameter! Only change it if you understand what it does!
After changing this parameter you need to update your reference image and alignment markers!
"},{"location":"Parameters/#parameter-camagcgain","title":"Parameter CamAgcGain","text":"Auto-Gain-Control-Value
Range (0 .. 30)
Section: TakeImage
Default Value: 15
See here for the ov2640 camera datasheet. See here for the ov5640 camera datasheet.
Warning
This is an Expert Parameter! Only change it if you understand what it does!
After changing this parameter you need to update your reference image and alignment markers!
Note
This is used when CamAgc is off.
Note
Access the gain level of the sensor, higher values produce brighter images.
"},{"location":"Parameters/#parameter-camautosharpness","title":"Parameter CamAutoSharpness","text":"Auto-Sharpness
- When true, the camera attempts to automatically adjusts the sharpness.
- When false, the CamSharpness setting is used instead.
Section: TakeImage
Default Value: false
See here for the ov2640 camera datasheet. See here for the ov5640 camera datasheet.
Warning
This is an Expert Parameter! Only change it if you understand what it does!
After changing this parameter you need to update your reference image and alignment markers!
Note
The OV2640 does not officially support auto sharpness, this is an experimental parameter!
Note
This parameter can also be set on the Reference Image configuration page!
"},{"location":"Parameters/#parameter-camawb","title":"Parameter CamAwb","text":"Auto-White-Balance
- When true, the camera attempts to automatically control white balance.
- When false, the CamWbMode setting is used instead.
Section: TakeImage
Default Value: true
See here for the ov2640 camera datasheet. See here for the ov5640 camera datasheet.
Warning
This is an Expert Parameter! Only change it if you understand what it does!
After changing this parameter you need to update your reference image and alignment markers!
"},{"location":"Parameters/#parameter-camawbgain","title":"Parameter CamAwbGain","text":"Auto-White-Balance-Gain
- Enable/Disable CamAwbGain control.
Section: TakeImage
Default Value: true
See here for the ov2640 camera datasheet. See here for the ov5640 camera datasheet.
Warning
This is an Expert Parameter! Only change it if you understand what it does!
After changing this parameter you need to update your reference image and alignment markers!
"},{"location":"Parameters/#parameter-cambpc","title":"Parameter CamBpc","text":"Black-Pixel-Correction
- Enable/Disable black point compensation, this can make black parts of the image darker.
Section: TakeImage
Default Value: true
See here for the ov2640 camera datasheet. See here for the ov5640 camera datasheet.
Warning
This is an Expert Parameter! Only change it if you understand what it does!
After changing this parameter you need to update your reference image and alignment markers!
"},{"location":"Parameters/#parameter-cambrightness","title":"Parameter CamBrightness","text":"Image-Brightness
Range (-2 .. 2)
Section: TakeImage
Default Value: 0
See here for the ov2640 camera datasheet. See here for the ov5640 camera datasheet.
Warning
After changing this parameter you need to update your reference image and alignment markers!
Note
This parameter can also be set on the Reference Image configuration page!
"},{"location":"Parameters/#parameter-camcolorbar","title":"Parameter CamColorbar","text":"Colorbar
currently not implemented.
Section: TakeImage
Default Value: false
See here for the ov2640 camera datasheet. See here for the ov5640 camera datasheet.
Warning
This is an Expert Parameter! Only change it if you understand what it does!
"},{"location":"Parameters/#parameter-camcontrast","title":"Parameter CamContrast","text":"Image-Contrast
Range (-2 .. 2)
Section: TakeImage
Default Value: 0
See here for the ov2640 camera datasheet. See here for the ov5640 camera datasheet.
Warning
After changing this parameter you need to update your reference image and alignment markers!
Note
This parameter can also be set on the Reference Image configuration page!
"},{"location":"Parameters/#parameter-camdcw","title":"Parameter CamDcw","text":"Image-Downsize
- When CamDcw is on, the image that you receive will be the size that you requested (VGA, QQVGA, etc).
- When CamDcw is off, the image that you receive will be one of UXGA, SVGA, or CIF.
Section: TakeImage
Default Value: true
See here for the ov2640 camera datasheet. See here for the ov5640 camera datasheet.
Warning
This is an Expert Parameter! Only change it if you understand what it does!
After changing this parameter you need to update your reference image and alignment markers!
If CamZoom is used, this must be activated.
Note
If CamDcw is off, and you pick a different image size, this implicitly turns CamDcw back on again.
"},{"location":"Parameters/#parameter-camdenoise","title":"Parameter CamDenoise","text":"Image-Denoise
- Denoise Image, is only supported by OV3660 and OV5640
range on OV3660 and OV5640 (0 .. 8)
Section: TakeImage
Default Value: 0
See here for the ov2640 camera datasheet. See here for the ov5640 camera datasheet.
Warning
This is an Expert Parameter! Only change it if you understand what it does!
"},{"location":"Parameters/#parameter-camgainceiling","title":"Parameter CamGainceiling","text":"Gain-Ceiling
Available options:
x2 x4 x8 x16 x32 x64 x128
Default Value for ov2640: x4 Default Value for ov5640: x8
See here for the ov2640 camera datasheet. See here for the ov5640 camera datasheet.
Warning
This is an Expert Parameter! Only change it if you understand what it does!
After changing this parameter you need to update your reference image and alignment markers!
Note
A higher gain means that the sensor has a greater response to light, but also makes sensor noise more visible.
This is used when CamAgc is on.
Note
The Gain is an analog multiplier applied to the raw sensor data. The Ceiling is the maximum gain value that the sensor will use.
"},{"location":"Parameters/#parameter-camhmirror","title":"Parameter CamHmirror","text":"Mirror-Image
- When true, the camera image is mirrored left-to-right.
Section: TakeImage
Default Value: false
See here for the ov2640 camera datasheet. See here for the ov5640 camera datasheet.
Warning
After changing this parameter you need to update your reference image and alignment markers!
Note
This parameter can also be set on the Reference Image configuration page!
"},{"location":"Parameters/#parameter-camlenc","title":"Parameter CamLenc","text":"Lens-Correction
- Enable/Disable lens correction.
Section: TakeImage
Default Value: true
See here for the ov2640 camera datasheet. See here for the ov5640 camera datasheet.
Warning
This is an Expert Parameter! Only change it if you understand what it does!
After changing this parameter you need to update your reference image and alignment markers!
Note
This can help compensate for light fall-off at the edge of the sensor area.
"},{"location":"Parameters/#parameter-camquality","title":"Parameter CamQuality","text":"Image-Quality
Range (8 .. 63)
Section: TakeImage
Default Value: 10
See here for the ov2640 camera datasheet. See here for the ov5640 camera datasheet.
Warning
This is an Expert Parameter! Only change it if you understand what it does!
After changing this parameter you need to update your reference image and alignment markers!
Value below 10 could result in system instabilities!
Note
Quality index for pictures: 8 (highest quality) ... 63 (lowest quality)
This is similar to the quality setting when exporting a jpeg image from photo editing software.
"},{"location":"Parameters/#parameter-camrawgma","title":"Parameter CamRawGma","text":"Raw-Gamma
- Enable/Disable raw gamma mode.
Section: TakeImage
Default Value: true
See here for the ov2640 camera datasheet. See here for the ov5640 camera datasheet.
Warning
This is an Expert Parameter! Only change it if you understand what it does!
After changing this parameter you need to update your reference image and alignment markers!
Note
The main purpose of the Gamma (GMA) function is to compensate for the non-linear characteristics of the sensor. GMA converts the pixel values according to the Gamma curve to compensate the sensor output under different light strengths. The non-linear gamma curve is approximately constructed with different linear functions. Raw gamma compensates the image in the RAW domain.
"},{"location":"Parameters/#parameter-camsaturation","title":"Parameter CamSaturation","text":"Image-Saturation
Range (-2 .. 2)
Section: TakeImage
Default Value: 0
See here for the ov2640 camera datasheet. See here for the ov5640 camera datasheet.
Warning
After changing this parameter you need to update your reference image and alignment markers!
Note
Positive values increase saturation (more vibrant colors), negative values lower it (more muted colors).
Note
This parameter can also be set on the Reference Image configuration page!
"},{"location":"Parameters/#parameter-camsharpness","title":"Parameter CamSharpness","text":"Image-Sharpness
Range (-2 .. 2)
Section: TakeImage
Default Value: 0
See here for the ov2640 camera datasheet. See here for the ov5640 camera datasheet.
Warning
This is an Expert Parameter! Only change it if you understand what it does!
After changing this parameter you need to update your reference image and alignment markers!
Note
The OV2640 does not officially support sharpness, this is an experimental parameter!
Note
Positive values increase sharpness (more defined edges), negative values lower it (softer edges).
This is used when CamAutoSharpness is off.
Note
This parameter can also be set on the Reference Image configuration page!
"},{"location":"Parameters/#parameter-camspecialeffect","title":"Parameter CamSpecialEffect","text":"Image-Special-Effect
Available options:
no_effect negative grayscale red green blue retro
Section: TakeImage
Default Value: no_effect
See here for the ov2640 camera datasheet. See here for the ov5640 camera datasheet.
Warning
This is an Expert Parameter! Only change it if you understand what it does!
After changing this parameter you need to update your reference image and alignment markers!
Note
This parameter can also be set on the Reference Image configuration page!
"},{"location":"Parameters/#parameter-camvflip","title":"Parameter CamVflip","text":"Flip-Image
- When true, the camera image is flipped top-to-bottom.
Section: TakeImage
Default Value: false
See here for the ov2640 camera datasheet. See here for the ov5640 camera datasheet.
Warning
After changing this parameter you need to update your reference image and alignment markers!
Note
On some OV5640 Cameras, the image becomes reddish when Vflip is used in conjunction with the zoom function!
Note
This parameter can also be set on the Reference Image configuration page!
"},{"location":"Parameters/#parameter-camwbmode","title":"Parameter CamWbMode","text":"White-Balance-Mode
Available options:
auto sunny cloudy office home
Section: TakeImage
Default Value: auto
See here for the ov2640 camera datasheet. See here for the ov5640 camera datasheet.
Warning
After changing this parameter you need to update your reference image and alignment markers!
Note
This is used when CamAwb is off.
Note
This parameter can also be set on the Reference Image configuration page!
"},{"location":"Parameters/#parameter-camwpc","title":"Parameter CamWpc","text":"White-Pixel-Correction
- Enable/Disable white point compensation, his can make white parts of the image whiter.
Section: TakeImage
Default Value: true
See here for the ov2640 camera datasheet. See here for the ov5640 camera datasheet.
Warning
After changing this parameter you need to update your reference image and alignment markers!
Note
This parameter can also be set on the Reference Image configuration page!
"},{"location":"Parameters/#parameter-camzoom","title":"Parameter CamZoom","text":"Digital-Zoom
- Enable/Disable digital zoom.
Section: TakeImage
Default Value: false
See here for the ov2640 camera datasheet. See here for the ov5640 camera datasheet.
Warning
This is an Expert Parameter! Only change it if you understand what it does!
After changing this parameter you need to update your reference image and alignment markers!
Note
It is always zoomed into the center of the image, if CamZoomOffsetX and CamZoomOffsetY are zero.
Note
This parameter can also be set on the Reference Image configuration page!
"},{"location":"Parameters/#parameter-camzoomoffsetx","title":"Parameter CamZoomOffsetX","text":"Digital-Zoom-OffsetX
range on OV2640 (-480 .. 480) range on OV3660 (-704 .. 704) range on OV5640 (-960 .. 960)
Section: TakeImage
Default Value: 0
See here for the ov2640 camera datasheet. See here for the ov5640 camera datasheet.
Warning
This is an Expert Parameter! Only change it if you understand what it does!
After changing this parameter you need to update your reference image and alignment markers!
Note
X displacement of the image from the center. Positive values \u200b\u200bshift the image to the right, negative values \u200b\u200bto the left. The maximum possible offset depends on the value of the CamZoomSize.
Note
This parameter can also be set on the Reference Image configuration page!
"},{"location":"Parameters/#parameter-camzoomoffsety","title":"Parameter CamZoomOffsetY","text":"Digital-Zoom-OffsetY
range on OV2640 (-360 .. 360) range on OV3660 (-528 .. 528) range on OV5640 (-720 .. 720)
Section: TakeImage
Default Value: 0
See here for the ov2640 camera datasheet. See here for the ov5640 camera datasheet.
Warning
This is an Expert Parameter! Only change it if you understand what it does!
After changing this parameter you need to update your reference image and alignment markers!
Note
Y displacement of the image from the center. Positive values \u200b\u200bmove the image up, negative values \u200b\u200bmove the image down. The maximum possible offset depends on the value of the CamZoomSize.
Note
This parameter can also be set on the Reference Image configuration page!
"},{"location":"Parameters/#parameter-camzoomsize","title":"Parameter CamZoomSize","text":"Digital-Zoom-Size
range on OV2640 (0 .. 29) range on OV3660 (0 .. 43) range on OV5640 (0 .. 59)
Section: TakeImage
Default Value: 0
See here for the ov2640 camera datasheet. See here for the ov5640 camera datasheet.
Warning
This is an Expert Parameter! Only change it if you understand what it does!
After changing this parameter you need to update your reference image and alignment markers!
Note
Zoom factor/level of the digital zoom, the larger the value, the more it zooms in.
Note
This parameter can also be set on the Reference Image configuration page!
"},{"location":"Parameters/#parameter-demo","title":"Parameter Demo","text":"Enable to use demo images instead of the real camera images. Make sure to have a /demo folder on your SD-Card and make sure it contains the expected files! Check here for details.
Section: TakeImage
Default Value: false
Warning
This is an Expert Parameter! Only change it if you understand what it does!
"},{"location":"Parameters/#parameter-ledintensity","title":"Parameter LEDIntensity","text":"Set the Flash LED Intensity: (0 .. 100)
Section: TakeImage
Default Value: 50
Note
After changing this parameter you need to update your reference image and alignment markers!
Note
This parameter can also be set on the Reference Image configuration page!
"},{"location":"Parameters/#parameter-rawimageslocation","title":"Parameter RawImagesLocation","text":"Location on the SD-Card to store the raw images.
Section: TakeImage
Default Value: /log/source
Warning
A SD-Card has limited write cycles. Since the device does not do Wear Leveling, this can wear out your SD-Card!
"},{"location":"Parameters/#parameter-rawimagesretention","title":"Parameter RawImagesRetention","text":"Number of days to keep the raw images (0 = forever)
Unit: Days
Section: TakeImage
Default Value: 15
"},{"location":"Parameters/#parameter-waitbeforetakingpicture","title":"Parameter WaitBeforeTakingPicture","text":"Waiting time between switching the flash light (onboard LED) on and taking the picture.
Unit: seconds
Section: TakeImage
Default Value: 5
Warning
This is an Expert Parameter! Only change it if you understand what it does!
"},{"location":"Parameters/#section-alignment","title":"Section Alignment","text":""},{"location":"Parameters/#parameter-alignmentalgo","title":"Parameter AlignmentAlgo","text":"Section: Alignment
Default Value: Default
Warning
This is an Expert Parameter! Only change it if you understand what it does!
Algorithm used for the alignment step.
Available options:
Default: Use only red color channel HighAccuracy: Use all 3 color channels (3x slower) Fast: First time use HighAccuracy, then only check if the image is shifted Off: Disable alignment algorithm
"},{"location":"Parameters/#parameter-initialrotate","title":"Parameter InitialRotate","text":"Section: Alignment
Default Value: 0
Unit: Degrees
Note
This parameter can also be set on the Reference Image configuration page!
Note
After changing this parameter you need to update your reference image and alignment markers!
Initial rotation of image before alignment in degree (-360 .. +360)
"},{"location":"Parameters/#parameter-searchfieldx","title":"Parameter SearchFieldX","text":"Section: Alignment
Default Value: 20
Unit: Pixels
Warning
This is an Expert Parameter! Only change it if you understand what it does!
X-size (width) in which the reference is searched.
Note
Since the alignment is one of the steps using a lot of computation time, the search field should be as small as possible. The calculation time goes quadratic with the search field size.
"},{"location":"Parameters/#parameter-searchfieldy","title":"Parameter SearchFieldY","text":"Section: Alignment
Default Value: 20
Unit: Pixels
Warning
This is an Expert Parameter! Only change it if you understand what it does!
Y-size (height) in which the reference is searched.
Note
Since the alignment is one of the steps using a lot of computation time, the search field should be as small as possible. The calculation time goes quadratic with the search field size.
"},{"location":"Parameters/#section-digits","title":"Section Digits","text":""},{"location":"Parameters/#parameter-cnngoodthreshold","title":"Parameter CNNGoodThreshold","text":"Section: Digits
Default Value: 0.5
Warning
This is an Expert Parameter! Only change it if you understand what it does!
Threshold above which the classification should be to accept the value (only meaningful for digits).
Warning
This is only supported for the dig-class100 models!
"},{"location":"Parameters/#parameter-model","title":"Parameter Model","text":"Section: Digits
Default Value: /config/dig-cont_*.tflite (See /config/config.ini)
Path to CNN model file for image recognition. See here for details.
"},{"location":"Parameters/#parameter-roiimageslocation","title":"Parameter ROIImagesLocation","text":"Section: Digits
Default Value: /log/digit
Location to store separated digit images on the SD-Card.
Warning
A SD-Card has limited write cycles. Since the device does not do Wear Leveling, this can wear out your SD-Card!
"},{"location":"Parameters/#parameter-roiimagesretention","title":"Parameter ROIImagesRetention","text":"Section: Digits
Default Value: 3
Unit: Days
Days to keep the separated digit images (0 = forever).
"},{"location":"Parameters/#section-analog","title":"Section Analog","text":""},{"location":"Parameters/#parameter-cnngoodthreshold_1","title":"Parameter CNNGoodThreshold","text":"Section: Analog
Default Value: 0.5
Warning
This is an Expert Parameter! Only change it if you understand what it does!
Threshold above which the classification should be to accept the value (only meaningful for digits).
Warning
This is only supported for the ana-class100 models!
"},{"location":"Parameters/#parameter-extendedresolution","title":"Parameter ExtendedResolution","text":"Warning
This parameter is unused! Use NUMBER.ExtendedResolution instead!
"},{"location":"Parameters/#parameter-model_1","title":"Parameter Model","text":"Section: Analog
Default Value: /config/ana-cont_*.tflite (See /config/config.ini)
Path to CNN model file for image recognition. See here for details.
"},{"location":"Parameters/#parameter-roiimageslocation_1","title":"Parameter ROIImagesLocation","text":"Section: Analog
Default Value: /log/analog
Location to store separated analog images on the SD-Card.
Warning
A SD-Card has limited write cycles. Since the device does not do Wear Leveling, this can wear out your SD-Card!
"},{"location":"Parameters/#parameter-roiimagesretention_1","title":"Parameter ROIImagesRetention","text":"Section: Analog
Default Value: 3
Unit: Days
Days to keep the separated analog images (0 = forever).
"},{"location":"Parameters/#section-postprocessing","title":"Section PostProcessing","text":""},{"location":"Parameters/#parameter-allownegativerates","title":"Parameter AllowNegativeRates","text":"Warning
This parameter is unused! Use NUMBER.AllowNegativeRates instead!
"},{"location":"Parameters/#parameter-errormessage","title":"Parameter ErrorMessage","text":"Section: PostProcessing
Default Value: true
Warning
This is an Expert Parameter! Only change it if you understand what it does!
Do not show error message in return value. In an error case, the last valid number will be used for the various transmission protocols (MQTT, InfluxDB, REST, ...).
"},{"location":"Parameters/#parameter-allownegativerates_1","title":"Parameter AllowNegativeRates","text":"Section: PostProcessing
Default Value: false
Allow a meter to count backwards (decreasing values).
Note
This is unusual (it means there is a negative rate) and not wanted in most cases!
Note
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.
"},{"location":"Parameters/#parameter-analogtodigittransitionstart","title":"Parameter AnalogToDigitTransitionStart","text":"Section: PostProcessing
Default Value: 9.2
This can be used if you have wrong values, but the recognition of the individual ROIs are correct. Look for the start of changing of the first digit and note the analog pointer value behind. Set it here. Only used on combination of digits and analog pointers. See here for details.
Range: 6.0 .. 9.9.
Note
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.
"},{"location":"Parameters/#parameter-changeratethreshold","title":"Parameter ChangeRateThreshold","text":"Section: PostProcessing
Default Value: 2
Range: 0 .. 9.
Threshold parameter for change rate detection. 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.
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
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.
"},{"location":"Parameters/#example","title":"Example","text":" - Smallest ROI provides value for
0.000'x (Eg. a water meter with 4 pointers behind the decimal point) - ChangeRateThreshold = 2
"},{"location":"Parameters/#with-extended-resolution-disabled","title":"With Extended Resolution disabled","text":"PreValue: 123.456'7 -> Threshold = +/-0.000'2. All changes between 123.456'5 and 123.456'9 get ignored
"},{"location":"Parameters/#with-extended-resolution-enabled","title":"With Extended Resolution enabled","text":"PreValue: 123.456'78 -> Threshold = +/-0.000'02. All changes between 123.456'76 and 123.456'80 get ignored.
"},{"location":"Parameters/#parameter-checkdigitincreaseconsistency","title":"Parameter CheckDigitIncreaseConsistency","text":"Section: PostProcessing
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
This parameter must be prefixed with <NUMBER> followed by a dot (eg. main.CheckDigitIncreaseConsistency). <NUMBER> is the name of the number sequence defined in the ROI's.
"},{"location":"Parameters/#parameter-decimalshift","title":"Parameter DecimalShift","text":"Section: PostProcessing
Default Value: 0
Shift the decimal separator (positiv or negativ). Eg. to move from m\u00b3 to liter (1 m\u00b3 equals 1000 liters), you need to set it to +3.
Note
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.
"},{"location":"Parameters/#parameter-extendedresolution_1","title":"Parameter ExtendedResolution","text":"Section: PostProcessing
Default Value: false
Use the decimal place of the last analog counter for increased accuracy.
Note
This parameter is only supported on the *-class* and *-const models! See Choosing-the-Model for details.
Note
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.
"},{"location":"Parameters/#parameter-ignoreleadingnan","title":"Parameter IgnoreLeadingNaN","text":"Section: PostProcessing
Default Value: true
Leading N's will be deleted before further processing. This is only relevant for models which use N! See here for details.
Note
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.
"},{"location":"Parameters/#parameter-maxratetype","title":"Parameter MaxRateType","text":"Section: PostProcessing
Default Value: AbsoluteChange
Defines if the Change Rate is calculated as the difference between the last two readings (AbsoluteChange = difference) or as the difference normalized to the interval (RateChange = difference per minute).
Note
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.
"},{"location":"Parameters/#parameter-maxratevalue","title":"Parameter MaxRateValue","text":"Section: PostProcessing
Default Value: 0,05
Maximum allowed change between two readings, if exceeded the last reading will be rejected. Depending on the settings of <NUMBER>.MaxRateType the MaxRateValue is either treated as the difference between the two measurements (AbsoluteChange = difference) not taking the set time interval into account or as the difference normalized to the interval (RateChange = difference per minute).
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 as610,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
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.
"},{"location":"Parameters/#parameter-prevalueagestartup","title":"Parameter PreValueAgeStartup","text":"Section: PostProcessing
Default Value: 720
Warning
This is an Expert Parameter! Only change it if you understand what it does!
Time in minutes, how long a previous read value is valid after reboot.
"},{"location":"Parameters/#parameter-prevalueuse","title":"Parameter PreValueUse","text":"Section: PostProcessing
Default Value: true
Use the previous value (value from previous round) for consistency checks. This also works through a reboot of the device!
"},{"location":"Parameters/#section-mqtt","title":"Section MQTT","text":""},{"location":"Parameters/#parameter-cacert","title":"Parameter CACert","text":"Section: MQTT
Default Value: \"\"
Example: /config/certs/RootCA.crt.
Warning
This is an Expert Parameter! Only change it if you understand what it does!
Path to the CA certificate file.
This is part of the configuration to enable TLS 1.2 for MQTT.
The CA Certificate is used by the client to validate the broker is who it claims to be. It allows the client to authenticate the server, which is the first part of the MTLS handshake.
Usually there is a common RootCA certificate for the MQTT broker. More information is available here.
For more information on how to create your own certificate, see: mosquitto.org or emqx.com.
Note
This also means that you might have to change the protocol and port in uri to mqtts://example.com:8883!
Only Certificates up to 4096 Bit are supported!
"},{"location":"Parameters/#parameter-clientcert","title":"Parameter ClientCert","text":"Section: MQTT
Default Value: \"\"
Example: /config/certs/client.crt.
Warning
This is an Expert Parameter! Only change it if you understand what it does!
Path to the Client Certificate file.
This is part of the configuration to enable TLS 1.2 for MQTT.
The Client Certificate is used by the client to prove its identity to the server, in conjunction with the Client Key. It is the second part of the MTLS handshake.
Usually there is a one pair of Client Certificate/Key for each client that connects to the MQTT broker. More information is available here.
For more information on how to create your own certificate, see: mosquitto.org or emqx.com.
Note
If set, ClientKey must be set too. This also means that you might have to change the protocol and port in uri to mqtts://example.com:8883!
"},{"location":"Parameters/#parameter-clientid","title":"Parameter ClientID","text":"Section: MQTT
Default Value: watermeter
Client ID used to connect to the MQTT broker. If disabled, the hostname will be used.
"},{"location":"Parameters/#parameter-clientkey","title":"Parameter ClientKey","text":"Section: MQTT
Default Value: \"\"
Example: /config/certs/client.key.
Warning
This is an Expert Parameter! Only change it if you understand what it does!
Path to the Client Key file.
This is part of the configuration to enable TLS 1.2 for MQTT.
The Client Key is used by the client to prove its identity to the server, in conjunction with the Client Certificate. It is the second part of the MTLS handshake.
Usually there is a one pair of Client Certificate/Key for each client that connects to the MQTT broker
For more information on how to create your own certificate, see: mosquitto.org or emqx.com.
Note
If set, ClientCert must be set too. This also means that you might have to change the protocol and port in uri to mqtts://example.com:8883!
"},{"location":"Parameters/#parameter-domoticztopicin","title":"Parameter DomoticzTopicIn","text":"Section: MQTT
Default Value: domoticz/in
Domoticz \"in\" topic as configured on the \"MQTT Client Gateway\" setup page on the Domoticz system. Used to publish counter/s value/s.
Parameter <NUMBER>.DomoticzIDX is required (see below).
"},{"location":"Parameters/#parameter-homeassistantdiscovery","title":"Parameter HomeassistantDiscovery","text":"Section: MQTT
Default Value: true
Enable or disable the Homeassistant Discovery. See here for details about the discovery.
"},{"location":"Parameters/#parameter-maintopic","title":"Parameter MainTopic","text":"Section: MQTT
Default Value: watermeter
MQTT main topic, under which the counters are published.
The single value will be published with the following key: MAINTOPIC/NUMBER/RESULT_TOPIC
With:
NUMBER: The name of the value (a meter might have more than one value). The names get defined in the analog and digit ROI configuration (defaults to main). RESULT_TOPIC: Automatically filled with the right name, eg. value, rate, timestamp, error, ....
The general connection status can be found in MAINTOPIC/CONNECTION. See MQTT Result Topics for a full list of topics.
Note
The main topic is allowed to contain / which can be used to split it into multiple levels, eg. /basement/meters/watermeter/1/ if you have multiple water meters in your basement.
The nodeId for the Home Assistant MQTT Service Discovery must follow the schema <discovery_prefix>/<component>/[<node_id>/]<object_id>/config. The node_id is not configurable but derived from the MainTopic by stripping any but the last topic level. A MainTopic with the value home/basement/watermeter is transformed into the node_id watermeter, resulting in the discovery topic homeassistant/sensor/watermeter/value/config for the current value.
"},{"location":"Parameters/#parameter-metertype","title":"Parameter MeterType","text":"Section: MQTT
Default Value: other
Select the Meter Type so the sensors have the right units in Homeassistant.
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\u00b3, you need to also set it to m\u00b3. 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/min 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/min 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 \u00b0F/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!
"},{"location":"Parameters/#parameter-domoticzidx","title":"Parameter DomoticzIDX","text":"Section: MQTT
Default Value: 0
The Idx number for the counter device. Can be obtained from the devices setup page on the Domoticz system.
Note
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.
"},{"location":"Parameters/#parameter-retainmessages","title":"Parameter RetainMessages","text":"Section: MQTT
Default Value: true
Enable or disable the Retain Flag for all MQTT entries.
Warning
Disabling (set to false) this does not clear the last retained value on the MQTT broker! This must be done manually, see How to Delete Retained Messages in MQTT? and this discussion!
"},{"location":"Parameters/#parameter-uri","title":"Parameter Uri","text":"Section: MQTT
Default Value: mqtt://example.com:1883
URI to the MQTT broker including the port. E.g. mqtt://192.168.1.1:1883.
"},{"location":"Parameters/#parameter-validateservercert","title":"Parameter ValidateServerCert","text":"Section: MQTT
Default Value: true
Warning
This is an Expert Parameter! Only change it if you understand what it does!
Enable or disable the validation of the server certificate CN field.
If enabled (true), the certificate sent by the server is validated using the configured Root CA Certificate file. The server name in uri is compared with the CN field of the server certificate. A connection is only established if they agree. It ensures the origin of the server.
If disabled (false), the ESP32 skipped any validation of server certificate CN field. This reduces the security of TLS and makes the MQTT client susceptible to MITM attacks.
Note
This also means that you might have to change the protocol and port in to mqtts://example.com:8883!
If you use public brokers, is recommended to set this parameter to \"enabled (true)\".
"},{"location":"Parameters/#parameter-password","title":"Parameter password","text":"Section: MQTT
Default Value: PASSWORD
Password for MQTT authentication.
"},{"location":"Parameters/#parameter-user","title":"Parameter user","text":"Section: MQTT
Default Value: USERNAME
Username for MQTT authentication.
"},{"location":"Parameters/#section-influxdb","title":"Section InfluxDB","text":""},{"location":"Parameters/#parameter-database","title":"Parameter Database","text":"Section: InfluxDB
Default Value: ''
Name of the InfluxDB v1 Database into which to publish the values.
Note
See section InfluxDBv2 for InfluxDB v2 support!
"},{"location":"Parameters/#parameter-field","title":"Parameter Field","text":"Section: InfluxDB
Default Value: undefined
Dedicated definition of the field for InfluxDB use for saving in the Influx database (e.g.: \"watermeter/value\").
Note
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.
"},{"location":"Parameters/#parameter-measurement","title":"Parameter Measurement","text":"Section: InfluxDB
Default Value: undefined
Name of the InfluxDB v1 Measurement to use to publish the value.
Note
See section InfluxDBv2 for InfluxDB v2 support!
"},{"location":"Parameters/#parameter-uri_1","title":"Parameter Uri","text":"Section: InfluxDB
Default Value: undefined
URI of the HTTP interface to InfluxDB v1, without trailing slash, e.g. http://192.168.1.1:8086.
Note
See section InfluxDBv2 for InfluxDB v2 support!
"},{"location":"Parameters/#parameter-password_1","title":"Parameter password","text":"Section: InfluxDB
Default Value: undefined
Password for the InfluxDB v1 authentication.
Note
See section InfluxDBv2 for InfluxDB v2 support!
"},{"location":"Parameters/#parameter-user_1","title":"Parameter user","text":"Section: InfluxDB
Default Value: undefined
Username for the InfluxDB v1 authentication.
Note
See section InfluxDBv2 for InfluxDB v2 support!
"},{"location":"Parameters/#section-influxdbv2","title":"Section InfluxDBv2","text":""},{"location":"Parameters/#parameter-bucket","title":"Parameter Bucket","text":"Section: InfluxDBv2
Default Value: ''
Name of the InfluxDB v2 Bucket into which to publish the values.
"},{"location":"Parameters/#parameter-database_1","title":"Parameter Database","text":"Warning
This parameter is unused! Use Basket instead!
"},{"location":"Parameters/#parameter-field_1","title":"Parameter Field","text":"Section: InfluxDBv2
Default Value: undefined
Field for InfluxDB v2 to use for saving.
Note
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.
"},{"location":"Parameters/#parameter-measurement_1","title":"Parameter Measurement","text":"Section: InfluxDBv2
Default Value: undefined
Name of the InfluxDB v2 Measurement to use to publish the value.
"},{"location":"Parameters/#parameter-org","title":"Parameter Org","text":"Section: InfluxDBv2
Default Value: undefined
Organisation (Org) for InfluxDB v2 authentication
"},{"location":"Parameters/#parameter-token","title":"Parameter Token","text":"Section: InfluxDBv2
Default Value: undefined
Token for InfluxDB v2 authentication
"},{"location":"Parameters/#parameter-uri_2","title":"Parameter Uri","text":"Section: InfluxDBv2
Default Value: undefined
URI of the HTTP interface to InfluxDB v2, without trailing slash, e.g. http://192.168.1.1:8086.
"},{"location":"Parameters/#section-gpio","title":"Section GPIO","text":""},{"location":"Parameters/#parameter-io0","title":"Parameter IO0","text":"Section: GPIO
Default Value: input disabled 10 false false
Warning
This is an Expert Parameter! Only change it if you understand what it does!
This parameter can be used to configure the GPIO IO0 pin.
Warning
This pin is only usable with restrictions! It must be disabled when the camera is used. Additionally, it is used to activate Bootloader mode and must therefore be HIGH after a reset!
Parameters:
GPIO 0 state: One of input, input pullup, input pulldown or output. GPIO 0 use interrupt: Enable interrupt trigger GPIO 0 PWM duty resolution: LEDC PWM duty resolution in bit GPIO 0 enable MQTT: Enable MQTT publishing/subscribing GPIO 0 enable HTTP: Enable HTTP write/read GPIO 0 name: MQTT topic name (empty = GPIO0). Allowed characters: a-z, A-Z, 0-9, _, -.
"},{"location":"Parameters/#parameter-io1","title":"Parameter IO1","text":"Section: GPIO
Default Value: input disabled 10 false false
Warning
This is an Expert Parameter! Only change it if you understand what it does!
This parameter can be used to configure the GPIO IO1 pin.
Warning
This pin is by default used for the serial communication as TX pin (USB logging)!
Parameters:
GPIO 1 state: One of input, input pullup, input pulldown or output. GPIO 1 use interrupt: Enable interrupt trigger GPIO 1 PWM duty resolution: LEDC PWM duty resolution in bit GPIO 1 enable MQTT: Enable MQTT publishing/subscribing GPIO 1 enable HTTP: Enable HTTP write/read GPIO 1 name: MQTT topic name (empty = GPIO1). Allowed characters: a-z, A-Z, 0-9, _, -.
"},{"location":"Parameters/#parameter-io12","title":"Parameter IO12","text":"Section: GPIO
Default Value: input-pullup disabled 10 false false
Warning
This is an Expert Parameter! Only change it if you understand what it does!
This parameter can be used to configure the GPIO IO12 pin.
Note
This pin is usable without known restrictions!
Parameters:
GPIO 12 state: One of external-flash-ws281x, input, input pullup, input pulldown or output. GPIO 12 use interrupt: Enable interrupt trigger GPIO 12 PWM duty resolution: LEDC PWM duty resolution in bit GPIO 12 enable MQTT: Enable MQTT publishing/subscribing GPIO 12 enable HTTP: Enable HTTP write/read GPIO 12 name: MQTT topic name (empty = GPIO12). Allowed characters: a-z, A-Z, 0-9, _, -.
"},{"location":"Parameters/#parameter-io13","title":"Parameter IO13","text":"Section: GPIO
Default Value: input-pullup disabled 10 false false
Warning
This is an Expert Parameter! Only change it if you understand what it does!
This parameter can be used to configure the GPIO IO13 pin.
Note
This pin is usable without known restrictions!
Parameters:
GPIO 13 state: One of input, input pullup, input pulldown or output. GPIO 13 use interrupt: Enable interrupt trigger GPIO 13 PWM duty resolution: LEDC PWM duty resolution in bit GPIO 13 enable MQTT: Enable MQTT publishing/subscribing GPIO 13 enable HTTP: Enable HTTP write/read GPIO 13 name: MQTT topic name (empty = GPIO13). Allowed characters: a-z, A-Z, 0-9, _, -.
"},{"location":"Parameters/#parameter-io3","title":"Parameter IO3","text":"Section: GPIO
Default Value: input disabled 10 false false
Warning
This is an Expert Parameter! Only change it if you understand what it does!
This parameter can be used to configure the GPIO IO3 pin.
Warning
This pin is by default used for the serial communication as RX pin (USB logging)!
Parameters:
GPIO 3 state: One of input, input pullup, input pulldown or output. GPIO 3 use interrupt: Enable interrupt trigger GPIO 3 PWM duty resolution: LEDC PWM duty resolution in bit GPIO 3 enable MQTT: Enable MQTT publishing/subscribing GPIO 3 enable HTTP: Enable HTTP write/read GPIO 3 name: MQTT topic name (empty = GPIO3). Allowed characters: a-z, A-Z, 0-9, _, -.
"},{"location":"Parameters/#parameter-io4","title":"Parameter IO4","text":"Section: GPIO
Default Value: built-in-led disabled 10 false false
Warning
This is an Expert Parameter! Only change it if you understand what it does!
This parameter can be used to configure the GPIO IO4 pin.
Warning
This pin is only usable with restrictions! By default, it is used for build-in flash light (onboard LED).
Parameters:
GPIO 4 state: One of built-in-led, input, input pullup, input pulldown or output. GPIO 4 use interrupt: Enable interrupt trigger GPIO 4 PWM duty resolution: LEDC PWM duty resolution in bit GPIO 4 enable MQTT: Enable MQTT publishing/subscribing GPIO 4 enable HTTP: Enable HTTP write/read GPIO 4 name: MQTT topic name (empty = GPIO4). Allowed characters: a-z, A-Z, 0-9, _, -.
"},{"location":"Parameters/#parameter-ledcolor","title":"Parameter LEDColor","text":"Section: GPIO
Default Value: 150 150 150
Color of the attached LEDs to GPIO12 in Red, Green Blue from 0 (full off) .. 255 (full on) (See IO12 parameter).
"},{"location":"Parameters/#parameter-lednumbers","title":"Parameter LEDNumbers","text":"Section: GPIO
Default Value: 2
Number of LEDs on the external LED-stripe attached to GPIO12 (See IO12 parameter).
"},{"location":"Parameters/#parameter-ledtype","title":"Parameter LEDType","text":"Section: GPIO
Default Value: WS2812 Type of the WS2812x which is connected to GPIO12 (See IO12 parameter).
"},{"location":"Parameters/#parameter-maintopicmqtt","title":"Parameter MainTopicMQTT","text":"Section: GPIO
Default Value: wasserzaehler/GPIO
Note
This parameter is not accessible through the Web Interface Configuration Page!
The GPIO Interface is prepared to report it's status and status changes as a MQTT topic. With this parameter you configure the MQTT main topic, under which the status is published. As this parameter is still experimental it can only be set manually in the config.ini itself and has not been tested in detail so far.
"},{"location":"Parameters/#section-autotimer","title":"Section AutoTimer","text":""},{"location":"Parameters/#parameter-autostart","title":"Parameter AutoStart","text":"Section: AutoTimer
Default Value: true
Warning
This parameter is no longer available. The flow is now always enabled. If you want it to be disabled, set an interval which is high enough (eg. 1440 = 24h).
"},{"location":"Parameters/#parameter-interval","title":"Parameter Interval","text":"Section: AutoTimer
Default Value: 5
Unit: Minutes
Interval in which the Flow (Digitization Round) is run. It will run immediately on startup and then the next time after the given interval. If a round takes longer than this interval, the next round gets postponed until the current round completes.
If the flow gets started by a MQTT message or the REST API call, the interval automatically gets reset.
Note
If you want the flow to be disabled, set an interval which is high enough (eg. 1440 = 24h).
"},{"location":"Parameters/#section-datalogging","title":"Section DataLogging","text":""},{"location":"Parameters/#parameter-datafilesretention","title":"Parameter DataFilesRetention","text":"Section: DataLogging
Default Value: 3
Unit: Days
Number of days to keep the data files (0 = forever).
"},{"location":"Parameters/#parameter-datalogactive","title":"Parameter DataLogActive","text":"Section: DataLogging
Default Value: true Activate data logging to the SD-Card.
The files will be stored in /log/data/data_YYYY-MM-DD.csv. See Data Logging for details.
Warning
A SD-Card has limited write cycles. Since the device does not do Wear Leveling, this can wear out your SD-Card!
"},{"location":"Parameters/#section-debug","title":"Section Debug","text":""},{"location":"Parameters/#parameter-loglevel","title":"Parameter LogLevel","text":"Section: Debug
Default Value: 1 (ERROR) Define the log level for the logging to the SD-Card.
Available options:
1: ERROR 2: WARNING 3: INFO 4: DEBUG
As higher the level, as more log messages get written to the SD-Card.
Warning
DEBUG or INFO might damage the SD-Card if enabled long term due to excessive writes to the SD-Card! A SD-Card has limited write cycles. Since the device does not do Wear Leveling, this can wear out your SD-Card!
"},{"location":"Parameters/#parameter-logfilesretention","title":"Parameter LogfilesRetention","text":"Section: Debug
Default Value: 3
Unit: Days
Number of days to keep the log files (0 = forever).
"},{"location":"Parameters/#section-system","title":"Section System","text":""},{"location":"Parameters/#parameter-cpufrequency","title":"Parameter CPUFrequency","text":"Section: System
Default Value: 160
Set the CPU Frequency.
Warning
Setting it to 240 will lead to a faster device, but it will also require a stronger power supply! Additionally, depending on the quality of your ESP32-CAM, it might run unstable!
Possible values:
"},{"location":"Parameters/#parameter-hostname","title":"Parameter Hostname","text":"Section: System
Default Value: undefined
Warning
This is an Expert Parameter! Only change it if you understand what it does!
Hostname for the device. It gets automatically transferred to /wlan.ini on the SD-Card at the next startup.
"},{"location":"Parameters/#parameter-rssithreshold","title":"Parameter RSSIThreshold","text":"Section: System
Default Value: 0
Possible values: -100 .. 0 (0 = disabled).
Warning
This is an Expert Parameter! Only change it if you understand what it does!
This parameter activates a client triggered AP switching functionality (simplified roaming). If actual RSSI value is lower (more negative) than RSSIThreshold, all WIFI channels will be scanned for configured access point SSID. If an access point is in range which has better RSSI value (less negative) than actual RSSI value + 5 dBm, the device is trying to connect to this access point with the better RSSI value.
Note
The RSSI check only gets initiated at the end of each round to avoid any disturbance of processing.
Note
It gets automatically transferred to /wlan.ini on the SD-Card at next startup.
"},{"location":"Parameters/#parameter-setupmode","title":"Parameter SetupMode","text":"Section: System
Default Value: true
Note
This parameter is not accessible through the Web Interface Configuration Page!
Set this parameter to true to stay in the Setup Mode after the next start of the device.
"},{"location":"Parameters/#parameter-timeserver","title":"Parameter TimeServer","text":"Section: System
Default Value: pool.ntp.org
Warning
This is an Expert Parameter! Only change it if you understand what it does!
Time server to synchronize system time. If it is disabled or undefined, pool.ntp.org will be used. You can also set it to the IP of your router. Many routers like Fritzboxes can act as a local NTP server. To disable NTP, you need to activate it but set the TimeServer config to be empty (\"\"). In such case the time always starts at 01.01.1970 after each power cycle!
"},{"location":"Parameters/#parameter-timezone","title":"Parameter TimeZone","text":"Section: System
Default Value: CET-1CEST,M3.5.0,M10.5.0/3
Time zone in POSIX syntax (Europe/Berlin = CET-1CEST,M3.5.0,M10.5.0/3 - incl. daylight saving) Check the table on http://<DEVICE IP>/timezones.html to find the settings for your region.
"},{"location":"Parameters/#section-webhook","title":"Section Webhook","text":""},{"location":"Parameters/#parameter-apikey","title":"Parameter ApiKey","text":"Section: Webhook
Default Value: undefined
ApiKey sent as Header
"},{"location":"Parameters/#parameter-uploadimg","title":"Parameter UploadImg","text":"Section: Webhook
Default Value: 0 (NEVER)
Available options:
0: NEVER 1: ALWAYS 2: ON_ERROR
"},{"location":"Parameters/#parameter-uri_3","title":"Parameter Uri","text":"Section: Webhook
Default Value: undefined
URI of the HTTP Endpoint receiving requests, e.g. http://192.168.1.1/watermeter/webhook.
"},{"location":"Password-Protection/","title":"Password Protection","text":"The Web Interface and the REST API can be protected by a password.
To do so, you have to set the username and password in the wlan.ini file on the SD-Card. Uncomment (remove the leading ;) and update the two lines with http_username and http_password:
http_username = \"myusername\"\nhttp_password = \"mypassword\"\n
Warning
This is be a WEAK and INSECURE way to protect the Web Interface and the REST API. There was no audit nor a security review to check the correct implementation of the protection! The password gets transmitted unencrypted (plain text), this means it is very easy to extract it for somebody who has access to your WIFI!
USE AT YOUR OWN RISK!
Notes
The file wlan.ini file on the SD-Card can not be accessed through the Web interface.
"},{"location":"REST-API/","title":"REST API","text":"Various information is directly accessible over specific REST calls.
To use it, just append them to the IP, separated with a /, e.g. http://192.168.1.1/json
Note
For more detailed information to the REST handler, have a look to the code in the repository: registered handlers
"},{"location":"REST-API/#control","title":"Control","text":""},{"location":"REST-API/#flow_start","title":"flow_start","text":"Trigger the next flow + Payload: - No payload needed
This will automatically reset the flow interval.
"},{"location":"REST-API/#setprevalue","title":"setPreValue","text":"Set the last valid value (previous value) to given value or the actual RAW value. + Payload: - Set to given value (value >= 0), e.g. /setPreValue?numbers=main&value=1234.5678 * numbers= Provide name of number sequence, e.g. main * value= provide the value to be set
- Set to actual RAW value (value < 0, a valid RAW value is mandatory), e.g. `/setPreValue?numbers=main&value=-1`\n * `numbers=` Provide name of number sequence, e.g. main\n * `value=` provide yna negative number\n
"},{"location":"REST-API/#gpio","title":"GPIO","text":" -
Control a GPIO output
- The
GPIO entrypoint also support parameters: /GPIO?GPIO={PinNumber}&Status=high /GPIO?GPIO={PinNumber}&Status=low - Example:
/GPIO?GPIO=12&Status=high
-
Read a GPIO input
- The
GPIO entrypoint also support parameters: /GPIO?GPIO={PinNumber} - Example:
/GPIO?GPIO=12
"},{"location":"REST-API/#reboot","title":"reboot","text":"Trigger a reboot of the device
"},{"location":"REST-API/#mqtt_publish_discovery","title":"mqtt_publish_discovery","text":"Trigger re-sending of the Home Assistant discovery topics. The topics will get send at the end of the next round.
"},{"location":"REST-API/#results","title":"Results","text":""},{"location":"REST-API/#json","title":"json","text":"Show result in JSON syntax - Example: { \"main\": { \"value\": \"521.17108\", \"raw\": \"521.17108\", \"pre\": \"521.17108\", \"error\": \"no error\", \"rate\": \"0.023780\", \"timestamp\": \"2023-01-13T16:00:42+0100\" } }
"},{"location":"REST-API/#value","title":"value","text":"Show single result values - The value entrypoint also support parameters: - http://<IP>/value?all=true&type=value - http://<IP>/value?all=true&type=raw - http://<IP>/value?all=true&type=error - http://<IP>/value?all=true&type=prevalue
"},{"location":"REST-API/#img_tmprawjpg","title":"img_tmp/raw.jpg","text":"Capture and show a new raw image
"},{"location":"REST-API/#img_tmpalgjpg","title":"img_tmp/alg.jpg","text":"Show last aligned image
"},{"location":"REST-API/#img_tmpalg_roijpg","title":"img_tmp/alg_roi.jpg","text":"Show last aligned image including ROI overlay
"},{"location":"REST-API/#status","title":"Status","text":""},{"location":"REST-API/#statusflow","title":"statusflow","text":"Show the actual step of the flow incl. timestamp - Example: Take Image (15:56:34)
"},{"location":"REST-API/#rssi","title":"rssi","text":"Show the WIFI signal strength (Unit: dBm) - Example: -51
"},{"location":"REST-API/#cpu_temperature","title":"cpu_temperature","text":"Show the CPU temperature (Unit: \u00b0C) - Example: 38
"},{"location":"REST-API/#sysinfo","title":"sysinfo","text":"Show system infos in JSON syntax - Example: [{\"firmware\": \"\",\"buildtime\": \"2023-01-25 12:41\",\"gitbranch\": \"HEAD\",\"gittag\": \"\",\"gitrevision\": \"af13c68+\",\"html\": \"Development-Branch: HEAD (Commit: af13c68+)\",\"cputemp\": \"64\",\"hostname\": \"WaterMeterTest\",\"IPv4\": \"192.168.xxx.xxx\",\"freeHeapMem\": \"2818330\"}]
"},{"location":"REST-API/#starttime","title":"starttime","text":"Show starttime - Example: 20230113-154634
"},{"location":"REST-API/#uptime","title":"uptime","text":"Show uptime - Example: 0d 00h 15m 50s
"},{"location":"REST-API/#camera","title":"Camera","text":""},{"location":"REST-API/#lighton","title":"lighton","text":"Switch the camera flashlight on
"},{"location":"REST-API/#lightoff","title":"lightoff","text":"Switch the camera flashlight off
"},{"location":"REST-API/#capture","title":"capture","text":"Capture a new image (without flashlight)
"},{"location":"REST-API/#capture_with_flashlight","title":"capture_with_flashlight","text":"Capture a new image with flashlight
"},{"location":"REST-API/#stream","title":"stream","text":"Stream a live video of the camera.
It has a slow refresh rate of only 2 FPS to avoid stressing the system. Flow processing continues to work in the background, albeit possibly a bit slower.
When the flashlight parameter is set, it turns on the flaslight. Both http://<IP>/stream?flashlight=true and http://<IP>/stream?flashlight turn on the flashlight.
LIMITATION: To avoid using extra memory, no additional dedicated stream webserver is implemented for this feature (instead, the web interface server is reused in a kind of \"blocking way\"). This means that either the web interface is fully functional or the stream is active, but not both at the same time. However, this is sufficient for the intended use case.
"},{"location":"REST-API/#save","title":"save","text":"Save a new image to SD card - The save entrypoint also support parameters: - http://<IP>/save?filename=test.jpg&delay=1000
"},{"location":"REST-API/#logs","title":"Logs","text":""},{"location":"REST-API/#log","title":"log","text":"Last part of todays log (last 80 kBytes))
"},{"location":"REST-API/#logfileact","title":"logfileact","text":"Full log of today
"},{"location":"REST-API/#loghtml","title":"log.html","text":"Opens the log html page
"},{"location":"REST-API/#diagnostics","title":"Diagnostics","text":""},{"location":"REST-API/#heap","title":"heap","text":"print relevant memory (heap) information - Example: Heap info: Heap Total: 1888926 | SPI Free: 1827431 | SPI Larg Block: 1802240 | SPI Min Free: 758155 | Int Free: 61495 | Int Larg Block: 55296 | Int Min Free: 36427
"},{"location":"REST-API/#prometheusopenmetrics","title":"Prometheus/OpenMetrics","text":""},{"location":"REST-API/#metrics","title":"metrics","text":"Provides a set of metrics that can be scraped by prometheus. See Prometheus/OpenMetrics for details.
"},{"location":"REST-API/#password-protection","title":"Password Protection","text":"The Web Interface and the REST API can be protected by a password, see Password-Protection.
"},{"location":"ROI-Configuration/","title":"ROIs (Regions of Interest)","text":"Notes
You are using a neural network approach which is trained to fit as many different type of meters as possible. The accuracy will never be 100%. It is normal to see a missing reading once in a while. There are several precautions to detect this. For details see the section PostProcessing on the configuration page.
The most critical components for an accurate detection are:
-
Correct setting of the Regions Of Interest (ROIs) for detection of the image.
This must be done manually for each device/installation!
-
Using a well trained Model.
Have a look on the Digit Counters resp. Analog Needles to check if your types are contained. If your number types are not contained, you should take the effort to record them so we can add them to the training data. See Collect images to improve the models on how to collect new training data.
"},{"location":"ROI-Configuration/#precondition","title":"Precondition","text":"Please make sure to have:
- Setup your camera properly and taken a good Reference Image.
- Selected good Alignment References.
"},{"location":"ROI-Configuration/#define-the-rois","title":"Define the ROIs","text":"For each digit or analog pointer, a ROI must be defined.
You can even have multiple independent Numbers (eg. electerical meters mostly have 2 numbers for the high and low tariff).
Depending if you have only one of those types, you can enable/disable (1) it on the top left corner:
You can switch between the individual ROIs with the Drop down box (2). If you need additional ROIs or delete them you can do this with the control at (3). Like for the Alignment References, you can change the position, size and name of a ROI in the text fields or define them via drag and drop through the mouse button. Make sure the ROIs are in the right order, matching the significance of a digit/analog counter!
Warning
The order of the ROIs defines how the individual digits are combined to the total number. The first ROI is the digit with the highest order (left side), then the second and so on. You can control the order in the selector tab and change it with the buttons \"move Next\" or \"move Previous\".
In most cases digits are ordered equidistantly (have the same distance between each other) and have the same size. Because of this, the Web Interface keeps their sizes and distance the same. If you need individual sizes or distances, untick the settings (4).
In almost all cases the sizes and y values should be identical! The ratio between x and y might need adjustment. But make sure it is the same for all digits.
Same for the analog counters, the sizes should be identical and the x and y as well.
Note
Don't forget to save the settings with \"Save\" and do not reboot at this stage.
"},{"location":"ROI-Configuration/#analog-counters","title":"Analog Counters","text":"For analog counters the ROI setting is rather straight forward as the meter is usually quadratic with a clear center. The circle should exactly fit to the outer size of the meter and the cross should be in the middle of the pointer.
Here is an example with the details for the ROI ana1:
"},{"location":"ROI-Configuration/#digits","title":"Digits","text":"For the Digit Meters it is a little bit more complicated, as there are different options of digit models which can be choosen.
"},{"location":"ROI-Configuration/#correct-size-for-roi","title":"Correct Size for ROI","text":"First of all, choose the right size of the ROI. The configuration of ROIs differs a bit on the selected model (see below).
If you are in the initial setup, the model will be selectable in the next step. By default it is a dig-cont resp. ana-cont model.
In Model Selection you find the differences between the different available models. Pick the one you think fits best your purpose. If you don't get to good result, try another model.
Here we only show the different configuration of the ROIs.
-
Digit Meters with only recognized full digits (0, 1, 2, 3, ... 9)
Suggested Model: dig-class11-*.tfl
Advantage: broad variety of types included in the training.
Disadvantage: partially rotated numbers cannot be detected.
-
Digit Meters with sub-digit resolution (0.0, 0.1, 0.2, .... 9.8, 9.9)
Suggested Model: dig-cont-*.tfl or dig-class100-*.tfl
Advantage: partial numbers can be detected and a better post processing is possible.
Disadvantage: only limited types of meter types are trained due to the high effort for the training data.
"},{"location":"ROI-Configuration/#how-to-setup-the-digit-rois-perfectly","title":"How to setup the digit ROIs perfectly","text":"Details and the corresponding \"perfect\" setting is explained below. For a first run you can choose the following general settings:
- There is an inner and an outer frame for the ROIs.
- Make the inner frame exactly the size of the number.
Example 1 Example 2 \u2714\ufe0f Okay \u274c Not Okay \u274c Not Okay"},{"location":"ROI-Configuration/#setup-using-dig-class11-models","title":"Setup using dig-class11 models","text":"dig-class11 - Models recognize the complete digit only. Here it is not relevant if the ROI fits the Border of the digit window.
For this model, there should be a border of 20% of the image size around the number itself. This border is shown in the ROI setup image by the inner thinner rectangle. This rectangle should fit perfectly around the number when the number has not started to rotate to the next position:
Example 1 Example 2 \u2714\ufe0f Okay \u274c Not Okay \u274c Not Okay If you have perfect alignment and still are not getting satisfying results, most probably your numbers are not part of the training data yet. See Collect images to improve the models on how to collect new training data.
"},{"location":"ROI-Configuration/#setup-using-dig-class100-or-dig-cont-models","title":"Setup using dig-class100 or dig-cont Models","text":"These models recognize the tenths (fractions) between the numbers. Those models require a different ROI setup; the height must be set differently and more accurately.
First, the width can be set like for a dig-class11 model, i.e. 20% margin left and right.
The height of the outer rectangle should be set to the upper and lower edge of the number window. To achieve this, you might need to unlock the aspect ratio:
Here an example:
Example 1 \u2714\ufe0f Okay \u274c Not Okay"},{"location":"ROI-Configuration/#saving","title":"Saving","text":"Once you are done, push Save to persist your setup.
A reboot is required to apply the changed configuration!
"},{"location":"Reference-Image/","title":"Reference Image","text":"Note
The Reference Image is the basis for the coordinate system of the ROIs. Therefore it is very important, to have a well aligned image, that is not rotated.
At first an example image is shown. To define a new reference image push the button \"Create new Reference\" (2) and afterwards \"Take Image\" (2). It might take some seconds for processing, then your actual camera image should be shown. Then play with the provided parameters to get a good result.
"},{"location":"Reference-Image/#focus","title":"Focus","text":"This is the first time, where you have access to the camera image. It most likely is out of focus and not sharp! Ensure a sharp image of the camera by adjusting the focal length of the ESP OV2640 camera.
Note
Try to adjust the focus for the clearest possible image!
In order to use it for reading a meter, the focal-length of the OV2640 camera has to be manipulated. By default it only results in sharp image for distance bigger than around ~40cm which is not ideal for our purpose.
Therefore you need to remove the fixing glue of the OV2640 lens with a sharp knife. After this you can rotate the lens in and out. Rotating it by about a quarter of a turn counterclockwise results in a focus plane shift of about 10cm. You need to figure out your best setting with a little bit of trial and error for your specific environment.
Error
Be very carefully when rotating the lens. Best is to held the camera itself with one hand or a plier and rotate the lens with the other hand. Make sure not to rotate the whole camera as this can damage the ribbon cable!
Warning
This modification will void any warranty, as the sealing of the lens objective is broken!
Warning
This modification will render the camera unsuitable for general, web-cam type applications unless the focal length is changed back to the original setting.
"},{"location":"Reference-Image/#correct-horizontal-alignment","title":"Correct Horizontal Alignment","text":"Ensure an exact horizontal alignment of the number:
\u2714\ufe0f Okay \u274c Not Okay Warning
Updating the reference image also means that all alignment images and ROIs needs to be configured again. Therefore do this step later only with caution.
If everything is done, you can save the result with \"Update Reference Image\" (4).
Note
A reboot is not required at this point of time.
As next you should update the Alignment References.
"},{"location":"Reference-Image/#dealing-with-reflections","title":"Dealing with Reflections","text":"Reflections can be caused by the flash LED and make it hard to provide a reliable detection. There are various ways to deal with them:
- Attach a diffusor in front of the LED, eg. a filt (Filz) or parchment paper. Also white paper can do the job.
- Rotate the ESP-CAM so the LED is on another place.
- Reduce the LED intensity.
- Use external LED stripes, eg
WS2812x.
"},{"location":"Release-creation/","title":"Release Procedure","text":"Follow these steps to create a release:
- Document all relevant changes in the Changelog in the
main branch. To get a list of commits, you can call git log --oneline or check commits/main/. Summarize the relevant changes since the last release. - Wait for the GitHub action to run successfully.
- Test it to see if everything worsk as expected.
- Update the contributors list in the README.md by triggering the Manually update contributors list action.
-
Go to releases/new to create a new release. Fill in a new tag and select \"Create new tag: xxx on publish\". A tag should have the format x.y.z. It is suggested to first select \"Set as a pre-release\" at the bottom.
-
Wait for the GitHub-Action of release creation. After all is done:
- the release should be created
- the artifacts are downloadable from release
- The documented changes were applied to the release
- In case of a full release (not a pre-release), check that the Web Installer shows the right version. If needed, run he action manually: github.com/jomjol/AI-on-the-edge-device/actions/workflows/manual-update-webinstaller.yml.
"},{"location":"StatusLED-BlinkCodes/","title":"Board status LED (blink codes)","text":"This page lists possible blink codes of the red LED located on the ESP32-CAM board, their meaning and possible solutions.
The error code source definition can be found here.
"},{"location":"StatusLED-BlinkCodes/#general-design-approach","title":"General design approach:","text":" - 250ms blink code to identify source
- 500ms defined LED off
- 250ms blink code to identify error / status code
- 1,5s defined LED off to signal repetition
- Repetition blink code: infinite for critical errors and status indication or 2x for warning indication
- e.g. 3x blinks | 500ms LED off | 2x blinks --> error: SD card not found
source source blink count error / warning / status status blink count repeat infinite WLAN_CONN 1 Disconnected (No Access Point) 1 WLAN_CONN 1 Disconnected (Authentication failure) 2 WLAN_CONN 1 Disconnected (Timeout) 3 WLAN_CONN 1 Disconnected (further reasons) 4 WLAN_INIT 2 wlan.ini empty or not readable 1 X WLAN_INIT 2 SSID or password empty 2 X WLAN_INIT 2 WIFI init error (details console) 3 X SDCARD_INIT 3 SD card filesystem mount failed 1 X SDCARD_INIT 3 SD card not found (0x107) 2 X SDCARD_INIT 3 SD card init failed (details console) 3 X SDCARD_CHECK 4 Basic check: file creation/write error 1 X SDCARD_CHECK 4 Basic check: file read/CRC error 2 X SDCARD_CHECK 4 Basic check: file delete error 3 X SDCARD_CHECK 4 Basic check: folder/file presence 4 X CAM_INIT 5 Camera init failed (details console) 1 X CAM_INIT 5 Camera framebuffer check failed 2 PSRAM_INIT 6 RAM init failed: Not found/defective 1 X PSRAM_INIT 6 External SPI RAM < 4MB 2 X PSRAM_INIT 6 Total heap < 4MB 3 X TIME_CHECK 7 Missing time sync (check every round) 1 OTA_OR_AP 8 OTA process ongoing 1 X OTA_OR_AP 8 Soft AP started (for remote config) 2 X FLASHLIGHT N/A LED on when flashlight is on solid, no blink"},{"location":"StatusLED-BlinkCodes/#error-warning","title":"ERROR / WARNING","text":""},{"location":"StatusLED-BlinkCodes/#source-wlan_conn-wlan-disconnected","title":"Source WLAN_CONN: WLAN disconnected","text":"Note
Only warning indication, blink code repetition: 2x --> General info: WLAN disconnect reason code description
"},{"location":"StatusLED-BlinkCodes/#wlan-disconnected-no-access-point","title":"WLAN disconnected (No Access Point)","text":"WLAN connection is interrupted due to no access point in range.
"},{"location":"StatusLED-BlinkCodes/#wlan-disconnected-authentication-failure","title":"WLAN Disconnected (Authentication failure)","text":"WLAN connection is interrupted due to an authentication failure. If error repeats check WLAN config in wlan.ini (username, password)
"},{"location":"StatusLED-BlinkCodes/#wlan-disconnected-timeout","title":"WLAN Disconnected (Timeout)","text":"WLAN connection is interrupted due to an timeout because no beacon from AP is received in a timely manner. Most probably access point is not available anymore or connection is not reliable.
"},{"location":"StatusLED-BlinkCodes/#wlan-disconnected-further-reasons","title":"WLAN Disconnected (Further reasons)","text":"WLAN connection is interrupted due to further reasons. Disconnect reason is printed in warining message. Please check serial console output or logfile from sd card (using another device to retrieve logfile /sdcard/log/message/). Please refer to this page to have additional infos in terms of WLAN disconnect reasons --> WLAN disconnect reason code description
"},{"location":"StatusLED-BlinkCodes/#source-wlan_init-wlan-initialization","title":"Source WLAN_INIT: WLAN initialization","text":"Note
All critical errors, regular boot not possible
"},{"location":"StatusLED-BlinkCodes/#wlanini-empty-or-not-readable","title":"wlan.ini empty or not readable","text":"The wlan.ini file is present but content is either not readable or no content present. Please check for further errors in terms of SD card readability or content of wlan.ini which is located in /sdcard (most top folder od SD card)
"},{"location":"StatusLED-BlinkCodes/#ssid-or-password-empty","title":"SSID or password empty","text":"The mandatory parameters SSID (name of WIFI network) and / or password is empty. Please configure those parameters in wlan.ini and try again.
"},{"location":"StatusLED-BlinkCodes/#wifi-init-error-details-console","title":"WIFI init error (details console)","text":"A general WIFI initialization error occured. Please check serial console output or logfile from sd card (using another device to retrieve logfile /sdcard/log/message/)
"},{"location":"StatusLED-BlinkCodes/#source-sdcard_init-sd-card-initialization","title":"Source SDCARD_INIT: SD card initialization","text":"Note
All critical errors, regular boot not possible
"},{"location":"StatusLED-BlinkCodes/#sd-card-filesystem-mount-failed","title":"SD card filesystem mount failed","text":"Failed to mount FAT filesystem on SD card. Check SD card filesystem (only FAT supported) or try another card. Possible further infos: Please check serial console output.
"},{"location":"StatusLED-BlinkCodes/#sd-card-not-found-error-code-0x107","title":"SD card not found (Error code 0x107)","text":"SD card init failed. Check if SD card is properly inserted into SD card slot or try another card. Possible further infos: Please check serial console output.
"},{"location":"StatusLED-BlinkCodes/#sd-card-init-failed-details-console","title":"SD card init failed (details console)","text":"A general SD card initialization error occured. Please check serial console output.
"},{"location":"StatusLED-BlinkCodes/#source-sdcard_check-sd-card-basic-check","title":"Source SDCARD_CHECK: SD card basic check","text":"Note
All critical errors, normal boot not possible. Reduced WebUI is going to be loaded for further diagnostic possibilities or redo firmware update.
"},{"location":"StatusLED-BlinkCodes/#file-creation-write-error","title":"File creation / write error","text":"A basic check of SD card is performed at boot. Failed to create the test file or writing content to the file failed. Most likely SD card is defective or not supported. Please check logs with log viewer in reduced web interface, serial console output or try another card.
Recommendation: Format or try another card
"},{"location":"StatusLED-BlinkCodes/#file-read-crc-verfication-error","title":"File read / CRC verfication error","text":"A basic check of SD card is performed at boot. Failed to read the test file or CRC of read back content failed. Most likely SD card is defective. Please check logs with log viewer in reduced web interface or serial console output for further error indication or try another card.
Recommendation: Format or try another card
"},{"location":"StatusLED-BlinkCodes/#file-delete-error","title":"File delete error","text":"A basic check of SD card is performed at boot. Failed to delelte the test file. Most likely SD card is defective. Please check logs with log viewer in reduced web interface or serial console output for further error indication or try another card.
Recommendation: Format or try another card
"},{"location":"StatusLED-BlinkCodes/#folder-file-presence-failed","title":"Folder / File presence failed","text":"A basic check of SD card is performed at boot. One or more menadatory folder / file are not found on SD card. Please check logs with log viewer in reduced web interface or serial console output for further error indication.
Recommendation: Repeat installation using AI-on-the-edge-device__update__*.zip
"},{"location":"StatusLED-BlinkCodes/#source-cam_init-camera-initialization","title":"Source CAM_INIT: Camera initialization","text":""},{"location":"StatusLED-BlinkCodes/#camera-init-failed-details-console","title":"Camera init failed (details console)","text":"Note
Critical error, normal boot not possible. Reduced WebUI is going to be loaded for further diagnostic possibilities or redo firmware update.
A general camera initialization error occured. Please check logs with log viewer in reduced web interface or serial console output for further error indication.
Recommendation: Check for proper electrical connection, whether camera model is supported and whether power supply is sufficient.
"},{"location":"StatusLED-BlinkCodes/#camera-framebuffer-check-failed","title":"Camera framebuffer check failed","text":"The framebuffer of the camera was not readable. The firmware will trying to continue regular boot, but further errors can occur which block regular processing. Please check logs with logfile viewer if processing is behaving irregular.
Recommendation: Check for proper electrical commenection, wether camera model is supported and wether power supply is suffcient.
"},{"location":"StatusLED-BlinkCodes/#source-psram_init-external-ram-spi-ram-initialization","title":"Source PSRAM_INIT: External RAM (SPI RAM) initialization","text":"Note
A critical errors, normal boot not possible. Reduced WebUI is going to be loaded for further diagnostic possibilities or redo firmware update.
"},{"location":"StatusLED-BlinkCodes/#spi-ram-init-failed-not-founddefective","title":"SPI RAM init failed: Not found/defective","text":"External RAM (SPI RAM) initialization failed. Most likely external RAM not accessable or defective. Normal operation is not possible without having external RAM.
"},{"location":"StatusLED-BlinkCodes/#external-spi-ram-4mb","title":"External SPI RAM < 4MB","text":"External RAM (SPI RAM) initialization successful, but external RAM size is too small. A size of >= 4MB is necessary to run this firmware.
"},{"location":"StatusLED-BlinkCodes/#total-heap-4mb","title":"Total heap < 4MB","text":"Total available system memory (heap) is too small. A size of >= 4MB is necessary to run this firmware.
"},{"location":"StatusLED-BlinkCodes/#source-time_check-external-ram-spi-ram-initialization","title":"Source TIME_CHECK: External RAM (SPI RAM) initialization","text":""},{"location":"StatusLED-BlinkCodes/#missing-time-sync-check-every-round","title":"Missing time sync (check every round)","text":"Note
Only warning indication, blink code repetition: 2x
If system is configured to be synced with a NTP server the sync status is checked after every round (in state: \"Flow finished\". An warming message is also printed to log). If the time is not synced after serveral rounds, please check for proper configuration.
"},{"location":"StatusLED-BlinkCodes/#status","title":"STATUS","text":"Note
All only status indication
"},{"location":"StatusLED-BlinkCodes/#source-ota_or_ap-ota-update-access-point-mode","title":"Source OTA_OR_AP: OTA Update / Access point mode","text":""},{"location":"StatusLED-BlinkCodes/#ota-process-ongoing","title":"OTA process ongoing","text":"An OTA is performed right now. Please wait until OTA is completed. System is rebooting automatically. If system is not coming up, please check serial console output.
"},{"location":"StatusLED-BlinkCodes/#soft-ap-started-for-remote-config","title":"Soft AP started (for remote config)","text":"The built-in access point functionality is started to perform initial remote remote setup. Further description: Installtion --> Section Remote Setup using the built-in Access Point
"},{"location":"StatusLED-BlinkCodes/#source-flashlight-flashlight","title":"Source FLASHLIGHT: Flashlight","text":""},{"location":"StatusLED-BlinkCodes/#led-on-when-flashlight-is-on","title":"LED on when flashlight is on","text":"The LED is solid on as long the flashlight is on. This feature has lower priority than the other LED codes. Whenever another code occurs this feature will be overrided.
"},{"location":"Testing/","title":"Testing Option for VSCode","text":"You can test your functions directly on the device.
"},{"location":"Testing/#structure","title":"Structure","text":"All tests are under directory \"test\" in the project and not compiled with default build option of platformio. The main function is in file test_suite_controlflow.cpp. In method app_main() you can add your own tests.
"},{"location":"Testing/#include-my-own-test","title":"Include my own test","text":"In method app_main() of test_suite_controlflow.cpp you can add your own tests. Include your test-file in the top like
#include \"components/jomjol-flowcontroll/test_flow_postrocess_helper.cpp\"
components is a subfolder of tests here. Not the components directory of root source.
In the bottom add your test function.
RUN_TEST(testNegative);
Your test function should have a TEST_ASSERT_EQUAL_*. For more information look at unity-testing.
"},{"location":"Testing/#run-tests","title":"Run tests","text":"You will need a testing device. best with usb adapter. Before you upload your tests you will need to setup the device with initial setup procedure described in [[Installation]]
Now you can use Visual Studio Code or a standard console to upload the test code. In VS Code (tab platformio) open Advanced and select Test.
Alternatively you can run it in console/terminal with platformio test --environment esp32cam.
In my environment the serial terminal not opens. I have to do it for myself. You will see much logging. If any test fails it logs it out. Else it logs all test passed in the end.
"},{"location":"Testing/#troubleshooting","title":"Troubleshooting","text":"If you test very much cases in one function, the device runs in Stack Overflow and an endless boot. Reduce the count of test cases or split the test function in multiple functions.
"},{"location":"Upload-files-by-script/","title":"Scripted File Upload","text":"To upload a file e.g. using curl, you first have to delete it and then upload it:
curl -d '' http://192.168.1.153/delete/html/index.html\ncurl --data-binary @ota_page.html http://192.168.1.153/upload/html/index.html\n
"},{"location":"WLAN-disconnect-reason/","title":"WLAN disconnect reasons","text":"In the logfile the WLAN disconnect reason code are printed whenever a disconnect event occurs (WARNING LEVEL or higher).
Further information and additional description of reason codes can be found here: WLAN disconnect reason code description
"},{"location":"Watermeter-specific-analog---digit-transition/","title":"Analog/Digit Transition on Water Meters","text":"At first, for the most water meters the default configuration should be work. But the digit, especially the last digit differs in some devices.
"},{"location":"Watermeter-specific-analog---digit-transition/#normal-transition","title":"\"Normal\" transition","text":"In most cases, the transition of the last digit starts when the analogue pointer is > 9.
Often the last digit \"hangs\" a bit on this devices and comes not over zero. So it is not easy to see which digit is correct. In the first example 4 or still 3? (3 is correct).
"},{"location":"Watermeter-specific-analog---digit-transition/#early-transition","title":"Early transition","text":"Some units start the transition very early or run with the analogue pointer. In the third example, is it a 3 or a 2?
"},{"location":"Watermeter-specific-analog---digit-transition/#inaccuracies-in-image-recognition","title":"Inaccuracies in image recognition","text":"The models for image recognition are good, but have inaccuracies in the range +/- 0.2. In order to obtain as many correct results as possible, a treatment is carried out in the post process in the range of 9.8-0.2 for the analogue pointer, which must start differently depending on the type of counter.
"},{"location":"Watermeter-specific-analog---digit-transition/#how-to-configure-for-my-meter-type","title":"How to configure for my meter type","text":"If you have a devices with \"normal\" transition you should not have any issues. On devices with \"early\" transition, you can set the option AnalogToDigitTransitionStart to a value between 6 and 8. See the parameter documentation for details.
"},{"location":"Webhook/","title":"Webhook","text":""},{"location":"Webhook/#purpose","title":"Purpose","text":"The idea behind this webhook feature is to provide an alternative to MQTT and InfluxDB for transmitting data, such as water meter readings from a vacation home, to a standard PHP webspace.
You can call the webhook to upload the data or the raw image of a round to a server.
"},{"location":"Webhook/#configuration","title":"Configuration","text":"To configure the webhook feature, you only need to define a URI and an API key. The URI is where the webhook will send the data, and the API key is used to authenticate the requests, ensuring that only authorized devices can send data to your server. Optionally, \"Upload Image\" can be used to configure whether an additional PUT request should be sent to the same URI with the current image. A parameter timestamp is appended to establish a correlation.
"},{"location":"Webhook/#example-of-a-post-request","title":"Example of a POST Request","text":"Below is an example of the JSON payload that might be sent in a POST request to the webhook:
"},{"location":"Webhook/#request-headers","title":"Request Headers","text":"APIKEY: your-api-key-here\n
"},{"location":"Webhook/#json-payload","title":"JSON Payload","text":"[\n {\n \"timestamp\": \"2024-08-09T11:44:44+0200\",\n \"timestampLong\": 1723196684,\n \"name\": \"main\",\n \"rawValue\": \"0345.42647\",\n \"value\": \"345.42648\",\n \"preValue\": \"345.42648\",\n \"rate\": \"0.000000\",\n \"changeAbsolute\": \"0.00000\",\n \"error\": \"no error\"\n },\n {\n \"timestamp\": \"2024-08-09T11:44:44+0200\",\n \"timestampLong\": 1723196684,\n \"name\": \"test\",\n \"rawValue\": \"34\",\n \"value\": \"34\",\n \"preValue\": \"34\",\n \"rate\": \"0.000000\",\n \"changeAbsolute\": \"0\",\n \"error\": \"no error\"\n }\n]\n
"},{"location":"Webhook/#basic-example-of-a-server-using-php","title":"Basic Example of a server using PHP","text":"<?php\n$expectedApiKey = 'your-api-key-here';\n\n$receivedApiKey = isset($_SERVER['HTTP_APIKEY']) ? $_SERVER['HTTP_APIKEY'] : '';\n\nif ($receivedApiKey !== $expectedApiKey) {\n http_response_code(403); // 403 Forbidden\n echo json_encode(['status' => 'error', 'message' => 'Invalid API key']);\n exit;\n}\n\n$method = $_SERVER['REQUEST_METHOD'];\n\nif ($method === 'POST') {\n // Handle POST request: Write data to CSV\n $csvFile = 'webhook_log.csv';\n\n $jsonData = file_get_contents('php://input');\n\n $dataArray = json_decode($jsonData, true);\n if (!$jsonData || !is_array($dataArray)) {\n http_response_code(400); // 400 Bad Request\n echo json_encode(['status' => 'error', 'message' => 'Invalid JSON data']);\n exit;\n }\n\n $csvHandle = fopen($csvFile, 'a');\n if ($csvHandle === false) {\n http_response_code(500); // 500 Internal Server Error\n echo json_encode(['status' => 'error', 'message' => 'Unable to open CSV file']);\n exit;\n }\n\n foreach ($dataArray as $data) {\n $csvRow = [\n $data['timestampLong'], \n $data['name'], \n $data['rawValue'], \n $data['value'], \n $data['preValue'], \n $data['rate'], \n $data['changeAbsolute'], \n $data['error']\n ];\n fputcsv($csvHandle, $csvRow);\n }\n\n fclose($csvHandle);\n\n http_response_code(200); // 200 OK\n echo json_encode(['status' => 'success', 'message' => 'Data written to CSV file']);\n} elseif ($method === 'PUT') {\n // Handle PUT request: Save image\n $timestamp = $_GET['timestamp'];\n\n if (!ctype_digit($timestamp) || $timestamp < 0 || $timestamp > PHP_INT_MAX) {\n http_response_code(400); // 400 Bad Request\n echo json_encode(['status' => 'error', 'message' => 'Invalid timestamp']);\n exit;\n }\n\n $imageFilePath = 'uploaded_image_' . $timestamp . '.jpg';\n\n $imageData = file_get_contents('php://input');\n\n if (!$imageData) {\n http_response_code(400); // 400 Bad Request\n echo json_encode(['status' => 'error', 'message' => 'No image data received']);\n exit;\n }\n\n if (file_put_contents($imageFilePath, $imageData) === false) {\n http_response_code(500); // 500 Internal Server Error\n echo json_encode(['status' => 'error', 'message' => 'Unable to save the image']);\n exit;\n }\n\n http_response_code(200); // 200 OK\n echo json_encode(['status' => 'success', 'message' => 'Image uploaded successfully']);\n} else {\n // Handle unsupported HTTP methods\n http_response_code(405); // 405 Method Not Allowed\n echo json_encode(['status' => 'error', 'message' => 'Method not allowed']);\n}\n?>\n
"},{"location":"Webhook/#basic-example-of-a-server-using-python","title":"Basic Example of a server using Python","text":"from flask import Flask, request, jsonify\nimport csv\nimport os\n\napp = Flask(__name__)\n\n# List of allowed API keys\nALLOWED_API_KEYS = {\n '123',\n '456',\n '789'\n}\n\n@app.before_request\ndef check_api_key():\n # Get the API key from the request headers\n received_api_key = request.headers.get('APIKEY')\n\n # Check if the received API key is in the allowed list\n if received_api_key not in ALLOWED_API_KEYS:\n return jsonify({'status': 'error', 'message': 'Invalid API key'}), 403\n\n # Attach the API key to the request object for later use\n request.api_key = received_api_key\n\n@app.route('/webhook', methods=['POST', 'PUT'])\ndef webhook():\n # Create a directory for the API key if it doesn't exist\n api_key_dir = os.path.join('data', request.api_key)\n os.makedirs(api_key_dir, exist_ok=True)\n\n if request.method == 'POST':\n # Handle POST request: Write data to CSV\n data = request.get_json()\n if not data or not isinstance(data, list):\n return jsonify({'status': 'error', 'message': 'Invalid JSON data'}), 400\n\n csv_file = os.path.join(api_key_dir, 'webhook_log.csv')\n try:\n with open(csv_file, 'a', newline='') as csvfile:\n csv_writer = csv.writer(csvfile)\n for item in data:\n csv_writer.writerow([\n item.get('timestampLong'),\n item.get('name'),\n item.get('rawValue'),\n item.get('value'),\n item.get('preValue'),\n item.get('rate'),\n item.get('changeAbsolute'),\n item.get('error')\n ])\n return jsonify({'status': 'success', 'message': 'Data written to CSV file'}), 200\n except Exception as e:\n return jsonify({'status': 'error', 'message': 'Unable to open CSV file'}), 500\n\n elif request.method == 'PUT':\n # Handle PUT request: Save image\n timestamp = request.args.get('timestamp')\n if not timestamp or not timestamp.isdigit() or int(timestamp) < 0:\n return jsonify({'status': 'error', 'message': 'Invalid timestamp'}), 400\n\n image_data = request.data\n if not image_data:\n return jsonify({'status': 'error', 'message': 'No image data received'}), 400\n\n image_file_path = os.path.join(api_key_dir, f'{timestamp}.jpg')\n try:\n with open(image_file_path, 'wb') as image_file:\n image_file.write(image_data)\n return jsonify({'status': 'success', 'message': 'Image uploaded successfully'}), 200\n except Exception as e:\n return jsonify({'status': 'error', 'message': 'Unable to save the image'}), 500\n\n else:\n # Handle unsupported HTTP methods\n return jsonify({'status': 'error', 'message': 'Method not allowed'}), 405\n\nif __name__ == '__main__':\n app.run(host='0.0.0.0', port=5001)\n
"},{"location":"collect-new-images/","title":"Collect images to improve the models","text":"If your device has new, different digits or pointers it might be that the existing models don't recognize them well. In such case you can collect your images and so we can train the model better. This helps you and also others as the models get more accurate. Adding more images also helps if you have a model that is already known, but the neural models do not produce good results.
Experienced users can do the training also by themselves, see Learn a model with your own images.
"},{"location":"collect-new-images/#before-you-start","title":"Before you start","text":"Before you go ahead, please check if your digits/pointers are not yet contained in the training data. A visual overview is available at digits resp. pointers.
Poor recognition is often caused by blurred images, low contrast or incorrect setting of the ROIs. Therefore, check these possibilities first, as additional training will bring little improvement here. See ROI Configuration for details.
"},{"location":"collect-new-images/#collecting-images","title":"Collecting images","text":"The neural network is trained based on a set of images that have already been collected over time. If your digits are included or at least very similar to included images, the chance is very high that the neural network is working fine for you as well.
The neural network configuration is stored in the TensorFlow Lite format as *.tfl or *.tflite in the /config directory on the SD card. A model can be updated (or a new one added) by uploading the new file and activating it on the configuration page or in the config file /config/config.ini.
In order to incorporate new digits a training set of images is required. The training images needs to be collected in the final setup with the help of the Digits or Analog log settings (not to be confused with the Data or Debug log). Enable the logging of the images on the configuration page or in the config file /config/config.ini:
Now be patient! You have to wait until it has collected an image of each digit of every type. They will be placed on the SD card in the folder /log/digit/ resp. /log/analog/.
After some days, there will be a lot of images, many of them very similar. Because of this, it is important to select only a subset of them for the model training.
The tools shown below can help you with that.
"},{"location":"collect-new-images/#collecting-images-for-dig-class100dig-contana-class100","title":"Collecting images for dig-class100/dig-cont/ana-class100","text":"For digits use Collectmeterdigits resp. for pointers use collectmeteranalog to fetch the images from the device and select a subset of them. Please read the detailed instructions on the mentioned links for details!
If the fetching of the images is too slow for you, a faster way to get the images to your PC is to remove the SD-card from the ESP32 module and insert it into the card reader of yur PC. Then search for two..three images of each digit (not more! :-)). You will have to make sure to label the images yourself matching the effective value they are supposed to show.
"},{"location":"collect-new-images/#share-your-images","title":"Share your images","text":"In most cases we will integrate your images in the training dataset of the models. Only if we fear a degradation of the models or you need a different behavior, we might not include the data in the standard models (see at bottom of page for reasons).
To provide your images to us for training the model, open an Github Issue and append the zipped images ito it.
"},{"location":"collect-new-images/#images-can-be-rejected-if","title":"Images can be rejected if","text":" - You provide too many images. More than 1000 images of your device are really to much.
- Images which are not good enough (see ROI Configuration) will be rejected. It would reduce the accuracy of the networks.
- Images with too little focus will be rejected.
- Images with too much blur are rejected.
Our models are to small to recognize everything in any quality. So we use only images of medium or good quality.
"},{"location":"data-logging/","title":"Data Logging","text":"When Data Logging is enabled (See parameter DataLogActive), the results of every round gets written to the SD-Card.
The data files are stored in /log/data on the SD-Card.
"},{"location":"data-logging/#data-format","title":"Data Format","text":"The data is stored as CSV with the following columns: time, name-of-number, raw-value, return-value, pre-value, change-rate, change-absolute, error-text, cnn-digit, cnn-analog
"},{"location":"initial-setup/","title":"Initial Setup","text":"After setting up the device (firmware, SD card, WLAN) the device will connect to the wifi access point and start in an initial setup configuration:
With the buttons on the top you can navigate through 5 steps which guide you through the necessary setup:
- Create the Reference Image. It is the base for the position referencing and the identification of the digits and counters.
- Define two unique Reference Marks. They is used to align the individual camera images and identify the absolute positions.
- Define ROIs for the Digits. They will be used to digitize the digit part of your meter. If your meter has no digits, this step can be skipped.
- Define ROIs for the Analog Counters. (Only required in case your meter has analog counters)
- General Settings. Further configuration of your device.
All settings can be accessed later in the normal operation mode.
Note
Don't forget to save each step with \"Save\", and do not reboot at this stage.
"},{"location":"initial-setup/#finish-the-setup-and-change-to-the-normal-operation-mode","title":"Finish the Setup and change to the Normal Operation mode","text":"With the last step (1) you leave the Setup Mode and reboot to the Normal Operation mode.
"},{"location":"initial-setup/#access-to-the-setup-pages-in-the-normal-operation-mode","title":"Access to the Setup Pages in the Normal Operation mode","text":"You always can access all the settings during the normal operation mode via the Settings menu:
(1) Access to the General Settings. (2) Update of the Reference Image. (3) Update of the Alignment Marks. (4)/(5) Update of the ROIs.
"},{"location":"ota/","title":"Over-The-Air (OTA) Update","text":"You can do an OTA (over-the-air) update via the Web Interface. Grab the firmware from the
- Releases page (Stable, tested versions), or the
- Automatically build development branch (experimental, untested versions). Please inform yourself on Living on the Edge first!
"},{"location":"ota/#update-procedure","title":"Update Procedure","text":" - Create a backup of your configuration. Either use the Backup/Restore function of your device for this (menu
System > Backup/Restore) or back the files manually up using the File Server (menu File Server, folder config). It is recommended to at least save the config file config.ini! - Head to the menu
System > OTA Update and follow the instructions there.
If you do an update between major versions, it might be needed to modify the config file config.ini as it's syntax or context has changed. To do so, go to the menu Settings > Configuration (after the update completed and the device restarted) and check if it warns you about an unset parameter.
"},{"location":"ota/#update-from-version-v1200-or-newer","title":"Update from version v12.0.0 or newer","text":"You can use the over the air update mechanism, which uploads the update via a ZIP files.
The update file is located on the release page. Please choose the zip file with the following naming: AI-on-the-edge-device__update__*.zip
Go to the menu System --> OTA Update and follow the instructions there. After a final automatic reboot you should have the new version running.
"},{"location":"ota/#update-from-version-older-than-v1200","title":"Update from version older than v12.0.0","text":"If you update from an version older than 12.0.1, you should firstly update to version 12.0.1. Background are not fully backward compatible changes in the config.ini, that are taken care of in this version.
Warning
Make sure to read the instructions below carefully!
-
Backup your configuration (use the System -> Backup/Restore page)!
-
Upload and update the update-*.zip file from the release 12.0.1 see here .
-
Let it restart and check on the System -> Info page that the Firmware as well as the Web UI got updated. If only one got updated, redo the update. If it fails several times, you also can update the Firmware and the Web UI separately.
-
Safe way:
- Update first the
firmware.bin (extract it from one of the provided zip files) and do the Reboot - Update with the full zip file (
update-*.zip, ignore the version warning after the reboot)
-
Please go to Settings -> Configuration and address the changed parameters:
- DataLogging (storing the values for data graph)
- Debug (extended by different debug reporting levels)
-
Make sure it starts to do the digitization (check the Error field on the overview page). If it does not start a round within a minute, restart the device.
Note
If the system is working now without any issues, please open the configuration editor once and save the config.ini. This will update the file to the newest content.
Now you can safely update to the newest version.
"},{"location":"outdated--Integrated-Functions/","title":"Integrated Functions","text":"Warning
This page no longer is maintained!
"},{"location":"outdated--Integrated-Functions/#wasserzaehler","title":"wasserzaehler","text":"http://IP-ESP32/wasserzaehler.html
This is the main purpose of this device. It returns the converted image as a number with different option. The output can be modified either by the configuration parameters or by HTML parameters.
Details can be found here: tbd
"},{"location":"outdated--Integrated-Functions/#picture-server","title":"Picture Server","text":"http://IP-ESP32/capture
http://IP-ESP32/capture_with_flashlight
This is a implementation of the camera interface of https://github.com/jomjol/water-meter-picture-provider
It is fully compatible including the parameters (quality=..., size=... ) . This allows to use this ESP32 system in parallel to the corresponding docker system: https://github.com/jomjol/water-meter-system-complete, from which this project is basically the successor.
"},{"location":"outdated--Integrated-Functions/#file-server","title":"File server","text":"Access: http://IP-ESP32/fileserver/
Simple file server, that allows viewing, upload, download and deleting of single files of the SD-card content.
The usage is self explaining. The file path or file can directly be accessed by the URL after file server.
Example for config.ini : http://IP-ESP/fileserver/config/config.ini
"},{"location":"outdated--Integrated-Functions/#ota-update","title":"OTA-Update","text":"http://IP-ESP32/ota?file=firmware.bin
Here an over the air update can be triggered. The firmware file is expected to be located in the sub directory /firmware/ and can be uploaded with the file server. By the parameter file the name of the firmware file needs to be given.
"},{"location":"outdated--Integrated-Functions/#reboot","title":"Reboot","text":"http://IP-ESP32/reboot
A reboot with a delay of 5 seconds is initiated, e.g. after firmware update.
ATTENTION: currently this is not working properly - hardware power off is needed instead. Work in progress!
"},{"location":"outdated--Integrated-Functions/#simple-web-server","title":"Simple Web Server","text":"If none of the above URLs are fitting, a very simple web server checks, if there is a fitting file from the sub directory /html This can be used for a very simple web server for information or simple web pages.
"},{"location":"prometheus-openmetrics/","title":"Prometheus/OpenMetrics","text":"A set of metrics is exported via the /metrics REST API path on the device. Besides the current value, a set of device properties are exported. Multiple sequences (aka numbers) are supported via a label. The metrics are provided in text wire format.
Example:
$ curl http://<IP>/metrics\n# HELP ai_on_the_edge_device_flow_value current value of meter readout\n# TYPE ai_on_the_edge_device_flow_value gauge\nai_on_the_edge_device_flow_value{sequence=\"main\"} 240.7064\n# HELP ai_on_the_edge_device_cpu_temperature_celsius current cpu temperature in celsius\n# TYPE ai_on_the_edge_device_cpu_temperature_celsius gauge\nai_on_the_edge_device_cpu_temperature_celsius 41\n# HELP ai_on_the_edge_device_rssi_dbm current WiFi signal strength in dBm\n# TYPE ai_on_the_edge_device_rssi_dbm gauge\nai_on_the_edge_device_rssi_dbm -67\n# HELP ai_on_the_edge_device_memory_heap_free_bytes available heap memory\n# TYPE ai_on_the_edge_device_memory_heap_free_bytes gauge\nai_on_the_edge_device_memory_heap_free_bytes 716303\n# HELP ai_on_the_edge_device_uptime_seconds device uptime in seconds\n# TYPE ai_on_the_edge_device_uptime_seconds gauge\nai_on_the_edge_device_uptime_seconds 214267\n# HELP ai_on_the_edge_device_rounds_total data aquisition rounds since device startup\n# TYPE ai_on_the_edge_device_rounds_total counter\nai_on_the_edge_device_rounds_total 239\n
"},{"location":"prometheus-openmetrics/#prometheus-scrape-config","title":"Prometheus Scrape Config","text":"The following scrape config (add to prometheus.yml) can be used as an example to ingest available metrics with prometheus:
scrape_configs:\n - job_name: watermeter\n scrape_interval: 300s\n metrics_path: /metrics\n static_configs:\n - targets: ['<IP>']\n
"},{"location":"prometheus-openmetrics/#references","title":"References","text":""},{"location":"unstable-installation/","title":"Living on the Edge","text":" - The main branch contains the latest version of the Firmware and the Web Interface. It might already contain a fix for your issue. But it is work in progress, don't expect it to work stable or be an improvement for your AI-on-the-edge-device! Also it might break the OTA Update and thus require manual flashing over USB! For normal users it is better tu use a release.
- Any other branch is used to develop a feature or fix, only use them when you know what it is about!
"},{"location":"unstable-installation/#i-still-want-to-try-it","title":"I still want to try it","text":"Ok, then grab the latest main build from Github Actions Page and proceed as following:
- Pick the most top successful (green) build:
- Scroll down and download the
AI-on-the-edge-device__update__*.zip: - Flash the zip file using the OTA Update page of your device.
"}]}
\ No newline at end of file