mirror of
https://github.com/jomjol/AI-on-the-edge-device.git
synced 2025-12-14 07:26:53 +03:00
Compare commits
45 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
74d4f20858 | ||
|
|
e790a14caa | ||
|
|
f023a6b739 | ||
|
|
1e463188ea | ||
|
|
9991196961 | ||
|
|
ecece0f7fc | ||
|
|
1b3b7595c1 | ||
|
|
6d10f712d1 | ||
|
|
b84a2db050 | ||
|
|
374462a7d8 | ||
|
|
4facd7be05 | ||
|
|
3baf5865ad | ||
|
|
02138c44ac | ||
|
|
1094c8a0a8 | ||
|
|
75b15b8e9d | ||
|
|
36c12b400b | ||
|
|
35d90cd0ee | ||
|
|
999a8d9374 | ||
|
|
8a4269c6a0 | ||
|
|
8f5579cca5 | ||
|
|
e58b3a2cf8 | ||
|
|
222ee0921c | ||
|
|
e2bfcd26c9 | ||
|
|
18917b2d82 | ||
|
|
f0dea3abcb | ||
|
|
bd2d8b4a15 | ||
|
|
80e3f50a5b | ||
|
|
f6ca32d69f | ||
|
|
49e919c481 | ||
|
|
de768c4f44 | ||
|
|
002fc033aa | ||
|
|
f4af8de699 | ||
|
|
e4d6707a0b | ||
|
|
9f03e68690 | ||
|
|
b1df7df580 | ||
|
|
ebc9be4a28 | ||
|
|
5d0fc73c13 | ||
|
|
40a1aa0430 | ||
|
|
d7a733512f | ||
|
|
dc9f1aad27 | ||
|
|
cd3e641bcc | ||
|
|
ad72ffa37c | ||
|
|
2d45a0ed26 | ||
|
|
e8065ef414 | ||
|
|
33893eb566 |
27
.github/label-commenter-config.yml
vendored
27
.github/label-commenter-config.yml
vendored
@@ -3,7 +3,32 @@
|
||||
# Make sure to also add the response to .github/workflows/reply-bot.yml!
|
||||
# Due to the way it works, you have to add each response twice, once for the issue, once for the discussions!
|
||||
|
||||
labels:
|
||||
labels:
|
||||
#######################################################################
|
||||
# Bot Response: Documentation
|
||||
#######################################################################
|
||||
- name: bot-reply Documentation
|
||||
labeled:
|
||||
issue:
|
||||
body: |
|
||||
Please have a look on our documentation: https://jomjol.github.io/AI-on-the-edge-device-docs
|
||||
discussion:
|
||||
body: |
|
||||
Please have a look on our documentation: https://jomjol.github.io/AI-on-the-edge-device-docs
|
||||
|
||||
#######################################################################
|
||||
# Bot Response: ROI setup
|
||||
#######################################################################
|
||||
- name: bot-reply ROI Setup
|
||||
labeled:
|
||||
issue:
|
||||
body: |
|
||||
Make sure to setup your ROIs properly. Have a look on our documentation: https://jomjol.github.io/AI-on-the-edge-device-docs/ROI-Configuration/#how-to-setup-the-digit-rois-perfectly
|
||||
discussion:
|
||||
body: |
|
||||
Make sure to setup your ROIs properly. Have a look on our documentation: https://jomjol.github.io/AI-on-the-edge-device-docs/ROI-Configuration/#how-to-setup-the-digit-rois-perfectly
|
||||
|
||||
|
||||
#######################################################################
|
||||
# Bot Response: Logfile
|
||||
#######################################################################
|
||||
|
||||
@@ -380,7 +380,7 @@ jobs:
|
||||
#########################################################################################
|
||||
## Update the Web Installer on a release
|
||||
#########################################################################################
|
||||
# This is the same as in the update-webinstaller.yml
|
||||
# Make sure to also update update-webinstaller.yml!
|
||||
update-web-installer:
|
||||
needs: [release]
|
||||
environment:
|
||||
@@ -408,12 +408,14 @@ 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
|
||||
cp -f docs/manifest_template.json docs/manifest.json
|
||||
sed -i 's/VERSION/${{ steps.last_release.outputs.tag_name }}/g' docs/manifest.json
|
||||
echo "Updating index and manifest file..."
|
||||
sed -i 's/$VERSION/${{ steps.last_release.outputs.tag_name }}/g' docs/index.html
|
||||
sed -i 's/$VERSION/${{ steps.last_release.outputs.tag_name }}/g' docs/manifest.json
|
||||
- name: Setup Pages
|
||||
uses: actions/configure-pages@v2
|
||||
|
||||
10
.github/workflows/manual-update-webinstaller.yml
vendored
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:
|
||||
# - Changes to the docs folder in the `rolling` branch
|
||||
# - On a release
|
||||
# - Manually triggered
|
||||
# Make sure to also update the lower part of build.yml!
|
||||
|
||||
name: Manual Web Installer Update
|
||||
|
||||
@@ -40,12 +40,14 @@ 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
|
||||
cp -f docs/manifest_template.json docs/manifest.json
|
||||
sed -i 's/VERSION/${{ steps.last_release.outputs.tag_name }}/g' docs/manifest.json
|
||||
echo "Updating index and manifest file..."
|
||||
sed -i 's/$VERSION/${{ steps.last_release.outputs.tag_name }}/g' docs/index.html
|
||||
sed -i 's/$VERSION/${{ steps.last_release.outputs.tag_name }}/g' docs/manifest.json
|
||||
|
||||
- name: Setup Pages
|
||||
uses: actions/configure-pages@v2
|
||||
|
||||
34
Changelog.md
34
Changelog.md
@@ -1,8 +1,40 @@
|
||||
## [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.2.1...v15.2.4)
|
||||
For a full list of changes see [Full list of changes](https://github.com/jomjol/AI-on-the-edge-device/compare/v15.3.0...v15.2.4)
|
||||
|
||||
#### Changed
|
||||
|
||||
|
||||
@@ -2,15 +2,41 @@
|
||||
|
||||
**There are a lot of ideas for further improvements, but only limited capacity on side of the developer.** Therefore I have created this page as a collection of ideas.
|
||||
|
||||
1. Who ever has a new idea can put it here, so it that it is not forgotten.
|
||||
1. Whoever has a new idea can put it here, so that it is not forgotten.
|
||||
|
||||
2. Who ever has time, capacity and passion to support, can take any of the ideas and implement them.
|
||||
I will support and help where ever I can!
|
||||
2. Whoever has the time, capacity and passion to support the project can take any of the ideas and implement them. I will provide support and help wherever I can!
|
||||
|
||||
|
||||
|
||||
____
|
||||
|
||||
|
||||
#### #40 Trigger with cron like exact time slot
|
||||
|
||||
* https://github.com/jomjol/AI-on-the-edge-device/issues/2470
|
||||
|
||||
|
||||
|
||||
#### #39 upnp implementation to auto detect the device
|
||||
|
||||
* https://github.com/jomjol/AI-on-the-edge-device/issues/2481
|
||||
|
||||
|
||||
|
||||
#### #38 Energy Saving
|
||||
|
||||
* Deep sleep between recognition
|
||||
* https://github.com/jomjol/AI-on-the-edge-device/issues/2486
|
||||
|
||||
|
||||
|
||||
#### #37 Auto init SD card
|
||||
|
||||
* Fully implement the SD card handling (including formatting) into the firmware
|
||||
* https://github.com/jomjol/AI-on-the-edge-device/issues/2488Demo
|
||||
|
||||
#### #36 Run demo without camera
|
||||
|
||||
Demo mode requires a working camera (if not, one receives a 'Cam bad' error). Would be nice to demo or play around on other ESP32 boards (or on ESP32-CAM boards when you broke the camera cable...).
|
||||
|
||||
#### #35 Use the same model, but provide the image from a Smartphone Camera
|
||||
@@ -51,7 +77,7 @@ haveing this state in the mqtt broker can trigger functions like closing the ate
|
||||
|
||||
#### ~~#29 Add favicon and use the hostname for the website~~- implemented v11.3.1
|
||||
|
||||
~~* https://github.com/jomjol/AI-on-the-edge-device/issues/927~~
|
||||
* ~~https://github.com/jomjol/AI-on-the-edge-device/issues/927~~
|
||||
|
||||
#### #28 Improved error handling for ROIs
|
||||
|
||||
@@ -89,7 +115,7 @@ haveing this state in the mqtt broker can trigger functions like closing the ate
|
||||
|
||||
#### ~~#22 Direct hint to the different neural network files in the other repositories~~- implemented >v11.3.1
|
||||
|
||||
~~* https://github.com/jomjol/AI-on-the-edge-device/issues/644~~
|
||||
* ~~https://github.com/jomjol/AI-on-the-edge-device/issues/644~~
|
||||
|
||||
|
||||
|
||||
|
||||
98
README.md
98
README.md
@@ -1,31 +1,31 @@
|
||||
# Welcome to the AI-on-the-edge-device
|
||||
<img src="images/icon/watermeter.svg" width="100px">
|
||||
|
||||
Artificial intelligence based systems have been established in our every days live. Just think of speech or image recognition. Most of the systems relay on either powerful processors or a direct connection to the cloud for doing the calculations up there. With the increasing power of modern processors the AI systems are coming closer to the end user - which is usually called **edge computing**.
|
||||
Here this edge computing is brought into a practical oriented example, where a AI network is implemented on a ESP32 device so: **AI on the edge**.
|
||||
Artificial intelligence based systems have become established in our everyday lives. Just think of speech or image recognition. Most of the systems rely on either powerful processors or a direct connection to the cloud for doing the calculations there. With the increasing power of modern processors, the AI systems are coming closer to the end user – which is usually called **edge computing**.
|
||||
Here, this edge computing is put into a practically oriented example, where an AI network is implemented on an ESP32 device so: **AI on the edge**.
|
||||
|
||||
This projects allows you to digitalize your **analoge** water, gas, power and other meters using cheap and easily available hardware.
|
||||
This project allows you to digitize your **analog** water, gas, power and other meters using cheap and easily available hardware.
|
||||
|
||||
All you need is an [ESP32 board with a supported camera](https://jomjol.github.io/AI-on-the-edge-device-docs/Hardware-Compatibility/) and a bit of a practical hand.
|
||||
All you need is an [ESP32 board with a supported camera](https://jomjol.github.io/AI-on-the-edge-device-docs/Hardware-Compatibility/) and something of a practical hand.
|
||||
|
||||
<img src="images/esp32-cam.png" width="200px">
|
||||
|
||||
## Key features
|
||||
- Tensorflow Lite (TFlite) integration - including easy to use wrapper
|
||||
- Inline Image processing (feature detection, alignment, ROI extraction)
|
||||
- **Small** and **cheap** device (3x4.5x2 cm³, < 10 EUR)
|
||||
- camera and illumination integrated
|
||||
- Web surface to administrate and control
|
||||
- OTA-Interface to update directly through the web interface
|
||||
- Tensorflow Lite (TFlite) integration – including easy-to-use wrapper
|
||||
- Inline image processing (feature detection, alignment, ROI extraction)
|
||||
- **Small** and **cheap** device (3 x 4.5 x 2 cm³, < 10 EUR)
|
||||
- Integrated camera and illumination
|
||||
- Web interface for administration and control
|
||||
- OTA interface for updating directly via the web interface
|
||||
- Full integration into Homeassistant
|
||||
- Support for Influx DB 1
|
||||
- Support for Influx DB 1 and 2
|
||||
- MQTT
|
||||
- REST API
|
||||
|
||||
## Workflow
|
||||
The device takes a photo of your meter at a defined interval. It then extracts the Regions of Interest (ROI's) out of it and runs them through an artificial inteligence. As a result, you get the digitalized value of your meter.
|
||||
The device takes a photo of your meter at a defined interval. It then extracts the Regions of Interest (ROIs) from the image and runs them through artificial intelligence. As a result, you get the digitized value of your meter.
|
||||
|
||||
There are several options what to do with that value. Either send it to a MQTT broker, write it to an InfluxDb or simply provide it throug a REST API.
|
||||
There are several options for what to do with that value. Either send it to an MQTT broker, write it to an InfluxDb or simply provide access to it via a REST API.
|
||||
|
||||
<img src="https://raw.githubusercontent.com/jomjol/AI-on-the-edge-device/master/images/idea.jpg" width="600">
|
||||
|
||||
@@ -41,62 +41,68 @@ There are several options what to do with that value. Either send it to a MQTT b
|
||||
|
||||
|
||||
## Setup
|
||||
There is a growing [documentation](https://jomjol.github.io/AI-on-the-edge-device-docs/) which provides you with a lot of information.
|
||||
Head there to get a start, set it up and configure it.
|
||||
There is growing [documentation](https://jomjol.github.io/AI-on-the-edge-device-docs/) which provides you with a lot of information. Head there to get a start, set it up and configure it.
|
||||
|
||||
There are also a articles in the German Heise magazine "make:" about the setup and the technical background (behind a paywall) : [DIY - Setup](https://www.heise.de/select/make/2021/2/2103513300897420296)
|
||||
There are also articles in the German Heise magazine "make:" about the setup and technical background (behind a paywall): [DIY - Setup](https://www.heise.de/select/make/2021/2/2103513300897420296)
|
||||
|
||||
For further background information, head to [Neural Networks](https://www.heise.de/select/make/2021/6/2126410443385102621), [Training Neural Networks](https://www.heise.de/select/make/2022/1/2134114065999161585) and [Programming on the ESP32](https://www.heise.de/select/make/2022/2/2204010051597422030)
|
||||
A lot of people created useful Youtube videos which might help you getting started.
|
||||
Here a small selection:
|
||||
|
||||
- [youtube.com/watch?v=HKBofb1cnNc](https://www.youtube.com/watch?v=HKBofb1cnNc)
|
||||
- [youtube.com/watch?v=yyf0ORNLCk4](https://www.youtube.com/watch?v=yyf0ORNLCk4)
|
||||
- [youtube.com/watch?v=XxmTubGek6M](https://www.youtube.com/watch?v=XxmTubGek6M)
|
||||
- [youtube.com/watch?v=mDIJEyElkAU](https://www.youtube.com/watch?v=mDIJEyElkAU)
|
||||
- [youtube.com/watch?v=SssiPkyKVVs](https://www.youtube.com/watch?v=SssiPkyKVVs)
|
||||
- [youtube.com/watch?v=MAHE_QyHZFQ](https://www.youtube.com/watch?v=MAHE_QyHZFQ)
|
||||
- [youtube.com/watch?v=Uap_6bwtILQ](https://www.youtube.com/watch?v=Uap_6bwtILQ)
|
||||
|
||||
For further background information, head to [Neural Networks](https://www.heise.de/select/make/2021/6/2126410443385102621), [Training Neural Networks](https://www.heise.de/select/make/2022/1/2134114065999161585) and [Programming on the ESP32](https://www.heise.de/select/make/2022/2/2204010051597422030).
|
||||
|
||||
### Download
|
||||
The latest available version is available on the [Releases page](https://github.com/jomjol/AI-on-the-edge-device/releases).
|
||||
The latest available version can be found on the [Releases page](https://github.com/jomjol/AI-on-the-edge-device/releases).
|
||||
|
||||
### Flashing of the ESP32
|
||||
Initially you will have to flash the ESP32 through an USB connection. Later an update is possible directly over the Air (OTA).
|
||||
### Flashing the ESP32
|
||||
Initially you will have to flash the ESP32 via a USB connection. Later updates are possible directly over the air (OTA using WIFI).
|
||||
|
||||
There are different ways to flash your ESP32:
|
||||
- [Web Installer and Console](https://jomjol.github.io/AI-on-the-edge-device/index.html) (Webbrowser based tool to flash the ESP32 and extract the Log over USB)
|
||||
- The 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:
|
||||

|
||||
- Flash Tool from Espressif
|
||||
- ESPtool (Command Line Tool)
|
||||
- ESPtool (command-line tool)
|
||||
|
||||
See the [Docu](https://jomjol.github.io/AI-on-the-edge-device-docs/Installation/) for more information.
|
||||
See the [documentation](https://jomjol.github.io/AI-on-the-edge-device-docs/Installation/) for more information.
|
||||
|
||||
### Flashing the SD-Card
|
||||
The SD-Card must be flashed separately, see the [Docu](https://jomjol.github.io/AI-on-the-edge-device-docs/Installation/) for details.
|
||||
### Flashing the SD Card
|
||||
The SD card can be setup automatically after the firmware got installed. See the [documentation](https://jomjol.github.io/AI-on-the-edge-device-docs/Installation/#remote-setup-using-the-built-in-access-point) for details. For this to work, the SD card must be FAT formated (which is the default on a new SD card).
|
||||
Alternatively the SD card still can be setup manually, see the [documentation](https://jomjol.github.io/AI-on-the-edge-device-docs/Installation/#3-sd-card) for details!
|
||||
|
||||
## Casing
|
||||
|
||||
A 3d-printable housing can be found here:
|
||||
Various 3D-printable housing can be found here:
|
||||
- https://www.thingiverse.com/thing:4573481 (Water Meter)
|
||||
- https://www.thingiverse.com/thing:5028229 (Power Meter)
|
||||
- https://www.thingiverse.com/thing:5224101 (Gas Meter)
|
||||
- https://www.thingiverse.com/thing:4571627 (ESP32-Cam housing only)
|
||||
|
||||
## Build it yourself
|
||||
See [Build Instructions](code/README.md).
|
||||
- https://www.thingiverse.com/thing:4571627 (ESP32-cam housing only)
|
||||
|
||||
## Donate
|
||||
If you would like to support the developer with a cup of coffee you can do that via [Paypal](https://www.paypal.com/donate?hosted_button_id=8TRSVYNYKDSWL).
|
||||
If you would like to support the developer with a cup of coffee, you can do that via [PayPal](https://www.paypal.com/donate?hosted_button_id=8TRSVYNYKDSWL).
|
||||
|
||||
<form action="https://www.paypal.com/donate" method="post" target="_top">
|
||||
<input type="hidden" name="hosted_button_id" value="8TRSVYNYKDSWL" />
|
||||
<input type="image" src="https://www.paypalobjects.com/en_US/DK/i/btn/btn_donateCC_LG.gif" border="0" name="submit" title="PayPal - The safer, easier way to pay online!" alt="Donate with PayPal button" />
|
||||
<img alt="" border="0" src="https://www.paypal.com/en_DE/i/scr/pixel.gif" width="1" height="1" />
|
||||
</form>
|
||||
If you have any technical topics, you can create an [Issue](https://github.com/jomjol/AI-on-the-edge-device/issues).
|
||||
<a href="https://www.paypal.com/donate?hosted_button_id=8TRSVYNYKDSWL"><img border="0" src="images/paypal.png" width="200px" target="_blank"></a>
|
||||
|
||||
In other cases you can contact the developer via email: <img src="https://raw.githubusercontent.com/jomjol/AI-on-the-edge-device/master/images/mail.jpg" height="25">
|
||||
## Support
|
||||
If you have any technical problems please search the [discussions](https://github.com/jomjol/AI-on-the-edge-device/discussions). In case you found a ug or have a feature request, please open an [issue](https://github.com/jomjol/AI-on-the-edge-device/issues).
|
||||
|
||||
In other cases you can contact the developer via email: <img src="https://raw.githubusercontent.com/jomjol/AI-on-the-edge-device/master/images/mail.jpg" height="25">
|
||||
|
||||
## Changes and History
|
||||
See [Changelog](Changelog.md)
|
||||
See [Changelog](Changelog.md).
|
||||
|
||||
## Build It Yourself
|
||||
See [Build Instructions](code/README.md).
|
||||
|
||||
## Tools
|
||||
|
||||
* Logfile downloader and combiner (Thx to [reserve85](https://github.com/reserve85))
|
||||
* Files see ['/tools/logfile-tool'](tbd), How-to see [Docu](https://jomjol.github.io/AI-on-the-edge-device-docs/outdated--Gasmeter-Log-Downloader/)
|
||||
* Files see ['/tools/logfile-tool'](tbd), how-to see [documentation](https://jomjol.github.io/AI-on-the-edge-device-docs/outdated--Gasmeter-Log-Downloader/)
|
||||
|
||||
## Additional Ideas
|
||||
There are some ideas and feature requests which are not followed currently - mainly due to capacity reasons on side of the developer. They are collected here: [FeatureRequest.md](FeatureRequest.md)
|
||||
|
||||
------
|
||||
|
||||
There are some ideas and feature requests which are not currently being pursued – mainly due to capacity reasons on the part of the developers.
|
||||
They features are collected in the [issues](https://github.com/jomjol/AI-on-the-edge-device/issues) and in [FeatureRequest.md](FeatureRequest.md).
|
||||
|
||||
1
code/.gitignore
vendored
1
code/.gitignore
vendored
@@ -1,4 +1,5 @@
|
||||
.pio
|
||||
.idea
|
||||
.vscode/.browse.c_cpp.db*
|
||||
.vscode/c_cpp_properties.json
|
||||
.vscode/launch.json
|
||||
|
||||
@@ -8,6 +8,15 @@ git checkout rolling
|
||||
git submodule update --init
|
||||
```
|
||||
|
||||
## Update Submodules
|
||||
```
|
||||
cd /components/submodule-name (e.g. tflite-micro-example)
|
||||
git checkout VERSION (e.g. HASH of latest tflite-micro-example build)
|
||||
cd ../../ (auf Ebene von code)
|
||||
git submodule update --init
|
||||
```
|
||||
Evt. muss man vorher noch einige Verzeichnisse in compenents von Hand löschen, da sie beim checkout nicht gelöscht wurden (vor update -- init)
|
||||
|
||||
## Build and Flash within terminal
|
||||
See further down to build it within an IDE.
|
||||
### Compile
|
||||
|
||||
Submodule code/components/esp-nn updated: 6b3ef8e226...1a35708d93
Submodule code/components/esp32-camera updated: 5c8349f4cf...c0c17bd3de
@@ -2,6 +2,6 @@ FILE(GLOB_RECURSE app_sources ${CMAKE_CURRENT_SOURCE_DIR}/*.*)
|
||||
|
||||
idf_component_register(SRCS ${app_sources}
|
||||
INCLUDE_DIRS "." "../../include" "miniz"
|
||||
REQUIRES vfs tflite-lib esp_http_server app_update esp_http_client nvs_flash jomjol_tfliteclass jomjol_flowcontroll spiffs jomjol_helper jomjol_controlGPIO)
|
||||
REQUIRES vfs esp_http_server app_update esp_http_client nvs_flash jomjol_tfliteclass jomjol_flowcontroll spiffs jomjol_helper jomjol_controlGPIO)
|
||||
|
||||
|
||||
|
||||
@@ -588,7 +588,9 @@ static esp_err_t download_get_handler(httpd_req_t *req)
|
||||
/* Read file in chunks into the scratch buffer */
|
||||
chunksize = fread(chunk, 1, SERVER_FILER_SCRATCH_BUFSIZE, fd);
|
||||
|
||||
/* Send the buffer contents as HTTP response chunk */
|
||||
/* Send buffer contents as HTTP chunk. If empty this functions as a
|
||||
* last-chunk message, signaling end-of-response, to the HTTP client.
|
||||
* See RFC 2616, section 3.6.1 for details on Chunked Transfer Encoding. */
|
||||
if (httpd_resp_send_chunk(req, chunk, chunksize) != ESP_OK) {
|
||||
fclose(fd);
|
||||
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "File sending failed!");
|
||||
@@ -606,8 +608,6 @@ static esp_err_t download_get_handler(httpd_req_t *req)
|
||||
fclose(fd);
|
||||
ESP_LOGD(TAG, "File successfully sent");
|
||||
|
||||
/* Respond with an empty chunk to signal HTTP response completion */
|
||||
httpd_resp_send_chunk(req, NULL, 0);
|
||||
return ESP_OK;
|
||||
}
|
||||
|
||||
|
||||
@@ -145,7 +145,8 @@ int ClassFlowCNNGeneral::PointerEvalHybridNew(float number, float number_of_pred
|
||||
{
|
||||
// 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
|
||||
result = (int) ((int) trunc(number) + 10) % 10;
|
||||
// add precisition of 2 digits and round before trunc
|
||||
result = (int) ((int) trunc(round((number+10 % 10)*100)) ) / 100;
|
||||
|
||||
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));
|
||||
@@ -484,7 +485,7 @@ bool ClassFlowCNNGeneral::doFlow(string time)
|
||||
|
||||
if (!doAlignAndCut(time)){
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "doFlow after alignment");
|
||||
|
||||
@@ -852,10 +853,9 @@ bool ClassFlowCNNGeneral::doNeuralNetwork(string time)
|
||||
|
||||
bool ClassFlowCNNGeneral::isExtendedResolution(int _number)
|
||||
{
|
||||
if (!(CNNType == Digital))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
if (CNNType == Digital)
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ static const char* TAG = "INFLUXDBV2";
|
||||
void ClassFlowInfluxDBv2::SetInitialParameter(void)
|
||||
{
|
||||
uri = "";
|
||||
database = "";
|
||||
bucket = "";
|
||||
dborg = "";
|
||||
dbtoken = "";
|
||||
// dbfield = "";
|
||||
@@ -109,9 +109,9 @@ bool ClassFlowInfluxDBv2::ReadParameter(FILE* pfile, string& aktparamgraph)
|
||||
{
|
||||
handleMeasurement(splitted[0], splitted[1]);
|
||||
}
|
||||
if (((toUpper(splitted[0]) == "DATABASE")) && (splitted.size() > 1))
|
||||
if (((toUpper(splitted[0]) == "BUCKET")) && (splitted.size() > 1))
|
||||
{
|
||||
this->database = splitted[1];
|
||||
this->bucket = splitted[1];
|
||||
}
|
||||
}
|
||||
|
||||
@@ -119,11 +119,11 @@ bool ClassFlowInfluxDBv2::ReadParameter(FILE* pfile, string& aktparamgraph)
|
||||
printf("org: %s\n", dborg.c_str());
|
||||
printf("token: %s\n", dbtoken.c_str());
|
||||
|
||||
if ((uri.length() > 0) && (database.length() > 0) && (dbtoken.length() > 0) && (dborg.length() > 0))
|
||||
if ((uri.length() > 0) && (bucket.length() > 0) && (dbtoken.length() > 0) && (dborg.length() > 0))
|
||||
{
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Init InfluxDB with uri: " + uri + ", org: " + dborg + ", token: *****");
|
||||
// printf("vor V2 Init\n");
|
||||
InfluxDB_V2_Init(uri, database, dborg, dbtoken);
|
||||
InfluxDB_V2_Init(uri, bucket, dborg, dbtoken);
|
||||
// printf("nach V2 Init\n");
|
||||
InfluxDBenable = true;
|
||||
} else {
|
||||
|
||||
@@ -15,7 +15,7 @@ class ClassFlowInfluxDBv2 :
|
||||
public ClassFlow
|
||||
{
|
||||
protected:
|
||||
std::string uri, database;
|
||||
std::string uri, bucket;
|
||||
std::string dborg, dbtoken, dbfield;
|
||||
std::string OldValue;
|
||||
ClassFlowPostProcessing* flowpostprocessing;
|
||||
|
||||
@@ -37,6 +37,9 @@ void ClassFlowMQTT::SetInitialParameter(void)
|
||||
topicUptime = "";
|
||||
topicFreeMem = "";
|
||||
|
||||
caCertFilename = "";
|
||||
clientCertFilename = "";
|
||||
clientKeyFilename = "";
|
||||
clientname = wlan_config.hostname;
|
||||
|
||||
OldValue = "";
|
||||
@@ -102,6 +105,18 @@ bool ClassFlowMQTT::ReadParameter(FILE* pfile, string& aktparamgraph)
|
||||
while (this->getNextLine(pfile, &aktparamgraph) && !this->isNewParagraph(aktparamgraph))
|
||||
{
|
||||
splitted = ZerlegeZeile(aktparamgraph);
|
||||
if ((toUpper(splitted[0]) == "CACERT") && (splitted.size() > 1))
|
||||
{
|
||||
this->caCertFilename = splitted[1];
|
||||
}
|
||||
if ((toUpper(splitted[0]) == "CLIENTCERT") && (splitted.size() > 1))
|
||||
{
|
||||
this->clientCertFilename = splitted[1];
|
||||
}
|
||||
if ((toUpper(splitted[0]) == "CLIENTKEY") && (splitted.size() > 1))
|
||||
{
|
||||
this->clientKeyFilename = splitted[1];
|
||||
}
|
||||
if ((toUpper(splitted[0]) == "USER") && (splitted.size() > 1))
|
||||
{
|
||||
this->user = splitted[1];
|
||||
@@ -196,7 +211,8 @@ bool ClassFlowMQTT::Start(float AutoInterval)
|
||||
mqttServer_setParameter(flowpostprocessing->GetNumbers(), keepAlive, roundInterval);
|
||||
|
||||
bool MQTTConfigCheck = MQTT_Configure(uri, clientname, user, password, maintopic, LWT_TOPIC, LWT_CONNECTED,
|
||||
LWT_DISCONNECTED, keepAlive, SetRetainFlag, (void *)&GotConnected);
|
||||
LWT_DISCONNECTED, caCertFilename, clientCertFilename, clientKeyFilename,
|
||||
keepAlive, SetRetainFlag, (void *)&GotConnected);
|
||||
|
||||
if (!MQTTConfigCheck) {
|
||||
return false;
|
||||
|
||||
@@ -19,6 +19,7 @@ protected:
|
||||
std::string OldValue;
|
||||
ClassFlowPostProcessing* flowpostprocessing;
|
||||
std::string user, password;
|
||||
std::string caCertFilename, clientCertFilename, clientKeyFilename;
|
||||
bool SetRetainFlag;
|
||||
int keepAlive; // Seconds
|
||||
float roundInterval; // Minutes
|
||||
|
||||
@@ -2,6 +2,6 @@ FILE(GLOB_RECURSE app_sources ${CMAKE_CURRENT_SOURCE_DIR}/*.*)
|
||||
|
||||
idf_component_register(SRCS ${app_sources}
|
||||
INCLUDE_DIRS "."
|
||||
REQUIRES tflite-lib esp_http_client jomjol_logfile)
|
||||
REQUIRES esp_http_client jomjol_logfile)
|
||||
|
||||
|
||||
|
||||
@@ -16,16 +16,16 @@ std::string _influxDBUser;
|
||||
std::string _influxDBPassword;
|
||||
|
||||
std::string _influxDB_V2_URI;
|
||||
std::string _influxDB_V2_Database;
|
||||
std::string _influxDB_V2_Bucket;
|
||||
std::string _influxDB_V2_Token;
|
||||
std::string _influxDB_V2_Org;
|
||||
|
||||
static esp_err_t http_event_handler(esp_http_client_event_t *evt);
|
||||
|
||||
void InfluxDB_V2_Init(std::string _uri, std::string _database, std::string _org, std::string _token)
|
||||
void InfluxDB_V2_Init(std::string _uri, std::string _bucket, std::string _org, std::string _token)
|
||||
{
|
||||
_influxDB_V2_URI = _uri;
|
||||
_influxDB_V2_Database = _database;
|
||||
_influxDB_V2_Bucket = _bucket;
|
||||
_influxDB_V2_Org = _org;
|
||||
_influxDB_V2_Token = _token;
|
||||
}
|
||||
@@ -49,20 +49,16 @@ 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);
|
||||
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));
|
||||
t = mktime(&tm);
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Timestamp: " + _timestamp + ", Timestamp (UTC): " + std::to_string(t));
|
||||
|
||||
sprintf(nowTimestamp,"%ld000000000", (long) t); // UTC
|
||||
|
||||
payload = _measurement + " " + _key + "=" + _content + " " + nowTimestamp;
|
||||
}
|
||||
else
|
||||
@@ -74,7 +70,7 @@ void InfluxDB_V2_Publish(std::string _measurement, std::string _key, std::string
|
||||
|
||||
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "sending line to influxdb:" + payload);
|
||||
|
||||
std::string apiURI = _influxDB_V2_URI + "/api/v2/write?org=" + _influxDB_V2_Org + "&bucket=" + _influxDB_V2_Database;
|
||||
std::string apiURI = _influxDB_V2_URI + "/api/v2/write?org=" + _influxDB_V2_Org + "&bucket=" + _influxDB_V2_Bucket;
|
||||
apiURI.shrink_to_fit();
|
||||
http_config.url = apiURI.c_str();
|
||||
ESP_LOGI(TAG, "http_config: %s", http_config.url); // Add mark on log to see when it restarted
|
||||
@@ -165,20 +161,16 @@ 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);
|
||||
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));
|
||||
t = mktime(&tm);
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Timestamp: " + _timestamp + ", Timestamp (UTC): " + std::to_string(t));
|
||||
|
||||
sprintf(nowTimestamp,"%ld000000000", (long) t); // UTC
|
||||
|
||||
payload = _measurement + " " + _key + "=" + _content + " " + nowTimestamp;
|
||||
}
|
||||
else
|
||||
@@ -191,7 +183,7 @@ void InfluxDBPublish(std::string _measurement, std::string _key, std::string _co
|
||||
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "sending line to influxdb:" + payload);
|
||||
|
||||
|
||||
// use the default retention policy of the database
|
||||
// use the default retention policy of the bucket
|
||||
std::string apiURI = _influxDBURI + "/write?db=" + _influxDBDatabase;
|
||||
// std::string apiURI = _influxDBURI + "/api/v2/write?bucket=" + _influxDBDatabase + "/";
|
||||
|
||||
|
||||
@@ -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 _database, std::string _org, std::string _token);
|
||||
void InfluxDB_V2_Init(std::string _uri, std::string _bucket, std::string _org, std::string _token);
|
||||
void InfluxDB_V2_Publish(std::string _measurement, std::string _key, std::string _content, std::string _timestamp);
|
||||
|
||||
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
#include "interface_mqtt.h"
|
||||
|
||||
#include "esp_log.h"
|
||||
#if DEBUG_DETAIL_ON
|
||||
#include "esp_timer.h"
|
||||
#endif
|
||||
#include "connect_wlan.h"
|
||||
#include "mqtt_client.h"
|
||||
#include "ClassLogFile.h"
|
||||
@@ -32,6 +35,7 @@ bool mqtt_connected = false;
|
||||
|
||||
esp_mqtt_client_handle_t client = NULL;
|
||||
std::string uri, client_id, lwt_topic, lwt_connected, lwt_disconnected, user, password, maintopic;
|
||||
std::string caCert, clientCert, clientKey;
|
||||
int keepalive;
|
||||
bool SetRetainFlag;
|
||||
void (*callbackOnConnected)(std::string, bool) = NULL;
|
||||
@@ -169,6 +173,10 @@ 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:");
|
||||
@@ -198,6 +206,7 @@ static void mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_
|
||||
|
||||
bool MQTT_Configure(std::string _mqttURI, std::string _clientid, std::string _user, std::string _password,
|
||||
std::string _maintopic, std::string _lwt, std::string _lwt_connected, std::string _lwt_disconnected,
|
||||
std::string _cacertfilename, std::string _clientcertfilename, std::string _clientkeyfilename,
|
||||
int _keepalive, bool _SetRetainFlag, void *_callbackOnConnected) {
|
||||
if ((_mqttURI.length() == 0) || (_maintopic.length() == 0) || (_clientid.length() == 0))
|
||||
{
|
||||
@@ -215,6 +224,25 @@ bool MQTT_Configure(std::string _mqttURI, std::string _clientid, std::string _us
|
||||
maintopic = _maintopic;
|
||||
callbackOnConnected = ( void (*)(std::string, bool) )(_callbackOnConnected);
|
||||
|
||||
if (_clientcertfilename.length() && _clientkeyfilename.length()){
|
||||
std::ifstream cert_ifs(_clientcertfilename);
|
||||
std::string cert_content((std::istreambuf_iterator<char>(cert_ifs)), (std::istreambuf_iterator<char>()));
|
||||
clientCert = cert_content;
|
||||
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "using clientCert: " + _clientcertfilename);
|
||||
|
||||
std::ifstream key_ifs(_clientkeyfilename);
|
||||
std::string key_content((std::istreambuf_iterator<char>(key_ifs)), (std::istreambuf_iterator<char>()));
|
||||
clientKey = key_content;
|
||||
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "using clientKey: " + _clientkeyfilename);
|
||||
}
|
||||
|
||||
if (_cacertfilename.length() ){
|
||||
std::ifstream ifs(_cacertfilename);
|
||||
std::string content((std::istreambuf_iterator<char>(ifs)), (std::istreambuf_iterator<char>()));
|
||||
caCert = content;
|
||||
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "using caCert: " + _cacertfilename);
|
||||
}
|
||||
|
||||
if (_user.length() && _password.length()){
|
||||
user = _user;
|
||||
password = _password;
|
||||
@@ -268,6 +296,20 @@ int MQTT_Init() {
|
||||
mqtt_cfg.session.keepalive = keepalive;
|
||||
mqtt_cfg.buffer.size = 1536; // size of MQTT send/receive buffer (Default: 1024)
|
||||
|
||||
if (caCert.length()){
|
||||
mqtt_cfg.broker.verification.certificate = caCert.c_str();
|
||||
mqtt_cfg.broker.verification.certificate_len = caCert.length() + 1;
|
||||
mqtt_cfg.broker.verification.skip_cert_common_name_check = true;
|
||||
}
|
||||
|
||||
if (clientCert.length() && clientKey.length()){
|
||||
mqtt_cfg.credentials.authentication.certificate = clientCert.c_str();
|
||||
mqtt_cfg.credentials.authentication.certificate_len = clientCert.length() + 1;
|
||||
|
||||
mqtt_cfg.credentials.authentication.key = clientKey.c_str();
|
||||
mqtt_cfg.credentials.authentication.key_len = clientKey.length() + 1;
|
||||
}
|
||||
|
||||
if (user.length() && password.length()){
|
||||
mqtt_cfg.credentials.username = user.c_str();
|
||||
mqtt_cfg.credentials.authentication.password = password.c_str();
|
||||
@@ -371,8 +413,10 @@ bool mqtt_handler_set_prevalue(std::string _topic, char* _data, int _data_len)
|
||||
if (cJSON_IsNumber(value)) { // Check if value is a number
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "handler_set_prevalue called: numbersname: " + std::string(numbersname->valuestring) +
|
||||
", value: " + std::to_string(value->valuedouble));
|
||||
if (flowctrl.UpdatePrevalue(std::to_string(value->valuedouble), std::string(numbersname->valuestring), true))
|
||||
if (flowctrl.UpdatePrevalue(std::to_string(value->valuedouble), std::string(numbersname->valuestring), true)) {
|
||||
cJSON_Delete(jsonData);
|
||||
return ESP_OK;
|
||||
}
|
||||
}
|
||||
else {
|
||||
LogFile.WriteToFile(ESP_LOG_WARN, TAG, "handler_set_prevalue: value not a valid number (\"value\": 12345.12345)");
|
||||
@@ -381,6 +425,7 @@ bool mqtt_handler_set_prevalue(std::string _topic, char* _data, int _data_len)
|
||||
else {
|
||||
LogFile.WriteToFile(ESP_LOG_WARN, TAG, "handler_set_prevalue: numbersname not a valid string (\"numbersname\": \"main\")");
|
||||
}
|
||||
cJSON_Delete(jsonData);
|
||||
}
|
||||
else {
|
||||
LogFile.WriteToFile(ESP_LOG_WARN, TAG, "handler_set_prevalue: handler called, but no data received");
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
|
||||
bool MQTT_Configure(std::string _mqttURI, std::string _clientid, std::string _user, std::string _password,
|
||||
std::string _maintopic, std::string _lwt, std::string _lwt_connected, std::string _lwt_disconnected,
|
||||
std::string _cacertfilename, std::string _clientcertfilename, std::string _clientkeyfilename,
|
||||
int _keepalive, bool SetRetainFlag, void *callbackOnConnected);
|
||||
int MQTT_Init();
|
||||
void MQTTdestroy_client(bool _disable);
|
||||
|
||||
@@ -12,6 +12,31 @@
|
||||
|
||||
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);
|
||||
@@ -179,16 +204,20 @@ bool CTfLiteClass::LoadInputImageBasis(CImageBasis *rs)
|
||||
}
|
||||
|
||||
|
||||
|
||||
bool CTfLiteClass::MakeAllocate()
|
||||
{
|
||||
static tflite::AllOpsResolver resolver;
|
||||
|
||||
MakeStaticResolver();
|
||||
|
||||
|
||||
#ifdef DEBUG_DETAIL_ON
|
||||
LogFile.WriteHeapInfo("CTLiteClass::Alloc start");
|
||||
#endif
|
||||
|
||||
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "CTfLiteClass::MakeAllocate");
|
||||
this->interpreter = new tflite::MicroInterpreter(this->model, resolver, this->tensor_arena, this->kTensorArenaSize, this->error_reporter);
|
||||
this->interpreter = new tflite::MicroInterpreter(this->model, resolver, this->tensor_arena, this->kTensorArenaSize);
|
||||
// this->interpreter = new tflite::MicroInterpreter(this->model, resolver, this->tensor_arena, this->kTensorArenaSize, this->error_reporter);
|
||||
|
||||
if (this->interpreter)
|
||||
{
|
||||
@@ -285,6 +314,7 @@ 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;
|
||||
@@ -320,16 +350,21 @@ 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,8 +3,12 @@
|
||||
#ifndef CTFLITECLASS_H
|
||||
#define CTFLITECLASS_H
|
||||
|
||||
#include "tensorflow/lite/micro/all_ops_resolver.h"
|
||||
#include "tensorflow/lite/micro/micro_error_reporter.h"
|
||||
#include "tensorflow/lite/micro/micro_mutable_op_resolver.h"
|
||||
#include "tensorflow/lite/micro/micro_interpreter.h"
|
||||
#include "tensorflow/lite/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/micro_interpreter.h"
|
||||
#include "tensorflow/lite/schema/schema_generated.h"
|
||||
#include "tensorflow/lite/micro/kernels/micro_ops.h"
|
||||
@@ -13,6 +17,8 @@
|
||||
|
||||
#include "CImageBasis.h"
|
||||
|
||||
|
||||
|
||||
#ifdef SUPRESS_TFLITE_ERRORS
|
||||
#include "tensorflow/lite/core/api/error_reporter.h"
|
||||
#include "tensorflow/lite/micro/compatibility.h"
|
||||
@@ -27,6 +33,7 @@ namespace tflite {
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
#endif
|
||||
|
||||
|
||||
class CTfLiteClass
|
||||
{
|
||||
protected:
|
||||
@@ -34,7 +41,6 @@ class CTfLiteClass
|
||||
const tflite::Model* model;
|
||||
tflite::MicroInterpreter* interpreter;
|
||||
TfLiteTensor* output = nullptr;
|
||||
static tflite::AllOpsResolver resolver;
|
||||
|
||||
int kTensorArenaSize;
|
||||
uint8_t *tensor_arena;
|
||||
@@ -68,4 +74,6 @@ class CTfLiteClass
|
||||
int ReadInputDimenstion(int _dim);
|
||||
};
|
||||
|
||||
void MakeStaticResolver();
|
||||
|
||||
#endif //CTFLITECLASS_H
|
||||
Submodule code/components/tflite-micro-esp-examples updated: 095f55a6ee...1ccd7e14ac
@@ -1,3 +1,9 @@
|
||||
manifest_hash: 63f5c6c9f0bcebc7b9ca12d2aa8b26b2c5f5218d377dc4b2375d9b9ca1df7815
|
||||
dependencies:
|
||||
idf:
|
||||
component_hash: null
|
||||
source:
|
||||
type: idf
|
||||
version: 5.0.2
|
||||
manifest_hash: f880feca80f04921fc95fd31e9c2936b9896764c15a62f6e2d312c57a62a36db
|
||||
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
|
||||
|
||||
@@ -642,7 +642,6 @@ 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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -650,7 +649,10 @@ 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
|
||||
}
|
||||
/* 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
|
||||
}
|
||||
}
|
||||
|
||||
@@ -721,6 +723,7 @@ 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;
|
||||
@@ -813,4 +816,4 @@ bool setCpuFrequency(void) {
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -39,17 +39,21 @@ esp_err_t info_get_handler(httpd_req_t *req)
|
||||
char _valuechar[30];
|
||||
std::string _task;
|
||||
|
||||
if (httpd_req_get_url_query_str(req, _query, 200) == ESP_OK)
|
||||
if (httpd_req_get_url_query_str(req, _query, 200) != ESP_OK)
|
||||
{
|
||||
ESP_LOGD(TAG, "Query: %s", _query);
|
||||
|
||||
if (httpd_query_key_value(_query, "type", _valuechar, 30) == ESP_OK)
|
||||
{
|
||||
ESP_LOGD(TAG, "type is found: %s", _valuechar);
|
||||
_task = std::string(_valuechar);
|
||||
}
|
||||
return httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "invalid query string");
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, "Query: %s", _query);
|
||||
|
||||
if (httpd_query_key_value(_query, "type", _valuechar, 30) != ESP_OK)
|
||||
{
|
||||
return httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "missing or invalid 'type' query parameter (too long value?)");
|
||||
}
|
||||
|
||||
ESP_LOGD(TAG, "type is found: %s", _valuechar);
|
||||
_task = std::string(_valuechar);
|
||||
|
||||
httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
|
||||
|
||||
if (_task.compare("GitBranch") == 0)
|
||||
@@ -166,6 +170,12 @@ 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;
|
||||
}
|
||||
|
||||
Binary file not shown.
@@ -18,16 +18,19 @@
|
||||
|
||||
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>
|
||||
|
||||
<p>Notes:</p>
|
||||
<h2>Notes:</h2>
|
||||
<ul>
|
||||
<li>For the installation, make sure to switch the ESP32 to Bootloader mode!</li>
|
||||
<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>After the installation, a manual reset might be required!</li>
|
||||
<li>Please note that not all webbrowsers and operating systems support the needed access to USB!</li>
|
||||
<li>Please note that not all web browsers and operating systems support the necessary USB access needed for this Webinstaller!</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 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>
|
||||
|
||||
<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>
|
||||
</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": "13.0.8",
|
||||
"version": "$VERSION",
|
||||
"funding_url": "https://www.paypal.com/donate?hosted_button_id=8TRSVYNYKDSWL",
|
||||
"new_install_prompt_erase": false,
|
||||
"builds": [
|
||||
|
||||
@@ -1,25 +0,0 @@
|
||||
{
|
||||
"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
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
# 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/
|
||||
BIN
images/paypal.png
Normal file
BIN
images/paypal.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 69 KiB |
BIN
images/web-installer.png
Normal file
BIN
images/web-installer.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 82 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
sd-card/config/ana-class100_0171_s1_q.tflite
Normal file
BIN
sd-card/config/ana-class100_0171_s1_q.tflite
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
sd-card/config/ana-cont_1208_s2_q.tflite
Normal file
BIN
sd-card/config/ana-cont_1208_s2_q.tflite
Normal file
Binary file not shown.
@@ -31,7 +31,7 @@ main.dig2 343 126 30 54 false
|
||||
main.dig3 391 126 30 54 false
|
||||
|
||||
[Analog]
|
||||
Model = /config/ana-cont_1207_s2_q.tflite
|
||||
Model = /config/ana-cont_1208_s2_q.tflite
|
||||
CNNGoodThreshold = 0.5
|
||||
;ROIImagesLocation = /log/analog
|
||||
;ROIImagesRetention = 3
|
||||
@@ -62,6 +62,9 @@ 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
|
||||
@@ -72,7 +75,7 @@ HomeassistantDiscovery = false
|
||||
|
||||
;[InfluxDBv2]
|
||||
;Uri = undefined
|
||||
;Database = undefined
|
||||
;Bucket = undefined
|
||||
;Measurement = undefined
|
||||
;Org = undefined
|
||||
;Token = undefined
|
||||
|
||||
Binary file not shown.
BIN
sd-card/config/dig-class100-0168_s2_q.tflite
Normal file
BIN
sd-card/config/dig-class100-0168_s2_q.tflite
Normal file
Binary file not shown.
BIN
sd-card/config/dig-class11_1700_s2.tflite
Normal file
BIN
sd-card/config/dig-class11_1700_s2.tflite
Normal file
Binary file not shown.
@@ -1,19 +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! */
|
||||
var domainname_for_testing = "192.168.1.151";
|
||||
* 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";
|
||||
|
||||
|
||||
/* 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 (((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);
|
||||
if (domainname_for_testing != "") {
|
||||
console.log("Using pre-defined domainname for testing: " + domainname_for_testing);
|
||||
domainname = "http://" + domainname_for_testing
|
||||
}
|
||||
else
|
||||
|
||||
@@ -753,6 +753,39 @@
|
||||
<td>$TOOLTIP_MQTT_password</td>
|
||||
</tr>
|
||||
|
||||
<tr class="MQTTItem expert" id="exMqtt">
|
||||
<td class="indent1">
|
||||
<input type="checkbox" id="MQTT_CACert_enabled" value="1" onclick = 'InvertEnableItem("MQTT", "CACert")' unchecked >
|
||||
<label for=MQTT_CACert_enabled><class id="MQTT_CACert_text" style="color:black;">Root CA Certificate file</class></label>
|
||||
</td>
|
||||
<td>
|
||||
<input type="text" id="MQTT_CACert_value1">
|
||||
</td>
|
||||
<td>$TOOLTIP_MQTT_CACert</td>
|
||||
</tr>
|
||||
|
||||
<tr class="MQTTItem expert" id="exMqtt">
|
||||
<td class="indent1">
|
||||
<input type="checkbox" id="MQTT_ClientCert_enabled" value="1" onclick = 'InvertEnableItem("MQTT", "ClientCert")' unchecked >
|
||||
<label for=MQTT_ClientCert_enabled><class id="MQTT_ClientCert_text" style="color:black;">Client Certificate file</class></label>
|
||||
</td>
|
||||
<td>
|
||||
<input type="text" id="MQTT_ClientCert_value1">
|
||||
</td>
|
||||
<td>$TOOLTIP_MQTT_ClientCert</td>
|
||||
</tr>
|
||||
|
||||
<tr class="MQTTItem expert" id="exMqtt">
|
||||
<td class="indent1">
|
||||
<input type="checkbox" id="MQTT_ClientKey_enabled" value="1" onclick = 'InvertEnableItem("MQTT", "ClientKey")' unchecked >
|
||||
<label for=MQTT_ClientKey_enabled><class id="MQTT_ClientKey_text" style="color:black;">Client Key file</class></label>
|
||||
</td>
|
||||
<td>
|
||||
<input type="text" id="MQTT_ClientKey_value1">
|
||||
</td>
|
||||
<td>$TOOLTIP_MQTT_ClientKey</td>
|
||||
</tr>
|
||||
|
||||
<tr class="MQTTItem">
|
||||
<td class="indent1">
|
||||
<label><class id="MQTT_RetainMessages_text" style="color:black;">Retain Messages</class></label>
|
||||
@@ -919,13 +952,13 @@
|
||||
|
||||
<tr class="InfluxDBv2Item">
|
||||
<td class="indent1">
|
||||
<input type="checkbox" id="InfluxDBv2_Database_enabled" value="1" onclick = 'InvertEnableItem("InfluxDBv2", "Database")' unchecked >
|
||||
<label for=InfluxDBv2_Database_enabled><class id="InfluxDBv2_Database_text" style="color:black;">Database</class></label>
|
||||
<input type="checkbox" id="InfluxDBv2_Bucket_enabled" value="1" onclick = 'InvertEnableItem("InfluxDBv2", "Bucket")' unchecked >
|
||||
<label for=InfluxDBv2_Bucket_enabled><class id="InfluxDBv2_Bucket_text" style="color:black;">Bucket</class></label>
|
||||
</td>
|
||||
<td>
|
||||
<input required type="text" id="InfluxDBv2_Database_value1">
|
||||
<input required type="text" id="InfluxDBv2_Bucket_value1">
|
||||
</td>
|
||||
<td>$TOOLTIP_InfluxDBv2_Database</td>
|
||||
<td>$TOOLTIP_InfluxDBv2_Bucket</td>
|
||||
</tr>
|
||||
|
||||
<tr class="InfluxDBv2Item">
|
||||
@@ -2089,6 +2122,9 @@ function UpdateInput() {
|
||||
WriteParameter(param, category, "MQTT", "RetainMessages", false);
|
||||
WriteParameter(param, category, "MQTT", "HomeassistantDiscovery", false);
|
||||
WriteParameter(param, category, "MQTT", "MeterType", true);
|
||||
WriteParameter(param, category, "MQTT", "CACert", true);
|
||||
WriteParameter(param, category, "MQTT", "ClientCert", true);
|
||||
WriteParameter(param, category, "MQTT", "ClientKey", true);
|
||||
|
||||
WriteParameter(param, category, "InfluxDB", "Uri", true);
|
||||
WriteParameter(param, category, "InfluxDB", "Database", true);
|
||||
@@ -2098,7 +2134,7 @@ function UpdateInput() {
|
||||
// WriteParameter(param, category, "InfluxDB", "Field", true);
|
||||
|
||||
WriteParameter(param, category, "InfluxDBv2", "Uri", true);
|
||||
WriteParameter(param, category, "InfluxDBv2", "Database", true);
|
||||
WriteParameter(param, category, "InfluxDBv2", "Bucket", true);
|
||||
// WriteParameter(param, category, "InfluxDBv2", "Measurement", true);
|
||||
WriteParameter(param, category, "InfluxDBv2", "Org", true);
|
||||
WriteParameter(param, category, "InfluxDBv2", "Token", true);
|
||||
@@ -2225,6 +2261,9 @@ function ReadParameterAll()
|
||||
ReadParameter(param, "MQTT", "RetainMessages", false);
|
||||
ReadParameter(param, "MQTT", "HomeassistantDiscovery", false);
|
||||
ReadParameter(param, "MQTT", "MeterType", true);
|
||||
ReadParameter(param, "MQTT", "CACert", true);
|
||||
ReadParameter(param, "MQTT", "ClientCert", true);
|
||||
ReadParameter(param, "MQTT", "ClientKey", true);
|
||||
|
||||
ReadParameter(param, "InfluxDB", "Uri", true);
|
||||
ReadParameter(param, "InfluxDB", "Database", true);
|
||||
@@ -2233,7 +2272,7 @@ function ReadParameterAll()
|
||||
ReadParameter(param, "InfluxDB", "password", true);
|
||||
|
||||
ReadParameter(param, "InfluxDBv2", "Uri", true);
|
||||
ReadParameter(param, "InfluxDBv2", "Database", true);
|
||||
ReadParameter(param, "InfluxDBv2", "Bucket", true);
|
||||
ReadParameter(param, "InfluxDBv2", "Measurement", true);
|
||||
ReadParameter(param, "InfluxDBv2", "Org", true);
|
||||
ReadParameter(param, "InfluxDBv2", "Token", true);
|
||||
|
||||
@@ -2,6 +2,8 @@
|
||||
<html lang="en" xml:lang="en">
|
||||
<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">
|
||||
|
||||
@@ -183,6 +183,9 @@ function ParseConfig() {
|
||||
ParamAddValue(param, catname, "RetainMessages");
|
||||
ParamAddValue(param, catname, "HomeassistantDiscovery");
|
||||
ParamAddValue(param, catname, "MeterType");
|
||||
ParamAddValue(param, catname, "CACert");
|
||||
ParamAddValue(param, catname, "ClientCert");
|
||||
ParamAddValue(param, catname, "ClientKey");
|
||||
|
||||
var catname = "InfluxDB";
|
||||
category[catname] = new Object();
|
||||
@@ -203,7 +206,7 @@ function ParseConfig() {
|
||||
category[catname]["found"] = false;
|
||||
param[catname] = new Object();
|
||||
ParamAddValue(param, catname, "Uri");
|
||||
ParamAddValue(param, catname, "Database");
|
||||
ParamAddValue(param, catname, "Bucket");
|
||||
// ParamAddValue(param, catname, "Measurement");
|
||||
ParamAddValue(param, catname, "Org");
|
||||
ParamAddValue(param, catname, "Token");
|
||||
|
||||
746
sd-card/html/watermeter.svg
Normal file
746
sd-card/html/watermeter.svg
Normal file
@@ -0,0 +1,746 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
|
||||
<svg
|
||||
version="1.1"
|
||||
id="Layer_1"
|
||||
x="0px"
|
||||
y="0px"
|
||||
viewBox="0 0 310.39999 310.39999"
|
||||
xml:space="preserve"
|
||||
sodipodi:docname="watermeter.svg"
|
||||
width="310.39999"
|
||||
height="310.39999"
|
||||
inkscape:version="1.1.2 (0a00cf5339, 2022-02-04)"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"><metadata
|
||||
id="metadata151"><rdf:RDF><cc:Work
|
||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /></cc:Work></rdf:RDF></metadata><defs
|
||||
id="defs149"><inkscape:perspective
|
||||
sodipodi:type="inkscape:persp3d"
|
||||
inkscape:vp_x="0 : 155.2 : 1"
|
||||
inkscape:vp_y="0 : 1000 : 0"
|
||||
inkscape:vp_z="310.39999 : 155.2 : 1"
|
||||
inkscape:persp3d-origin="155.2 : 103.46666 : 1"
|
||||
id="perspective1295" /><linearGradient
|
||||
id="linearGradient888"
|
||||
inkscape:swatch="solid"><stop
|
||||
style="stop-color:#ff0000;stop-opacity:1;"
|
||||
offset="0"
|
||||
id="stop886" /></linearGradient></defs><sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1003"
|
||||
id="namedview147"
|
||||
showgrid="false"
|
||||
fit-margin-top="0"
|
||||
fit-margin-left="0"
|
||||
fit-margin-right="0"
|
||||
fit-margin-bottom="0"
|
||||
inkscape:zoom="0.31481804"
|
||||
inkscape:cx="-1332.5158"
|
||||
inkscape:cy="-481.23036"
|
||||
inkscape:window-x="0"
|
||||
inkscape:window-y="0"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="Layer_1"
|
||||
inkscape:pagecheckerboard="0"
|
||||
showguides="true"
|
||||
inkscape:guide-bbox="true"
|
||||
inkscape:snap-text-baseline="false" />
|
||||
|
||||
|
||||
<circle
|
||||
style="fill:#000000;fill-opacity:1"
|
||||
cx="155.2"
|
||||
cy="155.2"
|
||||
r="155.2"
|
||||
id="circle6"
|
||||
inkscape:export-filename="/home/gruinelli/temp/AI-on-the-edge-device/images/icon/favicon.ico"
|
||||
inkscape:export-xdpi="19.790001"
|
||||
inkscape:export-ydpi="19.790001" />
|
||||
<circle
|
||||
style="fill:#999999"
|
||||
cx="155.2"
|
||||
cy="155.2"
|
||||
id="circle8"
|
||||
inkscape:export-filename="/home/gruinelli/temp/AI-on-the-edge-device/images/icon/favicon.ico"
|
||||
inkscape:export-xdpi="19.790001"
|
||||
inkscape:export-ydpi="19.790001"
|
||||
r="141.60001" />
|
||||
<path
|
||||
style="fill:#ff0000;fill-opacity:1"
|
||||
d="m 240.8,122 h -14 c -3.2,0 -5.6,-2.4 -5.6,-5.6 V 87.999997 c 0,-3.2 2.4,-5.6 5.6,-5.6 h 14 c 3.2,0 5.6,2.4 5.6,5.6 V 116.4 c -0.4,3.2 -2.8,5.6 -5.6,5.6 z"
|
||||
id="path10"
|
||||
inkscape:connector-curvature="0"
|
||||
inkscape:export-filename="/home/gruinelli/temp/AI-on-the-edge-device/images/icon/favicon.ico"
|
||||
inkscape:export-xdpi="19.790001"
|
||||
inkscape:export-ydpi="19.790001" />
|
||||
|
||||
<path
|
||||
style="fill:#000000;fill-opacity:1"
|
||||
d="m 209.2,122 h -14 c -3.2,0 -5.6,-2.4 -5.6,-5.6 V 87.999997 c 0,-3.2 2.4,-5.6 5.6,-5.6 h 14 c 3.2,0 5.6,2.4 5.6,5.6 V 116.4 c 0,3.2 -2.4,5.6 -5.6,5.6 z"
|
||||
id="path14"
|
||||
inkscape:connector-curvature="0"
|
||||
inkscape:export-filename="/home/gruinelli/temp/AI-on-the-edge-device/images/icon/favicon.ico"
|
||||
inkscape:export-xdpi="19.790001"
|
||||
inkscape:export-ydpi="19.790001" />
|
||||
|
||||
<path
|
||||
style="fill:#000002;fill-opacity:1"
|
||||
d="m 178,122 h -14 c -3.2,0 -5.6,-2.4 -5.6,-5.6 V 87.999997 c 0,-3.2 2.4,-5.6 5.6,-5.6 h 14 c 3.2,0 5.6,2.4 5.6,5.6 V 116.4 c -0.4,3.2 -2.8,5.6 -5.6,5.6 z"
|
||||
id="path18"
|
||||
inkscape:connector-curvature="0"
|
||||
inkscape:export-filename="/home/gruinelli/temp/AI-on-the-edge-device/images/icon/favicon.ico"
|
||||
inkscape:export-xdpi="19.790001"
|
||||
inkscape:export-ydpi="19.790001" />
|
||||
|
||||
<path
|
||||
style="fill:#000000;fill-opacity:1"
|
||||
d="m 146.8,122 h -14 c -3.2,0 -5.6,-2.4 -5.6,-5.6 V 87.999997 c 0,-3.2 2.4,-5.6 5.6,-5.6 h 14 c 3.2,0 5.6,2.4 5.6,5.6 V 116.4 c -0.4,3.2 -2.8,5.6 -5.6,5.6 z"
|
||||
id="path22"
|
||||
inkscape:connector-curvature="0"
|
||||
inkscape:export-filename="/home/gruinelli/temp/AI-on-the-edge-device/images/icon/favicon.ico"
|
||||
inkscape:export-xdpi="19.790001"
|
||||
inkscape:export-ydpi="19.790001" />
|
||||
|
||||
<path
|
||||
style="fill:#000003;fill-opacity:1"
|
||||
d="m 115.2,122 h -14 c -3.2,0 -5.6,-2.4 -5.6,-5.6 V 87.999997 c 0,-3.2 2.4,-5.6 5.6,-5.6 h 14 c 3.2,0 5.6,2.4 5.6,5.6 V 116.4 c 0,3.2 -2.4,5.6 -5.6,5.6 z"
|
||||
id="path26"
|
||||
inkscape:connector-curvature="0"
|
||||
inkscape:export-filename="/home/gruinelli/temp/AI-on-the-edge-device/images/icon/favicon.ico"
|
||||
inkscape:export-xdpi="19.790001"
|
||||
inkscape:export-ydpi="19.790001" />
|
||||
|
||||
<path
|
||||
style="fill:#000000;fill-opacity:1"
|
||||
d="M 84,122 H 70 c -3.2,0 -5.6,-2.4 -5.6,-5.6 V 87.999997 c 0,-3.2 2.4,-5.6 5.6,-5.6 h 14 c 3.2,0 5.6,2.4 5.6,5.6 V 116.4 c -0.4,3.2 -2.8,5.6 -5.6,5.6 z"
|
||||
id="path30"
|
||||
inkscape:connector-curvature="0"
|
||||
inkscape:export-filename="/home/gruinelli/temp/AI-on-the-edge-device/images/icon/favicon.ico"
|
||||
inkscape:export-xdpi="19.790001"
|
||||
inkscape:export-ydpi="19.790001" />
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
<g
|
||||
id="g116"
|
||||
transform="translate(-98.8,-98.800003)"
|
||||
inkscape:export-filename="/home/gruinelli/temp/AI-on-the-edge-device/images/icon/favicon.ico"
|
||||
inkscape:export-xdpi="19.790001"
|
||||
inkscape:export-ydpi="19.790001">
|
||||
</g>
|
||||
<g
|
||||
id="g118"
|
||||
transform="translate(-98.8,-98.800003)"
|
||||
inkscape:export-filename="/home/gruinelli/temp/AI-on-the-edge-device/images/icon/favicon.ico"
|
||||
inkscape:export-xdpi="19.790001"
|
||||
inkscape:export-ydpi="19.790001">
|
||||
</g>
|
||||
<g
|
||||
id="g120"
|
||||
transform="translate(-98.8,-98.800003)"
|
||||
inkscape:export-filename="/home/gruinelli/temp/AI-on-the-edge-device/images/icon/favicon.ico"
|
||||
inkscape:export-xdpi="19.790001"
|
||||
inkscape:export-ydpi="19.790001">
|
||||
</g>
|
||||
<g
|
||||
id="g122"
|
||||
transform="translate(-98.8,-98.800003)"
|
||||
inkscape:export-filename="/home/gruinelli/temp/AI-on-the-edge-device/images/icon/favicon.ico"
|
||||
inkscape:export-xdpi="19.790001"
|
||||
inkscape:export-ydpi="19.790001">
|
||||
</g>
|
||||
<g
|
||||
id="g124"
|
||||
transform="translate(-98.8,-98.800003)"
|
||||
inkscape:export-filename="/home/gruinelli/temp/AI-on-the-edge-device/images/icon/favicon.ico"
|
||||
inkscape:export-xdpi="19.790001"
|
||||
inkscape:export-ydpi="19.790001">
|
||||
</g>
|
||||
<g
|
||||
id="g126"
|
||||
transform="translate(-98.8,-98.800003)"
|
||||
inkscape:export-filename="/home/gruinelli/temp/AI-on-the-edge-device/images/icon/favicon.ico"
|
||||
inkscape:export-xdpi="19.790001"
|
||||
inkscape:export-ydpi="19.790001">
|
||||
</g>
|
||||
<g
|
||||
id="g128"
|
||||
transform="translate(-98.8,-98.800003)"
|
||||
inkscape:export-filename="/home/gruinelli/temp/AI-on-the-edge-device/images/icon/favicon.ico"
|
||||
inkscape:export-xdpi="19.790001"
|
||||
inkscape:export-ydpi="19.790001">
|
||||
</g>
|
||||
<g
|
||||
id="g130"
|
||||
transform="translate(-98.8,-98.800003)"
|
||||
inkscape:export-filename="/home/gruinelli/temp/AI-on-the-edge-device/images/icon/favicon.ico"
|
||||
inkscape:export-xdpi="19.790001"
|
||||
inkscape:export-ydpi="19.790001">
|
||||
</g>
|
||||
<g
|
||||
id="g132"
|
||||
transform="translate(-98.8,-98.800003)"
|
||||
inkscape:export-filename="/home/gruinelli/temp/AI-on-the-edge-device/images/icon/favicon.ico"
|
||||
inkscape:export-xdpi="19.790001"
|
||||
inkscape:export-ydpi="19.790001">
|
||||
</g>
|
||||
<g
|
||||
id="g134"
|
||||
transform="translate(-98.8,-98.800003)"
|
||||
inkscape:export-filename="/home/gruinelli/temp/AI-on-the-edge-device/images/icon/favicon.ico"
|
||||
inkscape:export-xdpi="19.790001"
|
||||
inkscape:export-ydpi="19.790001">
|
||||
</g>
|
||||
<g
|
||||
id="g136"
|
||||
transform="translate(-98.8,-98.800003)"
|
||||
inkscape:export-filename="/home/gruinelli/temp/AI-on-the-edge-device/images/icon/favicon.ico"
|
||||
inkscape:export-xdpi="19.790001"
|
||||
inkscape:export-ydpi="19.790001">
|
||||
</g>
|
||||
<g
|
||||
id="g138"
|
||||
transform="translate(-98.8,-98.800003)"
|
||||
inkscape:export-filename="/home/gruinelli/temp/AI-on-the-edge-device/images/icon/favicon.ico"
|
||||
inkscape:export-xdpi="19.790001"
|
||||
inkscape:export-ydpi="19.790001">
|
||||
</g>
|
||||
<g
|
||||
id="g140"
|
||||
transform="translate(-98.8,-98.800003)"
|
||||
inkscape:export-filename="/home/gruinelli/temp/AI-on-the-edge-device/images/icon/favicon.ico"
|
||||
inkscape:export-xdpi="19.790001"
|
||||
inkscape:export-ydpi="19.790001">
|
||||
</g>
|
||||
<g
|
||||
id="g142"
|
||||
transform="translate(-98.8,-98.800003)"
|
||||
inkscape:export-filename="/home/gruinelli/temp/AI-on-the-edge-device/images/icon/favicon.ico"
|
||||
inkscape:export-xdpi="19.790001"
|
||||
inkscape:export-ydpi="19.790001">
|
||||
</g>
|
||||
<g
|
||||
id="g144"
|
||||
transform="translate(-98.8,-98.800003)"
|
||||
inkscape:export-filename="/home/gruinelli/temp/AI-on-the-edge-device/images/icon/favicon.ico"
|
||||
inkscape:export-xdpi="19.790001"
|
||||
inkscape:export-ydpi="19.790001">
|
||||
</g>
|
||||
<rect
|
||||
style="fill:none;fill-opacity:1;stroke:#0c0000;stroke-width:5;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:stroke markers fill"
|
||||
id="rect958"
|
||||
width="222.78813"
|
||||
height="51.122875"
|
||||
x="44.665253"
|
||||
y="76.849152"
|
||||
rx="10"
|
||||
ry="10"
|
||||
inkscape:export-filename="/home/gruinelli/temp/AI-on-the-edge-device/images/icon/favicon.ico"
|
||||
inkscape:export-xdpi="19.790001"
|
||||
inkscape:export-ydpi="19.790001" />
|
||||
|
||||
|
||||
<g
|
||||
id="g2493"
|
||||
transform="matrix(-0.44400058,-1.0430452,1.0430452,-0.44400058,-85.63466,328.03956)"
|
||||
style="stroke-width:0.882135"
|
||||
inkscape:export-filename="/home/gruinelli/temp/AI-on-the-edge-device/images/icon/favicon.ico"
|
||||
inkscape:export-xdpi="19.790001"
|
||||
inkscape:export-ydpi="19.790001"><path
|
||||
style="fill:#e6e9ee;stroke-width:0.882135"
|
||||
d="m 72.8,202.4 v 0 c -16,0 -29.2,-13.2 -29.2,-29.2 v 0 c 0,-16 13.2,-29.2 29.2,-29.2 v 0 c 16,0 29.2,13.2 29.2,29.2 v 0 c 0,16.4 -13.2,29.2 -29.2,29.2 z"
|
||||
id="path44"
|
||||
inkscape:connector-curvature="0" /><path
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:0.882135"
|
||||
d="m 72.8,198.4 c -0.8,0 -1.2,-0.4 -1.2,-1.2 v -6 c 0,-0.8 0.4,-1.2 1.2,-1.2 0.8,0 1.2,0.4 1.2,1.2 v 6 c 0,0.8 -0.4,1.2 -1.2,1.2 z"
|
||||
id="path46"
|
||||
inkscape:connector-curvature="0" /><path
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:0.882135"
|
||||
d="m 72.8,156.8 c -0.8,0 -1.2,-0.4 -1.2,-1.2 v -6 c 0,-0.8 0.4,-1.2 1.2,-1.2 0.8,0 1.2,0.4 1.2,1.2 v 5.6 c 0,0.8 -0.4,1.6 -1.2,1.6 z"
|
||||
id="path48"
|
||||
inkscape:connector-curvature="0" /><path
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:0.882135"
|
||||
d="m 54.8,174.8 h -6 c -0.8,0 -1.2,-0.4 -1.2,-1.2 0,-0.8 0.4,-1.2 1.2,-1.2 h 6 c 0.8,0 1.2,0.4 1.2,1.2 0,0.4 -0.4,1.2 -1.2,1.2 z"
|
||||
id="path50"
|
||||
inkscape:connector-curvature="0" /><path
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:0.882135"
|
||||
d="m 96.8,174.8 h -6 c -0.8,0 -1.2,-0.4 -1.2,-1.2 0,-0.8 0.4,-1.2 1.2,-1.2 h 6 c 0.8,0 1.2,0.4 1.2,1.2 0,0.4 -0.8,1.2 -1.2,1.2 z"
|
||||
id="path52"
|
||||
inkscape:connector-curvature="0" /><path
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:0.882135"
|
||||
d="m 56,191.6 c -0.4,0 -0.8,0 -0.8,-0.4 -0.4,-0.4 -0.4,-1.2 0,-1.6 l 4,-4 c 0.4,-0.4 1.2,-0.4 1.6,0 0.4,0.4 0.4,1.2 0,1.6 l -4,4 c -0.4,0 -0.4,0.4 -0.8,0.4 z"
|
||||
id="path54"
|
||||
inkscape:connector-curvature="0" /><path
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:0.882135"
|
||||
d="m 85.6,162 c -0.4,0 -0.8,0 -0.8,-0.4 -0.4,-0.4 -0.4,-1.2 0,-1.6 l 4,-4 c 0.4,-0.4 1.2,-0.4 1.6,0 0.4,0.4 0.4,1.2 0,1.6 l -4,4 c -0.4,0 -0.4,0.4 -0.8,0.4 z"
|
||||
id="path56"
|
||||
inkscape:connector-curvature="0" /><path
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:0.882135"
|
||||
d="m 60,162 c -0.4,0 -0.8,0 -0.8,-0.4 l -4,-4 c -0.4,-0.4 -0.4,-1.2 0,-1.6 0.4,-0.4 1.2,-0.4 1.6,0 l 4,4 c 0.4,0.4 0.4,1.2 0,1.6 0,0 -0.4,0.4 -0.8,0.4 z"
|
||||
id="path58"
|
||||
inkscape:connector-curvature="0" /><path
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:0.882135"
|
||||
d="m 89.6,191.6 c -0.4,0 -0.8,0 -0.8,-0.4 l -4,-4 c -0.4,-0.4 -0.4,-1.2 0,-1.6 0.4,-0.4 1.2,-0.4 1.6,0 l 4,4 c 0.4,0.4 0.4,1.2 0,1.6 0,0 -0.4,0.4 -0.8,0.4 z"
|
||||
id="path60"
|
||||
inkscape:connector-curvature="0" /><path
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:0.882135"
|
||||
d="m 82,196.8 c -0.4,0 -0.8,-0.4 -1.2,-0.8 l -2.4,-5.6 c -0.4,-0.8 0,-1.2 0.8,-1.6 0.8,-0.4 1.2,0 1.6,0.8 l 2.4,5.6 c 0.4,0.8 0,1.2 -0.8,1.6 0,0 -0.4,0 -0.4,0 z"
|
||||
id="path62"
|
||||
inkscape:connector-curvature="0" /><path
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:0.882135"
|
||||
d="m 66,158 c -0.4,0 -0.8,-0.4 -1.2,-0.8 l -2.4,-5.6 c -0.4,-0.8 0,-1.2 0.8,-1.6 0.8,-0.4 1.2,0 1.6,0.8 l 2.4,5.6 c 0.4,0.8 0,1.2 -0.8,1.6 0,0 -0.4,0 -0.4,0 z"
|
||||
id="path64"
|
||||
inkscape:connector-curvature="0" /><path
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:0.882135"
|
||||
d="m 50.8,183.6 c -0.4,0 -0.8,-0.4 -1.2,-0.8 -0.4,-0.8 0,-1.2 0.8,-1.6 l 5.6,-2.4 c 0.8,-0.4 1.2,0 1.6,0.8 0.4,0.8 0,1.2 -0.8,1.6 l -5.6,2.4 z"
|
||||
id="path66"
|
||||
inkscape:connector-curvature="0" /><path
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:0.882135"
|
||||
d="m 89.6,167.6 c -0.4,0 -0.8,-0.4 -1.2,-0.8 -0.4,-0.8 0,-1.2 0.8,-1.6 l 5.6,-2.4 c 0.8,-0.4 1.2,0 1.6,0.8 0.4,0.8 0,1.2 -0.8,1.6 l -5.6,2.4 c -0.4,0 -0.4,0 -0.4,0 z"
|
||||
id="path68"
|
||||
inkscape:connector-curvature="0" /><path
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:0.882135"
|
||||
d="m 63.6,196.8 h -0.4 c -0.8,-0.4 -0.8,-1.2 -0.8,-1.6 l 2.4,-5.6 c 0.4,-0.8 1.2,-0.8 1.6,-0.8 0.8,0.4 0.8,1.2 0.8,1.6 l -2.4,5.6 c 0,0.4 -0.8,0.8 -1.2,0.8 z"
|
||||
id="path70"
|
||||
inkscape:connector-curvature="0" /><path
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:0.882135"
|
||||
d="m 79.6,158 h -0.4 c -0.8,-0.4 -0.8,-1.2 -0.8,-1.6 l 2.4,-5.6 c 0.4,-0.8 1.2,-0.8 1.6,-0.8 0.8,0.4 0.8,1.2 0.8,1.6 l -2.4,5.6 c 0,0.4 -0.8,0.8 -1.2,0.8 z"
|
||||
id="path72"
|
||||
inkscape:connector-curvature="0" /><path
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:0.882135"
|
||||
d="M 56,167.6 H 55.6 L 50,165.2 c -0.8,-0.4 -0.8,-1.2 -0.8,-1.6 0.4,-0.8 1.2,-0.8 1.6,-0.8 l 5.6,2.4 c 0.8,0.4 0.8,1.2 0.8,1.6 0,0.8 -0.4,0.8 -1.2,0.8 z"
|
||||
id="path74"
|
||||
inkscape:connector-curvature="0" /><path
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:0.882135"
|
||||
d="m 94.8,183.6 h -0.4 l -5.6,-2.4 C 88,180.8 88,180 88,179.6 c 0.4,-0.8 1.2,-0.8 1.6,-0.8 l 5.6,2.4 c 0.8,0.4 0.8,1.2 0.8,1.6 0,0.8 -0.8,0.8 -1.2,0.8 z"
|
||||
id="path76"
|
||||
inkscape:connector-curvature="0" /><path
|
||||
style="fill:#ff0000;fill-opacity:1;stroke-width:0.882135"
|
||||
d="m 72.8,180.4 v 0 c -4,0 -6.8,-3.2 -6.8,-6.8 v 0 c 0,-4 3.2,-6.8 6.8,-6.8 v 0 c 4,0 6.8,3.2 6.8,6.8 v 0 c 0,3.6 -2.8,6.8 -6.8,6.8 z"
|
||||
id="path78"
|
||||
inkscape:connector-curvature="0" /><path
|
||||
id="rect1441"
|
||||
style="opacity:1;fill:#ff0000;stroke-width:2.21715"
|
||||
d="m 72.801641,150.78759 v 0 l 5.635295,19.11133 h -11.27059 z"
|
||||
sodipodi:nodetypes="ccccc" /></g><g
|
||||
id="g2493-1"
|
||||
transform="matrix(-1.0365525,-0.458954,0.458954,-1.0365525,191.69502,452.08902)"
|
||||
inkscape:transform-center-x="-0.13984455"
|
||||
inkscape:transform-center-y="1.3468756"
|
||||
style="stroke-width:0.882135"
|
||||
inkscape:export-filename="/home/gruinelli/temp/AI-on-the-edge-device/images/icon/favicon.ico"
|
||||
inkscape:export-xdpi="19.790001"
|
||||
inkscape:export-ydpi="19.790001"><path
|
||||
style="fill:#e6e9ee;stroke-width:0.882135"
|
||||
d="m 72.8,202.4 v 0 c -16,0 -29.2,-13.2 -29.2,-29.2 v 0 c 0,-16 13.2,-29.2 29.2,-29.2 v 0 c 16,0 29.2,13.2 29.2,29.2 v 0 c 0,16.4 -13.2,29.2 -29.2,29.2 z"
|
||||
id="path44-8"
|
||||
inkscape:connector-curvature="0" /><path
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:0.882135"
|
||||
d="m 72.8,198.4 c -0.8,0 -1.2,-0.4 -1.2,-1.2 v -6 c 0,-0.8 0.4,-1.2 1.2,-1.2 0.8,0 1.2,0.4 1.2,1.2 v 6 c 0,0.8 -0.4,1.2 -1.2,1.2 z"
|
||||
id="path46-79"
|
||||
inkscape:connector-curvature="0" /><path
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:0.882135"
|
||||
d="m 72.8,156.8 c -0.8,0 -1.2,-0.4 -1.2,-1.2 v -6 c 0,-0.8 0.4,-1.2 1.2,-1.2 0.8,0 1.2,0.4 1.2,1.2 v 5.6 c 0,0.8 -0.4,1.6 -1.2,1.6 z"
|
||||
id="path48-2"
|
||||
inkscape:connector-curvature="0" /><path
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:0.882135"
|
||||
d="m 54.8,174.8 h -6 c -0.8,0 -1.2,-0.4 -1.2,-1.2 0,-0.8 0.4,-1.2 1.2,-1.2 h 6 c 0.8,0 1.2,0.4 1.2,1.2 0,0.4 -0.4,1.2 -1.2,1.2 z"
|
||||
id="path50-0"
|
||||
inkscape:connector-curvature="0" /><path
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:0.882135"
|
||||
d="m 96.8,174.8 h -6 c -0.8,0 -1.2,-0.4 -1.2,-1.2 0,-0.8 0.4,-1.2 1.2,-1.2 h 6 c 0.8,0 1.2,0.4 1.2,1.2 0,0.4 -0.8,1.2 -1.2,1.2 z"
|
||||
id="path52-2"
|
||||
inkscape:connector-curvature="0" /><path
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:0.882135"
|
||||
d="m 56,191.6 c -0.4,0 -0.8,0 -0.8,-0.4 -0.4,-0.4 -0.4,-1.2 0,-1.6 l 4,-4 c 0.4,-0.4 1.2,-0.4 1.6,0 0.4,0.4 0.4,1.2 0,1.6 l -4,4 c -0.4,0 -0.4,0.4 -0.8,0.4 z"
|
||||
id="path54-3"
|
||||
inkscape:connector-curvature="0" /><path
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:0.882135"
|
||||
d="m 85.6,162 c -0.4,0 -0.8,0 -0.8,-0.4 -0.4,-0.4 -0.4,-1.2 0,-1.6 l 4,-4 c 0.4,-0.4 1.2,-0.4 1.6,0 0.4,0.4 0.4,1.2 0,1.6 l -4,4 c -0.4,0 -0.4,0.4 -0.8,0.4 z"
|
||||
id="path56-7"
|
||||
inkscape:connector-curvature="0" /><path
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:0.882135"
|
||||
d="m 60,162 c -0.4,0 -0.8,0 -0.8,-0.4 l -4,-4 c -0.4,-0.4 -0.4,-1.2 0,-1.6 0.4,-0.4 1.2,-0.4 1.6,0 l 4,4 c 0.4,0.4 0.4,1.2 0,1.6 0,0 -0.4,0.4 -0.8,0.4 z"
|
||||
id="path58-5"
|
||||
inkscape:connector-curvature="0" /><path
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:0.882135"
|
||||
d="m 89.6,191.6 c -0.4,0 -0.8,0 -0.8,-0.4 l -4,-4 c -0.4,-0.4 -0.4,-1.2 0,-1.6 0.4,-0.4 1.2,-0.4 1.6,0 l 4,4 c 0.4,0.4 0.4,1.2 0,1.6 0,0 -0.4,0.4 -0.8,0.4 z"
|
||||
id="path60-9"
|
||||
inkscape:connector-curvature="0" /><path
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:0.882135"
|
||||
d="m 82,196.8 c -0.4,0 -0.8,-0.4 -1.2,-0.8 l -2.4,-5.6 c -0.4,-0.8 0,-1.2 0.8,-1.6 0.8,-0.4 1.2,0 1.6,0.8 l 2.4,5.6 c 0.4,0.8 0,1.2 -0.8,1.6 0,0 -0.4,0 -0.4,0 z"
|
||||
id="path62-22"
|
||||
inkscape:connector-curvature="0" /><path
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:0.882135"
|
||||
d="m 66,158 c -0.4,0 -0.8,-0.4 -1.2,-0.8 l -2.4,-5.6 c -0.4,-0.8 0,-1.2 0.8,-1.6 0.8,-0.4 1.2,0 1.6,0.8 l 2.4,5.6 c 0.4,0.8 0,1.2 -0.8,1.6 0,0 -0.4,0 -0.4,0 z"
|
||||
id="path64-8"
|
||||
inkscape:connector-curvature="0" /><path
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:0.882135"
|
||||
d="m 50.8,183.6 c -0.4,0 -0.8,-0.4 -1.2,-0.8 -0.4,-0.8 0,-1.2 0.8,-1.6 l 5.6,-2.4 c 0.8,-0.4 1.2,0 1.6,0.8 0.4,0.8 0,1.2 -0.8,1.6 l -5.6,2.4 z"
|
||||
id="path66-9"
|
||||
inkscape:connector-curvature="0" /><path
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:0.882135"
|
||||
d="m 89.6,167.6 c -0.4,0 -0.8,-0.4 -1.2,-0.8 -0.4,-0.8 0,-1.2 0.8,-1.6 l 5.6,-2.4 c 0.8,-0.4 1.2,0 1.6,0.8 0.4,0.8 0,1.2 -0.8,1.6 l -5.6,2.4 c -0.4,0 -0.4,0 -0.4,0 z"
|
||||
id="path68-7"
|
||||
inkscape:connector-curvature="0" /><path
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:0.882135"
|
||||
d="m 63.6,196.8 h -0.4 c -0.8,-0.4 -0.8,-1.2 -0.8,-1.6 l 2.4,-5.6 c 0.4,-0.8 1.2,-0.8 1.6,-0.8 0.8,0.4 0.8,1.2 0.8,1.6 l -2.4,5.6 c 0,0.4 -0.8,0.8 -1.2,0.8 z"
|
||||
id="path70-36"
|
||||
inkscape:connector-curvature="0" /><path
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:0.882135"
|
||||
d="m 79.6,158 h -0.4 c -0.8,-0.4 -0.8,-1.2 -0.8,-1.6 l 2.4,-5.6 c 0.4,-0.8 1.2,-0.8 1.6,-0.8 0.8,0.4 0.8,1.2 0.8,1.6 l -2.4,5.6 c 0,0.4 -0.8,0.8 -1.2,0.8 z"
|
||||
id="path72-1"
|
||||
inkscape:connector-curvature="0" /><path
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:0.882135"
|
||||
d="M 56,167.6 H 55.6 L 50,165.2 c -0.8,-0.4 -0.8,-1.2 -0.8,-1.6 0.4,-0.8 1.2,-0.8 1.6,-0.8 l 5.6,2.4 c 0.8,0.4 0.8,1.2 0.8,1.6 0,0.8 -0.4,0.8 -1.2,0.8 z"
|
||||
id="path74-2"
|
||||
inkscape:connector-curvature="0" /><path
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:0.882135"
|
||||
d="m 94.8,183.6 h -0.4 l -5.6,-2.4 C 88,180.8 88,180 88,179.6 c 0.4,-0.8 1.2,-0.8 1.6,-0.8 l 5.6,2.4 c 0.8,0.4 0.8,1.2 0.8,1.6 0,0.8 -0.8,0.8 -1.2,0.8 z"
|
||||
id="path76-9"
|
||||
inkscape:connector-curvature="0" /><path
|
||||
style="fill:#ff0000;fill-opacity:1;stroke-width:0.882135"
|
||||
d="m 72.8,180.4 v 0 c -4,0 -6.8,-3.2 -6.8,-6.8 v 0 c 0,-4 3.2,-6.8 6.8,-6.8 v 0 c 4,0 6.8,3.2 6.8,6.8 v 0 c 0,3.6 -2.8,6.8 -6.8,6.8 z"
|
||||
id="path78-3"
|
||||
inkscape:connector-curvature="0" /><path
|
||||
id="rect1441-1"
|
||||
style="opacity:1;fill:#ff0000;stroke-width:2.21715"
|
||||
d="m 72.801641,150.78759 v 0 l 5.635295,19.11133 h -11.27059 z"
|
||||
sodipodi:nodetypes="ccccc" /></g><g
|
||||
id="g2493-9"
|
||||
transform="matrix(1.1065407,0.24626723,-0.24626723,1.1065407,81.269684,28.240985)"
|
||||
style="stroke-width:0.882135"
|
||||
inkscape:export-filename="/home/gruinelli/temp/AI-on-the-edge-device/images/icon/favicon.ico"
|
||||
inkscape:export-xdpi="19.790001"
|
||||
inkscape:export-ydpi="19.790001"><path
|
||||
style="fill:#e6e9ee;stroke-width:0.882135"
|
||||
d="m 72.8,202.4 v 0 c -16,0 -29.2,-13.2 -29.2,-29.2 v 0 c 0,-16 13.2,-29.2 29.2,-29.2 v 0 c 16,0 29.2,13.2 29.2,29.2 v 0 c 0,16.4 -13.2,29.2 -29.2,29.2 z"
|
||||
id="path44-4"
|
||||
inkscape:connector-curvature="0" /><path
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:0.882135"
|
||||
d="m 72.8,198.4 c -0.8,0 -1.2,-0.4 -1.2,-1.2 v -6 c 0,-0.8 0.4,-1.2 1.2,-1.2 0.8,0 1.2,0.4 1.2,1.2 v 6 c 0,0.8 -0.4,1.2 -1.2,1.2 z"
|
||||
id="path46-78"
|
||||
inkscape:connector-curvature="0" /><path
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:0.882135"
|
||||
d="m 72.8,156.8 c -0.8,0 -1.2,-0.4 -1.2,-1.2 v -6 c 0,-0.8 0.4,-1.2 1.2,-1.2 0.8,0 1.2,0.4 1.2,1.2 v 5.6 c 0,0.8 -0.4,1.6 -1.2,1.6 z"
|
||||
id="path48-4"
|
||||
inkscape:connector-curvature="0" /><path
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:0.882135"
|
||||
d="m 54.8,174.8 h -6 c -0.8,0 -1.2,-0.4 -1.2,-1.2 0,-0.8 0.4,-1.2 1.2,-1.2 h 6 c 0.8,0 1.2,0.4 1.2,1.2 0,0.4 -0.4,1.2 -1.2,1.2 z"
|
||||
id="path50-5"
|
||||
inkscape:connector-curvature="0" /><path
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:0.882135"
|
||||
d="m 96.8,174.8 h -6 c -0.8,0 -1.2,-0.4 -1.2,-1.2 0,-0.8 0.4,-1.2 1.2,-1.2 h 6 c 0.8,0 1.2,0.4 1.2,1.2 0,0.4 -0.8,1.2 -1.2,1.2 z"
|
||||
id="path52-0"
|
||||
inkscape:connector-curvature="0" /><path
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:0.882135"
|
||||
d="m 56,191.6 c -0.4,0 -0.8,0 -0.8,-0.4 -0.4,-0.4 -0.4,-1.2 0,-1.6 l 4,-4 c 0.4,-0.4 1.2,-0.4 1.6,0 0.4,0.4 0.4,1.2 0,1.6 l -4,4 c -0.4,0 -0.4,0.4 -0.8,0.4 z"
|
||||
id="path54-36"
|
||||
inkscape:connector-curvature="0" /><path
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:0.882135"
|
||||
d="m 85.6,162 c -0.4,0 -0.8,0 -0.8,-0.4 -0.4,-0.4 -0.4,-1.2 0,-1.6 l 4,-4 c 0.4,-0.4 1.2,-0.4 1.6,0 0.4,0.4 0.4,1.2 0,1.6 l -4,4 c -0.4,0 -0.4,0.4 -0.8,0.4 z"
|
||||
id="path56-1"
|
||||
inkscape:connector-curvature="0" /><path
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:0.882135"
|
||||
d="m 60,162 c -0.4,0 -0.8,0 -0.8,-0.4 l -4,-4 c -0.4,-0.4 -0.4,-1.2 0,-1.6 0.4,-0.4 1.2,-0.4 1.6,0 l 4,4 c 0.4,0.4 0.4,1.2 0,1.6 0,0 -0.4,0.4 -0.8,0.4 z"
|
||||
id="path58-0"
|
||||
inkscape:connector-curvature="0" /><path
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:0.882135"
|
||||
d="m 89.6,191.6 c -0.4,0 -0.8,0 -0.8,-0.4 l -4,-4 c -0.4,-0.4 -0.4,-1.2 0,-1.6 0.4,-0.4 1.2,-0.4 1.6,0 l 4,4 c 0.4,0.4 0.4,1.2 0,1.6 0,0 -0.4,0.4 -0.8,0.4 z"
|
||||
id="path60-6"
|
||||
inkscape:connector-curvature="0" /><path
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:0.882135"
|
||||
d="m 82,196.8 c -0.4,0 -0.8,-0.4 -1.2,-0.8 l -2.4,-5.6 c -0.4,-0.8 0,-1.2 0.8,-1.6 0.8,-0.4 1.2,0 1.6,0.8 l 2.4,5.6 c 0.4,0.8 0,1.2 -0.8,1.6 0,0 -0.4,0 -0.4,0 z"
|
||||
id="path62-3"
|
||||
inkscape:connector-curvature="0" /><path
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:0.882135"
|
||||
d="m 66,158 c -0.4,0 -0.8,-0.4 -1.2,-0.8 l -2.4,-5.6 c -0.4,-0.8 0,-1.2 0.8,-1.6 0.8,-0.4 1.2,0 1.6,0.8 l 2.4,5.6 c 0.4,0.8 0,1.2 -0.8,1.6 0,0 -0.4,0 -0.4,0 z"
|
||||
id="path64-2"
|
||||
inkscape:connector-curvature="0" /><path
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:0.882135"
|
||||
d="m 50.8,183.6 c -0.4,0 -0.8,-0.4 -1.2,-0.8 -0.4,-0.8 0,-1.2 0.8,-1.6 l 5.6,-2.4 c 0.8,-0.4 1.2,0 1.6,0.8 0.4,0.8 0,1.2 -0.8,1.6 l -5.6,2.4 z"
|
||||
id="path66-06"
|
||||
inkscape:connector-curvature="0" /><path
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:0.882135"
|
||||
d="m 89.6,167.6 c -0.4,0 -0.8,-0.4 -1.2,-0.8 -0.4,-0.8 0,-1.2 0.8,-1.6 l 5.6,-2.4 c 0.8,-0.4 1.2,0 1.6,0.8 0.4,0.8 0,1.2 -0.8,1.6 l -5.6,2.4 c -0.4,0 -0.4,0 -0.4,0 z"
|
||||
id="path68-1"
|
||||
inkscape:connector-curvature="0" /><path
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:0.882135"
|
||||
d="m 63.6,196.8 h -0.4 c -0.8,-0.4 -0.8,-1.2 -0.8,-1.6 l 2.4,-5.6 c 0.4,-0.8 1.2,-0.8 1.6,-0.8 0.8,0.4 0.8,1.2 0.8,1.6 l -2.4,5.6 c 0,0.4 -0.8,0.8 -1.2,0.8 z"
|
||||
id="path70-5"
|
||||
inkscape:connector-curvature="0" /><path
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:0.882135"
|
||||
d="m 79.6,158 h -0.4 c -0.8,-0.4 -0.8,-1.2 -0.8,-1.6 l 2.4,-5.6 c 0.4,-0.8 1.2,-0.8 1.6,-0.8 0.8,0.4 0.8,1.2 0.8,1.6 l -2.4,5.6 c 0,0.4 -0.8,0.8 -1.2,0.8 z"
|
||||
id="path72-5"
|
||||
inkscape:connector-curvature="0" /><path
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:0.882135"
|
||||
d="M 56,167.6 H 55.6 L 50,165.2 c -0.8,-0.4 -0.8,-1.2 -0.8,-1.6 0.4,-0.8 1.2,-0.8 1.6,-0.8 l 5.6,2.4 c 0.8,0.4 0.8,1.2 0.8,1.6 0,0.8 -0.4,0.8 -1.2,0.8 z"
|
||||
id="path74-4"
|
||||
inkscape:connector-curvature="0" /><path
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:0.882135"
|
||||
d="m 94.8,183.6 h -0.4 l -5.6,-2.4 C 88,180.8 88,180 88,179.6 c 0.4,-0.8 1.2,-0.8 1.6,-0.8 l 5.6,2.4 c 0.8,0.4 0.8,1.2 0.8,1.6 0,0.8 -0.8,0.8 -1.2,0.8 z"
|
||||
id="path76-7"
|
||||
inkscape:connector-curvature="0" /><path
|
||||
style="fill:#ff0000;fill-opacity:1;stroke-width:0.882135"
|
||||
d="m 72.8,180.4 v 0 c -4,0 -6.8,-3.2 -6.8,-6.8 v 0 c 0,-4 3.2,-6.8 6.8,-6.8 v 0 c 4,0 6.8,3.2 6.8,6.8 v 0 c 0,3.6 -2.8,6.8 -6.8,6.8 z"
|
||||
id="path78-6"
|
||||
inkscape:connector-curvature="0" /><path
|
||||
id="rect1441-5"
|
||||
style="opacity:1;fill:#ff0000;stroke-width:2.21715"
|
||||
d="m 72.801641,150.78759 v 0 l 5.635295,19.11133 h -11.27059 z"
|
||||
sodipodi:nodetypes="ccccc" /></g><g
|
||||
id="g2493-3"
|
||||
transform="matrix(0.81724208,0.78561769,-0.78561769,0.81724208,322.48101,-24.488096)"
|
||||
style="stroke-width:0.882135"
|
||||
inkscape:export-filename="/home/gruinelli/temp/AI-on-the-edge-device/images/icon/favicon.ico"
|
||||
inkscape:export-xdpi="19.790001"
|
||||
inkscape:export-ydpi="19.790001"><path
|
||||
style="fill:#e6e9ee;stroke-width:0.882135"
|
||||
d="m 72.8,202.4 v 0 c -16,0 -29.2,-13.2 -29.2,-29.2 v 0 c 0,-16 13.2,-29.2 29.2,-29.2 v 0 c 16,0 29.2,13.2 29.2,29.2 v 0 c 0,16.4 -13.2,29.2 -29.2,29.2 z"
|
||||
id="path44-6"
|
||||
inkscape:connector-curvature="0" /><path
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:0.882135"
|
||||
d="m 72.8,198.4 c -0.8,0 -1.2,-0.4 -1.2,-1.2 v -6 c 0,-0.8 0.4,-1.2 1.2,-1.2 0.8,0 1.2,0.4 1.2,1.2 v 6 c 0,0.8 -0.4,1.2 -1.2,1.2 z"
|
||||
id="path46-7"
|
||||
inkscape:connector-curvature="0" /><path
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:0.882135"
|
||||
d="m 72.8,156.8 c -0.8,0 -1.2,-0.4 -1.2,-1.2 v -6 c 0,-0.8 0.4,-1.2 1.2,-1.2 0.8,0 1.2,0.4 1.2,1.2 v 5.6 c 0,0.8 -0.4,1.6 -1.2,1.6 z"
|
||||
id="path48-5"
|
||||
inkscape:connector-curvature="0" /><path
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:0.882135"
|
||||
d="m 54.8,174.8 h -6 c -0.8,0 -1.2,-0.4 -1.2,-1.2 0,-0.8 0.4,-1.2 1.2,-1.2 h 6 c 0.8,0 1.2,0.4 1.2,1.2 0,0.4 -0.4,1.2 -1.2,1.2 z"
|
||||
id="path50-3"
|
||||
inkscape:connector-curvature="0" /><path
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:0.882135"
|
||||
d="m 96.8,174.8 h -6 c -0.8,0 -1.2,-0.4 -1.2,-1.2 0,-0.8 0.4,-1.2 1.2,-1.2 h 6 c 0.8,0 1.2,0.4 1.2,1.2 0,0.4 -0.8,1.2 -1.2,1.2 z"
|
||||
id="path52-5"
|
||||
inkscape:connector-curvature="0" /><path
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:0.882135"
|
||||
d="m 56,191.6 c -0.4,0 -0.8,0 -0.8,-0.4 -0.4,-0.4 -0.4,-1.2 0,-1.6 l 4,-4 c 0.4,-0.4 1.2,-0.4 1.6,0 0.4,0.4 0.4,1.2 0,1.6 l -4,4 c -0.4,0 -0.4,0.4 -0.8,0.4 z"
|
||||
id="path54-6"
|
||||
inkscape:connector-curvature="0" /><path
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:0.882135"
|
||||
d="m 85.6,162 c -0.4,0 -0.8,0 -0.8,-0.4 -0.4,-0.4 -0.4,-1.2 0,-1.6 l 4,-4 c 0.4,-0.4 1.2,-0.4 1.6,0 0.4,0.4 0.4,1.2 0,1.6 l -4,4 c -0.4,0 -0.4,0.4 -0.8,0.4 z"
|
||||
id="path56-2"
|
||||
inkscape:connector-curvature="0" /><path
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:0.882135"
|
||||
d="m 60,162 c -0.4,0 -0.8,0 -0.8,-0.4 l -4,-4 c -0.4,-0.4 -0.4,-1.2 0,-1.6 0.4,-0.4 1.2,-0.4 1.6,0 l 4,4 c 0.4,0.4 0.4,1.2 0,1.6 0,0 -0.4,0.4 -0.8,0.4 z"
|
||||
id="path58-9"
|
||||
inkscape:connector-curvature="0" /><path
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:0.882135"
|
||||
d="m 89.6,191.6 c -0.4,0 -0.8,0 -0.8,-0.4 l -4,-4 c -0.4,-0.4 -0.4,-1.2 0,-1.6 0.4,-0.4 1.2,-0.4 1.6,0 l 4,4 c 0.4,0.4 0.4,1.2 0,1.6 0,0 -0.4,0.4 -0.8,0.4 z"
|
||||
id="path60-1"
|
||||
inkscape:connector-curvature="0" /><path
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:0.882135"
|
||||
d="m 82,196.8 c -0.4,0 -0.8,-0.4 -1.2,-0.8 l -2.4,-5.6 c -0.4,-0.8 0,-1.2 0.8,-1.6 0.8,-0.4 1.2,0 1.6,0.8 l 2.4,5.6 c 0.4,0.8 0,1.2 -0.8,1.6 0,0 -0.4,0 -0.4,0 z"
|
||||
id="path62-2"
|
||||
inkscape:connector-curvature="0" /><path
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:0.882135"
|
||||
d="m 66,158 c -0.4,0 -0.8,-0.4 -1.2,-0.8 l -2.4,-5.6 c -0.4,-0.8 0,-1.2 0.8,-1.6 0.8,-0.4 1.2,0 1.6,0.8 l 2.4,5.6 c 0.4,0.8 0,1.2 -0.8,1.6 0,0 -0.4,0 -0.4,0 z"
|
||||
id="path64-7"
|
||||
inkscape:connector-curvature="0" /><path
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:0.882135"
|
||||
d="m 50.8,183.6 c -0.4,0 -0.8,-0.4 -1.2,-0.8 -0.4,-0.8 0,-1.2 0.8,-1.6 l 5.6,-2.4 c 0.8,-0.4 1.2,0 1.6,0.8 0.4,0.8 0,1.2 -0.8,1.6 l -5.6,2.4 z"
|
||||
id="path66-0"
|
||||
inkscape:connector-curvature="0" /><path
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:0.882135"
|
||||
d="m 89.6,167.6 c -0.4,0 -0.8,-0.4 -1.2,-0.8 -0.4,-0.8 0,-1.2 0.8,-1.6 l 5.6,-2.4 c 0.8,-0.4 1.2,0 1.6,0.8 0.4,0.8 0,1.2 -0.8,1.6 l -5.6,2.4 c -0.4,0 -0.4,0 -0.4,0 z"
|
||||
id="path68-9"
|
||||
inkscape:connector-curvature="0" /><path
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:0.882135"
|
||||
d="m 63.6,196.8 h -0.4 c -0.8,-0.4 -0.8,-1.2 -0.8,-1.6 l 2.4,-5.6 c 0.4,-0.8 1.2,-0.8 1.6,-0.8 0.8,0.4 0.8,1.2 0.8,1.6 l -2.4,5.6 c 0,0.4 -0.8,0.8 -1.2,0.8 z"
|
||||
id="path70-3"
|
||||
inkscape:connector-curvature="0" /><path
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:0.882135"
|
||||
d="m 79.6,158 h -0.4 c -0.8,-0.4 -0.8,-1.2 -0.8,-1.6 l 2.4,-5.6 c 0.4,-0.8 1.2,-0.8 1.6,-0.8 0.8,0.4 0.8,1.2 0.8,1.6 l -2.4,5.6 c 0,0.4 -0.8,0.8 -1.2,0.8 z"
|
||||
id="path72-6"
|
||||
inkscape:connector-curvature="0" /><path
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:0.882135"
|
||||
d="M 56,167.6 H 55.6 L 50,165.2 c -0.8,-0.4 -0.8,-1.2 -0.8,-1.6 0.4,-0.8 1.2,-0.8 1.6,-0.8 l 5.6,2.4 c 0.8,0.4 0.8,1.2 0.8,1.6 0,0.8 -0.4,0.8 -1.2,0.8 z"
|
||||
id="path74-0"
|
||||
inkscape:connector-curvature="0" /><path
|
||||
style="fill:#000000;fill-opacity:1;stroke-width:0.882135"
|
||||
d="m 94.8,183.6 h -0.4 l -5.6,-2.4 C 88,180.8 88,180 88,179.6 c 0.4,-0.8 1.2,-0.8 1.6,-0.8 l 5.6,2.4 c 0.8,0.4 0.8,1.2 0.8,1.6 0,0.8 -0.8,0.8 -1.2,0.8 z"
|
||||
id="path76-6"
|
||||
inkscape:connector-curvature="0" /><path
|
||||
style="fill:#ff0000;fill-opacity:1;stroke-width:0.882135"
|
||||
d="m 72.8,180.4 v 0 c -4,0 -6.8,-3.2 -6.8,-6.8 v 0 c 0,-4 3.2,-6.8 6.8,-6.8 v 0 c 4,0 6.8,3.2 6.8,6.8 v 0 c 0,3.6 -2.8,6.8 -6.8,6.8 z"
|
||||
id="path78-2"
|
||||
inkscape:connector-curvature="0" /><path
|
||||
id="rect1441-6"
|
||||
style="opacity:1;fill:#ff0000;stroke-width:2.21715"
|
||||
d="m 72.801641,150.78759 v 0 l 5.635295,19.11133 h -11.27059 z"
|
||||
sodipodi:nodetypes="ccccc" /></g><text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-weight:normal;font-size:33.3333px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
x="67.090721"
|
||||
y="114.12241"
|
||||
id="text1475"
|
||||
inkscape:export-filename="/home/gruinelli/temp/AI-on-the-edge-device/images/icon/favicon.ico"
|
||||
inkscape:export-xdpi="19.790001"
|
||||
inkscape:export-ydpi="19.790001"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan1473"
|
||||
x="67.090721"
|
||||
y="114.12241"
|
||||
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:33.3333px;font-family:Sans;-inkscape-font-specification:'Sans Bold';fill:#ffffff">5</tspan></text><text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-weight:normal;font-size:33.3333px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
x="99.090721"
|
||||
y="114.12241"
|
||||
id="text7150"
|
||||
inkscape:export-filename="/home/gruinelli/temp/AI-on-the-edge-device/images/icon/favicon.ico"
|
||||
inkscape:export-xdpi="19.790001"
|
||||
inkscape:export-ydpi="19.790001"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan7148"
|
||||
x="99.090721"
|
||||
y="114.12241"
|
||||
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:33.3333px;font-family:Sans;-inkscape-font-specification:'Sans Bold';fill:#ffffff">2</tspan></text><text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-weight:normal;font-size:33.3333px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
x="131.09073"
|
||||
y="114.12241"
|
||||
id="text7154"
|
||||
inkscape:export-filename="/home/gruinelli/temp/AI-on-the-edge-device/images/icon/favicon.ico"
|
||||
inkscape:export-xdpi="19.790001"
|
||||
inkscape:export-ydpi="19.790001"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan7152"
|
||||
x="131.09073"
|
||||
y="114.12241"
|
||||
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:33.3333px;font-family:Sans;-inkscape-font-specification:'Sans Bold';fill:#ffffff">0</tspan></text><text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-weight:normal;font-size:33.3333px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
x="161.09073"
|
||||
y="114.12241"
|
||||
id="text7158"
|
||||
inkscape:export-filename="/home/gruinelli/temp/AI-on-the-edge-device/images/icon/favicon.ico"
|
||||
inkscape:export-xdpi="19.790001"
|
||||
inkscape:export-ydpi="19.790001"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan7156"
|
||||
x="161.09073"
|
||||
y="114.12241"
|
||||
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:33.3333px;font-family:Sans;-inkscape-font-specification:'Sans Bold';fill:#ffffff">3</tspan></text><text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-weight:normal;font-size:33.3333px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
x="193.09073"
|
||||
y="114.12241"
|
||||
id="text7400"
|
||||
inkscape:export-filename="/home/gruinelli/temp/AI-on-the-edge-device/images/icon/favicon.ico"
|
||||
inkscape:export-xdpi="19.790001"
|
||||
inkscape:export-ydpi="19.790001"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan7398"
|
||||
x="193.09073"
|
||||
y="114.12241"
|
||||
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:33.3333px;font-family:Sans;-inkscape-font-specification:'Sans Bold';fill:#ffffff">0</tspan></text><text
|
||||
xml:space="preserve"
|
||||
style="font-style:normal;font-weight:normal;font-size:33.3333px;line-height:125%;font-family:Sans;letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1"
|
||||
x="225.09073"
|
||||
y="114.12241"
|
||||
id="text7404"
|
||||
inkscape:export-filename="/home/gruinelli/temp/AI-on-the-edge-device/images/icon/favicon.ico"
|
||||
inkscape:export-xdpi="19.790001"
|
||||
inkscape:export-ydpi="19.790001"><tspan
|
||||
sodipodi:role="line"
|
||||
id="tspan7402"
|
||||
x="225.09073"
|
||||
y="114.12241"
|
||||
style="font-style:normal;font-variant:normal;font-weight:bold;font-stretch:normal;font-size:33.3333px;font-family:Sans;-inkscape-font-specification:'Sans Bold';fill:#ffffff">1</tspan></text><rect
|
||||
style="fill:none;stroke:#1f00ea;stroke-width:3;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="rect18406"
|
||||
width="23.916084"
|
||||
height="39.886673"
|
||||
x="222.59164"
|
||||
y="81.731308"
|
||||
inkscape:export-filename="/home/gruinelli/temp/AI-on-the-edge-device/images/icon/favicon.ico"
|
||||
inkscape:export-xdpi="19.790001"
|
||||
inkscape:export-ydpi="19.790001" /><rect
|
||||
style="fill:none;stroke:#1f00ea;stroke-width:3;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="rect20467"
|
||||
width="23.916084"
|
||||
height="39.886673"
|
||||
x="190.59164"
|
||||
y="81.731308"
|
||||
inkscape:export-filename="/home/gruinelli/temp/AI-on-the-edge-device/images/icon/favicon.ico"
|
||||
inkscape:export-xdpi="19.790001"
|
||||
inkscape:export-ydpi="19.790001" /><rect
|
||||
style="fill:none;stroke:#1f00ea;stroke-width:3;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="rect20469"
|
||||
width="23.916084"
|
||||
height="39.886673"
|
||||
x="158.59164"
|
||||
y="81.731308"
|
||||
inkscape:export-filename="/home/gruinelli/temp/AI-on-the-edge-device/images/icon/favicon.ico"
|
||||
inkscape:export-xdpi="19.790001"
|
||||
inkscape:export-ydpi="19.790001" /><circle
|
||||
style="fill:none;stroke:#02ea00;stroke-width:3;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="path20619"
|
||||
cx="245.87659"
|
||||
cy="173.6358"
|
||||
r="35.34029"
|
||||
inkscape:export-filename="/home/gruinelli/temp/AI-on-the-edge-device/images/icon/favicon.ico"
|
||||
inkscape:export-xdpi="19.790001"
|
||||
inkscape:export-ydpi="19.790001" /><circle
|
||||
style="fill:none;stroke:#02ea00;stroke-width:3;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
|
||||
id="path20619-5"
|
||||
cx="195.75063"
|
||||
cy="239.26401"
|
||||
r="35.34029"
|
||||
inkscape:export-filename="/home/gruinelli/temp/AI-on-the-edge-device/images/icon/favicon.ico"
|
||||
inkscape:export-xdpi="19.790001"
|
||||
inkscape:export-ydpi="19.790001" /></svg>
|
||||
|
After Width: | Height: | Size: 38 KiB |
Reference in New Issue
Block a user