Compare commits
6 Commits
v15.4.0
...
add-websoc
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
59ccd601fc | ||
|
|
becbfc463f | ||
|
|
a5d2086159 | ||
|
|
716dcb5a84 | ||
|
|
a5c66eb014 | ||
|
|
6c86317d52 |
27
.github/label-commenter-config.yml
vendored
@@ -3,32 +3,7 @@
|
||||
# Make sure to also add the response to .github/workflows/reply-bot.yml!
|
||||
# Due to the way it works, you have to add each response twice, once for the issue, once for the discussions!
|
||||
|
||||
labels:
|
||||
#######################################################################
|
||||
# Bot Response: Documentation
|
||||
#######################################################################
|
||||
- name: bot-reply Documentation
|
||||
labeled:
|
||||
issue:
|
||||
body: |
|
||||
Please have a look on our documentation: https://jomjol.github.io/AI-on-the-edge-device-docs
|
||||
discussion:
|
||||
body: |
|
||||
Please have a look on our documentation: https://jomjol.github.io/AI-on-the-edge-device-docs
|
||||
|
||||
#######################################################################
|
||||
# Bot Response: ROI setup
|
||||
#######################################################################
|
||||
- name: bot-reply ROI Setup
|
||||
labeled:
|
||||
issue:
|
||||
body: |
|
||||
Make sure to setup your ROIs properly. Have a look on our documentation: https://jomjol.github.io/AI-on-the-edge-device-docs/ROI-Configuration/#how-to-setup-the-digit-rois-perfectly
|
||||
discussion:
|
||||
body: |
|
||||
Make sure to setup your ROIs properly. Have a look on our documentation: https://jomjol.github.io/AI-on-the-edge-device-docs/ROI-Configuration/#how-to-setup-the-digit-rois-perfectly
|
||||
|
||||
|
||||
labels:
|
||||
#######################################################################
|
||||
# Bot Response: Logfile
|
||||
#######################################################################
|
||||
|
||||
@@ -380,7 +380,7 @@ jobs:
|
||||
#########################################################################################
|
||||
## Update the Web Installer on a release
|
||||
#########################################################################################
|
||||
# Make sure to also update update-webinstaller.yml!
|
||||
# This is the same as in the update-webinstaller.yml
|
||||
update-web-installer:
|
||||
needs: [release]
|
||||
environment:
|
||||
@@ -408,14 +408,12 @@ jobs:
|
||||
|
||||
- name: Add binary to Web Installer and update manifest
|
||||
run: |
|
||||
echo "Updating Web installer to use firmware from ${{ steps.last_release.outputs.tag_name }}..."
|
||||
rm -f docs/binary/firmware.bin
|
||||
wget https://github.com/jomjol/AI-on-the-edge-device/releases/download/${{ steps.last_release.outputs.tag_name }}/AI-on-the-edge-device__update__${{ steps.last_release.outputs.tag_name }}.zip
|
||||
unzip AI-on-the-edge-device__update__${{ steps.last_release.outputs.tag_name }}.zip
|
||||
cp -f firmware.bin docs/binary/firmware.bin
|
||||
echo "Updating index and manifest file..."
|
||||
sed -i 's/$VERSION/${{ steps.last_release.outputs.tag_name }}/g' docs/index.html
|
||||
sed -i 's/$VERSION/${{ steps.last_release.outputs.tag_name }}/g' docs/manifest.json
|
||||
cp -f docs/manifest_template.json docs/manifest.json
|
||||
sed -i 's/VERSION/${{ steps.last_release.outputs.tag_name }}/g' docs/manifest.json
|
||||
- name: Setup Pages
|
||||
uses: actions/configure-pages@v2
|
||||
|
||||
10
.github/workflows/manual-update-webinstaller.yml
vendored
@@ -1,7 +1,7 @@
|
||||
# This updates the Web Installer with the files from the docs folder and the binary of the latest release
|
||||
# it only gets run on:
|
||||
# - Manually triggered
|
||||
# Make sure to also update the lower part of build.yml!
|
||||
# - Changes to the docs folder in the `rolling` branch
|
||||
# - On a release
|
||||
|
||||
name: Manual Web Installer Update
|
||||
|
||||
@@ -40,14 +40,12 @@ jobs:
|
||||
|
||||
- name: Add binary to Web Installer and update manifest
|
||||
run: |
|
||||
echo "Updating Web installer to use firmware from ${{ steps.last_release.outputs.tag_name }}..."
|
||||
rm -f docs/binary/firmware.bin
|
||||
wget https://github.com/jomjol/AI-on-the-edge-device/releases/download/${{ steps.last_release.outputs.tag_name }}/AI-on-the-edge-device__update__${{ steps.last_release.outputs.tag_name }}.zip
|
||||
unzip AI-on-the-edge-device__update__${{ steps.last_release.outputs.tag_name }}.zip
|
||||
cp -f firmware.bin docs/binary/firmware.bin
|
||||
echo "Updating index and manifest file..."
|
||||
sed -i 's/$VERSION/${{ steps.last_release.outputs.tag_name }}/g' docs/index.html
|
||||
sed -i 's/$VERSION/${{ steps.last_release.outputs.tag_name }}/g' docs/manifest.json
|
||||
cp -f docs/manifest_template.json docs/manifest.json
|
||||
sed -i 's/VERSION/${{ steps.last_release.outputs.tag_name }}/g' docs/manifest.json
|
||||
|
||||
- name: Setup Pages
|
||||
uses: actions/configure-pages@v2
|
||||
|
||||
48
Changelog.md
@@ -1,51 +1,3 @@
|
||||
## [15.4.0] - 2023-12-22
|
||||
|
||||
### Changes
|
||||
|
||||
For a full list of changes see [Full list of changes](https://github.com/jomjol/AI-on-the-edge-device/compare/15.4.0...v15.3.0)
|
||||
|
||||
#### Changed
|
||||
|
||||
- Updates submodules (esp-nn, tflite-micro-example, esp-camera)
|
||||
|
||||
- Explicitly included needed tflite network layers (instead of all) , resulting in much smaller firmware size
|
||||
|
||||
- Added shortcut icon
|
||||
|
||||
- Rename in InfluxDB 'Database' to 'Bucket'
|
||||
|
||||
- Updated analog tflite files
|
||||
- dig-class100-0167_s2_q.tflite
|
||||
- dig-class11_1700_s2.tflite
|
||||
- ana-cont_1208_s2_q.tflite
|
||||
|
||||
|
||||
#### Fixed
|
||||
|
||||
* InfluxDB: consider DST setting for UTC time conversion
|
||||
|
||||
* Minor html response bugfix
|
||||
|
||||
- Memory leakage (MQTT)
|
||||
|
||||
|
||||
|
||||
## [15.3.0] - 2023-07-22
|
||||
|
||||
### Changes
|
||||
|
||||
For a full list of changes see [Full list of changes](https://github.com/jomjol/AI-on-the-edge-device/compare/v15.3.0...v15.2.4)
|
||||
|
||||
#### Changed
|
||||
|
||||
- Updated PlatformIO to `6.3.2`
|
||||
- Updated analog tflite files
|
||||
- ana-cont_1207_s2_q.tflite
|
||||
- dig-cont_0620_s3_q.tflite
|
||||
|
||||
|
||||
|
||||
|
||||
## [15.2.4] - 2023-05-02
|
||||
|
||||
### Changes
|
||||
|
||||
@@ -2,41 +2,15 @@
|
||||
|
||||
**There are a lot of ideas for further improvements, but only limited capacity on side of the developer.** Therefore I have created this page as a collection of ideas.
|
||||
|
||||
1. Whoever has a new idea can put it here, so that it is not forgotten.
|
||||
1. Who ever has a new idea can put it here, so it that it is not forgotten.
|
||||
|
||||
2. Whoever has the time, capacity and passion to support the project can take any of the ideas and implement them. I will provide support and help wherever I can!
|
||||
2. Who ever has time, capacity and passion to support, can take any of the ideas and implement them.
|
||||
I will support and help where ever I can!
|
||||
|
||||
|
||||
|
||||
____
|
||||
|
||||
|
||||
#### #40 Trigger with cron like exact time slot
|
||||
|
||||
* https://github.com/jomjol/AI-on-the-edge-device/issues/2470
|
||||
|
||||
|
||||
|
||||
#### #39 upnp implementation to auto detect the device
|
||||
|
||||
* https://github.com/jomjol/AI-on-the-edge-device/issues/2481
|
||||
|
||||
|
||||
|
||||
#### #38 Energy Saving
|
||||
|
||||
* Deep sleep between recognition
|
||||
* https://github.com/jomjol/AI-on-the-edge-device/issues/2486
|
||||
|
||||
|
||||
|
||||
#### #37 Auto init SD card
|
||||
|
||||
* Fully implement the SD card handling (including formatting) into the firmware
|
||||
* https://github.com/jomjol/AI-on-the-edge-device/issues/2488Demo
|
||||
|
||||
#### #36 Run demo without camera
|
||||
|
||||
Demo mode requires a working camera (if not, one receives a 'Cam bad' error). Would be nice to demo or play around on other ESP32 boards (or on ESP32-CAM boards when you broke the camera cable...).
|
||||
|
||||
#### #35 Use the same model, but provide the image from a Smartphone Camera
|
||||
@@ -77,7 +51,7 @@ haveing this state in the mqtt broker can trigger functions like closing the ate
|
||||
|
||||
#### ~~#29 Add favicon and use the hostname for the website~~- implemented v11.3.1
|
||||
|
||||
* ~~https://github.com/jomjol/AI-on-the-edge-device/issues/927~~
|
||||
~~* https://github.com/jomjol/AI-on-the-edge-device/issues/927~~
|
||||
|
||||
#### #28 Improved error handling for ROIs
|
||||
|
||||
@@ -115,7 +89,7 @@ haveing this state in the mqtt broker can trigger functions like closing the ate
|
||||
|
||||
#### ~~#22 Direct hint to the different neural network files in the other repositories~~- implemented >v11.3.1
|
||||
|
||||
* ~~https://github.com/jomjol/AI-on-the-edge-device/issues/644~~
|
||||
~~* https://github.com/jomjol/AI-on-the-edge-device/issues/644~~
|
||||
|
||||
|
||||
|
||||
|
||||
106
README.md
@@ -1,31 +1,31 @@
|
||||
# Welcome to the AI-on-the-edge-device
|
||||
<img src="images/icon/watermeter.svg" width="100px">
|
||||
|
||||
Artificial intelligence based systems have become established in our everyday lives. Just think of speech or image recognition. Most of the systems rely on either powerful processors or a direct connection to the cloud for doing the calculations there. With the increasing power of modern processors, the AI systems are coming closer to the end user – which is usually called **edge computing**.
|
||||
Here, this edge computing is put into a practically oriented example, where an AI network is implemented on an ESP32 device so: **AI on the edge**.
|
||||
Artificial intelligence based systems have been established in our every days live. Just think of speech or image recognition. Most of the systems relay on either powerful processors or a direct connection to the cloud for doing the calculations up there. With the increasing power of modern processors the AI systems are coming closer to the end user - which is usually called **edge computing**.
|
||||
Here this edge computing is brought into a practical oriented example, where a AI network is implemented on a ESP32 device so: **AI on the edge**.
|
||||
|
||||
This project allows you to digitize your **analog** water, gas, power and other meters using cheap and easily available hardware.
|
||||
This projects allows you to digitalize your **analoge** water, gas, power and other meters using cheap and easily available hardware.
|
||||
|
||||
All you need is an [ESP32 board with a supported camera](https://jomjol.github.io/AI-on-the-edge-device-docs/Hardware-Compatibility/) and something of a practical hand.
|
||||
All you need is an [ESP32 board with a supported camera](https://jomjol.github.io/AI-on-the-edge-device-docs/Hardware-Compatibility/) and a bit of a practical hand.
|
||||
|
||||
<img src="images/esp32-cam.png" width="200px">
|
||||
|
||||
## Key features
|
||||
- Tensorflow Lite (TFlite) integration – including easy-to-use wrapper
|
||||
- Inline image processing (feature detection, alignment, ROI extraction)
|
||||
- **Small** and **cheap** device (3 x 4.5 x 2 cm³, < 10 EUR)
|
||||
- Integrated camera and illumination
|
||||
- Web interface for administration and control
|
||||
- OTA interface for updating directly via the web interface
|
||||
- Tensorflow Lite (TFlite) integration - including easy to use wrapper
|
||||
- Inline Image processing (feature detection, alignment, ROI extraction)
|
||||
- **Small** and **cheap** device (3x4.5x2 cm³, < 10 EUR)
|
||||
- camera and illumination integrated
|
||||
- Web surface to administrate and control
|
||||
- OTA-Interface to update directly through the web interface
|
||||
- Full integration into Homeassistant
|
||||
- Support for Influx DB 1 and 2
|
||||
- Support for Influx DB 1
|
||||
- MQTT
|
||||
- REST API
|
||||
|
||||
## Workflow
|
||||
The device takes a photo of your meter at a defined interval. It then extracts the Regions of Interest (ROIs) from the image and runs them through artificial intelligence. As a result, you get the digitized value of your meter.
|
||||
The device takes a photo of your meter at a defined interval. It then extracts the Regions of Interest (ROI's) out of it and runs them through an artificial inteligence. As a result, you get the digitalized value of your meter.
|
||||
|
||||
There are several options for what to do with that value. Either send it to an MQTT broker, write it to an InfluxDb or simply provide access to it via a REST API.
|
||||
There are several options what to do with that value. Either send it to a MQTT broker, write it to an InfluxDb or simply provide it throug a REST API.
|
||||
|
||||
<img src="https://raw.githubusercontent.com/jomjol/AI-on-the-edge-device/master/images/idea.jpg" width="600">
|
||||
|
||||
@@ -41,68 +41,62 @@ There are several options for what to do with that value. Either send it to an M
|
||||
|
||||
|
||||
## Setup
|
||||
There is growing [documentation](https://jomjol.github.io/AI-on-the-edge-device-docs/) which provides you with a lot of information. Head there to get a start, set it up and configure it.
|
||||
There is a growing [documentation](https://jomjol.github.io/AI-on-the-edge-device-docs/) which provides you with a lot of information.
|
||||
Head there to get a start, set it up and configure it.
|
||||
|
||||
There are also articles in the German Heise magazine "make:" about the setup and technical background (behind a paywall): [DIY - Setup](https://www.heise.de/select/make/2021/2/2103513300897420296)
|
||||
There are also a articles in the German Heise magazine "make:" about the setup and the technical background (behind a paywall) : [DIY - Setup](https://www.heise.de/select/make/2021/2/2103513300897420296)
|
||||
|
||||
A lot of people created useful Youtube videos which might help you getting started.
|
||||
Here a small selection:
|
||||
|
||||
- [youtube.com/watch?v=HKBofb1cnNc](https://www.youtube.com/watch?v=HKBofb1cnNc)
|
||||
- [youtube.com/watch?v=yyf0ORNLCk4](https://www.youtube.com/watch?v=yyf0ORNLCk4)
|
||||
- [youtube.com/watch?v=XxmTubGek6M](https://www.youtube.com/watch?v=XxmTubGek6M)
|
||||
- [youtube.com/watch?v=mDIJEyElkAU](https://www.youtube.com/watch?v=mDIJEyElkAU)
|
||||
- [youtube.com/watch?v=SssiPkyKVVs](https://www.youtube.com/watch?v=SssiPkyKVVs)
|
||||
- [youtube.com/watch?v=MAHE_QyHZFQ](https://www.youtube.com/watch?v=MAHE_QyHZFQ)
|
||||
- [youtube.com/watch?v=Uap_6bwtILQ](https://www.youtube.com/watch?v=Uap_6bwtILQ)
|
||||
|
||||
For further background information, head to [Neural Networks](https://www.heise.de/select/make/2021/6/2126410443385102621), [Training Neural Networks](https://www.heise.de/select/make/2022/1/2134114065999161585) and [Programming on the ESP32](https://www.heise.de/select/make/2022/2/2204010051597422030).
|
||||
For further background information, head to [Neural Networks](https://www.heise.de/select/make/2021/6/2126410443385102621), [Training Neural Networks](https://www.heise.de/select/make/2022/1/2134114065999161585) and [Programming on the ESP32](https://www.heise.de/select/make/2022/2/2204010051597422030)
|
||||
|
||||
### Download
|
||||
The latest available version can be found on the [Releases page](https://github.com/jomjol/AI-on-the-edge-device/releases).
|
||||
The latest available version is available on the [Releases page](https://github.com/jomjol/AI-on-the-edge-device/releases).
|
||||
|
||||
### Flashing the ESP32
|
||||
Initially you will have to flash the ESP32 via a USB connection. Later updates are possible directly over the air (OTA using WIFI).
|
||||
### Flashing of the ESP32
|
||||
Initially you will have to flash the ESP32 through an USB connection. Later an update is possible directly over the Air (OTA).
|
||||
|
||||
There are different ways to flash your ESP32:
|
||||
- The prefered way is the [Web Installer and Console](https://jomjol.github.io/AI-on-the-edge-device/index.html) which is a browser-based tool to flash the ESP32 and extract the log over USB:
|
||||

|
||||
- [Web Installer and Console](https://jomjol.github.io/AI-on-the-edge-device/index.html) (Webbrowser based tool to flash the ESP32 and extract the Log over USB)
|
||||
- Flash Tool from Espressif
|
||||
- ESPtool (command-line tool)
|
||||
- ESPtool (Command Line Tool)
|
||||
|
||||
See the [documentation](https://jomjol.github.io/AI-on-the-edge-device-docs/Installation/) for more information.
|
||||
See the [Docu](https://jomjol.github.io/AI-on-the-edge-device-docs/Installation/) for more information.
|
||||
|
||||
### Flashing the SD Card
|
||||
The SD card can be setup automatically after the firmware got installed. See the [documentation](https://jomjol.github.io/AI-on-the-edge-device-docs/Installation/#remote-setup-using-the-built-in-access-point) for details. For this to work, the SD card must be FAT formated (which is the default on a new SD card).
|
||||
Alternatively the SD card still can be setup manually, see the [documentation](https://jomjol.github.io/AI-on-the-edge-device-docs/Installation/#3-sd-card) for details!
|
||||
### Flashing the SD-Card
|
||||
The SD-Card must be flashed separately, see the [Docu](https://jomjol.github.io/AI-on-the-edge-device-docs/Installation/) for details.
|
||||
|
||||
## Casing
|
||||
Various 3D-printable housing can be found here:
|
||||
|
||||
A 3d-printable housing can be found here:
|
||||
- https://www.thingiverse.com/thing:4573481 (Water Meter)
|
||||
- https://www.thingiverse.com/thing:5028229 (Power Meter)
|
||||
- https://www.thingiverse.com/thing:5224101 (Gas Meter)
|
||||
- https://www.thingiverse.com/thing:4571627 (ESP32-cam housing only)
|
||||
- https://www.thingiverse.com/thing:4571627 (ESP32-Cam housing only)
|
||||
|
||||
## Donate
|
||||
If you would like to support the developer with a cup of coffee, you can do that via [PayPal](https://www.paypal.com/donate?hosted_button_id=8TRSVYNYKDSWL).
|
||||
|
||||
<a href="https://www.paypal.com/donate?hosted_button_id=8TRSVYNYKDSWL"><img border="0" src="images/paypal.png" width="200px" target="_blank"></a>
|
||||
|
||||
## Support
|
||||
If you have any technical problems please search the [discussions](https://github.com/jomjol/AI-on-the-edge-device/discussions). In case you found a ug or have a feature request, please open an [issue](https://github.com/jomjol/AI-on-the-edge-device/issues).
|
||||
|
||||
In other cases you can contact the developer via email: <img src="https://raw.githubusercontent.com/jomjol/AI-on-the-edge-device/master/images/mail.jpg" height="25">
|
||||
|
||||
## Changes and History
|
||||
See [Changelog](Changelog.md).
|
||||
|
||||
## Build It Yourself
|
||||
## Build it yourself
|
||||
See [Build Instructions](code/README.md).
|
||||
|
||||
## Donate
|
||||
If you would like to support the developer with a cup of coffee you can do that via [Paypal](https://www.paypal.com/donate?hosted_button_id=8TRSVYNYKDSWL).
|
||||
|
||||
<form action="https://www.paypal.com/donate" method="post" target="_top">
|
||||
<input type="hidden" name="hosted_button_id" value="8TRSVYNYKDSWL" />
|
||||
<input type="image" src="https://www.paypalobjects.com/en_US/DK/i/btn/btn_donateCC_LG.gif" border="0" name="submit" title="PayPal - The safer, easier way to pay online!" alt="Donate with PayPal button" />
|
||||
<img alt="" border="0" src="https://www.paypal.com/en_DE/i/scr/pixel.gif" width="1" height="1" />
|
||||
</form>
|
||||
If you have any technical topics, you can create an [Issue](https://github.com/jomjol/AI-on-the-edge-device/issues).
|
||||
|
||||
In other cases you can contact the developer via email: <img src="https://raw.githubusercontent.com/jomjol/AI-on-the-edge-device/master/images/mail.jpg" height="25">
|
||||
|
||||
## Changes and History
|
||||
See [Changelog](Changelog.md)
|
||||
|
||||
## Tools
|
||||
|
||||
* Logfile downloader and combiner (Thx to [reserve85](https://github.com/reserve85))
|
||||
* Files see ['/tools/logfile-tool'](tbd), how-to see [documentation](https://jomjol.github.io/AI-on-the-edge-device-docs/outdated--Gasmeter-Log-Downloader/)
|
||||
* Files see ['/tools/logfile-tool'](tbd), How-to see [Docu](https://jomjol.github.io/AI-on-the-edge-device-docs/outdated--Gasmeter-Log-Downloader/)
|
||||
|
||||
## Additional Ideas
|
||||
There are some ideas and feature requests which are not currently being pursued – mainly due to capacity reasons on the part of the developers.
|
||||
They features are collected in the [issues](https://github.com/jomjol/AI-on-the-edge-device/issues) and in [FeatureRequest.md](FeatureRequest.md).
|
||||
There are some ideas and feature requests which are not followed currently - mainly due to capacity reasons on side of the developer. They are collected here: [FeatureRequest.md](FeatureRequest.md)
|
||||
|
||||
------
|
||||
|
||||
|
||||
1
code/.gitignore
vendored
@@ -1,5 +1,4 @@
|
||||
.pio
|
||||
.idea
|
||||
.vscode/.browse.c_cpp.db*
|
||||
.vscode/c_cpp_properties.json
|
||||
.vscode/launch.json
|
||||
|
||||
@@ -8,15 +8,6 @@ git checkout rolling
|
||||
git submodule update --init
|
||||
```
|
||||
|
||||
## Update Submodules
|
||||
```
|
||||
cd /components/submodule-name (e.g. tflite-micro-example)
|
||||
git checkout VERSION (e.g. HASH of latest tflite-micro-example build)
|
||||
cd ../../ (auf Ebene von code)
|
||||
git submodule update --init
|
||||
```
|
||||
Evt. muss man vorher noch einige Verzeichnisse in compenents von Hand löschen, da sie beim checkout nicht gelöscht wurden (vor update -- init)
|
||||
|
||||
## Build and Flash within terminal
|
||||
See further down to build it within an IDE.
|
||||
### Compile
|
||||
|
||||
@@ -2,6 +2,6 @@ FILE(GLOB_RECURSE app_sources ${CMAKE_CURRENT_SOURCE_DIR}/*.*)
|
||||
|
||||
idf_component_register(SRCS ${app_sources}
|
||||
INCLUDE_DIRS "." "../../include" "miniz"
|
||||
REQUIRES vfs esp_http_server app_update esp_http_client nvs_flash jomjol_tfliteclass jomjol_flowcontroll spiffs jomjol_helper jomjol_controlGPIO)
|
||||
REQUIRES vfs tflite-lib esp_http_server app_update esp_http_client nvs_flash jomjol_tfliteclass jomjol_flowcontroll spiffs jomjol_helper jomjol_controlGPIO)
|
||||
|
||||
|
||||
|
||||
@@ -588,9 +588,7 @@ static esp_err_t download_get_handler(httpd_req_t *req)
|
||||
/* Read file in chunks into the scratch buffer */
|
||||
chunksize = fread(chunk, 1, SERVER_FILER_SCRATCH_BUFSIZE, fd);
|
||||
|
||||
/* Send buffer contents as HTTP chunk. If empty this functions as a
|
||||
* last-chunk message, signaling end-of-response, to the HTTP client.
|
||||
* See RFC 2616, section 3.6.1 for details on Chunked Transfer Encoding. */
|
||||
/* Send the buffer contents as HTTP response chunk */
|
||||
if (httpd_resp_send_chunk(req, chunk, chunksize) != ESP_OK) {
|
||||
fclose(fd);
|
||||
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "File sending failed!");
|
||||
@@ -608,6 +606,8 @@ static esp_err_t download_get_handler(httpd_req_t *req)
|
||||
fclose(fd);
|
||||
ESP_LOGD(TAG, "File successfully sent");
|
||||
|
||||
/* Respond with an empty chunk to signal HTTP response completion */
|
||||
httpd_resp_send_chunk(req, NULL, 0);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
@@ -717,8 +717,7 @@ static esp_err_t upload_post_handler(httpd_req_t *req)
|
||||
|
||||
/* Close file upon upload completion */
|
||||
fclose(fd);
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "File saved: " + string(filename));
|
||||
ESP_LOGI(TAG, "File reception completed");
|
||||
ESP_LOGI(TAG, "File reception complete");
|
||||
|
||||
std::string directory = std::string(filepath);
|
||||
size_t zw = directory.find("/");
|
||||
@@ -737,27 +736,21 @@ static esp_err_t upload_post_handler(httpd_req_t *req)
|
||||
// ESP_LOGD(TAG, "Directory danach 2: %s", directory.c_str());
|
||||
|
||||
/* Redirect onto root to see the updated file list */
|
||||
if (strcmp(filename, "/config/config.ini") == 0 ||
|
||||
strcmp(filename, "/config/ref0.jpg") == 0 ||
|
||||
strcmp(filename, "/config/ref0_org.jpg") == 0 ||
|
||||
strcmp(filename, "/config/ref1.jpg") == 0 ||
|
||||
strcmp(filename, "/config/ref1_org.jpg") == 0 ||
|
||||
strcmp(filename, "/config/reference.jpg") == 0 ||
|
||||
strcmp(filename, "/img_tmp/ref0.jpg") == 0 ||
|
||||
strcmp(filename, "/img_tmp/ref0_org.jpg") == 0 ||
|
||||
strcmp(filename, "/img_tmp/ref1.jpg") == 0 ||
|
||||
strcmp(filename, "/img_tmp/ref1_org.jpg") == 0 ||
|
||||
strcmp(filename, "/img_tmp/reference.jpg") == 0 )
|
||||
{
|
||||
httpd_resp_set_status(req, HTTPD_200); // Avoid reloading of folder content
|
||||
}
|
||||
else {
|
||||
httpd_resp_set_status(req, "303 See Other"); // Reload folder content after upload
|
||||
}
|
||||
httpd_resp_set_status(req, "303 See Other");
|
||||
httpd_resp_set_hdr(req, "Location", directory.c_str());
|
||||
|
||||
/* Redirect onto root to see the updated file list */
|
||||
httpd_resp_set_status(req, "303 See Other");
|
||||
httpd_resp_set_hdr(req, "Location", directory.c_str());
|
||||
httpd_resp_sendstr(req, "File uploaded successfully");
|
||||
|
||||
/*
|
||||
if (strcmp(filepath, CONFIG_FILE) == 0) {
|
||||
ESP_LOGD(TAG, "New config found. Reload handler.");
|
||||
gpio_handler_deinit();
|
||||
MQTTdestroy();
|
||||
}
|
||||
*/
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
@@ -844,15 +837,16 @@ static esp_err_t delete_post_handler(httpd_req_t *req)
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
if (stat(filepath, &file_stat) == -1) { // File does not exist
|
||||
/* This is ok, we would delete it anyway */
|
||||
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "File does not exist: " + string(filename));
|
||||
if (stat(filepath, &file_stat) == -1) {
|
||||
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "File does not exist: " + string(filename));
|
||||
/* Respond with 400 Bad Request */
|
||||
httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "File does not exist");
|
||||
return ESP_FAIL;
|
||||
}
|
||||
|
||||
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Deleting file: " + string(filename));
|
||||
/* Delete file */
|
||||
unlink(filepath);
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "File deleted: " + string(filename));
|
||||
ESP_LOGI(TAG, "File deletion completed");
|
||||
|
||||
directory = std::string(filepath);
|
||||
size_t zw = directory.find("/");
|
||||
@@ -869,30 +863,16 @@ static esp_err_t delete_post_handler(httpd_req_t *req)
|
||||
directory = directory.substr(start_fn, found - start_fn + 1);
|
||||
directory = "/fileserver" + directory;
|
||||
ESP_LOGD(TAG, "Directory danach 4: %s", directory.c_str());
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
/* Redirect onto root to see the updated file list */
|
||||
if (strcmp(filename, "/config/config.ini") == 0 ||
|
||||
strcmp(filename, "/config/ref0.jpg") == 0 ||
|
||||
strcmp(filename, "/config/ref0_org.jpg") == 0 ||
|
||||
strcmp(filename, "/config/ref1.jpg") == 0 ||
|
||||
strcmp(filename, "/config/ref1_org.jpg") == 0 ||
|
||||
strcmp(filename, "/config/reference.jpg") == 0 ||
|
||||
strcmp(filename, "/img_tmp/ref0.jpg") == 0 ||
|
||||
strcmp(filename, "/img_tmp/ref0_org.jpg") == 0 ||
|
||||
strcmp(filename, "/img_tmp/ref1.jpg") == 0 ||
|
||||
strcmp(filename, "/img_tmp/ref1_org.jpg") == 0 ||
|
||||
strcmp(filename, "/img_tmp/reference.jpg") == 0 )
|
||||
{
|
||||
httpd_resp_set_status(req, HTTPD_200); // Avoid reloading of folder content
|
||||
}
|
||||
else {
|
||||
httpd_resp_set_status(req, "303 See Other"); // Reload folder content after upload
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////
|
||||
|
||||
/* Redirect onto root to see the updated file list */
|
||||
httpd_resp_set_status(req, "303 See Other");
|
||||
httpd_resp_set_hdr(req, "Location", directory.c_str());
|
||||
httpd_resp_sendstr(req, "File successfully deleted");
|
||||
return ESP_OK;
|
||||
@@ -949,7 +929,7 @@ std::string unzip_new(std::string _in_zip_file, std::string _target_zip, std::st
|
||||
|
||||
// Get and print information about each file in the archive.
|
||||
int numberoffiles = (int)mz_zip_reader_get_num_files(&zip_archive);
|
||||
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Files to be extracted: " + to_string(numberoffiles));
|
||||
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Numbers of files to be extracted: " + to_string(numberoffiles));
|
||||
|
||||
sort_iter = 0;
|
||||
{
|
||||
@@ -1013,7 +993,7 @@ std::string unzip_new(std::string _in_zip_file, std::string _target_zip, std::st
|
||||
|
||||
string filename_zw = zw + SUFFIX_ZW;
|
||||
|
||||
ESP_LOGI(TAG, "File to extract: %s, Temp. Filename: %s", zw.c_str(), filename_zw.c_str());
|
||||
ESP_LOGI(TAG, "Filename to extract: %s, Zwischenfilename: %s", zw.c_str(), filename_zw.c_str());
|
||||
|
||||
std::string folder = filename_zw.substr(0, filename_zw.find_last_of('/'));
|
||||
MakeDir(folder);
|
||||
@@ -1117,7 +1097,7 @@ void unzip(std::string _in_zip_file, std::string _target_directory){
|
||||
// Save to File.
|
||||
zw = std::string(archive_filename);
|
||||
zw = _target_directory + zw;
|
||||
ESP_LOGD(TAG, "File to extract: %s", zw.c_str());
|
||||
ESP_LOGD(TAG, "Filename to extract: %s", zw.c_str());
|
||||
FILE* fpTargetFile = fopen(zw.c_str(), "wb");
|
||||
fwrite(p, 1, (uint)uncomp_size, fpTargetFile);
|
||||
fclose(fpTargetFile);
|
||||
|
||||
@@ -61,13 +61,7 @@ esp_err_t send_file(httpd_req_t *req, std::string filename)
|
||||
endsWith(filename, ".jpeg") ||
|
||||
endsWith(filename, ".ico") ||
|
||||
endsWith(filename, ".png")) {
|
||||
|
||||
if (filename == "/sdcard/html/setup.html") {
|
||||
httpd_resp_set_hdr(req, "Clear-Site-Data", "\"*\"");
|
||||
}
|
||||
else {
|
||||
httpd_resp_set_hdr(req, "Cache-Control", "max-age=86400");
|
||||
}
|
||||
httpd_resp_set_hdr(req, "Cache-Control", "max-age=86400");
|
||||
}
|
||||
|
||||
set_content_type_from_file(req, filename.c_str());
|
||||
|
||||
@@ -2,6 +2,6 @@ FILE(GLOB_RECURSE app_sources ${CMAKE_CURRENT_SOURCE_DIR}/*.*)
|
||||
|
||||
idf_component_register(SRCS ${app_sources}
|
||||
INCLUDE_DIRS "."
|
||||
REQUIRES esp_timer esp_wifi jomjol_tfliteclass jomjol_helper jomjol_controlcamera jomjol_mqtt jomjol_influxdb jomjol_fileserver_ota jomjol_image_proc jomjol_wlan)
|
||||
REQUIRES esp_timer esp_wifi jomjol_tfliteclass jomjol_helper jomjol_controlcamera jomjol_mqtt jomjol_influxdb jomjol_fileserver_ota jomjol_image_proc jomjol_wlan jomjol_helper)
|
||||
|
||||
|
||||
|
||||
@@ -37,6 +37,23 @@ ClassFlowCNNGeneral::ClassFlowCNNGeneral(ClassFlowAlignment *_flowalign, t_CNNTy
|
||||
imagesRetention = 5;
|
||||
}
|
||||
|
||||
ClassFlowCNNGeneral::ClassFlowCNNGeneral(ClassFlowAlignment *_flowalign, std::string _cnn_name) : ClassFlowImage(NULL, TAG)
|
||||
{
|
||||
string cnnmodelfile = "";
|
||||
modelxsize = 1;
|
||||
modelysize = 1;
|
||||
CNNGoodThreshold = 0.0;
|
||||
ListFlowControll = NULL;
|
||||
previousElement = NULL;
|
||||
SaveAllFiles = false;
|
||||
disabled = false;
|
||||
isLogImageSelect = false;
|
||||
CNNType = AutoDetect;
|
||||
flowpostalignment = _flowalign;
|
||||
imagesRetention = 5;
|
||||
cnn_name = _cnn_name;
|
||||
}
|
||||
|
||||
|
||||
string ClassFlowCNNGeneral::getReadout(int _analog = 0, bool _extendedResolution, int prev, float _before_narrow_Analog, float analogDigitalTransitionStart)
|
||||
{
|
||||
@@ -55,7 +72,7 @@ string ClassFlowCNNGeneral::getReadout(int _analog = 0, bool _extendedResolution
|
||||
// LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "getReadout(analog) number=" + std::to_string(number) + ", result_after_decimal_point=" + std::to_string(result_after_decimal_point) + ", prev=" + std::to_string(prev));
|
||||
result = std::to_string(prev);
|
||||
|
||||
if (_extendedResolution)
|
||||
if (_extendedResolution && (CNNType != Digital))
|
||||
result = result + std::to_string(result_after_decimal_point);
|
||||
|
||||
for (int i = GENERAL[_analog]->ROI.size() - 2; i >= 0; --i)
|
||||
@@ -142,11 +159,11 @@ int ClassFlowCNNGeneral::PointerEvalHybridNew(float number, float number_of_pred
|
||||
int result_before_decimal_point = ((int) floor(number) + 10) % 10;
|
||||
|
||||
if (eval_predecessors < 0)
|
||||
{
|
||||
// on first digit is no spezial logic for transition needed
|
||||
// we use the recognition as given. The result is the int value of the recognition
|
||||
// add precisition of 2 digits and round before trunc
|
||||
result = (int) ((int) trunc(round((number+10 % 10)*100)) ) / 100;
|
||||
{
|
||||
if ((result_after_decimal_point <= Digital_Uncertainty * 10) || (result_after_decimal_point >= Digital_Uncertainty * 10)) // Band around the digit --> Rounding, as digit reaches inaccuracy in the frame
|
||||
result = (int) (round(number) + 10) % 10;
|
||||
else
|
||||
result = (int) ((int) trunc(number) + 10) % 10;
|
||||
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "PointerEvalHybridNew - No predecessor - Result = " + std::to_string(result) +
|
||||
" number: " + std::to_string(number) + " number_of_predecessors = " + std::to_string(number_of_predecessors)+ " eval_predecessors = " + std::to_string(eval_predecessors) + " Digital_Uncertainty = " + std::to_string(Digital_Uncertainty));
|
||||
@@ -485,7 +502,7 @@ bool ClassFlowCNNGeneral::doFlow(string time)
|
||||
|
||||
if (!doAlignAndCut(time)){
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "doFlow after alignment");
|
||||
|
||||
@@ -853,9 +870,10 @@ bool ClassFlowCNNGeneral::doNeuralNetwork(string time)
|
||||
|
||||
bool ClassFlowCNNGeneral::isExtendedResolution(int _number)
|
||||
{
|
||||
if (CNNType == Digital)
|
||||
return false;
|
||||
return true;
|
||||
if (!(CNNType == Digital))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@ protected:
|
||||
t_CNNType CNNType;
|
||||
std::vector<general*> GENERAL;
|
||||
float CNNGoodThreshold;
|
||||
std::string cnn_name = "ClassFlowCNNGeneral";
|
||||
|
||||
//moved to define.h
|
||||
//float Analog_error = 3.0;
|
||||
@@ -56,6 +57,7 @@ protected:
|
||||
|
||||
public:
|
||||
ClassFlowCNNGeneral(ClassFlowAlignment *_flowalign, t_CNNType _cnntype = AutoDetect);
|
||||
ClassFlowCNNGeneral(ClassFlowAlignment *_flowalign, std::string _cnn_name);
|
||||
|
||||
bool ReadParameter(FILE* pfile, string& aktparamgraph);
|
||||
bool doFlow(string time);
|
||||
@@ -81,7 +83,7 @@ public:
|
||||
|
||||
t_CNNType getCNNType(){return CNNType;};
|
||||
|
||||
string name(){return "ClassFlowCNNGeneral";};
|
||||
string name(){return "ClassFlowCNNGeneral " + cnn_name;};
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -24,6 +24,7 @@ extern "C" {
|
||||
#include "server_mqtt.h"
|
||||
#endif //ENABLE_MQTT
|
||||
|
||||
#include "websocket.h"
|
||||
#include "server_help.h"
|
||||
#include "MainFlowControl.h"
|
||||
#include "../../include/defines.h"
|
||||
@@ -85,8 +86,10 @@ std::string ClassFlowControll::TranslateAktstatus(std::string _input)
|
||||
return ("Take Image");
|
||||
if (_input.compare("ClassFlowAlignment") == 0)
|
||||
return ("Aligning");
|
||||
if (_input.compare("ClassFlowCNNGeneral") == 0)
|
||||
return ("Digitalization of ROIs");
|
||||
if (_input.compare("ClassFlowCNNGeneral Digital") == 0)
|
||||
return ("Digitalization of Digital ROIs");
|
||||
if (_input.compare("ClassFlowCNNGeneral Analog") == 0)
|
||||
return ("Digitalization of Analog ROIs");
|
||||
#ifdef ENABLE_MQTT
|
||||
if (_input.compare("ClassFlowMQTT") == 0)
|
||||
return ("Sending MQTT");
|
||||
@@ -100,7 +103,7 @@ std::string ClassFlowControll::TranslateAktstatus(std::string _input)
|
||||
if (_input.compare("ClassFlowPostProcessing") == 0)
|
||||
return ("Post-Processing");
|
||||
|
||||
return "Unkown Status";
|
||||
return "Unkown Status: " + _input +"";
|
||||
}
|
||||
|
||||
|
||||
@@ -187,6 +190,8 @@ void ClassFlowControll::SetInitialParameter(void)
|
||||
aktRunNr = 0;
|
||||
aktstatus = "Flow task not yet created";
|
||||
aktstatusWithTime = aktstatus;
|
||||
|
||||
schedule_websocket_message("{\"state\": \"" + aktstatus + "\"}");
|
||||
}
|
||||
|
||||
|
||||
@@ -220,12 +225,12 @@ ClassFlow* ClassFlowControll::CreateClassFlow(std::string _type)
|
||||
}
|
||||
if (toUpper(_type).compare("[ANALOG]") == 0)
|
||||
{
|
||||
cfc = new ClassFlowCNNGeneral(flowalignment);
|
||||
cfc = new ClassFlowCNNGeneral(flowalignment, std::string("Analog"));
|
||||
flowanalog = (ClassFlowCNNGeneral*) cfc;
|
||||
}
|
||||
if (toUpper(_type).compare(0, 7, "[DIGITS") == 0)
|
||||
{
|
||||
cfc = new ClassFlowCNNGeneral(flowalignment);
|
||||
cfc = new ClassFlowCNNGeneral(flowalignment, std::string("Digit"));
|
||||
flowdigit = (ClassFlowCNNGeneral*) cfc;
|
||||
}
|
||||
#ifdef ENABLE_MQTT
|
||||
@@ -269,6 +274,8 @@ void ClassFlowControll::InitFlow(std::string config)
|
||||
aktstatus = "Initialization";
|
||||
aktstatusWithTime = aktstatus;
|
||||
|
||||
schedule_websocket_message("{\"state\": \"" + aktstatus + "\"}");
|
||||
|
||||
//#ifdef ENABLE_MQTT
|
||||
//MQTTPublish(mqttServer_getMainTopic() + "/" + "status", "Initialization", 1, false); // Right now, not possible -> MQTT Service is going to be started later
|
||||
//#endif //ENABLE_MQTT
|
||||
@@ -331,6 +338,8 @@ void ClassFlowControll::setActStatus(std::string _aktstatus)
|
||||
{
|
||||
aktstatus = _aktstatus;
|
||||
aktstatusWithTime = aktstatus;
|
||||
|
||||
schedule_websocket_message("{\"state\": \"" + aktstatus + "\"}");
|
||||
}
|
||||
|
||||
|
||||
@@ -347,6 +356,8 @@ void ClassFlowControll::doFlowTakeImageOnly(string time)
|
||||
#ifdef ENABLE_MQTT
|
||||
MQTTPublish(mqttServer_getMainTopic() + "/" + "status", aktstatus, 1, false);
|
||||
#endif //ENABLE_MQTT
|
||||
|
||||
schedule_websocket_message("{\"state\": \"" + aktstatus + "\"}");
|
||||
|
||||
FlowControll[i]->doFlow(time);
|
||||
}
|
||||
@@ -379,6 +390,7 @@ bool ClassFlowControll::doFlow(string time)
|
||||
aktstatus = TranslateAktstatus(FlowControll[i]->name());
|
||||
aktstatusWithTime = aktstatus + " (" + zw_time + ")";
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Status: " + aktstatusWithTime);
|
||||
schedule_websocket_message("{\"state\": \"" + aktstatus + "\"}");
|
||||
#ifdef ENABLE_MQTT
|
||||
MQTTPublish(mqttServer_getMainTopic() + "/" + "status", aktstatus, qos, false);
|
||||
#endif //ENABLE_MQTT
|
||||
@@ -413,6 +425,7 @@ bool ClassFlowControll::doFlow(string time)
|
||||
aktstatus = "Flow finished";
|
||||
aktstatusWithTime = aktstatus + " (" + zw_time + ")";
|
||||
//LogFile.WriteToFile(ESP_LOG_INFO, TAG, aktstatusWithTime);
|
||||
schedule_websocket_message("{\"state\": \"" + aktstatus + "\"}");
|
||||
#ifdef ENABLE_MQTT
|
||||
MQTTPublish(mqttServer_getMainTopic() + "/" + "status", aktstatus, qos, false);
|
||||
#endif //ENABLE_MQTT
|
||||
|
||||
@@ -34,14 +34,13 @@ protected:
|
||||
|
||||
bool AutoStart;
|
||||
float AutoInterval;
|
||||
bool SetupModeActive;
|
||||
void SetInitialParameter(void);
|
||||
std::string aktstatusWithTime;
|
||||
std::string aktstatus;
|
||||
int aktRunNr;
|
||||
|
||||
public:
|
||||
bool SetupModeActive;
|
||||
|
||||
void InitFlow(std::string config);
|
||||
bool doFlow(string time);
|
||||
void doFlowTakeImageOnly(string time);
|
||||
|
||||
@@ -20,7 +20,7 @@ static const char* TAG = "INFLUXDBV2";
|
||||
void ClassFlowInfluxDBv2::SetInitialParameter(void)
|
||||
{
|
||||
uri = "";
|
||||
bucket = "";
|
||||
database = "";
|
||||
dborg = "";
|
||||
dbtoken = "";
|
||||
// dbfield = "";
|
||||
@@ -109,9 +109,9 @@ bool ClassFlowInfluxDBv2::ReadParameter(FILE* pfile, string& aktparamgraph)
|
||||
{
|
||||
handleMeasurement(splitted[0], splitted[1]);
|
||||
}
|
||||
if (((toUpper(splitted[0]) == "BUCKET")) && (splitted.size() > 1))
|
||||
if (((toUpper(splitted[0]) == "DATABASE")) && (splitted.size() > 1))
|
||||
{
|
||||
this->bucket = splitted[1];
|
||||
this->database = splitted[1];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,11 +119,11 @@ bool ClassFlowInfluxDBv2::ReadParameter(FILE* pfile, string& aktparamgraph)
|
||||
printf("org: %s\n", dborg.c_str());
|
||||
printf("token: %s\n", dbtoken.c_str());
|
||||
|
||||
if ((uri.length() > 0) && (bucket.length() > 0) && (dbtoken.length() > 0) && (dborg.length() > 0))
|
||||
if ((uri.length() > 0) && (database.length() > 0) && (dbtoken.length() > 0) && (dborg.length() > 0))
|
||||
{
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Init InfluxDB with uri: " + uri + ", org: " + dborg + ", token: *****");
|
||||
// printf("vor V2 Init\n");
|
||||
InfluxDB_V2_Init(uri, bucket, dborg, dbtoken);
|
||||
InfluxDB_V2_Init(uri, database, dborg, dbtoken);
|
||||
// printf("nach V2 Init\n");
|
||||
InfluxDBenable = true;
|
||||
} else {
|
||||
|
||||
@@ -15,7 +15,7 @@ class ClassFlowInfluxDBv2 :
|
||||
public ClassFlow
|
||||
{
|
||||
protected:
|
||||
std::string uri, bucket;
|
||||
std::string uri, database;
|
||||
std::string dborg, dbtoken, dbfield;
|
||||
std::string OldValue;
|
||||
ClassFlowPostProcessing* flowpostprocessing;
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
#include "ClassLogFile.h"
|
||||
|
||||
#include "time_sntp.h"
|
||||
#include "websocket.h"
|
||||
#include "interface_mqtt.h"
|
||||
#include "ClassFlowPostProcessing.h"
|
||||
#include "ClassFlowControll.h"
|
||||
@@ -37,9 +38,6 @@ void ClassFlowMQTT::SetInitialParameter(void)
|
||||
topicUptime = "";
|
||||
topicFreeMem = "";
|
||||
|
||||
caCertFilename = "";
|
||||
clientCertFilename = "";
|
||||
clientKeyFilename = "";
|
||||
clientname = wlan_config.hostname;
|
||||
|
||||
OldValue = "";
|
||||
@@ -105,18 +103,6 @@ bool ClassFlowMQTT::ReadParameter(FILE* pfile, string& aktparamgraph)
|
||||
while (this->getNextLine(pfile, &aktparamgraph) && !this->isNewParagraph(aktparamgraph))
|
||||
{
|
||||
splitted = ZerlegeZeile(aktparamgraph);
|
||||
if ((toUpper(splitted[0]) == "CACERT") && (splitted.size() > 1))
|
||||
{
|
||||
this->caCertFilename = splitted[1];
|
||||
}
|
||||
if ((toUpper(splitted[0]) == "CLIENTCERT") && (splitted.size() > 1))
|
||||
{
|
||||
this->clientCertFilename = splitted[1];
|
||||
}
|
||||
if ((toUpper(splitted[0]) == "CLIENTKEY") && (splitted.size() > 1))
|
||||
{
|
||||
this->clientKeyFilename = splitted[1];
|
||||
}
|
||||
if ((toUpper(splitted[0]) == "USER") && (splitted.size() > 1))
|
||||
{
|
||||
this->user = splitted[1];
|
||||
@@ -211,8 +197,7 @@ bool ClassFlowMQTT::Start(float AutoInterval)
|
||||
mqttServer_setParameter(flowpostprocessing->GetNumbers(), keepAlive, roundInterval);
|
||||
|
||||
bool MQTTConfigCheck = MQTT_Configure(uri, clientname, user, password, maintopic, LWT_TOPIC, LWT_CONNECTED,
|
||||
LWT_DISCONNECTED, caCertFilename, clientCertFilename, clientKeyFilename,
|
||||
keepAlive, SetRetainFlag, (void *)&GotConnected);
|
||||
LWT_DISCONNECTED, keepAlive, SetRetainFlag, (void *)&GotConnected);
|
||||
|
||||
if (!MQTTConfigCheck) {
|
||||
return false;
|
||||
@@ -265,11 +250,15 @@ bool ClassFlowMQTT::doFlow(string zwtime)
|
||||
namenumber = maintopic + "/" + namenumber + "/";
|
||||
|
||||
|
||||
if (result.length() > 0)
|
||||
if (result.length() > 0) {
|
||||
success |= MQTTPublish(namenumber + "value", result, qos, SetRetainFlag);
|
||||
schedule_websocket_message("{\"value\": \"" + result + "\", \"number\": \"" + (*NUMBERS)[i]->name + "\"}");
|
||||
}
|
||||
|
||||
if (resulterror.length() > 0)
|
||||
if (resulterror.length() > 0) {
|
||||
success |= MQTTPublish(namenumber + "error", resulterror, qos, SetRetainFlag);
|
||||
schedule_websocket_message("{\"error\": \"" + resulterror + "\", \"number\": \"" + (*NUMBERS)[i]->name + "\"}");
|
||||
}
|
||||
|
||||
if (resultrate.length() > 0) {
|
||||
success |= MQTTPublish(namenumber + "rate", resultrate, qos, SetRetainFlag);
|
||||
@@ -289,8 +278,10 @@ bool ClassFlowMQTT::doFlow(string zwtime)
|
||||
success |= MQTTPublish(namenumber + "rate_per_digitalization_round", resultchangabs, qos, SetRetainFlag);
|
||||
}
|
||||
|
||||
if (resultraw.length() > 0)
|
||||
if (resultraw.length() > 0) {
|
||||
success |= MQTTPublish(namenumber + "raw", resultraw, qos, SetRetainFlag);
|
||||
schedule_websocket_message("{\"raw\": \"" + resultraw + "\", \"number\": \"" + (*NUMBERS)[i]->name + "\"}");
|
||||
}
|
||||
|
||||
if (resulttimestamp.length() > 0)
|
||||
success |= MQTTPublish(namenumber + "timestamp", resulttimestamp, qos, SetRetainFlag);
|
||||
|
||||
@@ -19,7 +19,6 @@ protected:
|
||||
std::string OldValue;
|
||||
ClassFlowPostProcessing* flowpostprocessing;
|
||||
std::string user, password;
|
||||
std::string caCertFilename, clientCertFilename, clientKeyFilename;
|
||||
bool SetRetainFlag;
|
||||
int keepAlive; // Seconds
|
||||
float roundInterval; // Minutes
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
|
||||
#include <time.h>
|
||||
|
||||
#include "websocket.h"
|
||||
#include "time_sntp.h"
|
||||
|
||||
#include "esp_log.h"
|
||||
@@ -866,12 +867,12 @@ bool ClassFlowPostProcessing::doFlow(string zwtime)
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "handleAllowNegativeRate for device: " + NUMBERS[j]->name);
|
||||
if ((NUMBERS[j]->Value < NUMBERS[j]->PreValue))
|
||||
{
|
||||
// more debug if extended resolution is on, see #2447
|
||||
if (NUMBERS[j]->isExtendedResolution) {
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Neg: value=" + std::to_string(NUMBERS[j]->Value)
|
||||
+ ", preValue=" + std::to_string(NUMBERS[j]->PreValue)
|
||||
+ ", preToll=" + std::to_string(NUMBERS[j]->PreValue-(2/pow(10, NUMBERS[j]->Nachkomma))));
|
||||
}
|
||||
#ifdef SERIAL_DEBUG
|
||||
ESP_LOGD(TAG, "Neg: value=%f, preValue=%f, preToll%f", NUMBERS[j]->Value, NUMBERS[j]->PreValue,
|
||||
NUMBERS[j]->PreValue-(2/pow(10, NUMBERS[j]->Nachkomma))
|
||||
) ;
|
||||
#endif
|
||||
|
||||
// Include inaccuracy of 0.2 for isExtendedResolution.
|
||||
if (NUMBERS[j]->Value >= (NUMBERS[j]->PreValue-(2/pow(10, NUMBERS[j]->Nachkomma))) && NUMBERS[j]->isExtendedResolution) {
|
||||
NUMBERS[j]->Value = NUMBERS[j]->PreValue;
|
||||
@@ -882,6 +883,8 @@ bool ClassFlowPostProcessing::doFlow(string zwtime)
|
||||
NUMBERS[j]->ReturnValue = "";
|
||||
NUMBERS[j]->lastvalue = imagetime;
|
||||
|
||||
schedule_websocket_message("{\"status\": \"" + NUMBERS[j]->ErrorMessageText + "\", \"number\": \"" + NUMBERS[j]->name + "\"}");
|
||||
|
||||
string _zw = NUMBERS[j]->name + ": Raw: " + NUMBERS[j]->ReturnRawValue + ", Value: " + NUMBERS[j]->ReturnValue + ", Status: " + NUMBERS[j]->ErrorMessageText;
|
||||
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, _zw);
|
||||
WriteDataLog(j);
|
||||
@@ -915,6 +918,8 @@ bool ClassFlowPostProcessing::doFlow(string zwtime)
|
||||
NUMBERS[j]->ReturnRateValue = "";
|
||||
NUMBERS[j]->lastvalue = imagetime;
|
||||
|
||||
schedule_websocket_message("{\"status\": \"" + NUMBERS[j]->ErrorMessageText + "\", \"number\": \"" + NUMBERS[j]->name + "\"}");
|
||||
|
||||
string _zw = NUMBERS[j]->name + ": Raw: " + NUMBERS[j]->ReturnRawValue + ", Value: " + NUMBERS[j]->ReturnValue + ", Status: " + NUMBERS[j]->ErrorMessageText;
|
||||
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, _zw);
|
||||
WriteDataLog(j);
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "Helper.h"
|
||||
#include "statusled.h"
|
||||
|
||||
#include "websocket.h"
|
||||
#include "esp_camera.h"
|
||||
#include "time_sntp.h"
|
||||
#include "ClassControllCamera.h"
|
||||
@@ -230,7 +231,7 @@ esp_err_t handler_stream(httpd_req_t *req)
|
||||
if (httpd_query_key_value(_query, "flashlight", _value, 10) == ESP_OK)
|
||||
{
|
||||
#ifdef DEBUG_DETAIL_ON
|
||||
ESP_LOGD(TAG, "flashlight is found%s", _value);
|
||||
ESP_LOGD(TAG, "flashlight is found%s", _size);
|
||||
#endif
|
||||
if (strlen(_value) > 0)
|
||||
flashlightOn = true;
|
||||
@@ -453,7 +454,7 @@ esp_err_t handler_wasserzaehler(httpd_req_t *req)
|
||||
else {
|
||||
/* Digital ROIs */
|
||||
txt = "<body style=\"font-family: arial\">";
|
||||
txt += "<hr><h3>Recognized Digit ROIs (previous round)</h3>\n";
|
||||
txt += "<h3>Recognized Digit ROIs (previous round)</h3>\n";
|
||||
txt += "<table style=\"border-spacing: 5px\"><tr style=\"text-align: center; vertical-align: top;\">\n";
|
||||
|
||||
std::vector<HTMLInfo*> htmlinfodig;
|
||||
@@ -488,7 +489,7 @@ esp_err_t handler_wasserzaehler(httpd_req_t *req)
|
||||
|
||||
|
||||
/* Analog ROIs */
|
||||
txt = "<hr><h3>Recognized Analog ROIs (previous round)</h3>\n";
|
||||
txt = "<h3>Recognized Analog ROIs (previous round)</h3>\n";
|
||||
txt += "<table style=\"border-spacing: 5px\"><tr style=\"text-align: center; vertical-align: top;\">\n";
|
||||
|
||||
std::vector<HTMLInfo*> htmlinfoana;
|
||||
@@ -510,7 +511,7 @@ esp_err_t handler_wasserzaehler(httpd_req_t *req)
|
||||
|
||||
/* Full Image
|
||||
* Only show it after the image got taken and aligned */
|
||||
txt = "<hr><h3>Aligned Image (current round)</h3>\n";
|
||||
txt = "<h3>Aligned Image (current round)</h3>\n";
|
||||
if ((*status == std::string("Initialization")) ||
|
||||
(*status == std::string("Initialization (delayed)")) ||
|
||||
(*status == std::string("Take Image"))) {
|
||||
@@ -657,7 +658,14 @@ esp_err_t handler_editflow(httpd_req_t *req)
|
||||
|
||||
string out2 = out.substr(0, out.length() - 4) + "_org.jpg";
|
||||
|
||||
if ((flowctrl.SetupModeActive || (*flowctrl.getActStatus() == "Flow finished")) && psram_init_shared_memory_for_take_image_step()) {
|
||||
std::string state = *flowctrl.getActStatus();
|
||||
|
||||
/* To be able to provide the image, several conditions must be met due to the shared PSRAM usage:
|
||||
- Ether the round most be completed or not started yet
|
||||
- Or we must be in Setup Mode
|
||||
- Additionally, the initialization of the shared PSRAM must be successful */
|
||||
if (((state == "Flow finished") || (state == "Initialization") || (state == "Initialization (delayed)") || isSetupModusActive()) &&
|
||||
psram_init_shared_memory_for_take_image_step()) {
|
||||
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Taking image for Alignment Mark Update...");
|
||||
|
||||
CAlignAndCutImage *caic = new CAlignAndCutImage("cutref", in);
|
||||
@@ -680,7 +688,7 @@ esp_err_t handler_editflow(httpd_req_t *req)
|
||||
}
|
||||
else {
|
||||
LogFile.WriteToFile(ESP_LOG_WARN, TAG, std::string("Taking image for Alignment Mark not possible while device") +
|
||||
" is busy with a round (Current State: '" + *flowctrl.getActStatus() + "')!");
|
||||
" is busy with a round (Current State: '" + state + "')!");
|
||||
zw = "Device Busy";
|
||||
}
|
||||
|
||||
@@ -890,7 +898,7 @@ esp_err_t handler_prevalue(httpd_req_t *req)
|
||||
|
||||
if (httpd_query_key_value(_query, "value", _value, 20) == ESP_OK) {
|
||||
#ifdef DEBUG_DETAIL_ON
|
||||
ESP_LOGD(TAG, "Value: %s", _value);
|
||||
ESP_LOGD(TAG, "Value: %s", _size);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
@@ -978,6 +986,10 @@ void task_autodoFlow(void *pvParameter)
|
||||
{
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "----------------------------------------------------------------"); // Clear separation between runs
|
||||
std::string _zw = "Round #" + std::to_string(++countRounds) + " started";
|
||||
|
||||
schedule_websocket_message("{\"round\": \"" + std::to_string(countRounds) + "\"}");
|
||||
schedule_websocket_message("{\"uptime\": \"" + std::to_string(getUpTime()) + "\"}");
|
||||
|
||||
time_t roundStartTime = getUpTime();
|
||||
LogFile.WriteToFile(ESP_LOG_INFO, TAG, _zw);
|
||||
fr_start = esp_timer_get_time();
|
||||
@@ -1005,12 +1017,15 @@ void task_autodoFlow(void *pvParameter)
|
||||
// Round finished -> Logfile
|
||||
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Round #" + std::to_string(countRounds) +
|
||||
" completed (" + std::to_string(getUpTime() - roundStartTime) + " seconds)");
|
||||
schedule_websocket_message("{\"round duration\": \"" + std::to_string(getUpTime() - roundStartTime) + "\"}");
|
||||
|
||||
// CPU Temp -> Logfile
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "CPU Temperature: " + std::to_string((int)temperatureRead()) + "°C");
|
||||
schedule_websocket_message("{\"cpu temperature\": \"" + std::to_string(temperatureRead()) + "\"}");
|
||||
|
||||
// WIFI Signal Strength (RSSI) -> Logfile
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "WIFI Signal (RSSI): " + std::to_string(get_WIFI_RSSI()) + "dBm");
|
||||
schedule_websocket_message("{\"wifi rssi\": \"" + std::to_string(get_WIFI_RSSI()) + "\"}");
|
||||
|
||||
// Check if time is synchronized (if NTP is configured)
|
||||
if (getUseNtp() && !getTimeIsSet()) {
|
||||
|
||||
@@ -2,6 +2,6 @@ FILE(GLOB_RECURSE app_sources ${CMAKE_CURRENT_SOURCE_DIR}/*.*)
|
||||
|
||||
idf_component_register(SRCS ${app_sources}
|
||||
INCLUDE_DIRS "."
|
||||
REQUIRES esp_timer tflite-lib jomjol_logfile fatfs sdmmc)
|
||||
REQUIRES esp_timer tflite-lib jomjol_logfile fatfs sdmmc esp_http_server)
|
||||
|
||||
|
||||
|
||||
129
code/components/jomjol_helper/websocket.cpp
Normal file
@@ -0,0 +1,129 @@
|
||||
#include "esp_log.h"
|
||||
#include <esp_http_server.h>
|
||||
|
||||
#include "../../include/defines.h"
|
||||
|
||||
#include "ClassLogFile.h"
|
||||
#include "freertos/ringbuf.h"
|
||||
#include "psram.h"
|
||||
|
||||
#include "websocket.h"
|
||||
|
||||
|
||||
#define MAX_MESSAGE_LENGTH 100
|
||||
|
||||
static const char *TAG = "WEBSOCKET";
|
||||
|
||||
static httpd_handle_t server = NULL;
|
||||
static httpd_handle_t websocket_handle = NULL;
|
||||
|
||||
/*
|
||||
* Structure holding server handle and message
|
||||
* in order to use out of request send */
|
||||
struct async_resp_arg {
|
||||
httpd_handle_t hd;
|
||||
char message[MAX_MESSAGE_LENGTH];
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
* async send function, which we put into the httpd work queue
|
||||
*/
|
||||
static void websocket_send_pending_message(void *arg) {
|
||||
esp_err_t ret;
|
||||
struct async_resp_arg *resp_arg = (struct async_resp_arg *)arg;
|
||||
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Sending Websocket message: '" + std::string(resp_arg->message) + "'");
|
||||
|
||||
httpd_ws_frame_t ws_pkt;
|
||||
memset(&ws_pkt, 0, sizeof(httpd_ws_frame_t));
|
||||
ws_pkt.payload = (uint8_t *)resp_arg->message;
|
||||
ws_pkt.len = strlen(resp_arg->message);
|
||||
ws_pkt.type = HTTPD_WS_TYPE_TEXT;
|
||||
|
||||
static size_t max_clients = CONFIG_LWIP_MAX_LISTENING_TCP;
|
||||
size_t fds = max_clients;
|
||||
int client_fds[max_clients];
|
||||
|
||||
ret = httpd_get_client_list(server, &fds, client_fds);
|
||||
if (ret != ESP_OK) {
|
||||
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Failed to get Websocket client ist: " + std::to_string(ret) + "!");
|
||||
free_psram_heap("websocket msg", resp_arg);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Send it to all websocket clients */
|
||||
for (int i = 0; i < fds; i++) {
|
||||
int client_info = httpd_ws_get_fd_info(server, client_fds[i]);
|
||||
if (client_info == HTTPD_WS_CLIENT_WEBSOCKET) {
|
||||
httpd_ws_send_frame_async(websocket_handle, client_fds[i], &ws_pkt);
|
||||
}
|
||||
}
|
||||
|
||||
free_psram_heap("websocket msg", resp_arg);
|
||||
}
|
||||
|
||||
|
||||
esp_err_t schedule_websocket_message(std::string message) {
|
||||
// return 0;
|
||||
esp_err_t ret;
|
||||
|
||||
if (websocket_handle == NULL) { // No websocket connecten open
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Scheduled websocket message: '" + message + "'");
|
||||
|
||||
struct async_resp_arg *resp_arg = (struct async_resp_arg *)malloc_psram_heap("websocket msg",
|
||||
sizeof(struct async_resp_arg), MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
|
||||
if (resp_arg == NULL) {
|
||||
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Failed to malloc memory for scheduled websocket message!");
|
||||
return ESP_ERR_NO_MEM;
|
||||
}
|
||||
|
||||
strncpy(resp_arg->message, message.c_str(), MAX_MESSAGE_LENGTH);
|
||||
|
||||
ret = httpd_queue_work(websocket_handle, websocket_send_pending_message, resp_arg);
|
||||
if (ret != ESP_OK) {
|
||||
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Websocket Scheduling failed: " + std::to_string(ret) + "!");
|
||||
free_psram_heap("websocket msg", resp_arg);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static esp_err_t ws_handler(httpd_req_t *req) {
|
||||
if (req->method == HTTP_GET) {
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Handshake done, the new websocket connection was opened");
|
||||
websocket_handle = req->handle;
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
|
||||
static const httpd_uri_t ws_uri = {
|
||||
.uri = "/ws",
|
||||
.method = HTTP_GET,
|
||||
.handler = ws_handler,
|
||||
.user_ctx = NULL,
|
||||
.is_websocket = true
|
||||
};
|
||||
|
||||
|
||||
esp_err_t start_websocket_server(httpd_handle_t _server) {
|
||||
esp_err_t ret;
|
||||
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Init Websocket Server");
|
||||
|
||||
server = _server;
|
||||
|
||||
// Registering the ws handler
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Registering URI handler");
|
||||
ret = httpd_register_uri_handler(server, &ws_uri);
|
||||
if (ret != ESP_OK) {
|
||||
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Registering Websocket URI handler failed: " + std::to_string(ret));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
10
code/components/jomjol_helper/websocket.h
Normal file
@@ -0,0 +1,10 @@
|
||||
#ifndef WEBSOCKET_H
|
||||
#define WEBSOCKET_H
|
||||
|
||||
#include <esp_http_server.h>
|
||||
|
||||
esp_err_t start_websocket_server(httpd_handle_t server);
|
||||
|
||||
esp_err_t schedule_websocket_message(std::string message);
|
||||
|
||||
#endif // WEBSOCKET_H
|
||||
@@ -2,6 +2,6 @@ FILE(GLOB_RECURSE app_sources ${CMAKE_CURRENT_SOURCE_DIR}/*.*)
|
||||
|
||||
idf_component_register(SRCS ${app_sources}
|
||||
INCLUDE_DIRS "."
|
||||
REQUIRES esp_http_client jomjol_logfile)
|
||||
REQUIRES tflite-lib esp_http_client jomjol_logfile)
|
||||
|
||||
|
||||
|
||||
@@ -16,16 +16,16 @@ std::string _influxDBUser;
|
||||
std::string _influxDBPassword;
|
||||
|
||||
std::string _influxDB_V2_URI;
|
||||
std::string _influxDB_V2_Bucket;
|
||||
std::string _influxDB_V2_Database;
|
||||
std::string _influxDB_V2_Token;
|
||||
std::string _influxDB_V2_Org;
|
||||
|
||||
static esp_err_t http_event_handler(esp_http_client_event_t *evt);
|
||||
|
||||
void InfluxDB_V2_Init(std::string _uri, std::string _bucket, std::string _org, std::string _token)
|
||||
void InfluxDB_V2_Init(std::string _uri, std::string _database, std::string _org, std::string _token)
|
||||
{
|
||||
_influxDB_V2_URI = _uri;
|
||||
_influxDB_V2_Bucket = _bucket;
|
||||
_influxDB_V2_Database = _database;
|
||||
_influxDB_V2_Org = _org;
|
||||
_influxDB_V2_Token = _token;
|
||||
}
|
||||
@@ -49,16 +49,20 @@ void InfluxDB_V2_Publish(std::string _measurement, std::string _key, std::string
|
||||
if (_timestamp.length() > 0)
|
||||
{
|
||||
struct tm tm;
|
||||
|
||||
time_t t;
|
||||
time(&t);
|
||||
localtime_r(&t, &tm); // Extract DST setting from actual time to consider it for timestamp evaluation
|
||||
|
||||
strptime(_timestamp.c_str(), PREVALUE_TIME_FORMAT_OUTPUT, &tm);
|
||||
t = mktime(&tm);
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Timestamp: " + _timestamp + ", Timestamp (UTC): " + std::to_string(t));
|
||||
time_t t = mktime(&tm); // Time in Localtime (looks like timezone is not used by strptime)
|
||||
|
||||
// struct tm * ptm;
|
||||
// ptm = gmtime ( &t );
|
||||
// time_t utc = mktime(ptm);
|
||||
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Use handover timestamp: " + _timestamp + " converted GMT timestamp: " + std::to_string(t));
|
||||
|
||||
// utc = 2*t - utc; // Take care of timezone (looks difficult, but is easy: t = t + (t - utc), weil t-utc = timezone)
|
||||
// LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "time conversion utc after: " + std::to_string(utc));
|
||||
|
||||
sprintf(nowTimestamp,"%ld000000000", (long) t); // UTC
|
||||
|
||||
payload = _measurement + " " + _key + "=" + _content + " " + nowTimestamp;
|
||||
}
|
||||
else
|
||||
@@ -70,7 +74,7 @@ void InfluxDB_V2_Publish(std::string _measurement, std::string _key, std::string
|
||||
|
||||
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "sending line to influxdb:" + payload);
|
||||
|
||||
std::string apiURI = _influxDB_V2_URI + "/api/v2/write?org=" + _influxDB_V2_Org + "&bucket=" + _influxDB_V2_Bucket;
|
||||
std::string apiURI = _influxDB_V2_URI + "/api/v2/write?org=" + _influxDB_V2_Org + "&bucket=" + _influxDB_V2_Database;
|
||||
apiURI.shrink_to_fit();
|
||||
http_config.url = apiURI.c_str();
|
||||
ESP_LOGI(TAG, "http_config: %s", http_config.url); // Add mark on log to see when it restarted
|
||||
@@ -112,7 +116,7 @@ static esp_err_t http_event_handler(esp_http_client_event_t *evt)
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "HTTP Client Error encountered");
|
||||
break;
|
||||
case HTTP_EVENT_ON_CONNECTED:
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "HTTP Client connected");
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "HTTP Client Error encountered");
|
||||
ESP_LOGI(TAG, "HTTP Client Connected");
|
||||
break;
|
||||
case HTTP_EVENT_HEADERS_SENT:
|
||||
@@ -161,16 +165,20 @@ void InfluxDBPublish(std::string _measurement, std::string _key, std::string _co
|
||||
if (_timestamp.length() > 0)
|
||||
{
|
||||
struct tm tm;
|
||||
|
||||
time_t t;
|
||||
time(&t);
|
||||
localtime_r(&t, &tm); // Extract DST setting from actual time to consider it for timestamp evaluation
|
||||
|
||||
strptime(_timestamp.c_str(), PREVALUE_TIME_FORMAT_OUTPUT, &tm);
|
||||
t = mktime(&tm);
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Timestamp: " + _timestamp + ", Timestamp (UTC): " + std::to_string(t));
|
||||
time_t t = mktime(&tm); // Time in Localtime (looks like timezone is not used by strptime)
|
||||
|
||||
// struct tm * ptm;
|
||||
// ptm = gmtime ( &t );
|
||||
// time_t utc = mktime(ptm);
|
||||
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Use handover timestamp: " + _timestamp + " converted GMT timestamp: " + std::to_string(t));
|
||||
|
||||
// utc = 2*t - utc; // Take care of timezone (looks difficult, but is easy: t = t + (t - utc), weil t-utc = timezone)
|
||||
// LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "time conversion utc after: " + std::to_string(utc));
|
||||
|
||||
sprintf(nowTimestamp,"%ld000000000", (long) t); // UTC
|
||||
|
||||
payload = _measurement + " " + _key + "=" + _content + " " + nowTimestamp;
|
||||
}
|
||||
else
|
||||
@@ -183,7 +191,7 @@ void InfluxDBPublish(std::string _measurement, std::string _key, std::string _co
|
||||
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "sending line to influxdb:" + payload);
|
||||
|
||||
|
||||
// use the default retention policy of the bucket
|
||||
// use the default retention policy of the database
|
||||
std::string apiURI = _influxDBURI + "/write?db=" + _influxDBDatabase;
|
||||
// std::string apiURI = _influxDBURI + "/api/v2/write?bucket=" + _influxDBDatabase + "/";
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ void InfluxDBInit(std::string _influxDBURI, std::string _database, std::string _
|
||||
void InfluxDBPublish(std::string _measurement, std::string _key, std::string _content, std::string _timestamp);
|
||||
|
||||
// Interface to InfluxDB v2.x
|
||||
void InfluxDB_V2_Init(std::string _uri, std::string _bucket, std::string _org, std::string _token);
|
||||
void InfluxDB_V2_Init(std::string _uri, std::string _database, std::string _org, std::string _token);
|
||||
void InfluxDB_V2_Publish(std::string _measurement, std::string _key, std::string _content, std::string _timestamp);
|
||||
|
||||
|
||||
|
||||
@@ -2,9 +2,6 @@
|
||||
#include "interface_mqtt.h"
|
||||
|
||||
#include "esp_log.h"
|
||||
#if DEBUG_DETAIL_ON
|
||||
#include "esp_timer.h"
|
||||
#endif
|
||||
#include "connect_wlan.h"
|
||||
#include "mqtt_client.h"
|
||||
#include "ClassLogFile.h"
|
||||
@@ -12,11 +9,6 @@
|
||||
#include "cJSON.h"
|
||||
#include "../../include/defines.h"
|
||||
|
||||
#if DEBUG_DETAIL_ON
|
||||
#include "esp_timer.h"
|
||||
#endif
|
||||
|
||||
|
||||
static const char *TAG = "MQTT IF";
|
||||
|
||||
std::map<std::string, std::function<void()>>* connectFunktionMap = NULL;
|
||||
@@ -35,7 +27,6 @@ bool mqtt_connected = false;
|
||||
|
||||
esp_mqtt_client_handle_t client = NULL;
|
||||
std::string uri, client_id, lwt_topic, lwt_connected, lwt_disconnected, user, password, maintopic;
|
||||
std::string caCert, clientCert, clientKey;
|
||||
int keepalive;
|
||||
bool SetRetainFlag;
|
||||
void (*callbackOnConnected)(std::string, bool) = NULL;
|
||||
@@ -173,10 +164,6 @@ static esp_err_t mqtt_event_handler_cb(esp_mqtt_event_handle_t event) {
|
||||
else if (event->error_handle->connect_return_code == MQTT_CONNECTION_REFUSE_NOT_AUTHORIZED) {
|
||||
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Connection refused, not authorized. Check username/password (0x05)");
|
||||
}
|
||||
else {
|
||||
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Other event id:" + event->error_handle->connect_return_code);
|
||||
ESP_LOGE(TAG, "Other event id:%d", event->error_handle->connect_return_code);
|
||||
}
|
||||
|
||||
#ifdef DEBUG_DETAIL_ON
|
||||
ESP_LOGD(TAG, "MQTT_EVENT_ERROR - esp_mqtt_error_codes:");
|
||||
@@ -206,7 +193,6 @@ static void mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_
|
||||
|
||||
bool MQTT_Configure(std::string _mqttURI, std::string _clientid, std::string _user, std::string _password,
|
||||
std::string _maintopic, std::string _lwt, std::string _lwt_connected, std::string _lwt_disconnected,
|
||||
std::string _cacertfilename, std::string _clientcertfilename, std::string _clientkeyfilename,
|
||||
int _keepalive, bool _SetRetainFlag, void *_callbackOnConnected) {
|
||||
if ((_mqttURI.length() == 0) || (_maintopic.length() == 0) || (_clientid.length() == 0))
|
||||
{
|
||||
@@ -224,25 +210,6 @@ bool MQTT_Configure(std::string _mqttURI, std::string _clientid, std::string _us
|
||||
maintopic = _maintopic;
|
||||
callbackOnConnected = ( void (*)(std::string, bool) )(_callbackOnConnected);
|
||||
|
||||
if (_clientcertfilename.length() && _clientkeyfilename.length()){
|
||||
std::ifstream cert_ifs(_clientcertfilename);
|
||||
std::string cert_content((std::istreambuf_iterator<char>(cert_ifs)), (std::istreambuf_iterator<char>()));
|
||||
clientCert = cert_content;
|
||||
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "using clientCert: " + _clientcertfilename);
|
||||
|
||||
std::ifstream key_ifs(_clientkeyfilename);
|
||||
std::string key_content((std::istreambuf_iterator<char>(key_ifs)), (std::istreambuf_iterator<char>()));
|
||||
clientKey = key_content;
|
||||
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "using clientKey: " + _clientkeyfilename);
|
||||
}
|
||||
|
||||
if (_cacertfilename.length() ){
|
||||
std::ifstream ifs(_cacertfilename);
|
||||
std::string content((std::istreambuf_iterator<char>(ifs)), (std::istreambuf_iterator<char>()));
|
||||
caCert = content;
|
||||
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "using caCert: " + _cacertfilename);
|
||||
}
|
||||
|
||||
if (_user.length() && _password.length()){
|
||||
user = _user;
|
||||
password = _password;
|
||||
@@ -296,20 +263,6 @@ int MQTT_Init() {
|
||||
mqtt_cfg.session.keepalive = keepalive;
|
||||
mqtt_cfg.buffer.size = 1536; // size of MQTT send/receive buffer (Default: 1024)
|
||||
|
||||
if (caCert.length()){
|
||||
mqtt_cfg.broker.verification.certificate = caCert.c_str();
|
||||
mqtt_cfg.broker.verification.certificate_len = caCert.length() + 1;
|
||||
mqtt_cfg.broker.verification.skip_cert_common_name_check = true;
|
||||
}
|
||||
|
||||
if (clientCert.length() && clientKey.length()){
|
||||
mqtt_cfg.credentials.authentication.certificate = clientCert.c_str();
|
||||
mqtt_cfg.credentials.authentication.certificate_len = clientCert.length() + 1;
|
||||
|
||||
mqtt_cfg.credentials.authentication.key = clientKey.c_str();
|
||||
mqtt_cfg.credentials.authentication.key_len = clientKey.length() + 1;
|
||||
}
|
||||
|
||||
if (user.length() && password.length()){
|
||||
mqtt_cfg.credentials.username = user.c_str();
|
||||
mqtt_cfg.credentials.authentication.password = password.c_str();
|
||||
@@ -413,10 +366,8 @@ bool mqtt_handler_set_prevalue(std::string _topic, char* _data, int _data_len)
|
||||
if (cJSON_IsNumber(value)) { // Check if value is a number
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "handler_set_prevalue called: numbersname: " + std::string(numbersname->valuestring) +
|
||||
", value: " + std::to_string(value->valuedouble));
|
||||
if (flowctrl.UpdatePrevalue(std::to_string(value->valuedouble), std::string(numbersname->valuestring), true)) {
|
||||
cJSON_Delete(jsonData);
|
||||
if (flowctrl.UpdatePrevalue(std::to_string(value->valuedouble), std::string(numbersname->valuestring), true))
|
||||
return ESP_OK;
|
||||
}
|
||||
}
|
||||
else {
|
||||
LogFile.WriteToFile(ESP_LOG_WARN, TAG, "handler_set_prevalue: value not a valid number (\"value\": 12345.12345)");
|
||||
@@ -425,7 +376,6 @@ bool mqtt_handler_set_prevalue(std::string _topic, char* _data, int _data_len)
|
||||
else {
|
||||
LogFile.WriteToFile(ESP_LOG_WARN, TAG, "handler_set_prevalue: numbersname not a valid string (\"numbersname\": \"main\")");
|
||||
}
|
||||
cJSON_Delete(jsonData);
|
||||
}
|
||||
else {
|
||||
LogFile.WriteToFile(ESP_LOG_WARN, TAG, "handler_set_prevalue: handler called, but no data received");
|
||||
|
||||
@@ -11,7 +11,6 @@
|
||||
|
||||
bool MQTT_Configure(std::string _mqttURI, std::string _clientid, std::string _user, std::string _password,
|
||||
std::string _maintopic, std::string _lwt, std::string _lwt_connected, std::string _lwt_disconnected,
|
||||
std::string _cacertfilename, std::string _clientcertfilename, std::string _clientkeyfilename,
|
||||
int _keepalive, bool SetRetainFlag, void *callbackOnConnected);
|
||||
int MQTT_Init();
|
||||
void MQTTdestroy_client(bool _disable);
|
||||
|
||||
@@ -12,31 +12,6 @@
|
||||
|
||||
static const char *TAG = "TFLITE";
|
||||
|
||||
/// Static Resolver muss mit allen Operatoren geladen Werden, die benöägit werden - ABER nur 1x --> gesonderte Funktion /////////////////////////////
|
||||
static bool MakeStaticResolverDone = false;
|
||||
static tflite::MicroMutableOpResolver<15> resolver;
|
||||
|
||||
void MakeStaticResolver()
|
||||
{
|
||||
if (MakeStaticResolverDone)
|
||||
return;
|
||||
|
||||
MakeStaticResolverDone = true;
|
||||
|
||||
resolver.AddFullyConnected();
|
||||
resolver.AddReshape();
|
||||
resolver.AddSoftmax();
|
||||
resolver.AddConv2D();
|
||||
resolver.AddMaxPool2D();
|
||||
resolver.AddQuantize();
|
||||
resolver.AddMul();
|
||||
resolver.AddAdd();
|
||||
resolver.AddLeakyRelu();
|
||||
resolver.AddDequantize();
|
||||
}
|
||||
////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
float CTfLiteClass::GetOutputValue(int nr)
|
||||
{
|
||||
TfLiteTensor* output2 = this->interpreter->output(0);
|
||||
@@ -204,20 +179,16 @@ bool CTfLiteClass::LoadInputImageBasis(CImageBasis *rs)
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool CTfLiteClass::MakeAllocate()
|
||||
{
|
||||
|
||||
MakeStaticResolver();
|
||||
|
||||
static tflite::AllOpsResolver resolver;
|
||||
|
||||
#ifdef DEBUG_DETAIL_ON
|
||||
LogFile.WriteHeapInfo("CTLiteClass::Alloc start");
|
||||
#endif
|
||||
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "CTfLiteClass::MakeAllocate");
|
||||
this->interpreter = new tflite::MicroInterpreter(this->model, resolver, this->tensor_arena, this->kTensorArenaSize);
|
||||
// this->interpreter = new tflite::MicroInterpreter(this->model, resolver, this->tensor_arena, this->kTensorArenaSize, this->error_reporter);
|
||||
this->interpreter = new tflite::MicroInterpreter(this->model, resolver, this->tensor_arena, this->kTensorArenaSize, this->error_reporter);
|
||||
|
||||
if (this->interpreter)
|
||||
{
|
||||
@@ -314,7 +285,6 @@ bool CTfLiteClass::ReadFileToModel(std::string _fn)
|
||||
bool CTfLiteClass::LoadModel(std::string _fn)
|
||||
{
|
||||
#ifdef SUPRESS_TFLITE_ERRORS
|
||||
// this->error_reporter = new tflite::ErrorReporter;
|
||||
this->error_reporter = new tflite::OwnMicroErrorReporter;
|
||||
#else
|
||||
this->error_reporter = new tflite::MicroErrorReporter;
|
||||
@@ -350,21 +320,16 @@ CTfLiteClass::CTfLiteClass()
|
||||
CTfLiteClass::~CTfLiteClass()
|
||||
{
|
||||
delete this->interpreter;
|
||||
// delete this->error_reporter;
|
||||
delete this->error_reporter;
|
||||
|
||||
psram_free_shared_tensor_arena_and_model_memory();
|
||||
}
|
||||
|
||||
#ifdef SUPRESS_TFLITE_ERRORS
|
||||
|
||||
namespace tflite
|
||||
{
|
||||
//tflite::ErrorReporter
|
||||
// int OwnMicroErrorReporter::Report(const char* format, va_list args)
|
||||
|
||||
int OwnMicroErrorReporter::Report(const char* format, va_list args)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
@@ -3,12 +3,8 @@
|
||||
#ifndef CTFLITECLASS_H
|
||||
#define CTFLITECLASS_H
|
||||
|
||||
#include "tensorflow/lite/micro/micro_mutable_op_resolver.h"
|
||||
#include "tensorflow/lite/micro/micro_interpreter.h"
|
||||
#include "tensorflow/lite/micro/micro_mutable_op_resolver.h"
|
||||
#include "tensorflow/lite/micro/kernels/micro_ops.h"
|
||||
|
||||
#include "tensorflow/lite/micro/tflite_bridge/micro_error_reporter.h"
|
||||
#include "tensorflow/lite/micro/all_ops_resolver.h"
|
||||
#include "tensorflow/lite/micro/micro_error_reporter.h"
|
||||
#include "tensorflow/lite/micro/micro_interpreter.h"
|
||||
#include "tensorflow/lite/schema/schema_generated.h"
|
||||
#include "tensorflow/lite/micro/kernels/micro_ops.h"
|
||||
@@ -17,8 +13,6 @@
|
||||
|
||||
#include "CImageBasis.h"
|
||||
|
||||
|
||||
|
||||
#ifdef SUPRESS_TFLITE_ERRORS
|
||||
#include "tensorflow/lite/core/api/error_reporter.h"
|
||||
#include "tensorflow/lite/micro/compatibility.h"
|
||||
@@ -33,7 +27,6 @@ namespace tflite {
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
#endif
|
||||
|
||||
|
||||
class CTfLiteClass
|
||||
{
|
||||
protected:
|
||||
@@ -41,6 +34,7 @@ class CTfLiteClass
|
||||
const tflite::Model* model;
|
||||
tflite::MicroInterpreter* interpreter;
|
||||
TfLiteTensor* output = nullptr;
|
||||
static tflite::AllOpsResolver resolver;
|
||||
|
||||
int kTensorArenaSize;
|
||||
uint8_t *tensor_arena;
|
||||
@@ -74,6 +68,4 @@ class CTfLiteClass
|
||||
int ReadInputDimenstion(int _dim);
|
||||
};
|
||||
|
||||
void MakeStaticResolver();
|
||||
|
||||
#endif //CTFLITECLASS_H
|
||||
@@ -2,6 +2,6 @@ FILE(GLOB_RECURSE app_sources ${CMAKE_CURRENT_SOURCE_DIR}/*.*)
|
||||
|
||||
idf_component_register(SRCS ${app_sources}
|
||||
INCLUDE_DIRS "."
|
||||
REQUIRES tflite-lib jomjol_logfile jomjol_configfile)
|
||||
REQUIRES tflite-lib jomjol_logfile jomjol_configfile jomjol_helper)
|
||||
|
||||
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "esp_sntp.h"
|
||||
#include "../../include/defines.h"
|
||||
|
||||
#include "websocket.h"
|
||||
#include "ClassLogFile.h"
|
||||
|
||||
#include "configFile.h"
|
||||
@@ -68,6 +69,8 @@ void time_sync_notification_cb(struct timeval *tv)
|
||||
}
|
||||
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Time is synced with NTP Server " +
|
||||
getServerName() + ": " + getCurrentTimeString("%Y-%m-%d %H:%M:%S"));
|
||||
|
||||
schedule_websocket_message("{\"ntp\": \"synchronized\"}");
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -174,12 +174,10 @@ int LoadWlanFromFile(std::string fn)
|
||||
}
|
||||
|
||||
/* Check if password is empty (mandatory parameter) */
|
||||
/* Disabled see issue #2393
|
||||
if (wlan_config.password.empty()) {
|
||||
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Password empty. Device init aborted!");
|
||||
return -2;
|
||||
}
|
||||
*/
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -1,9 +1,3 @@
|
||||
dependencies:
|
||||
idf:
|
||||
component_hash: null
|
||||
source:
|
||||
type: idf
|
||||
version: 5.0.2
|
||||
manifest_hash: f880feca80f04921fc95fd31e9c2936b9896764c15a62f6e2d312c57a62a36db
|
||||
manifest_hash: 63f5c6c9f0bcebc7b9ca12d2aa8b26b2c5f5218d377dc4b2375d9b9ca1df7815
|
||||
target: esp32
|
||||
version: 1.0.0
|
||||
|
||||
@@ -173,7 +173,7 @@
|
||||
fprintf(stderr, "Error at %s:%d\n", __FILE__, __LINE__); \
|
||||
exit(1); \
|
||||
}
|
||||
// #define SUPRESS_TFLITE_ERRORS // use, to avoid error messages from TFLITE
|
||||
#define SUPRESS_TFLITE_ERRORS // use, to avoid error messages from TFLITE
|
||||
|
||||
|
||||
// connect_wlan.cpp
|
||||
|
||||
@@ -36,6 +36,7 @@
|
||||
#include "MainFlowControl.h"
|
||||
#include "server_file.h"
|
||||
#include "server_ota.h"
|
||||
#include "websocket.h"
|
||||
#include "time_sntp.h"
|
||||
#include "configFile.h"
|
||||
//#include "ClassControllCamera.h"
|
||||
@@ -491,7 +492,8 @@ extern "C" void app_main(void)
|
||||
// ********************************************
|
||||
ESP_LOGD(TAG, "starting servers");
|
||||
|
||||
server = start_webserver();
|
||||
server = start_webserver();
|
||||
start_websocket_server(server);
|
||||
register_server_camera_uri(server);
|
||||
register_server_main_flow_task_uri(server);
|
||||
register_server_file_uri(server, "/sdcard");
|
||||
@@ -642,6 +644,7 @@ void migrateConfiguration(void) {
|
||||
/* Fieldname has a <NUMBER> as prefix! */
|
||||
if (isInString(configLines[i], "Fieldname")) { // It is the parameter "Fieldname"
|
||||
migrated = migrated | replaceString(configLines[i], "Fieldname", "Field"); // Rename it to Field
|
||||
migrated = migrated | replaceString(configLines[i], ";", ""); // Enable it
|
||||
}
|
||||
}
|
||||
|
||||
@@ -649,10 +652,7 @@ void migrateConfiguration(void) {
|
||||
/* Fieldname has a <NUMBER> as prefix! */
|
||||
if (isInString(configLines[i], "Fieldname")) { // It is the parameter "Fieldname"
|
||||
migrated = migrated | replaceString(configLines[i], "Fieldname", "Field"); // Rename it to Field
|
||||
}
|
||||
/* Database got renamed to Bucket! */
|
||||
if (isInString(configLines[i], "Database")) { // It is the parameter "Database"
|
||||
migrated = migrated | replaceString(configLines[i], "Database", "Bucket"); // Rename it to Bucket
|
||||
migrated = migrated | replaceString(configLines[i], ";", ""); // Enable it
|
||||
}
|
||||
}
|
||||
|
||||
@@ -723,7 +723,6 @@ std::vector<std::string> splitString(const std::string& str) {
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*bool replace_all(std::string& s, std::string const& toReplace, std::string const& replaceWith) {
|
||||
std::string buf;
|
||||
std::size_t pos = 0;
|
||||
@@ -816,4 +815,4 @@ bool setCpuFrequency(void) {
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -39,21 +39,17 @@ esp_err_t info_get_handler(httpd_req_t *req)
|
||||
char _valuechar[30];
|
||||
std::string _task;
|
||||
|
||||
if (httpd_req_get_url_query_str(req, _query, 200) != ESP_OK)
|
||||
if (httpd_req_get_url_query_str(req, _query, 200) == ESP_OK)
|
||||
{
|
||||
return httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "invalid query string");
|
||||
ESP_LOGD(TAG, "Query: %s", _query);
|
||||
|
||||
if (httpd_query_key_value(_query, "type", _valuechar, 30) == ESP_OK)
|
||||
{
|
||||
ESP_LOGD(TAG, "type is found: %s", _valuechar);
|
||||
_task = std::string(_valuechar);
|
||||
}
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, "Query: %s", _query);
|
||||
|
||||
if (httpd_query_key_value(_query, "type", _valuechar, 30) != ESP_OK)
|
||||
{
|
||||
return httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "missing or invalid 'type' query parameter (too long value?)");
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, "type is found: %s", _valuechar);
|
||||
_task = std::string(_valuechar);
|
||||
|
||||
httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
|
||||
|
||||
if (_task.compare("GitBranch") == 0)
|
||||
@@ -170,12 +166,6 @@ esp_err_t info_get_handler(httpd_req_t *req)
|
||||
httpd_resp_sendstr(req, zw.c_str());
|
||||
return ESP_OK;
|
||||
}
|
||||
else
|
||||
{
|
||||
char formatted[256];
|
||||
snprintf(formatted, sizeof(formatted), "Unknown value for parameter info 'type': '%s'\n", _task.c_str());
|
||||
return httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, formatted);
|
||||
}
|
||||
|
||||
return ESP_OK;
|
||||
}
|
||||
@@ -437,7 +427,7 @@ httpd_handle_t start_webserver(void)
|
||||
config.server_port = 80;
|
||||
config.ctrl_port = 32768;
|
||||
config.max_open_sockets = 5; //20210921 --> previously 7
|
||||
config.max_uri_handlers = 39; // previously 24, 20220511: 35, 20221220: 37, 2023-01-02:38
|
||||
config.max_uri_handlers = 45; // previously 24, 20220511: 35, 20221220: 37, 2023-01-02:38, 20230430 (adding websocket): 45
|
||||
config.max_resp_headers = 8;
|
||||
config.backlog_conn = 5;
|
||||
config.lru_purge_enable = true; // this cuts old connections if new ones are needed.
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
|
||||
[common:esp32-idf]
|
||||
extends = common:idf
|
||||
platform = platformio/espressif32 @ 6.3.2
|
||||
platform = platformio/espressif32 @ 6.2.0
|
||||
framework = espidf
|
||||
lib_deps =
|
||||
${common:idf.lib_deps}
|
||||
|
||||
@@ -109,11 +109,7 @@ CONFIG_ESP_INT_WDT_TIMEOUT_MS=300
|
||||
|
||||
CONFIG_HTTPD_MAX_REQ_HDR_LEN=1024
|
||||
CONFIG_HTTPD_PURGE_BUF_LEN=16
|
||||
<<<<<<< Updated upstream
|
||||
=======
|
||||
CONFIG_HTTPD_WS_SUPPORT=y
|
||||
CONFIG_LWIP_MAX_SOCKETS=12
|
||||
>>>>>>> Stashed changes
|
||||
|
||||
CONFIG_ESP32_WIFI_DYNAMIC_RX_BUFFER_NUM=16
|
||||
CONFIG_ESP32_WIFI_CACHE_TX_BUFFER_NUM=16
|
||||
|
||||
BIN
docs/binary/firmware.bin
Normal file
@@ -18,19 +18,16 @@
|
||||
|
||||
For further information about AI-on-the-edge-device please go to <a href=https://github.com/jomjol/AI-on-the-edge-device target=_blank>https://github.com/jomjol/AI-on-the-edge-device</a>.</p>
|
||||
|
||||
<h2>Notes:</h2>
|
||||
<p>Notes:</p>
|
||||
<ul>
|
||||
<li>The Webinstall will install the latest firmware (Version <b>$VERSION</b>).</li>
|
||||
<li>For the installation, make sure to switch the ESP32 to Bootloader mode by keeping the <b>FLASH</b> button pressed while the <b>RESET</b> button gets relesed. if there is no <b>FLASH</b> button, you need to pull <b>GPIO0</b> low!</li>
|
||||
<li>For the installation, make sure to switch the ESP32 to Bootloader mode!</li>
|
||||
<li>After the installation, a manual reset might be required!</li>
|
||||
<li>Please note that not all web browsers and operating systems support the necessary USB access needed for this Webinstaller!</li>
|
||||
<li>Please note that not all webbrowsers and operating systems support the needed access to USB!</li>
|
||||
<li>Check the <a href=https://jomjol.github.io/AI-on-the-edge-device-docs/Installation target=_blank>documentation</a> for additional information.</li>
|
||||
<li>The SD card can be setup automatically after the firmware got installed. See the <a href=https://jomjol.github.io/AI-on-the-edge-device-docs/Installation/#remote-setup-using-the-built-in-access-point target=_blank>documentation</a> for details. For this to work, the SD card must be FAT formated (which is the default on a new SD card).
|
||||
Alternatively the SD card still can be setup manually, see the <a href=https://jomjol.github.io/AI-on-the-edge-device-docs/Installation/#3-sd-card target=_blank>documentation</a> for details!</li>
|
||||
<li>The SD-Card still must be setup separately. This can be done manually or using the new <b>Remote Setup</b>. See the <a href=https://jomjol.github.io/AI-on-the-edge-device-docs/Installation/#3-sd-card target=_blank>documentation</a> for further instructions!</li>
|
||||
|
||||
</ul>
|
||||
|
||||
<hr>
|
||||
|
||||
|
||||
<p><esp-web-install-button manifest="manifest.json"></esp-web-install-button></p>
|
||||
<hr>
|
||||
<p style="font-size: small;">Installer and Console powered by <a href=https://esphome.github.io/esp-web-tools/ target=_blank>ESP Web Tools</a></p>
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "AI-on-the-edge",
|
||||
"version": "$VERSION",
|
||||
"version": "13.0.8",
|
||||
"funding_url": "https://www.paypal.com/donate?hosted_button_id=8TRSVYNYKDSWL",
|
||||
"new_install_prompt_erase": false,
|
||||
"builds": [
|
||||
|
||||
25
docs/manifest_template.json
Normal file
@@ -0,0 +1,25 @@
|
||||
{
|
||||
"name": "AI-on-the-edge",
|
||||
"version": "VERSION",
|
||||
"funding_url": "https://www.paypal.com/donate?hosted_button_id=8TRSVYNYKDSWL",
|
||||
"new_install_prompt_erase": false,
|
||||
"builds": [
|
||||
{
|
||||
"chipFamily": "ESP32",
|
||||
"parts": [
|
||||
{
|
||||
"path": "binary/bootloader.bin",
|
||||
"offset": 4096
|
||||
},
|
||||
{
|
||||
"path": "binary/partitions.bin",
|
||||
"offset": 32768
|
||||
},
|
||||
{
|
||||
"path": "binary/firmware.bin",
|
||||
"offset": 65536
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
6
firmware/README.md
Normal file
@@ -0,0 +1,6 @@
|
||||
# Firmware
|
||||
The firmware got moved to the [Release page](https://github.com/jomjol/AI-on-the-edge-device/releases).
|
||||
|
||||
# Installation Guide
|
||||
|
||||
You find the complete installation guide at https://jomjol.github.io/AI-on-the-edge-device-docs/Installation/
|
||||
|
Before Width: | Height: | Size: 36 KiB |
|
Before Width: | Height: | Size: 69 KiB |
|
Before Width: | Height: | Size: 82 KiB |
BIN
releases/download/v11.2.0/bootloader.bin
Normal file
BIN
releases/download/v11.2.0/partitions.bin
Normal file
BIN
releases/download/v12.0.1/firmware.bin
Normal file
BIN
releases/download/v13.0.8/firmware.bin
Normal file
BIN
sd-card/config/ana-class100_0157_s1_q.tflite
Normal file
BIN
sd-card/config/ana-cont_1105_s2_q.tflite
Normal file
@@ -12,7 +12,7 @@ FixedExposure = false
|
||||
Demo = false
|
||||
|
||||
[Alignment]
|
||||
InitialRotate = 0.0
|
||||
InitialRotate = 179
|
||||
InitialMirror = false
|
||||
SearchFieldX = 20
|
||||
SearchFieldY = 20
|
||||
@@ -22,7 +22,7 @@ FlipImageSize = false
|
||||
/config/ref1.jpg 442 142
|
||||
|
||||
[Digits]
|
||||
Model = /config/dig-cont_0620_s3_q.tflite
|
||||
Model = /config/dig-cont_0611_s3_q.tflite
|
||||
CNNGoodThreshold = 0.5
|
||||
;ROIImagesLocation = /log/digit
|
||||
;ROIImagesRetention = 3
|
||||
@@ -31,7 +31,7 @@ main.dig2 343 126 30 54 false
|
||||
main.dig3 391 126 30 54 false
|
||||
|
||||
[Analog]
|
||||
Model = /config/ana-cont_1208_s2_q.tflite
|
||||
Model = /config/ana-cont_1105_s2_q.tflite
|
||||
CNNGoodThreshold = 0.5
|
||||
;ROIImagesLocation = /log/analog
|
||||
;ROIImagesRetention = 3
|
||||
@@ -62,9 +62,6 @@ CheckDigitIncreaseConsistency = false
|
||||
RetainMessages = false
|
||||
HomeassistantDiscovery = false
|
||||
;MeterType = other
|
||||
;CACert = /config/certs/RootCA.pem
|
||||
;ClientCert = /config/certs/client.pem.crt
|
||||
;ClientKey = /config/certs/client.pem.key
|
||||
|
||||
;[InfluxDB]
|
||||
;Uri = undefined
|
||||
@@ -75,7 +72,7 @@ HomeassistantDiscovery = false
|
||||
|
||||
;[InfluxDBv2]
|
||||
;Uri = undefined
|
||||
;Bucket = undefined
|
||||
;Database = undefined
|
||||
;Measurement = undefined
|
||||
;Org = undefined
|
||||
;Token = undefined
|
||||
@@ -109,6 +106,6 @@ LogfilesRetention = 3
|
||||
TimeZone = CET-1CEST,M3.5.0,M10.5.0/3
|
||||
;TimeServer = pool.ntp.org
|
||||
;Hostname = undefined
|
||||
RSSIThreshold = -75
|
||||
;RSSIThreshold = 0
|
||||
CPUFrequency = 160
|
||||
SetupMode = true
|
||||
|
||||
BIN
sd-card/config/dig-class100_0160_s2_q.tflite
Normal file
BIN
sd-card/config/dig-cont_0611_s3.tflite
Normal file
|
Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 29 KiB |
|
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 30 KiB |
|
Before Width: | Height: | Size: 38 KiB After Width: | Height: | Size: 29 KiB |
@@ -1,41 +1,42 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" xml:lang="en">
|
||||
<html>
|
||||
<head>
|
||||
<title>Backup/Restore Configuration</title>
|
||||
<meta charset="UTF-8" />
|
||||
<link rel="icon" href="favicon.ico?v=$COMMIT_HASH" type="image/x-icon">
|
||||
<title>Backup/Restore Configuration</title>
|
||||
<meta charset="utf-8">
|
||||
|
||||
<style>
|
||||
h1 {font-size: 2em;}
|
||||
h2 {font-size: 1.5em; margin-block-start: 0.0em; margin-block-end: 0.2em;}
|
||||
h3 {font-size: 1.2em;}
|
||||
p {font-size: 1em;}
|
||||
<style>
|
||||
h1 {font-size: 2em;}
|
||||
h2 {font-size: 1.5em;}
|
||||
h3 {font-size: 1.2em;}
|
||||
p {font-size: 1em;}
|
||||
|
||||
input[type=number] {
|
||||
width: 138px;
|
||||
padding: 10px 5px;
|
||||
display: inline-block;
|
||||
border: 1px solid #ccc;
|
||||
font-size: 16px;
|
||||
}
|
||||
input[type=number] {
|
||||
width: 138px;
|
||||
padding: 10px 5px;
|
||||
display: inline-block;
|
||||
border: 1px solid #ccc;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.button {
|
||||
padding: 5px 10px;
|
||||
width: 205px;
|
||||
font-size: 16px;
|
||||
}
|
||||
</style>
|
||||
.button {
|
||||
padding: 10px 20px;
|
||||
width: 211px;
|
||||
font-size: 16px;
|
||||
}
|
||||
</style>
|
||||
|
||||
</head>
|
||||
|
||||
<body style="font-family: arial; padding: 0px 10px;">
|
||||
<h2>Backup Configuration</h2>
|
||||
<p>With the following action the <a href="/fileserver/config/" target="_self">config</a> folder on the SD-card gets zipped and provided as a download.</p>
|
||||
<h2>Backup Configuration</h2>
|
||||
<p>With the following action the <a href="/fileserver/config/" target="_self">config</a> folder on the SD-card gets zipped and provided as a download.</p>
|
||||
|
||||
<button class="button" id="startBackup" type="button" onclick="startBackup()">Create Backup</button>
|
||||
<p id=progress></p>
|
||||
<hr>
|
||||
<h2>Restore Configuration</h2>
|
||||
<p>Use the <a href="/fileserver/config/" target="_self">File Server</a> to upload individual files.</p>
|
||||
<button class="button" id="startBackup" type="button" onclick="startBackup()">Create Config backup</button>
|
||||
<p id=progress></p>
|
||||
<hr>
|
||||
<h2>Restore Configuration</h2>
|
||||
<p>Use the <a href="/fileserver/config/" target="_self">File Server</a> to upload individual files.</p>
|
||||
</body>
|
||||
|
||||
|
||||
|
||||
@@ -1,17 +1,18 @@
|
||||
|
||||
/* The UI can also be run locally, but you have to set the IP of your devide accordingly.
|
||||
* And you also might have to disable CORS in your webbrowser!
|
||||
* Keep empty to disable using it. Enabling it will break access through a forwared port, see
|
||||
* https://github.com/jomjol/AI-on-the-edge-device/issues/2681 */
|
||||
var domainname_for_testing = "";
|
||||
//var domainname_for_testing = "192.168.1.151";
|
||||
* And you also might have to disable CORS in your webbrowser! */
|
||||
var domainname_for_testing = "192.168.178.23";
|
||||
|
||||
|
||||
/* Returns the domainname with prepended protocol.
|
||||
Eg. http://watermeter.fritz.box or http://192.168.1.5 */
|
||||
function getDomainname(){
|
||||
var host = window.location.hostname;
|
||||
if (domainname_for_testing != "") {
|
||||
if (((host == "127.0.0.1") || (host == "localhost") || (host == ""))
|
||||
// && ((window.location.port == "80") || (window.location.port == ""))
|
||||
)
|
||||
|
||||
{
|
||||
console.log("Using pre-defined domainname for testing: " + domainname_for_testing);
|
||||
domainname = "http://" + domainname_for_testing
|
||||
}
|
||||
@@ -138,8 +139,8 @@ function compareVersions() {
|
||||
console.log("FW Hash: " + fWGitHash + ", Web UI Hash: " + webUiHash);
|
||||
|
||||
if (fWGitHash != webUiHash) {
|
||||
firework.launch("The version of the web interface (" + webUiHash +
|
||||
") does not match the firmware version (" +
|
||||
firework.launch("The Version of the Web Interface (" + webUiHash +
|
||||
") does not match the Firmware Version (" +
|
||||
fWGitHash + ")! It is suggested to keep them on the same version!", 'warning', 30000);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,26 +1,17 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" xml:lang="en">
|
||||
<html>
|
||||
<head>
|
||||
<title>Data Viewer</title>
|
||||
<meta charset="UTF-8" />
|
||||
|
||||
<style>
|
||||
h1 {font-size: 2em;}
|
||||
h2 {font-size: 1.5em; margin-block-start: 0.0em; margin-block-end: 0.2em;}
|
||||
h3 {font-size: 1.2em;}
|
||||
p {font-size: 1em;}
|
||||
|
||||
html,
|
||||
body {
|
||||
height: 100%;
|
||||
margin: 1px;
|
||||
margin: 2px;
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
}
|
||||
|
||||
.box {
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
height: 99.75%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.box .row.header {
|
||||
@@ -39,31 +30,26 @@
|
||||
font-family: 'Courier New', Courier, monospace;
|
||||
font-size: small;
|
||||
}
|
||||
|
||||
.button {
|
||||
padding: 5px 10px;
|
||||
width: 160px;
|
||||
font-size: 16px;
|
||||
}
|
||||
</style>
|
||||
<script type="text/javascript" src="common.js?v=$COMMIT_HASH"></script>
|
||||
</head>
|
||||
<body>
|
||||
<h2>Data Viewer</h2>
|
||||
<h4>Today's latest data</h4>
|
||||
<h3>Todays Data</h3>
|
||||
<h4>Last part of Todays Data</h4>
|
||||
<div class="box">
|
||||
<div class="row header">
|
||||
<button class="button" onClick="reload();">Refresh</button>
|
||||
<button class="button" onClick="window.open(getDomainname() + '/datafileact');">Show Full File</button>
|
||||
<button class="button" onClick="window.location.href = getDomainname() + '/fileserver/log/data/'">Show Data Files</button>
|
||||
<button class="button" onClick="window.location.href = 'graph.html?v=$COMMIT_HASH'">Show Graph</button>
|
||||
<button onClick="reload();">Refresh</button>
|
||||
<button onClick="window.open(getDomainname() + '/datafileact');">Show Full File</button>
|
||||
<button onClick="window.location.href = getDomainname() + '/fileserver/log/data/'">Show Data Files</button>
|
||||
<button onClick="window.location.href = 'graph.html?v=$COMMIT_HASH'">Show Graph</button>
|
||||
</div>
|
||||
<div class="row content" id="data"><br><br><br><b>Loading data file, please wait...</b></div>
|
||||
<div class="row content" id="data"><br><br><br><b>Loading Data file, please wait...</b></div>
|
||||
<div class="row footer">
|
||||
<button class="button" onClick="reload();">Refresh</button>
|
||||
<button class="button" onClick="window.open(getDomainname() + '/datafileact');">Show Full File</button>
|
||||
<button class="button" onClick="window.location.href = getDomainname() + '/fileserver/log/data/'">Show Data Files</button>
|
||||
<button class="button" onClick="window.location.href = 'graph.html?v=$COMMIT_HASH'">Show Graph</button>
|
||||
<button onClick="reload();">Refresh</button>
|
||||
<button onClick="window.open(getDomainname() + '/datafileact');">Show Full File</button>
|
||||
<button onClick="window.location.href = getDomainname() + '/fileserver/log/data/'">Show Data Files</button>
|
||||
<button onClick="window.location.href = 'graph.html?v=$COMMIT_HASH'">Show Graph</button>
|
||||
<p></p>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
@@ -1,135 +1,101 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" xml:lang="en">
|
||||
<html>
|
||||
<head>
|
||||
<title>Alignment marker</title>
|
||||
<meta charset="UTF-8" />
|
||||
|
||||
<style>
|
||||
h1 {font-size: 2em;}
|
||||
h2 {font-size: 1.5em; margin-block-start: 0.0em; margin-block-end: 0.2em;}
|
||||
h3 {font-size: 1.2em;}
|
||||
p {font-size: 1em;}
|
||||
<link rel="icon" href="favicon.ico?v=$COMMIT_HASH" type="image/x-icon">
|
||||
<title>Alignment Marks</title>
|
||||
<meta charset="utf-8"/>
|
||||
|
||||
<style>
|
||||
h1 {font-size: 2em;}
|
||||
h2 {font-size: 1.5em; margin-block-start: 0.0em; margin-block-end: 0.2em;}
|
||||
h3 {font-size: 1.2em;}
|
||||
p {font-size: 1em;}
|
||||
|
||||
input[type=number] {
|
||||
width: 60px;
|
||||
margin-right: 10px;
|
||||
padding: 3px 5px;
|
||||
display: inline-block;
|
||||
border: 1px solid #ccc;
|
||||
font-size: 16px;
|
||||
}
|
||||
input[type=number] {
|
||||
width: 100px;
|
||||
margin-right: 10px;
|
||||
padding: 3px 5px;
|
||||
display: inline-block;
|
||||
border: 1px solid #ccc;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
input[type=text] {
|
||||
padding: 3px 5px;
|
||||
display: inline-block;
|
||||
border: 1px solid #ccc;
|
||||
font-size: 16px;
|
||||
}
|
||||
input[type=text] {
|
||||
padding: 3px 5px;
|
||||
display: inline-block;
|
||||
border: 1px solid #ccc;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
input:out-of-range {
|
||||
background-color: rgba(255, 0, 0, 0.25);
|
||||
border: 1px solid red;
|
||||
}
|
||||
select {
|
||||
padding: 3px 5px;
|
||||
display: inline-block;
|
||||
border: 1px solid #ccc;
|
||||
font-size: 16px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
select {
|
||||
padding: 3px 5px;
|
||||
display: inline-block;
|
||||
border: 1px solid #ccc;
|
||||
font-size: 16px;
|
||||
margin-right: 10px;
|
||||
min-width: 100px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.button {
|
||||
padding: 5px 10px;
|
||||
width: 205px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
th, td {
|
||||
padding: 5px 5px 5px 0px;
|
||||
}
|
||||
|
||||
table {
|
||||
width: 660px;
|
||||
padding: 5px;
|
||||
}
|
||||
</style>
|
||||
<link href="firework.css?v=$COMMIT_HASH" rel="stylesheet">
|
||||
<script type="text/javascript" src="jquery-3.6.0.min.js?v=$COMMIT_HASH"></script>
|
||||
<script type="text/javascript" src="firework.js?v=$COMMIT_HASH"></script>
|
||||
.button {
|
||||
padding: 5px 10px;
|
||||
width: 210px;
|
||||
font-size: 16px;
|
||||
}
|
||||
</style>
|
||||
<link href="firework.css?v=$COMMIT_HASH" rel="stylesheet">
|
||||
<script type="text/javascript" src="jquery-3.6.0.min.js?v=$COMMIT_HASH"></script>
|
||||
<script type="text/javascript" src="firework.js?v=$COMMIT_HASH"></script>
|
||||
</head>
|
||||
|
||||
<body style="font-family: arial; padding: 0px 10px;">
|
||||
|
||||
<h2>Alignment Marker</h2>
|
||||
<details id="desc_details" style="font-size:16px">
|
||||
<summary><b>CLICK HERE</b> for usage description. More infos in documentation:
|
||||
<a href=https://jomjol.github.io/AI-on-the-edge-device-docs/Alignment/ target=_blank>Alignment</a>
|
||||
</summary>
|
||||
<p>
|
||||
Two alignment marker with clear contour and proper contrast are needed to identify unique "fix points" on the image.
|
||||
The marker area should be not be part of the variable area of ROI evaluation. Please find more information in documenation:
|
||||
<a href=https://jomjol.github.io/AI-on-the-edge-device-docs/Alignment/ target=_blank>Alignment</a>
|
||||
</p>
|
||||
<p>
|
||||
Select an alignment marker area using drag and dop feature by mouse operation or by manually entering the coordinates and sizes in the fields below the image.
|
||||
After you selected a suitable first alignment marker area, push the <b>"Update Marker"</b> button. Switch to second alignment marker with <b>"Marker"</b>
|
||||
and repeat the procedure.
|
||||
</p>
|
||||
<p>
|
||||
After definition of both alignment marker is completed don't forget to save with the <b>"Save New Marker"</b> button!<br>
|
||||
<b>NOTE:</b> There is no need to perform a reboot after every saving or step. It's sufficient to reboot after all configuration steps
|
||||
(reference image, alignment, ROI configuration) are completed to activate new configuration.
|
||||
</p>
|
||||
</details>
|
||||
<hr />
|
||||
<h2>Alignment Marks</h2>
|
||||
<p>On this page you define two Reference Marks.
|
||||
See <a href=https://jomjol.github.io/AI-on-the-edge-device-docs/Alignment/ target=_blank>https://jomjol.github.io/AI-on-the-edge-device-docs/Alignment/</a> for explanations.</p>
|
||||
<p>After saving the Reference Marks, you can define the <a href=edit_digits.html>digit</a> resp. <a href=edit_analog.html>analog</a> ROI's.<br>
|
||||
Only after those steps a reboot is required.</p>
|
||||
|
||||
<table>
|
||||
<colgroup>
|
||||
<col span="1" style="width: 33.3%;">
|
||||
<col span="1" style="width: 33.3%;">
|
||||
<col span="1" style="width: 33.3%;">
|
||||
</colgroup>
|
||||
<tr>
|
||||
<td>Marker:
|
||||
<td><canvas id="canvas" crossorigin></canvas></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td>Select Reference:
|
||||
<select id="index" name="reference" onchange="ChangeSelection()">
|
||||
<option value="0" selected>Marker 1</option>
|
||||
<option value="1" >Marker 2</option>
|
||||
<option value="0" selected>Reference 0</option>
|
||||
<option value="1" >Reference 1</option>
|
||||
</select>
|
||||
</td>
|
||||
<td colspan="2" style="padding-left: 22px; color: grey;">Filename: <output type="text" name="name" id="name" onchange="namechanged()"></td>
|
||||
<td colspan="2">Storage Path/Name: <input type="text" name="name" id="name" onchange="namechanged()"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="padding-top: 10px">x: <input type="number" name="refx" id="refx" step=1 onchange="valuemanualchanged()"></td>
|
||||
<td style="padding-top: 10px">dx: <input type="number" name="refdx" id="refdx" step=1 onchange="valuemanualchanged()"></td>
|
||||
<td rowspan="2" style="padding-top: 10px;"><input class="button" type="button" value="Update Marker" onclick="CutOutReference()"></td>
|
||||
<td rowspan="2" style="padding-top: 10px"><input class="button" type="button" value="Update Reference Image" onclick="CutOutReference()"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>y: <input type="number" name="refy" id="refy" step=1 onchange="valuemanualchanged()"></td>
|
||||
<td>dy: <input type="number" name="refdy" id="refdy" step=1 onchange="valuemanualchanged()"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="vertical-align: bottom;">Selected Image Area:</td>
|
||||
<td style="vertical-align: bottom;">Resulting Marker:</td>
|
||||
<td><input class="button" type="button" id="enhancecontrast" value="Enhance Image Contrast" onclick="EnhanceContrast()"></td>
|
||||
<td style="padding-top: 10px">Original Image:</td>
|
||||
<td style="padding-top: 10px">Reference Image:</td>
|
||||
<td rowspan="2"><input class="button" type="button" id="enhancecontrast" value="Enhance Contrast" onclick="EnhanceContrast()"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="height:70px; vertical-align: top;"><img id="img_ref_org" src = ""></td> <!--/img_tmp/ref_zw_org.jpg-->
|
||||
<td style="height:70px; vertical-align: top;"><img id="img_ref" src = ""></td> <!--/img_tmp/ref_zw.jpg-->
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="vertical-align:bottom;"><b>Reference Image:</b></td>
|
||||
<td></td>
|
||||
<td><input style="font-weight:bold;" class="button" type="submit" name="saveroi" id="savemarker" onclick="SaveToConfig()" value="Save New Marker">
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="3"><canvas id="canvas" crossorigin></canvas></td>
|
||||
</tr>
|
||||
</table>
|
||||
<td><img id="img_ref_org" src = "/img_tmp/ref_zw_org.jpg"></td>
|
||||
<td><img id="img_ref" src = "/img_tmp/ref_zw.jpg"></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td><input class="button" type="submit" name="saveroi" onclick="SaveToConfig()" value="Save">
|
||||
<p>Proceed to update the <a href=edit_digits.html>digit</a> resp. <a href=edit_analog.html>analog</a> ROI's when you are done.</p></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<script type="text/javascript" src="common.js?v=$COMMIT_HASH"></script>
|
||||
<script type="text/javascript" src="readconfigcommon.js?v=$COMMIT_HASH"></script>
|
||||
@@ -164,15 +130,10 @@ function ChangeSelection(){
|
||||
}
|
||||
|
||||
function SaveToConfig(){
|
||||
if (confirm("Are you sure you want to save the new alignment marker configuration?")) {
|
||||
WriteConfigININew();
|
||||
UpdateConfigReference(domainname)
|
||||
SaveConfigToServer(domainname);
|
||||
document.getElementById("savemarker").disabled = true;
|
||||
document.getElementById("enhancecontrast").disabled = true;
|
||||
|
||||
firework.launch('Alignment marker saved. They will get applied after next reboot', 'success', 5000);
|
||||
}
|
||||
WriteConfigININew();
|
||||
UpdateConfigReference(domainname)
|
||||
SaveConfigToServer(domainname);
|
||||
firework.launch('Reference Marks got updated. The change will get applied after the next reboot!', 'success', 5000);
|
||||
}
|
||||
|
||||
function EnhanceContrast(){
|
||||
@@ -185,7 +146,6 @@ function EnhanceContrast(){
|
||||
enhanceCon = true;
|
||||
if (MakeContrastImageZW(refInfo[aktindex], enhanceCon, domainname)) {
|
||||
UpdateReference();
|
||||
document.getElementById("enhancecontrast").disabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -214,6 +174,7 @@ function UpdateReference(){
|
||||
document.getElementById("refy").value = refInfo[aktindex]["y"];
|
||||
rect.startX = document.getElementById("refx").value;
|
||||
rect.startY = document.getElementById("refy").value;
|
||||
document.getElementById("enhancecontrast").disabled = true;
|
||||
draw();
|
||||
}
|
||||
|
||||
@@ -254,27 +215,14 @@ function dataURLtoBlob(dataurl) {
|
||||
return { top: Math.round(top), left: Math.round(left) };
|
||||
}
|
||||
|
||||
|
||||
/* hash #description open the details part of the page */
|
||||
function openDescription() {
|
||||
if(window.location.hash) {
|
||||
var hash = window.location.hash.substring(1); //Puts hash in variable, and removes the # character
|
||||
if(hash == 'description')
|
||||
document.getElementById("desc_details").open = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function init() {
|
||||
openDescription();
|
||||
|
||||
function init() {
|
||||
domainname = getDomainname();
|
||||
loadConfig(domainname);
|
||||
ParseConfig();
|
||||
param = getConfigParameters();
|
||||
|
||||
document.getElementById("savemarker").disabled = true;
|
||||
document.getElementById("enhancecontrast").disabled = true;
|
||||
|
||||
canvas.addEventListener('mousedown', mouseDown, false);
|
||||
canvas.addEventListener('mouseup', mouseUp, false);
|
||||
canvas.addEventListener('mousemove', mouseMove, false);
|
||||
@@ -287,8 +235,6 @@ function dataURLtoBlob(dataurl) {
|
||||
|
||||
drawImage();
|
||||
}
|
||||
|
||||
|
||||
function drawImage(){
|
||||
var canvas = document.getElementById('canvas');
|
||||
var context = canvas.getContext('2d');
|
||||
@@ -308,7 +254,6 @@ function dataURLtoBlob(dataurl) {
|
||||
if (MakeRefZW(refInfo[aktindex], domainname)) {
|
||||
UpdateReference();
|
||||
document.getElementById("enhancecontrast").disabled = false;
|
||||
document.getElementById("savemarker").disabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,221 +1,142 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" xml:lang="en">
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>Analog ROI</title>
|
||||
<link rel="icon" href="favicon.ico?v=$COMMIT_HASH" type="image/x-icon">
|
||||
<meta charset="utf-8"/>
|
||||
<title>Analog ROI's</title>
|
||||
|
||||
<style>
|
||||
h1 {font-size: 2em;}
|
||||
h2 {font-size: 1.5em; margin-block-start: 0.0em; margin-block-end: 0.2em;}
|
||||
h3 {font-size: 1.2em;}
|
||||
p {font-size: 1em;}
|
||||
<style>
|
||||
h1 {font-size: 2em;}
|
||||
h2 {font-size: 1.5em; margin-block-start: 0.0em; margin-block-end: 0.2em;}
|
||||
h3 {font-size: 1.2em;}
|
||||
p {font-size: 1em;}
|
||||
|
||||
input[type=number] {
|
||||
width: 60px;
|
||||
margin-right: 10px;
|
||||
padding: 3px 5px;
|
||||
display: inline-block;
|
||||
border: 1px solid #ccc;
|
||||
font-size: 16px;
|
||||
}
|
||||
input[type=number] {
|
||||
width: 100px;
|
||||
margin-right: 10px;
|
||||
padding: 3px 5px;
|
||||
display: inline-block;
|
||||
border: 1px solid #ccc;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
input[type=text] {
|
||||
padding: 3px 5px;
|
||||
display: inline-block;
|
||||
border: 1px solid #ccc;
|
||||
font-size: 16px;
|
||||
}
|
||||
input[type=text] {
|
||||
padding: 3px 5px;
|
||||
display: inline-block;
|
||||
border: 1px solid #ccc;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
input:out-of-range {
|
||||
background-color: rgba(255, 0, 0, 0.25);
|
||||
border: 1px solid red;
|
||||
}
|
||||
select {
|
||||
padding: 3px 5px;
|
||||
display: inline-block;
|
||||
border: 1px solid #ccc;
|
||||
font-size: 16px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
select {
|
||||
padding: 3px 5px;
|
||||
display: inline-block;
|
||||
border: 1px solid #ccc;
|
||||
font-size: 16px;
|
||||
margin-right: 10px;
|
||||
min-width: 100px;
|
||||
max-width: 100%;
|
||||
vertical-align: middle;
|
||||
overflow: hidden;
|
||||
}
|
||||
.button {
|
||||
padding: 5px 10px;
|
||||
width: 210px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.button {
|
||||
padding: 5px 10px;
|
||||
width: 160px;
|
||||
font-size: 16px;
|
||||
}
|
||||
.move {
|
||||
padding: 4px 4px;
|
||||
width: 100px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
.multiplier {
|
||||
padding: 0px 0px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
th, td {
|
||||
padding: 5px 5px 5px 0px;
|
||||
}
|
||||
|
||||
#div2{
|
||||
background-color:#777;
|
||||
margin-bottom:20px;
|
||||
}
|
||||
|
||||
.disabledDiv {
|
||||
pointer-events: none;
|
||||
opacity: 0.4;
|
||||
}
|
||||
|
||||
table {
|
||||
width: 660px;
|
||||
padding: 5px;
|
||||
table-layout: fixed;
|
||||
}
|
||||
</style>
|
||||
|
||||
<link href="firework.css?v=$COMMIT_HASH" rel="stylesheet">
|
||||
<script type="text/javascript" src="jquery-3.6.0.min.js?v=$COMMIT_HASH"></script>
|
||||
<script type="text/javascript" src="firework.js?v=$COMMIT_HASH"></script>
|
||||
th, td {
|
||||
padding: 5px 5px 5px 0px;
|
||||
}
|
||||
|
||||
#div2{
|
||||
background-color:#777;
|
||||
margin-bottom:20px;
|
||||
}
|
||||
.disabledDiv {
|
||||
pointer-events: none;
|
||||
opacity: 0.4;
|
||||
}
|
||||
</style>
|
||||
<link href="firework.css?v=$COMMIT_HASH" rel="stylesheet">
|
||||
<script type="text/javascript" src="jquery-3.6.0.min.js?v=$COMMIT_HASH"></script>
|
||||
<script type="text/javascript" src="firework.js?v=$COMMIT_HASH"></script>
|
||||
</head>
|
||||
|
||||
<body style="font-family: arial; padding: 0px 10px;">
|
||||
|
||||
<h2>Analog ROI</h2>
|
||||
<details id="desc_details" style="font-size:16px">
|
||||
<summary><b>CLICK HERE</b> for usage description. More infos in documentation:
|
||||
<a href=https://jomjol.github.io/AI-on-the-edge-device-docs/ROI-Configuration/ target=_blank>ROI Configuration</a>
|
||||
</summary>
|
||||
<p>
|
||||
<b>R</b>egion <b>O</b>f <b>I</b>nterest (ROI) for analog pointer counter can be defined on this page. If no analog pointer counter need to be
|
||||
processed, disable analog pointer counter processing by deselecting <b>"Analog ROI Processing"</b>.
|
||||
</p>
|
||||
<p>
|
||||
By default one number sequence (a number seqence contains of 1-x digit ROIs + 1-x analog counter ROIs which are processed together) is
|
||||
predefined and already selected in the drop down <b>"Number Sequence"</b>. If you need more than one number sequence additional
|
||||
one's can be added with the buttons next to the drop down. Each number sequence will be processed separately.
|
||||
</p>
|
||||
<p>
|
||||
Using drag and drop by mouse of by manually entering the parameters into the given fields the analog ROIs can be positined to the analog pointer
|
||||
counters on the reference image. To have proper ROI definition please check the documentation:
|
||||
<a href=https://jomjol.github.io/AI-on-the-edge-device-docs/ROI-Configuration/ target=_blank>ROI Configuration</a>. It's very important to be
|
||||
really precise to have reliable processing. With the drop down <b>"ROI"</b> you can change between the different ROIs in the selected
|
||||
number sequence. To create new ROIs use <b>"New ROI"</b>.
|
||||
</p>
|
||||
<p>
|
||||
The order of the ROIs defines the position (and therefore the multiplication factor) within the reading sequence. The position
|
||||
in the number sequence can be changed with the buttons <b>"Move ROI Lower"</b> and <b>"Move ROI Higher"</b>. The multiplication factor which is
|
||||
shown below the ROI drop down is the multiplication factor of pure position/order in number sequence and the factor right-hand side to this is
|
||||
the additionally corrected by decimal shift setting (configuration, expert parameter, default: 0).
|
||||
</p>
|
||||
<p>
|
||||
After definition of digit ROIs is completed don't forget to save with the <b>"Save Config"</b> button!<br>
|
||||
<b>NOTE:</b> There is no need to perform a reboot after every saving or step. It's sufficient to reboot after all configuration steps
|
||||
(reference image, alignment, ROI configuration) are completed to activate new configuration.
|
||||
</p>
|
||||
</details>
|
||||
<hr />
|
||||
|
||||
<p>
|
||||
<input type="checkbox" id="Category_Analog_enabled" value="1" onclick = 'EnDisableAnalog()' checked >
|
||||
<label style="font-weight: bold; font-size: larger;" for="Category_Analog_enabled">Analog ROI Processing</label>
|
||||
</p>
|
||||
|
||||
|
||||
<h2>Analog ROI's</h2>
|
||||
<p>On this page you define ROI's for the analog counters.
|
||||
See <a href=https://jomjol.github.io/AI-on-the-edge-device-docs/ROI-Configuration/ target=_blank>https://jomjol.github.io/AI-on-the-edge-device-docs/ROI-Configuration/</a> for explanations.</p>
|
||||
|
||||
<input type="checkbox" id="Category_Analog_enabled" value="1" onclick = 'EnDisableAnalog()' checked ><label for="Category_Analog_enabled">Enable Analog ROI's</label></p>
|
||||
|
||||
<div id="div1">
|
||||
<table>
|
||||
<tr>
|
||||
<td><canvas id="canvas" crossorigin></canvas></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<table>
|
||||
<colgroup>
|
||||
<col span="1" style="width: 22%;">
|
||||
<col span="1" style="width: 26%;">
|
||||
<col span="1" style="width: 26%;">
|
||||
<col span="1" style="width: 26%;">
|
||||
</colgroup>
|
||||
<tr>
|
||||
<td colspan="4" style="padding: 0px"><class id="Numbers_text" style="color:black;">Number Sequence:</class></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<p>
|
||||
<table>
|
||||
<tr>
|
||||
<class id="Numbers_text" style="color:black;"><b>Number: </b></class>
|
||||
<select id="Numbers_value1" onchange="numberChanged()">
|
||||
</select>
|
||||
</td>
|
||||
<td><input class="button" type="submit" id="newNumber" name="newNumber" onclick="newNumber()" value="New Sequence"></td>
|
||||
<td><input class="button" type="submit" id="renameNumber" name="renameNumber" onclick="renameNumber()" value="Rename Sequence"></td>
|
||||
<td><input class="button" type="submit" id="removeNumber" name="removeNumber" onclick="removeNumber()" value="Delete Sequence"></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<hr />
|
||||
|
||||
<table>
|
||||
<colgroup>
|
||||
<col span="1" style="width: 22%;">
|
||||
<col span="1" style="width: 26%;">
|
||||
<col span="1" style="width: 26%;">
|
||||
<col span="1" style="width: 26%;">
|
||||
</colgroup>
|
||||
<tr>
|
||||
<td style="padding: 0px">ROI:</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><select id="index" name="index" onchange="ChangeSelection()" tabindex=1></select></td>
|
||||
<td><input class="button" type="submit" id="newROI" name="newROI" onclick="newROI()" value="New ROI"></td>
|
||||
<td><input class="button" type="submit" id="renameROI" name="renameROI" onclick="renameROI()" value="Rename ROI"></td>
|
||||
<td><input class="button" type="submit" id="deleteROI" name="deleteROI" onclick="deleteROI()" value="Delete ROI"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="multiplier">Multiplier: <output type="text" id="multiplier" name="multiplier"></output><br>
|
||||
(only based on order)
|
||||
</td>
|
||||
<td class="multiplier">Multiplier: <output type="text" id="multiplier_decshift" name="multiplier_decshift"></output><br>
|
||||
(order + decimal shift: <output type="text" id="decimalShift" name="decimalShift"></output>)
|
||||
</td>
|
||||
<td><input class="button" type="submit" id="movePrevious" onclick="movePrevious()" value="Move ROI Higher"></td>
|
||||
<td><input class="button" type="submit" id="moveNext" onclick="moveNext()" value="Move ROI Lower"></td>
|
||||
</tr>
|
||||
</table>
|
||||
<input class="move" type="submit" id="renameNumber" name="renameNumber" onclick="renameNumber()" value="Rename">
|
||||
<input class="move" type="submit" id="newNumber" name="newNumber" onclick="newNumber()" value="New">
|
||||
<input class="move" type="submit" id="removeNumber" name="removeNumber" onclick="removeNumber()" value="Remove">
|
||||
</tr>
|
||||
</table>
|
||||
</p>
|
||||
|
||||
<table>
|
||||
<colgroup>
|
||||
<col span="1" style="width: 18%;">
|
||||
<col span="1" style="width: 18%;">
|
||||
<col span="1" style="width: 64%;">
|
||||
</colgroup>
|
||||
<tr>
|
||||
<td>x: <input type="number" name="refx" id="refx" step=1 onchange="valuemanualchanged()" tabindex=2></td>
|
||||
<td>Δx: <input type="number" name="refdx" id="refdx" step=1 onchange="valuemanualchangeddx()" tabindex=4></td>
|
||||
<td><input type="checkbox" id="lockAspectRatio" name="lockAspectRatio" value="1" onclick="changelockAspectRatio()" checked tabindex=6><label for="lockAspectRatio"> Lock aspect ratio </label></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>y: <input type="number" name="refy" id="refy" step=1 onchange="valuemanualchanged()" tabindex=3></td>
|
||||
<td>Δy: <input type="number" name="refdy" id="refdy" step=1 onchange="valuemanualchanged()" tabindex=5></td>
|
||||
<td><input type="checkbox" id="lockSizes" name="lockSizes" value="1" onclick="changelockSizes()" checked tabindex=7><label for="lockSizes"> Synchronize y, Δx and Δy between ROIs</label></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2"></td>
|
||||
<td><input type="checkbox" id="CCW" name="CCW" value="0" onclick="changeCCW()" unchecked tabindex=8><label for="CCW">Counter clockwise rotation (CCW)</label></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<tr>
|
||||
<td><input class="button" type="submit" id= "newROI" name="newROI" onclick="newROI()" value="New ROI (after current)"></td>
|
||||
<td><input class="button" type="submit" id= "deleteROI" name="deleteROI" onclick="deleteROI()" value="Delete ROI"></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<select id="index" name="index" onchange="ChangeSelection()" tabindex=1>
|
||||
</select>
|
||||
</td>
|
||||
<td>
|
||||
<input class="button" type="submit" id="renameROI" name="renameROI" onclick="renameROI()" value="Rename">
|
||||
</td>
|
||||
<td>
|
||||
<input class="move" type="submit" id="moveNext" onclick="moveNext()" value="move Next">
|
||||
<input class="move" type="submit" id="movePrevious" onclick="movePrevious()" value="move Previous">
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>x: <input type="number" name="refx" id="refx" step=1 onchange="valuemanualchanged()" tabindex=2></td>
|
||||
<td>Δx: <input type="number" name="refdx" id="refdx" step=1 onchange="valuemanualchangeddx()" tabindex=4></td>
|
||||
<td><input type="checkbox" id="lockAspectRatio" name="lockAspectRatio" value="1" onclick="changelockAspectRatio()" checked tabindex=6><label for="lockAspectRatio"> Lock aspect ratio</label></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>y: <input type="number" name="refy" id="refy" step=1 onchange="valuemanualchanged()" tabindex=3></td>
|
||||
<td>Δy: <input type="number" name="refdy" id="refdy" step=1 onchange="valuemanualchanged()" tabindex=5></td>
|
||||
<td><input type="checkbox" id="lockSizes" name="lockSizes" value="1" onclick="changelockSizes()" checked tabindex=7><label for="lockSizes"> Synchronize Δx and Δy between ROIs</label></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2"></td>
|
||||
<td><input type="checkbox" id="CCW" name="CCW" value="0" onclick="changeCCW()" unchecked tabindex=8><label for="CCW"> Counter-Clockwise Rotation: </label></td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<table>
|
||||
<colgroup>
|
||||
<col span="1" style="width: 22%;">
|
||||
<col span="1" style="width: 26%;">
|
||||
<col span="1" style="width: 26%;">
|
||||
<col span="1" style="width: 26%;">
|
||||
</colgroup>
|
||||
<tr>
|
||||
<td colspan="3" style="vertical-align: bottom;"><b>Reference Image:</b></td>
|
||||
<!---<td><button class="button" id="reboot" type="button" onclick="doReboot()">Reboot device</button></td>-->
|
||||
<td><input style="font-weight:bold;" class="button" type="submit" id="saveroi" name="saveroi" onclick="SaveToConfig()" value="Save Config" tabindex=10></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="4"><canvas id="canvas" crossorigin></canvas></td>
|
||||
</tr>
|
||||
</table>
|
||||
<table>
|
||||
<tr>
|
||||
<td><input class="button" type="submit" id="saveroi" name="saveroi" onclick="SaveToConfig()" value="Save" tabindex=9>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><button class="button" id="reboot" type="button" onclick="doReboot()">Reboot to activate the changes</button></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
<script type="text/javascript" src="common.js?v=$COMMIT_HASH"></script>
|
||||
@@ -237,15 +158,16 @@
|
||||
lockSizes = false;
|
||||
domainname = getDomainname();
|
||||
|
||||
function doReboot() {
|
||||
if (confirm("Are you sure you want to reboot? Did you save your changes?")) {
|
||||
var stringota = getDomainname() + "/reboot";
|
||||
window.location = stringota;
|
||||
window.location.href = stringota;
|
||||
window.location.assign(stringota);
|
||||
window.location.replace(stringota);
|
||||
}
|
||||
|
||||
function doReboot() {
|
||||
if (confirm("Are you sure you want to reboot? Did you save your changes?")) {
|
||||
var stringota = getDomainname() + "/reboot";
|
||||
window.location = stringota;
|
||||
window.location.href = stringota;
|
||||
window.location.assign(stringota);
|
||||
window.location.replace(stringota);
|
||||
}
|
||||
}
|
||||
|
||||
function EnDisableAnalog() {
|
||||
isEnabled = document.getElementById("Category_Analog_enabled").checked;
|
||||
@@ -264,9 +186,9 @@ function EnDisableAnalog() {
|
||||
|
||||
sah1(document.getElementById("div1"), !isEnabled);
|
||||
|
||||
|
||||
cofcat["Analog"]["enabled"] = isEnabled;
|
||||
document.getElementById("saveroi").disabled = false;
|
||||
|
||||
|
||||
if (isEnabled)
|
||||
{
|
||||
UpdateROIs();
|
||||
@@ -290,10 +212,6 @@ function onNameChange(){
|
||||
}
|
||||
|
||||
function deleteROI(){
|
||||
if (!confirm("Delete the selected ROI?")) {
|
||||
return; //break out of the function early because prompt was aborted
|
||||
}
|
||||
|
||||
ROIInfo.splice(aktindex, 1);
|
||||
if (aktindex > ROIInfo.length - 1){
|
||||
aktindex = ROIInfo.length - 1;
|
||||
@@ -302,21 +220,18 @@ function deleteROI(){
|
||||
draw();
|
||||
}
|
||||
|
||||
function newROI() {
|
||||
function newROI(){
|
||||
var sel = document.getElementById("Numbers_value1");
|
||||
var _number= sel.options[sel.selectedIndex].text;
|
||||
sel = document.getElementById("index");
|
||||
var _roialt= sel.options[sel.selectedIndex].text;
|
||||
|
||||
var _roinew = prompt("Please enter a name for the new ROI", "name");
|
||||
if (_roinew === null) {
|
||||
return; //break out of the function early because prompt was aborted
|
||||
}
|
||||
var _roinew = prompt("Please enter name of new ROI", "name");
|
||||
|
||||
if (ROIInfo.length > 0)
|
||||
erg = CreateROI(_number, "analog", sel.selectedIndex, _roinew, 15, 30, ROIInfo[aktindex]["dx"], ROIInfo[aktindex]["dy"], ROIInfo[aktindex]["CCW"]=="true");
|
||||
erg = CreateROI(_number, "analog", sel.selectedIndex, _roinew, 1, 1, ROIInfo[aktindex]["dx"], ROIInfo[aktindex]["dy"], ROIInfo[aktindex]["CCW"]=="true");
|
||||
else
|
||||
erg = CreateROI(_number, "analog", sel.selectedIndex, _roinew, 15, 30, 30, 30, false);
|
||||
erg = CreateROI(_number, "analog", sel.selectedIndex, _roinew, 1, 1, 30, 30, false);
|
||||
|
||||
if (erg != "")
|
||||
firework.launch(erg, 'danger', 30000);
|
||||
@@ -360,9 +275,7 @@ function changeCCW(){
|
||||
ROIInfo[aktindex]["CCW"] = "true";
|
||||
else
|
||||
ROIInfo[aktindex]["CCW"] = "false";
|
||||
|
||||
UpdateROIs();
|
||||
|
||||
UpdateROIs();
|
||||
}
|
||||
|
||||
function ChangeSelection(){
|
||||
@@ -372,68 +285,11 @@ function ChangeSelection(){
|
||||
}
|
||||
|
||||
function SaveToConfig(){
|
||||
if (confirm("Are you sure you want to save the new analog ROI configuration?")) {
|
||||
//_zwcat = getConfigCategory();
|
||||
cofcat["Analog"]["enabled"] = document.getElementById("Category_Analog_enabled").checked;
|
||||
WriteConfigININew();
|
||||
SaveConfigToServer(domainname);
|
||||
UpdateROIs();
|
||||
document.getElementById("saveroi").disabled = true;
|
||||
|
||||
firework.launch('Configuration saved. It will get applied after next reboot', 'success', 5000);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function ShowMultiplier()
|
||||
{
|
||||
var decimalShift = 0;
|
||||
var multiplier;
|
||||
var multiplier_decshift;
|
||||
var fixedDecimals;
|
||||
var fixedDecimals_decshift;
|
||||
var NumberInfo = getNUMBERInfo();
|
||||
var CategoryInfo = getConfigCategory();
|
||||
|
||||
var sel = document.getElementById("Numbers_value1");
|
||||
var _number= sel.options[sel.selectedIndex].text;
|
||||
document.getElementById("decimalShift").value = 0;
|
||||
for (var i = 0; i < NumberInfo.length; ++i) {
|
||||
if (NumberInfo[i]["name"] == _number) {
|
||||
if (NumberInfo[i]["PostProcessing"]["DecimalShift"]["enabled"]) {
|
||||
decimalShift = NumberInfo[i]["PostProcessing"]["DecimalShift"]["value1"];
|
||||
document.getElementById("decimalShift").value=decimalShift;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (CategoryInfo["Analog"]["enabled"] == true && CategoryInfo["Digits"]["enabled"] == true) { // Digit + Analog
|
||||
multiplier = fixedDecimals = aktindex + 1;
|
||||
multiplier_decshift = fixedDecimals_decshift = multiplier - Number(decimalShift);
|
||||
|
||||
if (multiplier < 0)
|
||||
fixedDecimals = 0;
|
||||
|
||||
if (multiplier_decshift < 0)
|
||||
fixedDecimals_decshift = 0;
|
||||
|
||||
document.getElementById("multiplier").value="x" + Number(10 ** (-1*multiplier)).toFixed(fixedDecimals);
|
||||
document.getElementById("multiplier_decshift").value="x" + Number(10 ** (-1*multiplier_decshift)).toFixed(fixedDecimals_decshift);
|
||||
}
|
||||
else if (CategoryInfo["Analog"]["enabled"] == true && CategoryInfo["Digits"]["enabled"] == false) { // Only Analog
|
||||
multiplier = ROIInfo.length - 1 - aktindex;
|
||||
multiplier_decshift = fixedDecimals_decshift = multiplier + Number(decimalShift);
|
||||
|
||||
if (multiplier_decshift > 0)
|
||||
fixedDecimals_decshift = 0;
|
||||
|
||||
if (fixedDecimals_decshift < 0) {
|
||||
fixedDecimals_decshift = -1 * fixedDecimals_decshift;
|
||||
}
|
||||
|
||||
document.getElementById("multiplier").value="x" + Number(10 ** multiplier).toFixed(0);
|
||||
document.getElementById("multiplier_decshift").value="x" + Number(10 ** multiplier_decshift).toFixed(fixedDecimals_decshift);
|
||||
}
|
||||
// _zwcat = getConfigCategory();
|
||||
cofcat["Analog"]["enabled"] = document.getElementById("Category_Analog_enabled").checked;
|
||||
WriteConfigININew();
|
||||
SaveConfigToServer(domainname);
|
||||
firework.launch('Configuration got updated. It will get applied after the next reboot!', 'success', 5000);
|
||||
}
|
||||
|
||||
|
||||
@@ -449,28 +305,19 @@ function UpdateROIs(_sel){
|
||||
{
|
||||
document.getElementById("Category_Analog_enabled").checked = false;
|
||||
EnDisableAnalog();
|
||||
firework.launch('Analog ROI processing is disabled. Activate with checkbox if needed', 'warning', 10000);
|
||||
firework.launch('Analog ROIs are disabled - please enable first (Check box top left)', 'warning', 10000);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ROIInfo.length == 0){
|
||||
firework.launch('No analog ROIs defined in selected number sequence', 'warning', 10000);
|
||||
firework.launch('There are no ROIs defined. Please first create a new ROI ("New ROIs ...")', 'danger', 10000);
|
||||
document.getElementById("newROI").disabled = false;
|
||||
document.getElementById("deleteROI").disabled = true;
|
||||
document.getElementById("renameROI").disabled = true;
|
||||
document.getElementById("index").disabled = true;
|
||||
document.getElementById("multiplier").style.display = "none";
|
||||
document.getElementById("multiplier_decshift").style.display = "none";
|
||||
document.getElementById("refx").disabled = true;
|
||||
document.getElementById("refdx").disabled = true;
|
||||
document.getElementById("refy").disabled = true;
|
||||
document.getElementById("refdy").disabled = true;
|
||||
document.getElementById("lockSizes").disabled = true;
|
||||
document.getElementById("lockAspectRatio").disabled = true;
|
||||
document.getElementById("CCW").disabled = true;
|
||||
document.getElementById("saveroi").disabled = true;
|
||||
document.getElementById("renameROI").disabled = true;
|
||||
document.getElementById("moveNext").disabled = true;
|
||||
document.getElementById("movePrevious").disabled = true;
|
||||
document.getElementById("saveroi").disabled = false;
|
||||
return;
|
||||
}
|
||||
else
|
||||
@@ -479,15 +326,6 @@ function UpdateROIs(_sel){
|
||||
document.getElementById("deleteROI").disabled = false;
|
||||
document.getElementById("renameROI").disabled = false;
|
||||
document.getElementById("index").disabled = false;
|
||||
document.getElementById("multiplier").style.display = "";
|
||||
document.getElementById("multiplier_decshift").style.display = "";
|
||||
document.getElementById("refx").disabled = false;
|
||||
document.getElementById("refdx").disabled = false;
|
||||
document.getElementById("refy").disabled = false;
|
||||
document.getElementById("refdy").disabled = false;
|
||||
document.getElementById("lockSizes").disabled = false;
|
||||
document.getElementById("lockAspectRatio").disabled = false;
|
||||
document.getElementById("CCW").disabled = false;
|
||||
document.getElementById("saveroi").disabled = false;
|
||||
}
|
||||
|
||||
@@ -497,7 +335,7 @@ function UpdateROIs(_sel){
|
||||
}
|
||||
|
||||
if (aktindex > ROIInfo.length)
|
||||
aktindex = ROIInfo.length-1;
|
||||
aktindex = ROIInfo.length;
|
||||
|
||||
for (var i = 0; i < ROIInfo.length; ++i){
|
||||
var option = document.createElement("option");
|
||||
@@ -520,9 +358,7 @@ function UpdateROIs(_sel){
|
||||
document.getElementById("moveNext").disabled = false;
|
||||
if (aktindex == (ROIInfo.length-1)){
|
||||
document.getElementById("moveNext").disabled = true;
|
||||
}
|
||||
|
||||
ShowMultiplier();
|
||||
}
|
||||
|
||||
document.getElementById("lockAspectRatio").checked = lockAspectRatio;
|
||||
document.getElementById("lockSizes").checked = lockSizes;
|
||||
@@ -537,7 +373,8 @@ function UpdateROIs(_sel){
|
||||
rect.startY = ROIInfo[aktindex]["y"];
|
||||
rect.w = ROIInfo[aktindex]["dx"];
|
||||
rect.h = ROIInfo[aktindex]["dy"];
|
||||
draw();
|
||||
draw();
|
||||
|
||||
}
|
||||
|
||||
function loadCanvas(dataURL) {
|
||||
@@ -567,20 +404,10 @@ function UpdateROIs(_sel){
|
||||
var left = box.left + scrollLeft - clientLeft;
|
||||
return { top: Math.round(top), left: Math.round(left) };
|
||||
}
|
||||
|
||||
|
||||
/* hash #description open the details part of the page */
|
||||
function openDescription() {
|
||||
if(window.location.hash) {
|
||||
var hash = window.location.hash.substring(1); //Puts hash in variable, and removes the # character
|
||||
if(hash == 'description')
|
||||
document.getElementById("desc_details").open = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
function init() {
|
||||
openDescription();
|
||||
domainname = getDomainname();
|
||||
canvas.addEventListener('mousedown', mouseDown, false);
|
||||
canvas.addEventListener('mouseup', mouseUp, false);
|
||||
@@ -613,12 +440,11 @@ function UpdateROIs(_sel){
|
||||
console.log("Not all ROI have the same dX and dY, unticking the sync checkbox!");
|
||||
}
|
||||
|
||||
document.getElementById("saveroi").disabled = true;
|
||||
|
||||
drawImage();
|
||||
draw();
|
||||
}
|
||||
|
||||
|
||||
function drawImage(){
|
||||
var canvas = document.getElementById('canvas');
|
||||
var context = canvas.getContext('2d');
|
||||
@@ -657,13 +483,10 @@ function UpdateNUMBERS(_sel){
|
||||
|
||||
function renameNumber(){
|
||||
var sel = document.getElementById("Numbers_value1");
|
||||
var _delete= sel.options[sel.selectedIndex].text;
|
||||
var _numbernew = prompt("Please enter a new name for the selected number sequence", _delete);
|
||||
if (_numbernew === null) {
|
||||
return; //break out of the function early because prompt was aborted
|
||||
}
|
||||
var _delte= sel.options[sel.selectedIndex].text;
|
||||
var _numbernew = prompt("Please enter new name", _delte);
|
||||
|
||||
erg = RenameNUMBER(_delete, _numbernew);
|
||||
erg = RenameNUMBER(_delte, _numbernew);
|
||||
if (erg != "")
|
||||
firework.launch(erg, 'danger', 30000);
|
||||
else
|
||||
@@ -671,10 +494,7 @@ function renameNumber(){
|
||||
}
|
||||
|
||||
function newNumber(){
|
||||
var _numbernew = prompt("Please enter a name for the new number sequence", "name");
|
||||
if (_numbernew === null) {
|
||||
return; //break out of the function early because prompt was aborted
|
||||
}
|
||||
var _numbernew = prompt("Please enter name of new number", "name");
|
||||
|
||||
erg = CreateNUMBER(_numbernew);
|
||||
if (erg != "")
|
||||
@@ -685,13 +505,10 @@ function newNumber(){
|
||||
|
||||
|
||||
function removeNumber(){
|
||||
if (confirm("The entire number sequence will be removed (digit + analog parts). " +
|
||||
"To remove single ROI of the number sequence, use \"Delete ROI\" instead.\n" +
|
||||
"Do you really want to proceed?"))
|
||||
{
|
||||
if (confirm("This will remove the number complete (analog and digital).\nIf you only want to remove the digital ROIs, please use \"Delete ROIs\".\nDo you want to proceed?")) {
|
||||
var sel = document.getElementById("Numbers_value1");
|
||||
var _delete= sel.options[sel.selectedIndex].text;
|
||||
erg = DeleteNUMBER(_delete);
|
||||
var _delte= sel.options[sel.selectedIndex].text;
|
||||
erg = DeleteNUMBER(_delte);
|
||||
if (erg != "")
|
||||
firework.launch(erg, 'danger', 30000);
|
||||
UpdateNUMBERS();
|
||||
@@ -759,12 +576,8 @@ function drawTextBG(context, txt, x, y, padding) {
|
||||
var dx = parseInt(ROIInfo[_nb].dx) + parseInt(lw);
|
||||
var dy = parseInt(ROIInfo[_nb].dy) + parseInt(lw);
|
||||
context.strokeRect(x0, y0, dx, dy);
|
||||
|
||||
if (ROIInfo[_nb]["CCW"] != "true")
|
||||
drawTextBG(context, ROIInfo[_nb]["name"], x0+dx/2-0.5, y0-13, 5);
|
||||
else
|
||||
drawTextBG(context, ROIInfo[_nb]["name"]+" (CCW)", x0+dx/2-0.5, y0-13, 5);
|
||||
|
||||
drawTextBG(context, ROIInfo[_nb]["name"], x0+dx/2-0.5, y0-13, 5);
|
||||
|
||||
lw = 1;
|
||||
var x0 = parseInt(ROIInfo[_nb].x) - parseInt(lw/2);
|
||||
var y0 = parseInt(ROIInfo[_nb].y) - parseInt(lw/2);
|
||||
@@ -773,8 +586,7 @@ function drawTextBG(context, txt, x, y, padding) {
|
||||
context.strokeRect(x0, y0, dx, dy);
|
||||
context.lineWidth = lw;
|
||||
context.beginPath();
|
||||
// context.arc (x0+dx/2, y0+dy/2, dx/2, 0, 2 * Math.PI);
|
||||
context.ellipse(x0+dx/2, y0+dy/2, dx/2, dy/2, 0, 0, 2 * Math.PI);
|
||||
context.arc(x0+dx/2, y0+dy/2, dx/2, 0, 2 * Math.PI);
|
||||
context.moveTo(x0+dx/2, y0);
|
||||
context.lineTo(x0+dx/2, y0+dy);
|
||||
context.moveTo(x0, y0+dy/2);
|
||||
@@ -790,17 +602,11 @@ function drawTextBG(context, txt, x, y, padding) {
|
||||
var y0 = parseInt(rect.startY) - parseInt(lw/2);
|
||||
var dx = parseInt(rect.w) + parseInt(lw);
|
||||
var dy = parseInt(rect.h) + parseInt(lw);
|
||||
context.strokeRect(x0, y0, dx, dy);
|
||||
|
||||
if (ROIInfo[aktindex]["CCW"] != "true")
|
||||
drawTextBG(context, ROIInfo[aktindex]["name"], x0+dx/2, y0-11, 5);
|
||||
else
|
||||
drawTextBG(context, ROIInfo[aktindex]["name"] + " (CCW)", x0+dx/2, y0-11, 5);
|
||||
|
||||
context.strokeRect(x0, y0, dx, dy);
|
||||
drawTextBG(context, ROIInfo[aktindex]["name"], x0+dx/2, y0-11, 5);
|
||||
context.lineWidth = 1;
|
||||
context.beginPath();
|
||||
// context.arc(x0+dx/2, y0+dy/2, dx/2, 0, 2 * Math.PI);
|
||||
context.ellipse(x0+dx/2, y0+dy/2, dx/2, dy/2, 0, 0, 2 * Math.PI);
|
||||
context.arc(x0+dx/2, y0+dy/2, dx/2, 0, 2 * Math.PI);
|
||||
context.moveTo(x0+dx/2, y0);
|
||||
context.lineTo(x0+dx/2, y0+dy);
|
||||
context.moveTo(x0, y0+dy/2);
|
||||
@@ -900,7 +706,6 @@ function drawTextBG(context, txt, x, y, padding) {
|
||||
rect.startY = document.getElementById("refy").value;
|
||||
draw();
|
||||
}
|
||||
document.getElementById("saveroi").disabled = false;
|
||||
}
|
||||
|
||||
function valuemanualchangeddx(){
|
||||
@@ -916,7 +721,6 @@ function drawTextBG(context, txt, x, y, padding) {
|
||||
rect.startY = document.getElementById("refy").value;
|
||||
draw();
|
||||
}
|
||||
document.getElementById("saveroi").disabled = false;
|
||||
}
|
||||
|
||||
|
||||
@@ -926,10 +730,8 @@ function drawTextBG(context, txt, x, y, padding) {
|
||||
sel = document.getElementById("index");
|
||||
var _roialt= sel.options[sel.selectedIndex].text;
|
||||
|
||||
var _roinew = prompt("Please enter a new name for the selected ROI", _roialt);
|
||||
if (_roinew === null) {
|
||||
return; //break out of the function early because prompt was aborted
|
||||
}
|
||||
|
||||
var _roinew = prompt("Please enter new name", _roialt);
|
||||
|
||||
erg = RenameROI(_number, "analog", _roialt, _roinew);
|
||||
if (erg != "")
|
||||
@@ -940,15 +742,13 @@ function drawTextBG(context, txt, x, y, padding) {
|
||||
|
||||
function numberChanged()
|
||||
{
|
||||
aktindex = 0;
|
||||
UpdateROIs();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
init();
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
136
sd-card/html/edit_check.html
Normal file
@@ -0,0 +1,136 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<link rel="icon" href="favicon.ico?v=$COMMIT_HASH" type="image/x-icon">
|
||||
<meta charset="utf-8"/>
|
||||
<title>Check</title>
|
||||
|
||||
<style>
|
||||
h1 {font-size: 2em;}
|
||||
h2 {font-size: 1.5em; margin-block-start: 0.0em; margin-block-end: 0.2em;}
|
||||
h3 {font-size: 1.2em;}
|
||||
p {font-size: 1em;}
|
||||
|
||||
.button {
|
||||
padding: 5px 10px;
|
||||
width: 210px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
</style>
|
||||
|
||||
</head>
|
||||
|
||||
<body style="font-family: arial">
|
||||
|
||||
<table>
|
||||
<tr><td colspan="2">Result:</td></tr>
|
||||
<tr>
|
||||
<td>
|
||||
<iframe name="maincontent" id ="maincontent" width="700px" height="700px"></iframe>
|
||||
</td>
|
||||
<td style="padding-left: 15px;">
|
||||
<p>
|
||||
<input class="button" type="submit" id="take" onclick="doTake()" value="1. Take Picture">
|
||||
</p>
|
||||
<p>
|
||||
<input class="button" type="submit" id="align" onclick="doAlign()" value="2. Align Image"><br>
|
||||
</p>
|
||||
<p>
|
||||
Takes up to 2 Minutes!
|
||||
</p>
|
||||
Digits and Analog recognition not yet implemented.
|
||||
<p>
|
||||
<input class="button" type="submit" id="digits" onclick="doDigits()" value="3a. Analyse Digits">
|
||||
</p>
|
||||
<p>
|
||||
<input class="button" type="submit" id="analog" onclick="doAnalog()" value="3b Analyse Analog">
|
||||
</p>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<script type="text/javascript" src="common.js?v=$COMMIT_HASH"></script>
|
||||
<script type="text/javascript" src="readconfig.js?v=$COMMIT_HASH"></script>
|
||||
|
||||
<script type="text/javascript">
|
||||
var domainname = getDomainname();
|
||||
|
||||
function doAnalog(){
|
||||
var xhttp = new XMLHttpRequest();
|
||||
url = domainname + "/editflow?task=test_analog";
|
||||
if (domainname.length > 0){
|
||||
url = url + "&host=" + domainname;
|
||||
}
|
||||
xhttp.open("GET", url, false);
|
||||
xhttp.send();
|
||||
var html = xhttp.responseText;
|
||||
html = html.replace("src=\"/", "src=\"" + domainname + "/");
|
||||
|
||||
document.getElementById("maincontent").src = 'data:text/html,' + encodeURIComponent(html);
|
||||
}
|
||||
|
||||
|
||||
function doDigits(){
|
||||
var xhttp = new XMLHttpRequest();
|
||||
url = domainname + "/editflow?task=test_digits";
|
||||
if (domainname.length > 0){
|
||||
url = url + "&host=" + domainname;
|
||||
}
|
||||
xhttp.open("GET", url, false);
|
||||
xhttp.send();
|
||||
var html = xhttp.responseText;
|
||||
html = html.replace("src=\"/", "src=\"" + domainname + "/");
|
||||
|
||||
document.getElementById("maincontent").src = 'data:text/html,' + encodeURIComponent(html);
|
||||
}
|
||||
|
||||
|
||||
function doAlign(){
|
||||
var xhttp = new XMLHttpRequest();
|
||||
url = domainname + "/editflow?task=test_align";
|
||||
if (domainname.length > 0){
|
||||
url = url + "&host=" + domainname;
|
||||
}
|
||||
xhttp.open("GET", url, false);
|
||||
xhttp.send();
|
||||
var html = xhttp.responseText;
|
||||
html = html.replace("src=\"/", "src=\"" + domainname + "/");
|
||||
|
||||
document.getElementById("maincontent").src = 'data:text/html,' + encodeURIComponent(html);
|
||||
|
||||
document.getElementById("align").disabled = false;
|
||||
// document.getElementById("digits").disabled = false;
|
||||
// document.getElementById("analog").disabled = false;
|
||||
}
|
||||
|
||||
|
||||
function doTake(){
|
||||
var xhttp = new XMLHttpRequest();
|
||||
url = domainname + "/editflow?task=test_take";
|
||||
if (domainname.length > 0){
|
||||
url = url + "&host=" + domainname;
|
||||
}
|
||||
xhttp.open("GET", url, false);
|
||||
xhttp.send();
|
||||
var html = xhttp.responseText;
|
||||
document.getElementById("maincontent").src = 'data:text/html,' + encodeURIComponent(html);
|
||||
|
||||
document.getElementById("align").disabled = false;
|
||||
document.getElementById("digits").disabled = true;
|
||||
document.getElementById("analog").disabled = true;
|
||||
}
|
||||
|
||||
function Init(){
|
||||
domainname = getDomainname();
|
||||
document.getElementById("align").disabled = true;
|
||||
document.getElementById("digits").disabled = true;
|
||||
document.getElementById("analog").disabled = true;
|
||||
}
|
||||
|
||||
Init();
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,24 +1,25 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" xml:lang="en">
|
||||
<html>
|
||||
<head>
|
||||
<link rel="icon" href="favicon.ico?v=$COMMIT_HASH" type="image/x-icon">
|
||||
<title>Edit Config</title>
|
||||
<meta charset="UTF-8" />
|
||||
<meta charset="utf-8">
|
||||
|
||||
<style>
|
||||
h1 {font-size: 2em;}
|
||||
h2 {font-size: 1.5em; margin-block-start: 0.0em; margin-block-end: 0.2em;}
|
||||
h3 {font-size: 1.2em;}
|
||||
p {font-size: 1em;}
|
||||
h1 {font-size: 2em;}
|
||||
h2 {font-size: 1.5em; margin-block-start: 0.0em; margin-block-end: 0.2em;}
|
||||
h3 {font-size: 1.2em;}
|
||||
p {font-size: 1em;}
|
||||
|
||||
.button {
|
||||
padding: 5px 10px;
|
||||
width: 220px;
|
||||
font-size: 16px;
|
||||
}
|
||||
.button {
|
||||
padding: 5px 20px;
|
||||
width: 211px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
textarea {
|
||||
font-size: 15px;
|
||||
}
|
||||
textarea {
|
||||
font-size: 14px;
|
||||
}
|
||||
</style>
|
||||
<link href="firework.css?v=$COMMIT_HASH" rel="stylesheet">
|
||||
<script type="text/javascript" src="jquery-3.6.0.min.js?v=$COMMIT_HASH"></script>
|
||||
@@ -27,60 +28,59 @@
|
||||
|
||||
<body style="font-family: arial; padding: 0px 10px;">
|
||||
|
||||
<table style="width:660px">
|
||||
<h2>Configuration - "Config.ini" Editor</h2>
|
||||
<td>
|
||||
<textarea id="inputTextToSave" rows="30" style="width:100%"></textarea>
|
||||
</td>
|
||||
</table>
|
||||
<table>
|
||||
<tr><td><h2>Config.ini:</h2></td></tr>
|
||||
<tr>
|
||||
<td colspan="3">
|
||||
<textarea id="inputTextToSave" cols="100" rows="33"></textarea>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><button class="button" onclick="saveTextAsFile()">Save</button></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><button class="button" id="reboot" type="button" onclick="doReboot()">Reboot to activate changes</button></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<table>
|
||||
<td>
|
||||
<button class="button" onclick="saveTextAsFile()">Save Config</button>
|
||||
</td>
|
||||
<td>
|
||||
<button class="button" id="reboot" type="button" onclick="doReboot()">Reboot to activate changes</button>
|
||||
</td>
|
||||
</table>
|
||||
|
||||
<script type="text/javascript" src="common.js?v=$COMMIT_HASH"></script>
|
||||
<script type="text/javascript" src="readconfigcommon.js?v=$COMMIT_HASH"></script>
|
||||
|
||||
<script type="text/javascript">
|
||||
var canvas = document.getElementById('canvas'),
|
||||
domainname = getDomainname();
|
||||
<script type="text/javascript" src="common.js?v=$COMMIT_HASH"></script>
|
||||
<script type="text/javascript" src="readconfigcommon.js?v=$COMMIT_HASH"></script>
|
||||
|
||||
<script type="text/javascript">
|
||||
var canvas = document.getElementById('canvas'),
|
||||
domainname = getDomainname();
|
||||
|
||||
|
||||
function LoadConfigNeu() {
|
||||
domainname = getDomainname();
|
||||
loadConfig(domainname);
|
||||
document.getElementById("inputTextToSave").value = getConfig();
|
||||
}
|
||||
|
||||
function saveTextAsFile()
|
||||
{
|
||||
if (confirm("Are you sure you want to save the configuration?")) {
|
||||
FileDeleteOnServer("/config/config.ini", domainname);
|
||||
var textToSave = document.getElementById("inputTextToSave").value;
|
||||
FileSendContent(textToSave, "/config/config.ini", domainname);
|
||||
|
||||
firework.launch('Configuration saved. It will get applied after next reboot', 'success', 5000);
|
||||
}
|
||||
function LoadConfigNeu() {
|
||||
domainname = getDomainname();
|
||||
loadConfig(domainname);
|
||||
document.getElementById("inputTextToSave").value = getConfig();
|
||||
}
|
||||
|
||||
function doReboot() {
|
||||
if (confirm("Are you sure you want to reboot?")) {
|
||||
var stringota = "/reboot";
|
||||
window.location = stringota;
|
||||
window.location.href = stringota;
|
||||
window.location.assign(stringota);
|
||||
window.location.replace(stringota);
|
||||
}
|
||||
function saveTextAsFile()
|
||||
{
|
||||
if (confirm("Are you sure you want to update \"config.ini\"?")) {
|
||||
FileDeleteOnServer("/config/config.ini", domainname);
|
||||
var textToSave = document.getElementById("inputTextToSave").value;
|
||||
FileSendContent(textToSave, "/config/config.ini", domainname);
|
||||
firework.launch('Configuration got updated. It will get applied after the next reboot!', 'success', 5000);
|
||||
}
|
||||
|
||||
LoadConfigNeu();
|
||||
|
||||
</script>
|
||||
}
|
||||
|
||||
function doReboot() {
|
||||
if (confirm("Are you sure you want to reboot the ESP32?")) {
|
||||
var stringota = "/reboot";
|
||||
window.location = stringota;
|
||||
window.location.href = stringota;
|
||||
window.location.assign(stringota);
|
||||
window.location.replace(stringota);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
LoadConfigNeu();
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,212 +1,137 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" xml:lang="en">
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>Digit ROI</title>
|
||||
<link rel="icon" href="favicon.ico?v=$COMMIT_HASH" type="image/x-icon">
|
||||
<meta charset="utf-8"/>
|
||||
<title>Digit ROI's</title>
|
||||
|
||||
<style>
|
||||
h1 {font-size: 2em;}
|
||||
h2 {font-size: 1.5em; margin-block-start: 0.0em; margin-block-end: 0.2em;}
|
||||
h3 {font-size: 1.2em;}
|
||||
p {font-size: 1em;}
|
||||
<style>
|
||||
h1 {font-size: 2em;}
|
||||
h2 {font-size: 1.5em; margin-block-start: 0.0em; margin-block-end: 0.2em;}
|
||||
h3 {font-size: 1.2em;}
|
||||
p {font-size: 1em;}
|
||||
|
||||
input[type=number] {
|
||||
width: 60px;
|
||||
margin-right: 10px;
|
||||
padding: 3px 5px;
|
||||
display: inline-block;
|
||||
border: 1px solid #ccc;
|
||||
font-size: 16px;
|
||||
}
|
||||
input[type=number] {
|
||||
width: 100px;
|
||||
margin-right: 10px;
|
||||
padding: 3px 5px;
|
||||
display: inline-block;
|
||||
border: 1px solid #ccc;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
input[type=text] {
|
||||
padding: 3px 5px;
|
||||
display: inline-block;
|
||||
border: 1px solid #ccc;
|
||||
font-size: 16px;
|
||||
}
|
||||
input[type=text] {
|
||||
padding: 3px 5px;
|
||||
display: inline-block;
|
||||
border: 1px solid #ccc;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
input:out-of-range {
|
||||
background-color: rgba(255, 0, 0, 0.25);
|
||||
border: 1px solid red;
|
||||
}
|
||||
select {
|
||||
padding: 3px 5px;
|
||||
display: inline-block;
|
||||
border: 1px solid #ccc;
|
||||
font-size: 16px;
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
select {
|
||||
padding: 3px 5px;
|
||||
display: inline-block;
|
||||
border: 1px solid #ccc;
|
||||
font-size: 16px;
|
||||
margin-right: 10px;
|
||||
min-width: 100px;
|
||||
max-width: 100%;
|
||||
vertical-align: middle;
|
||||
overflow: hidden;
|
||||
}
|
||||
.button {
|
||||
padding: 5px 10px;
|
||||
width: 210px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.button {
|
||||
padding: 5px 10px;
|
||||
width: 160px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.multiplier {
|
||||
padding: 0px 0px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
th, td {
|
||||
padding: 5px 5px 5px 0px;
|
||||
}
|
||||
|
||||
table {
|
||||
width: 660px;
|
||||
padding: 5px;
|
||||
table-layout: fixed;
|
||||
}
|
||||
</style>
|
||||
|
||||
<link href="firework.css?v=$COMMIT_HASH" rel="stylesheet">
|
||||
<script type="text/javascript" src="jquery-3.6.0.min.js?v=$COMMIT_HASH"></script>
|
||||
<script type="text/javascript" src="firework.js?v=$COMMIT_HASH"></script>
|
||||
.move {
|
||||
padding: 4px 4px;
|
||||
width: 100px;
|
||||
font-size: 12px;
|
||||
}
|
||||
|
||||
th, td {
|
||||
padding: 5px 5px 5px 0px;
|
||||
}
|
||||
</style>
|
||||
<link href="firework.css?v=$COMMIT_HASH" rel="stylesheet">
|
||||
<script type="text/javascript" src="jquery-3.6.0.min.js?v=$COMMIT_HASH"></script>
|
||||
<script type="text/javascript" src="firework.js?v=$COMMIT_HASH"></script>
|
||||
</head>
|
||||
|
||||
<body style="font-family: arial; padding: 0px 10px;">
|
||||
|
||||
<h2>Digit ROI</h2>
|
||||
<details id="desc_details" style="font-size:16px">
|
||||
<summary><b>CLICK HERE</b> for usage description. More infos in documentation:
|
||||
<a href=https://jomjol.github.io/AI-on-the-edge-device-docs/ROI-Configuration/ target=_blank>ROI Configuration</a>
|
||||
</summary>
|
||||
<p>
|
||||
<b>R</b>egion <b>O</b>f <b>I</b>nterest (ROI) for digit numbers can be defined on this page. If no digit numbers need to be processed,
|
||||
disable digit processing by deselecting <b>"Digit ROI Processing"</b>.
|
||||
</p>
|
||||
<p>
|
||||
By default one number sequence (a number seqence contains of 1-x digit ROIs + 1-x analog counter ROIs which are processed together) is
|
||||
predefined and already selected in the drop down <b>"Number sequence"</b>. If you need more than one number sequence additional
|
||||
one's can be added with the buttons next to the drop down. Each number sequence will be processed separately.
|
||||
</p>
|
||||
<p>
|
||||
Using drag and drop by mouse of by manually entering the parameters into the given fields the digit ROIs can be positined to the digit numbers
|
||||
on the reference image. To have proper ROI definition please check the documentation:
|
||||
<a href=https://jomjol.github.io/AI-on-the-edge-device-docs/ROI-Configuration/ target=_blank>ROI Configuration</a>. It's very important to be
|
||||
really precise to have reliable processing. With the drop down <b>"ROI"</b> you can change between the different ROIs in the selected
|
||||
number sequence. To create new ROIs use <b>"New ROI"</b>.
|
||||
</p>
|
||||
<p>
|
||||
The order of the ROIs defines the position (and therefore the multiplication factor) within the reading sequence. The position
|
||||
in the number sequence can be changed with the buttons <b>"Move ROI Lower"</b> and <b>"Move ROI Higher"</b>. The multiplication factor which is
|
||||
shown below the ROI drop down is the multiplication factor of pure position/order in number sequence and the factor right-hand side to this is
|
||||
the additionally corrected by decimal shift setting (configuration, expert parameter, default: 0).
|
||||
</p>
|
||||
<p>
|
||||
After definition of digit ROIs is completed don't forget to save with the <b>"Save Config"</b> button!<br>
|
||||
<b>NOTE:</b> There is no need to perform a reboot after every saving or step. It's sufficient to reboot after all configuration steps
|
||||
(reference image, alignment, ROI configuration) are completed to activate new configuration.
|
||||
</p>
|
||||
</details>
|
||||
<hr />
|
||||
|
||||
<p>
|
||||
<input type="checkbox" id="Category_Digits_enabled" value="1" onclick = 'EnDisableDigits()' checked>
|
||||
<label style="font-weight: bold; font-size: larger;" for="Category_Digits_enabled">Digit ROI Processing</label>
|
||||
</p>
|
||||
<h2>Digit ROI's</h2>
|
||||
<p>On this page you define ROI's for the digits.
|
||||
See <a href=https://jomjol.github.io/AI-on-the-edge-device-docs/ROI-Configuration/ target=_blank>https://jomjol.github.io/AI-on-the-edge-device-docs/ROI-Configuration/</a> for explanations.</p>
|
||||
|
||||
<p><input type="checkbox" id="Category_Digits_enabled" value="1" onclick = 'EnDisableDigits()' checked><label for="Category_Digits_enabled">Enable Digit ROI's</label></p>
|
||||
|
||||
<p>After saving the digit ROI's, you can define the <a href=edit_analog.html>analog</a> ROI's if your meter has analog counters.<br>
|
||||
Only after those steps a reboot is required.</p>
|
||||
|
||||
|
||||
<div id="div1">
|
||||
|
||||
<table>
|
||||
<colgroup>
|
||||
<col span="1" style="width: 22%;">
|
||||
<col span="1" style="width: 26%;">
|
||||
<col span="1" style="width: 26%;">
|
||||
<col span="1" style="width: 26%;">
|
||||
</colgroup>
|
||||
<tr>
|
||||
<td colspan="4" style="padding: 0px"><class id="Numbers_text" style="color:black;">Number Sequence:</class></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<table>
|
||||
<tr>
|
||||
<canvas id="canvas" crossorigin></canvas>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<p>
|
||||
<table>
|
||||
<tr>
|
||||
<class id="Numbers_text" style="color:black;"><b>Number:</b> </class>
|
||||
<select id="Numbers_value1" onchange="numberChanged()">
|
||||
</select>
|
||||
</td>
|
||||
<td><input class="button" type="submit" id="newNumber" name="newNumber" onclick="newNumber()" value="New Sequence"></td>
|
||||
<td><input class="button" type="submit" id="renameNumber" name="renameNumber" onclick="renameNumber()" value="Rename Sequence"></td>
|
||||
<td><input class="button" type="submit" id="removeNumber" name="removeNumber" onclick="removeNumber()" value="Delete Sequence"></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<hr />
|
||||
|
||||
<table>
|
||||
<colgroup>
|
||||
<col span="1" style="width: 22%;">
|
||||
<col span="1" style="width: 26%;">
|
||||
<col span="1" style="width: 26%;">
|
||||
<col span="1" style="width: 26%;">
|
||||
</colgroup>
|
||||
<tr>
|
||||
<td style="padding: 0px">ROI:</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><select id="index" name="index" onchange="ChangeSelection()" tabindex=1></select></td>
|
||||
<td><input class="button" type="submit" id="newROI" name="newROI" onclick="newROI()" value="New ROI"></td>
|
||||
<td><input class="button" type="submit" id="renameROI" name="renameROI" onclick="renameROI()" value="Rename ROI"></td>
|
||||
<td><input class="button" type="submit" id="deleteROI" name="deleteROI" onclick="deleteROI()" value="Delete ROI"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td class="multiplier">Multiplier: <output type="text" id="multiplier" name="multiplier"></output><br>
|
||||
(only based on order)
|
||||
</td>
|
||||
<td class="multiplier">Multiplier: <output type="text" id="multiplier_decshift" name="multiplier_decshift"></output><br>
|
||||
(order + decimal shift: <output type="text" id="decimalShift" name="decimalShift"></output>)
|
||||
</td>
|
||||
<td><input class="button" type="submit" id="movePrevious" onclick="movePrevious()" value="Move ROI Higher"></td>
|
||||
<td><input class="button" type="submit" id="moveNext" onclick="moveNext()" value="Move ROI Lower"></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<input class="move" type="submit" id="renameNumber" name="renameNumber" onclick="renameNumber()" value="Rename">
|
||||
<input class="move" type="submit" id="newNumber" name="newNumber" onclick="newNumber()" value="New">
|
||||
<input class="move" type="submit" id="removeNumber" name="removeNumber" onclick="removeNumber()" value="Remove">
|
||||
</tr>
|
||||
</table>
|
||||
</p>
|
||||
|
||||
<table>
|
||||
<colgroup>
|
||||
<col span="1" style="width: 18%;">
|
||||
<col span="1" style="width: 18%;">
|
||||
<col span="1" style="width: 64%;">
|
||||
</colgroup>
|
||||
<tr>
|
||||
<td>x: <input type="number" name="refx" id="refx" step=1 onchange="valuemanualchanged()" tabindex=2></td>
|
||||
<td>Δx: <input type="number" name="refdx" id="refdx" step=1 onchange="valuemanualchangeddx()" tabindex=4></td>
|
||||
<td><input type="checkbox" id="lockAspectRatio" name="lockAspectRatio" value="1" onclick="changelockAspectRatio()" checked tabindex=6><label for="lockAspectRatio"> Lock aspect ratio </label></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>y: <input type="number" name="refy" id="refy" step=1 onchange="valuemanualchanged()" tabindex=3></td>
|
||||
<td>Δy: <input type="number" name="refdy" id="refdy" step=1 onchange="valuemanualchanged()" tabindex=5></td>
|
||||
<td><input type="checkbox" id="lockSizes" name="lockSizes" value="1" onclick="changelockSizes()" checked tabindex=7><label for="lockSizes"> Synchronize y, Δx and Δy between ROIs</label></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2"></td>
|
||||
<td><input type="checkbox" id="lockSpaceEquidistant" name="lockSpaceEquidistant" value="1" onclick="changeLockSpaceEquidistant()" checked tabindex=8>
|
||||
<label for="lockSpaceEquidistant">Keep equidistance of <input type="number" name="space" id="space" step=1 onchange="valuemanualchangedspace()" tabindex=9> between all ROIs</label>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><input class="button" type="submit" id="newROI" name="newROI" onclick="newROI()" value="New ROI (after current)"></td>
|
||||
<td><input class="button" type="submit" id="deleteROI" name="deleteROI" onclick="deleteROI()" value="Delete ROI"></td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<select id="index" name="index" onchange="ChangeSelection()" tabindex=1>
|
||||
</select>
|
||||
</td>
|
||||
<td>
|
||||
<input class="button" type="submit" id="renameROI" name="renameROI" onclick="renameROI()" value="Rename">
|
||||
<td>
|
||||
<input class="move" type="submit" id="moveNext" onclick="moveNext()" value="move Next">
|
||||
<input class="move" type="submit" id="movePrevious" onclick="movePrevious()" value="move Previous">
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>x: <input type="number" name="refx" id="refx" step=1 onchange="valuemanualchanged()" tabindex=2></td>
|
||||
<td>Δx: <input type="number" name="refdx" id="refdx" step=1 onchange="valuemanualchangeddx()" tabindex=4></td>
|
||||
<td><input type="checkbox" id="lockAspectRatio" name="lockAspectRatio" value="1" onclick="changelockAspectRatio()" checked tabindex=6><label for="lockAspectRatio"> Lock aspect ratio </label></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>y: <input type="number" name="refy" id="refy" step=1 onchange="valuemanualchanged()" tabindex=3></td>
|
||||
<td>Δy: <input type="number" name="refdy" id="refdy" step=1 onchange="valuemanualchanged()" tabindex=5></td>
|
||||
<td><input type="checkbox" id="lockSizes" name="lockSizes" value="1" onclick="changelockSizes()" checked tabindex=7><label for="lockSizes"> Synchronize y, Δx and Δy between ROIs</label></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2"></td>
|
||||
<td ><input type="checkbox" id="lockSpaceEquidistant" name="lockSpaceEquidistant" value="1" onclick="changeLockSpaceEquidistant()" checked tabindex=9>
|
||||
<label for="lockSpaceEquidistant">Keep equidistance of <input type="number" name="space" id="space" step=1 onchange="valuemanualchangedspace()" tabindex=8> between all ROIs</label></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<table>
|
||||
<colgroup>
|
||||
<col span="1" style="width: 22%;">
|
||||
<col span="1" style="width: 26%;">
|
||||
<col span="1" style="width: 26%;">
|
||||
<col span="1" style="width: 26%;">
|
||||
</colgroup>
|
||||
<tr>
|
||||
<td colspan="3" style="vertical-align: bottom;"><b>Reference Image:</b></td>
|
||||
<td><input style="font-weight:bold;" class="button" type="submit" id="saveroi" name="saveroi" onclick="SaveToConfig()" value="Save Config" tabindex=10></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="4"><canvas id="canvas" crossorigin></canvas></td>
|
||||
</tr>
|
||||
</table>
|
||||
<tr>
|
||||
<td><input class="button" type="submit" id="saveroi" name="saveroi" onclick="SaveToConfig()" value="Save" tabindex=10>
|
||||
<p>Proceed to update the <a href=edit_analog.html>analog</a> ROI's when you are done or <a href=reboot_page.html>reboot</a> if there are no analogue counters.</p></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<script type="text/javascript" src="common.js?v=$COMMIT_HASH"></script>
|
||||
<script type="text/javascript" src="readconfigcommon.js?v=$COMMIT_HASH"></script>
|
||||
@@ -258,7 +183,6 @@ function EnDisableDigits() {
|
||||
sah1(document.getElementById("div1"), !isEnabled);
|
||||
|
||||
cofcat["Digits"]["enabled"] = isEnabled;
|
||||
document.getElementById("saveroi").disabled = false;
|
||||
|
||||
if (isEnabled)
|
||||
{
|
||||
@@ -284,10 +208,6 @@ function onNameChange(){
|
||||
}
|
||||
|
||||
function deleteROI(){
|
||||
if (!confirm("Delete the selected ROI?")) {
|
||||
return; //break out of the function early because prompt was aborted
|
||||
}
|
||||
|
||||
ROIInfo.splice(aktindex, 1);
|
||||
if (aktindex > ROIInfo.length - 1){
|
||||
aktindex = ROIInfo.length - 1;
|
||||
@@ -302,10 +222,7 @@ function newROI() {
|
||||
sel = document.getElementById("index");
|
||||
var _roialt= sel.options[sel.selectedIndex].text;
|
||||
|
||||
var _roinew = prompt("Please enter a name for the new ROI", "name");
|
||||
if (_roinew === null) {
|
||||
return; //break out of the function early because prompt was aborted
|
||||
}
|
||||
var _roinew = prompt("Please enter name of new ROI", "name");
|
||||
|
||||
if (ROIInfo.length > 0) {
|
||||
if (ROIInfo.length > 1) {
|
||||
@@ -315,7 +232,7 @@ function newROI() {
|
||||
parseInt(ROIInfo[sel.selectedIndex].y), ROIInfo[aktindex]["dx"], ROIInfo[aktindex]["dy"], 0);
|
||||
}
|
||||
else
|
||||
erg = CreateROI(_number, "digit", sel.selectedIndex, _roinew, 15, 30, 30, 51, 0);
|
||||
erg = CreateROI(_number, "digit", sel.selectedIndex, _roinew, 1, 1, 30, 51, 0);
|
||||
|
||||
if (erg != "")
|
||||
firework.launch(erg, 'danger', 30000);
|
||||
@@ -357,7 +274,7 @@ function changelockSizes(){
|
||||
valuemanualchangedspace();
|
||||
|
||||
if (!lockSizes) {
|
||||
firework.launch("In most cases it's advised to keep the y, Δx and Δy identical!", 'warning', 10000);
|
||||
firework.launch("For best results it is in most cases advised to keep the y, Δx and Δy identical!", 'warning', 10000);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -379,51 +296,11 @@ function ChangeSelection(){
|
||||
}
|
||||
|
||||
function SaveToConfig(){
|
||||
if (confirm("Are you sure you want to save the new digit ROI configuration?")) {
|
||||
// _zwcat = getConfigCategory();
|
||||
cofcat["Digits"]["enabled"] = document.getElementById("Category_Digits_enabled").checked;
|
||||
WriteConfigININew();
|
||||
SaveConfigToServer(domainname);
|
||||
UpdateROIs();
|
||||
document.getElementById("saveroi").disabled = true;
|
||||
|
||||
firework.launch('Configuration saved. It will get applied after next reboot', 'success', 5000);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function ShowMultiplier()
|
||||
{
|
||||
var decimalShift = 0;
|
||||
var multiplier;
|
||||
var multiplier_decshift;
|
||||
var fixedDecimals_decshift;
|
||||
var NumberInfo = getNUMBERInfo();
|
||||
|
||||
var sel = document.getElementById("Numbers_value1");
|
||||
var _number= sel.options[sel.selectedIndex].text;
|
||||
document.getElementById("decimalShift").value = 0;
|
||||
for (var i = 0; i < NumberInfo.length; ++i) {
|
||||
if (NumberInfo[i]["name"] == _number) {
|
||||
if (NumberInfo[i]["PostProcessing"]["DecimalShift"]["enabled"]) {
|
||||
decimalShift = NumberInfo[i]["PostProcessing"]["DecimalShift"]["value1"];
|
||||
document.getElementById("decimalShift").value = decimalShift;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
multiplier = ROIInfo.length - 1 - aktindex;
|
||||
multiplier_decshift = fixedDecimals_decshift = multiplier + Number(decimalShift);
|
||||
|
||||
if (multiplier_decshift > 0)
|
||||
fixedDecimals_decshift = 0;
|
||||
|
||||
if (fixedDecimals_decshift < 0) {
|
||||
fixedDecimals_decshift = -1*fixedDecimals_decshift;
|
||||
}
|
||||
|
||||
document.getElementById("multiplier").value="x" + Number(10 ** multiplier).toFixed(0);
|
||||
document.getElementById("multiplier_decshift").value="x" + Number(10 ** multiplier_decshift).toFixed(fixedDecimals_decshift);
|
||||
// _zwcat = getConfigCategory();
|
||||
cofcat["Digits"]["enabled"] = document.getElementById("Category_Digits_enabled").checked;
|
||||
WriteConfigININew();
|
||||
SaveConfigToServer(domainname);
|
||||
firework.launch('Configuration got updated. It will get applied after the next reboot!', 'success', 5000);
|
||||
}
|
||||
|
||||
|
||||
@@ -439,28 +316,19 @@ function UpdateROIs(_sel){
|
||||
{
|
||||
document.getElementById("Category_Digits_enabled").checked = false;
|
||||
EnDisableDigits();
|
||||
firework.launch('Digit ROI processing is disabled. Activate with checkbox if needed', 'warning', 10000);
|
||||
firework.launch('Digital ROIs are disabled - please enable first (Check box top left)', 'warning', 10000);
|
||||
return;
|
||||
}
|
||||
|
||||
if (ROIInfo.length == 0){
|
||||
firework.launch('No digit ROIs defined in selected number sequence', 'warning', 10000);
|
||||
firework.launch('There are no ROIs defined. Please first create a new ROI ("New ROIs ...")', 'danger', 10000);
|
||||
document.getElementById("newROI").disabled = false;
|
||||
document.getElementById("deleteROI").disabled = true;
|
||||
document.getElementById("renameROI").disabled = true;
|
||||
document.getElementById("index").disabled = true;
|
||||
document.getElementById("multiplier").style.display = "none";
|
||||
document.getElementById("multiplier_decshift").style.display = "none";
|
||||
document.getElementById("refx").disabled = true;
|
||||
document.getElementById("refdx").disabled = true;
|
||||
document.getElementById("refy").disabled = true;
|
||||
document.getElementById("refdy").disabled = true;
|
||||
document.getElementById("lockSizes").disabled = true;
|
||||
document.getElementById("lockAspectRatio").disabled = true;
|
||||
document.getElementById("lockSpaceEquidistant").disabled = true;
|
||||
document.getElementById("saveroi").disabled = true;
|
||||
document.getElementById("renameROI").disabled = true;
|
||||
document.getElementById("moveNext").disabled = true;
|
||||
document.getElementById("movePrevious").disabled = true;
|
||||
document.getElementById("saveroi").disabled = false;
|
||||
return;
|
||||
}
|
||||
else
|
||||
@@ -469,15 +337,6 @@ function UpdateROIs(_sel){
|
||||
document.getElementById("deleteROI").disabled = false;
|
||||
document.getElementById("renameROI").disabled = false;
|
||||
document.getElementById("index").disabled = false;
|
||||
document.getElementById("multiplier").style.display = "";
|
||||
document.getElementById("multiplier_decshift").style.display = "";
|
||||
document.getElementById("refx").disabled = false;
|
||||
document.getElementById("refdx").disabled = false;
|
||||
document.getElementById("refy").disabled = false;
|
||||
document.getElementById("refdy").disabled = false;
|
||||
document.getElementById("lockSizes").disabled = false;
|
||||
document.getElementById("lockAspectRatio").disabled = false;
|
||||
document.getElementById("lockSpaceEquidistant").disabled = false;
|
||||
document.getElementById("saveroi").disabled = false;
|
||||
}
|
||||
|
||||
@@ -487,7 +346,7 @@ function UpdateROIs(_sel){
|
||||
}
|
||||
|
||||
if (aktindex > ROIInfo.length)
|
||||
aktindex = ROIInfo.length-1;
|
||||
aktindex = ROIInfo.length;
|
||||
|
||||
for (var i = 0; i < ROIInfo.length; ++i){
|
||||
var option = document.createElement("option");
|
||||
@@ -510,9 +369,7 @@ function UpdateROIs(_sel){
|
||||
document.getElementById("moveNext").disabled = false;
|
||||
if (aktindex == (ROIInfo.length-1)){
|
||||
document.getElementById("moveNext").disabled = true;
|
||||
}
|
||||
|
||||
ShowMultiplier();
|
||||
}
|
||||
|
||||
document.getElementById("lockAspectRatio").checked = lockAspectRatio;
|
||||
document.getElementById("lockSizes").checked = lockSizes;
|
||||
@@ -533,7 +390,7 @@ function UpdateROIs(_sel){
|
||||
rect.startY = ROIInfo[aktindex]["y"];
|
||||
rect.w = ROIInfo[aktindex]["dx"];
|
||||
rect.h = ROIInfo[aktindex]["dy"];
|
||||
draw();
|
||||
draw();
|
||||
}
|
||||
|
||||
function loadCanvas(dataURL) {
|
||||
@@ -563,20 +420,8 @@ function UpdateROIs(_sel){
|
||||
var left = box.left + scrollLeft - clientLeft;
|
||||
return { top: Math.round(top), left: Math.round(left) };
|
||||
}
|
||||
|
||||
|
||||
/* hash #description open the details part of the page */
|
||||
function openDescription() {
|
||||
if(window.location.hash) {
|
||||
var hash = window.location.hash.substring(1); //Puts hash in variable, and removes the # character
|
||||
if(hash == 'description')
|
||||
document.getElementById("desc_details").open = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function init() {
|
||||
openDescription();
|
||||
domainname = getDomainname();
|
||||
canvas.addEventListener('mousedown', mouseDown, false);
|
||||
canvas.addEventListener('mouseup', mouseUp, false);
|
||||
@@ -636,8 +481,6 @@ function UpdateROIs(_sel){
|
||||
document.getElementById("space").value = space;
|
||||
}
|
||||
|
||||
document.getElementById("saveroi").disabled = true;
|
||||
|
||||
drawImage();
|
||||
draw();
|
||||
}
|
||||
@@ -680,13 +523,10 @@ function UpdateNUMBERS(_sel){
|
||||
|
||||
function renameNumber(){
|
||||
var sel = document.getElementById("Numbers_value1");
|
||||
var _delete= sel.options[sel.selectedIndex].text;
|
||||
var _numbernew = prompt("Please enter a new name for the selected number sequence", _delete);
|
||||
if (_numbernew === null) {
|
||||
return; //break out of the function early because prompt was aborted
|
||||
}
|
||||
var _delte= sel.options[sel.selectedIndex].text;
|
||||
var _numbernew = prompt("Please enter new name", _delte);
|
||||
|
||||
erg = RenameNUMBER(_delete, _numbernew);
|
||||
erg = RenameNUMBER(_delte, _numbernew);
|
||||
if (erg != "")
|
||||
firework.launch(erg, 'danger', 30000);
|
||||
else
|
||||
@@ -694,27 +534,21 @@ function renameNumber(){
|
||||
}
|
||||
|
||||
function newNumber(){
|
||||
var _numbernew = prompt("Please enter a name for the new number sequence", "name");
|
||||
if (_numbernew === null) {
|
||||
return; //break out of the function early because prompt was aborted
|
||||
}
|
||||
var _numbernew = prompt("Please enter name of new number", "name");
|
||||
|
||||
erg = CreateNUMBER(_numbernew);
|
||||
if (erg != "")
|
||||
firework.launch(erg, 'danger', 30000);
|
||||
firework.launch(erg, 'danger', 30000);
|
||||
else
|
||||
UpdateNUMBERS(_numbernew);
|
||||
}
|
||||
|
||||
|
||||
function removeNumber(){
|
||||
if (confirm("The entire number sequence will be removed (digit + analog parts). " +
|
||||
"To remove single ROI of the number sequence, use \"Delete ROI\" instead.\n" +
|
||||
"Do you really want to proceed?"))
|
||||
{
|
||||
if (confirm("This will remove the number complete (analog and digital).\nIf you only want to remove the digital ROIs, please use \"Delete ROIs\".\nDo you want to proceed?")) {
|
||||
var sel = document.getElementById("Numbers_value1");
|
||||
var _delete= sel.options[sel.selectedIndex].text;
|
||||
erg = DeleteNUMBER(_delete);
|
||||
var _delte= sel.options[sel.selectedIndex].text;
|
||||
erg = DeleteNUMBER(_delte);
|
||||
if (erg != "")
|
||||
firework.launch(erg, 'danger', 30000);
|
||||
UpdateNUMBERS();
|
||||
@@ -921,7 +755,6 @@ function draw() {
|
||||
}
|
||||
draw();
|
||||
}
|
||||
document.getElementById("saveroi").disabled = false;
|
||||
}
|
||||
|
||||
function valuemanualchangeddx(){
|
||||
@@ -947,7 +780,6 @@ function draw() {
|
||||
|
||||
draw();
|
||||
}
|
||||
document.getElementById("saveroi").disabled = false;
|
||||
}
|
||||
|
||||
function valuemanualchangedspace(){
|
||||
@@ -989,10 +821,8 @@ function draw() {
|
||||
sel = document.getElementById("index");
|
||||
var _roialt= sel.options[sel.selectedIndex].text;
|
||||
|
||||
var _roinew = prompt("Please enter a new name for the selected ROI", _roialt);
|
||||
if (_roinew === null) {
|
||||
return; //break out of the function early because prompt was aborted
|
||||
}
|
||||
|
||||
var _roinew = prompt("Please enter new name", _roialt);
|
||||
|
||||
erg = RenameROI(_number, "digit", _roialt, _roinew);
|
||||
if (erg != "")
|
||||
@@ -1003,7 +833,6 @@ function draw() {
|
||||
|
||||
function numberChanged()
|
||||
{
|
||||
aktindex = 0;
|
||||
UpdateROIs();
|
||||
}
|
||||
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" xml:lang="en">
|
||||
<html style="width: fit-content">
|
||||
<head>
|
||||
<link rel="icon" href="favicon.ico?v=$COMMIT_HASH" type="image/x-icon">
|
||||
<title>AI on the edge</title>
|
||||
<meta charset="UTF-8" />
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
|
||||
<style>
|
||||
h1 {font-size: 2em; margin-block-end: 0.3em;}
|
||||
@@ -17,7 +19,7 @@ p {font-size: 1em;}
|
||||
|
||||
<body style="font-family: arial">
|
||||
|
||||
<h2>Welcome to the setup of the AI-on-the-edge-device</h2>
|
||||
<h2>Welcome to the Setup of the Digitizer</h2>
|
||||
|
||||
|
||||
<p>
|
||||
@@ -25,48 +27,41 @@ p {font-size: 1em;}
|
||||
</p>
|
||||
|
||||
<p>
|
||||
This is the first time you started the device after the initial installation. You have been automatically routed to the <b>initial setup procedure</b>.
|
||||
With the prodecure the basic setup of your device within seven steps will be performed. After completion of all steps the setup mode will be completed
|
||||
and the device restarts automatically to the regular web interface.<br>
|
||||
Note: All settings of the initial setup will be also accessible using regular web interface.
|
||||
See documentation: <a href=https://jomjol.github.io/AI-on-the-edge-device-docs/initial-setup target=_blank>Initial setup procedure</a> for additional explanations.</p>
|
||||
This is the first time you started the digitizer after the initial installation. You have been automatically routed to the <b>initial setup procedure</b>.
|
||||
Here you adjust the settings for your meter within five steps. In the final step the inital setup will be disabled and it will restart to the normal mode.
|
||||
All settings will also be accessible there. See <a href=https://jomjol.github.io/AI-on-the-edge-device-docs/initial-setup target=_blank>
|
||||
https://jomjol.github.io/AI-on-the-edge-device-docs/initial-setup</a> for additional explanations.</p>
|
||||
</p>
|
||||
<p> You can navigate forward and backward during the setup with the buttons "Next Step" and "Previous Step".<br>
|
||||
With the button "Abort Setup" the setup will be skipped and abort screen will be presented.<br>
|
||||
To restart the setup process, push the button "Restart Setup".
|
||||
<p>You can navigate forward and backward during the setup with the buttons "Next" and "Previous".<br><br>
|
||||
<span color=red>Do not forget to save in each step before heading to another step!</span><br>
|
||||
</p>
|
||||
<p>
|
||||
This is an overview over the seven steps:
|
||||
This is an overview over the five steps:
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<ol>
|
||||
<li><p>Adjust <b>lens focus</b> and check for <b>reflections of flashlight</b>.<br>
|
||||
Ensure you camera lens has proper focus to object and flashlight do not create any distoring reflections.</p></li>
|
||||
<li><p>Create the <b>reference image</b>.<br>
|
||||
<li><p>Create the <b>Reference Image</b>.<br>
|
||||
It is the base for the position referencing and the identification of the digits and counters.</p></li>
|
||||
<li><p>Define two unique <b>alignment marker</b>.<br>
|
||||
They are used to perform an orientation alignment of the taken camera images before further processing</p></li>
|
||||
<li></p>Define <b>ROI's</b> for the <b>digits</b>.<br>
|
||||
<li><p>Define two unique <b>Reference Marks</b>.<br>
|
||||
They is used to align the individual camera images and identify the absolut positions.</p></li>
|
||||
<li></p>Define <b>ROI's</b> for the <b>Digits</b>.<br>
|
||||
They will be used to digitize the digit part of your meter.<br>
|
||||
NOTE: If your meter has no digits, this step can be skipped.</p></li>
|
||||
<li>Define <b>ROI's</b> for the <b>analog counters</b>.<br>
|
||||
If your meter has no digits, this step can be skipped.</p></li>
|
||||
<li>Define <b>ROI's</b>> for the <b>Analog Counters</b>.<br>
|
||||
They will be used to digitize the analog part of your meter.<br>
|
||||
NOTE: If your meter has no analog counters, this step can be skipped.</p></li>
|
||||
<li><p><b>Additional configuration:</b> List of all parameters<br>
|
||||
Further configuration of your device can be done here.<br>
|
||||
NOTE: This can also be performed later with regular web interface, e.g. to setup any publishing service like MQTT</p>
|
||||
</li>
|
||||
<li><p><b>Setup Completion:</b> End/Abort setup mode<br>
|
||||
In the final step the setup mode needs to be properly terminated by pushing the button in this page.<br>
|
||||
NOTE: This is important, otherwise the setup mode is recalled again after reboot.</p>
|
||||
</li>
|
||||
If your meter has no analog counters, this step can be skipped.</p></li>
|
||||
<li><p><b>General Settings</b><br>
|
||||
Further configuration of your device.</p></li>
|
||||
</ol>
|
||||
|
||||
<p>Please be patient when switching to another step. The device takes some time to load all needed information!</p>
|
||||
|
||||
<p>After step 5 the setup is completed, you then can reboot and starts into the normal operation mode.</p>
|
||||
|
||||
<p>If you need support, have a look to the <a href=https://jomjol.github.io/AI-on-the-edge-device-docs target=_blank>documentation</a> or the <a href=https://github.com/jomjol/AI-on-the-edge-device/discussions target=_blank>discussion</a> pages.</p>
|
||||
|
||||
<p><b>Have fun with your AI-on-the-edge-device!</b></p>
|
||||
<p><b>Have fun with your digitizer!</b></p>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" xml:lang="en">
|
||||
<html style="width: fit-content">
|
||||
<head>
|
||||
<link rel="icon" href="favicon.ico?v=$COMMIT_HASH" type="image/x-icon">
|
||||
<title>AI on the edge</title>
|
||||
<meta charset="UTF-8" />
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
|
||||
<style>
|
||||
h1 {font-size: 2em; margin-block-end: 0.3em;}
|
||||
@@ -12,8 +14,8 @@ p {font-size: 1em;}
|
||||
|
||||
|
||||
.button {
|
||||
padding: 5px 10px;
|
||||
width: 205px;
|
||||
padding: 5px 20px;
|
||||
width: 211px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
@@ -26,16 +28,15 @@ p {font-size: 1em;}
|
||||
|
||||
<body style="font-family: arial">
|
||||
|
||||
<h4>Initial setup aborted!</h4>
|
||||
<h4>Step 6: Setup Completed!</h4>
|
||||
|
||||
<p>You have <b>aborted</b> the initial setup!</p>
|
||||
<p>Once you push the button below, the setup mode will be ended and the device will be automatically restart to regular web interface.
|
||||
Please be aware: The configuration of the device is not or only parly adapted to your needs!<br>
|
||||
Configuration can still be adapted / completed using regular web interface.
|
||||
<p>Congratulations, you completed the setup and are now ready to reboot to the normal mode!</p>
|
||||
<p>Once you have pushed the button below, the setup modus will be left and the digitizer will restart to normal operation mode.<br>
|
||||
The Web Interface will automatically reload. It will take some minutes until you get the first reading.
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<button class="button" onclick="reboot()">Abort Setup + Reboot</button>
|
||||
<button class="button" onclick="reboot()">Leave Setup Modus and Reboot to Normal modus</button>
|
||||
</p>
|
||||
|
||||
<script type="text/javascript" src="common.js?v=$COMMIT_HASH"></script>
|
||||
@@ -43,12 +44,15 @@ p {font-size: 1em;}
|
||||
<script type="text/javascript" src="readconfigcommon.js?v=$COMMIT_HASH"></script>
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
var canvas = document.getElementById('canvas'),
|
||||
domainname = getDomainname();
|
||||
aktstatu = 0;
|
||||
|
||||
function reboot() {
|
||||
if (confirm("Do you want to abort the setup mode and switch to regular web interface?")) {
|
||||
if (confirm("Do you want to leave the configuration mode and restart the ESP32?")) {
|
||||
domainname = getDomainname();
|
||||
if (!loadConfig(domainname)) {
|
||||
firework.launch('Setup mode could not be deactivated! Please try again!', 'danger', 30000);
|
||||
firework.launch('Setup Modus could not be deactivated! Please try again!', 'danger', 30000);
|
||||
return;
|
||||
}
|
||||
ParseConfig();
|
||||
@@ -59,11 +63,12 @@ p {font-size: 1em;}
|
||||
WriteConfigININew();
|
||||
SaveConfigToServer(domainname);
|
||||
|
||||
var stringota = getDomainname() + "/reboot";
|
||||
parent.location = stringota;
|
||||
parent.location.href = stringota;
|
||||
parent.location.assign(stringota);
|
||||
parent.location.replace(stringota);
|
||||
|
||||
var stringota = "/reboot";
|
||||
window.location = stringota;
|
||||
window.location.href = stringota;
|
||||
window.location.assign(stringota);
|
||||
window.location.replace(stringota);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,74 +0,0 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" xml:lang="en">
|
||||
<head>
|
||||
<title>AI on the edge</title>
|
||||
<meta charset="UTF-8" />
|
||||
|
||||
<style>
|
||||
h1 {font-size: 2em; margin-block-end: 0.3em;}
|
||||
h2 {font-size: 1.5em;margin-block-start: 0.3em;}
|
||||
h3 {font-size: 1.2em;}
|
||||
p {font-size: 1em;}
|
||||
|
||||
|
||||
.button {
|
||||
padding: 5px 10px;
|
||||
width: 205px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
|
||||
</style>
|
||||
<link href="firework.css?v=$COMMIT_HASH" rel="stylesheet">
|
||||
<script type="text/javascript" src="jquery-3.6.0.min.js?v=$COMMIT_HASH"></script>
|
||||
<script type="text/javascript" src="firework.js?v=$COMMIT_HASH"></script>
|
||||
</head>
|
||||
|
||||
<body style="font-family: arial">
|
||||
|
||||
<h4>Step 7 / 7: Initial setup completed!</h4>
|
||||
|
||||
<p>
|
||||
Congratulations! You have completed the initial setup and you are now ready to restart to the regular operation mode!
|
||||
</p>
|
||||
<p>
|
||||
Once you push the button below, the setup mode will be completed and the device will be automatically restart to regular web interface.
|
||||
If configuration is error free, the device will automatically start with first processing. It will take some time until you get the first reading.
|
||||
</p>
|
||||
<p>
|
||||
<button class="button" onclick="reboot()">Complete Setup + Reboot</button>
|
||||
</p>
|
||||
|
||||
<script type="text/javascript" src="common.js?v=$COMMIT_HASH"></script>
|
||||
<script type="text/javascript" src="readconfigparam.js?v=$COMMIT_HASH"></script>
|
||||
<script type="text/javascript" src="readconfigcommon.js?v=$COMMIT_HASH"></script>
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
function reboot() {
|
||||
if (confirm("Do you want to complete the setup mode and switch to regular web interface?")) {
|
||||
domainname = getDomainname();
|
||||
if (!loadConfig(domainname)) {
|
||||
firework.launch('Setup mode could not be deactivated! Please try again!', 'danger', 30000);
|
||||
return;
|
||||
}
|
||||
ParseConfig();
|
||||
param = getConfigParameters();
|
||||
param["System"]["SetupMode"]["enabled"] = true;
|
||||
param["System"]["SetupMode"]["value1"] = "false";
|
||||
|
||||
WriteConfigININew();
|
||||
SaveConfigToServer(domainname);
|
||||
|
||||
var stringota = getDomainname() + "/reboot";
|
||||
parent.location = stringota;
|
||||
parent.location.href = stringota;
|
||||
parent.location.assign(stringota);
|
||||
parent.location.replace(stringota);
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,175 +1,100 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" xml:lang="en">
|
||||
<html>
|
||||
<head>
|
||||
<title>Reference Image</title>
|
||||
<meta charset="utf-8"/>
|
||||
|
||||
<style>
|
||||
h1 {font-size: 2em;}
|
||||
h2 {font-size: 1.5em; margin-block-start: 0.0em; margin-block-end: 0.2em;}
|
||||
h3 {font-size: 1.2em;}
|
||||
p {font-size: 1em;}
|
||||
<link rel="icon" href="favicon.ico?v=$COMMIT_HASH" type="image/x-icon">
|
||||
<title>Reference Image</title>
|
||||
<meta charset="utf-8"/>
|
||||
|
||||
<style>
|
||||
h1 {font-size: 2em;}
|
||||
h2 {font-size: 1.5em; margin-block-start: 0.0em; margin-block-end: 0.2em;}
|
||||
h3 {font-size: 1.2em;}
|
||||
p {font-size: 1em;}
|
||||
|
||||
input[type=number] {
|
||||
width: 60px;
|
||||
margin-right: 10px;
|
||||
padding: 3px 5px;
|
||||
display: inline-block;
|
||||
border: 1px solid #ccc;
|
||||
font-size: 16px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
input[type=number] {
|
||||
width: 100px;
|
||||
margin-right: 10px;
|
||||
padding: 3px 5px;
|
||||
display: inline-block;
|
||||
border: 1px solid #ccc;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
input:out-of-range {
|
||||
background-color: rgba(255, 0, 0, 0.25);
|
||||
border: 1px solid red;
|
||||
}
|
||||
.button {
|
||||
padding: 5px 10px;
|
||||
width: 210px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
input:invalid {
|
||||
background-color: rgba(255, 0, 0, 0.25);
|
||||
border: 1px solid red;
|
||||
}
|
||||
|
||||
.button {
|
||||
padding: 5px 10px;
|
||||
width: 205px;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
th, td {
|
||||
padding: 5px 5px 5px 0px;
|
||||
}
|
||||
|
||||
table {
|
||||
width: 660px;
|
||||
padding: 5px;
|
||||
}
|
||||
</style>
|
||||
|
||||
<link href="firework.css?v=$COMMIT_HASH" rel="stylesheet">
|
||||
<script type="text/javascript" src="jquery-3.6.0.min.js?v=$COMMIT_HASH"></script>
|
||||
<script type="text/javascript" src="firework.js?v=$COMMIT_HASH"></script>
|
||||
table {
|
||||
padding: 5px;
|
||||
}
|
||||
</style>
|
||||
<link href="firework.css?v=$COMMIT_HASH" rel="stylesheet">
|
||||
<script type="text/javascript" src="jquery-3.6.0.min.js?v=$COMMIT_HASH"></script>
|
||||
<script type="text/javascript" src="firework.js?v=$COMMIT_HASH"></script>
|
||||
</head>
|
||||
|
||||
<body style="font-family: arial; padding: 0px 10px;">
|
||||
<h2>Reference Image</h2>
|
||||
<details id="desc_details" style="font-size:16px">
|
||||
<summary><b>CLICK HERE</b> for usage description. More infos in documentation:
|
||||
<a href=https://jomjol.github.io/AI-on-the-edge-device-docs/Reference-Image/ target=_blank>Reference Image</a>
|
||||
</summary>
|
||||
<p>
|
||||
The reference image is the base image on which the alignment markers, digit ROIs and anlog ROIs will be defined.
|
||||
</p>
|
||||
<p>
|
||||
Firstly the actual saved reference image is shown. If you start with the setup from scratch a default image is shown as placeholder.
|
||||
Use the button <b>"Create New Reference"</b> to start creation of your own reference image. After selecting the button a new image will be taken
|
||||
all configured parameter will be applied to the shown image. With the button <b>"Update Image"</b> you can update the image again (still all parameter
|
||||
get applied to the new image).
|
||||
</p>
|
||||
<p>
|
||||
To have reliable evaluation processing a properly horizontal aligned evaluation area is mandatory. Using the parameters "Rotation angle" and
|
||||
"Rotation angle (Fine-tune)" the image can be rotated in both directions. The resulting rotation anlge is used to prerotate the image before
|
||||
the alignment algorithm is processed to compensate only small misalignments. Further information can be found in documenation:
|
||||
<a href=https://jomjol.github.io/AI-on-the-edge-device-docs/Reference-Image/ target=_blank>Reference Image</a>
|
||||
</p>
|
||||
<p>
|
||||
After setting up your reference image don't forget to save with the <b>"Save New Reference"</b> button!<br>
|
||||
<b>NOTE:</b> There is no need to perform a reboot after every saving or step. It's sufficient to reboot after all configuration steps
|
||||
(reference image, alignment, ROI configuration) are completed to activate new configuration.
|
||||
</p>
|
||||
</details>
|
||||
<hr />
|
||||
<p>On this page you define the Reference Image.
|
||||
See <a href=https://jomjol.github.io/AI-on-the-edge-device-docs/Reference-Image/ target=_blank>https://jomjol.github.io/AI-on-the-edge-device-docs/Reference-Image/</a> for explanations.</p>
|
||||
<p>After saving a new Reference Image, make sure to update the <a href=edit_alignment.html>Alignment Marks</a> and then
|
||||
the <a href=edit_digits.html>digit</a> resp. <a href=edit_analog.html>analog</a> ROI's.<br>
|
||||
Only after those steps a reboot is required.</p>
|
||||
|
||||
<table>
|
||||
<colgroup>
|
||||
<col span="1" style="width: 33.3%;">
|
||||
<col span="1" style="width: 33.3%;">
|
||||
<col span="1" style="width: 33.3%;">
|
||||
</colgroup>
|
||||
<tr>
|
||||
<td><input class="button" type="button" value="Show Actual Reference" onclick="showReference(param)"></td>
|
||||
<td><input class="button" type="button" id="startreference" value="Create New Reference" onclick="loadRawImage(false)"></td>
|
||||
<td><input class="button" type="submit" id="take" onclick="doTake()" value="Update Image">
|
||||
</tr>
|
||||
</table>
|
||||
<table>
|
||||
<colgroup>
|
||||
<col span="1" style="width: 32%;">
|
||||
<col span="1" style="width: 28%;">
|
||||
<col span="1" style="width: 18%;">
|
||||
<col span="1" style="width: 22%;">
|
||||
</colgroup>
|
||||
<tr>
|
||||
<td><label for="mirror" id="labelmirror">Mirror image:</label></td>
|
||||
<td><input type="checkbox" id="mirror" name="mirror" value="1" onchange="drawRotated()"></td>
|
||||
<td>
|
||||
<class id="TakeImage_LEDIntensity_text" style="color:black;">LED intensity:</class>
|
||||
</td>
|
||||
<td>
|
||||
<input required style="clear: both" type="number" id="TakeImage_LEDIntensity_value1" size="13" value="0" min="0" max="100"
|
||||
oninput="(!validity.rangeOverflow||(value=100)) && (!validity.rangeUnderflow||(value=0)) &&
|
||||
(!validity.stepMismatch||(value=parseInt(this.value)));">
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><label for="flip" id="labelflip">Flip image size:</label></td>
|
||||
<td><input type="checkbox" id="flip" name="flip" value="1" onchange="drawRotated()"></td>
|
||||
<td>
|
||||
<class id="TakeImage_Brightness_text" style="color:black;">Brightness:</class>
|
||||
</td>
|
||||
<td>
|
||||
<input style="clear: both; width: 80%;vertical-align:middle" type="range" id="TakeImage_Brightness_value1" size="13" value=0 min="-2" max="2" oninput="this.nextElementSibling.value = this.value">
|
||||
<output id="TakeImage_Brightness_value1_output" style="vertical-align:middle; min-width:15px; padding-right:5px; text-align:right; float:left">0</output>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><label for="prerotateangle">Rotation angle:</label></td>
|
||||
<td>
|
||||
<input required type="number" id="prerotateangle" name="prerotateangle" value="0" min="-360" max="360" onchange="drawRotated()"
|
||||
oninput="(!validity.rangeOverflow||(value=360)) && (!validity.rangeUnderflow||(value=-360)) &&
|
||||
(!validity.stepMismatch||(value=parseInt(this.value)));">degree
|
||||
</td>
|
||||
<td>
|
||||
<class id="TakeImage_Contrast_text" style="color:black;">Contrast:</class>
|
||||
</td>
|
||||
<td>
|
||||
<input style="clear: both; width: 80%;vertical-align:middle" type="range" id="TakeImage_Contrast_value1" size="13" value=0 min="-2" max="2" oninput="this.nextElementSibling.value = this.value">
|
||||
<output id="TakeImage_Contrast_value1_output" style="vertical-align:middle; min-width:15px; padding-right:5px; text-align:right; float:left">0</output>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><label for="finerotate">Rotation angle (Fine-tune):</label></td>
|
||||
<td>
|
||||
<input required type="number" id="finerotate" name="finerotate" value=0.0 min="-1" max="1" step="0.1" onchange="drawRotated()"
|
||||
oninput="(!validity.rangeOverflow||(value=1)) && (!validity.rangeUnderflow||(value=-1)) &&
|
||||
(!validity.stepMismatch||(value=parseInt(this.value)));">degree
|
||||
</td>
|
||||
<td>
|
||||
<class id="TakeImage_Saturation_text" style="color:black;">Saturation:</class>
|
||||
</td>
|
||||
<td>
|
||||
<input style="clear: both; width: 80%;vertical-align:middle" type="range" id="TakeImage_Saturation_value1" size="13" value=0 min="-2" max="2" oninput="this.nextElementSibling.value = this.value">
|
||||
<output id="TakeImage_Saturation_value1_output" style="vertical-align:middle; min-width:15px; padding-right:5px; text-align:right; float:left">0</output>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<table>
|
||||
<colgroup>
|
||||
<col span="1" style="width: 33.3%;">
|
||||
<col span="1" style="width: 33.3%;">
|
||||
<col span="1" style="width: 33.3%;">
|
||||
</colgroup>
|
||||
<tr>
|
||||
<td style="vertical-align: bottom;"><b>Reference Image:</b></td>
|
||||
<td></td>
|
||||
<td>
|
||||
<input style="font-weight:bold;" class="button" type="button" id="updatereferenceimage" value="Save New Reference" onclick="SaveReference()">
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="3"><canvas id="canvas"></canvas></td>
|
||||
</tr>
|
||||
</table>
|
||||
<tr>
|
||||
<td><input class="button" type="button" value="Show Actual Reference" onclick="showReference(param)"></td>
|
||||
<td><input class="button" type="button" value="Create New Reference" onclick="loadRawImage()"></td>
|
||||
<td><input class="button" type="submit" id="take" onclick="doTake()" value="Take Image"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td style="padding-top: 10px"><label for="mirror" id="labelmirror">Mirror Image:</label></td>
|
||||
<td style="padding-top: 10px"><input type="checkbox" id="mirror" name="mirror" value="1" onchange="drawRotated()"></td>
|
||||
<td>
|
||||
<class id="TakeImage_LEDIntensity_text" style="color:black;">LEDIntensity: </class>
|
||||
<input type="number" id="TakeImage_LEDIntensity_value1" size="13" value=0 min="0" max="100" style="float: right; clear: both;">
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
|
||||
<td><label for="flip" id="labelflip">Flip Image Size:</label></td>
|
||||
<td><input type="checkbox" id="flip" name="flip" value="1" onchange="drawRotated()"></td>
|
||||
<td>
|
||||
<class id="TakeImage_Brightness_text" style="color:black;">Brightness: </class>
|
||||
<input type="number" id="TakeImage_Brightness_value1" size="13" value=0 min="-2" max="2" style="float: right; clear: both;">
|
||||
</td>
|
||||
|
||||
</tr>
|
||||
<tr>
|
||||
<td><label for="mirror">Pre-rotate Angle:</label></td>
|
||||
<td><input type="number" id="prerotateangle" name="prerotateangle" value="0" min="-360" max="360" onchange="drawRotated()">Degrees</td>
|
||||
<td>
|
||||
<class id="TakeImage_Contrast_text" style="color:black;">Contrast</class>
|
||||
<input type="number" id="TakeImage_Contrast_value1" size="13" value=0 min="-2" max="2" style="float: right; clear: both;">
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><label for="mirror">Fine Alignment:</label></td>
|
||||
<td><input type="number" id="finerotate" name="finerotate" value=0.0 min="-1" max="1" step="0.2" onchange="drawRotated()">Degrees</td>
|
||||
<td>
|
||||
<class id="TakeImage_Saturation_text" style="color:black;">Saturation</class>
|
||||
<input type="number" id="TakeImage_Saturation_value1" size="13" value=0 min="-2" max="2" style="float: right; clear: both;">
|
||||
</td>
|
||||
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<table>
|
||||
<tr>
|
||||
<td><canvas id="canvas"></canvas></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td><input class="button" type="button" id="updatereferenceimage" value="Save" onclick="SaveReference()">
|
||||
<p>Proceed to update the <a href=edit_alignment.html>Alignment Marks</a> when you are done.</p></td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
<script type="text/javascript" src="common.js?v=$COMMIT_HASH"></script>
|
||||
@@ -177,6 +102,7 @@
|
||||
<script type="text/javascript" src="readconfigparam.js?v=$COMMIT_HASH"></script>
|
||||
|
||||
|
||||
|
||||
<script language="JavaScript">
|
||||
var canvas = document.getElementById('canvas'),
|
||||
ctx = canvas.getContext('2d'),
|
||||
@@ -184,8 +110,7 @@
|
||||
domainname = getDomainname();
|
||||
isActReference = false;
|
||||
param;
|
||||
|
||||
|
||||
|
||||
function doReboot() {
|
||||
if (confirm("Are you sure you want to reboot? Did you save the config?")) {
|
||||
var stringota = getDomainname() + "/reboot";
|
||||
@@ -196,7 +121,6 @@
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function doTake(){
|
||||
var xhttp = new XMLHttpRequest();
|
||||
if (param["TakeImage"]["Brightness"].found && param["TakeImage"]["Brightness"].enabled)
|
||||
@@ -220,24 +144,15 @@
|
||||
xhttp.open("GET", url, false);
|
||||
xhttp.send();
|
||||
|
||||
firework.launch('Taking updated image...', 'success', 5000);
|
||||
loadRawImage(true);
|
||||
|
||||
loadRawImage();
|
||||
}
|
||||
|
||||
|
||||
function loadRawImage(new_image) {
|
||||
if (new_image) {
|
||||
url = getDomainname() + "/img_tmp/raw.jpg" + "?session=" + Math.floor((Math.random() * 1000000) + 1);
|
||||
document.getElementById("updatereferenceimage").disabled = false;
|
||||
}
|
||||
else {
|
||||
document.getElementById("updatereferenceimage").disabled = true;
|
||||
doTake();
|
||||
}
|
||||
|
||||
|
||||
function loadRawImage(){
|
||||
url = getDomainname() + "/img_tmp/raw.jpg" + "?session=" + Math.floor((Math.random() * 1000000) + 1);
|
||||
document.getElementById("finerotate").disabled = false;
|
||||
document.getElementById("prerotateangle").disabled = false;
|
||||
document.getElementById("startreference").disabled = true;
|
||||
document.getElementById("updatereferenceimage").disabled = false;
|
||||
document.getElementById("take").disabled = false;
|
||||
if (param["Alignment"]["InitialMirror"].found)
|
||||
document.getElementById("mirror").disabled = false;
|
||||
@@ -273,22 +188,14 @@
|
||||
// document.getElementById("TakeImage_Contrast_value1").disabled = false;
|
||||
|
||||
isActReference = false;
|
||||
loadCanvas(url, true);
|
||||
}
|
||||
|
||||
loadCanvas(url);
|
||||
drawRotated();
|
||||
}
|
||||
|
||||
function showReference(_param){
|
||||
url = getDomainname() + "/fileserver/config/reference.jpg" + "?session=" + Math.floor((Math.random() * 1000000) + 1);
|
||||
|
||||
if (_param["Alignment"]["InitialRotate"].value1 < 0) {
|
||||
document.getElementById("prerotateangle").value = Math.ceil(_param["Alignment"]["InitialRotate"].value1);
|
||||
}
|
||||
else {
|
||||
document.getElementById("prerotateangle").value = Math.floor(_param["Alignment"]["InitialRotate"].value1);
|
||||
}
|
||||
|
||||
document.getElementById("finerotate").value = (Number(_param["Alignment"]["InitialRotate"].value1) -
|
||||
Number(document.getElementById("prerotateangle").value)).toFixed(1);
|
||||
url = getDomainname() + "/fileserver/config/reference.jpg" + "?session=" + Math.floor((Math.random() * 1000000) + 1);;
|
||||
document.getElementById("finerotate").value = 0;
|
||||
document.getElementById("prerotateangle").value = _param["Alignment"]["InitialRotate"].value1;
|
||||
|
||||
if (_param["Alignment"]["InitialMirror"].found && (_param["Alignment"]["InitialMirror"].value1 == "true"))
|
||||
document.getElementById("mirror").checked = true;
|
||||
@@ -299,7 +206,6 @@
|
||||
document.getElementById("finerotate").disabled = true;
|
||||
document.getElementById("prerotateangle").disabled = true;
|
||||
document.getElementById("updatereferenceimage").disabled = true;
|
||||
document.getElementById("startreference").disabled = false;
|
||||
document.getElementById("take").disabled = true;
|
||||
document.getElementById("TakeImage_Brightness_value1").disabled = true;
|
||||
document.getElementById("TakeImage_Saturation_value1").disabled = true;
|
||||
@@ -318,10 +224,10 @@
|
||||
document.getElementById("flip").disabled = true;
|
||||
|
||||
isActReference = true;
|
||||
loadCanvas(url, false);
|
||||
loadCanvas(url);
|
||||
drawRotated(false, true);
|
||||
}
|
||||
|
||||
|
||||
|
||||
function dataURLtoBlob(dataurl) {
|
||||
var arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1],
|
||||
bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n);
|
||||
@@ -330,12 +236,10 @@
|
||||
}
|
||||
return new Blob([u8arr], {type:mime});
|
||||
}
|
||||
|
||||
|
||||
|
||||
function SaveReference(){
|
||||
if (confirm("Are you sure you want to save the new reference image configuration?")) {
|
||||
param["Alignment"]["InitialRotate"].value1 = (Number(document.getElementById("prerotateangle").value) +
|
||||
Number(document.getElementById("finerotate").value)).toFixed(1);
|
||||
if (confirm("Are you sure you want to update the Reference Image?")) {
|
||||
param["Alignment"]["InitialRotate"].value1 = document.getElementById("prerotateangle").value;
|
||||
|
||||
if ((param["Alignment"]["InitialMirror"].found == true) && (document.getElementById("mirror").checked))
|
||||
{
|
||||
@@ -364,28 +268,22 @@
|
||||
|
||||
WriteConfigININew();
|
||||
SaveConfigToServer(getDomainname());
|
||||
document.getElementById("updatereferenceimage").disabled = true;
|
||||
|
||||
SaveCanvasToImage(canvas, "/config/reference.jpg", true, getDomainname());
|
||||
showReference(param);
|
||||
//UpdatePage();
|
||||
|
||||
firework.launch('Reference image configuration saved. It will get applied after next reboot', 'success', 5000);
|
||||
UpdatePage();
|
||||
firework.launch('Reference got saved. It will get applied after the next reboot!', 'success', 5000);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function loadCanvas(dataURL, grid) {
|
||||
function loadCanvas(dataURL) {
|
||||
var canvas = document.getElementById('canvas');
|
||||
var context = canvas.getContext('2d');
|
||||
|
||||
imageObj.onload = function() {
|
||||
canvas.width = this.width;
|
||||
canvas.height = this.height;
|
||||
if (grid)
|
||||
drawRotated(true);
|
||||
else
|
||||
drawRotated(false);
|
||||
drawRotated();
|
||||
};
|
||||
|
||||
imageObj.src = dataURL;
|
||||
@@ -405,19 +303,7 @@
|
||||
return { top: Math.round(top), left: Math.round(left) };
|
||||
}
|
||||
|
||||
|
||||
/* hash #description open the details part of the page */
|
||||
function openDescription() {
|
||||
if(window.location.hash) {
|
||||
var hash = window.location.hash.substring(1); //Puts hash in variable, and removes the # character
|
||||
if(hash == 'description')
|
||||
document.getElementById("desc_details").open = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function init() {
|
||||
openDescription();
|
||||
canvas.addEventListener('mousemove', mouseMove, false);
|
||||
loadConfig(getDomainname());
|
||||
ParseConfig();
|
||||
@@ -453,11 +339,10 @@
|
||||
showReference(param);
|
||||
}
|
||||
|
||||
|
||||
function UpdateInput() {
|
||||
WriteParameter(param, category, "TakeImage", "Brightness", false, true);
|
||||
WriteParameter(param, category, "TakeImage", "Contrast", false, true);
|
||||
WriteParameter(param, category, "TakeImage", "Saturation", false, true);
|
||||
WriteParameter(param, category, "TakeImage", "Brightness", false);
|
||||
WriteParameter(param, category, "TakeImage", "Contrast", false);
|
||||
WriteParameter(param, category, "TakeImage", "Saturation", false);
|
||||
WriteParameter(param, category, "TakeImage", "LEDIntensity", false);
|
||||
}
|
||||
|
||||
@@ -480,7 +365,7 @@
|
||||
}
|
||||
|
||||
|
||||
function WriteParameter(_param, _category, _cat, _name, _optional, outval = false, _select = false, _anzpara = 1){
|
||||
function WriteParameter(_param, _category, _cat, _name, _optional, _select = false, _anzpara = 1){
|
||||
if (_param[_cat][_name]["found"]){
|
||||
if (_optional) {
|
||||
document.getElementById(_cat+"_"+_name+"_enabled").checked = _param[_cat][_name]["enabled"];
|
||||
@@ -504,8 +389,7 @@
|
||||
document.getElementById(_cat+"_"+_name+"_value"+j).value = _param[_cat][_name]["value"+j];
|
||||
}
|
||||
}
|
||||
if (outval)
|
||||
document.getElementById(_cat+"_"+_name+"_value1_output").value = document.getElementById(_cat+"_"+_name+"_value1").value;
|
||||
|
||||
}
|
||||
else {
|
||||
if (_optional) {
|
||||
@@ -519,7 +403,7 @@
|
||||
}
|
||||
|
||||
|
||||
function drawRotated(_grid = true) {
|
||||
function drawRotated(_grid = true, _isreference = false){
|
||||
finerot= parseFloat(document.getElementById("finerotate").value);
|
||||
prerot = parseFloat(document.getElementById("prerotateangle").value);
|
||||
mirror = document.getElementById("mirror").checked;
|
||||
@@ -571,12 +455,12 @@
|
||||
|
||||
|
||||
context.restore();
|
||||
if (_grid == true && !isActReference){
|
||||
drawGrid();
|
||||
}
|
||||
|
||||
if (_grid)
|
||||
drawGrid();
|
||||
}
|
||||
|
||||
|
||||
function drawGrid(){
|
||||
var canvas = document.getElementById('canvas');
|
||||
var ctx = canvas.getContext('2d');
|
||||
@@ -605,13 +489,8 @@
|
||||
ctx.restore();
|
||||
}
|
||||
|
||||
|
||||
function mouseMove(e) {
|
||||
if (isActReference)
|
||||
drawRotated(false);
|
||||
else
|
||||
drawRotated(true);
|
||||
|
||||
drawRotated();
|
||||
var canvas = document.getElementById('canvas');
|
||||
var context = canvas.getContext('2d');
|
||||
|
||||
@@ -629,8 +508,8 @@
|
||||
context.stroke();
|
||||
}
|
||||
|
||||
|
||||
init();
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
|
||||
@@ -1,33 +1,34 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" xml:lang="en">
|
||||
|
||||
<html style="width: fit-content">
|
||||
<head>
|
||||
<link rel="icon" href="favicon.ico?v=$COMMIT_HASH" type="image/x-icon">
|
||||
<title>AI on the edge</title>
|
||||
<meta charset="UTF-8" />
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
|
||||
<style>
|
||||
|
||||
h1 {font-size: 2em; margin-block-end: 0.3em;}
|
||||
h2 {font-size: 1.5em;margin-block-start: 0.3em;}
|
||||
h3 {font-size: 1.2em;}
|
||||
p {font-size: 1em;}
|
||||
|
||||
|
||||
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body style="font-family: arial">
|
||||
|
||||
<h4>Step 1 / 7: Adjust Focus And Verify Flashlight</h4>
|
||||
Firstly you have find a proper mounting position and potentially have to adjust the focus of the camera lens to get a sharp and crisp image.
|
||||
This <b>live stream with flashlight on</b> could be helpful for this task. More details about adjusting the camera lens can be found here:
|
||||
<a href=https://jomjol.github.io/AI-on-the-edge-device-docs/Reference-Image/#focus target=_blank>Focus Adjustment</a><br>
|
||||
Additionally it should be verfied that the flashlight is not creating any distrubing reflection in the processing relevant areas.
|
||||
Beside using the built-in internal flash LED it's also possible to attach additional external LEDs to the device to have more possiblities
|
||||
to get proper light condition. Please read the documentation if you'd like to use extenal LEDs:
|
||||
<a href=https://jomjol.github.io/AI-on-the-edge-device-docs/External-LED/ target=_blank>Installation Of External LEDs</a>
|
||||
<p>
|
||||
NOTE: The flashlight indensity is set to default (50%) for initial verfication in this step and can be modified in next step. After modification
|
||||
you can come back to this step if you'd like to test with adjusted light intensity.<br>
|
||||
The live stream can also be called at any time also after setup mode is completed on regular web interface.
|
||||
</p>
|
||||
<h4>Step 1: Define a Reference Image</h4>
|
||||
The reference image is the base to define the digits, counters and references positions.
|
||||
<p>
|
||||
Firstly you see the default image. Use the Button "Create New Reference" to start to create your own reference image.<br>
|
||||
Most important feature is a straight alignment of the image. Use the Pre-rotate angle and the fine alignment to adjust the rotation of the image.
|
||||
</p>
|
||||
<p>
|
||||
Don't forget to save your changes with the <b>"Save"</b> button!
|
||||
</p>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,21 +1,34 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" xml:lang="en">
|
||||
|
||||
<html style="width: fit-content">
|
||||
<head>
|
||||
<link rel="icon" href="favicon.ico?v=$COMMIT_HASH" type="image/x-icon">
|
||||
<title>AI on the edge</title>
|
||||
<meta charset="UTF-8" />
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
|
||||
<style>
|
||||
h1 {font-size: 2em; margin-block-end: 0.3em;}
|
||||
h2 {font-size: 1.5em;margin-block-start: 0.3em;}
|
||||
h3 {font-size: 1.2em;}
|
||||
p {font-size: 1em;}
|
||||
|
||||
|
||||
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body style="font-family: arial">
|
||||
|
||||
<h4>Step 2 / 7: Create A Reference Image</h4>
|
||||
<h4>Step 2: Define two Alignment Marks</h4>
|
||||
Two opposite alignment marks are needed to identify unique fix points on the image.
|
||||
<p>
|
||||
Mark the reference by drag and dop with the mouse or with the coordinates and push <b>"Update Reference"</b>.
|
||||
<br>
|
||||
You can switch between the two reference with <b>"Select Reference"</b>.
|
||||
</p>
|
||||
<p>
|
||||
Don't forget to save your changes with the <b>"Save"</b> button!
|
||||
</p>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,21 +1,36 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" xml:lang="en">
|
||||
|
||||
<html style="width: fit-content">
|
||||
<head>
|
||||
<link rel="icon" href="favicon.ico?v=$COMMIT_HASH" type="image/x-icon">
|
||||
<title>AI on the edge</title>
|
||||
<meta charset="UTF-8" />
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
|
||||
<style>
|
||||
|
||||
h1 {font-size: 2em; margin-block-end: 0.3em;}
|
||||
h2 {font-size: 1.5em;margin-block-start: 0.3em;}
|
||||
h3 {font-size: 1.2em;}
|
||||
p {font-size: 1em;}
|
||||
|
||||
|
||||
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body style="font-family: arial">
|
||||
|
||||
<h4>Step 3 / 7: Definement Of Alignment Marker</h4>
|
||||
<h4>Step 3: Define ROI's for your Digits</h4>
|
||||
Here you define your digits you want to read. If you have more than one number on the reading you can define several numbers with the <b>"Number"</b> selector. There you can also define new numbers.
|
||||
<p>
|
||||
With the drop down menue <b>"ROI x"</b> you can change between the different digits. Mark them with the mouse or the coordinates.
|
||||
<br>
|
||||
To create new ROIs use <b>"New ROIs"</b>. The order of the ROIs defines the positon within the reading. <br>
|
||||
You can change it with <b>"move Next" / "move Previous"</b>.
|
||||
</p>
|
||||
<p>
|
||||
Don't forget to save your changes with the <b>"Save"</b> button!
|
||||
</p>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,21 +1,35 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" xml:lang="en">
|
||||
|
||||
<html style="width: fit-content">
|
||||
<head>
|
||||
<link rel="icon" href="favicon.ico?v=$COMMIT_HASH" type="image/x-icon">
|
||||
<title>AI on the edge</title>
|
||||
<meta charset="UTF-8" />
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
|
||||
<style>
|
||||
h1 {font-size: 2em; margin-block-end: 0.3em;}
|
||||
h2 {font-size: 1.5em;margin-block-start: 0.3em;}
|
||||
h3 {font-size: 1.2em;}
|
||||
p {font-size: 1em;}
|
||||
|
||||
|
||||
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body style="font-family: arial">
|
||||
|
||||
<h4>Step 4 / 7: Configuration Of ROIs For Digit Numbers</h4>
|
||||
<h4>Step 4: Define ROI's for your Analog Counters</h4>
|
||||
Here you define your analog counters you want to read. If you have more than one number on the reading you can define several numbers with the <b>"Number"</b> selector. There you can also define new numbers. If you do not have analog counters delete all ROIs.
|
||||
<p>
|
||||
With the drop down menue <b>"ROI x"</b> you can change between the different counters. Mark them with the mouse or the coordinates.
|
||||
<br>
|
||||
To create new ROIs use <b>"New ROIs"</b>. The order of the ROIs defines the positon within the reading. <br>
|
||||
You can change it with <b>"move Next" / "move Previous"</b>.
|
||||
</p>
|
||||
<p>
|
||||
Don't forget to save your changes with the <b>"Save"</b> button!
|
||||
</p>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,21 +1,31 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" xml:lang="en">
|
||||
|
||||
<html style="width: fit-content">
|
||||
<head>
|
||||
<link rel="icon" href="favicon.ico?v=$COMMIT_HASH" type="image/x-icon">
|
||||
<title>AI on the edge</title>
|
||||
<meta charset="UTF-8" />
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
|
||||
<style>
|
||||
<style>
|
||||
h1 {font-size: 2em; margin-block-end: 0.3em;}
|
||||
h2 {font-size: 1.5em;margin-block-start: 0.3em;}
|
||||
h3 {font-size: 1.2em;}
|
||||
p {font-size: 1em;}
|
||||
|
||||
|
||||
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body style="font-family: arial">
|
||||
|
||||
<h4>Step 5 / 7: Configuration Of ROIs For Analog Counters</h4>
|
||||
<h4>Step 5: General Configuration Settings</h4>
|
||||
<p>Here you can define additional settings. The default settings should fit for a normal/initial setup.</p>
|
||||
<p>You will also be able to change them later, so don't worry if you do not understand the parameters yet!</p>
|
||||
</p>
|
||||
<p>
|
||||
Don't forget to save your changes with the <b>"Save"</b> button!
|
||||
</p>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
</html>
|
||||
|
||||
@@ -1,23 +1 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" xml:lang="en">
|
||||
|
||||
<head>
|
||||
<title>AI on the edge</title>
|
||||
<meta charset="UTF-8" />
|
||||
|
||||
<style>
|
||||
h1 {font-size: 2em; margin-block-end: 0.3em;}
|
||||
h2 {font-size: 1.5em;margin-block-start: 0.3em;}
|
||||
h3 {font-size: 1.2em;}
|
||||
p {font-size: 1em;}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body style="font-family: arial">
|
||||
|
||||
<h4>Step 6 / 7: Configuration Page: List Of All Parameters</h4>
|
||||
<p>
|
||||
NOTE: All parameter can be edited later in the regular web interface. So don't worry if you do not understand the parameters yet!
|
||||
</p>
|
||||
</body>
|
||||
</html>
|
||||
<!-- This page is never shown -->
|
||||
@@ -1 +0,0 @@
|
||||
<!-- This page is never shown -->
|
||||
@@ -1,15 +1,9 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" xml:lang="en">
|
||||
<html>
|
||||
<head>
|
||||
<link href="/firework.css?v=$COMMIT_HASH" rel="stylesheet">
|
||||
<script type="text/javascript" src="/jquery-3.6.0.min.js?v=$COMMIT_HASH"></script>
|
||||
<script type="text/javascript" src="/firework.js?v=$COMMIT_HASH"></script>
|
||||
<style>
|
||||
h1 {font-size: 2em;}
|
||||
h2 {font-size: 1.5em; margin-block-start: 0.0em; margin-block-end: 0.2em;}
|
||||
h3 {font-size: 1.2em;}
|
||||
p {font-size: 1em;}
|
||||
|
||||
#files_table {
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
border-collapse: collapse;
|
||||
@@ -33,172 +27,147 @@
|
||||
padding-top: 12px;
|
||||
padding-bottom: 12px;
|
||||
text-align: left;
|
||||
background-color:lightgrey;
|
||||
color: black;
|
||||
background-color: #0011ff;
|
||||
color: white;
|
||||
}
|
||||
|
||||
input[type=file] {
|
||||
padding: 5px 0px;
|
||||
display: inline-block;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
input[type=text] {
|
||||
padding: 5px 10px;
|
||||
display: inline-block;
|
||||
border: 1px solid #ccc;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
.button {
|
||||
padding: 4px 10px;
|
||||
width: 100px;
|
||||
font-size: 16px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
</body>
|
||||
<table class="fixed" border="0" width=100% style="font-family: arial">
|
||||
</body>
|
||||
<table class="fixed" border="0" width=100% style="font-family: arial">
|
||||
<tr><td>
|
||||
<h2>Content on SD-Card</h2>
|
||||
</td>
|
||||
<td rowspan="2" width="500px">
|
||||
<table border="0">
|
||||
<tr>
|
||||
<td style="vertical-align: top;width: 300px;">
|
||||
<h2>Fileserver</h2>
|
||||
<td>
|
||||
<label for="newfile">Upload a file</label>
|
||||
</td>
|
||||
<td rowspan="2">
|
||||
<table border="0" style="width:100%">
|
||||
<tr>
|
||||
<td style="width:80px">
|
||||
<label for="newfile">Source</label>
|
||||
</td>
|
||||
<td colspan="2">
|
||||
<input id="newfile" type="file" onchange="setpath()" style="width:100%;">
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>
|
||||
<label for="filepath">Destination</label>
|
||||
</td>
|
||||
<td>
|
||||
<input id="filepath" type="text" style="width:94%;">
|
||||
</td>
|
||||
<td>
|
||||
<button id="upload" type="button" class="button" onclick="upload()">Upload</button>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<td colspan="2">
|
||||
<input id="newfile" type="file" onchange="setpath()" style="width:100%;">
|
||||
</td>
|
||||
</tr>
|
||||
<tr></tr>
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
<button style="font-size:16px; padding: 5px 10px" id="dirup" type="button" onclick="dirup()" disabled>🡹 Directory up</button>
|
||||
<span style="padding-left:15px" id="currentpath"></span>
|
||||
<td>
|
||||
<label for="filepath">Set path on server</label>
|
||||
</td>
|
||||
<td>
|
||||
<input id="filepath" type="text" style="width:100%;">
|
||||
</td>
|
||||
<td>
|
||||
<button id="upload" type="button" onclick="upload()">Upload</button>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</td></tr>
|
||||
<tr>
|
||||
<td>
|
||||
<span id="currentpath"></span> <button id="dirup" type="button" onclick="dirup()" disabled>🠑 Directory up</button>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<script type="text/javascript" src="/common.js?v=$COMMIT_HASH">
|
||||
</script>
|
||||
<script language="JavaScript">
|
||||
function setpath() {
|
||||
var fileserverpraefix = "/fileserver";
|
||||
var anz_zeichen_fileserver = fileserverpraefix.length;
|
||||
var default_path = window.location.pathname.substring(anz_zeichen_fileserver) + document.getElementById("newfile").files[0].name;
|
||||
document.getElementById("filepath").value = default_path;
|
||||
}
|
||||
<script type="text/javascript" src="/common.js?v=$COMMIT_HASH">
|
||||
</script>
|
||||
<script language="JavaScript">
|
||||
function setpath() {
|
||||
var fileserverpraefix = "/fileserver";
|
||||
var anz_zeichen_fileserver = fileserverpraefix.length;
|
||||
var default_path = window.location.pathname.substring(anz_zeichen_fileserver) + document.getElementById("newfile").files[0].name;
|
||||
document.getElementById("filepath").value = default_path;
|
||||
}
|
||||
|
||||
function dirup() {
|
||||
var str = window.location.href;
|
||||
str = str.substring(0, str.length-1);
|
||||
var zw = str.indexOf("/");
|
||||
var found = zw;
|
||||
while (zw >= 0)
|
||||
{
|
||||
zw = str.indexOf("/", found+1);
|
||||
if (zw >= 0)
|
||||
found = zw;
|
||||
function dirup() {
|
||||
var str = window.location.href;
|
||||
str = str.substring(0, str.length-1);
|
||||
var zw = str.indexOf("/");
|
||||
var found = zw;
|
||||
while (zw >= 0)
|
||||
{
|
||||
zw = str.indexOf("/", found+1);
|
||||
if (zw >= 0)
|
||||
found = zw;
|
||||
}
|
||||
var res = str.substring(0, found+1);
|
||||
|
||||
window.location.href = res;
|
||||
}
|
||||
|
||||
|
||||
function upload() {
|
||||
var filePath = document.getElementById("filepath").value;
|
||||
var upload_path = "/upload/" + filePath;
|
||||
var fileInput = document.getElementById("newfile").files;
|
||||
|
||||
/* Max size of an individual file. Make sure this
|
||||
* value is same as that set in file_server.c */
|
||||
var MAX_FILE_SIZE = 8000*1024;
|
||||
var MAX_FILE_SIZE_STR = "8000KB";
|
||||
|
||||
if (fileInput.length == 0) {
|
||||
firework.launch('No file selected!', 'danger', 30000);
|
||||
} else if (filePath.length == 0) {
|
||||
firework.launch('File path on server is not set!', 'danger', 30000);
|
||||
} else if (filePath.length > 100) {
|
||||
firework.launch('Filename is to long! Max 100 characters.', 'danger', 30000);
|
||||
} else if (filePath.indexOf(' ') >= 0) {
|
||||
firework.launch('File path on server cannot have spaces!', 'danger', 30000);
|
||||
} else if (filePath[filePath.length-1] == '/') {
|
||||
firework.launch('File name not specified after path!', 'danger', 30000);
|
||||
} else if (fileInput[0].size > MAX_FILE_SIZE) {
|
||||
firework.launch("File size must be less than " + MAX_FILE_SIZE_STR + "!", 'danger', 30000);
|
||||
} else {
|
||||
document.getElementById("newfile").disabled = true;
|
||||
document.getElementById("filepath").disabled = true;
|
||||
document.getElementById("upload").disabled = true;
|
||||
|
||||
var file = fileInput[0];
|
||||
var xhttp = new XMLHttpRequest();
|
||||
xhttp.onreadystatechange = function() {
|
||||
if (xhttp.readyState == 4) {
|
||||
if (xhttp.status == 200) {
|
||||
document.open();
|
||||
document.write(xhttp.responseText);
|
||||
document.close();
|
||||
} else if (xhttp.status == 0) {
|
||||
firework.launch('Server closed the connection abruptly!', 'danger', 30000);
|
||||
UpdatePage(false);
|
||||
} else {
|
||||
firework.launch('An error occured: ' + xhttp.responseText, 'danger', 30000);
|
||||
UpdatePage(false);
|
||||
}
|
||||
}
|
||||
var res = str.substring(0, found+1);
|
||||
|
||||
window.location.href = res;
|
||||
}
|
||||
};
|
||||
xhttp.open("POST", upload_path, true);
|
||||
xhttp.send(file);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function upload() {
|
||||
var filePath = document.getElementById("filepath").value;
|
||||
var upload_path = "/upload/" + filePath;
|
||||
var fileInput = document.getElementById("newfile").files;
|
||||
function checkAtRootLevel(res) {
|
||||
if (getPath() == "/fileserver/") { // Already at root level
|
||||
document.getElementById("dirup").disabled = true;
|
||||
console.log("Already on sd-card root level!");
|
||||
return true;
|
||||
}
|
||||
|
||||
/* Max size of an individual file. Make sure this
|
||||
* value is same as that set in file_server.c */
|
||||
var MAX_FILE_SIZE = 8000*1024;
|
||||
var MAX_FILE_SIZE_STR = "8000KB";
|
||||
|
||||
if (fileInput.length == 0) {
|
||||
firework.launch('No file selected!', 'danger', 30000);
|
||||
} else if (filePath.length == 0) {
|
||||
firework.launch('File path on server is not set!', 'danger', 30000);
|
||||
} else if (filePath.length > 100) {
|
||||
firework.launch('Filename is to long! Max 100 characters.', 'danger', 30000);
|
||||
} else if (filePath.indexOf(' ') >= 0) {
|
||||
firework.launch('File path on server cannot have spaces!', 'danger', 30000);
|
||||
} else if (filePath[filePath.length-1] == '/') {
|
||||
firework.launch('File name not specified after path!', 'danger', 30000);
|
||||
} else if (fileInput[0].size > MAX_FILE_SIZE) {
|
||||
firework.launch("File size must be less than " + MAX_FILE_SIZE_STR + "!", 'danger', 30000);
|
||||
} else {
|
||||
document.getElementById("newfile").disabled = true;
|
||||
document.getElementById("filepath").disabled = true;
|
||||
document.getElementById("upload").disabled = true;
|
||||
|
||||
var file = fileInput[0];
|
||||
var xhttp = new XMLHttpRequest();
|
||||
xhttp.onreadystatechange = function() {
|
||||
if (xhttp.readyState == 4) {
|
||||
if (xhttp.status == 200) {
|
||||
document.open();
|
||||
document.write(xhttp.responseText);
|
||||
document.close();
|
||||
firework.launch('File upload completed', 'success', 5000);
|
||||
} else if (xhttp.status == 0) {
|
||||
firework.launch('Server closed the connection abruptly!', 'danger', 30000);
|
||||
UpdatePage(false);
|
||||
} else {
|
||||
firework.launch('An error occured: ' + xhttp.responseText, 'danger', 30000);
|
||||
UpdatePage(false);
|
||||
}
|
||||
}
|
||||
};
|
||||
xhttp.open("POST", upload_path, true);
|
||||
xhttp.send(file);
|
||||
}
|
||||
}
|
||||
document.getElementById("dirup").disabled = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
function checkAtRootLevel(res) {
|
||||
if (getPath() == "/fileserver/") { // Already at root level
|
||||
document.getElementById("dirup").disabled = true;
|
||||
console.log("Already on sd-card root level!");
|
||||
return true;
|
||||
}
|
||||
function getPath() {
|
||||
return window.location.pathname.replace(/\/+$/, '') + "/"
|
||||
}
|
||||
|
||||
document.getElementById("dirup").disabled = false;
|
||||
return false;
|
||||
}
|
||||
checkAtRootLevel();
|
||||
|
||||
console.log("Current path: " + getPath().replace("/fileserver", ""));
|
||||
document.getElementById("currentpath").innerHTML = "Current path: <b>" + getPath().replace("/fileserver", "") + "</b>";
|
||||
|
||||
function getPath() {
|
||||
return window.location.pathname.replace(/\/+$/, '') + "/"
|
||||
}
|
||||
document.cookie = "page=" + getPath() + "; path=/";
|
||||
|
||||
checkAtRootLevel();
|
||||
</script>
|
||||
|
||||
console.log("Current path: " + getPath().replace("/fileserver", ""));
|
||||
document.getElementById("currentpath").innerHTML = "Current path: <b>" + getPath().replace("/fileserver", "") + "</b>";
|
||||
|
||||
document.cookie = "page=" + getPath() + "; path=/";
|
||||
|
||||
</script>
|
||||
</body>
|
||||
</body>
|
||||
</html>
|
||||
@@ -4,15 +4,13 @@
|
||||
border-color: #888;
|
||||
border-radius: 6px;
|
||||
color: #fff;
|
||||
left: 10%;
|
||||
left: 200px;
|
||||
padding: 5px;
|
||||
position: fixed;
|
||||
opacity: 0;
|
||||
text-align: center;
|
||||
top: 0px;
|
||||
width: 80%;
|
||||
min-width:30%;
|
||||
max-width:580px;
|
||||
width: 600px;
|
||||
z-index: 99;
|
||||
font-size:120%;
|
||||
}
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
p += parseInt($(this).height()) + 30
|
||||
});
|
||||
|
||||
$('<div id="'+ fid +'" class="'+ c +'">'+ m +'<a onclick="firework.remove(\'#'+ fid +'\')"><img style="height:28px;" src=close.png></a></div>')
|
||||
$('<div id="'+ fid +'" class="'+ c +'">'+ m +'<a onclick="firework.remove(\'#'+ fid +'\')"><img src=close.png></a></div>')
|
||||
.appendTo('body')
|
||||
.animate({
|
||||
opacity: 1,
|
||||
|
||||
@@ -1,40 +1,16 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" xml:lang="en">
|
||||
<head>
|
||||
<title>Data Graph</title>
|
||||
<html>
|
||||
<head>
|
||||
<script type="text/javascript" src='plotly-basic-2.18.2.min.js?v=$COMMIT_HASH'></script>
|
||||
|
||||
<script type="text/javascript" src="common.js?v=$COMMIT_HASH"></script>
|
||||
<script type="text/javascript" src="readconfigcommon.js?v=$COMMIT_HASH"></script>
|
||||
<script type="text/javascript" src="readconfigparam.js?v=$COMMIT_HASH"></script>
|
||||
|
||||
<script type="text/javascript" src="readconfigparam.js?v=$COMMIT_HASH"></script>
|
||||
<style>
|
||||
h1 {font-size: 2em;}
|
||||
h2 {font-size: 1.5em; margin-block-start: 0.0em; margin-block-end: 0.2em;}
|
||||
h3 {font-size: 1.2em;}
|
||||
p {font-size: 1em;}
|
||||
|
||||
body {
|
||||
font-family: Arial, Helvetica, sans-serif;
|
||||
}
|
||||
|
||||
select {
|
||||
padding: 3px 5px;
|
||||
display: inline-block;
|
||||
border: 1px solid #ccc;
|
||||
font-size: 16px;
|
||||
margin-right: 10px;
|
||||
min-width: 100px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.button {
|
||||
padding: 5px 10px;
|
||||
width: 160px;
|
||||
font-size: 16px;
|
||||
}
|
||||
</style>
|
||||
|
||||
|
||||
<script>
|
||||
function run() {
|
||||
datefile = document.getElementById("datafiles").value;
|
||||
@@ -47,7 +23,7 @@
|
||||
.then(response => {
|
||||
// handle the response
|
||||
if (response.status == 404) {
|
||||
firework.launch("No data available for " + dateString, 'warning', 10000);
|
||||
firework.launch("No log data available for " + dateString, 'warning', 10000);
|
||||
}
|
||||
response.text()
|
||||
.then( result => {
|
||||
@@ -156,17 +132,17 @@
|
||||
},
|
||||
|
||||
margin: {
|
||||
l: 70,
|
||||
r: 70,
|
||||
l: 50,
|
||||
r: 50,
|
||||
b: 50,
|
||||
t: 40,
|
||||
t: 50,
|
||||
pad: 4
|
||||
},
|
||||
|
||||
legend: {
|
||||
x: 0.02,
|
||||
y: 0.97,
|
||||
xanchor: 'left'
|
||||
x: 0.2,
|
||||
y: 0.9,
|
||||
xanchor: 'right'
|
||||
}
|
||||
};
|
||||
|
||||
@@ -182,19 +158,19 @@
|
||||
<link href="firework.css?v=$COMMIT_HASH" rel="stylesheet">
|
||||
<script type="text/javascript" src="jquery-3.6.0.min.js?v=$COMMIT_HASH"></script>
|
||||
<script type="text/javascript" src="firework.js?v=$COMMIT_HASH"></script>
|
||||
</head>
|
||||
</head>
|
||||
<body>
|
||||
<h3>Data Graph</h3>
|
||||
<div id='chart'><p>Loading...<br></p></div>
|
||||
<select id="datafiles" onchange="run();"></select>
|
||||
<select id="numbers" onchange="run();"></select>
|
||||
<input type="checkbox" id="showRrelativeValues" onclick = 'run();' unchecked ><label for="showRrelativeValues">Show relative values</label>
|
||||
<button onclick="run();">Refresh</button>
|
||||
|
|
||||
<button onClick="window.location.href = 'data.html?v=$COMMIT_HASH'">Show data</button>
|
||||
<button onClick="window.location.href = getDomainname() + '/fileserver/log/data/'">Show data files</button>
|
||||
|
||||
<body>
|
||||
<h2>Data Graph</h2>
|
||||
<div id='chart'><p>Loading...<br></p></div>
|
||||
Number sequence:
|
||||
<select id="numbers" onchange="run();"></select>
|
||||
Day:
|
||||
<select id="datafiles" onchange="run();"></select>
|
||||
<input type="checkbox" id="showRrelativeValues" onclick = 'run();' unchecked ><label for="showRrelativeValues">Show relative values</label><br><br>
|
||||
<button class="button" onclick="run();">Refresh</button>
|
||||
<button class="button" onClick="window.location.href = 'data.html?v=$COMMIT_HASH'">Show Data Viewer</button>
|
||||
<button class="button" onClick="window.location.href = getDomainname() + '/fileserver/log/data/'">Show Data Files</button>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
function WriteModelFiles()
|
||||
@@ -238,15 +214,7 @@
|
||||
WriteModelFiles();
|
||||
WriteNumbers();
|
||||
|
||||
function Refresh() {
|
||||
setTimeout (function() {
|
||||
run();
|
||||
Refresh();
|
||||
}, 300000);
|
||||
}
|
||||
|
||||
run();
|
||||
Refresh();
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,122 +1,94 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" xml:lang="en">
|
||||
<html>
|
||||
<head>
|
||||
<link rel="icon" href="favicon.ico?v=$COMMIT_HASH" type="image/x-icon">
|
||||
<link rel="apple-touch-icon" href="watermeter.svg" />
|
||||
<link rel="shortcut icon" href="watermeter.svg" sizes="196x196">
|
||||
<title>AI on the edge</title>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="stylesheet" href="style.css?v=$COMMIT_HASH" type="text/css" >
|
||||
<link href="firework.css?v=$COMMIT_HASH" rel="stylesheet">
|
||||
<link rel="icon" href="favicon.ico?v=$COMMIT_HASH" type="image/x-icon">
|
||||
<title>AI on the edge</title>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link rel="stylesheet" href="style.css?v=$COMMIT_HASH" type="text/css" >
|
||||
<link href="firework.css?v=$COMMIT_HASH" rel="stylesheet">
|
||||
|
||||
<script type="text/javascript" src="common.js?v=$COMMIT_HASH"></script>
|
||||
<script type="text/javascript" src="readconfigcommon.js?v=$COMMIT_HASH"></script>
|
||||
<script type="text/javascript" src="readconfigparam.js?v=$COMMIT_HASH"></script>
|
||||
<script type="text/javascript" src="common.js?v=$COMMIT_HASH"></script>
|
||||
<script type="text/javascript" src="readconfigcommon.js?v=$COMMIT_HASH"></script>
|
||||
<script type="text/javascript" src="readconfigparam.js?v=$COMMIT_HASH"></script>
|
||||
|
||||
<script type="text/javascript" src="jquery-3.6.0.min.js?v=$COMMIT_HASH"></script>
|
||||
<script type="text/javascript" src="firework.js?v=$COMMIT_HASH"></script>
|
||||
<script type="text/javascript" src="jquery-3.6.0.min.js?v=$COMMIT_HASH"></script>
|
||||
<script type="text/javascript" src="common.js?v=$COMMIT_HASH"></script>
|
||||
<script type="text/javascript" src="firework.js?v=$COMMIT_HASH"></script>
|
||||
|
||||
<script>
|
||||
var streamPopup;
|
||||
var streamFlashlight = false;
|
||||
var streamWindowFeatures =
|
||||
'channelmode=no,directories=no,fullscreen=no,' +
|
||||
'location=no,dependent=yes,menubar=no,resizable=no,scrollbars=no,' +
|
||||
'status=no,toolbar=no,titlebar=no,' +
|
||||
'left=10,top=250,width=640px,height=480px';
|
||||
<script>
|
||||
async function loadPage(page) {
|
||||
console.log("loadPage(" + page + ")");
|
||||
document.cookie = "page="+page + "; path=/";
|
||||
document.getElementById('maincontent').src = page;
|
||||
|
||||
function loadPage(page) {
|
||||
console.log("loadPage( " + page + " )");
|
||||
[].forEach.call(document.querySelectorAll('.submenu'), function (el) {
|
||||
el.style.visibility = 'hidden';
|
||||
});
|
||||
}
|
||||
|
||||
if (streamPopup) // Ensure that stream popup is closed because it's blocking web interface
|
||||
streamPopup.close();
|
||||
|
||||
asyncPageLoad(page);
|
||||
function resetMenu() {
|
||||
[].forEach.call(document.querySelectorAll('.submenu'), function (el) {
|
||||
el.style.visibility = 'visible';
|
||||
});
|
||||
}
|
||||
|
||||
function getCookie(cname) {
|
||||
let name = cname + "=";
|
||||
let decodedCookie = decodeURIComponent(document.cookie);
|
||||
let ca = decodedCookie.split(';');
|
||||
for(let i = 0; i <ca.length; i++) {
|
||||
let c = ca[i];
|
||||
while (c.charAt(0) == ' ') {
|
||||
c = c.substring(1);
|
||||
}
|
||||
|
||||
|
||||
async function asyncPageLoad(page ) {
|
||||
console.log(" loading " + page + " ...");
|
||||
document.cookie = "page="+page + "; path=/";
|
||||
document.getElementById('maincontent').src = page;
|
||||
|
||||
[].forEach.call(document.querySelectorAll('.submenu'), function (el) {
|
||||
el.style.visibility = 'hidden';
|
||||
});
|
||||
if (c.indexOf(name) == 0) {
|
||||
return c.substring(name.length, c.length);
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
</script>
|
||||
|
||||
|
||||
function resetMenu() {
|
||||
[].forEach.call(document.querySelectorAll('.submenu'), function (el) {
|
||||
el.style.visibility = 'visible';
|
||||
});
|
||||
}
|
||||
|
||||
function getCookie(cname) {
|
||||
let name = cname + "=";
|
||||
let decodedCookie = decodeURIComponent(document.cookie);
|
||||
let ca = decodedCookie.split(';');
|
||||
for(let i = 0; i <ca.length; i++) {
|
||||
let c = ca[i];
|
||||
while (c.charAt(0) == ' ') {
|
||||
c = c.substring(1);
|
||||
}
|
||||
if (c.indexOf(name) == 0) {
|
||||
return c.substring(name.length, c.length);
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="main">
|
||||
|
||||
<table style="border: none; width:100%">
|
||||
<tr>
|
||||
<td style="padding-right: 10px;"><img style="width:64px; height:64px" src="favicon.ico?v=$COMMIT_HASH"></td>
|
||||
<td><h1 id="id_title"> Digitizer - AI on the edge</h1>
|
||||
<h2>An ESP32 all inclusive neural network recognition system for meter digitalization</h2>
|
||||
</td>
|
||||
</tr>
|
||||
<table style="border: none">
|
||||
<tr><td style="padding-right: 10px;"><img src="favicon.ico?v=$COMMIT_HASH"></td>
|
||||
<td><h1 id="id_title"> Digitizer - AI on the edge</h1>
|
||||
<h2>An ESP32 all inclusive neural network recognition system for meter digitalization</h2>
|
||||
</td></tr>
|
||||
</table>
|
||||
|
||||
|
||||
<div class="menu" onmouseover="resetMenu()">
|
||||
<ul>
|
||||
<li><a href="#" onclick="loadPage('overview.html?v=$COMMIT_HASH');">Overview</a></li>
|
||||
<li><a>Settings <i class="arrow down"></i></a>
|
||||
<ul class="submenu">
|
||||
<li><a href="#" onclick="loadPage('prevalue_set.html?v=$COMMIT_HASH');">Set "Previous Value"</a></li>
|
||||
<li><a href="#" onclick="loadPage('prevalue_set.html?v=$COMMIT_HASH');">Set Previous Value</a></li>
|
||||
<li><a href="#" onclick="loadPage('edit_config_param.html?v=$COMMIT_HASH');">Configuration</a></li>
|
||||
<li><a>Alignment <i class="arrow right"></i></a>
|
||||
<ul>
|
||||
<li><a href="#" onclick="loadPage('edit_reference.html?v=$COMMIT_HASH');">Reference Image</a></li>
|
||||
<li><a href="#" onclick="loadPage('edit_alignment.html?v=$COMMIT_HASH');">Alignment Marker</a></li>
|
||||
<li><a href="#" onclick="loadPage('edit_alignment.html?v=$COMMIT_HASH');">Alignment Marks</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a><strong>R</strong>egions <strong>O</strong>f <strong>I</strong>nterest <i class="arrow right"></i></a>
|
||||
<ul>
|
||||
<li><a href="#" onclick="loadPage('edit_digits.html?v=$COMMIT_HASH');">Digit ROI</a></li>
|
||||
<li><a href="#" onclick="loadPage('edit_analog.html?v=$COMMIT_HASH');">Analog ROI</a></li>
|
||||
<li><a href="#" onclick="loadPage('edit_digits.html?v=$COMMIT_HASH');">Digital ROIs</a></li>
|
||||
<li><a href="#" onclick="loadPage('edit_analog.html?v=$COMMIT_HASH');">Analog ROIs</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
|
||||
<li><a>Data<i class="arrow down"></i></a>
|
||||
<li><a>Data <i class="arrow down"></i></a>
|
||||
<ul class="submenu">
|
||||
<li><a href="#" onclick="loadPage(getDomainname() + '/value?full');">Recognition</a></li>
|
||||
<li><a>Livestream <i class="arrow right"></i></a>
|
||||
<ul>
|
||||
<li><a href="#" onclick="start_livestream(false);">Live Stream (Light off)</a></li>
|
||||
<li><a href="#" onclick="start_livestream(true);">Live Stream (Light on)</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#" onclick="loadPage('graph.html?v=$COMMIT_HASH');">Data Graph</a></li>
|
||||
<li><a href="#" onclick="loadPage('data.html?v=$COMMIT_HASH');">Data Table</a></li>
|
||||
<li><a href="#" onclick="loadPage('data.html?v=$COMMIT_HASH');">Data Viewer</a></li>
|
||||
<li><a href="#" onclick="loadPage(getDomainname() + '/fileserver/log/data/');">Data Files</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
@@ -130,96 +102,28 @@
|
||||
<li><a href="#" onclick="loadPage(getDomainname() + '/fileserver/');">File Server</a></li>
|
||||
<li><a href="#" onclick="loadPage('reboot_page.html?v=$COMMIT_HASH');">Reboot</a></li>
|
||||
<li><a href="#" onclick="loadPage('info.html?v=$COMMIT_HASH');">Info</a></li>
|
||||
<li><a href="https://jomjol.github.io/AI-on-the-edge-device-docs/" target="_blank">Help</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li id="ManualControl" style="display:none;"><a>Manual Control <i class="arrow down"></i></a> <!-- Workaround: Hide menu if no entry is available -->
|
||||
<ul class="submenu">
|
||||
<!--<li><a href="#" onclick="flow_start()">Start Round</a></li>--> <!-- Needs to be adapted on code side first to ensure proper user feedback -->
|
||||
<li id="HASendDiscovery" style="display:none;"><a href="#" onclick="HA_send_discovery()">Resend HA Discovery</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<iframe title="maincontent" name="maincontent" class="iframe" id="maincontent"></iframe>
|
||||
<iframe name="maincontent" class="iframe" id="maincontent"></iframe>
|
||||
|
||||
<span id="Version" style="font-size: 10px; margin-top: -5px;padding-left: 10px;">Loading version...</span>
|
||||
<span id="Version" style="font-size: 10px; margin-top: -5px">Loading version...</span>
|
||||
|
||||
<script type="text/javascript">
|
||||
LoadHostname();
|
||||
LoadFwVersion();
|
||||
LoadWebUiVersion();
|
||||
HA_send_discovery_visibility();
|
||||
LoadHostname();
|
||||
LoadFwVersion();
|
||||
LoadWebUiVersion();
|
||||
|
||||
if (getCookie("page") == "" || getCookie("page") == "reboot_page.html?v=$COMMIT_HASH") {
|
||||
if (getCookie("page") == "" || getCookie("page") == "reboot_page.html?v=$COMMIT_HASH") {
|
||||
document.cookie = "page=overview.html?v=$COMMIT_HASH" + "; path=/";
|
||||
}
|
||||
console.log("Loading page: " + getCookie("page"));
|
||||
document.getElementById('maincontent').src = getCookie("page");
|
||||
|
||||
/*
|
||||
function flow_start() {
|
||||
var url = getDomainname() + '/flow_start';
|
||||
var xhttp = new XMLHttpRequest();
|
||||
xhttp.onreadystatechange = function() {
|
||||
if (this.readyState == 4 && this.status == 200) {
|
||||
if (xhttp.responseText.substring(0,3) == "001") {
|
||||
firework.launch('Flow start triggered', 'success', 5000);
|
||||
window.location.reload();
|
||||
}
|
||||
else if (xhttp.responseText.substring(0,3) == "002") {
|
||||
firework.launch('Flow start scheduled. Start after round is completed', 'success', 5000);
|
||||
}
|
||||
else if (xhttp.responseText.substring(0,3) == "099") {
|
||||
firework.launch('Flow start triggered, but start not possible (no flow task available)', 'danger', 5000);
|
||||
}
|
||||
}
|
||||
}
|
||||
xhttp.open("GET", url, true);
|
||||
xhttp.send();
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
function HA_send_discovery_visibility() {
|
||||
loadConfig(domainname);
|
||||
ParseConfig();
|
||||
category = getConfigCategory();
|
||||
param = getConfigParameters();
|
||||
if (category["MQTT"]["enabled"] && param["MQTT"]["HomeassistantDiscovery"]["value1"] == "true") {
|
||||
document.getElementById("ManualControl").style.display="";
|
||||
document.getElementById("HASendDiscovery").style.display="";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function HA_send_discovery() {
|
||||
console.log("HA Discovery scheduled");
|
||||
var url = getDomainname() + '/mqtt_publish_discovery';
|
||||
var xhttp = new XMLHttpRequest();
|
||||
xhttp.onreadystatechange = function() {
|
||||
if (this.readyState == 4 && this.status == 200) {
|
||||
firework.launch('Sending HA discovery topics scheduled. The sending will be processed in state "Publish to MQTT"', 'success', 5000);
|
||||
}
|
||||
}
|
||||
xhttp.open("GET", url, true);
|
||||
xhttp.send();
|
||||
}
|
||||
|
||||
|
||||
function start_livestream(streamFlashlight) {
|
||||
if (streamPopup)
|
||||
streamPopup.close();
|
||||
|
||||
if (streamFlashlight)
|
||||
streamPopup = window.open(getDomainname() + '/stream?flashlight=true','LivestreamWithlight',streamWindowFeatures);
|
||||
else
|
||||
streamPopup = window.open(getDomainname() + '/stream','Livestream',streamWindowFeatures);
|
||||
|
||||
streamPopup.focus();
|
||||
}
|
||||
}
|
||||
console.log("Loading page: " + getCookie("page"));
|
||||
document.getElementById('maincontent').src = getCookie("page");
|
||||
</script>
|
||||
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" xml:lang="en">
|
||||
<html>
|
||||
<head>
|
||||
<link rel="icon" href="favicon.ico?v=$COMMIT_HASH" type="image/x-icon">
|
||||
<title>Info</title>
|
||||
<meta charset="UTF-8" />
|
||||
<meta charset="utf-8">
|
||||
|
||||
<style>
|
||||
h1 {font-size: 2em;}
|
||||
@@ -10,490 +11,190 @@ h2 {font-size: 1.5em;}
|
||||
h3 {font-size: 1.2em;}
|
||||
p {font-size: 1em;}
|
||||
|
||||
th, td {
|
||||
padding: 5px 5px 5px 5px;
|
||||
border-width: 1px;
|
||||
border-style: solid;
|
||||
border-color: rgb(240, 240, 240);
|
||||
div {
|
||||
width: 350px;
|
||||
padding: 10px 5px;
|
||||
border: 1px solid #ccc;
|
||||
font-family: arial;
|
||||
font-size: 16px;
|
||||
max-height: 35px;
|
||||
}
|
||||
|
||||
output {
|
||||
padding-left:5px;
|
||||
}
|
||||
|
||||
table {
|
||||
width: 660px;
|
||||
padding: 5px;
|
||||
border-collapse:collapse;
|
||||
}
|
||||
</style>
|
||||
|
||||
<script type="text/javascript" src="common.js?v=$COMMIT_HASH"></script>
|
||||
</head>
|
||||
|
||||
<body style="font-family: arial; padding: 0px 10px;">
|
||||
<table>
|
||||
<colgroup>
|
||||
<col span="1" style="width: 35%;">
|
||||
<col span="1" style="width: 65%;">
|
||||
</colgroup>
|
||||
<tr>
|
||||
<h3>Runtime Information</h3>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Start time:</td>
|
||||
<td><output id="starttime"></output></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Uptime:</td>
|
||||
<td><output id="uptime"></output></td>
|
||||
</tr>
|
||||
</table>
|
||||
<h3>Runtime Information</h3>
|
||||
<table style="font-family: arial">
|
||||
<tr>
|
||||
<td>
|
||||
Last restart:
|
||||
</td>
|
||||
<td>
|
||||
<div id="starttime">
|
||||
<object data="/starttime"></object>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
Uptime:
|
||||
</td>
|
||||
<td>
|
||||
<div id="uptime">
|
||||
<object data="/uptime"></object>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<table>
|
||||
<colgroup>
|
||||
<col span="1" style="width: 35%;">
|
||||
<col span="1" style="width: 65%;">
|
||||
</colgroup>
|
||||
<tr>
|
||||
<h3>Build Info</h3>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Firmware version:</td>
|
||||
<td>
|
||||
<output id="firmware"></output>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Firmware build time:</td>
|
||||
<td>
|
||||
<output id="build-time"></output>
|
||||
</td>
|
||||
</tr>
|
||||
<h3>Build Info</h3>
|
||||
<table style="font-family: arial">
|
||||
<tr>
|
||||
<td>
|
||||
Firmware Version:
|
||||
</td>
|
||||
<td>
|
||||
<div id="firmware" style="width: 700px">
|
||||
<object data="/info?type=FirmwareVersion" style="width: 700px"></object>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
Firmware Build Time:
|
||||
</td>
|
||||
<td>
|
||||
<div id="build-time">
|
||||
<object data="/info?type=BuildTime"></object>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<td>Web interface version:</td>
|
||||
<td>
|
||||
<output id="web-ui"></output>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<tr>
|
||||
<td>
|
||||
Web Interface Version:
|
||||
</td>
|
||||
<td>
|
||||
<div id="web-ui" style="width: 700px">
|
||||
<object data="/info?type=HTMLVersion" style="width: 700px"></object>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
|
||||
<table>
|
||||
<colgroup>
|
||||
<col span="1" style="width: 35%;">
|
||||
<col span="1" style="width: 65%;">
|
||||
</colgroup>
|
||||
<tr>
|
||||
<h3>Host Info</h3>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Hostname:</td>
|
||||
<td>
|
||||
<output id="hostname"></output>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>IP Address:</td>
|
||||
<td>
|
||||
<output id="IP-address"></output>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>WLAN SSID:</td>
|
||||
<td>
|
||||
<output id="wlan-ssid"></output>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<table>
|
||||
<colgroup>
|
||||
<col span="1" style="width: 35%;">
|
||||
<col span="1" style="width: 65%;">
|
||||
</colgroup>
|
||||
<tr>
|
||||
<h3>SD Card Info</h3>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>SD card manufacturer:</td>
|
||||
<td>
|
||||
<output id="SDCardManufacturer"></output>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>SD card name:</td>
|
||||
<td>
|
||||
<output id="SDCardName"></output>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>SD card size:</td>
|
||||
<td>
|
||||
<output id="SDCardCapacity"></output>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>SD card sector size:</td>
|
||||
<td>
|
||||
<output id="SDCardSectorSize"></output>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Partition size:</td>
|
||||
<td>
|
||||
<output id="SDCardPartitionSize"></output>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Partition free space:</td>
|
||||
<td>
|
||||
<output id="SDCardFreePartitionSpace"></output>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Partition allocation size:</td>
|
||||
<td>
|
||||
<output id="SDCardPartitionAllocationSize"></output>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<table>
|
||||
<colgroup>
|
||||
<col span="1" style="width: 35%;">
|
||||
<col span="1" style="width: 65%;">
|
||||
</colgroup>
|
||||
<tr>
|
||||
<h3>Memory Info</h3>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Total Free (Int + Ext):</td>
|
||||
<td>
|
||||
<output id="RAMTotalFree"></output>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Ext. RAM - Free:</td>
|
||||
<td>
|
||||
<output id="ExtRAMFree"></output>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Ext. RAM - Largest Free Block:</td>
|
||||
<td>
|
||||
<output id="ExtRAMLargestFree"></output>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Ext. RAM - Min Free:</td>
|
||||
<td>
|
||||
<output id="ExtRAMMinFree"></output>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Int. RAM - Free:</td>
|
||||
<td>
|
||||
<output id="IntRAMFree"></output>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Int. RAM - Largest Free Block:</td>
|
||||
<td>
|
||||
<output id="IntRAMLargestFree"></output>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>Int. RAM - Min Free:</td>
|
||||
<td>
|
||||
<output id="IntRAMMinFree"></output>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
<h3>Host Info</h3>
|
||||
<table style="font-family: arial">
|
||||
<tr>
|
||||
<td>
|
||||
Hostname:
|
||||
</td>
|
||||
<td>
|
||||
<div id="Hostname">
|
||||
<object data="/info?type=Hostname"></object>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
IP-Address:
|
||||
</td>
|
||||
<td>
|
||||
<div id="IP">
|
||||
<object data="/info?type=IP"></object>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
WLan-SSID:
|
||||
</td>
|
||||
<td>
|
||||
<div id="SSID">
|
||||
<object data="/info?type=SSID"></object>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<h3>SD Card Info</h3>
|
||||
<table style="font-family: arial">
|
||||
<tr>
|
||||
<td>
|
||||
SD Card Manufacturer:
|
||||
</td>
|
||||
<td>
|
||||
<div id="SDCardManufacturer">
|
||||
<object data="/info?type=SDCardManufacturer"></object>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
SD Card Name:
|
||||
</td>
|
||||
<td>
|
||||
<div id="SDCardName">
|
||||
<object data="/info?type=SDCardName"></object>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
SD Card Size [MB]:
|
||||
</td>
|
||||
<td>
|
||||
<div id="SDCardCapacity">
|
||||
<object data="/info?type=SDCardCapacity"></object>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
SD Card Sector Size [byte]:
|
||||
</td>
|
||||
<td>
|
||||
<div id="SDCardSectorSize">
|
||||
<object data="/info?type=SDCardSectorSize"></object>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
Partition Size [MB]:
|
||||
</td>
|
||||
<td>
|
||||
<div id="SDPartitionSize">
|
||||
<object data="/info?type=SDCardPartitionSize"></object>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
Partition Free Space [MB]:
|
||||
</td>
|
||||
<td>
|
||||
<div id="SDFreePartitionSpace">
|
||||
<object data="/info?type=SDCardFreePartitionSpace"></object>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
Partition Allocation Size [byte]:
|
||||
</td>
|
||||
<td>
|
||||
<div id="SDCardPartitionAllocationSize">
|
||||
<object data="/info?type=SDCardPartitionAllocationSize"></object>
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
<h3>Copyright</h3>
|
||||
Copyright © 2020 - 2023 by <a href="https://github.com/jomjol/AI-on-the-edge-device" target=_blank>Jomjol</a> and others.
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
<script type="text/javascript">
|
||||
|
||||
function loadLastRestart()
|
||||
{
|
||||
url = getDomainname() + '/starttime';
|
||||
var xhttp = new XMLHttpRequest();
|
||||
xhttp.onreadystatechange = function() {
|
||||
if (this.readyState == 4 && this.status == 200) {
|
||||
//Input format: 19700101-010019
|
||||
var timestamp = xhttp.response.substr(6,2) + "." +
|
||||
xhttp.response.substr(4,2) + "." +
|
||||
xhttp.response.substr(0,4) + " " +
|
||||
xhttp.response.substr(9,2) + ":" +
|
||||
xhttp.response.substr(11,2) + ":" +
|
||||
xhttp.response.substr(13,2);
|
||||
document.getElementById("starttime").value = timestamp;
|
||||
}
|
||||
}
|
||||
xhttp.open("GET", url, true);
|
||||
xhttp.send();
|
||||
}
|
||||
|
||||
function loadUptime()
|
||||
{
|
||||
url = getDomainname() + '/uptime';
|
||||
var xhttp = new XMLHttpRequest();
|
||||
xhttp.onreadystatechange = function() {
|
||||
if (this.readyState == 4 && this.status == 200) {
|
||||
document.getElementById("uptime").value = xhttp.response;
|
||||
}
|
||||
}
|
||||
xhttp.open("GET", url, true);
|
||||
xhttp.send();
|
||||
}
|
||||
|
||||
function loadFWVersion()
|
||||
{
|
||||
url = getDomainname() + '/info?type=FirmwareVersion';
|
||||
var xhttp = new XMLHttpRequest();
|
||||
xhttp.onreadystatechange = function() {
|
||||
if (this.readyState == 4 && this.status == 200) {
|
||||
document.getElementById("firmware").value = xhttp.response;
|
||||
}
|
||||
}
|
||||
xhttp.open("GET", url, true);
|
||||
xhttp.send();
|
||||
}
|
||||
|
||||
function loadFWBuildTime()
|
||||
{
|
||||
url = getDomainname() + '/info?type=BuildTime';
|
||||
var xhttp = new XMLHttpRequest();
|
||||
xhttp.onreadystatechange = function() {
|
||||
if (this.readyState == 4 && this.status == 200) {
|
||||
// Input format: 2023-04-02 10:56
|
||||
var timestamp = xhttp.response.substr(8,2) + "." +
|
||||
xhttp.response.substr(5,2) + "." +
|
||||
xhttp.response.substr(0,4) + " " +
|
||||
xhttp.response.substr(11,2) + ":" +
|
||||
xhttp.response.substr(14,2);
|
||||
document.getElementById("build-time").value = timestamp;
|
||||
}
|
||||
}
|
||||
xhttp.open("GET", url, true);
|
||||
xhttp.send();
|
||||
}
|
||||
|
||||
function loadHTMLVersion()
|
||||
{
|
||||
url = getDomainname() + '/info?type=HTMLVersion';
|
||||
var xhttp = new XMLHttpRequest();
|
||||
xhttp.onreadystatechange = function() {
|
||||
if (this.readyState == 4 && this.status == 200) {
|
||||
document.getElementById("web-ui").value = xhttp.response;
|
||||
}
|
||||
}
|
||||
xhttp.open("GET", url, true);
|
||||
xhttp.send();
|
||||
}
|
||||
|
||||
function loadHostname()
|
||||
{
|
||||
url = getDomainname() + '/info?type=Hostname';
|
||||
var xhttp = new XMLHttpRequest();
|
||||
xhttp.onreadystatechange = function() {
|
||||
if (this.readyState == 4 && this.status == 200) {
|
||||
document.getElementById("hostname").value = xhttp.response;
|
||||
}
|
||||
}
|
||||
xhttp.open("GET", url, true);
|
||||
xhttp.send();
|
||||
}
|
||||
|
||||
function loadIPAddress()
|
||||
{
|
||||
url = getDomainname() + '/info?type=IP';
|
||||
var xhttp = new XMLHttpRequest();
|
||||
xhttp.onreadystatechange = function() {
|
||||
if (this.readyState == 4 && this.status == 200) {
|
||||
document.getElementById("IP-address").value = xhttp.response;
|
||||
}
|
||||
}
|
||||
xhttp.open("GET", url, true);
|
||||
xhttp.send();
|
||||
}
|
||||
|
||||
function loadWLANSSID()
|
||||
{
|
||||
url = getDomainname() + '/info?type=SSID';
|
||||
var xhttp = new XMLHttpRequest();
|
||||
xhttp.onreadystatechange = function() {
|
||||
if (this.readyState == 4 && this.status == 200) {
|
||||
document.getElementById("WLAN-SSID").value = xhttp.response;
|
||||
}
|
||||
}
|
||||
xhttp.open("GET", url, true);
|
||||
xhttp.send();
|
||||
}
|
||||
|
||||
function loadWLANSSID()
|
||||
{
|
||||
url = getDomainname() + '/info?type=SSID';
|
||||
var xhttp = new XMLHttpRequest();
|
||||
xhttp.onreadystatechange = function() {
|
||||
if (this.readyState == 4 && this.status == 200) {
|
||||
document.getElementById("wlan-ssid").value = xhttp.response;
|
||||
}
|
||||
}
|
||||
xhttp.open("GET", url, true);
|
||||
xhttp.send();
|
||||
}
|
||||
|
||||
function loadWLANSSID()
|
||||
{
|
||||
url = getDomainname() + '/info?type=SSID';
|
||||
var xhttp = new XMLHttpRequest();
|
||||
xhttp.onreadystatechange = function() {
|
||||
if (this.readyState == 4 && this.status == 200) {
|
||||
document.getElementById("wlan-ssid").value = xhttp.response;
|
||||
}
|
||||
}
|
||||
xhttp.open("GET", url, true);
|
||||
xhttp.send();
|
||||
}
|
||||
|
||||
function loadSDCardManufacturer()
|
||||
{
|
||||
url = getDomainname() + '/info?type=SDCardManufacturer';
|
||||
var xhttp = new XMLHttpRequest();
|
||||
xhttp.onreadystatechange = function() {
|
||||
if (this.readyState == 4 && this.status == 200) {
|
||||
document.getElementById("SDCardManufacturer").value = xhttp.response;
|
||||
}
|
||||
}
|
||||
xhttp.open("GET", url, true);
|
||||
xhttp.send();
|
||||
}
|
||||
|
||||
function loadSDCardName()
|
||||
{
|
||||
url = getDomainname() + '/info?type=SDCardName';
|
||||
var xhttp = new XMLHttpRequest();
|
||||
xhttp.onreadystatechange = function() {
|
||||
if (this.readyState == 4 && this.status == 200) {
|
||||
document.getElementById("SDCardName").value = xhttp.response;
|
||||
}
|
||||
}
|
||||
xhttp.open("GET", url, true);
|
||||
xhttp.send();
|
||||
}
|
||||
|
||||
function loadSDCardCapacity()
|
||||
{
|
||||
url = getDomainname() + '/info?type=SDCardCapacity';
|
||||
var xhttp = new XMLHttpRequest();
|
||||
xhttp.onreadystatechange = function() {
|
||||
if (this.readyState == 4 && this.status == 200) {
|
||||
document.getElementById("SDCardCapacity").value = xhttp.response + " MB";
|
||||
}
|
||||
}
|
||||
xhttp.open("GET", url, true);
|
||||
xhttp.send();
|
||||
}
|
||||
|
||||
function loadSDCardSectorSize()
|
||||
{
|
||||
url = getDomainname() + '/info?type=SDCardSectorSize';
|
||||
var xhttp = new XMLHttpRequest();
|
||||
xhttp.onreadystatechange = function() {
|
||||
if (this.readyState == 4 && this.status == 200) {
|
||||
document.getElementById("SDCardSectorSize").value = xhttp.response + " byte";
|
||||
}
|
||||
}
|
||||
xhttp.open("GET", url, true);
|
||||
xhttp.send();
|
||||
}
|
||||
|
||||
function loadSDCardPartitionSize()
|
||||
{
|
||||
url = getDomainname() + '/info?type=SDCardPartitionSize';
|
||||
var xhttp = new XMLHttpRequest();
|
||||
xhttp.onreadystatechange = function() {
|
||||
if (this.readyState == 4 && this.status == 200) {
|
||||
document.getElementById("SDCardPartitionSize").value = xhttp.response + " MB";
|
||||
}
|
||||
}
|
||||
xhttp.open("GET", url, true);
|
||||
xhttp.send();
|
||||
}
|
||||
|
||||
function loadSDCardFreePartitionSpace()
|
||||
{
|
||||
url = getDomainname() + '/info?type=SDCardFreePartitionSpace';
|
||||
var xhttp = new XMLHttpRequest();
|
||||
xhttp.onreadystatechange = function() {
|
||||
if (this.readyState == 4 && this.status == 200) {
|
||||
document.getElementById("SDCardFreePartitionSpace").value = xhttp.response + " MB";
|
||||
}
|
||||
}
|
||||
xhttp.open("GET", url, true);
|
||||
xhttp.send();
|
||||
}
|
||||
|
||||
function loadSDCardPartitionAllocationSize()
|
||||
{
|
||||
url = getDomainname() + '/info?type=SDCardPartitionAllocationSize';
|
||||
var xhttp = new XMLHttpRequest();
|
||||
xhttp.onreadystatechange = function() {
|
||||
if (this.readyState == 4 && this.status == 200) {
|
||||
document.getElementById("SDCardPartitionAllocationSize").value = xhttp.response + " byte";
|
||||
}
|
||||
}
|
||||
xhttp.open("GET", url, true);
|
||||
xhttp.send();
|
||||
}
|
||||
|
||||
function loadMemoryInfo()
|
||||
{
|
||||
url = getDomainname() + '/heap';
|
||||
var xhttp = new XMLHttpRequest();
|
||||
xhttp.onreadystatechange = function() {
|
||||
if (this.readyState == 4 && this.status == 200) {
|
||||
data = xhttp.response.split("|");
|
||||
document.getElementById("RAMTotalFree").value = data[0].split("l: ")[1] + " byte";
|
||||
document.getElementById("IntRAMFree").value = data[4].split(":")[1] + " byte";
|
||||
document.getElementById("IntRAMLargestFree").value = data[5].split(":")[1] + " byte";
|
||||
document.getElementById("IntRAMMinFree").value = data[6].split(":")[1] + " byte";
|
||||
document.getElementById("ExtRAMFree").value = data[1].split(":")[1] + " byte";
|
||||
document.getElementById("ExtRAMLargestFree").value = data[2].split(":")[1] + " byte";
|
||||
document.getElementById("ExtRAMMinFree").value = data[3].split(":")[1] + " byte";
|
||||
}
|
||||
}
|
||||
xhttp.open("GET", url, true);
|
||||
xhttp.send();
|
||||
}
|
||||
|
||||
function init()
|
||||
{
|
||||
loadMemoryInfo();
|
||||
loadLastRestart();
|
||||
loadUptime();
|
||||
loadFWVersion();
|
||||
loadFWBuildTime();
|
||||
loadHTMLVersion();
|
||||
loadHostname();
|
||||
loadIPAddress();
|
||||
loadWLANSSID();
|
||||
loadSDCardManufacturer();
|
||||
loadSDCardName();
|
||||
loadSDCardCapacity();
|
||||
loadSDCardSectorSize();
|
||||
loadSDCardPartitionSize();
|
||||
loadSDCardFreePartitionSpace();
|
||||
loadSDCardPartitionAllocationSize();
|
||||
}
|
||||
|
||||
init();
|
||||
</script>
|
||||
|
||||
@@ -1,19 +1,16 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" xml:lang="en">
|
||||
<html>
|
||||
<head>
|
||||
<title>Log Viewer</title>
|
||||
|
||||
<style>
|
||||
html,
|
||||
body {
|
||||
height: 100%;
|
||||
margin: 1px;
|
||||
margin: 2px;
|
||||
}
|
||||
|
||||
.box {
|
||||
display: flex;
|
||||
flex-flow: column;
|
||||
height: 99.75%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.box .row.header {
|
||||
@@ -32,27 +29,21 @@
|
||||
font-family: 'Courier New', Courier, monospace;
|
||||
font-size: small;
|
||||
}
|
||||
|
||||
.button {
|
||||
padding: 5px 10px;
|
||||
width: 190px;
|
||||
font-size: 16px;
|
||||
}
|
||||
</style>
|
||||
<script type="text/javascript" src="common.js?v=$COMMIT_HASH"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="box">
|
||||
<div class="row header">
|
||||
<button class="button" onClick="reload();">Reload</button>
|
||||
<button class="button" onClick="window.open(getDomainname() + '/logfileact');">Show Full Log</button>
|
||||
<button class="button" onClick="window.location.href = getDomainname() + '/fileserver/log/message/'">Show Older Log Files</button>
|
||||
<button onClick="reload();">Reload</button>
|
||||
<button onClick="window.open(getDomainname() + '/logfileact');">Show full log</button>
|
||||
<button onClick="window.location.href = getDomainname() + '/fileserver/log/message/'">Show older log files</button>
|
||||
</div>
|
||||
<div class="row content" id="log"><br><br><br><b>Loading logfile, please wait...</b></div>
|
||||
<div class="row content" id="log"><br><br><br><b>Loading Logfile, please wait...</b></div>
|
||||
<div class="row footer">
|
||||
<button class="button" onClick="reload();">Reload</button>
|
||||
<button class="button" onClick="window.open(getDomainname() + '/logfileact');">Show Full Log</button>
|
||||
<button class="button" onClick="window.location.href = getDomainname() + '/fileserver/log/message/'">Show Older Log Files</button>
|
||||
<button onClick="reload();">Reload</button>
|
||||
<button onClick="window.open(getDomainname() + '/logfileact');">Show full log</button>
|
||||
<button onClick="window.location.href = getDomainname() + '/fileserver/log/message/'">Show older log files</button>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
|
||||
@@ -1,25 +1,27 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" xml:lang="en">
|
||||
<html>
|
||||
<head>
|
||||
<link rel="icon" href="favicon.ico?v=$COMMIT_HASH" type="image/x-icon">
|
||||
<title>OTA Update</title>
|
||||
<meta charset="UTF-8" />
|
||||
<meta charset="utf-8">
|
||||
|
||||
<style>
|
||||
h1 {font-size: 2em;}
|
||||
h2 {font-size: 1.5em; margin-block-start: 0.0em; margin-block-end: 0.2em;}
|
||||
h3 {font-size: 1.2em;}
|
||||
h2 {font-size: 1.5em;}
|
||||
h3 {font-size: 1.2em;}
|
||||
p {font-size: 1em;}
|
||||
|
||||
input[type=file] {
|
||||
width: 660px;
|
||||
padding: 5px 0px;
|
||||
input[type=number] {
|
||||
width: 138px;
|
||||
padding: 10px 5px;
|
||||
display: inline-block;
|
||||
border: 1px solid #ccc;
|
||||
font-size: 16px;
|
||||
}
|
||||
}
|
||||
|
||||
.button {
|
||||
padding: 5px 10px;
|
||||
width: 205px;
|
||||
padding: 10px 20px;
|
||||
width: 211px;
|
||||
font-size: 16px;
|
||||
}
|
||||
</style>
|
||||
@@ -49,11 +51,11 @@
|
||||
<form id="upload_form" enctype="multipart/form-data" method="post">
|
||||
<input type="file" accept=".bin,.zip,.tfl,.tflite" name="file_selector" id="file_selector" onchange="validate_file()"><br><br>
|
||||
|
||||
<button class="button" id="start_OTA_button" type="button" onclick="start_OTA()" disabled>Upload And Install</button>
|
||||
<button class="button" style="width:300px" id="start_OTA_button" type="button" onclick="start_OTA()" disabled>Upload and install</button>
|
||||
<br><br>
|
||||
<progress id="progressBar" value="0" max="100" style="width:600px;"></progress>
|
||||
<h3><span id="status">Status: Idle</span></h3>
|
||||
<p id="loaded_n_total"></p>
|
||||
<h3><span id="status">Status: idle</span></h3>
|
||||
</form>
|
||||
|
||||
|
||||
@@ -260,10 +262,10 @@
|
||||
|
||||
function progressHandler(event) {
|
||||
_("loaded_n_total").innerHTML = "Uploaded " + (event.loaded / 1024 / 1024).toFixed(2) +
|
||||
" MB of " + (event.total / 1024/ 1024).toFixed(2) + " MB";
|
||||
" MBytes of " + (event.total / 1024/ 1024).toFixed(2) + " MBytes.";
|
||||
var percent = (event.loaded / event.total) * 100;
|
||||
_("progressBar").value = Math.round(percent);
|
||||
_("status").innerHTML = "Status: " + Math.round(percent) + "% uploaded. Please wait...";
|
||||
_("status").innerHTML = "Status: " + Math.round(percent) + "% uploaded... please wait";
|
||||
}
|
||||
|
||||
|
||||
|
||||