Compare commits

..

343 Commits

Author SHA1 Message Date
CaCO3
245302c6ca Release Preparations (#1925)
* Fix for securing wlan.ini (#1509)

* Fix for securing wlan.ini

* Fixing error with ' instead of "

* Changing to errorcode 403

* maybe strcmp instead of regular ==

Co-authored-by: Pär Hedberg <par.hedberg@nordicmedtest.se>

* Update Web-Installer

* solves #1530 (#1531)

* Refactor JSON (#1518)

* use correct log level

* corrected logging

* typo

* refactored JSON generagion: removed unused parameters, consolidated into singel function, added "pre"

* Wrapped 'rate' into double quotes, like all other JSON values

Co-authored-by: CaCO3 <caco@ruinelli.ch>

* Various corrections (#1519)

* use correct log level

* corrected logging

* typo

* add release to webinstaller

* changed logs, added INFO log of raw, value, error

* .

Co-authored-by: CaCO3 <caco@ruinelli.ch>

* Prevent auto restart on cam framebuffer init error (#1522)

* use correct log level

* revert autorestart on camera framebuffer init error

* .

Co-authored-by: CaCO3 <caco@ruinelli.ch>

* #1524 - ensure the recognized digit is less than 10 (#1525)

* fix kernel panic (vector out of range) in getReadoutRawString

* fix key of caches

* fix key of caches

* fix key caches

* fix cache keys

* fix cache keys

* move set variables to top

* debug

* fix key

* testing

* try fix changelog

* test

* Update Changelog.md for  release

* Revert "Update Changelog.md for  release"

This reverts commit 4f51ec7962.

* remove testing

* fix release creation

* testing

* Update Changelog.md for  release

* test

* Revert "Merge branch 'master' of https://github.com/haverland/AI-on-the-edge-device"

This reverts commit f68695a4c0, reversing
changes made to a096cf7182.

* Revert "test"

This reverts commit a096cf7182.

* revert testing

* #1524 - ensure the result of ZeigerEvalHybridNeu is <10

* Fix late digit transition #1503

Co-authored-by: github-actions <github-actions@github.com>

* fix frozen time in datafile on error (#1534)

Co-authored-by: CaCO3 <caco@ruinelli.ch>

* log NTP server name (#1497)

* log NTP server name

* .

* .

* replace calls to /wasserzaehler.html with calls to /value (#1469)

Co-authored-by: CaCO3 <caco@ruinelli.ch>

* Fix cookie usage, use correct http response codes, add 404 page (#1495)

* replaced some HTTP response code with better matching codes

* add custom 404 page, add log entry for debugging

* fix cookie

* replace non-necessary whitespace

* .

Co-authored-by: CaCO3 <caco@ruinelli.ch>

* Don't autofail if NTP server can't be reached during initalization (#1498)

This fixes an issue with a restricted network without internet access,
where the hardcoded ntp server can't be reached and thus the esp resets,
as it's not able to finish initalization.

* Update Changelog.md

* Update Changelog.md for  release

* Fix for securing wlan.ini (#1509)

* Fix for securing wlan.ini

* Fixing error with ' instead of "

* Changing to errorcode 403

* maybe strcmp instead of regular ==

Co-authored-by: Pär Hedberg <par.hedberg@nordicmedtest.se>

* Update Web-Installer

* solves #1530 (#1531)

* Refactor JSON (#1518)

* use correct log level

* corrected logging

* typo

* refactored JSON generagion: removed unused parameters, consolidated into singel function, added "pre"

* Wrapped 'rate' into double quotes, like all other JSON values

Co-authored-by: CaCO3 <caco@ruinelli.ch>

* Various corrections (#1519)

* use correct log level

* corrected logging

* typo

* add release to webinstaller

* changed logs, added INFO log of raw, value, error

* .

Co-authored-by: CaCO3 <caco@ruinelli.ch>

* Prevent auto restart on cam framebuffer init error (#1522)

* use correct log level

* revert autorestart on camera framebuffer init error

* .

Co-authored-by: CaCO3 <caco@ruinelli.ch>

* #1524 - ensure the recognized digit is less than 10 (#1525)

* fix kernel panic (vector out of range) in getReadoutRawString

* fix key of caches

* fix key of caches

* fix key caches

* fix cache keys

* fix cache keys

* move set variables to top

* debug

* fix key

* testing

* try fix changelog

* test

* Update Changelog.md for  release

* Revert "Update Changelog.md for  release"

This reverts commit 4f51ec7962.

* remove testing

* fix release creation

* testing

* Update Changelog.md for  release

* test

* Revert "Merge branch 'master' of https://github.com/haverland/AI-on-the-edge-device"

This reverts commit f68695a4c0, reversing
changes made to a096cf7182.

* Revert "test"

This reverts commit a096cf7182.

* revert testing

* #1524 - ensure the result of ZeigerEvalHybridNeu is <10

* Fix late digit transition #1503

Co-authored-by: github-actions <github-actions@github.com>

* only use sntp_getservername() after init sntp

* set default NTP server on dnew installations

Co-authored-by: CaCO3 <caco@ruinelli.ch>
Co-authored-by: Ralf Rachinger <git@ralfrachinger.de>
Co-authored-by: jomjol <30766535+jomjol@users.noreply.github.com>
Co-authored-by: github-actions <github-actions@github.com>
Co-authored-by: parhedberg <par.hedberg@gmail.com>
Co-authored-by: Pär Hedberg <par.hedberg@nordicmedtest.se>
Co-authored-by: Christopher Fenner <9592452+CFenner@users.noreply.github.com>
Co-authored-by: Frank Haverland <fspapaping@googlemail.com>

* Renamed variables and added debug log (#1537)

* add debug logs

* renamed variables

* renamed TAGs, added flow status logging

* .

* .

Co-authored-by: CaCO3 <caco@ruinelli.ch>

* replaced printf usage in LogFile.WriteToFile()

* ENABLE_MQTT c++ macro definition (#1546)

* macro

* 2

* 2

* delete jomjol_mqtt from CMakeLists

* mqtt macro

* final

* ENABLE_INFLUXDB c++ macro definition (#1547)

* macro

* 2

* 2

* delete jomjol_mqtt from CMakeLists

* mqtt macro

* final

* ENABLE_INFLUXDB c++ macro definition

* Update Changelog.md

* Update Changelog.md

* Rearange task to CPU (http, camera, mqtt) (#1557)

* Streamlined MQTT interlock when not activated & interlock MQTT when WIFI is not connected (#1556)

* streamlined mqtt interlock when disabled

* Disconnect mqtt client before reboot

* Interlock MQTT with WIFI

* Update

* loglevel to DEBUG

* Update

* mqtt msg id incremental

* new ENABLE_MQTT includes

* Loglevel to DEBUG

* Loglevel

* Update interface_mqtt.cpp

* show uptime on overview page, moved labels from firmware to Web UI (#1543)

* show uptime on overview page, moved labels from firmware to Web UI

* show uptime on info page

* also use formated time in log

Co-authored-by: CaCO3 <caco@ruinelli.ch>

* Continue boot on bad PSRAM (#1558)

* add sensor status, show special index/setup page in case of a critical error

* continue booting on PSRAM error

* Update main.cpp

added log messages

* init PSRAM and add more log messages

* cleanup of init checks

* .

* .

* .

Co-authored-by: CaCO3 <caco@ruinelli.ch>

* add sensor status, show special index/setup page in case of a critical error (#1560)

* add sensor status, show special index/setup page in case of a critical error

* Added Reboot

* .

* added more buttons

Co-authored-by: CaCO3 <caco@ruinelli.ch>
Co-authored-by: jomjol <30766535+jomjol@users.noreply.github.com>

* Update Webinstaller to v13.0.7

* remove  html-from-11.3.1 in release (#1565)

* fix kernel panic (vector out of range) in getReadoutRawString

* fix key of caches

* fix key of caches

* fix key caches

* fix cache keys

* fix cache keys

* move set variables to top

* debug

* fix key

* testing

* try fix changelog

* test

* Update Changelog.md for  release

* Revert "Update Changelog.md for  release"

This reverts commit 4f51ec7962.

* remove testing

* fix release creation

* testing

* Update Changelog.md for  release

* test

* Revert "Merge branch 'master' of https://github.com/haverland/AI-on-the-edge-device"

This reverts commit f68695a4c0, reversing
changes made to a096cf7182.

* Revert "test"

This reverts commit a096cf7182.

* revert testing

* #1524 - ensure the result of ZeigerEvalHybridNeu is <10

* Fix late digit transition #1503

* only initial_esp32_setup and update.zip as artefacts

* remove unneeded cache

* rename step ota-v2 to ota

* rename ota-v2 to ota

Co-authored-by: github-actions <github-actions@github.com>

* make the sidebar on the overviw page wider and show the round counter (#1570)

Co-authored-by: CaCO3 <caco@ruinelli.ch>

* Create reply-bot.yml

* Update ClassFlowPostProcessing.cpp

* Add bot (#1581)

* Update reply-bot.yml

* Create label-commenter-config.yml

* added missing html change

* extended instructions (#1583)

Co-authored-by: CaCO3 <caco@ruinelli.ch>

* Fix Rate Problem

* removed redundant "Status:"

* Bugfix Double Extract ZIP-Files

* Update FeatureRequest.md (#1591)

in case of position change between the measurments set this state to true, if there is no change set it back to false.
In a defined time window this movement can lead into an alarm state / water leak..
haveing this state in the mqtt broker can trigger functions like closing the ater pipe walve and so on...

* Update manifest.json

* Delete .gitignore

* Delete .gitmodules

* Delete firmware.bin

* Add files via upload

* Block REST API calls till resource is ready (#1609)

* Block REST API call till ressource is ready

* Update

* Update

* Update

* replace relative include of gethost.js with absolute one. This is needed as that file gets incuded on dynamically generated content which can be on different path levels (#1610)

Co-authored-by: CaCO3 <caco@ruinelli.ch>

* esp_spiram.h has been replaced by esp32/spiram.h (#1605)

* esp_spiram.h has been replaced by esp32/spiram.h

* Preparations for next Bugfix Release (#1615)

* Merge branch 'rolling' (#1559)

* Fix for securing wlan.ini (#1509)

* Fix for securing wlan.ini

* Fixing error with ' instead of "

* Changing to errorcode 403

* maybe strcmp instead of regular ==

Co-authored-by: Pär Hedberg <par.hedberg@nordicmedtest.se>

* Update Web-Installer

* solves #1530 (#1531)

* Refactor JSON (#1518)

* use correct log level

* corrected logging

* typo

* refactored JSON generagion: removed unused parameters, consolidated into singel function, added "pre"

* Wrapped 'rate' into double quotes, like all other JSON values

Co-authored-by: CaCO3 <caco@ruinelli.ch>

* Various corrections (#1519)

* use correct log level

* corrected logging

* typo

* add release to webinstaller

* changed logs, added INFO log of raw, value, error

* .

Co-authored-by: CaCO3 <caco@ruinelli.ch>

* Prevent auto restart on cam framebuffer init error (#1522)

* use correct log level

* revert autorestart on camera framebuffer init error

* .

Co-authored-by: CaCO3 <caco@ruinelli.ch>

* #1524 - ensure the recognized digit is less than 10 (#1525)

* fix kernel panic (vector out of range) in getReadoutRawString

* fix key of caches

* fix key of caches

* fix key caches

* fix cache keys

* fix cache keys

* move set variables to top

* debug

* fix key

* testing

* try fix changelog

* test

* Update Changelog.md for  release

* Revert "Update Changelog.md for  release"

This reverts commit 4f51ec7962.

* remove testing

* fix release creation

* testing

* Update Changelog.md for  release

* test

* Revert "Merge branch 'master' of https://github.com/haverland/AI-on-the-edge-device"

This reverts commit f68695a4c0, reversing
changes made to a096cf7182.

* Revert "test"

This reverts commit a096cf7182.

* revert testing

* #1524 - ensure the result of ZeigerEvalHybridNeu is <10

* Fix late digit transition #1503

Co-authored-by: github-actions <github-actions@github.com>

* fix frozen time in datafile on error (#1534)

Co-authored-by: CaCO3 <caco@ruinelli.ch>

* log NTP server name (#1497)

* log NTP server name

* .

* .

* replace calls to /wasserzaehler.html with calls to /value (#1469)

Co-authored-by: CaCO3 <caco@ruinelli.ch>

* Fix cookie usage, use correct http response codes, add 404 page (#1495)

* replaced some HTTP response code with better matching codes

* add custom 404 page, add log entry for debugging

* fix cookie

* replace non-necessary whitespace

* .

Co-authored-by: CaCO3 <caco@ruinelli.ch>

* Don't autofail if NTP server can't be reached during initalization (#1498)

This fixes an issue with a restricted network without internet access,
where the hardcoded ntp server can't be reached and thus the esp resets,
as it's not able to finish initalization.

* Update Changelog.md

* Update Changelog.md for  release

* Fix for securing wlan.ini (#1509)

* Fix for securing wlan.ini

* Fixing error with ' instead of "

* Changing to errorcode 403

* maybe strcmp instead of regular ==

Co-authored-by: Pär Hedberg <par.hedberg@nordicmedtest.se>

* Update Web-Installer

* solves #1530 (#1531)

* Refactor JSON (#1518)

* use correct log level

* corrected logging

* typo

* refactored JSON generagion: removed unused parameters, consolidated into singel function, added "pre"

* Wrapped 'rate' into double quotes, like all other JSON values

Co-authored-by: CaCO3 <caco@ruinelli.ch>

* Various corrections (#1519)

* use correct log level

* corrected logging

* typo

* add release to webinstaller

* changed logs, added INFO log of raw, value, error

* .

Co-authored-by: CaCO3 <caco@ruinelli.ch>

* Prevent auto restart on cam framebuffer init error (#1522)

* use correct log level

* revert autorestart on camera framebuffer init error

* .

Co-authored-by: CaCO3 <caco@ruinelli.ch>

* #1524 - ensure the recognized digit is less than 10 (#1525)

* fix kernel panic (vector out of range) in getReadoutRawString

* fix key of caches

* fix key of caches

* fix key caches

* fix cache keys

* fix cache keys

* move set variables to top

* debug

* fix key

* testing

* try fix changelog

* test

* Update Changelog.md for  release

* Revert "Update Changelog.md for  release"

This reverts commit 4f51ec7962.

* remove testing

* fix release creation

* testing

* Update Changelog.md for  release

* test

* Revert "Merge branch 'master' of https://github.com/haverland/AI-on-the-edge-device"

This reverts commit f68695a4c0, reversing
changes made to a096cf7182.

* Revert "test"

This reverts commit a096cf7182.

* revert testing

* #1524 - ensure the result of ZeigerEvalHybridNeu is <10

* Fix late digit transition #1503

Co-authored-by: github-actions <github-actions@github.com>

* only use sntp_getservername() after init sntp

* set default NTP server on dnew installations

Co-authored-by: CaCO3 <caco@ruinelli.ch>
Co-authored-by: Ralf Rachinger <git@ralfrachinger.de>
Co-authored-by: jomjol <30766535+jomjol@users.noreply.github.com>
Co-authored-by: github-actions <github-actions@github.com>
Co-authored-by: parhedberg <par.hedberg@gmail.com>
Co-authored-by: Pär Hedberg <par.hedberg@nordicmedtest.se>
Co-authored-by: Christopher Fenner <9592452+CFenner@users.noreply.github.com>
Co-authored-by: Frank Haverland <fspapaping@googlemail.com>

* Renamed variables and added debug log (#1537)

* add debug logs

* renamed variables

* renamed TAGs, added flow status logging

* .

* .

Co-authored-by: CaCO3 <caco@ruinelli.ch>

* replaced printf usage in LogFile.WriteToFile()

* ENABLE_MQTT c++ macro definition (#1546)

* macro

* 2

* 2

* delete jomjol_mqtt from CMakeLists

* mqtt macro

* final

* ENABLE_INFLUXDB c++ macro definition (#1547)

* macro

* 2

* 2

* delete jomjol_mqtt from CMakeLists

* mqtt macro

* final

* ENABLE_INFLUXDB c++ macro definition

* Update Changelog.md

Co-authored-by: parhedberg <par.hedberg@gmail.com>
Co-authored-by: Pär Hedberg <par.hedberg@nordicmedtest.se>
Co-authored-by: jomjol <30766535+jomjol@users.noreply.github.com>
Co-authored-by: Christopher Fenner <9592452+CFenner@users.noreply.github.com>
Co-authored-by: CaCO3 <caco@ruinelli.ch>
Co-authored-by: Frank Haverland <fspapaping@googlemail.com>
Co-authored-by: github-actions <github-actions@github.com>
Co-authored-by: Ralf Rachinger <git@ralfrachinger.de>
Co-authored-by: Nicolas Liaudat <nliaudat@users.noreply.github.com>

* Update Changelog.md for  release

Co-authored-by: parhedberg <par.hedberg@gmail.com>
Co-authored-by: Pär Hedberg <par.hedberg@nordicmedtest.se>
Co-authored-by: jomjol <30766535+jomjol@users.noreply.github.com>
Co-authored-by: Christopher Fenner <9592452+CFenner@users.noreply.github.com>
Co-authored-by: CaCO3 <caco@ruinelli.ch>
Co-authored-by: Frank Haverland <fspapaping@googlemail.com>
Co-authored-by: github-actions <github-actions@github.com>
Co-authored-by: Ralf Rachinger <git@ralfrachinger.de>
Co-authored-by: Nicolas Liaudat <nliaudat@users.noreply.github.com>

* new model version (#1619)

* fix kernel panic (vector out of range) in getReadoutRawString

* fix key of caches

* fix key of caches

* fix key caches

* fix cache keys

* fix cache keys

* move set variables to top

* debug

* fix key

* testing

* try fix changelog

* test

* Update Changelog.md for  release

* Revert "Update Changelog.md for  release"

This reverts commit 4f51ec7962.

* remove testing

* fix release creation

* testing

* Update Changelog.md for  release

* test

* Revert "Merge branch 'master' of https://github.com/haverland/AI-on-the-edge-device"

This reverts commit f68695a4c0, reversing
changes made to a096cf7182.

* Revert "test"

This reverts commit a096cf7182.

* revert testing

* #1524 - ensure the result of ZeigerEvalHybridNeu is <10

* Fix late digit transition #1503

* only initial_esp32_setup and update.zip as artefacts

* remove unneeded cache

* rename step ota-v2 to ota

* rename ota-v2 to ota

* new models

- ana-class100 v1.5.4
- ana-cont-11.0.4
- dig-class100 v1.5.0

Co-authored-by: github-actions <github-actions@github.com>

* Update Changelog.md (#1630)

* Correct RenameNumber

* Update Changelog.md

* Fix reloading of data file (#1635)

* Update data.html

* fixed

* show link to graph

Co-authored-by: CaCO3 <caco@ruinelli.ch>

* Centralizing the defines (#1624)

* defines changes

* Finish #define move + #define STBI_ONLY_JPEGsave 2% of Flash

* remove the defines on the old places

* ClassFlowCNNGeneral in define.h

* revert to origin

* fix translation not ready

* Update defines.h

* Update WebInstaller

* Code translation (#1626)

* comment translation

* translation part #2

* code translation from DE to ENG #part3

* translation #4

* dismantled =>splitted

* bereich => range

* Update defines.h

Co-authored-by: jomjol <30766535+jomjol@users.noreply.github.com>

* Update manifest.json

* Add files via upload

* #ifndef in *.h + #pragma once (#1639)

* Update defines.h (#1640)

comment #define STBI_ONLY_JPEG as you do no want it in rolling but in rolling-minimize-firmware-size

delete old reference to DE 


'''
    #define AnalogFehler 3
    #define AnalogToDigtalFehler 0.8
    #define DigitalUnschaerfe 0.2
    #define DigitalBand 3
    #define DigitalAnalogerVorgaengerUebergangsbereich 2
    #define DigitalUebergangsbereichVorgaenger 0.7 // 9.3 - 0.7
    #define DigitalUebergangsbereichVorlauf 9.7
'''

* Trigger a flow start by REST API or MQTT (#1648)

* Trigger flow start by Rest API

* Increase handlers

* Update

* Update

* Update

* Change max handlers

* Add debug message

* Trigger flow start by MQTT

* Update

* Remove unused function

* Remove handler_doflow + routines

* Cleanup

* MergeCheck

* Optimize logfile write (#1652)

* remove no longer needed OpenFileAndWait()

* remove WriteToDedicatedFile

* .

Co-authored-by: CaCO3 <caco@ruinelli.ch>

* show release in log instead of branch (#1660)

Co-authored-by: CaCO3 <caco@ruinelli.ch>

* Update sdkconfig.defaults (#1661)

Reverting changes of `sdkconfig.defaults` falsly added within https://github.com/jomjol/AI-on-the-edge-device/pull/1626

* Init GPIO handler before MQTT init (#1663)

* Update HTML & Firmware (#1671)

* Remove unnecessary null pointer checks #1649 (#1673)

* fix kernel panic (vector out of range) in getReadoutRawString

* fix key of caches

* fix key of caches

* fix key caches

* fix cache keys

* fix cache keys

* move set variables to top

* debug

* fix key

* testing

* try fix changelog

* test

* Update Changelog.md for  release

* Revert "Update Changelog.md for  release"

This reverts commit 4f51ec7962.

* remove testing

* fix release creation

* testing

* Update Changelog.md for  release

* test

* Revert "Merge branch 'master' of https://github.com/haverland/AI-on-the-edge-device"

This reverts commit f68695a4c0, reversing
changes made to a096cf7182.

* Revert "test"

This reverts commit a096cf7182.

* revert testing

* #1524 - ensure the result of ZeigerEvalHybridNeu is <10

* Fix late digit transition #1503

* only initial_esp32_setup and update.zip as artefacts

* remove unneeded cache

* rename step ota-v2 to ota

* rename ota-v2 to ota

* new models

- ana-class100 v1.5.4
- ana-cont-11.0.4
- dig-class100 v1.5.0

* Remove unnecessary null pointer checks #1649

Co-authored-by: github-actions <github-actions@github.com>

* Improve NTP handling (#1676)

* fix special case where number is named "default" (keep all topics in top level instead of in a sub-group)

* re-implemented SNTP usage, added way to disable NTP client, added timezone table

* minor fixes

Co-authored-by: CaCO3 <caco@ruinelli.ch>

* fix special case where number is named "default" (keep all topics in top level instead of in a sub-group) (#1664)

Co-authored-by: CaCO3 <caco@ruinelli.ch>

* prepare docs for deployment through actions (#1688)

Co-authored-by: CaCO3 <caco@ruinelli.ch>

* make more robust, add log (#1690)

Co-authored-by: CaCO3 <caco@ruinelli.ch>

* Extend Github Actions (#1680)

* Update build.yaml

* Update build.yaml

* Update build.yaml

* Update build.yaml

* Update build.yaml

* Update build.yaml

* Update build.yaml

* Update build.yaml

* Update build.yaml

* automate manifest update

* Update build.yaml

* revert changes to docs folder

* Update build.yaml

* Update build.yaml

* Update build.yaml

* Update build.yaml

* Update build.yaml

* Update build.yaml

* Update build.yaml

* Add files via upload

* prepare docs for deployment through actions (#1688)

Co-authored-by: CaCO3 <caco@ruinelli.ch>

* automate manifest update

# Conflicts:
#	docs/binary/firmware.bin
#	docs/binary/v12.0.1/firmware.bin
#	docs/binary/v12.0.5/firmware.bin
#	docs/binary/v13.0.5/firmware.bin
#	docs/binary/v13.0.7/firmware.bin

* revert changes to docs folder

* revert changes to docs folder

# Conflicts:
#	docs/releases/download/firmware.bin

* Update build.yaml

Co-authored-by: CaCO3 <caco@ruinelli.ch>

* Improve initial setup proc (#1692)

* Initial Test

* Initial functional version.

* Add Bot Replies (#1701)

* Update label-commenter-config.yml

* Update reply-bot.yml

* Update label-commenter-config.yml

* disable remove-labels because they no longer work

* delete img_convert.h as included in code\components\tflite-micro-esp-… (#1695)

* delete img_convert.h as included in code\components\tflite-micro-esp-examples\components\esp32-camera\conversions\include\img_converters.h

* macro definition #ifdef ENABLE_SOFTAP

* macro definition #ifdef ENABLE_SOFTAP (#1698)

* macro definition #ifdef ENABLE_SOFTAP

* Update platformio.ini

* softap define in define.h

* Update platformio.ini

* #define WLAN_CONFIG_FILE "/sdcard/wlan.ini"

Co-authored-by: jomjol <30766535+jomjol@users.noreply.github.com>

* Deinit components before reboot (#1704)

* Deinit all components before reboot

* Update

* Update

* fetch index.html after reboot -> less 404 (#1705)

* Safe optimizations (#1706)

* safe optimizations

* Merge branch 'rolling' of https://github.com/nliaudat/AI-on-the-edge-device into rolling

* Enable SoftAP

* Update defines

* add a define to configure the logfile handling (#1709)

Co-authored-by: CaCO3 <caco@ruinelli.ch>

* Move Logfile Switch to define.h

* Update Reboot Algo

* Update server_ota.cpp

* Avoid loading of status infos twice (#1711)

* Force a reboot even reboot task cannot be created due to lack of heap (#1713)

* Deinit all components before reboot

* Update

* Update

* Force reboot when reboot task cannot be created

* Improve log message when web UI is incomplete (#1716)

* improve warning if version.txt is missing

* typo

* show round duration in log

Co-authored-by: CaCO3 <caco@ruinelli.ch>

* fix static IP in UP, improve explanation for HA (#1719)

* fix static IP in UP, improve explanation for HA

* Update edit_config_param.html

Co-authored-by: CaCO3 <caco@ruinelli.ch>

* Create demo folder at startup (if not present)

* Update defines.h (#1726)

* improve explanations,added example (#1729)

Co-authored-by: CaCO3 <caco@ruinelli.ch>

* Add demo mode (#1720)

* move main part to cam file

* added demo mode

* .

* add a define to configure the logfile handling (#1709)

Co-authored-by: CaCO3 <caco@ruinelli.ch>

* Move Logfile Switch to define.h

* Update Reboot Algo

* Update server_ota.cpp

* Avoid loading of status infos twice (#1711)

* Force a reboot even reboot task cannot be created due to lack of heap (#1713)

* Deinit all components before reboot

* Update

* Update

* Force reboot when reboot task cannot be created

* Improve log message when web UI is incomplete (#1716)

* improve warning if version.txt is missing

* typo

* show round duration in log

Co-authored-by: CaCO3 <caco@ruinelli.ch>

* .

* .

* .

* creade demo dir

* fix static IP in UP, improve explanation for HA (#1719)

* fix static IP in UP, improve explanation for HA

* Update edit_config_param.html

Co-authored-by: CaCO3 <caco@ruinelli.ch>

* Create demo folder at startup (if not present)

* move demo files

* Update defines.h (#1726)

* updated description

* moved to expert section

* fixed broken enabled state

Co-authored-by: CaCO3 <caco@ruinelli.ch>
Co-authored-by: jomjol <30766535+jomjol@users.noreply.github.com>
Co-authored-by: Slider0007 <115730895+Slider0007@users.noreply.github.com>

* Fix regression of reboot handler / reboot waiting script (#1725)

* Reboot after OTA: Avoid exeception

* Overview - optimize reload behaviour after reboot

* Update

* Update

* Moved softAP to the very first checks

* Update SoftAP

* Update build.yaml (#1737)

* Update build.yaml

* Update build.yaml

* #1649 unnecessary np check (#1736)

* consolidate test-ip definition, added missing Access-Control-Allow-Origin,

* Revert "consolidate test-ip definition, added missing Access-Control-Allow-Origin,"

This reverts commit 56cfeb732e.

* consolidate test-ip definition, added missing Access-Control-Allow-Origin (#1741)

Co-authored-by: CaCO3 <caco@ruinelli.ch>

* Replace alert boxes with overlay info boxes  (#1742)

* consolidate test-ip definition, added missing Access-Control-Allow-Origin

* replace alert boxes with overlay info boxes

* .

* .

* .

* .

* .

* .

* .

* .

* .

* .

* .

Co-authored-by: CaCO3 <caco@ruinelli.ch>

* compiler optimization (#1749)

compiler optimization for tflite-micro-esp-examples

* Modify stack sizes + max open files (SD) , add REST handler for heap/(stack) infos (#1751)

* Modify stack sizes+max open files,add rest handler

* Update

* Optimized CImageBasis

* Update feature.yaml

* cache static files (#1755)

Co-authored-by: CaCO3 <caco@ruinelli.ch>

* Implemented Reboot for "firmware.bin" as well

* new OTA page with progressbar (#1756)

* new OTA page with progress bar

* improve error message on missing demo files

* .

* Implemented Reboot for "firmware.bin" as well

* Update feature.yaml

* cache static files (#1755)

Co-authored-by: CaCO3 <caco@ruinelli.ch>

* .

* .

* added filename validation

* .

* .

* .

* move

* added missing dash to regex

* restrict file type

* .

* .

* .

* .

* cleanup no longer needed mode

* only start restart counter if restart is required

Co-authored-by: CaCO3 <caco@ruinelli.ch>
Co-authored-by: jomjol <30766535+jomjol@users.noreply.github.com>

* Rolling-bot: Only show jomjol repo rollings (#1783)

* Update platfromio.ini

* Add option to disable brownout detector (#1784)

* Update defines.h

* Update main.cpp

* Improve file server (#1785)

* .

* .

* .

* .

* .

* .

* .

Co-authored-by: CaCO3 <caco@ruinelli.ch>

* Ignore cache on GIT hash change (new commit or release) (#1787)

* Add hash to all html, css, and js URLs

* Update build.yaml

* Update build.yaml

* .

* .

Co-authored-by: CaCO3 <caco@ruinelli.ch>

* fix overview.html

* GPIO handler: Deinit before delete (#1795)

* Rest handler: Use none chunked transfer (#1797)

* Resthandler info,sysinfo,starttime: no chunk trans

* flowstart,statusflow,cputemp,rssi,uptime,prevalue

* Renamed error messages

* STBI_ONLY_JPEG (#1789)

* Add error handling for memory intensive tasks (#1798)

* tflite model loading: error handling

* FlowAlignment: error handling

* CImageBasis+GetJPGStream : error handling

* Update graph.html (#1802)

* Delete demo-images directory

Data is now provided in the documentation

* REST handler sysinfo + MQTT topic: Free heap memory not reporting (#1815)

* REST handler sysinfo: Fix reporting of free memory

* MQTT topic freemem: Fix reporting of free memory

* Refactor getEspHeapInfo routine (#1816)

* Refactor getEspHeapInfo

* ClassLogfile: Remove redundandent one

* DataGraph: datafiles sorted -> newest on top (#1817)

* plaformio [env:esp32cam-dev] : Add task analysis & test for 8m spiram  real support (#1818)

add support of   TASK_ANALYSIS_ON 
test full support of 8mb spiram board  (https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/system/himem.html)

* Improve html roi disablement (#1825)

* Improve ROI-Problem

* Update

* Update common.js

* Update links

* Store preprocessed image with ROI to RAM (#1809)

* tflite model loading: error handling

* FlowAlignment: error handling

* CImageBasis+GetJPGStream : error handling

* store preprocessed ALG_ROI.jpg to memory

* Update

* Create clean-branch-cache-after-pull-request-got-closed.yml

* Clean sdkconfig (not default) (#1828)

* Delete sdkconfig - Kopie.defaults

* Delete sdkconfig.esp32cam-testing

* Delete sdkconfig - Kopie.esp32cam

* Update platformio.ini

* Delete clean-branch-cache-after-pull-request-got-closed.yml

* Update README.md

* Esp32 sys info (#1829)

* Add files via upload

* Update defines.h

* Update main.cpp

* git ignore + sdkconfig.esp32cam-dev (#1830)

* update build actions/cache@v3.2.3 (#1831)

* actions/cache@v3.2.3

* Create clear _all_cache.yml

* fix typo naming workflow clear_cache.yml

* Update tflite

* Initial Implementation (#1834)

* Fix pointer call in ClassControllCamera.cpp:310 (#1833)

ClassControllCamera.cpp:310:67: error: request for member 'rgb_image' in '_zwImage', which is of pointer type 'CImageBasis*'
ClassControllCamera.cpp:310:117: error: request for member 'width' in '_zwImage', which is of pointer type 'CImageBasis*'
ClassControllCamera.cpp:310:157: error: request for member 'height' in '_zwImage', which is of pointer type 'CImageBasis*'

* Initial Implementation (#1835)

* improve caching (#1836)

* improve caching

See https://github.com/actions/cache/blob/main/tips-and-workarounds.md#update-a-cache

* Update build.yaml

* Update build.yaml

* Update build.yaml

* Update README.md

* Update build.yaml

* Update build.yaml

* Update README.md

* Update build.yaml

* Update label-commenter-config.yml

* Fix uninitialized filename (#1838)

* fix the uninitialized filename. It only got used for the logging in case the file exists but failed to get loaded (eg. /sdcard/log/data/data_2023-01-14.csv)

* .

Co-authored-by: CaCO3 <caco@ruinelli.ch>

* Show ways to get notified about new releases

* update wiki references

* enhance development environment (#1841)

* add sdkconfig.defaults per environment 

https://github.com/platformio/platform-espressif32/issues/638

* add env to platformio

* add sdkconfig.<pioenv>.defaults

* Update platformio.ini

* Update .gitignore

* Delete sdkconfig.esp32cam-cpu-freq-240.defaults

* Delete sdkconfig.esp32cam-dev-himem.defaults

* Delete sdkconfig.esp32cam-dev.defaults

* Delete sdkconfig.esp32cam-no-softap.defaults

* Add files via upload

* Update sdkconfig.esp32cam-cpu-freq-240.defaults

* Update platformio.ini

* Update platformio.ini

* Update CMakeLists.txt

* Update sdkconfig.esp32cam-dev.defaults

* Update platformio.ini

* add HIMEM debugging tools (check free size, and memory test) (#1852)

* Update defines.h

* Update esp_sys.h

* Update esp_sys.cpp

* Add files via upload

* Update perfmon.c

* Update main.cpp

* Update main.cpp

* Delete himem_memory_check.c

* Add files via upload

* Update defines.h

* Update himem_memory_check.cpp

* Update main.cpp

* Update himem_memory_check.cpp

* Update himem_memory_check.h

* Update main.cpp

* fix define

* Avoid multiple Access-Control-Allow-Origin * (#1859)

* Avoid multiple Access-Control-Allow-Origin *

* Adapt loglevel to debug

* Update build.yaml

* Improve data logging on errors (#1839)

* use error level for log if "Rate to High" or "Negative Rate"

* remove redundant data logging

* .

* .

* update time also in case of an error

* move calculation of difference to the top as discussed in PR 1839

Co-authored-by: CaCO3 <caco@ruinelli.ch>

* Heap tracing (#1861)

* Update sdkconfig.esp32cam-dev-task-analysis.defaults

* Update defines.h

* Update platformio.ini

* Update main.cpp

* Update defines.h

* Update ClassFlowCNNGeneral.cpp

* Update platformio.ini

* disable HIMEM (external > 4mb ram) not used (#1864)

#force disable HIMEM as not used in default config, can be enabled with [env:esp32cam-dev-himem]
#free 256kb of internal memory :
#I (2112) esp_himem: Initialized. Using last 8 32KB address blocks for bank switching on 4352 KB of physical memory.
CONFIG_SPIRAM_BANKSWITCH_ENABLE=n
#CONFIG_SPIRAM_BANKSWITCH_RESERVE is not set

* Update ota_page.html (#1866)

Fixed the firework to match the actual button text.
Fixed other random typos.

* add AlignmentAlgo=off option (#1867)

* Replace outdated wiki links, wording (#1871)

* Revert "add AlignmentAlgo=off option (#1867)" (#1876)

This reverts commit 3de4cc7c56.

* fixed typo (#1881)

Co-authored-by: CaCO3 <caco@ruinelli.ch>

* Show WIFI signal text labels / Log RSSI value to logfile (#1877)

* Overview: WIFI RSSI strength text labels

* Log RSSI value (debug level)

* Typo

* Update config.ini (#1880)

* Update Changelog.md for  release (#1892)

Co-authored-by: github-actions <github-actions@github.com>

* Update Changelog.md

* Remove newline in version (#1891)

* remove newline in version

* .

* .

Co-authored-by: CaCO3 <caco@ruinelli.ch>

* Show alternative images for states "Initialization" and "Take Image" (#1858)

* Show image for flow not started + take image

* Update

* Adding new images

* .

* Avoid multiple Access-Control-Allow-Origin * (#1859)

* Avoid multiple Access-Control-Allow-Origin *

* Adapt loglevel to debug

* Update build.yaml

* .

* New state "initialization (delayed)", renaming

* Overview: Renamed "Status" + switched position

* Improve data logging on errors (#1839)

* use error level for log if "Rate to High" or "Negative Rate"

* remove redundant data logging

* .

* .

* update time also in case of an error

* move calculation of difference to the top as discussed in PR 1839

Co-authored-by: CaCO3 <caco@ruinelli.ch>

* Heap tracing (#1861)

* Update sdkconfig.esp32cam-dev-task-analysis.defaults

* Update defines.h

* Update platformio.ini

* Update main.cpp

* Update defines.h

* Update ClassFlowCNNGeneral.cpp

* Update platformio.ini

* disable HIMEM (external > 4mb ram) not used (#1864)

#force disable HIMEM as not used in default config, can be enabled with [env:esp32cam-dev-himem]
#free 256kb of internal memory :
#I (2112) esp_himem: Initialized. Using last 8 32KB address blocks for bank switching on 4352 KB of physical memory.
CONFIG_SPIRAM_BANKSWITCH_ENABLE=n
#CONFIG_SPIRAM_BANKSWITCH_RESERVE is not set

* Update ota_page.html (#1866)

Fixed the firework to match the actual button text.
Fixed other random typos.

* add AlignmentAlgo=off option (#1867)

* Replace outdated wiki links, wording (#1871)

* Revert "add AlignmentAlgo=off option (#1867)" (#1876)

This reverts commit 3de4cc7c56.

* fixed typo (#1881)

Co-authored-by: CaCO3 <caco@ruinelli.ch>

* Show WIFI signal text labels / Log RSSI value to logfile (#1877)

* Overview: WIFI RSSI strength text labels

* Log RSSI value (debug level)

* Typo

* Update config.ini (#1880)

* Update Changelog.md for  release (#1892)

Co-authored-by: github-actions <github-actions@github.com>

* Update Changelog.md

* Remove newline in version (#1891)

* remove newline in version

* .

* .

Co-authored-by: CaCO3 <caco@ruinelli.ch>

Co-authored-by: CaCO3 <caco@ruinelli.ch>
Co-authored-by: CaCO3 <caco3@ruinelli.ch>
Co-authored-by: Nicolas Liaudat <nliaudat@users.noreply.github.com>
Co-authored-by: AngryApostrophe <89547888+AngryApostrophe@users.noreply.github.com>
Co-authored-by: github-actions <github-actions@github.com>

* restructure manual setup zip (#1897)

* Update build.yaml

* Update build.yaml

* Update build.yaml

* fix typos and wording on config page (#1898)

* Update label-commenter-config.yml

* Update label-commenter-config.yml

* remove external Web UI dependencies (#1896)

Co-authored-by: CaCO3 <caco@ruinelli.ch>

* Remove excessive whitespaces and newlines in json (#1904)

* .

* .

* .

* .

* .

* remove newlines in json as it is not needed

* .

Co-authored-by: CaCO3 <caco@ruinelli.ch>

* REST handler CPU temp / RSSI: Remove units (#1908)

* REST CPU temp: escape special character

* REST CPUTemp+RSSI: remove units, output as int

* REST handler sysinfo: CPU tempature as integer

* Update Changelog.md (#1893)

* Update Changelog.md

* Update Changelog.md

* Update Changelog.md

* Update Changelog.md

* Update Index & Index.html

* Move Update description to online docu

* Update index.html

* Update Changelog.md

* Update Changelog.md

---------

Co-authored-by: jomjol <30766535+jomjol@users.noreply.github.com>

* Update Changelog.md

---------

Co-authored-by: parhedberg <par.hedberg@gmail.com>
Co-authored-by: Pär Hedberg <par.hedberg@nordicmedtest.se>
Co-authored-by: jomjol <30766535+jomjol@users.noreply.github.com>
Co-authored-by: Christopher Fenner <9592452+CFenner@users.noreply.github.com>
Co-authored-by: CaCO3 <caco@ruinelli.ch>
Co-authored-by: Frank Haverland <fspapaping@googlemail.com>
Co-authored-by: github-actions <github-actions@github.com>
Co-authored-by: Ralf Rachinger <git@ralfrachinger.de>
Co-authored-by: Nicolas Liaudat <nliaudat@users.noreply.github.com>
Co-authored-by: Slider0007 <115730895+Slider0007@users.noreply.github.com>
Co-authored-by: smartboart <38385805+smartboart@users.noreply.github.com>
Co-authored-by: AngryApostrophe <89547888+AngryApostrophe@users.noreply.github.com>
Co-authored-by: Dave <43378003+dkneisz@users.noreply.github.com>
2023-01-27 21:25:58 +01:00
github-actions
0e2ab869cb Update Changelog.md for release 2022-12-19 20:48:23 +00:00
jomjol
04f2f23931 Update Changelog.md 2022-12-19 21:39:45 +01:00
jomjol
c6cfe73e23 Update ClassFlowPostProcessing.cpp 2022-12-19 21:23:25 +01:00
jomjol
914cfceedf Update ClassFlowPostProcessing.cpp 2022-12-19 20:59:01 +01:00
CaCO3
f1a836a407 Merge for next Bugfix Release (#1616)
* Fix for securing wlan.ini (#1509)

* Fix for securing wlan.ini

* Fixing error with ' instead of "

* Changing to errorcode 403

* maybe strcmp instead of regular ==

Co-authored-by: Pär Hedberg <par.hedberg@nordicmedtest.se>

* Update Web-Installer

* solves #1530 (#1531)

* Refactor JSON (#1518)

* use correct log level

* corrected logging

* typo

* refactored JSON generagion: removed unused parameters, consolidated into singel function, added "pre"

* Wrapped 'rate' into double quotes, like all other JSON values

Co-authored-by: CaCO3 <caco@ruinelli.ch>

* Various corrections (#1519)

* use correct log level

* corrected logging

* typo

* add release to webinstaller

* changed logs, added INFO log of raw, value, error

* .

Co-authored-by: CaCO3 <caco@ruinelli.ch>

* Prevent auto restart on cam framebuffer init error (#1522)

* use correct log level

* revert autorestart on camera framebuffer init error

* .

Co-authored-by: CaCO3 <caco@ruinelli.ch>

* #1524 - ensure the recognized digit is less than 10 (#1525)

* fix kernel panic (vector out of range) in getReadoutRawString

* fix key of caches

* fix key of caches

* fix key caches

* fix cache keys

* fix cache keys

* move set variables to top

* debug

* fix key

* testing

* try fix changelog

* test

* Update Changelog.md for  release

* Revert "Update Changelog.md for  release"

This reverts commit 4f51ec7962.

* remove testing

* fix release creation

* testing

* Update Changelog.md for  release

* test

* Revert "Merge branch 'master' of https://github.com/haverland/AI-on-the-edge-device"

This reverts commit f68695a4c0, reversing
changes made to a096cf7182.

* Revert "test"

This reverts commit a096cf7182.

* revert testing

* #1524 - ensure the result of ZeigerEvalHybridNeu is <10

* Fix late digit transition #1503

Co-authored-by: github-actions <github-actions@github.com>

* fix frozen time in datafile on error (#1534)

Co-authored-by: CaCO3 <caco@ruinelli.ch>

* log NTP server name (#1497)

* log NTP server name

* .

* .

* replace calls to /wasserzaehler.html with calls to /value (#1469)

Co-authored-by: CaCO3 <caco@ruinelli.ch>

* Fix cookie usage, use correct http response codes, add 404 page (#1495)

* replaced some HTTP response code with better matching codes

* add custom 404 page, add log entry for debugging

* fix cookie

* replace non-necessary whitespace

* .

Co-authored-by: CaCO3 <caco@ruinelli.ch>

* Don't autofail if NTP server can't be reached during initalization (#1498)

This fixes an issue with a restricted network without internet access,
where the hardcoded ntp server can't be reached and thus the esp resets,
as it's not able to finish initalization.

* Update Changelog.md

* Update Changelog.md for  release

* Fix for securing wlan.ini (#1509)

* Fix for securing wlan.ini

* Fixing error with ' instead of "

* Changing to errorcode 403

* maybe strcmp instead of regular ==

Co-authored-by: Pär Hedberg <par.hedberg@nordicmedtest.se>

* Update Web-Installer

* solves #1530 (#1531)

* Refactor JSON (#1518)

* use correct log level

* corrected logging

* typo

* refactored JSON generagion: removed unused parameters, consolidated into singel function, added "pre"

* Wrapped 'rate' into double quotes, like all other JSON values

Co-authored-by: CaCO3 <caco@ruinelli.ch>

* Various corrections (#1519)

* use correct log level

* corrected logging

* typo

* add release to webinstaller

* changed logs, added INFO log of raw, value, error

* .

Co-authored-by: CaCO3 <caco@ruinelli.ch>

* Prevent auto restart on cam framebuffer init error (#1522)

* use correct log level

* revert autorestart on camera framebuffer init error

* .

Co-authored-by: CaCO3 <caco@ruinelli.ch>

* #1524 - ensure the recognized digit is less than 10 (#1525)

* fix kernel panic (vector out of range) in getReadoutRawString

* fix key of caches

* fix key of caches

* fix key caches

* fix cache keys

* fix cache keys

* move set variables to top

* debug

* fix key

* testing

* try fix changelog

* test

* Update Changelog.md for  release

* Revert "Update Changelog.md for  release"

This reverts commit 4f51ec7962.

* remove testing

* fix release creation

* testing

* Update Changelog.md for  release

* test

* Revert "Merge branch 'master' of https://github.com/haverland/AI-on-the-edge-device"

This reverts commit f68695a4c0, reversing
changes made to a096cf7182.

* Revert "test"

This reverts commit a096cf7182.

* revert testing

* #1524 - ensure the result of ZeigerEvalHybridNeu is <10

* Fix late digit transition #1503

Co-authored-by: github-actions <github-actions@github.com>

* only use sntp_getservername() after init sntp

* set default NTP server on dnew installations

Co-authored-by: CaCO3 <caco@ruinelli.ch>
Co-authored-by: Ralf Rachinger <git@ralfrachinger.de>
Co-authored-by: jomjol <30766535+jomjol@users.noreply.github.com>
Co-authored-by: github-actions <github-actions@github.com>
Co-authored-by: parhedberg <par.hedberg@gmail.com>
Co-authored-by: Pär Hedberg <par.hedberg@nordicmedtest.se>
Co-authored-by: Christopher Fenner <9592452+CFenner@users.noreply.github.com>
Co-authored-by: Frank Haverland <fspapaping@googlemail.com>

* Renamed variables and added debug log (#1537)

* add debug logs

* renamed variables

* renamed TAGs, added flow status logging

* .

* .

Co-authored-by: CaCO3 <caco@ruinelli.ch>

* replaced printf usage in LogFile.WriteToFile()

* ENABLE_MQTT c++ macro definition (#1546)

* macro

* 2

* 2

* delete jomjol_mqtt from CMakeLists

* mqtt macro

* final

* ENABLE_INFLUXDB c++ macro definition (#1547)

* macro

* 2

* 2

* delete jomjol_mqtt from CMakeLists

* mqtt macro

* final

* ENABLE_INFLUXDB c++ macro definition

* Update Changelog.md

* Update Changelog.md

* Rearange task to CPU (http, camera, mqtt) (#1557)

* Streamlined MQTT interlock when not activated & interlock MQTT when WIFI is not connected (#1556)

* streamlined mqtt interlock when disabled

* Disconnect mqtt client before reboot

* Interlock MQTT with WIFI

* Update

* loglevel to DEBUG

* Update

* mqtt msg id incremental

* new ENABLE_MQTT includes

* Loglevel to DEBUG

* Loglevel

* Update interface_mqtt.cpp

* show uptime on overview page, moved labels from firmware to Web UI (#1543)

* show uptime on overview page, moved labels from firmware to Web UI

* show uptime on info page

* also use formated time in log

Co-authored-by: CaCO3 <caco@ruinelli.ch>

* Continue boot on bad PSRAM (#1558)

* add sensor status, show special index/setup page in case of a critical error

* continue booting on PSRAM error

* Update main.cpp

added log messages

* init PSRAM and add more log messages

* cleanup of init checks

* .

* .

* .

Co-authored-by: CaCO3 <caco@ruinelli.ch>

* add sensor status, show special index/setup page in case of a critical error (#1560)

* add sensor status, show special index/setup page in case of a critical error

* Added Reboot

* .

* added more buttons

Co-authored-by: CaCO3 <caco@ruinelli.ch>
Co-authored-by: jomjol <30766535+jomjol@users.noreply.github.com>

* Update Webinstaller to v13.0.7

* remove  html-from-11.3.1 in release (#1565)

* fix kernel panic (vector out of range) in getReadoutRawString

* fix key of caches

* fix key of caches

* fix key caches

* fix cache keys

* fix cache keys

* move set variables to top

* debug

* fix key

* testing

* try fix changelog

* test

* Update Changelog.md for  release

* Revert "Update Changelog.md for  release"

This reverts commit 4f51ec7962.

* remove testing

* fix release creation

* testing

* Update Changelog.md for  release

* test

* Revert "Merge branch 'master' of https://github.com/haverland/AI-on-the-edge-device"

This reverts commit f68695a4c0, reversing
changes made to a096cf7182.

* Revert "test"

This reverts commit a096cf7182.

* revert testing

* #1524 - ensure the result of ZeigerEvalHybridNeu is <10

* Fix late digit transition #1503

* only initial_esp32_setup and update.zip as artefacts

* remove unneeded cache

* rename step ota-v2 to ota

* rename ota-v2 to ota

Co-authored-by: github-actions <github-actions@github.com>

* make the sidebar on the overviw page wider and show the round counter (#1570)

Co-authored-by: CaCO3 <caco@ruinelli.ch>

* Create reply-bot.yml

* Update ClassFlowPostProcessing.cpp

* Add bot (#1581)

* Update reply-bot.yml

* Create label-commenter-config.yml

* added missing html change

* extended instructions (#1583)

Co-authored-by: CaCO3 <caco@ruinelli.ch>

* Fix Rate Problem

* removed redundant "Status:"

* Bugfix Double Extract ZIP-Files

* Update FeatureRequest.md (#1591)

in case of position change between the measurments set this state to true, if there is no change set it back to false.
In a defined time window this movement can lead into an alarm state / water leak..
haveing this state in the mqtt broker can trigger functions like closing the ater pipe walve and so on...

* Update manifest.json

* Delete .gitignore

* Delete .gitmodules

* Delete firmware.bin

* Add files via upload

* Block REST API calls till resource is ready (#1609)

* Block REST API call till ressource is ready

* Update

* Update

* Update

* replace relative include of gethost.js with absolute one. This is needed as that file gets incuded on dynamically generated content which can be on different path levels (#1610)

Co-authored-by: CaCO3 <caco@ruinelli.ch>

* esp_spiram.h has been replaced by esp32/spiram.h (#1605)

* esp_spiram.h has been replaced by esp32/spiram.h

* Preparations for next Bugfix Release (#1615)

* Merge branch 'rolling' (#1559)

* Fix for securing wlan.ini (#1509)

* Fix for securing wlan.ini

* Fixing error with ' instead of "

* Changing to errorcode 403

* maybe strcmp instead of regular ==

Co-authored-by: Pär Hedberg <par.hedberg@nordicmedtest.se>

* Update Web-Installer

* solves #1530 (#1531)

* Refactor JSON (#1518)

* use correct log level

* corrected logging

* typo

* refactored JSON generagion: removed unused parameters, consolidated into singel function, added "pre"

* Wrapped 'rate' into double quotes, like all other JSON values

Co-authored-by: CaCO3 <caco@ruinelli.ch>

* Various corrections (#1519)

* use correct log level

* corrected logging

* typo

* add release to webinstaller

* changed logs, added INFO log of raw, value, error

* .

Co-authored-by: CaCO3 <caco@ruinelli.ch>

* Prevent auto restart on cam framebuffer init error (#1522)

* use correct log level

* revert autorestart on camera framebuffer init error

* .

Co-authored-by: CaCO3 <caco@ruinelli.ch>

* #1524 - ensure the recognized digit is less than 10 (#1525)

* fix kernel panic (vector out of range) in getReadoutRawString

* fix key of caches

* fix key of caches

* fix key caches

* fix cache keys

* fix cache keys

* move set variables to top

* debug

* fix key

* testing

* try fix changelog

* test

* Update Changelog.md for  release

* Revert "Update Changelog.md for  release"

This reverts commit 4f51ec7962.

* remove testing

* fix release creation

* testing

* Update Changelog.md for  release

* test

* Revert "Merge branch 'master' of https://github.com/haverland/AI-on-the-edge-device"

This reverts commit f68695a4c0, reversing
changes made to a096cf7182.

* Revert "test"

This reverts commit a096cf7182.

* revert testing

* #1524 - ensure the result of ZeigerEvalHybridNeu is <10

* Fix late digit transition #1503

Co-authored-by: github-actions <github-actions@github.com>

* fix frozen time in datafile on error (#1534)

Co-authored-by: CaCO3 <caco@ruinelli.ch>

* log NTP server name (#1497)

* log NTP server name

* .

* .

* replace calls to /wasserzaehler.html with calls to /value (#1469)

Co-authored-by: CaCO3 <caco@ruinelli.ch>

* Fix cookie usage, use correct http response codes, add 404 page (#1495)

* replaced some HTTP response code with better matching codes

* add custom 404 page, add log entry for debugging

* fix cookie

* replace non-necessary whitespace

* .

Co-authored-by: CaCO3 <caco@ruinelli.ch>

* Don't autofail if NTP server can't be reached during initalization (#1498)

This fixes an issue with a restricted network without internet access,
where the hardcoded ntp server can't be reached and thus the esp resets,
as it's not able to finish initalization.

* Update Changelog.md

* Update Changelog.md for  release

* Fix for securing wlan.ini (#1509)

* Fix for securing wlan.ini

* Fixing error with ' instead of "

* Changing to errorcode 403

* maybe strcmp instead of regular ==

Co-authored-by: Pär Hedberg <par.hedberg@nordicmedtest.se>

* Update Web-Installer

* solves #1530 (#1531)

* Refactor JSON (#1518)

* use correct log level

* corrected logging

* typo

* refactored JSON generagion: removed unused parameters, consolidated into singel function, added "pre"

* Wrapped 'rate' into double quotes, like all other JSON values

Co-authored-by: CaCO3 <caco@ruinelli.ch>

* Various corrections (#1519)

* use correct log level

* corrected logging

* typo

* add release to webinstaller

* changed logs, added INFO log of raw, value, error

* .

Co-authored-by: CaCO3 <caco@ruinelli.ch>

* Prevent auto restart on cam framebuffer init error (#1522)

* use correct log level

* revert autorestart on camera framebuffer init error

* .

Co-authored-by: CaCO3 <caco@ruinelli.ch>

* #1524 - ensure the recognized digit is less than 10 (#1525)

* fix kernel panic (vector out of range) in getReadoutRawString

* fix key of caches

* fix key of caches

* fix key caches

* fix cache keys

* fix cache keys

* move set variables to top

* debug

* fix key

* testing

* try fix changelog

* test

* Update Changelog.md for  release

* Revert "Update Changelog.md for  release"

This reverts commit 4f51ec7962.

* remove testing

* fix release creation

* testing

* Update Changelog.md for  release

* test

* Revert "Merge branch 'master' of https://github.com/haverland/AI-on-the-edge-device"

This reverts commit f68695a4c0, reversing
changes made to a096cf7182.

* Revert "test"

This reverts commit a096cf7182.

* revert testing

* #1524 - ensure the result of ZeigerEvalHybridNeu is <10

* Fix late digit transition #1503

Co-authored-by: github-actions <github-actions@github.com>

* only use sntp_getservername() after init sntp

* set default NTP server on dnew installations

Co-authored-by: CaCO3 <caco@ruinelli.ch>
Co-authored-by: Ralf Rachinger <git@ralfrachinger.de>
Co-authored-by: jomjol <30766535+jomjol@users.noreply.github.com>
Co-authored-by: github-actions <github-actions@github.com>
Co-authored-by: parhedberg <par.hedberg@gmail.com>
Co-authored-by: Pär Hedberg <par.hedberg@nordicmedtest.se>
Co-authored-by: Christopher Fenner <9592452+CFenner@users.noreply.github.com>
Co-authored-by: Frank Haverland <fspapaping@googlemail.com>

* Renamed variables and added debug log (#1537)

* add debug logs

* renamed variables

* renamed TAGs, added flow status logging

* .

* .

Co-authored-by: CaCO3 <caco@ruinelli.ch>

* replaced printf usage in LogFile.WriteToFile()

* ENABLE_MQTT c++ macro definition (#1546)

* macro

* 2

* 2

* delete jomjol_mqtt from CMakeLists

* mqtt macro

* final

* ENABLE_INFLUXDB c++ macro definition (#1547)

* macro

* 2

* 2

* delete jomjol_mqtt from CMakeLists

* mqtt macro

* final

* ENABLE_INFLUXDB c++ macro definition

* Update Changelog.md

Co-authored-by: parhedberg <par.hedberg@gmail.com>
Co-authored-by: Pär Hedberg <par.hedberg@nordicmedtest.se>
Co-authored-by: jomjol <30766535+jomjol@users.noreply.github.com>
Co-authored-by: Christopher Fenner <9592452+CFenner@users.noreply.github.com>
Co-authored-by: CaCO3 <caco@ruinelli.ch>
Co-authored-by: Frank Haverland <fspapaping@googlemail.com>
Co-authored-by: github-actions <github-actions@github.com>
Co-authored-by: Ralf Rachinger <git@ralfrachinger.de>
Co-authored-by: Nicolas Liaudat <nliaudat@users.noreply.github.com>

* Update Changelog.md for  release

Co-authored-by: parhedberg <par.hedberg@gmail.com>
Co-authored-by: Pär Hedberg <par.hedberg@nordicmedtest.se>
Co-authored-by: jomjol <30766535+jomjol@users.noreply.github.com>
Co-authored-by: Christopher Fenner <9592452+CFenner@users.noreply.github.com>
Co-authored-by: CaCO3 <caco@ruinelli.ch>
Co-authored-by: Frank Haverland <fspapaping@googlemail.com>
Co-authored-by: github-actions <github-actions@github.com>
Co-authored-by: Ralf Rachinger <git@ralfrachinger.de>
Co-authored-by: Nicolas Liaudat <nliaudat@users.noreply.github.com>

* new model version (#1619)

* fix kernel panic (vector out of range) in getReadoutRawString

* fix key of caches

* fix key of caches

* fix key caches

* fix cache keys

* fix cache keys

* move set variables to top

* debug

* fix key

* testing

* try fix changelog

* test

* Update Changelog.md for  release

* Revert "Update Changelog.md for  release"

This reverts commit 4f51ec7962.

* remove testing

* fix release creation

* testing

* Update Changelog.md for  release

* test

* Revert "Merge branch 'master' of https://github.com/haverland/AI-on-the-edge-device"

This reverts commit f68695a4c0, reversing
changes made to a096cf7182.

* Revert "test"

This reverts commit a096cf7182.

* revert testing

* #1524 - ensure the result of ZeigerEvalHybridNeu is <10

* Fix late digit transition #1503

* only initial_esp32_setup and update.zip as artefacts

* remove unneeded cache

* rename step ota-v2 to ota

* rename ota-v2 to ota

* new models

- ana-class100 v1.5.4
- ana-cont-11.0.4
- dig-class100 v1.5.0

Co-authored-by: github-actions <github-actions@github.com>

* Update Changelog.md (#1630)

* Correct RenameNumber

* Update Changelog.md

* Fix reloading of data file (#1635)

* Update data.html

* fixed

* show link to graph

Co-authored-by: CaCO3 <caco@ruinelli.ch>

Co-authored-by: parhedberg <par.hedberg@gmail.com>
Co-authored-by: Pär Hedberg <par.hedberg@nordicmedtest.se>
Co-authored-by: jomjol <30766535+jomjol@users.noreply.github.com>
Co-authored-by: Christopher Fenner <9592452+CFenner@users.noreply.github.com>
Co-authored-by: CaCO3 <caco@ruinelli.ch>
Co-authored-by: Frank Haverland <fspapaping@googlemail.com>
Co-authored-by: github-actions <github-actions@github.com>
Co-authored-by: Ralf Rachinger <git@ralfrachinger.de>
Co-authored-by: Nicolas Liaudat <nliaudat@users.noreply.github.com>
Co-authored-by: Slider0007 <115730895+Slider0007@users.noreply.github.com>
Co-authored-by: smartboart <38385805+smartboart@users.noreply.github.com>
2022-12-19 20:31:44 +01:00
github-actions
55f78dce6d Update Changelog.md for release 2022-12-11 22:44:08 +00:00
CaCO3
304b9e0c32 Merge branch 'rolling' (#1559)
* Fix for securing wlan.ini (#1509)

* Fix for securing wlan.ini

* Fixing error with ' instead of "

* Changing to errorcode 403

* maybe strcmp instead of regular ==

Co-authored-by: Pär Hedberg <par.hedberg@nordicmedtest.se>

* Update Web-Installer

* solves #1530 (#1531)

* Refactor JSON (#1518)

* use correct log level

* corrected logging

* typo

* refactored JSON generagion: removed unused parameters, consolidated into singel function, added "pre"

* Wrapped 'rate' into double quotes, like all other JSON values

Co-authored-by: CaCO3 <caco@ruinelli.ch>

* Various corrections (#1519)

* use correct log level

* corrected logging

* typo

* add release to webinstaller

* changed logs, added INFO log of raw, value, error

* .

Co-authored-by: CaCO3 <caco@ruinelli.ch>

* Prevent auto restart on cam framebuffer init error (#1522)

* use correct log level

* revert autorestart on camera framebuffer init error

* .

Co-authored-by: CaCO3 <caco@ruinelli.ch>

* #1524 - ensure the recognized digit is less than 10 (#1525)

* fix kernel panic (vector out of range) in getReadoutRawString

* fix key of caches

* fix key of caches

* fix key caches

* fix cache keys

* fix cache keys

* move set variables to top

* debug

* fix key

* testing

* try fix changelog

* test

* Update Changelog.md for  release

* Revert "Update Changelog.md for  release"

This reverts commit 4f51ec7962.

* remove testing

* fix release creation

* testing

* Update Changelog.md for  release

* test

* Revert "Merge branch 'master' of https://github.com/haverland/AI-on-the-edge-device"

This reverts commit f68695a4c0, reversing
changes made to a096cf7182.

* Revert "test"

This reverts commit a096cf7182.

* revert testing

* #1524 - ensure the result of ZeigerEvalHybridNeu is <10

* Fix late digit transition #1503

Co-authored-by: github-actions <github-actions@github.com>

* fix frozen time in datafile on error (#1534)

Co-authored-by: CaCO3 <caco@ruinelli.ch>

* log NTP server name (#1497)

* log NTP server name

* .

* .

* replace calls to /wasserzaehler.html with calls to /value (#1469)

Co-authored-by: CaCO3 <caco@ruinelli.ch>

* Fix cookie usage, use correct http response codes, add 404 page (#1495)

* replaced some HTTP response code with better matching codes

* add custom 404 page, add log entry for debugging

* fix cookie

* replace non-necessary whitespace

* .

Co-authored-by: CaCO3 <caco@ruinelli.ch>

* Don't autofail if NTP server can't be reached during initalization (#1498)

This fixes an issue with a restricted network without internet access,
where the hardcoded ntp server can't be reached and thus the esp resets,
as it's not able to finish initalization.

* Update Changelog.md

* Update Changelog.md for  release

* Fix for securing wlan.ini (#1509)

* Fix for securing wlan.ini

* Fixing error with ' instead of "

* Changing to errorcode 403

* maybe strcmp instead of regular ==

Co-authored-by: Pär Hedberg <par.hedberg@nordicmedtest.se>

* Update Web-Installer

* solves #1530 (#1531)

* Refactor JSON (#1518)

* use correct log level

* corrected logging

* typo

* refactored JSON generagion: removed unused parameters, consolidated into singel function, added "pre"

* Wrapped 'rate' into double quotes, like all other JSON values

Co-authored-by: CaCO3 <caco@ruinelli.ch>

* Various corrections (#1519)

* use correct log level

* corrected logging

* typo

* add release to webinstaller

* changed logs, added INFO log of raw, value, error

* .

Co-authored-by: CaCO3 <caco@ruinelli.ch>

* Prevent auto restart on cam framebuffer init error (#1522)

* use correct log level

* revert autorestart on camera framebuffer init error

* .

Co-authored-by: CaCO3 <caco@ruinelli.ch>

* #1524 - ensure the recognized digit is less than 10 (#1525)

* fix kernel panic (vector out of range) in getReadoutRawString

* fix key of caches

* fix key of caches

* fix key caches

* fix cache keys

* fix cache keys

* move set variables to top

* debug

* fix key

* testing

* try fix changelog

* test

* Update Changelog.md for  release

* Revert "Update Changelog.md for  release"

This reverts commit 4f51ec7962.

* remove testing

* fix release creation

* testing

* Update Changelog.md for  release

* test

* Revert "Merge branch 'master' of https://github.com/haverland/AI-on-the-edge-device"

This reverts commit f68695a4c0, reversing
changes made to a096cf7182.

* Revert "test"

This reverts commit a096cf7182.

* revert testing

* #1524 - ensure the result of ZeigerEvalHybridNeu is <10

* Fix late digit transition #1503

Co-authored-by: github-actions <github-actions@github.com>

* only use sntp_getservername() after init sntp

* set default NTP server on dnew installations

Co-authored-by: CaCO3 <caco@ruinelli.ch>
Co-authored-by: Ralf Rachinger <git@ralfrachinger.de>
Co-authored-by: jomjol <30766535+jomjol@users.noreply.github.com>
Co-authored-by: github-actions <github-actions@github.com>
Co-authored-by: parhedberg <par.hedberg@gmail.com>
Co-authored-by: Pär Hedberg <par.hedberg@nordicmedtest.se>
Co-authored-by: Christopher Fenner <9592452+CFenner@users.noreply.github.com>
Co-authored-by: Frank Haverland <fspapaping@googlemail.com>

* Renamed variables and added debug log (#1537)

* add debug logs

* renamed variables

* renamed TAGs, added flow status logging

* .

* .

Co-authored-by: CaCO3 <caco@ruinelli.ch>

* replaced printf usage in LogFile.WriteToFile()

* ENABLE_MQTT c++ macro definition (#1546)

* macro

* 2

* 2

* delete jomjol_mqtt from CMakeLists

* mqtt macro

* final

* ENABLE_INFLUXDB c++ macro definition (#1547)

* macro

* 2

* 2

* delete jomjol_mqtt from CMakeLists

* mqtt macro

* final

* ENABLE_INFLUXDB c++ macro definition

* Update Changelog.md

Co-authored-by: parhedberg <par.hedberg@gmail.com>
Co-authored-by: Pär Hedberg <par.hedberg@nordicmedtest.se>
Co-authored-by: jomjol <30766535+jomjol@users.noreply.github.com>
Co-authored-by: Christopher Fenner <9592452+CFenner@users.noreply.github.com>
Co-authored-by: CaCO3 <caco@ruinelli.ch>
Co-authored-by: Frank Haverland <fspapaping@googlemail.com>
Co-authored-by: github-actions <github-actions@github.com>
Co-authored-by: Ralf Rachinger <git@ralfrachinger.de>
Co-authored-by: Nicolas Liaudat <nliaudat@users.noreply.github.com>
2022-12-11 23:34:38 +01:00
github-actions
f4d086508d Update Changelog.md for release 2022-12-06 19:42:16 +00:00
jomjol
e23c89ae57 Update Changelog.md 2022-12-06 20:32:48 +01:00
Ralf Rachinger
53a764abc8 Don't autofail if NTP server can't be reached during initalization (#1498)
This fixes an issue with a restricted network without internet access,
where the hardcoded ntp server can't be reached and thus the esp resets,
as it's not able to finish initalization.
2022-12-06 07:00:43 +01:00
CaCO3
4f07c88769 Fix cookie usage, use correct http response codes, add 404 page (#1495)
* replaced some HTTP response code with better matching codes

* add custom 404 page, add log entry for debugging

* fix cookie

* replace non-necessary whitespace

* .

Co-authored-by: CaCO3 <caco@ruinelli.ch>
2022-12-06 06:53:05 +01:00
CaCO3
fa406d8989 replace calls to /wasserzaehler.html with calls to /value (#1469)
Co-authored-by: CaCO3 <caco@ruinelli.ch>
2022-12-06 06:52:25 +01:00
parhedberg
1ca54f39f8 Using named cookies to get a correct redirect (#1492)
* Using named cookies

* Prevent from deleting wlan.ini file

* Missed "

* Revert "Prevent from deleting wlan.ini file"

This reverts commit 901b6998b6.

Co-authored-by: Pär Hedberg <par.hedberg@nordicmedtest.se>
2022-12-05 20:43:06 +01:00
CaCO3
5867e90f69 Extend mqtt json (#1489)
* add whitespaces in JSON in MQTT

* re-added pre-value

Co-authored-by: CaCO3 <caco@ruinelli.ch>
2022-12-05 18:44:43 +01:00
CaCO3
e87b91f6eb MQTT improvements (#1487)
* removed no longer used code

* updated logs

* increased heap memory. this most likely was the reason that the MQTT init failed, see https://github.com/jomjol/AI-on-the-edge-device/issues/1455#issuecomment-1336450501

Co-authored-by: CaCO3 <caco@ruinelli.ch>
2022-12-05 06:55:08 +01:00
CaCO3
4b52e61755 De-init camera on startup. This solves init errors in cause it was already initialized in a prevous run (#1486)
Co-authored-by: CaCO3 <caco@ruinelli.ch>
2022-12-05 06:53:48 +01:00
github-actions
eb48212630 Update Changelog.md for release 2022-12-04 14:58:57 +00:00
jomjol
961662f483 Merge branch 'rolling' 2022-12-04 15:48:18 +01:00
jomjol
306b1a75a5 Merge branch 'rolling' of https://github.com/jomjol/AI-on-the-edge-device into rolling 2022-12-04 15:47:46 +01:00
jomjol
7350864150 QuickFix MQTT Reboot 2022-12-04 15:47:38 +01:00
CaCO3
16d0758ea3 remove redundant log text ("5 minutes delay" gets loged further down already. (#1480)
Co-authored-by: CaCO3 <caco@ruinelli.ch>
2022-12-04 15:43:44 +01:00
jomjol
877a1b14e5 Merge branch 'rolling' of https://github.com/jomjol/AI-on-the-edge-device into rolling 2022-12-04 15:12:25 +01:00
jomjol
a122b37c81 Quick Fix for MQTT Init Problem 2022-12-04 15:12:20 +01:00
CaCO3
ad137b329b compare only the first 7 characters of the hashes (#1472)
Co-authored-by: CaCO3 <caco@ruinelli.ch>
2022-12-03 22:28:22 +01:00
Slider0007
85905a7045 Improve MQTT connection handling (#1462)
* modify mqtt init at startup + after disconnection

* mqtt_init only when not initialized

* Minor udapte

* Apply suggestions from code review

Co-authored-by: CaCO3 <caco3@ruinelli.ch>

* Correct typo

Co-authored-by: CaCO3 <caco3@ruinelli.ch>
2022-12-03 19:10:44 +01:00
github-actions
9847f95c93 Update Changelog.md for release 2022-12-02 21:29:30 +00:00
jomjol
e9e13588f6 Merge branch 'rolling' 2022-12-02 22:20:32 +01:00
jomjol
6c8a45f2dc Update to espressif v5.2.0 2022-12-02 22:05:00 +01:00
CaCO3
e7d28f9bde Update Changelog.md 2022-12-02 18:21:08 +01:00
CaCO3
33015351d6 Update Changelog.md (#1444)
* Update Changelog.md

* add latest PR to changelog

* Update Changelog.md
2022-12-02 18:19:53 +01:00
github-actions
0a461b2bd0 Update Changelog.md for release 2022-12-02 16:41:49 +00:00
jomjol
ecf1e78208 Update Changelog.md 2022-12-02 17:30:07 +01:00
Slider0007
a8b9acf170 Disable heap logs by default (#1464)
* disabale heap logs by default

* Cleanup log (INFO->DEBUG)
2022-12-02 17:00:31 +01:00
CaCO3
45a3138d28 write logfile logs earlier, shorten startup banner, add uptime to logfile (#1443)
Co-authored-by: CaCO3 <caco@ruinelli.ch>
2022-12-02 16:59:25 +01:00
CaCO3
7e997889aa add MQTT status topic (#1438) 2022-11-30 20:26:11 +01:00
CaCO3
6c51af7107 Use only commit hash for comparison instead whole string (#1436)
* Use only commit hash for comparison instead whole string

* .
2022-11-30 20:25:34 +01:00
CaCO3
8be7beab9a Add the timezone to the time output fomat (#1435)
* Add the timezone to the time output fomat, see https://github.com/jomjol/AI-on-the-edge-device/issues/1428

* use correct device class for timestamp
2022-11-30 20:25:03 +01:00
jomjol
62ec8d76c6 Update LogDownloader 2022-11-29 20:46:37 +01:00
github-actions
7a634797c4 Update Changelog.md for release 2022-11-28 20:11:57 +00:00
Frank Haverland
575d59dad2 fix release creation (#1422)
* fix kernel panic (vector out of range) in getReadoutRawString

* fix key of caches

* fix key of caches

* fix key caches

* fix cache keys

* fix cache keys

* move set variables to top

* debug

* fix key

* testing

* try fix changelog

* test

* Update Changelog.md for  release

* Revert "Update Changelog.md for  release"

This reverts commit 4f51ec7962.

* remove testing

* fix release creation

* testing

* Update Changelog.md for  release

* test

* Revert "Merge branch 'master' of https://github.com/haverland/AI-on-the-edge-device"

This reverts commit f68695a4c0, reversing
changes made to a096cf7182.

* Revert "test"

This reverts commit a096cf7182.

* revert testing

Co-authored-by: github-actions <github-actions@github.com>
2022-11-28 21:02:20 +01:00
CaCO3
524d800a0a Update info page (#1420)
* consolidate info page

* use new REST API

* .

* .

* .

* .

* .

* .

* .

* Make sure after the reboot we go to the overview page

* .

* Update server_main.cpp
2022-11-28 18:51:11 +01:00
jomjol
7b0e6200d6 Update Changelog.md 2022-11-27 19:21:37 +01:00
jomjol
65d011c9aa Merge branch 'rolling' 2022-11-27 18:43:31 +01:00
jomjol
dc3604f144 v13.0.0 2022-11-27 18:39:31 +01:00
CaCO3
1eb2dd4efa Update Changelog.md (#1418) 2022-11-27 17:07:23 +01:00
Frank Haverland
f4d345b902 fix problem with prepare release (#1417)
* fix kernel panic (vector out of range) in getReadoutRawString

* Update

* Revert "Update"

This reverts commit b50be7e825.

* fix key of caches

* fix key of caches

* fix key caches

* fix cache keys

* fix cache keys

* move set variables to top

* debug

Co-authored-by: jomjol <30766535+jomjol@users.noreply.github.com>
2022-11-27 17:07:12 +01:00
jomjol
a38837c61b Revert "Update"
This reverts commit b50be7e825.
2022-11-27 09:13:12 +01:00
jomjol
b50be7e825 Update 2022-11-27 09:12:24 +01:00
jomjol
74f45bee28 Update Changelog.md 2022-11-27 09:08:48 +01:00
jomjol
47b3b0c708 Update readconfigparam.js 2022-11-26 07:29:16 +01:00
CaCO3
9c390f3026 make button titles consistent (#1412)
Co-authored-by: CaCO3 <caco@ruinelli.ch>
2022-11-26 07:15:10 +01:00
jomjol
069aac5723 Downwards compatibility for DataLogging 2022-11-25 19:58:15 +01:00
CaCO3
9335cd73d5 Merge branch 'master' into rolling 2022-11-25 16:49:34 +01:00
CaCO3
e90beffb44 resolve release merge conflicts 2022-11-25 16:48:37 +01:00
CaCO3
55a06dbe1d resolve release merge conflicts 2022-11-25 16:47:59 +01:00
CaCO3
ae07159afe resolve release merge conflicts 2022-11-25 16:47:07 +01:00
CaCO3
1fff655ef1 resolve release merge conflicts 2022-11-25 16:46:26 +01:00
CaCO3
3815f9cf0a resolve release merge conflicts 2022-11-25 16:45:02 +01:00
CaCO3
e36490c89e resolve release merge conflicts 2022-11-25 16:37:54 +01:00
CaCO3
d4f02f971f solve release merge conflicts 2022-11-25 16:36:34 +01:00
CaCO3
ec326d9a11 resolve release merge conflicts 2022-11-25 08:32:28 +01:00
CaCO3
6e4df0ef87 Keep iframe page on reload (#1406)
* rename overview page

* reload same page in iframe again after reloading index page

Co-authored-by: CaCO3 <caco@ruinelli.ch>
2022-11-25 07:25:32 +01:00
CaCO3
3aa0411676 Use raw value as prevalue (#1405)
* remove loggng password

* use raw value of selected number as default value

* fix log message

Co-authored-by: CaCO3 <caco@ruinelli.ch>
2022-11-25 07:24:23 +01:00
CaCO3
9f20c126be Catch empty ref images (#1397)
* slow down constant reboots caused by the flow. With this, after a restart due to exception/panic the first round gets delayed by 5 minutes

* catch empty reference images

* .

Co-authored-by: CaCO3 <caco@ruinelli.ch>
2022-11-25 07:23:15 +01:00
jomjol
2707e8c9f4 Update tflite 2022-11-24 18:42:31 +01:00
CaCO3
0d467d8ad1 slow down reboot loops (#1396)
* slow down constant reboots caused by the flow. With this, after a restart due to exception/panic the first round gets delayed by 5 minutes

* retry InitCam() if it failed

* restart after 5 minutes if NTP init failed

* .

Co-authored-by: CaCO3 <caco@ruinelli.ch>
2022-11-23 21:52:51 +01:00
Slider0007
66be09c98e Add parameter to disable write data log (#1382) 2022-11-20 17:44:42 +01:00
CaCO3
60e9a427a5 Updated changelog (#1381) 2022-11-20 17:41:23 +01:00
rstephan
f72bdb7c45 Use none chunked transfer for "/json" endpoint (#1379) 2022-11-20 17:40:55 +01:00
jomjol
a53188e697 Update tflite, Readme.md 2022-11-18 21:46:22 +01:00
Slider0007
0dd63b9b7a Fix file retention, remove/correct logs (#1377) 2022-11-18 19:23:18 +01:00
CaCO3
513e300676 fix version check (#1374)
Co-authored-by: CaCO3 <caco@ruinelli.ch>
2022-11-18 06:54:51 +01:00
CaCO3
dd28859a9f Updated setup mode (#1370)
* update config

* delete unused file

* added notes about not-needed reboot, added links to wiki and discussions

Co-authored-by: CaCO3 <caco@ruinelli.ch>
2022-11-18 06:54:19 +01:00
CaCO3
ecc43edbba Improve NTP (#1364)
* checking NTP status on every round and restart NTP client if we still are in 1970

* .

* .

* .

Co-authored-by: CaCO3 <caco@ruinelli.ch>
2022-11-17 19:01:24 +01:00
CaCO3
bf8ab423e3 add link to file server (#1367) 2022-11-17 18:25:02 +01:00
CaCO3
8116a546b5 Update bug_report.yml 2022-11-17 18:07:40 +01:00
CaCO3
5c512367e2 Update bug_report.yml (#1365)
* Update bug_report.yml

* Update x_plain.yaml

* Update x_plain.yaml
2022-11-17 18:04:01 +01:00
CaCO3
e15ea561bc Enhance ROI editing (#1357)
* add labels to ROIs

* .

* fix naming check

* .

* .

Co-authored-by: CaCO3 <caco@ruinelli.ch>
2022-11-16 18:32:53 +01:00
CaCO3
9e4332314a Update training.yaml 2022-11-16 07:54:04 +01:00
CaCO3
880d9eae20 replace division by a multiplication (#1352)
Co-authored-by: CaCO3 <caco@ruinelli.ch>
2022-11-16 07:50:59 +01:00
SkylightXD
72fcd791db Update README.md (#1349)
Add gas meter case
2022-11-15 18:39:48 +01:00
CaCO3
39960b15ed Check web UI version and show alert on mismatch with Firmware version (#1329)
* SHhw Web UI version and compare it with the firmware. If it does not match, show a warning in the log

* compare version on Web UI loading and show alert on mismatch

* restructured info page
2022-11-14 19:58:22 +01:00
CaCO3
395b9a4c5b Lock sizes and keep X spaces equidistant (#1339)
* keep y, dx and dy identical

* added alert

* .

* add button to make X soaces equidistant

* .

* .

* add checkbox to synchronize dx and dy
2022-11-13 08:25:49 +01:00
George Ruinelli
5a2753a50b Updated issue templates 2022-11-12 16:58:02 +01:00
George Ruinelli
57c5c19cca Copy issue templated from master to rolling 2022-11-12 16:51:16 +01:00
CaCO3
c64ed36fa4 Support white space and equal in passwords (#1327)
* Updated the web Installer page, removed all redudnant files in the docs folder, updated the main README

* .

* consolidate the 2 identical ZerlegeZeile() function and move it to Helper.cpp and add workaround for whitespace and equal sign in password fields

* remove redundant code in HelperZerlegeZeile()

* Updated the web Installer page, removed all redudnant files in the docs folder, updated the main README

* .

* consolidate the 2 identical ZerlegeZeile() function and move it to Helper.cpp and add workaround for whitespace and equal sign in password fields

* remove redundant code in HelperZerlegeZeile()
2022-11-11 19:11:53 +01:00
CaCO3
754981c67f Update edit_config_param.html (#1323) 2022-11-11 19:09:59 +01:00
CaCO3
5c22986e2e fix log format 2022-11-10 23:49:10 +01:00
CaCO3
1746920f61 fix image url (#1322)
* Update index.html

* Update index.html
2022-11-10 20:59:52 +01:00
CaCO3
d33380d2a0 Update web installer (#1312)
* Updated the web Installer page, removed all redudnant files in the docs folder, updated the main README

* .
2022-11-10 18:53:06 +01:00
CaCO3
889ed9e6be Disable the Idle Task Watchdog resp. the Task Watchdog in general because we do not use it ATM. (#1303) 2022-11-09 18:25:42 +01:00
CaCO3
2b0e0f7d4e MQTT improvements (#1302)
* Update server_mqtt.cpp

* Update server_mqtt.cpp

* skipp all MQTT publishing until the next round if an error occures

* improve logging

* only use group for uid and topic if there is more than one number

* .

* .
2022-11-09 18:25:24 +01:00
CaCO3
2314d7ef18 Add missing file content (#1301)
* added file content
2022-11-07 21:53:03 +01:00
CaCO3
bec3a5ee3b Update miniz to 3.0.1 (#1300)
* minor update to 11.0.1 (resp. 3.0.1)

* Updated miniz from 3.0.0 to 3.0.1 and moved it to a separate component.
2022-11-07 21:16:47 +01:00
jomjol
c738a9a4da Improve SetPrevalue 2022-11-07 19:12:36 +01:00
jomjol
e7c8706b1b Update Internal libraries (esp32cam, tflite), Enhance debugging for OTA problems
Update Miniz
2022-11-06 17:41:32 +01:00
jomjol
f725adf5ba Merge branch 'rolling' of https://github.com/jomjol/AI-on-the-edge-device into rolling 2022-11-06 08:19:39 +01:00
jomjol
7bb1b08bdb Extend ROI, Number name check 2022-11-06 08:19:24 +01:00
CaCO3
d1e7ef1fce Add tag to logfile write (#1287)
* HTML: implement data viewer

* Correct CSV error

* Improve OTA

* Use consistent Log TAG syntax, name TAG variable the same in every file.

* .

* .

* .

* .

* .

* Update server_tflite.cpp

* Correct CSV error

* Improve OTA

* Use consistent Log TAG syntax, name TAG variable the same in every file.

* .

* .

* .

* .

* .

* Update server_tflite.cpp

* .

* .

* .

* .

* .

* .

* .

* .

Co-authored-by: jomjol <30766535+jomjol@users.noreply.github.com>
2022-11-06 08:13:53 +01:00
CaCO3
08f7e1275e Added more issue templates (#1291)
* Create training.yaml

* Update training.yaml

* Create plain.yaml

* Rename .github/plain.yaml to .github/ISSUE_TEMPLATE/plain.yaml

* Update plain.yaml

* Update plain.yaml

* Update plain.yaml

* Update bug_report.yml

* Update config.yml

* Create feature.yaml

* Update feature.yaml

* Update feature.yaml

* Update feature.yaml

* Update feature.yaml

* Update bug_report.yml

* Rename plain.yaml to _plain.yaml

* Rename _plain.yaml to x_plain.yaml

* Update bug_report.yml

* Update feature.yaml

* Update training.yaml

* Update config.yml

* Update training.yaml

* Update x_plain.yaml
2022-11-06 08:12:55 +01:00
jomjol
529690ec60 Update readconfigparam.js 2022-11-05 23:42:52 +01:00
jomjol
59431a7eaf OTA update, CSV log, data viewer
OTA update & HTML: implement data viewer

Correct CSV error

Improve OTA

Update data & OTA
2022-11-05 22:44:53 +01:00
jomjol
23b5ffbb92 Merge branch 'rolling' of https://github.com/jomjol/AI-on-the-edge-device into rolling 2022-11-05 19:56:15 +01:00
jomjol
9b8594c040 Change data to csv, harmonize REST API editflow 2022-11-05 19:56:09 +01:00
CaCO3
3e082ed06e Enhance homeassistant discovery (V5) (#1275)
* manual re-creation of #1246

* removed non-working approach to get interval

* postpone the MQTT service start until the ClassFlowControll::ReadParameter() gets called

* Increase the max_uri_handlers to 35 (was 30)

* removed newlines in logs

* added parameter to UI

* Register handler to re-start MQTT Discovery

* fix param
2022-11-05 19:32:58 +01:00
jomjol
22fe50f80a Ensure, that no ',' or '.' is in the ROIs name 2022-11-05 13:56:32 +01:00
jomjol
885cd71b80 Improved OTA (empty firmware directory) 2022-11-05 11:33:26 +01:00
jomjol
8c6805ec7c Update max_uri_handler, improve OTA debugging 2022-11-05 08:08:00 +01:00
CaCO3
1fc0b41fca Cleanup REST API 2 (#1273) 2022-11-04 22:38:18 +01:00
jomjol
7e26744e2e Revert "Revert "System instable""
This reverts commit 1d9ef7e634.
2022-11-04 21:59:22 +01:00
CaCO3
1d9ef7e634 Revert "System instable"
This reverts commit cb84074981339d44266a1a999a7567a722af11f4.

Cleanup REST API (#1255)

* Replaced URIs:
- value.html => value
- statusflow.html => statusflow
- cputemp.html => cputemp
- rssi.html => rssi
- statusflow.html => statusflow

Removed URLs:
 - wasserzaehler.html

* keep legacy API

* .

* .

* .

* .

* .

* .

* updated links

Remove ErrorMessage

Fix various warnings which become fatal with later gcc versons in esp-idf 5.x (#1268)

- we cannot use partial initialisation of structs in C++ files (copied from example C files initially it seems)
- IRAM_ATTR uses a COUNTER, do not use the attribute on the implementation
- provide missing copy implementations for Rgb and Hsv
- one no longer can |= on volatile variables; use = | instead
- fix project and header includes
- avoid redefining BLINK_GPIO
- Remove defined but unused variables
- Fix printf formats
- Add missing case statement (HTTP_EVENT_REDIRECT)
- RMT needs to be updated to new interface (CONFIG_RMT_SUPPRESS_DEPRECATE_WARN is on currently; see https://docs.espressif.com/projects/esp-idf/en/release-v5.0/esp32/api-reference/peripherals/rmt.html)
- Adjust tcpip_adpater_* to esp_netif_*
- Use buffered versions of *ntoa* functions for IPv4 addresses and not a static on the stack (also fixes warnings)
- Whatever I missed

Correct spelling of "Hostname" (#1270)

Correct sdkonfig

Increase max handler due to new handlers

Revert "Cleanup REST API (#1255)"

This reverts commit f3e73ec64a.

Revert "Increase max handler due to new handlers"

This reverts commit cbd63ad4bd.

System instable

Revert "Revert "Cleanup REST API (#1255)""

This reverts commit 2793c761413ffb987ab6a75da372e00e9f2f2cbd.

Co-Authored-By: Bjoern A. Zeeb <patch@zabbadoz.net>
2022-11-04 21:59:01 +01:00
Frank Haverland
1be49a75b1 fix kernel panic (vector out of range) in getReadoutRawString (#1250) 2022-10-31 22:04:34 +01:00
jomjol
b6b7587f0a Update README.md 2022-10-30 22:09:14 +01:00
jomjol
e3017c25a9 Test Installer 2022-10-30 22:02:16 +01:00
jomjol
d914e69e7a Update Webinstaller 2022-10-30 21:57:28 +01:00
jomjol
edf9f11048 Update Webinstaller 2022-10-30 21:54:02 +01:00
jomjol
44afd138c5 Create /docs + installer 2022-10-30 21:48:06 +01:00
CaCO3
d2b93a7110 Enhance UI (#1243)
* Temporarily disable data file writing as it can cause crashs, see https://github.com/jomjol/AI-on-the-edge-device/issues/1225

* removed edit function in graph as we don't need that in a release

* .

* improve log viewer

* replaced logfile enable/disable with enum to select log level. At least errors always will be logged (as before)

* .

* .

* colorize log

* scroll down

* improve log reload
2022-10-30 20:44:13 +01:00
CaCO3
ff726485ba Improve MQTT (#1232)
added shared variable for autointerval to use it as MQTT LWT timeout
2022-10-30 20:08:14 +01:00
jomjol
de46cd899e Merge pull request #1234 from jomjol/add-homeassistant-discovery2
Add homeassistant discovery
2022-10-30 10:58:54 +01:00
jomjol
37263bb239 Update ClassFlowPostProcessing.cpp 2022-10-29 20:20:59 +02:00
CaCO3
d21a38f42f Added parameter to enable/disable Homeassistant Discovery 2022-10-29 18:45:47 +02:00
CaCO3
9b9a7537f1 . 2022-10-29 12:06:20 +02:00
CaCO3
56d8c65008 add maintopic to entity name to get a better entity ID. For some undocumented reason, HA removes the maintopic again in the name, so it looks ok :) 2022-10-29 11:50:19 +02:00
CaCO3
fc24db7d59 truncate log MQTT contents when they are too long and remove all newline characters in logfile writes 2022-10-28 23:42:04 +02:00
CaCO3
0867dcc6da . 2022-10-28 22:58:39 +02:00
CaCO3
b9f57edb92 added separate binary sensor "problem" indicating an error state 2022-10-28 22:53:23 +02:00
CaCO3
7ebbba3cf2 refactoring 2022-10-28 17:50:27 +02:00
CaCO3
5188734c8b added device classes 2022-10-28 17:09:32 +02:00
CaCO3
4e476a75ca changed error topic to a binary sensor, removed meas unit if it has no unit 2022-10-28 16:53:55 +02:00
CaCO3
7a037a3254 adjusted icons 2022-10-28 16:27:00 +02:00
CaCO3
f6b44ac905 renaming 2022-10-28 16:11:09 +02:00
CaCO3
deecc128be added user friendly name, corrected Wifi icon 2022-10-28 16:00:13 +02:00
CaCO3
18f2b5824e Update build.yaml
replace dot as the OTA has issues with it
2022-10-28 00:27:28 +02:00
CaCO3
45084bab70 Merge branch 'rolling' into add-homeassistant-discovery2 2022-10-27 23:43:41 +02:00
CaCO3
6cdbe38717 . 2022-10-27 23:35:48 +02:00
CaCO3
fe0d0c2590 . 2022-10-27 23:16:15 +02:00
CaCO3
44f61c7c91 . 2022-10-27 23:10:39 +02:00
CaCO3
af8b7d6824 . 2022-10-27 22:26:56 +02:00
jomjol
170583f8fe Merge pull request #1233 from haverland/rolling
fix test cases running in stackoverlfow
2022-10-27 22:05:27 +02:00
CaCO3
648a35e4d7 Add HomeAssistant Discovery Topics 2022-10-27 22:02:21 +02:00
jomjol
99849063d9 Merge pull request #1231 from jomjol/improve-logfile-logging
Improve logging to logfile
2022-10-27 21:56:50 +02:00
Frank Haverland
5b22007a1e changelog update 2022-10-27 21:18:09 +02:00
Frank Haverland
80cf89c9d5 added new version of dig-class100 (new heliowatt images) 2022-10-27 21:02:55 +02:00
Frank Haverland
45d37ea957 fix testcase creation if analog has no pointers 2022-10-27 21:02:22 +02:00
Frank Haverland
f935c38571 fix test cases running in stackoverlfow 2022-10-27 20:14:26 +02:00
CaCO3
bfc7c2b8b7 . 2022-10-27 19:06:47 +02:00
CaCO3
08f90de683 . 2022-10-27 19:05:00 +02:00
CaCO3
32748e3182 . 2022-10-27 13:13:23 +02:00
CaCO3
7a280bc7c6 added callback on connected 2022-10-27 12:18:23 +02:00
CaCO3
f4ae688527 refactored check if logfile is enabled. error messages always get logged now 2022-10-27 10:44:28 +02:00
CaCO3
ca45d0a278 . 2022-10-27 10:03:05 +02:00
CaCO3
8f66fcf2a6 . 2022-10-27 01:12:53 +02:00
CaCO3
30549ac5af refactored MQTT 2022-10-27 01:09:09 +02:00
CaCO3
06ab14a6c9 Merge branch 'improve-mqtt' of https://github.com/jomjol/AI-on-the-edge-device into improve-mqtt 2022-10-26 22:46:08 +02:00
CaCO3
72e3570dc4 . 2022-10-26 22:46:01 +02:00
CaCO3
724169b059 . 2022-10-26 22:46:01 +02:00
CaCO3
6e58f5eebb updated log messages 2022-10-26 22:46:01 +02:00
CaCO3
96b3d7cc2f . 2022-10-26 22:46:01 +02:00
CaCO3
74c9eada47 . 2022-10-26 22:46:01 +02:00
CaCO3
9d65889824 removed \r\n in logs 2022-10-26 22:46:01 +02:00
CaCO3
98451c8fc7 renamed mainerrortopic with lwt, only send it once on connecting, minor fixes and cleanups 2022-10-26 22:46:01 +02:00
CaCO3
6b47eef4cd use unique MQTT client ID. Without this (and multiple running deevices with same ID), they disconnect each other! 2022-10-26 22:46:01 +02:00
CaCO3
158ec65e57 Merge branch 'rolling' of https://github.com/jomjol/AI-on-the-edge-device into rolling 2022-10-26 22:45:50 +02:00
CaCO3
c4bbd7c545 Temporarily disable data file writing as it can cause crashs, see https://github.com/jomjol/AI-on-the-edge-device/issues/1225 (#1228) 2022-10-26 22:44:19 +02:00
CaCO3
cb323eb715 Merge branch 'improve-mqtt' of https://github.com/jomjol/AI-on-the-edge-device into improve-mqtt 2022-10-26 22:40:21 +02:00
CaCO3
1aa23aa14a updated log messages 2022-10-26 22:40:08 +02:00
CaCO3
41abc19a97 . 2022-10-26 22:40:08 +02:00
CaCO3
99e03dde06 . 2022-10-26 22:40:08 +02:00
CaCO3
9d73c5475e removed \r\n in logs 2022-10-26 22:40:08 +02:00
CaCO3
25ae9a045f renamed mainerrortopic with lwt, only send it once on connecting, minor fixes and cleanups 2022-10-26 22:40:08 +02:00
CaCO3
dabe66819d use unique MQTT client ID. Without this (and multiple running deevices with same ID), they disconnect each other! 2022-10-26 22:40:08 +02:00
CaCO3
4ad7b97764 Merge branch 'rolling' of https://github.com/jomjol/AI-on-the-edge-device into rolling 2022-10-26 22:39:49 +02:00
CaCO3
083aeb42ec Update build.yaml (#1229) 2022-10-26 22:37:43 +02:00
CaCO3
a13d1d0692 Temporarily disable data file writing as it can cause crashs, see https://github.com/jomjol/AI-on-the-edge-device/issues/1225 2022-10-26 22:31:34 +02:00
jomjol
c12645ab4d Merge pull request #1227 from haverland/rolling
fix regression tests
2022-10-26 22:13:57 +02:00
Frank Haverland
116c99e55c fix regression tests 2022-10-26 20:10:19 +02:00
CaCO3
43b65d6b2e updated log messages 2022-10-26 11:12:56 +02:00
CaCO3
bc7a0e46b7 . 2022-10-26 10:54:28 +02:00
CaCO3
455962bd94 . 2022-10-26 10:53:24 +02:00
CaCO3
86c515bcb8 removed \r\n in logs 2022-10-26 10:52:06 +02:00
CaCO3
f09067a142 renamed mainerrortopic with lwt, only send it once on connecting, minor fixes and cleanups 2022-10-26 10:34:15 +02:00
CaCO3
8ce24df304 use unique MQTT client ID. Without this (and multiple running deevices with same ID), they disconnect each other! 2022-10-26 10:25:17 +02:00
jomjol
279a59d019 Merge pull request #1223 from jomjol/add-uri-to-get-last-80kB-of-logfile
Add URI to get last 80kBytes of the current logfile
2022-10-26 06:57:01 +02:00
CaCO3
d88e286696 changed to 80 kBytes 2022-10-26 01:14:00 +02:00
CaCO3
d07aa2a72d added a new URI /log to get last 16kBytes of the current logfile 2022-10-26 01:08:56 +02:00
CaCO3
bf30872439 skip multiple action runs on same content 2022-10-25 21:20:50 +02:00
jomjol
12dc4eb460 Updated graphical representation 2022-10-25 20:55:57 +02:00
jomjol
ab67d1ff35 Merge pull request #1220 from jomjol/various-improvements
Various improvements
2022-10-25 20:55:05 +02:00
CaCO3
86809d8bf8 fixed missing parameters 2022-10-25 20:44:15 +02:00
jomjol
85adf70394 Merge branch 'rolling' into various-improvements 2022-10-25 20:06:16 +02:00
jomjol
290e7f3835 Merge pull request #1206 from jomjol/add-log-level-to-logfile2
Add log level to logfile
2022-10-25 20:02:26 +02:00
George Ruinelli
e9e0eed871 . 2022-10-25 14:35:43 +02:00
George Ruinelli
4ab0f632b7 . 2022-10-25 14:29:34 +02:00
George Ruinelli
1a33834b3f . 2022-10-25 14:16:41 +02:00
CaCO3
1d367a58d5 Merge branch 'rolling' into add-log-level-to-logfile2 2022-10-25 14:14:23 +02:00
George Ruinelli
ec4ce66bcc . 2022-10-25 13:49:44 +02:00
George Ruinelli
4a0f5eadc2 . 2022-10-25 13:44:52 +02:00
George Ruinelli
f955f8786b show reset reason, add function to get MAC 2022-10-25 13:43:54 +02:00
George Ruinelli
38f6e49d00 Add USB port to readme 2022-10-25 13:19:26 +02:00
jomjol
4394d832b8 Merge pull request #1218 from jomjol/updated-explanation
Updated explanation for run interval
2022-10-25 06:58:10 +02:00
jomjol
9e68380814 Merge pull request #1219 from haverland/rolling
Fix Github-action on pull requests
2022-10-25 06:55:36 +02:00
Frank Haverland
c8bb95a852 Merge branch 'rolling' of https://github.com/haverland/AI-on-the-edge-device into rolling 2022-10-25 06:19:22 +02:00
Frank Haverland
9c2de84ee4 fix slashes in github.ref_name 2022-10-25 06:18:43 +02:00
Frank Haverland
d4b1c2c883 Merge branch 'jomjol:rolling' into rolling 2022-10-25 05:59:50 +02:00
CaCO3
550d9e1c87 typos 2022-10-24 22:45:36 +02:00
CaCO3
3f687a7233 Update edit_config_param.html 2022-10-24 22:42:44 +02:00
CaCO3
c1369ca0ff Update build.yaml (#1216) 2022-10-24 22:32:26 +02:00
George Ruinelli
76c8bce7b4 . 2022-10-24 21:41:40 +02:00
jomjol
e0ae9b8e4f Extend Graph.html 2022-10-24 21:20:46 +02:00
Frank Haverland
9de573c15e Merge branch 'rolling' of https://github.com/haverland/AI-on-the-edge-device into rolling 2022-10-24 19:37:55 +02:00
jomjol
716c23fed3 Update graph.html to data 2022-10-23 18:59:55 +02:00
jomjol
8e22bd06e9 Update ClassFlowCNNGeneral.cpp 2022-10-23 18:09:05 +02:00
jomjol
b78929745b Improve data logging 2022-10-23 16:12:34 +02:00
jomjol
6986f2186c Extented data logging 2022-10-23 13:50:02 +02:00
jomjol
3743ac18f5 Implement direct data logging 2022-10-23 12:36:09 +02:00
jomjol
13f1d40ca3 Merge branch 'rolling' of https://github.com/jomjol/AI-on-the-edge-device into rolling 2022-10-23 09:39:24 +02:00
jomjol
63f28097bd Update Changelog.md 2022-10-23 09:39:16 +02:00
jomjol
ff7fec1de4 Merge pull request #1208 from Slider0007/Add-sd-card-info+patch
Add SD card info to info.html (recommit incl. fix)
2022-10-23 08:42:02 +02:00
Slider0007
f65b2850a2 correct case sensitivity of include 2022-10-22 23:50:39 +02:00
Slider0007
3a999358b9 correct case sensitivity of include 2022-10-22 23:49:42 +02:00
Slider0007
d3e195df9f Name adjustment 2022-10-22 23:49:33 +02:00
Slider0007
dbf8e634d9 Name adjustment 2022-10-22 23:49:22 +02:00
Slider0007
2b810ca32d Name adjustment 2022-10-22 23:49:09 +02:00
Slider0007
0adfc45d36 Name adjustment 2022-10-22 23:48:55 +02:00
Slider0007
2a54d9b889 Name adjustment 2022-10-22 23:48:43 +02:00
Slider0007
4150c31b98 Add SD Card Info to info.html 2022-10-22 23:48:30 +02:00
Slider0007
803e8f2bff Add SD Card Info to info.html 2022-10-22 23:48:12 +02:00
George Ruinelli
b215345f11 remove unused variable 2022-10-22 21:45:35 +02:00
jomjol
98d35e0412 Revert "Merge pull request #1205 from Slider0007/Add-sdcard-info"
This reverts commit 437e8e4d25, reversing
changes made to 0a2b6b71ca.
2022-10-22 21:44:35 +02:00
jomjol
437e8e4d25 Merge pull request #1205 from Slider0007/Add-sdcard-info
Add sd card infos to info.html
2022-10-22 21:26:17 +02:00
Slider0007
e05085ddf0 Name adjustment 2022-10-22 20:31:17 +02:00
Slider0007
495b5de38c Name adjustment 2022-10-22 20:29:32 +02:00
Slider0007
c2b89dd199 Name adjustment 2022-10-22 20:27:21 +02:00
Slider0007
f15b1e5dfc Name adjustment 2022-10-22 19:35:51 +02:00
Slider0007
e308a1b5d9 Name adjustment 2022-10-22 19:30:37 +02:00
George Ruinelli
1e698440f9 added log level to logfile, adjusted some loglevels 2022-10-22 18:05:08 +02:00
Slider0007
98bf7e5387 Add SD Card Info to info.html 2022-10-22 13:17:02 +02:00
Slider0007
e1f8ac59cb Add SD Card Info to info.html 2022-10-22 13:11:11 +02:00
jomjol
0a2b6b71ca Merge pull request #1202 from jomjol/consolidate-uart-and-logfile-logging
Consolidate uart and logfile logging
2022-10-22 12:36:28 +02:00
jomjol
5daae7b47c Merge pull request #1201 from jomjol/replace-printf-with-esp_log
Replace printf with ESP_LOGD
2022-10-22 12:35:13 +02:00
George Ruinelli
4951fc9b80 removed redundant log entries (some now are DEBUG isntread of INFO or ERROR) 2022-10-21 23:19:36 +02:00
George Ruinelli
0bf8182728 . 2022-10-21 22:55:36 +02:00
George Ruinelli
a512d82793 . 2022-10-21 22:13:13 +02:00
George Ruinelli
4f305a8705 . 2022-10-21 21:33:05 +02:00
George Ruinelli
46daa4cb79 replaced printf with ESP_LOGD 2022-10-21 20:54:38 +02:00
jomjol
485363d7a2 Update FeatureRequest.md 2022-10-21 07:07:45 +02:00
jomjol
c8d2d9d4fd Implement direct data log 2022-10-19 22:27:26 +02:00
jomjol
0880213342 Merge branch 'rolling' of https://github.com/jomjol/AI-on-the-edge-device into rolling 2022-10-19 22:08:55 +02:00
jomjol
8d4fb74173 Implement data log 2022-10-19 22:08:02 +02:00
CaCO3
f10adb3383 Update build.yaml (#1193) 2022-10-19 22:01:56 +02:00
jomjol
3be33820d9 Merge branch 'rolling' of https://github.com/jomjol/AI-on-the-edge-device into rolling 2022-10-19 20:30:41 +02:00
jomjol
83f638c64f start implementing direct data log 2022-10-19 20:23:15 +02:00
jomjol
35d77a3925 Merge pull request #1188 from haverland/fix_analogtodigital
Fix analogtodigital with configuration transition start
2022-10-19 20:22:02 +02:00
jomjol
a33da0c750 Merge pull request #1189 from Slider0007/rolling
Fix for image logging + file deletion routines
2022-10-19 20:16:14 +02:00
Slider0007
cd2350140d Fix for image logging + file deletion routines 2022-10-19 09:32:52 +02:00
Frank Haverland
bd125b249b Merge branch 'jomjol:rolling' into rolling 2022-10-18 23:04:14 +02:00
Frank Haverland
33b9a15f73 enable debug on CNNGeneral 2022-10-18 23:02:11 +02:00
Frank Haverland
0e55fc7f7e add @Plawasan test cases. Works now with setable analogdigitTransistionstart 2022-10-18 23:01:09 +02:00
Frank Haverland
fc0bbc57cb update changelog 2022-10-17 22:27:39 +02:00
Frank Haverland
bc46149573 init the analogDigitalTransitionStart with 9.2 if nothing set in config 2022-10-17 22:22:47 +02:00
Frank Haverland
be8598bcaa read and save config for AnalogDigitalTransitionStart 2022-10-17 21:36:11 +02:00
Frank Haverland
ace1936a78 added AnalogDigitalTransitionStart to expert config 2022-10-17 20:47:12 +02:00
Frank Haverland
e5649d03b2 min and max of ANALOGDIGITALTRANSITIONSTART added 2022-10-17 20:40:20 +02:00
Frank Haverland
426d6bae3f fix name of ANALOGDIGITALTRANSITIONSTART 2022-10-17 20:37:15 +02:00
Frank Haverland
5d35df65f3 add testNegative 2022-10-17 20:29:50 +02:00
Frank Haverland
f91f5e3cba rewrite of ZeigerEvalAnalogToDigitNeu added explizit test-cases for it. 2022-10-17 20:29:35 +02:00
jomjol
1c66f8c6ca Merge pull request #1183 from haverland/minor_negative_accept
fix change for tollerance for extendedResolution.
2022-10-16 21:59:32 +02:00
Frank Haverland
a42902af0d Merge branch 'jomjol:rolling' into rolling 2022-10-16 21:19:04 +02:00
Frank Haverland
a871055d96 fix change for tollerance for extendedResolution. Added testcases for it 2022-10-16 21:12:52 +02:00
jomjol
64fcb9595c Implement Graph 2022-10-16 19:22:01 +02:00
jomjol
9d9cff977d Merge pull request #1181 from rdmueller/rolling
date for graph is now selectable
2022-10-16 19:13:39 +02:00
Ralf D. Müller
5724f37ea6 date for graph is now selectable 2022-10-16 14:22:38 +00:00
jomjol
3ca93b49ca Update FeatureRequest.md 2022-10-16 08:34:19 +02:00
jomjol
b2248818dd Remark for InfluxDB Version 2022-10-16 08:29:14 +02:00
jomjol
a702fbbe86 Create graph.html 2022-10-15 18:37:41 +02:00
jomjol
1002e502d5 Merge pull request #1179 from rdmueller/master
Graph of values directly on the web interface
2022-10-15 18:33:32 +02:00
Ralf D. Müller
17a8adae05 remove debug code 2022-10-15 16:11:15 +00:00
Ralf D. Müller
4fca050623 fix date 2022-10-15 16:04:49 +00:00
Ralf D. Müller
f371c176b6 set current date 2022-10-15 15:45:52 +00:00
Ralf D. Müller
1c6772f383 fix event 2022-10-15 15:22:49 +00:00
Ralf D. Müller
7d2f28084b made editor hidden as default 2022-10-15 15:20:22 +00:00
jomjol
923b8d7444 Merge pull request #1177 from haverland/minor_negative_accept
accept minor negative values if extended resolution is enabled
2022-10-15 16:53:29 +02:00
Frank Haverland
49e4eb3ef3 updated changelog 2022-10-15 16:02:01 +02:00
Frank Haverland
2c481c0d15 accept minor negative values if extendedResolution is enabled 2022-10-15 15:23:20 +02:00
jomjol
f2e854c935 Merge pull request #1174 from haverland/fix_analogtodigital
Fix analogtodigital
2022-10-15 08:33:05 +02:00
Frank Haverland
8045e0bfaf added testcases for #1143
cleanup the analogtodigit for better reading.
2022-10-14 23:20:05 +02:00
Frank Haverland
40e176ec28 digit will be roundet now from x.7..x.9 out of transition of the pointer 2022-10-14 20:03:18 +02:00
Frank Haverland
1ab135e989 fix hanging digits in transition 2022-10-14 19:53:04 +02:00
Frank Haverland
99c14ae9e0 Merge branch 'jomjol:rolling' into rolling 2022-10-14 19:21:17 +02:00
jomjol
00d859734d Merge pull request #1173 from jomjol/revert-1167-fix_analogtodigital
Revert "Fix analogtodigital"
2022-10-14 18:13:32 +02:00
jomjol
de4efff558 Revert "Fix analogtodigital" 2022-10-14 18:13:11 +02:00
jomjol
2ed3f4aa40 Revert "Merge pull request #1167 from haverland/fix_analogtodigital"
This reverts commit ba59c8ee66, reversing
changes made to 730006977c.
2022-10-14 18:12:11 +02:00
jomjol
ba59c8ee66 Merge pull request #1167 from haverland/fix_analogtodigital
Fix analogtodigital
2022-10-14 18:10:26 +02:00
CaCO3
fb97e22dee Update server_ota.cpp (#1169) 2022-10-13 23:26:05 +02:00
Frank Haverland
b0e7283d2b added lokal test case 2022-10-13 22:40:33 +02:00
Frank Haverland
e341564eee missing test cases from #1110 added 2022-10-13 22:15:08 +02:00
CaCO3
730006977c improved issues guiding (#1168) 2022-10-13 21:58:18 +02:00
Frank Haverland
ea26a5722a rewrite of analogtodigit, added new testcases 2022-10-13 21:41:40 +02:00
Frank Haverland
62742d92d2 set python verion because of warnings 2022-10-12 22:41:41 +02:00
Frank Haverland
50b9983534 fix warning set-output 2022-10-12 22:38:05 +02:00
Frank Haverland
34ea8302ef update action setup-python 2022-10-12 22:29:02 +02:00
Frank Haverland
a8fd0bbdef use newer actions checkout and cache 2022-10-12 22:09:38 +02:00
Frank Haverland
99e6243e25 test case description 2022-10-12 21:36:19 +02:00
Frank Haverland
0f6c767143 fix analogtodigital: remove rounding 2022-10-12 21:34:24 +02:00
jomjol
eb0b932c44 rolling 20221010 2022-10-10 07:09:00 +02:00
jomjol
1e4be0f3fe Merge pull request #1158 from Turbo87/pre-json
FlowPostProcessing::GetJSON: Add `pre` field to the `/json` response
2022-10-09 19:08:28 +02:00
Tobias Bieniek
47caa1b118 FlowPostProcessing::GetJSON: Add pre field to the /json response
This makes it easier for third-party software to fall back to the `pre` value, if the `value` itself is not available for some reason.
2022-10-09 18:45:59 +02:00
jomjol
641609e187 Update espressif32 to v5.2.0 2022-10-08 10:51:19 +02:00
jomjol
006fb6a611 Merge pull request #1147 from jomjol/refactor-config-page
Refactor config page
2022-10-08 10:45:35 +02:00
George Ruinelli
a0e4ee1d00 . 2022-10-07 21:56:29 +02:00
George Ruinelli
27d770c759 . 2022-10-07 21:54:38 +02:00
George Ruinelli
fe39b5120b . 2022-10-07 21:38:51 +02:00
George Ruinelli
74df27befd . 2022-10-07 21:30:21 +02:00
George Ruinelli
c92a1e430d . 2022-10-07 21:04:56 +02:00
George Ruinelli
642d22578f . 2022-10-07 20:41:51 +02:00
George Ruinelli
140ec1b380 . 2022-10-07 18:52:18 +02:00
George Ruinelli
17090c177e . 2022-10-07 18:40:26 +02:00
George Ruinelli
d2721cbd4b . 2022-10-07 18:18:21 +02:00
George Ruinelli
f80509c886 . 2022-10-07 16:59:23 +02:00
George Ruinelli
6c85796abe . 2022-10-07 16:56:35 +02:00
CaCO3
e82cbbf117 Rename bug_report.md to bug_report.yml 2022-10-04 23:24:32 +02:00
jomjol
bacdc97d90 Merge pull request #1131 from jomjol/fix-bug-template
Update bug_report.md
2022-10-04 21:54:59 +02:00
CaCO3
1e43c70adf Update bug_report.md 2022-10-04 21:24:45 +02:00
jomjol
16bb6e90a9 Update FeatureRequest.md 2022-10-03 09:07:03 +02:00
jomjol
cf6882c579 Merge branch 'rolling' of https://github.com/jomjol/AI-on-the-edge-device into rolling 2022-10-03 09:05:45 +02:00
jomjol
858d0b3361 Update FeatureRequest.md 2022-10-03 09:00:24 +02:00
jomjol
208a5433b7 Merge pull request #1121 from cristianmitran/patch-1
Support meter clock over
2022-10-02 17:33:35 +02:00
cristianmitran
9a7c9604fe Support meter clock over 2022-10-02 08:35:53 +02:00
jomjol
f44fa4df31 Update Changelog.md 2022-10-01 08:27:22 +02:00
jomjol
68a985a09f Merge pull request #1118 from jomjol/update-changelog
Update Changelog.md
2022-10-01 08:23:59 +02:00
jomjol
6b329aaa58 Rolling 20220930 2022-09-30 07:48:33 +02:00
jomjol
80798ae0e6 Merge branch 'master' into rolling 2022-09-30 07:26:36 +02:00
jomjol
cd61e2c92d Merge pull request #1117 from jomjol/updated-readme
update README.md
2022-09-30 07:26:01 +02:00
jomjol
c943510828 Rolling 20220930 2022-09-30 07:23:46 +02:00
CaCO3
9291d330dd Update Changelog.md 2022-09-29 23:45:38 +02:00
CaCO3
a856d9e2f2 Create README.md 2022-09-29 23:36:01 +02:00
jomjol
41f9436465 Merge pull request #1113 from jomjol/fix-missing-hash
Update build.yaml
2022-09-29 22:13:37 +02:00
jomjol
5233c14725 Update README.md 2022-09-29 19:54:40 +02:00
jomjol
3d42d949af Update README.md 2022-09-29 19:52:49 +02:00
github-actions
aec1dc770b Update Changelog.md for release 2022-09-29 17:21:56 +00:00
CaCO3
f335c17f0d Update build.yaml 2022-09-29 19:21:23 +02:00
217 changed files with 15738 additions and 6820 deletions

View File

@@ -1,31 +0,0 @@
---
name: Bug report
about: Create a bug report to help us improve
title: ''
labels: ''
assignees: ''
---
Thank you for taking your time to report a bug.
Before you proceed, please check:
- Do you use the latest version? See https://github.com/jomjol/AI-on-the-edge-device/releases.
- Is there already another similar issue? Check for open and closed Issue in https://github.com/jomjol/AI-on-the-edge-device/issues.
- Are instructions in the readme solving your issue (https://github.com/jomjol/AI-on-the-edge-device/tree/master#readme)?
- Are instructions in the wiki solving your issue? (https://github.com/jomjol/AI-on-the-edge-device/wiki)?
**Describe the bug**
A clear and concise description of what the bug is.
**Version**
Which version are you using? (See menu `System > Info`).
**Expected behavior**
A clear and concise description of what you expected to happen.
**Screenshots**
If applicable, add screenshots to help explain your problem.
**Additional context**
Add any other context about the problem here.

67
.github/ISSUE_TEMPLATE/bug_report.yml vendored Normal file
View File

@@ -0,0 +1,67 @@
name: 🐞 Bug Report
description: Use this form if you think you found a bug / Verwende dieses Formular, wenn Du denkst, dass Du einen Fehler gefunden hast.
labels: bug
body:
- type: markdown
attributes:
value: |
Thank you for taking your time to report a bug.
Before you proceed, please check:
- [ ] Do you use the [latest version](https://github.com/jomjol/AI-on-the-edge-device/releases)?
- [ ] Is there already another similar issue? Check for open and closed [Issue](https://github.com/jomjol/AI-on-the-edge-device/issues) and [Discussions](https://github.com/jomjol/AI-on-the-edge-device/discussions).
- [ ] Are instructions in the [README](https://github.com/jomjol/AI-on-the-edge-device/tree/master#readme) solving your issue?
- [ ] Are instructions in the [Wiki](https://github.com/jomjol/AI-on-the-edge-device/wiki) solving your issue?
Du darfst gerne auch in Deutsch schreiben!
- type: textarea
validations:
required: true
attributes:
label: The Problem
description: A clear and concise description of what the bug is.
- type: input
validations:
required: true
attributes:
label: Version
description: Which version are you using? (See menu `System > Info`).
- type: textarea
validations:
required: true
attributes:
label: Logfile
description: Add the logfile (See menu `System > Log Viewer`) to help explain your problem. This will be automatically formatted into code, so no need to format it on your side.
render: shell
- type: textarea
attributes:
label: Expected Behavior
description: A clear and concise description of what you expected to happen.
- type: textarea
attributes:
label: Screenshots
description: If applicable, add screenshots to help explain your problem.
- type: textarea
attributes:
label: Additional Context
description: Add any other context about the problem here.

5
.github/ISSUE_TEMPLATE/config.yml vendored Normal file
View File

@@ -0,0 +1,5 @@
blank_issues_enabled: false
contact_links:
- name: 💬 Open a new Discussion
url: https://github.com/jomjol/AI-on-the-edge-device/discussions/categories/q-a
about: Use this form if you have a question or need help setting your AI-on-the-edge-device it up

23
.github/ISSUE_TEMPLATE/feature.yaml vendored Normal file
View File

@@ -0,0 +1,23 @@
name: 💡 Feature Request
description: Use this form if you have an idea or wish for a new feature
labels: enhancement
body:
- type: markdown
attributes:
value: |
Thank you for taking your time to document your idea.
Before you proceed, please check:
- [ ] Is there already another similar issue open or closed? Check for open and closed [Issue](https://github.com/jomjol/AI-on-the-edge-device/issues) and [Discussions](https://github.com/jomjol/AI-on-the-edge-device/discussions).
- [ ] Is there already another similar [discussion](https://github.com/jomjol/AI-on-the-edge-device/discussions) ongoing?
Please be aware that we might decline your request if we have a reason for it!
- type: textarea
validations:
required: true
attributes:
label: The Feature
description: A clear and concise description of what the new feature should do. If possible, refer to other projects or add a mockup.

View File

@@ -1,10 +0,0 @@
---
name: General Question
about: General Question => Open a discussion instead
title: ''
labels: ''
assignees: ''
---
If its not a bug, please open a discussion instead, see https://github.com/jomjol/AI-on-the-edge-device/discussions

19
.github/ISSUE_TEMPLATE/training.yaml vendored Normal file
View File

@@ -0,0 +1,19 @@
name: 📖 New Training Data
description: Use this form if you collected images and want to provide them for training the model
title: New Training Data
labels: new training data
assignees: jomjol
body:
- type: markdown
attributes:
value: |
Before you proceed, please check:
- [ ] Did you make sure we don't have similar data yet in the training data? (see [Digital Counters](https://jomjol.github.io/neural-network-digital-counter-readout/) resp. [Analog Needles](https://jomjol.github.io/neural-network-analog-needle-readout))
- [ ] Did you follow the guideline as documented in the [Wiki](https://github.com/jomjol/AI-on-the-edge-device/wiki/ROI-Configuration)? We will only be able to accept the files if they fulfill the rules!
- type: textarea
validations:
required: true
attributes:
label: Files
description: You can drag & drop your **zipped** images here

8
.github/ISSUE_TEMPLATE/x_plain.yaml vendored Normal file
View File

@@ -0,0 +1,8 @@
name: 🗒️ Blank Form
description: Use this form if none of the others fit. Please only use none of the others fit!
body:
- type: textarea
attributes:
label: Issue

98
.github/label-commenter-config.yml vendored Normal file
View File

@@ -0,0 +1,98 @@
# Reply Bot Configuration
# See https://github.com/peaceiris/actions-label-commenter
# Make sure to also add the response to .github/workflows/reply-bot.yml!
# Due to the way it works, you have to add each response twice, once for the issue, once for the discussions!
labels:
#######################################################################
# Bot Response: Logfile
#######################################################################
- name: bot-reply Logfile
labeled:
issue:
body: |
Please provide a logfile!
Make sure to first enable the `DEBUG` level in `Settings->Configuration->Debug->Logfile Log Level`!
Then wait until the issue arises again.
When you copy the log into here, please make sure to use **Fenced code blocks** by wrapping it into separate lines with ` ``` `, see https://docs.github.com/en/get-started/writing-on-github/working-with-advanced-formatting/creating-and-highlighting-code-blocks#fenced-code-blocks
discussion:
body: |
Please provide a logfile!
Make sure to first enable the `DEBUG` level in `Settings->Configuration->Debug->Logfile Log Level`!
Then wait until the issue arises again.
When you copy the log into here, please make sure to use **Fenced code blocks** by wrapping it into separate lines with ` ``` `, see https://docs.github.com/en/get-started/writing-on-github/working-with-advanced-formatting/creating-and-highlighting-code-blocks#fenced-code-blocks
#######################################################################
# Bot Response: Web Console
#######################################################################
- name: bot-reply Web Console
labeled:
issue:
body: |
You can use the [Web Console](https://jomjol.github.io/AI-on-the-edge-device/index.html) to get USB log from the device.
The USB log contains more information about the startup and operation of the device than the normal Web UI log
When you copy the log into herm, please make sure to use **Fenced code blocks** by wrapping it into separate lines with ` ``` `, see https://docs.github.com/en/get-started/writing-on-github/working-with-advanced-formatting/creating-and-highlighting-code-blocks#fenced-code-blocks
discussion:
body: |
You can use the [Web Console](https://jomjol.github.io/AI-on-the-edge-device/index.html) to get USB log from the device.
The USB log contains more information about the startup and operation of the device than the normal Web UI log
When you copy the log into herm, please make sure to use **Fenced code blocks** by wrapping it into separate lines with ` ``` `, see https://docs.github.com/en/get-started/writing-on-github/working-with-advanced-formatting/creating-and-highlighting-code-blocks#fenced-code-blocks
#######################################################################
# Bot Response: Properly Format Code
#######################################################################
- name: bot-reply Properly Format Code
labeled:
issue:
body: |
Please make sure to use **Fenced code blocks** by wrapping it into separate lines with ` ``` `, see https://docs.github.com/en/get-started/writing-on-github/working-with-advanced-formatting/creating-and-highlighting-code-blocks#fenced-code-blocks
This makes your code or log much easier to read!
discussion:
body: |
Please make sure to use **Fenced code blocks** by wrapping it into separate lines with ` ``` `, see https://docs.github.com/en/get-started/writing-on-github/working-with-advanced-formatting/creating-and-highlighting-code-blocks#fenced-code-blocks
This makes your code or log much easier to read!
#######################################################################
# Bot Response: Web Installer
#######################################################################
- name: bot-reply Web Installer
labeled:
issue:
body: |
You can use the [Web Installer](https://jomjol.github.io/AI-on-the-edge-device/index.html) install the firmware onto the ESP32.
discussion:
body: |
You can use the [Web Installer](https://jomjol.github.io/AI-on-the-edge-device/index.html) install the firmware onto the ESP32.
#######################################################################
# Bot Response: Rolling Build
#######################################################################
- name: bot-reply Rolling Build
labeled:
issue:
body: |
You can try the latest [Automatic Build](https://github.com/jomjol/AI-on-the-edge-device/actions/workflows/build.yaml?query=branch%3Arolling+event%3Apush) of the the `rolling` or any other branch. It might already contain a fix for your issue.
See the [documentation](https://jomjol.github.io/AI-on-the-edge-device-docs/rolling-installation) for additional information.
discussion:
body: |
You can try the latest [Automatic Build](https://github.com/jomjol/AI-on-the-edge-device/actions/workflows/build.yaml?query=branch%3Arolling+event%3Apush) of the the `rolling` or any other branch. It might already contain a fix for your issue.
See the [documentation](https://jomjol.github.io/AI-on-the-edge-device-docs/rolling-installation) for additional information.
#######################################################################
# Bot Response: Show Trained Digits/Pointers
#######################################################################
- name: bot-reply Show Trained Digits/Pointers
labeled:
issue:
body: |
See [Digital Digits](https://jomjol.github.io/neural-network-digital-counter-readout) resp. [Analogue Pointers](https://jomjol.github.io/neural-network-analog-needle-readout) for an overview of all trained data.
If your type is not contained it can be added to our training material, see [here](https://jomjol.github.io/AI-on-the-edge-device-docs/Learn-models-with-your-own-images/).
discussion:
body: |
See [Digital Digits](https://jomjol.github.io/neural-network-digital-counter-readout) resp. [Analogue Pointers](https://jomjol.github.io/neural-network-analog-needle-readout) for an overview of all trained data.
If your type is not contained it can be added to our training material, see [here](https://jomjol.github.io/AI-on-the-edge-device-docs/Learn-models-with-your-own-images/).

View File

@@ -1,6 +1,6 @@
name: Build and Pack
on: [push]
on: [push, pull_request]
jobs:
#########################################################################################
@@ -10,96 +10,78 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- id: skip_check
uses: fkirc/skip-duplicate-actions@v5
with:
concurrent_skipping: same_content_newer
- uses: actions/checkout@v3
with:
submodules: recursive
- name: Set Variables
id: vars
run: |
echo "::set-output name=sha_short::$(git rev-parse --short HEAD)"
echo "sha_short=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
- name: Cache PlatformIO
uses: actions/cache@v2
- name: Update PIP cache on every commit
uses: actions/cache@v3.2.3
with:
path: ~/.cache/pip
key: pip-${{ github.run_id }}
restore-keys: pip # This matches above key as it is only used as a prefix. it the restores the nearest cache, see https://github.com/restore-keys:/blob/main/tips-and-workarounds.md#update-a-cache
- name: Update PlatformIO cache on every commit
uses: actions/cache@v3.2.3
with:
path: ~/.platformio
key: ${{ runner.os }}-${{ hashFiles('**/lockfiles') }}
key: platformio-${{ github.run_id }}
restore-keys: platformio # This matches above key as it is only used as a prefix. it the restores the nearest cache, see https://github.com/restore-keys:/blob/main/tips-and-workarounds.md#update-a-cache
- name: Update Build cache on every commit
uses: actions/cache@v3.2.3
with:
path: ./code/.pio/
key: build-${{ github.run_id }}
restore-keys: build # This matches above key as it is only used as a prefix. it the restores the nearest cache, see https://github.com/restore-keys:/blob/main/tips-and-workarounds.md#update-a-cache
- name: Update generated-files cache on every commit
uses: actions/cache@v3.2.3
with:
path: |
./code/.pio/build/esp32cam/firmware.bin
./code/.pio/build/esp32cam/partitions.bin
./code/.pio/build/esp32cam/bootloader.bin
./html/*
key: generated-files-${{ github.run_id }}
restore-keys: generated-files # This matches above key as it is only used as a prefix. it the restores the nearest cache, see https://github.com/restore-keys:/blob/main/tips-and-workarounds.md#update-a-cache
- name: Set up Python
uses: actions/setup-python@v2
uses: actions/setup-python@v4
with:
python-version: '3.10'
- name: Install PlatformIO
run: |
python -m pip install --upgrade pip
pip install --upgrade platformio
- name: Build Firmware
# run: echo "Testing... ${{ github.ref_name }}, ${{ steps.vars.outputs.sha_short }}" > ./sd-card/html/version.txt; mkdir -p ./code/.pio/build/esp32cam/; cd ./code/.pio/build/esp32cam/; echo "${{ steps.vars.outputs.sha_short }}" > firmware.bin; cp firmware.bin partitions.bin; cp firmware.bin bootloader.bin # Testing
#run: echo "Testing... ${{ github.ref_name }}, ${{ steps.vars.outputs.sha_short }}" > ./sd-card/html/version.txt; mkdir -p ./code/.pio/build/esp32cam/; cd ./code/.pio/build/esp32cam/; echo "${{ steps.vars.outputs.sha_short }}" > firmware.bin; cp firmware.bin partitions.bin; cp firmware.bin bootloader.bin # Testing
run: cd code; platformio run --environment esp32cam
- name: Store generated files in cache
uses: actions/cache@v3
with:
path: |
./code/.pio/build/esp32cam/firmware.bin
./code/.pio/build/esp32cam/partitions.bin
./code/.pio/build/esp32cam/bootloader.bin
./sd-card/html/version.txt
key: ${{ github.run_number }}
#########################################################################################
## Pack for old OTA (v1)
#########################################################################################
pack-for-OTA-v1:
# Old OTA concept
# firmware__*.zip needs to be unpacked before attaching to the release!
# The bin filename can contain versioning.
runs-on: ubuntu-latest
needs: build
steps:
- uses: actions/checkout@v2
- name: Get generated files from cache
uses: actions/cache@v3
with:
path: |
./code/.pio/build/esp32cam/firmware.bin
./code/.pio/build/esp32cam/partitions.bin
./code/.pio/build/esp32cam/bootloader.bin
./sd-card/html/version.txt
key: ${{ github.run_number }}
- name: Set Variables
id: vars
- name: Prepare Web UI (copy data from repo and update hashes in all files)
run: |
echo "::set-output name=sha_short::$(git rev-parse --short HEAD)"
- name: Rename firmware file to contain versioning (old ota)
run: |
mkdir -p ./dist_old_ota
cp "./code/.pio/build/esp32cam/firmware.bin" "./dist_old_ota/firmware__${{ github.ref_name }}_(${{ steps.vars.outputs.sha_short }}).bin"
- name: Upload Firmware artifact (old OTA concept)
uses: actions/upload-artifact@v3
with:
# name: "firmware__${{ github.ref_name }}__(${{ steps.vars.outputs.sha_short }})__(extract_before_upload__only_needed_for_migration_from_11.3.1)"
name: "firmware__(extract_before_upload)__${{ github.ref_name }}__(${{ steps.vars.outputs.sha_short }})"
path: ./dist_old_ota/*
- name: Upload Web interface artifact (old OTA concept)
uses: actions/upload-artifact@v3
with:
name: "html__${{ github.ref_name }}__(${{ steps.vars.outputs.sha_short }})"
path: ./sd-card/html/*
rm -rf ./html; mkdir html
cp ./sd-card/html/* ./html/
cd html; find . -type f -exec sed -i 's/$COMMIT_HASH/${{ steps.vars.outputs.sha_short }}/g' {} \;
#########################################################################################
## Pack for new OTA (v2)
## Pack for Update
#########################################################################################
pack-for-OTA-v2:
pack-for-update:
# New OTA concept
# update__version.zip file with following content:
# - /firmware.bin
@@ -109,112 +91,165 @@ jobs:
needs: build
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: Get generated files from cache
uses: actions/cache@v3
- name: Update generated-files cache on every commit
uses: actions/cache@v3.2.3
with:
path: |
./code/.pio/build/esp32cam/firmware.bin
./code/.pio/build/esp32cam/partitions.bin
./code/.pio/build/esp32cam/bootloader.bin
./sd-card/html/version.txt
key: ${{ github.run_number }}
./html/*
key: generated-files-${{ github.run_id }}
restore-keys: generated-files # This matches above key as it is only used as a prefix. it the restores the nearest cache, see https://github.com/restore-keys:/blob/main/tips-and-workarounds.md#update-a-cache
- name: Update update cache on every commit
uses: actions/cache@v3.2.3
with:
path: update
key: update-${{ github.run_id }}
restore-keys: update # This matches above key as it is only used as a prefix. it the restores the nearest cache, see https://github.com/restore-keys:/blob/main/tips-and-workarounds.md#update-a-cache
- name: Set Variables
id: vars
run: |
echo "sha_short=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
echo "branch=$(echo ${{ github.ref_name }} | tr / __)" >> $GITHUB_OUTPUT
- name: Prepare update__*.zip artifact
run: |
mkdir -p ./update
cp "./code/.pio/build/esp32cam/firmware.bin" "update/firmware.bin"
- name: Add Web UI to update
run: cp -r ./html ./update/
- name: Add CNN to update
run: |
mkdir -p ./update/config/
cp ./sd-card/config/*.tfl ./update/config/ 2>/dev/null || true
cp ./sd-card/config/*.tflite ./update/config/ 2>/dev/null || true
- name: Upload update as update.zip artifact (Firmware + Web UI + CNN)
uses: actions/upload-artifact@v3
with:
name: "AI-on-the-edge-device__update__${{ steps.vars.outputs.branch }}_(${{ steps.vars.outputs.sha_short }})"
path: ./update/*
#########################################################################################
## Pack for Remote Setup
#########################################################################################
pack-for-remote_setup:
# New Remote Setup concept
# remote_setup__version.zip file with following content:
# - /firmware.bin
# - /html/*
# - /config/*
runs-on: ubuntu-latest
needs: build
steps:
- uses: actions/checkout@v3
- name: Update generated-files cache on every commit
uses: actions/cache@v3.2.3
with:
path: |
./code/.pio/build/esp32cam/firmware.bin
./code/.pio/build/esp32cam/partitions.bin
./code/.pio/build/esp32cam/bootloader.bin
./html/*
key: generated-files-${{ github.run_id }}
restore-keys: generated-files # This matches above key as it is only used as a prefix. it the restores the nearest cache, see https://github.com/restore-keys:/blob/main/tips-and-workarounds.md#update-a-cache
- name: Update remote_setup cache on every commit
uses: actions/cache@v3.2.3
with:
path: remote_setup
key: remote_setup-${{ github.run_id }}
restore-keys: remote_setup # This matches above key as it is only used as a prefix. it the restores the nearest cache, see https://github.com/restore-keys:/blob/main/tips-and-workarounds.md#update-a-cache
- name: Set Variables
id: vars
run: |
echo "::set-output name=sha_short::$(git rev-parse --short HEAD)"
echo "sha_short=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
echo "branch=$(echo ${{ github.ref_name }} | tr / __)" >> $GITHUB_OUTPUT
- name: Prepare update.zip artifact
- name: Prepare remote_setup__*.zip artifact
run: |
mkdir -p ./dist
cp "./code/.pio/build/esp32cam/firmware.bin" "dist/firmware.bin"
mkdir -p ./remote_setup
cp "./code/.pio/build/esp32cam/firmware.bin" "remote_setup/firmware.bin"
# - name: Upload update.zip Artifact (Firmware only)
# uses: actions/upload-artifact@v3
# with:
# name: "update_firmware_only__${{ github.ref_name }}_(${{ steps.vars.outputs.sha_short }})"
# path: ./dist/*
- name: Add Web UI to dist
run: cp -r ./sd-card/html ./dist/
- name: Add Web UI to remote_setup
run: cp -r ./html ./remote_setup/
# - name: Upload update.zip artifact (Firmware + Web UI)
# uses: actions/upload-artifact@v3
# with:
# name: "update_firmware+webinterface__${{ github.ref_name }}_(${{ steps.vars.outputs.sha_short }})"
# path: ./dist/*
- name: Add CNN to dist
- name: Add whole config folder to remote_setup
run: |
mkdir ./dist/config/
cp ./sd-card/config/*.tfl ./dist/config/ 2>/dev/null || true
cp ./sd-card/config/*.tflite ./dist/config/ 2>/dev/null || true
mkdir -p ./remote_setup/config/
cp ./sd-card/config/* ./remote_setup/config/ 2>/dev/null || true
- name: Upload dist as update.zip artifact (Firmware + Web UI + CNN)
- name: Upload remote_setup as remote_setup.zip artifact (Firmware + Web UI + Config)
uses: actions/upload-artifact@v3
with:
name: "update__${{ github.ref_name }}_(${{ steps.vars.outputs.sha_short }})"
path: ./dist/*
- name: Store generated files in cache
uses: actions/cache@v3
with:
path: |
./dist
key: ${{ github.run_number }}-pack-for-OTA-v2
name: "AI-on-the-edge-device__remote-setup__${{ steps.vars.outputs.branch }}_(${{ steps.vars.outputs.sha_short }})"
path: ./remote_setup/*
#########################################################################################
## Pack for a fresh install (USB flashing) (initial_esp32_setup)
## Pack for a fresh install (USB flashing) (manual_setup)
#########################################################################################
pack-for-fresh-install:
pack-for-manual_setup:
# creates old style binaries for fresh installation (backward compatible to wiki)
runs-on: ubuntu-latest
needs: build
steps:
- uses: actions/checkout@v2
- uses: actions/checkout@v3
- name: Get generated files from cache
uses: actions/cache@v3
- name: Update generated-files cache on every commit
uses: actions/cache@v3.2.3
with:
path: |
./code/.pio/build/esp32cam/firmware.bin
./code/.pio/build/esp32cam/partitions.bin
./code/.pio/build/esp32cam/bootloader.bin
./sd-card/html/version.txt
key: ${{ github.run_number }}
./html/*
key: generated-files-${{ github.run_id }}
restore-keys: generated-files # This matches above key as it is only used as a prefix. it the restores the nearest cache, see https://github.com/restore-keys:/blob/main/tips-and-workarounds.md#update-a-cache
- name: Prepare artifacts for release
- name: Update manual_setup cache on every commit
uses: actions/cache@v3.2.3
with:
path: manual_setup
key: manual_setup-${{ github.run_id }}
restore-keys: manual_setup # This matches above key as it is only used as a prefix. it the restores the nearest cache, see https://github.com/restore-keys:/blob/main/tips-and-workarounds.md#update-a-cache
- name: Set Variables
id: vars
run: |
mkdir -p firmware
rm -rf firmware/*.zip
echo "sha_short=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
echo "branch=$(echo ${{ github.ref_name }} | tr / __)" >> $GITHUB_OUTPUT
- name: Prepare manual_setup__*.zip artifact
run: |
mkdir -p manual_setup
rm -rf manual_setup/*.zip
mkdir -p release
# copy builds to firmware folder
cp -f "./code/.pio/build/esp32cam/firmware.bin" "firmware/firmware.bin"
cp -f "./code/.pio/build/esp32cam/bootloader.bin" "firmware/bootloader.bin"
cp -f "./code/.pio/build/esp32cam/partitions.bin" "firmware/partitions.bin"
zip -r ./firmware/sd-card.zip sd-card
cd ./firmware
# copy builds to manual_setup folder
cp -f "./code/.pio/build/esp32cam/firmware.bin" "manual_setup/firmware.bin"
cp -f "./code/.pio/build/esp32cam/bootloader.bin" "manual_setup/bootloader.bin"
cp -f "./code/.pio/build/esp32cam/partitions.bin" "manual_setup/partitions.bin"
cd sd-card; zip -r ../manual_setup/sd-card.zip *; cd ..
cd ./manual_setup
- name: Upload initial_esp32_setup.zip artifact (Firmware + Bootloader + Partitions + Web UI)
- name: Upload manual_setup.zip artifact (Firmware + Bootloader + Partitions + Web UI)
uses: actions/upload-artifact@v3
with:
name: "initial_esp32_setup__${{ github.ref_name }}_(${{ steps.vars.outputs.sha_short }})"
path: ./firmware
- name: Store generated files in cache
uses: actions/cache@v3
with:
path: |
./firmware
key: ${{ github.run_number }}-pack-for-fresh-install
name: "AI-on-the-edge-device__manual-setup__${{ steps.vars.outputs.branch }}_(${{ steps.vars.outputs.sha_short }})"
path: ./manual_setup
#########################################################################################
@@ -222,56 +257,61 @@ jobs:
#########################################################################################
release:
runs-on: ubuntu-latest
needs: [pack-for-OTA-v2, pack-for-fresh-install]
needs: [pack-for-update, pack-for-manual_setup, pack-for-remote_setup]
if: startsWith(github.ref, 'refs/tags/')
# Sets permissions of the GITHUB_TOKEN to allow updating the branches
permissions:
contents: write
pages: write
id-token: write
steps:
- uses: actions/checkout@v2
- name: Get generated files from cache
uses: actions/cache@v3
- uses: actions/checkout@v3
- name: Update update cache on every commit
uses: actions/cache@v3.2.3
with:
path: |
./code/.pio/build/esp32cam/firmware.bin
./code/.pio/build/esp32cam/partitions.bin
./code/.pio/build/esp32cam/bootloader.bin
./sd-card/html/version.txt
key: ${{ github.run_number }}
# import the changes from
- name: Get generated files from cache
uses: actions/cache@v3
path: update
key: update-${{ github.run_id }}
restore-keys: update # This matches above key as it is only used as a prefix. it the restores the nearest cache, see https://github.com/restore-keys:/blob/main/tips-and-workarounds.md#update-a-cache
- name: Update remote_setup cache on every commit
uses: actions/cache@v3.2.3
with:
path: |
./dist
key: ${{ github.run_number }}-pack-for-OTA-v2
# import cached artifacts from pack-for-fresh-install
- name: Get generated files from cache
uses: actions/cache@v3
path: remote_setup
key: remote_setup-${{ github.run_id }}
restore-keys: remote_setup # This matches above key as it is only used as a prefix. it the restores the nearest cache, see https://github.com/restore-keys:/blob/main/tips-and-workarounds.md#update-a-cache
- name: Update manual_setup cache on every commit
uses: actions/cache@v3.2.3
with:
path: |
./firmware
key: ${{ github.run_number }}-pack-for-fresh-install
path: manual_setup
key: manual_setup-${{ github.run_id }}
restore-keys: manual_setup # This matches above key as it is only used as a prefix. it the restores the nearest cache, see https://github.com/restore-keys:/blob/main/tips-and-workarounds.md#update-a-cache
- name: Set Variables
id: vars
run: |
echo "::set-output name=sha_short::$(git rev-parse --short HEAD)"
echo "sha_short=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
echo "branch=$(echo ${{ github.ref_name }} | tr / __)" >> $GITHUB_OUTPUT
- name: Prepare artifacts for release
run: |
mkdir -p release
# create a update.zip like "update__rolling"
cd ./dist
zip -r ../release/update.zip .
cd ../firmware
zip -r ../release/initial_esp32_setup.zip .
cd ../sd-card/html
zip -r ../../firmware/html-from-11.3.1.zip .
# create AI-on-the-edge-device__update__*.zip like "AI-on-the-edge-device__update__v13.0.5.zip"
cd ./update
zip -r ../release/AI-on-the-edge-device__update__${{ steps.vars.outputs.branch }}.zip .
# create AI-on-the-edge-device__manual-setup__*.zip like "AI-on-the-edge-device__manual-setup__v13.0.5.zip"
cd ../manual_setup
zip -r ../release/AI-on-the-edge-device__manual-setup__${{ steps.vars.outputs.branch }}.zip .
# create AI-on-the-edge-device__remote-setup__*.zip like "AI-on-the-edge-device__remote-setup__v13.0.5.zip"
cd ../manual_setup
zip -r ../release/AI-on-the-edge-device__remote-setup__${{ steps.vars.outputs.branch }}.zip .
# extract the version used in next step
- id: get_version
if: startsWith(github.ref, 'refs/tags/')
@@ -298,15 +338,16 @@ jobs:
# all artifacts in firmware folder pushed to the release
- name: Release
uses: softprops/action-gh-release@v1
# Note:
# If you get the error "Resource not accessible by integration",
# The access rights are not sufficient, see
# https://github.com/softprops/action-gh-release/issues/232#issuecomment-1131379440
if: startsWith(github.ref, 'refs/tags/')
with:
name: ${{ steps.get_version.outputs.version-without-v }}
body: ${{ steps.extract-release-notes.outputs.release_notes }}
files: |
release/*
firmware/firmware.bin
firmware/html-from-11.3.1.zip
# Commit&Push Changelog to master branch. Must be manually merged back to rolling
- name: Commit changes and push changes
@@ -317,3 +358,57 @@ jobs:
git add Changelog.md
git commit Changelog.md -m "Update Changelog.md for ${{github.event.inputs.versionIncrement}} release"
git push origin HEAD:master
#########################################################################################
## Update the Web Installer on a release
#########################################################################################
update-web-installer:
needs: [release]
environment:
name: github-pages
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
permissions:
contents: read
pages: write
id-token: write
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Update update cache on every commit
uses: actions/cache@v3.2.3
with:
path: update
key: update-${{ github.run_id }}
restore-keys: update # This matches above key as it is only used as a prefix. it the restores the nearest cache, see https://github.com/restore-keys:/blob/main/tips-and-workarounds.md#update-a-cache
- name: Set Variables
id: vars
run: |
echo "sha_short=$(git rev-parse --short HEAD)" >> $GITHUB_OUTPUT
echo "branch=$(echo ${{ github.ref_name }} | tr / __)" >> $GITHUB_OUTPUT
- name: Add binary to Web Installer and update manifest
run: |
rm -f docs/binary/firmware.bin
cp -f update/firmware.bin docs/binary/firmware.bin
cp -f docs/manifest_template.json docs/manifest.json
sed -i 's/VERSION/${{ steps.vars.outputs.branch }}/g' docs/manifest.json
- name: Setup Pages
uses: actions/configure-pages@v2
- name: Upload artifact
uses: actions/upload-pages-artifact@v1
with:
path: 'docs'
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v1

30
.github/workflows/clear_cache.yml vendored Normal file
View File

@@ -0,0 +1,30 @@
name: Clear cache
on:
workflow_dispatch:
permissions:
actions: write
jobs:
clear-cache:
runs-on: ubuntu-latest
steps:
- name: Clear cache
uses: actions/github-script@v6
with:
script: |
console.log("About to clear")
const caches = await github.rest.actions.getActionsCacheList({
owner: context.repo.owner,
repo: context.repo.repo,
})
for (const cache of caches.data.actions_caches) {
console.log(cache)
github.rest.actions.deleteActionsCacheById({
owner: context.repo.owner,
repo: context.repo.repo,
cache_id: cache.id,
})
}
console.log("Clear completed")

79
.github/workflows/reply-bot.yml vendored Normal file
View File

@@ -0,0 +1,79 @@
# Reply Bot
# It uses the configuration in .github/label-commenter-config.yml
# See https://github.com/peaceiris/actions-label-commenter
name: Reply-Bot
on:
issues:
types: [labeled]
discussion:
types: [labeled]
permissions:
contents: read
issues: write
pull-requests: write
discussions: write
jobs:
comment:
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v3
####################################################################
## Remove labels again (issues only)
## Make sure to also add the reply message to .github/label-commenter-config.yml!
## This currently seems no longer to work due to changes on the actions-cool/issues-helper!
####################################################################
# - name: Remove 'Logfile' label again (issues only)
# if: github.event.label.name == 'bot-reply Logfile'
# uses: actions-cool/issues-helper@v3
# with:
# actions: 'remove-labels'
# labels: 'bot-reply Logfile'
#
# - name: Remove 'Web Console' label again (issues only)
# if: github.event.label.name == 'bot-reply Web Console'
# uses: actions-cool/issues-helper@v3
# with:
# actions: 'remove-labels'
# labels: 'bot-reply Web Console'
#
# - name: Remove 'Properly Format Code' label again (issues only)
# if: github.event.label.name == 'bot-reply Properly Format Code'
# uses: actions-cool/issues-helper@v3
# with:
# actions: 'remove-labels'
# labels: 'bot-reply Properly Format Code'
#
# - name: Remove 'Web Installer' label again (issues only)
# if: github.event.label.name == 'bot-reply Web Installer'
# uses: actions-cool/issues-helper@v3
# with:
# actions: 'remove-labels'
# labels: 'bot-reply Web Installer'
#
# - name: Remove 'Rolling Build' label again (issues only)
# if: github.event.label.name == 'bot-reply Rolling Build'
# uses: actions-cool/issues-helper@v3
# with:
# actions: 'remove-labels'
# labels: 'bot-reply Rolling Build'
#
# - name: Remove 'Show Trained Digits/Pointers' label again (issues only)
# if: github.event.label.name == 'bot-reply Show Trained Digits/Pointers'
# uses: actions-cool/issues-helper@v3
# with:
# actions: 'remove-labels'
# labels: 'bot-reply Show Trained Digits/Pointers'
####################################################################
## Write the response
####################################################################
- name: Write Response
uses: peaceiris/actions-label-commenter@c2d00660c86f2b9ed0fb35b372c451558eba85b3
with:
repo-token: "${{ secrets.GITHUB_TOKEN }}"

View File

@@ -2,110 +2,247 @@
## [Unreleased]
**Stabilization and Improved User Experience**
Thanks to over 80 Pull Requests from 6 contributors, we can anounce another great release with many many improvements and new features:
### Update Procedure
Update Procedure see [online documentation](https://jomjol.github.io/AI-on-the-edge-device-docs/Installation/#update)
### Changes
For a full list of changes see [Full list of changes](https://github.com/jomjol/AI-on-the-edge-device/compare/v13.0.8...v14.0.0)
#### Added
- [1877](https://github.com/jomjol/AI-on-the-edge-device/pull/1877) Show WIFI signal text labels / Log RSSI value to logfile
- Web UI caching of static files
- Added various debug tools
- [1798](https://github.com/jomjol/AI-on-the-edge-device/pull/1798) Add error handling for memory intensive tasks
- [1784](https://github.com/jomjol/AI-on-the-edge-device/pull/1784) Add option to disable brownout detector
- Added full web browser based installation mode (including initial setup of SD-card) - see [WebInstaller](https://jomjol.github.io/AI-on-the-edge-device/index.html)
- Added [Demo Mode](https://jomjol.github.io/AI-on-the-edge-device-docs/Demo-Mode)
- [1648](https://github.com/jomjol/AI-on-the-edge-device/pull/1648) Added trigger to start a flow by [REST](https://jomjol.github.io/AI-on-the-edge-device-docs/REST-API) API or [MQTT](https://jomjol.github.io/AI-on-the-edge-device-docs/MQTT-API/)
- Show special images during steps `Initializing` and `Take Image` as the current camera image might be incomplete or outdated
#### Changed
- Migrated documentation (Wiki) to [https://jomjol.github.io/AI-on-the-edge-device-docs](https://jomjol.github.io/AI-on-the-edge-device-docs). Please help us to make it even better.
- New OTA Update page with progress indication
- Various memory optimizations
- Cleanup code/Web UI
- Updated models
- [1809](https://github.com/jomjol/AI-on-the-edge-device/pull/1809) Store preprocessed image with ROI to RAM
- Better log messages on some errors/issues
- [1742](https://github.com/jomjol/AI-on-the-edge-device/pull/1742) Replace alert boxes with overlay info boxes
- Improve log message when web UI is installed incomplete
- [1676](https://github.com/jomjol/AI-on-the-edge-device/pull/1676) Improve NTP handling
- HTML: improved user informations (info boxes, error hints, ...)
- [1904](https://github.com/jomjol/AI-on-the-edge-device/pull/1904) Removed newlines in JSON and replaced all whitespaces where there was more than one
#### Fixed
- Fixed many many things
- [1509](https://github.com/jomjol/AI-on-the-edge-device/pull/1509) Protect `wifi.ini` from beeing deleted.
- [1530](https://github.com/jomjol/AI-on-the-edge-device/pull/1530) Homeassistant `Problem Sensor`
- [1518](https://github.com/jomjol/AI-on-the-edge-device/pull/1518) JSON Strings
- [1817](https://github.com/jomjol/AI-on-the-edge-device/pull/1817) DataGraph: datafiles sorted -> newest on top
#### Removed
- n.a.
## [13.0.8] - 2022-12-19
**Home Assistant MQTT Discovery Support**
### Update Procedure see [online documentation](https://jomjol.github.io/AI-on-the-edge-device-docs/Installation/#update)
### Added
- Implementation of [Home Assistant MQTT Discovery](https://www.home-assistant.io/integrations/mqtt/#mqtt-discovery)
- Improved ROIs configuration: locked ROI geometry, equidistant delta x
- Improved OTA Update mechanism (only working after installation for next update)
- Added data logging in `/log/data` - One day per file and each measurement is on one line
- Format: csv - comma separated
- Content: `time`, `name-of-number`, `raw-value`, `return-value`, `pre-value`, `change-rate`, `change-absolute`, `error-text`, `cnn-digital`, `cnn-analog`
- Show graph of values direct in the user interface (thanks to [@rdmueller](https://github.com/rdmueller))
- Using new data logging (see above)
- Possibility to choose different values and switch between different numbers (if present)
Note: You need to activate data logging for this feature to work, see above!
- PreValue is now contained in `/json` ([#1154](https://github.com/jomjol/AI-on-the-edge-device/issues/1154))
- SD card info into the `System>Info` menu (thanks to [@Slider007](https://github.com/Slider0007))
- Version check (Firmware vs. Web UI)
- Various minor new features
### Changed
- Updated tflite (`dig-cont_0600_s3.tflite`)
- Updated OTA functionality (more robust, but not fully bullet prove yet)
- Updated Espressif library to `espressif32@v5.2.0`
- [#1176](https://github.com/jomjol/AI-on-the-edge-device/discussions/1176) accept minor negative values (-0.2) if extended resolution is enabled
- [#1143](https://github.com/jomjol/AI-on-the-edge-device/issues/1143) added config parameter `AnalogDigitalTransitionStart`. It can setup very early and very late digit transition starts.
- New version of `dig-class100` (v1.4.0): added images of heliowatt powermeter
- NEW v13.0.2: Update Tool "Logfile downloader and combiner" to handle the new csv file format.
- NEW v13.0.2: MQTT: Added MQTT topic `status` (Digitalization Status), Timezone to MQTT topic `timestamp`.#
- NEW v13.0.2: Logging: Disable heap logs by default, cleanup
- NEW v13.0.7:
- log NTP server name
- Improved log messages
- Various preparations for next release
- **NEW v13.0.8**:
- Continue booting on PSRAM issues, Web UI will show an error
- Updated models
- Various UI enhancements
- Various internal improvements
- Show uptime in log
- Show uptime and round on overview page
### Fixed
- [#1116](https://github.com/jomjol/AI-on-the-edge-device/issues/1116) precision problem at setting prevalue
- [#1119](https://github.com/jomjol/AI-on-the-edge-device/issues/1119) renamed `firmware.bin` not working in OTA
- [#1143](https://github.com/jomjol/AI-on-the-edge-device/issues/1143) changed postprocess for `analog->digit` (lowest digit processing)
- [#1280](https://github.com/jomjol/AI-on-the-edge-device/issues/1280) check ROIs name for unsupported characters
- [#983](https://github.com/jomjol/AI-on-the-edge-device/issues/983) old log files did not get deleted
- Failed NTP time sync during startup gets now retried every round if needed
- Whitespaces and `=` in MQTT and InfluxDB passwords
- Various minor fixes and improvements
- NEW v13.0.2: Corrected Version comparison between firmware and Web UI.
- NEW v13.0.3: Re-updated build environment to v5.2.0 (from accidental downgrad to v4.4.0)
- NEW v13.0.4: Fix for reboot in case of MQTT not used
- NEW v13.0.5: No reboot in case of missing NTP-connection
- NEW v13.0.7:
- Prevent autoreboot on cam framebuffer init error
- Properly protect `wlan.ini` against deletion
- Fixed various MQTT topic content issues
- Fix Digit detected as 10 (<https://github.com/jomjol/AI-on-the-edge-device/pull/1525>)
- Fix frozen time in datafile on error
- Various minor fixes
- **NEW v13.0.8**:
- Fix Rate Problem ([#1578](https://github.com/jomjol/AI-on-the-edge-device/issues/1578), [#1572](https://github.com/jomjol/AI-on-the-edge-device/issues/1572))
- Stabilized MQTT
- Fixed redundant calls in OTA
- Block REST API calls till resource is ready
- Fixed number renaming ([#1635](https://github.com/jomjol/AI-on-the-edge-device/issues/1635))
### Removed
- n.a.
## [12.0.1] 2022-09-29
Improve **u**ser e**x**perience
:bangbang: The release breaks a few things in ota update :bangbang:
**Make sure to read the instructions below carfully!**.
1. Backup your configuration (use the `System > Backup/Restore` page)!
2. You should update to `11.3.1` before you update to this release. All other migrations are not tested.
1. Backup your configuration (use the `System > Backup/Restore` page)!
2. You should update to `11.3.1` before you update to this release. All other migrations are not tested.
Rolling newer than `11.3.1` can also be used, but no guaranty.
3. Upload and update the `firmware.bin` file from this release. **but do not reboot**
4. Upload the `html-from-11.3.1.zip` in html upload and update the web interface.
5. Now you can reboot.
3. Upload and update the `firmware.bin` file from this release. **but do not reboot**
4. Upload the `html-from-11.3.1.zip` in html upload and update the web interface.
5. Now you can reboot.
If anything bricks you can try to
1. Call `http://<IP>/ota?task=update&file=firmware.bin` resp. `http://<IP>/ota?task=update&file=html.zip` if the upload successed but the extraction failed.
1. Use the initial_esp32_setup.zip ( <https://github.com/jomjol/AI-on-the-edge-device/wiki/Installation> ) as alternative.
If anything breaks you can try to
1\. Call `http://<IP>/ota?task=update&file=firmware.bin` resp. `http://<IP>/ota?task=update&file=html.zip` if the upload successed but the extraction failed.
1\. Use the initial_esp32_setup.zip ( <https://github.com/jomjol/AI-on-the-edge-device/wiki/Installation> ) as alternative.
### Added
- Automatic release creation
- Newest firmware of rolling branch now automatically build and provided in [Github Actions Output](https://github.com/jomjol/AI-on-the-edge-device/actions) (developers only)
- [\#1068](https://github.com/jomjol/AI-on-the-edge-device/issues/1068) New update mechanism:
- Handling of all files (`zip`, `tfl`, `tflite`, `bin`) within in one common update interface
- Using the `update.zip` from the [Release page](https://github.com/jomjol/AI-on-the-edge-device/releases)
- Status (`upload`, `processing`, ...) displayed on Web Interface
- Automatical detection and suggestion for reboot where needed (Web Interface uupdates only need a page refresh)
- :bangbang: Best for OTA use Firefox. Chrome works with warnings. Safari stuck in upload.
- Automatic release creation
- Newest firmware of rolling branch now automatically build and provided in [Github Actions Output](https://github.com/jomjol/AI-on-the-edge-device/actions) (developers only)
- [#1068](https://github.com/jomjol/AI-on-the-edge-device/issues/1068) New update mechanism:
- Handling of all files (`zip`, `tfl`, `tflite`, `bin`) within in one common update interface
- Using the `update.zip` from the [Release page](https://github.com/jomjol/AI-on-the-edge-device/releases)
- Status (`upload`, `processing`, ...) displayed on Web Interface
- Automatical detection and suggestion for reboot where needed (Web Interface uupdates only need a page refresh)
- :bangbang: Best for OTA use Firefox. Chrome works with warnings. Safari stuck in upload.
### Changed
- Integrated version info better shown on the Info page and in the log
- Updated menu
- Update used libraries (`tflite`, `esp32-cam`, `esp-nn`, as of 20220924)
- Integrated version info better shown on the Info page and in the log
- Updated menu
- Update used libraries (`tflite`, `esp32-cam`, `esp-nn`, as of 20220924)
### Fixed
- [\#1092](https://github.com/jomjol/AI-on-the-edge-device/issues/1092) censor passwords in log outputs
- [\#1029](https://github.com/jomjol/AI-on-the-edge-device/issues/1029) wrong change of `checkDigitConsistency` now working like releases before `11.3.1`
- Spelling corrections (**[cristianmitran](https://github.com/cristianmitran)**)
- [#1092](https://github.com/jomjol/AI-on-the-edge-device/issues/1092) censor passwords in log outputs
- [#1029](https://github.com/jomjol/AI-on-the-edge-device/issues/1029) wrong change of `checkDigitConsistency` now working like releases before `11.3.1`
- Spelling corrections (**[cristianmitran](https://github.com/cristianmitran)**)
### Removed
- Remove the folder `/firmware` from GitHub repository.
If you want to get the latest `firmware.bin` and `html.zip` files, please download from the automated [build action](https://github.com/jomjol/AI-on-the-edge-device/actions) or [release page](https://github.com/jomjol/AI-on-the-edge-device/releases)
## [11.3.1] - (2022-09-17)
- Remove the folder `/firmware` from GitHub repository.
If you want to get the latest `firmware.bin` and `html.zip` files, please download from the automated [build action](https://github.com/jomjol/AI-on-the-edge-device/actions) or [release page](https://github.com/jomjol/AI-on-the-edge-device/releases)
## [11.3.1](https://github.com/jomjol/AI-on-the-edge-device/releases/tag/v11.3.1), 2022-09-17
Intermediate Digits
- **ATTENTION**:
- first update the `firmware.bin` and ensure that the new version is running
- **ATTENTION**:
- Only afterwards update the `html.zip`
- Otherwise the downwards compatibility of the new counter clockwise feature is not given and you end in a reboot loop, that needs manual flashing!
- first update the `firmware.bin` and ensure that the new version is running
- Only afterwards update the `html.zip`
- Otherwise the downwards compatibility of the new counter clockwise feature is not given and you end in a reboot loop, that needs manual flashing!
- **NEW v11.3.1**: corrected corrupted asset `firmware.bin`
- Increased precision (more than 6-7 digits)
- Implements Counter Clockwise Analog Pointers
- Improved post processing algorithm
- Debugging: intensive use of testcases
- MQTT: improved handling, extended logging, automated reconnect
- HTML: Backup Option for Configuration
- HTML: Improved Reboot
- HTML: Update WebUI (Reboot, Infos, CPU Temp, RSSI)
- This version is largely also based on the work of **[caco3](https://github.com/caco3)**, **[adellafave](https://github.com/adellafave)**, **[haverland](https://github.com/haverland)**, **[stefanbode](https://github.com/stefanbode)**, **[PLCHome](https://github.com/PLCHome)**
- **NEW v11.3.1**: corrected corrupted asset `firmware.bin`
- Increased precision (more than 6-7 digits)
- Implements Counter Clockwise Analog Pointers
- Improved post processing algorithm
- Debugging: intensive use of testcases
- MQTT: improved handling, extended logging, automated reconnect
- HTML: Backup Option for Configuration
- HTML: Improved Reboot
- HTML: Update WebUI (Reboot, Infos, CPU Temp, RSSI)
- This version is largely also based on the work of **[caco3](https://github.com/caco3)**, **[adellafave](https://github.com/adellafave)**, **[haverland](https://github.com/haverland)**, **[stefanbode](https://github.com/stefanbode)**, **[PLCHome](https://github.com/PLCHome)**
## [11.2.0](https://github.com/jomjol/AI-on-the-edge-device/releases/tag/v11.2.0), 2022-08-28
## [11.2.0] - (2022-08-28)
Intermediate Digits
- Updated Tensorflow / TFlite to newest tflite (version as of 2022-07-27)
- Updated analog neural network file (`ana-cont_11.3.0_s2.tflite` - default, `ana-class100_0120_s1_q.tflite`)
- Updated digital neural network file (`dig-cont_0570_s3.tflite` - default, `dig-class100_0120_s2_q.tflite`)
- Updated Tensorflow / TFlite to newest tflite (version as of 2022-07-27)
- Added automated filtering of tflite-file in the graphical configuration (thanks to @**[caco3](https://github.com/caco3)**)
- Updated consistency algorithm & test cases
- HTML: added favicon and system name, Improved reboot dialog (thanks to @**[caco3](https://github.com/caco3)**)
- Updated analog neural network file (`ana-cont_11.3.0_s2.tflite` - default, `ana-class100_0120_s1_q.tflite`)
- Updated digital neural network file (`dig-cont_0570_s3.tflite` - default, `dig-class100_0120_s2_q.tflite`)
- Added automated filtering of tflite-file in the graphical configuration (thanks to @**[caco3](https://github.com/caco3)**)
- Updated consistency algorithm & test cases
- HTML: added favicon and system name, Improved reboot dialog (thanks to @**[caco3](https://github.com/caco3)**)
## [11.1.1](https://github.com/jomjol/AI-on-the-edge-device/releases/tag/v11.1.1), 2022-08-22
## [11.1.1] - (2022-08-22)
Intermediate Digits
- New and improved consistency check (especially with analog and digital counters mixed)
- Bug Fix: digital counter algorithm
- New and improved consistency check (especially with analog and digital counters mixed)
- Bug Fix: digital counter algorithm
## [11.0.1](https://github.com/jomjol/AI-on-the-edge-device/releases/tag/v11.0.1), 2022-08-18
## [11.0.1] - (2022-08-18)
Intermediate Digits
- **NEW v11.0.1**: Bug Fix InfluxDB configuration (only update of html.zip necessary)
- **NEW v11.0.1**: Bug Fix InfluxDB configuration (only update of html.zip necessary)
- Implementation of new CNN types to detect intermediate values of digits with rolling numbers
- Implementation of new CNN types to detect intermediate values of digits with rolling numbers
- By default the old algo (0, 1, ..., 9, "N") is active (due to the limited types of digits trained so far)
- Activation can be done by selection a tflite file with the new trained model in the 'config.ini'
- **Details can be found in the [wiki](https://github.com/jomjol/AI-on-the-edge-device/wiki/Neural-Network-Types)** (different types, trained image types, naming convention)
- By default the old algo (0, 1, ..., 9, "N") is active (due to the limited types of digits trained so far)
- Activation can be done by selection a tflite file with the new trained model in the 'config.ini'
- **Details can be found in the [wiki](https://github.com/jomjol/AI-on-the-edge-device/wiki/Neural-Network-Types)** (different types, trained image types, naming convention)
- Updated neural network files (and adaption to new naming convention)
- Updated neural network files (and adaption to new naming convention)
- Published a tool to download and combine log files - **Thanks to **
- Published a tool to download and combine log files - **Thanks to **
- Files see ['/tools/logfile-tool'](tbd), How-to see [wiki](https://github.com/jomjol/AI-on-the-edge-device/wiki/Gasmeter-Log-Downloader)
- Files see ['/tools/logfile-tool'](tbd), How-to see [wiki](https://github.com/jomjol/AI-on-the-edge-device/wiki/Gasmeter-Log-Downloader)
- Bug Fix: InfluxDB enabling in grahic configuration
- Bug Fix: InfluxDB enabling in grahic configuration
## [10.6.2] - (2022-07-24)
## [10.6.2](https://github.com/jomjol/AI-on-the-edge-device/releases/tag/v10.6.2), 2022-07-24
Stability Increase
@@ -135,7 +272,7 @@ Stability Increase
- Bug Fix: no time with fixed IP, Postprocessing, MQTT
## [10.5.2] - (2022-02-22)
## [10.5.2](https://github.com/jomjol/AI-on-the-edge-device/releases/tag/v10.5.2), 2022-02-22
Stability Increase
@@ -148,7 +285,7 @@ Stability Increase
- Refactoring of check postprocessing consistency (e.g. max rate, negative rate, ...)
- Bug Fix: corrected error in "Check Consistency Increase"
## [10.4.0] - (2022-02-12)
## [10.4.0](https://github.com/jomjol/AI-on-the-edge-device/releases/tag/v10.4.0), 2022-02-12
Stability Increase
@@ -660,7 +797,19 @@ External Illumination
- Initial Version
[Unreleased]: https://github.com/haverland/AI-on-the-edge-device/compare/11.4.3...HEAD
[Unreleased]: https://github.com/jomjol/AI-on-the-edge-device/compare/13.0.8...HEAD
[13.0.8]: https://github.com/jomjol/AI-on-the-edge-device/compare/12.0.1...13.0.8
[13.0.7]: https://github.com/jomjol/AI-on-the-edge-device/compare/12.0.1...13.0.7
[13.0.5]: https://github.com/jomjol/AI-on-the-edge-device/compare/12.0.1...13.0.5
[13.0.4]: https://github.com/jomjol/AI-on-the-edge-device/compare/12.0.1...13.0.4
[13.0.1]: https://github.com/jomjol/AI-on-the-edge-device/compare/12.0.1...13.0.1
[12.0.1]: https://github.com/jomjol/AI-on-the-edge-device/compare/11.3.1...12.0.1
[11.4.3]: https://github.com/haverland/AI-on-the-edge-device/compare/10.6.2...11.4.3

View File

@@ -10,6 +10,36 @@
____
#### #34 implement state and Roi for water leak detection
for example see Roi on the next picture..
![grafik](https://user-images.githubusercontent.com/38385805/207858812-2a6ba41d-1a8c-4fa1-9b6a-53cdd113c106.png)
in case of position change between the measurments set this state to true, if there is no change set it back to false.
In a defined time window this movement can lead into an alarm state / water leak..
haveing this state in the mqtt broker can trigger functions like closing the ater pipe walve and so on...
#### #33 Implement MATTER protocoll
* see [#1404](https://github.com/jomjol/AI-on-the-edge-device/issues/1404)
#### #32 Add feature to correct misinterpreted value
* If a value is misinterpreted, the user can manually correct the value.
* The misinterpreted ROIs would be saved in a "training data" -folder on the SD-card
* Stretch goal: make sending of saved training data as easy as pushing a button =)
#### #31 Implement InfluxDB v2.x interface
* Currently only InfluxDB v1.x is supportet, extend to v2.x
* Remark: interface has changed
* see [#1160](https://github.com/jomjol/AI-on-the-edge-device/issues/1160)
#### #30 Support meter clock over
* In case of meter clocking over, that is, reaching its max. value and starting over from 0,
accept the new value and calculate correctly the difference.
(see line 739 onwards in ClassFlowPostProcessing.cpp)
#### ~~#29 Add favicon and use the hostname for the website~~- implemented v11.3.1

172
README.md
View File

@@ -1,21 +1,26 @@
# 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**.
This projects allows you to digitalize your **analoge** water, gas, power and other meters using cheap and easily available hardware.
All you need is an [ESP32 board with a supported camera](https://github.com/jomjol/AI-on-the-edge-device/wiki/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 a bit of a practical hand.
<img src="images/esp32-cam.png" width="200">
<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 for administration and control
- Web surface to administrate and control
- OTA-Interface to update directly through the web interface
- API for easy integration
- Inline Image processing (feature detection, alignment, ROI extraction)
- Tensorflow Lite (TFlite) integration - including easy to use wrapper
- Full integration into Homeassistant
- Support for Influx DB 1
- MQTT
- REST API
## Workflow
The device takes a photo of your meter at a defined interval. It then extracts the Regions of Interest (ROI's) out of it and runs them through an artificial inteligence. As a result, you get the digitalized value of your meter.
@@ -36,25 +41,35 @@ There are several options what to do with that value. Either send it to a MQTT b
## Setup
There is a growing [wiki](https://github.com/jomjol/AI-on-the-edge-device/wiki) which provides you with a lot of information.
There is a growing [documentation](https://jomjol.github.io/AI-on-the-edge-device-docs/) which provides you with a lot of information.
Head there to get a start, set it up and configure it.
There are also a articles in the German Heise magazine "make:" about the setup and the technical background (!not for free!)
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)
* [DIY - Setup](https://www.heise.de/select/make/2021/2/2103513300897420296)
* Background [Neural Networks](https://www.heise.de/select/make/2021/6/2126410443385102621), [Training Neural Networks](https://www.heise.de/select/make/2022/1/2134114065999161585) and [Programming on the ESP32](https://www.heise.de/select/make/2022/2/2204010051597422030)
For further background information, head to [Neural Networks](https://www.heise.de/select/make/2021/6/2126410443385102621), [Training Neural Networks](https://www.heise.de/select/make/2022/1/2134114065999161585) and [Programming on the ESP32](https://www.heise.de/select/make/2022/2/2204010051597422030)
## Download
### Download
The latest available version is available on the [Releases page](https://github.com/jomjol/AI-on-the-edge-device/releases).
Initially you will have to flash it through an USB connection. Later an update is possible directly over the Air (OTA).
### 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).
### Casing
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)
- Flash Tool from Espressif
- ESPtool (Command Line Tool)
See the [Docu](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.
## Casing
A 3d-printable housing can be found here:
- https://www.thingiverse.com/thing:4573481 (Water Meter)
- https://www.thingiverse.com/thing:5028229 (Power Meter)
- https://www.thingiverse.com/thing:5224101 (Gas Meter)
- https://www.thingiverse.com/thing:4571627 (ESP32-Cam housing only)
## Build it yourself
@@ -68,141 +83,20 @@ If you would like to support the developer with a cup of coffee you can do that
<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 file a issue in this repository.
If you have any technical topics, you can create an [Issue](https://github.com/jomjol/AI-on-the-edge-device/issues).
In other cases you can contact the developer via email: <img src="https://raw.githubusercontent.com/jomjol/AI-on-the-edge-device/master/images/mail.jpg" height="25">
## Changelog
**General remark:** Besides the file `firmware.bin`, typically the content of `/html` will need to be updated!
------
##### Rolling (2022-09-27)
- Internal improvements
- Bug fix: html update page
##### Rolling (2022-09-24)
- Updated menue
- Update tflite, esp32-cam-master, esp-nn (as of today 20220924)
##### Rolling (2022-09-21)
- Spelling corrections (**[cristianmitran](https://github.com/cristianmitran)**)
##### Rolling (2022-09-21)
- New update mechanism:
- handling of all files (zip, tfl, tflite, bin) within in one updload
- status (upload, processing, ...) displayed
- auto suggestion for reboot (or not in case of web ui update only)
##### Rolling (2022-09-19)
- Integrated version info better into the html (main page, logfile)
- Updated autobuild
- Remove `/firmware` from GitHub.
- If you want to get the latest firmware and html files, please download from the automated build action.
##### Rolling (2022-09-18)
- Updated PostProcessing with respect to `CheckDigitIncreaseConsistency`
##### 11.3.1 - Intermediate Digits (2022-09-17)
- **ATTENTION**:
- first update the 'firmware.bin' and ensure that the new version is running
- Only afterwards update the 'html.zip'
- Otherwise the downwards compatibility of the new counter clockwise feature is not given and you end in a reboot loop, that needs manual flashing!
- **NEW v11.3.1**: corrected corrupted asset `firmware.bin`
- Increased precision (more than 6-7 digits)
- Implements Counter Clockwise Analog Pointers
- Improved post processing algorithm
- Debugging: intensive use of testcases
- MQTT: improved handling, extended logging, automated reconnect
- HTML: Backup Option for Configuration
- HTML: Improved Reboot
- HTML: Update WebUI (Reboot, Infos, CPU Temp, RSSI)
- This version is largely also based on the work of **[caco3](https://github.com/caco3)**, **[adellafave](https://github.com/adellafave)**, **[haverland](https://github.com/haverland)**, **[stefanbode](https://github.com/stefanbode)**, **[PLCHome](https://github.com/PLCHome)**
##### 11.2.0 - Intermediate Digits (2022-08-28)
- Updated Tensorflow / TFlite to newest tflite (version as of 2022-07-27)
- Updated analog neural network file (`ana-cont_11.3.0_s2.tflite` - default, `ana-class100_0120_s1_q.tflite`)
- Updated digital neural network file (`dig-cont_0570_s3.tflite` - default, `dig-class100_0120_s2_q.tflite`)
- Added automated filtering of tflite-file in the graphical configuration (thanks to @**[caco3](https://github.com/caco3)**)
- Updated consistency algorithm & test cases
- HTML: added favicon and system name, Improved reboot dialog (thanks to @**[caco3](https://github.com/caco3)**)
##### 11.1.1 - Intermediate Digits (2022-08-22)
- New and improved consistency check (especially with analog and digital counters mixed)
- Bug Fix: digital counter algorithm
##### 11.0.1 - Intermediate Digits (2022-08-18)
- **NEW v11.0.1**: Bug Fix InfluxDB configuration (only update of html.zip necessary)
- Implementation of new CNN types to detect intermediate values of digits with rolling numbers
- By default the old algo (0, 1, ..., 9, "N") is active (due to the limited types of digits trained so far)
- Activation can be done by selection a tflite file with the new trained model in the 'config.ini'
- **Details can be found in the [wiki](https://github.com/jomjol/AI-on-the-edge-device/wiki/Neural-Network-Types)** (different types, trained image types, naming convention)
- Updated neural network files (and adaption to new naming convention)
- Published a tool to download and combine log files - **Thanks to **
- Files see ['/tools/logfile-tool'](tbd), How-to see [wiki](https://github.com/jomjol/AI-on-the-edge-device/wiki/Gasmeter-Log-Downloader)
- Bug Fix: InfluxDB enabling in grahic configuration
## Changes and History
See [Changelog](Changelog.md)
## Tools
* Logfile downloader and combiner (Thx to [reserve85](https://github.com/reserve85))
* Files see ['/tools/logfile-tool'](tbd), How-to see [wiki](https://github.com/jomjol/AI-on-the-edge-device/wiki/Gasmeter-Log-Downloader)
* Files see ['/tools/logfile-tool'](tbd), How-to see [Docu](https://jomjol.github.io/AI-on-the-edge-device-docs/outdated--Gasmeter-Log-Downloader/)
## Additional Ideas
There are some ideas and feature requests which are not followed currently - mainly due to capacity reasons on side of the developer. They are collected here: [FeatureRequest.md](FeatureRequest.md)
------
## History
##### 10.6.2 - Stability Increase (2022-07-24)
##### 9.2.0 - External Illumination (2021-12-02)
##### 8.5.0 Multi Meter Support (2021-10-07)
##### 7.1.2 MQTT-Update - (2021-06-17)
##### 6.7.2 Image Processing in Memory - (2021-05-01)
##### 5.0.0 Setup Modus - (2020-12-06)
##### 4.1.1 Configuration editor - (2020-12-02)
##### 4.0.0 Tflite Core - (2020-11-15)
##### 3.1.0 MQTT-Client - (2020-10-26)
##### 2.2.1 Version Control - (2020-09-27)
##### 2.1.0 Decimal Shift, Chrome & Edge - (2020-09-25)
##### 2.0.0 Layout update - (2020-09-12)
##### 1.1.3 Initial Version - (2020-09-09)
#### [Full Changelog](Changelog.md)

8
code/.gitignore vendored
View File

@@ -5,3 +5,11 @@
.vscode/ipch
version.cpp
sdkconfig.esp32cam
sdkconfig.esp32cam-dev
sdkconfig.esp32cam-debug
sdkconfig.esp32cam-board-rev3
sdkconfig.esp32cam-cpu-freq-240
sdkconfig.esp32cam-board-rev3-cpu-freq-240
sdkconfig.esp32cam-dev-himem
sdkconfig.esp32cam-dev-task-analysis
sdkconfig.esp32cam-no-softap

View File

@@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.13.4)
cmake_minimum_required(VERSION 3.16.0)
list(APPEND EXTRA_COMPONENT_DIRS $ENV{IDF_PATH}/examples/common_components/protocol_examples_common components/tflite-micro-esp-examples/components/tflite-lib)
@@ -8,6 +8,15 @@ ADD_CUSTOM_COMMAND(
COMMAND ${CMAKE_COMMAND} -P
${CMAKE_CURRENT_SOURCE_DIR}/version.cmake)
if(EXISTS "${SDKCONFIG}.defaults")
if(EXISTS "sdkconfig.defaults")
set(SDKCONFIG_DEFAULTS "${SDKCONFIG}.defaults;sdkconfig.defaults")
message(STATUS "-- Using defaults: ${SDKCONFIG_DEFAULTS} + sdkconfig.defaults")
else()
set(SDKCONFIG_DEFAULTS "${SDKCONFIG}.defaults")
endif()
message(STATUS "-- Using defaults: ${SDKCONFIG_DEFAULTS}")
endif()
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(esp32cam-server-only)
project(AI-on-the-edge)

View File

@@ -18,16 +18,14 @@ platformio run --environment esp32cam
### Upload
```
pio run --target upload
pio run --target upload --upload-port /dev/ttyUSB0
```
If it doesnt find the device:
1. make sure it is in bootloader mode
1. set the UART device correctly: In `platformio.ini`, set `upload_port` correctly, eg. `upload_port = /dev/ttyUSB0`
Alternatively you also can set the UART device in `platformio.ini`, eg. `upload_port = /dev/ttyUSB0`
### Monitor UART Log
```
pio device monitor
pio device monitor -p /dev/ttyUSB0
```
## Build and Flash with Visual Code IDE

View File

@@ -4,13 +4,16 @@
#include "Helper.h"
#include "configFile.h"
#include <esp_log.h>
//static const char *TAGCONFIGFILE = "configFile";
#include "../../include/defines.h"
static const char *TAG = "CONFIG";
ConfigFile::ConfigFile(std::string filePath)
{
std::string config = FormatFileName(filePath);
pFile = OpenFileAndWait(config.c_str(), "r");
pFile = fopen(config.c_str(), "r");
}
ConfigFile::~ConfigFile()
@@ -48,7 +51,7 @@ bool ConfigFile::getNextLine(std::string *rt, bool &disabled, bool &eof)
if (fgets(zw, 1024, pFile))
{
printf("%s", zw);
ESP_LOGD(TAG, "%s", zw);
if ((strlen(zw) == 0) && feof(pFile))
{
*rt = "";
@@ -64,10 +67,10 @@ bool ConfigFile::getNextLine(std::string *rt, bool &disabled, bool &eof)
}
*rt = zw;
*rt = trim(*rt);
while ((zw[0] == ';' || zw[0] == '#' || (rt->size() == 0)) && !(zw[1] == '[')) // Kommentarzeilen (; oder #) und Leerzeilen überspringen, es sei denn es ist ein neuer auskommentierter Paragraph
while ((zw[0] == ';' || zw[0] == '#' || (rt->size() == 0)) && !(zw[1] == '['))
{
fgets(zw, 1024, pFile);
printf("%s", zw);
ESP_LOGD(TAG, "%s", zw);
if (feof(pFile))
{
*rt = "";
@@ -81,25 +84,3 @@ bool ConfigFile::getNextLine(std::string *rt, bool &disabled, bool &eof)
disabled = ((*rt)[0] == ';');
return true;
}
std::vector<string> ConfigFile::ZerlegeZeile(std::string input, std::string delimiter)
{
std::vector<string> Output;
// std::string delimiter = " =,";
input = trim(input, delimiter);
size_t pos = findDelimiterPos(input, delimiter);
std::string token;
while (pos != std::string::npos) {
token = input.substr(0, pos);
token = trim(token, delimiter);
Output.push_back(token);
input.erase(0, pos + 1);
input = trim(input, delimiter);
pos = findDelimiterPos(input, delimiter);
}
Output.push_back(input);
return Output;
}

View File

@@ -1,3 +1,8 @@
#pragma once
#ifndef CONFIGFILE_H
#define CONFIGFILE_H
#include <string>
#include <vector>
@@ -9,8 +14,10 @@ public:
bool isNewParagraph(std::string input);
bool GetNextParagraph(std::string& aktparamgraph, bool &disabled, bool &eof);
bool getNextLine(std::string* rt, bool &disabled, bool &eof);
std::vector<std::string> ZerlegeZeile(std::string input, std::string delimiter = " =, \t");
bool ConfigFileExists(){return pFile;};
private:
FILE* pFile;
};
};
#endif //CONFIGFILE_H

View File

@@ -1,5 +1,8 @@
#pragma once
#ifndef COLOR_H
#define COLOR_H
#include <cstdint>
#include "esp_attr.h"
union Hsv;
@@ -67,3 +70,5 @@ union Hsv {
bool operator==( Hsv in ) const { return in.value == value; }
void swap( Hsv& o ) { value = o.value; }
};
#endif //COLOR_H

View File

@@ -1,5 +1,8 @@
#pragma once
#ifndef SMARTLEDS_H
#define SMARTLEDS_H
/*
* A C++ driver for the WS2812 LEDs using the RMT peripheral on the ESP32.
*
@@ -528,3 +531,5 @@ private:
int _latchFrames;
uint8_t _latchBuffer[ LATCH_FRAME_SIZE_BYTES ];
};
#endif //SMARTLEDS_H

View File

@@ -10,28 +10,26 @@
#include "server_tflite.h"
//#define LOG_LOCAL_LEVEL ESP_LOG_DEBUG
#include "esp_log.h"
//#include "errno.h"
#include <sys/stat.h>
#include <vector>
//#include <regex>
#include "defines.h"
#include "../../include/defines.h"
#include "server_GPIO.h"
#include "ClassLogFile.h"
#include "configFile.h"
#include "Helper.h"
#include "interface_mqtt.h"
#ifdef ENABLE_MQTT
#include "interface_mqtt.h"
#endif //ENABLE_MQTT
static const char *TAG_SERVERGPIO = "server_GPIO";
static const char *TAG = "GPIO";
QueueHandle_t gpio_queue_handle = NULL;
#define DEBUG_DETAIL_ON
GpioPin::GpioPin(gpio_num_t gpio, const char* name, gpio_pin_mode_t mode, gpio_int_type_t interruptType, uint8_t dutyResolution, std::string mqttTopic, bool httpEnable)
{
_gpio = gpio;
@@ -43,7 +41,7 @@ GpioPin::GpioPin(gpio_num_t gpio, const char* name, gpio_pin_mode_t mode, gpio_i
GpioPin::~GpioPin()
{
ESP_LOGD(TAG_SERVERGPIO,"reset GPIO pin %d", _gpio);
ESP_LOGD(TAG,"reset GPIO pin %d", _gpio);
if (_interruptType != GPIO_INTR_DISABLE) {
//hook isr handler for specific gpio pin
gpio_isr_handler_remove(_gpio);
@@ -66,13 +64,13 @@ static void IRAM_ATTR gpio_isr_handler(void* arg)
}
static void gpioHandlerTask(void *arg) {
ESP_LOGD(TAG_SERVERGPIO,"start interrupt task");
ESP_LOGD(TAG,"start interrupt task");
while(1){
if(uxQueueMessagesWaiting(gpio_queue_handle)){
while(uxQueueMessagesWaiting(gpio_queue_handle)){
GpioResult gpioResult;
xQueueReceive(gpio_queue_handle,(void*)&gpioResult,10);
ESP_LOGD(TAG_SERVERGPIO,"gpio: %d state: %d", gpioResult.gpio, gpioResult.value);
ESP_LOGD(TAG,"gpio: %d state: %d", gpioResult.gpio, gpioResult.value);
((GpioHandler*)arg)->gpioInterrupt(&gpioResult);
}
}
@@ -83,12 +81,14 @@ static void gpioHandlerTask(void *arg) {
}
void GpioPin::gpioInterrupt(int value) {
#ifdef ENABLE_MQTT
if (_mqttTopic != "") {
ESP_LOGD(TAG_SERVERGPIO, "gpioInterrupt %s %d", _mqttTopic.c_str(), value);
ESP_LOGD(TAG, "gpioInterrupt %s %d", _mqttTopic.c_str(), value);
MQTTPublish(_mqttTopic, value ? "true" : "false");
currentState = value;
MQTTPublish(_mqttTopic, value ? "true" : "false");
}
#endif //ENABLE_MQTT
currentState = value;
}
void GpioPin::init()
@@ -110,14 +110,16 @@ void GpioPin::init()
// if (_interruptType != GPIO_INTR_DISABLE) { // ohne GPIO_PIN_MODE_EXTERNAL_FLASH_WS281X, wenn das genutzt wird, dann soll auch der Handler hier nicht initialisiert werden, da das dann über SmartLED erfolgt.
if ((_interruptType != GPIO_INTR_DISABLE) && (_interruptType != GPIO_PIN_MODE_EXTERNAL_FLASH_WS281X)) {
//hook isr handler for specific gpio pin
ESP_LOGD(TAG_SERVERGPIO, "GpioPin::init add isr handler for GPIO %d\r\n", _gpio);
ESP_LOGD(TAG, "GpioPin::init add isr handler for GPIO %d", _gpio);
gpio_isr_handler_add(_gpio, gpio_isr_handler, (void*)&_gpio);
}
#ifdef ENABLE_MQTT
if ((_mqttTopic != "") && ((_mode == GPIO_PIN_MODE_OUTPUT) || (_mode == GPIO_PIN_MODE_OUTPUT_PWM) || (_mode == GPIO_PIN_MODE_BUILT_IN_FLASH_LED))) {
std::function<bool(std::string, char*, int)> f = std::bind(&GpioPin::handleMQTT, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
MQTTregisterSubscribeFunction(_mqttTopic, f);
}
#endif //ENABLE_MQTT
}
bool GpioPin::getValue(std::string* errorText)
@@ -131,30 +133,35 @@ bool GpioPin::getValue(std::string* errorText)
void GpioPin::setValue(bool value, gpio_set_source setSource, std::string* errorText)
{
ESP_LOGD(TAG_SERVERGPIO, "GpioPin::setValue %d\r\n", value);
ESP_LOGD(TAG, "GpioPin::setValue %d", value);
if ((_mode != GPIO_PIN_MODE_OUTPUT) && (_mode != GPIO_PIN_MODE_OUTPUT_PWM) && (_mode != GPIO_PIN_MODE_BUILT_IN_FLASH_LED)) {
(*errorText) = "GPIO is not in output mode";
} else {
gpio_set_level(_gpio, value);
#ifdef ENABLE_MQTT
if ((_mqttTopic != "") && (setSource != GPIO_SET_SOURCE_MQTT)) {
MQTTPublish(_mqttTopic, value ? "true" : "false");
}
#endif //ENABLE_MQTT
}
}
void GpioPin::publishState() {
int newState = gpio_get_level(_gpio);
if (newState != currentState) {
ESP_LOGD(TAG_SERVERGPIO,"publish state of GPIO %d new state %d", _gpio, newState);
ESP_LOGD(TAG,"publish state of GPIO %d new state %d", _gpio, newState);
#ifdef ENABLE_MQTT
MQTTPublish(_mqttTopic, newState ? "true" : "false");
#endif //ENABLE_MQTT
currentState = newState;
}
}
#ifdef ENABLE_MQTT
bool GpioPin::handleMQTT(std::string, char* data, int data_len) {
ESP_LOGD(TAG_SERVERGPIO, "GpioPin::handleMQTT data %.*s\r\n", data_len, data);
ESP_LOGD(TAG, "GpioPin::handleMQTT data %.*s", data_len, data);
std::string dataStr(data, data_len);
dataStr = toLower(dataStr);
@@ -169,16 +176,16 @@ bool GpioPin::handleMQTT(std::string, char* data, int data_len) {
}
if (errorText != "") {
ESP_LOGE(TAG_SERVERGPIO, "%s", errorText.c_str());
ESP_LOGE(TAG, "%s", errorText.c_str());
}
return (errorText == "");
}
#endif //ENABLE_MQTT
esp_err_t callHandleHttpRequest(httpd_req_t *req)
{
ESP_LOGD(TAG_SERVERGPIO,"callHandleHttpRequest");
ESP_LOGD(TAG,"callHandleHttpRequest");
GpioHandler *gpioHandler = (GpioHandler*)req->user_ctx;
return gpioHandler->handleHttpRequest(req);
@@ -186,17 +193,17 @@ esp_err_t callHandleHttpRequest(httpd_req_t *req)
void taskGpioHandler(void *pvParameter)
{
ESP_LOGD(TAG_SERVERGPIO,"taskGpioHandler");
ESP_LOGD(TAG,"taskGpioHandler");
((GpioHandler*)pvParameter)->init();
}
GpioHandler::GpioHandler(std::string configFile, httpd_handle_t httpServer)
{
ESP_LOGI(TAG_SERVERGPIO,"start GpioHandler");
ESP_LOGI(TAG,"start GpioHandler");
_configFile = configFile;
_httpServer = httpServer;
ESP_LOGI(TAG_SERVERGPIO, "register GPIO Uri");
ESP_LOGI(TAG, "register GPIO Uri");
registerGpioUri();
}
@@ -210,10 +217,10 @@ GpioHandler::~GpioHandler() {
void GpioHandler::init()
{
// TickType_t xDelay = 60000 / portTICK_PERIOD_MS;
// printf("wait before start %ldms\r\n", (long) xDelay);
// ESP_LOGD(TAG, "wait before start %ldms", (long) xDelay);
// vTaskDelay( xDelay );
printf("*************** Start GPIOHandler_Init *****************\n");
ESP_LOGD(TAG, "*************** Start GPIOHandler_Init *****************");
if (gpioMap == NULL) {
gpioMap = new std::map<gpio_num_t, GpioPin*>();
@@ -222,12 +229,12 @@ void GpioHandler::init()
}
ESP_LOGI(TAG_SERVERGPIO, "read GPIO config and init GPIO");
ESP_LOGI(TAG, "read GPIO config and init GPIO");
if (!readConfig()) {
clear();
delete gpioMap;
gpioMap = NULL;
ESP_LOGI(TAG_SERVERGPIO, "GPIO init completed, handler is disabled");
ESP_LOGI(TAG, "GPIO init completed, handler is disabled");
return;
}
@@ -236,20 +243,22 @@ void GpioHandler::init()
it->second->init();
}
#ifdef ENABLE_MQTT
std::function<void()> f = std::bind(&GpioHandler::handleMQTTconnect, this);
MQTTregisterConnectFunction("gpio-handler", f);
#endif //ENABLE_MQTT
if (xHandleTaskGpio == NULL) {
gpio_queue_handle = xQueueCreate(10,sizeof(GpioResult));
BaseType_t xReturned = xTaskCreate(&gpioHandlerTask, "gpio_int", configMINIMAL_STACK_SIZE * 8, (void *)this, tskIDLE_PRIORITY + 2, &xHandleTaskGpio);
BaseType_t xReturned = xTaskCreate(&gpioHandlerTask, "gpio_int", 3 * 1024, (void *)this, tskIDLE_PRIORITY + 4, &xHandleTaskGpio);
if(xReturned == pdPASS ) {
ESP_LOGD(TAG_SERVERGPIO, "xHandletaskGpioHandler started");
ESP_LOGD(TAG, "xHandletaskGpioHandler started");
} else {
ESP_LOGD(TAG_SERVERGPIO, "xHandletaskGpioHandler not started %d ", (int)xHandleTaskGpio);
ESP_LOGD(TAG, "xHandletaskGpioHandler not started %d ", (int)xHandleTaskGpio);
}
}
ESP_LOGI(TAG_SERVERGPIO, "GPIO init completed, is enabled");
ESP_LOGI(TAG, "GPIO init completed, is enabled");
}
void GpioHandler::taskHandler() {
@@ -261,7 +270,7 @@ void GpioHandler::taskHandler() {
}
}
#ifdef ENABLE_MQTT
void GpioHandler::handleMQTTconnect()
{
if (gpioMap != NULL) {
@@ -271,9 +280,12 @@ void GpioHandler::handleMQTTconnect()
}
}
}
#endif //ENABLE_MQTT
void GpioHandler::deinit() {
#ifdef ENABLE_MQTT
MQTTunregisterConnectFunction("gpio-handler");
#endif //ENABLE_MQTT
clear();
if (xHandleTaskGpio != NULL) {
vTaskDelete(xHandleTaskGpio);
@@ -294,19 +306,19 @@ bool GpioHandler::readConfig()
ConfigFile configFile = ConfigFile(_configFile);
std::vector<std::string> zerlegt;
std::vector<std::string> splitted;
std::string line = "";
bool disabledLine = false;
bool eof = false;
gpio_num_t gpioExtLED = (gpio_num_t) 0;
// printf("readConfig - Start 1\n");
// ESP_LOGD(TAG, "readConfig - Start 1");
while ((!configFile.GetNextParagraph(line, disabledLine, eof) || (line.compare("[GPIO]") != 0)) && !eof) {}
if (eof)
return false;
// printf("readConfig - Start 2 line: %s, disabbledLine: %d\n", line.c_str(), (int) disabledLine);
// ESP_LOGD(TAG, "readConfig - Start 2 line: %s, disabbledLine: %d", line.c_str(), (int) disabledLine);
_isEnabled = !disabledLine;
@@ -314,52 +326,59 @@ bool GpioHandler::readConfig()
if (!_isEnabled)
return false;
// printf("readConfig - Start 3\n");
// ESP_LOGD(TAG, "readConfig - Start 3");
#ifdef ENABLE_MQTT
// std::string mainTopicMQTT = "";
std::string mainTopicMQTT = GetMQTTMainTopic();
if (mainTopicMQTT.length() > 0)
{
mainTopicMQTT = mainTopicMQTT + "/GPIO";
ESP_LOGD(TAG_SERVERGPIO, "MAINTOPICMQTT found\r\n");
ESP_LOGD(TAG, "MAINTOPICMQTT found");
}
#endif // ENABLE_MQTT
bool registerISR = false;
while (configFile.getNextLine(&line, disabledLine, eof) && !configFile.isNewParagraph(line))
{
zerlegt = configFile.ZerlegeZeile(line);
splitted = ZerlegeZeile(line);
// const std::regex pieces_regex("IO([0-9]{1,2})");
// std::smatch pieces_match;
// if (std::regex_match(zerlegt[0], pieces_match, pieces_regex) && (pieces_match.size() == 2))
// if (std::regex_match(splitted[0], pieces_match, pieces_regex) && (pieces_match.size() == 2))
// {
// std::string gpioStr = pieces_match[1];
ESP_LOGD(TAG_SERVERGPIO, "conf param %s\r\n", toUpper(zerlegt[0]).c_str());
if (toUpper(zerlegt[0]) == "MAINTOPICMQTT") {
// ESP_LOGD(TAG_SERVERGPIO, "MAINTOPICMQTT found\r\n");
// mainTopicMQTT = zerlegt[1];
} else if ((zerlegt[0].rfind("IO", 0) == 0) && (zerlegt.size() >= 6))
ESP_LOGD(TAG, "conf param %s", toUpper(splitted[0]).c_str());
if (toUpper(splitted[0]) == "MAINTOPICMQTT") {
// ESP_LOGD(TAG, "MAINTOPICMQTT found");
// mainTopicMQTT = splitted[1];
} else if ((splitted[0].rfind("IO", 0) == 0) && (splitted.size() >= 6))
{
ESP_LOGI(TAG_SERVERGPIO,"Enable GP%s in %s mode", zerlegt[0].c_str(), zerlegt[1].c_str());
std::string gpioStr = zerlegt[0].substr(2, 2);
ESP_LOGI(TAG,"Enable GP%s in %s mode", splitted[0].c_str(), splitted[1].c_str());
std::string gpioStr = splitted[0].substr(2, 2);
gpio_num_t gpioNr = (gpio_num_t)atoi(gpioStr.c_str());
gpio_pin_mode_t pinMode = resolvePinMode(toLower(zerlegt[1]));
gpio_int_type_t intType = resolveIntType(toLower(zerlegt[2]));
uint16_t dutyResolution = (uint8_t)atoi(zerlegt[3].c_str());
bool mqttEnabled = toLower(zerlegt[4]) == "true";
bool httpEnabled = toLower(zerlegt[5]) == "true";
gpio_pin_mode_t pinMode = resolvePinMode(toLower(splitted[1]));
gpio_int_type_t intType = resolveIntType(toLower(splitted[2]));
uint16_t dutyResolution = (uint8_t)atoi(splitted[3].c_str());
#ifdef ENABLE_MQTT
bool mqttEnabled = toLower(splitted[4]) == "true";
#endif // ENABLE_MQTT
bool httpEnabled = toLower(splitted[5]) == "true";
char gpioName[100];
if (zerlegt.size() >= 7) {
strcpy(gpioName, trim(zerlegt[6]).c_str());
if (splitted.size() >= 7) {
strcpy(gpioName, trim(splitted[6]).c_str());
} else {
sprintf(gpioName, "GPIO%d", gpioNr);
}
#ifdef ENABLE_MQTT
std::string mqttTopic = mqttEnabled ? (mainTopicMQTT + "/" + gpioName) : "";
#else // ENABLE_MQTT
std::string mqttTopic = "";
#endif // ENABLE_MQTT
GpioPin* gpioPin = new GpioPin(gpioNr, gpioName, pinMode, intType,dutyResolution, mqttTopic, httpEnabled);
(*gpioMap)[gpioNr] = gpioPin;
if (pinMode == GPIO_PIN_MODE_EXTERNAL_FLASH_WS281X)
{
printf("Set WS2812 to GPIO %d\n", gpioNr);
ESP_LOGD(TAG, "Set WS2812 to GPIO %d", gpioNr);
gpioExtLED = gpioNr;
}
@@ -367,28 +386,28 @@ bool GpioHandler::readConfig()
registerISR = true;
}
}
if (toUpper(zerlegt[0]) == "LEDNUMBERS")
if (toUpper(splitted[0]) == "LEDNUMBERS")
{
LEDNumbers = stoi(zerlegt[1]);
LEDNumbers = stoi(splitted[1]);
}
if (toUpper(zerlegt[0]) == "LEDCOLOR")
if (toUpper(splitted[0]) == "LEDCOLOR")
{
uint8_t _r, _g, _b;
_r = stoi(zerlegt[1]);
_g = stoi(zerlegt[2]);
_b = stoi(zerlegt[3]);
_r = stoi(splitted[1]);
_g = stoi(splitted[2]);
_b = stoi(splitted[3]);
LEDColor = Rgb{_r, _g, _b};
}
if (toUpper(zerlegt[0]) == "LEDTYPE")
if (toUpper(splitted[0]) == "LEDTYPE")
{
if (zerlegt[1] == "WS2812")
if (splitted[1] == "WS2812")
LEDType = LED_WS2812;
if (zerlegt[1] == "WS2812B")
if (splitted[1] == "WS2812B")
LEDType = LED_WS2812B;
if (zerlegt[1] == "SK6812")
if (splitted[1] == "SK6812")
LEDType = LED_SK6812;
if (zerlegt[1] == "WS2813")
if (splitted[1] == "WS2813")
LEDType = LED_WS2813;
}
}
@@ -400,10 +419,10 @@ bool GpioHandler::readConfig()
if (gpioExtLED > 0)
{
// LogFile.WriteToFile("Startsequence 06"); // Nremove
// LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Startsequence 06"); // Nremove
// vTaskDelay( xDelay );
// xDelay = 5000 / portTICK_PERIOD_MS;
// printf("main: sleep for : %ldms\n", (long) xDelay);
// ESP_LOGD(TAG, "main: sleep for: %ldms", (long) xDelay);
// SmartLed leds( LED_WS2812, 2, GPIO_NUM_12, 0, DoubleBuffer );
@@ -420,7 +439,7 @@ bool GpioHandler::readConfig()
void GpioHandler::clear()
{
ESP_LOGD(TAG_SERVERGPIO, "GpioHandler::clear\r\n");
ESP_LOGD(TAG, "GpioHandler::clear");
if (gpioMap != NULL) {
for(std::map<gpio_num_t, GpioPin*>::iterator it = gpioMap->begin(); it != gpioMap->end(); ++it) {
@@ -434,7 +453,7 @@ void GpioHandler::clear()
void GpioHandler::registerGpioUri()
{
ESP_LOGI(TAG_SERVERGPIO, "server_GPIO - Registering URI handlers");
ESP_LOGI(TAG, "server_GPIO - Registering URI handlers");
httpd_uri_t camuri = { };
camuri.method = HTTP_GET;
@@ -446,7 +465,7 @@ void GpioHandler::registerGpioUri()
esp_err_t GpioHandler::handleHttpRequest(httpd_req_t *req)
{
ESP_LOGD(TAG_SERVERGPIO, "handleHttpRequest");
ESP_LOGD(TAG, "handleHttpRequest");
if (gpioMap == NULL) {
std::string resp_str = "GPIO handler not initialized";
@@ -458,18 +477,18 @@ esp_err_t GpioHandler::handleHttpRequest(httpd_req_t *req)
LogFile.WriteHeapInfo("handler_switch_GPIO - Start");
#endif
LogFile.WriteToFile("handler_switch_GPIO");
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "handler_switch_GPIO");
char _query[200];
char _valueGPIO[30];
char _valueStatus[30];
std::string gpio, status;
if (httpd_req_get_url_query_str(req, _query, 200) == ESP_OK) {
ESP_LOGD(TAG_SERVERGPIO, "Query: %s", _query);
ESP_LOGD(TAG, "Query: %s", _query);
if (httpd_query_key_value(_query, "GPIO", _valueGPIO, 30) == ESP_OK)
{
ESP_LOGD(TAG_SERVERGPIO, "GPIO is found %s", _valueGPIO);
ESP_LOGD(TAG, "GPIO is found %s", _valueGPIO);
gpio = std::string(_valueGPIO);
} else {
std::string resp_str = "GPIO No is not defined";
@@ -478,7 +497,7 @@ esp_err_t GpioHandler::handleHttpRequest(httpd_req_t *req)
}
if (httpd_query_key_value(_query, "Status", _valueStatus, 30) == ESP_OK)
{
ESP_LOGD(TAG_SERVERGPIO, "Status is found %s", _valueStatus);
ESP_LOGD(TAG, "Status is found %s", _valueStatus);
status = std::string(_valueStatus);
}
} else {
@@ -541,7 +560,7 @@ esp_err_t GpioHandler::handleHttpRequest(httpd_req_t *req)
void GpioHandler::flashLightEnable(bool value)
{
ESP_LOGD(TAG_SERVERGPIO, "GpioHandler::flashLightEnable %s\r\n", value ? "true" : "false");
ESP_LOGD(TAG, "GpioHandler::flashLightEnable %s", value ? "true" : "false");
if (gpioMap != NULL) {
for(std::map<gpio_num_t, GpioPin*>::iterator it = gpioMap->begin(); it != gpioMap->end(); ++it)
@@ -552,9 +571,9 @@ void GpioHandler::flashLightEnable(bool value)
it->second->setValue(value, GPIO_SET_SOURCE_INTERNAL, &resp_str);
if (resp_str == "") {
ESP_LOGD(TAG_SERVERGPIO, "Flash light pin GPIO %d switched to %s\r\n", (int)it->first, (value ? "on" : "off"));
ESP_LOGD(TAG, "Flash light pin GPIO %d switched to %s", (int)it->first, (value ? "on" : "off"));
} else {
ESP_LOGE(TAG_SERVERGPIO, "Can't set flash light pin GPIO %d. Error: %s\r\n", (int)it->first, resp_str.c_str());
ESP_LOGE(TAG, "Can't set flash light pin GPIO %d. Error: %s", (int)it->first, resp_str.c_str());
}
} else
{
@@ -562,7 +581,7 @@ void GpioHandler::flashLightEnable(bool value)
{
#ifdef __LEDGLOBAL
if (leds_global == NULL) {
ESP_LOGI(TAG_SERVERGPIO, "init SmartLed: LEDNumber=%d, GPIO=%d", LEDNumbers, (int)it->second->getGPIO());
ESP_LOGI(TAG, "init SmartLed: LEDNumber=%d, GPIO=%d", LEDNumbers, (int)it->second->getGPIO());
leds_global = new SmartLed( LEDType, LEDNumbers, it->second->getGPIO(), 0, DoubleBuffer );
} else {
// wait until we can update: https://github.com/RoboticsBrno/SmartLeds/issues/10#issuecomment-386921623
@@ -673,6 +692,7 @@ void gpio_handler_deinit() {
void gpio_handler_destroy()
{
if (gpioHandler != NULL) {
gpio_handler_deinit();
delete gpioHandler;
gpioHandler = NULL;
}
@@ -682,3 +702,4 @@ GpioHandler* gpio_handler_get()
{
return gpioHandler;
}

View File

@@ -1,3 +1,5 @@
#pragma once
#ifndef SERVER_GPIO_H
#define SERVER_GPIO_H
@@ -9,11 +11,6 @@
#include "SmartLeds.h"
//#include "ClassControllCamera.h"
// wenn __LEDGLOBAL definiert ist, wird eine globale Variable für die LED-Ansteuerung verwendet, ansonsten lokal und jedesmal neu
#define __LEDGLOBAL
typedef enum {
GPIO_PIN_MODE_DISABLED = 0x0,
GPIO_PIN_MODE_INPUT = 0x1,
@@ -45,7 +42,9 @@ public:
void init();
bool getValue(std::string* errorText);
void setValue(bool value, gpio_set_source setSource, std::string* errorText);
#ifdef ENABLE_MQTT
bool handleMQTT(std::string, char* data, int data_len);
#endif //ENABLE_MQTT
void publishState();
void gpioInterrupt(int value);
gpio_int_type_t getInterruptType() { return _interruptType; }
@@ -77,7 +76,9 @@ public:
void gpioInterrupt(GpioResult* gpioResult);
void flashLightEnable(bool value);
bool isEnabled() { return _isEnabled; }
#ifdef ENABLE_MQTT
void handleMQTTconnect();
#endif //ENABLE_MQTT
private:
std::string _configFile;
@@ -109,4 +110,5 @@ GpioHandler* gpio_handler_get();
#endif //SERVER_GPIO_H
#endif //SERVER_GPIO_H

View File

@@ -12,9 +12,7 @@
#include "server_ota.h"
#include "server_GPIO.h"
#define BOARD_ESP32CAM_AITHINKER
#include "../../include/defines.h"
#include <esp_event.h>
#include <esp_log.h>
@@ -28,47 +26,10 @@
#include "esp_camera.h"
// #define DEBUG_DETAIL_ON
#include "driver/ledc.h"
#include "server_tflite.h"
#define USE_PWM_LEDFLASH
#ifdef USE_PWM_LEDFLASH
//// PWM für Flash-LED
#define LEDC_TIMER LEDC_TIMER_1 // LEDC_TIMER_0
#define LEDC_MODE LEDC_LOW_SPEED_MODE
#define LEDC_OUTPUT_IO (4) // Define the output GPIO
#define LEDC_CHANNEL LEDC_CHANNEL_1
#define LEDC_DUTY_RES LEDC_TIMER_13_BIT // Set duty resolution to 13 bits
//#define LEDC_DUTY (195) // Set duty to 50%. ((2 ** 13) - 1) * 50% = 4095
#define LEDC_FREQUENCY (5000) // Frequency in Hertz. Set frequency at 5 kHz
#endif
// ESP32Cam (AiThinker) PIN Map
#define CAM_PIN_PWDN 32
#define CAM_PIN_RESET -1 //software reset will be performed
#define CAM_PIN_XCLK 0
#define CAM_PIN_SIOD 26
#define CAM_PIN_SIOC 27
#define CAM_PIN_D7 35
#define CAM_PIN_D6 34
#define CAM_PIN_D5 39
#define CAM_PIN_D4 36
#define CAM_PIN_D3 21
#define CAM_PIN_D2 19
#define CAM_PIN_D1 18
#define CAM_PIN_D0 5
#define CAM_PIN_VSYNC 25
#define CAM_PIN_HREF 23
#define CAM_PIN_PCLK 22
static const char *TAGCAMERACLASS = "server_part_camera";
static const char *TAG = "CAM";
static camera_config_t camera_config = {
.pin_pwdn = CAM_PIN_PWDN,
@@ -90,8 +51,8 @@ static camera_config_t camera_config = {
.pin_pclk = CAM_PIN_PCLK,
//XCLK 20MHz or 10MHz for OV2640 double FPS (Experimental)
.xclk_freq_hz = 20000000, // Orginalwert
// .xclk_freq_hz = 5000000, // Test, um die Bildfehler los zu werden !!!! Hängt in Version 9.2 !!!!
.xclk_freq_hz = 20000000, // Orginal value
// .xclk_freq_hz = 5000000, // Test to get rid of the image errors !!!! Hangs in version 9.2 !!!!
.ledc_timer = LEDC_TIMER_0,
.ledc_channel = LEDC_CHANNEL_0,
@@ -101,18 +62,16 @@ static camera_config_t camera_config = {
.jpeg_quality = 12, //0-63 lower number means higher quality
.fb_count = 1, //if more than one, i2s runs in continuous mode. Use only with JPEG
.fb_location = CAMERA_FB_IN_PSRAM, /*!< The location where the frame buffer will be allocated */
// .grab_mode = CAMERA_GRAB_WHEN_EMPTY,
.grab_mode = CAMERA_GRAB_LATEST, // erst ab neuer esp32cam-version
.grab_mode = CAMERA_GRAB_LATEST, // only from new esp32cam version
};
#include "driver/ledc.h"
CCamera Camera;
#define FLASH_GPIO GPIO_NUM_4
#define BLINK_GPIO GPIO_NUM_33
uint8_t *demoImage = NULL; // Buffer holding the demo image in bytes
#define DEMO_IMAGE_SIZE 30000 // Max size of demo image in bytes
typedef struct {
httpd_req_t *req;
@@ -120,6 +79,21 @@ typedef struct {
} jpg_chunking_t;
bool CCamera::testCamera(void) {
bool success;
camera_fb_t *fb = esp_camera_fb_get();
if (fb) {
success = true;
}
else {
success = false;
}
esp_camera_fb_return(fb);
return success;
}
void CCamera::ledc_init(void)
{
#ifdef USE_PWM_LEDFLASH
@@ -164,6 +138,7 @@ static size_t jpg_encode_stream(void * arg, size_t index, const void* data, size
return len;
}
bool CCamera::SetBrightnessContrastSaturation(int _brightness, int _contrast, int _saturation)
{
bool result = false;
@@ -221,50 +196,27 @@ void CCamera::SetQualitySize(int qual, framesize_t resol)
image_height = 480;
image_width = 640;
}
// No higher Mode than VGA, damit der Kameraspeicher ausreicht.
/*
if (resol == FRAMESIZE_SVGA)
{
image_height = 600;
image_width = 800;
}
if (resol == FRAMESIZE_XGA)
{
image_height = 768;
image_width = 1024;
}
if (resol == FRAMESIZE_SXGA)
{
image_height = 1024;
image_width = 1280;
}
if (resol == FRAMESIZE_UXGA)
{
image_height = 1200;
image_width = 1600;
}
*/
}
void CCamera::EnableAutoExposure(int flashdauer)
void CCamera::EnableAutoExposure(int flash_duration)
{
printf("EnableAutoExposure");
ESP_LOGD(TAG, "EnableAutoExposure");
LEDOnOff(true);
if (flashdauer > 0)
if (flash_duration > 0)
LightOnOff(true);
const TickType_t xDelay = flashdauer / portTICK_PERIOD_MS;
const TickType_t xDelay = flash_duration / portTICK_PERIOD_MS;
vTaskDelay( xDelay );
camera_fb_t * fb = esp_camera_fb_get();
esp_camera_fb_return(fb);
fb = esp_camera_fb_get();
if (!fb) {
ESP_LOGE(TAGCAMERACLASS, "Camera Capture Failed");
ESP_LOGE(TAG, "Camera Capture Failed");
LEDOnOff(false);
LightOnOff(false);
LogFile.SwitchOnOff(true);
LogFile.WriteToFile("Camera Capture Failed (Procedure 'EnableAutoExposure') --> Reboot"
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Capture Failed (Procedure 'EnableAutoExposure') --> Reboot! "
"Check that your camera module is working and connected properly.");
//doReboot();
}
@@ -278,24 +230,20 @@ void CCamera::EnableAutoExposure(int flashdauer)
LEDOnOff(false);
LightOnOff(false);
isFixedExposure = true;
waitbeforepicture_org = flashdauer;
waitbeforepicture_org = flash_duration;
}
esp_err_t CCamera::CaptureToBasisImage(CImageBasis *_Image, int delay)
{
string ftype;
uint8_t *zwischenspeicher = NULL;
#ifdef DEBUG_DETAIL_ON
LogFile.WriteHeapInfo("CCamera::CaptureToBasisImage - Start");
#endif
_Image->EmptyImage(); //Delete previous stored raw image -> black image
LEDOnOff(true);
#ifdef DEBUG_DETAIL_ON
LogFile.WriteHeapInfo("CCamera::CaptureToBasisImage - Start");
#endif
if (delay > 0)
{
LightOnOff(true);
@@ -303,41 +251,37 @@ esp_err_t CCamera::CaptureToBasisImage(CImageBasis *_Image, int delay)
vTaskDelay( xDelay );
}
#ifdef DEBUG_DETAIL_ON
LogFile.WriteHeapInfo("CCamera::CaptureToBasisImage - After LightOn");
#endif
#ifdef DEBUG_DETAIL_ON
LogFile.WriteHeapInfo("CCamera::CaptureToBasisImage - After LightOn");
#endif
camera_fb_t * fb = esp_camera_fb_get();
esp_camera_fb_return(fb);
fb = esp_camera_fb_get();
if (!fb) {
ESP_LOGE(TAGCAMERACLASS, "CaptureToBasisImage: Camera Capture Failed");
LEDOnOff(false);
LightOnOff(false);
LogFile.SwitchOnOff(true);
LogFile.WriteToFile("Camera is not working anymore (CCamera::CaptureToBasisImage) - most probably caused by a hardware problem (instablility, ...). "
ESP_LOGE(TAG, "CaptureToBasisImage: Capture Failed");
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "is not working anymore (CCamera::CaptureToBasisImage) - most probably caused by a hardware problem (instablility, ...). "
"System will reboot.");
doReboot();
return ESP_FAIL;
}
int _size = fb->len;
zwischenspeicher = (uint8_t*) malloc(_size);
if (!zwischenspeicher)
{
ESP_LOGE(TAGCAMERACLASS, "Insufficient memory space for image in function CaptureToBasisImage()");
LogFile.SwitchOnOff(true);
LogFile.WriteToFile("Insufficient memory space for image in function CaptureToBasisImage()");
if (demoMode) { // Use images stored on SD-Card instead of camera image
/* Replace Framebuffer with image from SD-Card */
loadNextDemoImage(fb);
}
for (int i = 0; i < _size; ++i)
*(zwischenspeicher + i) = *(fb->buf + i);
CImageBasis* _zwImage = new CImageBasis();
_zwImage->LoadFromMemory(fb->buf, fb->len);
esp_camera_fb_return(fb);
#ifdef DEBUG_DETAIL_ON
LogFile.WriteHeapInfo("CCamera::CaptureToBasisImage - After fb_get");
#endif
#ifdef DEBUG_DETAIL_ON
LogFile.WriteHeapInfo("CCamera::CaptureToBasisImage - After fb_get");
#endif
LEDOnOff(false);
@@ -347,15 +291,9 @@ esp_err_t CCamera::CaptureToBasisImage(CImageBasis *_Image, int delay)
// TickType_t xDelay = 1000 / portTICK_PERIOD_MS;
// vTaskDelay( xDelay ); // wait for power to recover
uint8_t * buf = NULL;
CImageBasis _zwImage;
_zwImage.LoadFromMemory(zwischenspeicher, _size);
free(zwischenspeicher);
#ifdef DEBUG_DETAIL_ON
LogFile.WriteHeapInfo("CCamera::CaptureToBasisImage - After LoadFromMemory");
#endif
#ifdef DEBUG_DETAIL_ON
LogFile.WriteHeapInfo("CCamera::CaptureToBasisImage - After LoadFromMemory");
#endif
stbi_uc* p_target;
stbi_uc* p_source;
@@ -363,31 +301,27 @@ esp_err_t CCamera::CaptureToBasisImage(CImageBasis *_Image, int delay)
int width = image_width;
int height = image_height;
#ifdef DEBUG_DETAIL_ON
std::string _zw = "Targetimage: " + std::to_string((int) _Image->rgb_image) + " Size: " + std::to_string(_Image->width) + ", " + std::to_string(_Image->height);
_zw = _zw + " _zwImage: " + std::to_string((int) _zwImage.rgb_image) + " Size: " + std::to_string(_zwImage.width) + ", " + std::to_string(_zwImage.height);
LogFile.WriteToFile(_zw);
#endif
#ifdef DEBUG_DETAIL_ON
std::string _zw = "Targetimage: " + std::to_string((int) _Image->rgb_image) + " Size: " + std::to_string(_Image->width) + ", " + std::to_string(_Image->height);
_zw = _zw + " _zwImage: " + std::to_string((int) _zwImage->rgb_image) + " Size: " + std::to_string(_zwImage->width) + ", " + std::to_string(_zwImage->height);
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, _zw);
#endif
for (int x = 0; x < width; ++x)
for (int y = 0; y < height; ++y)
{
p_target = _Image->rgb_image + (channels * (y * width + x));
p_source = _zwImage.rgb_image + (channels * (y * width + x));
p_source = _zwImage->rgb_image + (channels * (y * width + x));
p_target[0] = p_source[0];
p_target[1] = p_source[1];
p_target[2] = p_source[2];
}
#ifdef DEBUG_DETAIL_ON
LogFile.WriteHeapInfo("CCamera::CaptureToBasisImage - After Copy To Target");
#endif
delete _zwImage;
free(buf);
#ifdef DEBUG_DETAIL_ON
LogFile.WriteHeapInfo("CCamera::CaptureToBasisImage - Done");
#endif
#ifdef DEBUG_DETAIL_ON
LogFile.WriteHeapInfo("CCamera::CaptureToBasisImage - Done");
#endif
return ESP_OK;
}
@@ -397,7 +331,7 @@ esp_err_t CCamera::CaptureToFile(std::string nm, int delay)
{
string ftype;
LEDOnOff(true); // Abgeschaltet, um Strom zu sparen !!!!!!
LEDOnOff(true); // Switched off to save power !
if (delay > 0)
{
@@ -410,11 +344,10 @@ esp_err_t CCamera::CaptureToFile(std::string nm, int delay)
esp_camera_fb_return(fb);
fb = esp_camera_fb_get();
if (!fb) {
ESP_LOGE(TAGCAMERACLASS, "CaptureToFile: Camera Capture Failed");
ESP_LOGE(TAG, "CaptureToFile: Camera Capture Failed");
LEDOnOff(false);
LightOnOff(false);
LogFile.SwitchOnOff(true);
LogFile.WriteToFile("Camera Capture Failed (CCamera::CaptureToFile) --> Reboot"
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Capture Failed (CCamera::CaptureToFile) --> Reboot! "
"Check that your camera module is working and connected properly.");
//doReboot();
@@ -422,21 +355,21 @@ esp_err_t CCamera::CaptureToFile(std::string nm, int delay)
}
LEDOnOff(false);
#ifdef DEBUG_DETAIL_ON
printf("w %d, h %d, size %d\n", fb->width, fb->height, fb->len);
#endif
#ifdef DEBUG_DETAIL_ON
ESP_LOGD(TAG, "w %d, h %d, size %d", fb->width, fb->height, fb->len);
#endif
nm = FormatFileName(nm);
#ifdef DEBUG_DETAIL_ON
printf("Save Camera to : %s\n", nm.c_str());
#endif
#ifdef DEBUG_DETAIL_ON
ESP_LOGD(TAG, "Save Camera to: %s", nm.c_str());
#endif
ftype = toUpper(getFileType(nm));
#ifdef DEBUG_DETAIL_ON
printf("Filetype: %s\n", ftype.c_str());
#endif
#ifdef DEBUG_DETAIL_ON
ESP_LOGD(TAG, "Filetype: %s", ftype.c_str());
#endif
uint8_t * buf = NULL;
size_t buf_len = 0;
@@ -453,7 +386,7 @@ esp_err_t CCamera::CaptureToFile(std::string nm, int delay)
bool jpeg_converted = frame2jpg(fb, ActualQuality, &buf, &buf_len);
converted = true;
if(!jpeg_converted){
ESP_LOGE(TAGCAMERACLASS, "JPEG compression failed");
ESP_LOGE(TAG, "JPEG compression failed");
}
} else {
buf_len = fb->len;
@@ -461,7 +394,7 @@ esp_err_t CCamera::CaptureToFile(std::string nm, int delay)
}
}
FILE * fp = OpenFileAndWait(nm.c_str(), "wb");
FILE * fp = fopen(nm.c_str(), "wb");
if (fp == NULL) /* If an error occurs during the file creation */
{
fprintf(stderr, "fopen() failed for '%s'\n", nm.c_str());
@@ -507,7 +440,7 @@ esp_err_t CCamera::CaptureToHTTP(httpd_req_t *req, int delay)
esp_camera_fb_return(fb);
fb = esp_camera_fb_get();
if (!fb) {
ESP_LOGE(TAGCAMERACLASS, "Camera capture failed");
ESP_LOGE(TAG, "Camera capture failed");
LEDOnOff(false);
LightOnOff(false);
httpd_resp_send_500(req);
@@ -524,20 +457,29 @@ esp_err_t CCamera::CaptureToHTTP(httpd_req_t *req, int delay)
}
if(res == ESP_OK){
if(fb->format == PIXFORMAT_JPEG){
fb_len = fb->len;
if (demoMode) { // Use images stored on SD-Card instead of camera image
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Using Demo image!");
/* Replace Framebuffer with image from SD-Card */
loadNextDemoImage(fb);
res = httpd_resp_send(req, (const char *)fb->buf, fb->len);
} else {
jpg_chunking_t jchunk = {req, 0};
res = frame2jpg_cb(fb, 80, jpg_encode_stream, &jchunk)?ESP_OK:ESP_FAIL;
httpd_resp_send_chunk(req, NULL, 0);
fb_len = jchunk.len;
}
else {
if(fb->format == PIXFORMAT_JPEG){
fb_len = fb->len;
res = httpd_resp_send(req, (const char *)fb->buf, fb->len);
} else {
jpg_chunking_t jchunk = {req, 0};
res = frame2jpg_cb(fb, 80, jpg_encode_stream, &jchunk)?ESP_OK:ESP_FAIL;
httpd_resp_send_chunk(req, NULL, 0);
fb_len = jchunk.len;
}
}
}
esp_camera_fb_return(fb);
int64_t fr_end = esp_timer_get_time();
ESP_LOGI(TAGCAMERACLASS, "JPG: %uKB %ums", (uint32_t)(fb_len/1024), (uint32_t)((fr_end - fr_start)/1000));
ESP_LOGI(TAG, "JPG: %uKB %ums", (uint32_t)(fb_len/1024), (uint32_t)((fr_end - fr_start)/1000));
if (delay > 0)
{
@@ -547,24 +489,25 @@ esp_err_t CCamera::CaptureToHTTP(httpd_req_t *req, int delay)
return res;
}
void CCamera::LightOnOff(bool status)
{
GpioHandler* gpioHandler = gpio_handler_get();
if ((gpioHandler != NULL) && (gpioHandler->isEnabled())) {
printf("Use gpioHandler flashLigh\n");
ESP_LOGD(TAG, "Use gpioHandler flashLigh");
gpioHandler->flashLightEnable(status);
} else {
#ifdef USE_PWM_LEDFLASH
if (status)
{
printf("Internal Flash-LED turn on with PWM %d\n", led_intensity);
ESP_LOGD(TAG, "Internal Flash-LED turn on with PWM %d", led_intensity);
ESP_ERROR_CHECK(ledc_set_duty(LEDC_MODE, LEDC_CHANNEL, led_intensity));
// Update duty to apply the new value
ESP_ERROR_CHECK(ledc_update_duty(LEDC_MODE, LEDC_CHANNEL));
}
else
{
printf("Internal Flash-LED turn off PWM\n");
ESP_LOGD(TAG, "Internal Flash-LED turn off PWM");
ESP_ERROR_CHECK(ledc_set_duty(LEDC_MODE, LEDC_CHANNEL, 0));
ESP_ERROR_CHECK(ledc_update_duty(LEDC_MODE, LEDC_CHANNEL));
}
@@ -582,6 +525,7 @@ void CCamera::LightOnOff(bool status)
}
}
void CCamera::LEDOnOff(bool status)
{
// Init the GPIO
@@ -608,11 +552,11 @@ void CCamera::GetCameraParameter(httpd_req_t *req, int &qual, framesize_t &resol
if (httpd_req_get_url_query_str(req, _query, 100) == ESP_OK)
{
printf("Query: "); printf(_query); printf("\n");
ESP_LOGD(TAG, "Query: %s", _query);
if (httpd_query_key_value(_query, "size", _size, 10) == ESP_OK)
{
#ifdef DEBUG_DETAIL_ON
printf("Size: "); printf(_size); printf("\n");
ESP_LOGD(TAG, "Size: %s", _size);
#endif
if (strcmp(_size, "QVGA") == 0)
resol = FRAMESIZE_QVGA; // 320x240
@@ -630,7 +574,7 @@ void CCamera::GetCameraParameter(httpd_req_t *req, int &qual, framesize_t &resol
if (httpd_query_key_value(_query, "quality", _qual, 10) == ESP_OK)
{
#ifdef DEBUG_DETAIL_ON
printf("Quality: "); printf(_qual); printf("\n");
ESP_LOGD(TAG, "Quality: %s", _qual);
#endif
qual = atoi(_qual);
@@ -639,9 +583,10 @@ void CCamera::GetCameraParameter(httpd_req_t *req, int &qual, framesize_t &resol
if (qual < 0)
qual = 0;
}
};
}
}
framesize_t CCamera::TextToFramesize(const char * _size)
{
if (strcmp(_size, "QVGA") == 0)
@@ -663,7 +608,7 @@ framesize_t CCamera::TextToFramesize(const char * _size)
CCamera::CCamera()
{
#ifdef DEBUG_DETAIL_ON
printf("CreateClassCamera\n");
ESP_LOGD(TAG, "CreateClassCamera");
#endif
brightness = -5;
contrast = -5;
@@ -673,27 +618,120 @@ CCamera::CCamera()
ledc_init();
}
esp_err_t CCamera::InitCam()
{
printf("Init Camera\n");
ESP_LOGD(TAG, "Init Camera");
ActualQuality = camera_config.jpeg_quality;
ActualResolution = camera_config.frame_size;
//initialize the camera
esp_camera_deinit(); // De-init in case it was already initialized
esp_err_t err = esp_camera_init(&camera_config);
if (err != ESP_OK) {
ESP_LOGE(TAGCAMERACLASS, "Camera Init Failed");
ESP_LOGE(TAG, "Camera Init Failed");
return err;
}
CameraInitSuccessful = true;
return ESP_OK;
}
void CCamera::SetLEDIntensity(float _intrel)
{
_intrel = min(_intrel, (float) 100);
_intrel = max(_intrel, (float) 0);
_intrel = _intrel / 100;
led_intensity = (int) (_intrel * 8191);
printf("Set led_intensity to %d of 8191\n", led_intensity);
ESP_LOGD(TAG, "Set led_intensity to %d of 8191", led_intensity);
}
bool CCamera::getCameraInitSuccessful()
{
return CameraInitSuccessful;
}
std::vector<std::string> demoFiles;
void CCamera::useDemoMode()
{
char line[50];
FILE *fd = fopen("/sdcard/demo/files.txt", "r");
if (!fd) {
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Can not start Demo mode, the folder '/sdcard/demo/' does not contain the needed files!");
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "See Details on https://jomjol.github.io/AI-on-the-edge-device-docs/Demo-Mode!");
return;
}
demoImage = (uint8_t*)malloc(DEMO_IMAGE_SIZE);
if (demoImage == NULL) {
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Unable to acquire required memory for demo image!");
return;
}
while (fgets(line, sizeof(line), fd) != NULL) {
line[strlen(line) - 1] = '\0';
demoFiles.push_back(line);
}
fclose(fd);
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Using Demo mode (" + std::to_string(demoFiles.size()) +
" files) instead of real camera image!");
for (auto file : demoFiles) {
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, file);
}
demoMode = true;
}
bool CCamera::loadNextDemoImage(camera_fb_t *fb) {
char filename[50];
int readBytes;
long fileSize;
snprintf(filename, sizeof(filename), "/sdcard/demo/%s", demoFiles[getCountFlowRounds() % demoFiles.size()].c_str());
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Using " + std::string(filename) + " as demo image");
/* Inject saved image */
FILE * fp = fopen(filename, "rb");
if (!fp) {
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Failed to read file: " + std::string(filename) +"!");
return false;
}
fileSize = GetFileSize(filename);
if (fileSize > DEMO_IMAGE_SIZE) {
char buf[100];
snprintf(buf, sizeof(buf), "Demo Image (%d bytes) is larger than provided buffer (%d bytes)!",
(int)fileSize, DEMO_IMAGE_SIZE);
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, std::string(buf));
return false;
}
readBytes = fread(demoImage, 1, DEMO_IMAGE_SIZE, fp);
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "read " + std::to_string(readBytes) + " bytes");
fclose(fp);
fb->buf = demoImage; // Update pointer
fb->len = readBytes;
// ToDo do we also need to set height, width, format and timestamp?
return true;
}
long CCamera::GetFileSize(std::string filename)
{
struct stat stat_buf;
long rc = stat(filename.c_str(), &stat_buf);
return rc == 0 ? stat_buf.st_size : -1;
}

View File

@@ -1,3 +1,5 @@
#pragma once
#ifndef CLASSCONTROLLCAMERA_H
#define CLASSCONTROLLCAMERA_H
@@ -11,10 +13,7 @@
#include <string>
#include <esp_http_server.h>
#include "CImageBasis.h"
#define CAMERA_MODEL_AI_THINKER
#include "../../include/defines.h"
class CCamera {
protected:
@@ -26,6 +25,11 @@ class CCamera {
int led_intensity = 4095;
void ledc_init(void);
bool CameraInitSuccessful = false;
bool demoMode = false;
bool loadNextDemoImage(camera_fb_t *fb);
long GetFileSize(std::string filename);
public:
int image_height, image_width;
@@ -40,9 +44,11 @@ class CCamera {
bool SetBrightnessContrastSaturation(int _brightness, int _contrast, int _saturation);
void GetCameraParameter(httpd_req_t *req, int &qual, framesize_t &resol);
void SetLEDIntensity(float _intrel);
void EnableAutoExposure(int flashdauer);
bool testCamera(void);
void EnableAutoExposure(int flash_duration);
bool getCameraInitSuccessful();
void useDemoMode(void);
framesize_t TextToFramesize(const char * text);

View File

@@ -1,126 +0,0 @@
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef _IMG_CONVERTERS_H_
#define _IMG_CONVERTERS_H_
#ifdef __cplusplus
extern "C" {
#endif
#include <stddef.h>
#include <stdint.h>
#include <stdbool.h>
#include "esp_camera.h"
typedef size_t (* jpg_out_cb)(void * arg, size_t index, const void* data, size_t len);
/**
* @brief Convert image buffer to JPEG
*
* @param src Source buffer in RGB565, RGB888, YUYV or GRAYSCALE format
* @param src_len Length in bytes of the source buffer
* @param width Width in pixels of the source image
* @param height Height in pixels of the source image
* @param format Format of the source image
* @param quality JPEG quality of the resulting image
* @param cp Callback to be called to write the bytes of the output JPEG
* @param arg Pointer to be passed to the callback
*
* @return true on success
*/
bool fmt2jpg_cb(uint8_t *src, size_t src_len, uint16_t width, uint16_t height, pixformat_t format, uint8_t quality, jpg_out_cb cb, void * arg);
/**
* @brief Convert camera frame buffer to JPEG
*
* @param fb Source camera frame buffer
* @param quality JPEG quality of the resulting image
* @param cp Callback to be called to write the bytes of the output JPEG
* @param arg Pointer to be passed to the callback
*
* @return true on success
*/
bool frame2jpg_cb(camera_fb_t * fb, uint8_t quality, jpg_out_cb cb, void * arg);
/**
* @brief Convert image buffer to JPEG buffer
*
* @param src Source buffer in RGB565, RGB888, YUYV or GRAYSCALE format
* @param src_len Length in bytes of the source buffer
* @param width Width in pixels of the source image
* @param height Height in pixels of the source image
* @param format Format of the source image
* @param quality JPEG quality of the resulting image
* @param out Pointer to be populated with the address of the resulting buffer
* @param out_len Pointer to be populated with the length of the output buffer
*
* @return true on success
*/
bool fmt2jpg(uint8_t *src, size_t src_len, uint16_t width, uint16_t height, pixformat_t format, uint8_t quality, uint8_t ** out, size_t * out_len);
/**
* @brief Convert camera frame buffer to JPEG buffer
*
* @param fb Source camera frame buffer
* @param quality JPEG quality of the resulting image
* @param out Pointer to be populated with the address of the resulting buffer
* @param out_len Pointer to be populated with the length of the output buffer
*
* @return true on success
*/
bool frame2jpg(camera_fb_t * fb, uint8_t quality, uint8_t ** out, size_t * out_len);
/**
* @brief Convert image buffer to BMP buffer
*
* @param src Source buffer in JPEG, RGB565, RGB888, YUYV or GRAYSCALE format
* @param src_len Length in bytes of the source buffer
* @param width Width in pixels of the source image
* @param height Height in pixels of the source image
* @param format Format of the source image
* @param out Pointer to be populated with the address of the resulting buffer
* @param out_len Pointer to be populated with the length of the output buffer
*
* @return true on success
*/
bool fmt2bmp(uint8_t *src, size_t src_len, uint16_t width, uint16_t height, pixformat_t format, uint8_t ** out, size_t * out_len);
/**
* @brief Convert camera frame buffer to BMP buffer
*
* @param fb Source camera frame buffer
* @param out Pointer to be populated with the address of the resulting buffer
* @param out_len Pointer to be populated with the length of the output buffer
*
* @return true on success
*/
bool frame2bmp(camera_fb_t * fb, uint8_t ** out, size_t * out_len);
/**
* @brief Convert image buffer to RGB888 buffer (used for face detection)
*
* @param src Source buffer in JPEG, RGB565, RGB888, YUYV or GRAYSCALE format
* @param src_len Length in bytes of the source buffer
* @param format Format of the source image
* @param rgb_buf Pointer to the output buffer (width * height * 3)
*
* @return true on success
*/
bool fmt2rgb888(const uint8_t *src_buf, size_t src_len, pixformat_t format, uint8_t * rgb_buf);
#ifdef __cplusplus
}
#endif
#endif /* _IMG_CONVERTERS_H_ */

View File

@@ -1,245 +0,0 @@
/*
* This file is part of the OpenMV project.
* Copyright (c) 2013/2014 Ibrahim Abdelkader <i.abdalkader@gmail.com>
* This work is licensed under the MIT license, see the file LICENSE for details.
*
* Sensor abstraction layer.
*
*/
#ifndef __SENSOR_H__
#define __SENSOR_H__
#include <stdint.h>
#include <stdbool.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
OV9650_PID = 0x96,
OV7725_PID = 0x77,
OV2640_PID = 0x26,
OV3660_PID = 0x3660,
OV5640_PID = 0x5640,
OV7670_PID = 0x76,
NT99141_PID = 0x1410,
GC2145_PID = 0x2145,
GC032A_PID = 0x232a,
GC0308_PID = 0x9b,
} camera_pid_t;
typedef enum {
CAMERA_OV7725,
CAMERA_OV2640,
CAMERA_OV3660,
CAMERA_OV5640,
CAMERA_OV7670,
CAMERA_NT99141,
CAMERA_GC2145,
CAMERA_GC032A,
CAMERA_GC0308,
CAMERA_MODEL_MAX,
CAMERA_NONE,
} camera_model_t;
typedef enum {
OV2640_SCCB_ADDR = 0x30,// 0x60 >> 1
OV5640_SCCB_ADDR = 0x3C,// 0x78 >> 1
OV3660_SCCB_ADDR = 0x3C,// 0x78 >> 1
OV7725_SCCB_ADDR = 0x21,// 0x42 >> 1
OV7670_SCCB_ADDR = 0x21,// 0x42 >> 1
NT99141_SCCB_ADDR = 0x2A,// 0x54 >> 1
GC2145_SCCB_ADDR = 0x3C,// 0x78 >> 1
GC032A_SCCB_ADDR = 0x21,// 0x42 >> 1
GC0308_SCCB_ADDR = 0x21,// 0x42 >> 1
} camera_sccb_addr_t;
typedef enum {
PIXFORMAT_RGB565, // 2BPP/RGB565
PIXFORMAT_YUV422, // 2BPP/YUV422
PIXFORMAT_GRAYSCALE, // 1BPP/GRAYSCALE
PIXFORMAT_JPEG, // JPEG/COMPRESSED
PIXFORMAT_RGB888, // 3BPP/RGB888
PIXFORMAT_RAW, // RAW
PIXFORMAT_RGB444, // 3BP2P/RGB444
PIXFORMAT_RGB555, // 3BP2P/RGB555
} pixformat_t;
typedef enum {
FRAMESIZE_96X96, // 96x96
FRAMESIZE_QQVGA, // 160x120
FRAMESIZE_QCIF, // 176x144
FRAMESIZE_HQVGA, // 240x176
FRAMESIZE_240X240, // 240x240
FRAMESIZE_QVGA, // 320x240
FRAMESIZE_CIF, // 400x296
FRAMESIZE_HVGA, // 480x320
FRAMESIZE_VGA, // 640x480
FRAMESIZE_SVGA, // 800x600
FRAMESIZE_XGA, // 1024x768
FRAMESIZE_HD, // 1280x720
FRAMESIZE_SXGA, // 1280x1024
FRAMESIZE_UXGA, // 1600x1200
// 3MP Sensors
FRAMESIZE_FHD, // 1920x1080
FRAMESIZE_P_HD, // 720x1280
FRAMESIZE_P_3MP, // 864x1536
FRAMESIZE_QXGA, // 2048x1536
// 5MP Sensors
FRAMESIZE_QHD, // 2560x1440
FRAMESIZE_WQXGA, // 2560x1600
FRAMESIZE_P_FHD, // 1080x1920
FRAMESIZE_QSXGA, // 2560x1920
FRAMESIZE_INVALID
} framesize_t;
typedef struct {
const camera_model_t model;
const char *name;
const camera_sccb_addr_t sccb_addr;
const camera_pid_t pid;
const framesize_t max_size;
const bool support_jpeg;
} camera_sensor_info_t;
typedef enum {
ASPECT_RATIO_4X3,
ASPECT_RATIO_3X2,
ASPECT_RATIO_16X10,
ASPECT_RATIO_5X3,
ASPECT_RATIO_16X9,
ASPECT_RATIO_21X9,
ASPECT_RATIO_5X4,
ASPECT_RATIO_1X1,
ASPECT_RATIO_9X16
} aspect_ratio_t;
typedef enum {
GAINCEILING_2X,
GAINCEILING_4X,
GAINCEILING_8X,
GAINCEILING_16X,
GAINCEILING_32X,
GAINCEILING_64X,
GAINCEILING_128X,
} gainceiling_t;
typedef struct {
uint16_t max_width;
uint16_t max_height;
uint16_t start_x;
uint16_t start_y;
uint16_t end_x;
uint16_t end_y;
uint16_t offset_x;
uint16_t offset_y;
uint16_t total_x;
uint16_t total_y;
} ratio_settings_t;
typedef struct {
const uint16_t width;
const uint16_t height;
const aspect_ratio_t aspect_ratio;
} resolution_info_t;
// Resolution table (in sensor.c)
extern const resolution_info_t resolution[];
// camera sensor table (in sensor.c)
extern const camera_sensor_info_t camera_sensor[];
typedef struct {
uint8_t MIDH;
uint8_t MIDL;
uint16_t PID;
uint8_t VER;
} sensor_id_t;
typedef struct {
framesize_t framesize;//0 - 10
bool scale;
bool binning;
uint8_t quality;//0 - 63
int8_t brightness;//-2 - 2
int8_t contrast;//-2 - 2
int8_t saturation;//-2 - 2
int8_t sharpness;//-2 - 2
uint8_t denoise;
uint8_t special_effect;//0 - 6
uint8_t wb_mode;//0 - 4
uint8_t awb;
uint8_t awb_gain;
uint8_t aec;
uint8_t aec2;
int8_t ae_level;//-2 - 2
uint16_t aec_value;//0 - 1200
uint8_t agc;
uint8_t agc_gain;//0 - 30
uint8_t gainceiling;//0 - 6
uint8_t bpc;
uint8_t wpc;
uint8_t raw_gma;
uint8_t lenc;
uint8_t hmirror;
uint8_t vflip;
uint8_t dcw;
uint8_t colorbar;
} camera_status_t;
typedef struct _sensor sensor_t;
typedef struct _sensor {
sensor_id_t id; // Sensor ID.
uint8_t slv_addr; // Sensor I2C slave address.
pixformat_t pixformat;
camera_status_t status;
int xclk_freq_hz;
// Sensor function pointers
int (*init_status) (sensor_t *sensor);
int (*reset) (sensor_t *sensor);
int (*set_pixformat) (sensor_t *sensor, pixformat_t pixformat);
int (*set_framesize) (sensor_t *sensor, framesize_t framesize);
int (*set_contrast) (sensor_t *sensor, int level);
int (*set_brightness) (sensor_t *sensor, int level);
int (*set_saturation) (sensor_t *sensor, int level);
int (*set_sharpness) (sensor_t *sensor, int level);
int (*set_denoise) (sensor_t *sensor, int level);
int (*set_gainceiling) (sensor_t *sensor, gainceiling_t gainceiling);
int (*set_quality) (sensor_t *sensor, int quality);
int (*set_colorbar) (sensor_t *sensor, int enable);
int (*set_whitebal) (sensor_t *sensor, int enable);
int (*set_gain_ctrl) (sensor_t *sensor, int enable);
int (*set_exposure_ctrl) (sensor_t *sensor, int enable);
int (*set_hmirror) (sensor_t *sensor, int enable);
int (*set_vflip) (sensor_t *sensor, int enable);
int (*set_aec2) (sensor_t *sensor, int enable);
int (*set_awb_gain) (sensor_t *sensor, int enable);
int (*set_agc_gain) (sensor_t *sensor, int gain);
int (*set_aec_value) (sensor_t *sensor, int gain);
int (*set_special_effect) (sensor_t *sensor, int effect);
int (*set_wb_mode) (sensor_t *sensor, int mode);
int (*set_ae_level) (sensor_t *sensor, int level);
int (*set_dcw) (sensor_t *sensor, int enable);
int (*set_bpc) (sensor_t *sensor, int enable);
int (*set_wpc) (sensor_t *sensor, int enable);
int (*set_raw_gma) (sensor_t *sensor, int enable);
int (*set_lenc) (sensor_t *sensor, int enable);
int (*get_reg) (sensor_t *sensor, int reg, int mask);
int (*set_reg) (sensor_t *sensor, int reg, int mask, int value);
int (*set_res_raw) (sensor_t *sensor, int startX, int startY, int endX, int endY, int offsetX, int offsetY, int totalX, int totalY, int outputX, int outputY, bool scale, bool binning);
int (*set_pll) (sensor_t *sensor, int bypass, int mul, int sys, int root, int pre, int seld5, int pclken, int pclk);
int (*set_xclk) (sensor_t *sensor, int timer, int xclk);
} sensor_t;
camera_sensor_info_t *esp_camera_sensor_get_info(sensor_id_t *id);
#ifdef __cplusplus
}
#endif
#endif /* __SENSOR_H__ */

View File

@@ -7,16 +7,16 @@
#include "ClassControllCamera.h"
#include "ClassLogFile.h"
#include "esp_log.h"
#define SCRATCH_BUFSIZE2 8192
char scratch2[SCRATCH_BUFSIZE2];
#include "../../include/defines.h"
//#define DEBUG_DETAIL_ON
static const char *TAGPARTCAMERA = "server_camera";
static const char *TAG = "server_cam";
void PowerResetCamera(){
ESP_LOGD(TAGPARTCAMERA, "Resetting camera by power down line");
ESP_LOGD(TAG, "Resetting camera by power down line");
gpio_config_t conf;
conf.intr_type = GPIO_INTR_DISABLE;
conf.pin_bit_mask = 1LL << GPIO_NUM_32;
@@ -35,188 +35,229 @@ void PowerResetCamera(){
esp_err_t handler_lightOn(httpd_req_t *req)
{
#ifdef DEBUG_DETAIL_ON
LogFile.WriteHeapInfo("handler_lightOn - Start");
printf("handler_lightOn uri:\n"); printf(req->uri); printf("\n");
#endif
#ifdef DEBUG_DETAIL_ON
LogFile.WriteHeapInfo("handler_lightOn - Start");
ESP_LOGD(TAG, "handler_lightOn uri: %s", req->uri);
#endif
Camera.LightOnOff(true);
const char* resp_str = (const char*) req->user_ctx;
httpd_resp_send(req, resp_str, strlen(resp_str));
if (Camera.getCameraInitSuccessful())
{
Camera.LightOnOff(true);
const char* resp_str = (const char*) req->user_ctx;
httpd_resp_send(req, resp_str, strlen(resp_str));
}
else
{
httpd_resp_send_err(req, HTTPD_403_FORBIDDEN, "Camera not initialized: REST API /lighton not available!");
return ESP_ERR_NOT_FOUND;
}
#ifdef DEBUG_DETAIL_ON
LogFile.WriteHeapInfo("handler_lightOn - Done");
#endif
#ifdef DEBUG_DETAIL_ON
LogFile.WriteHeapInfo("handler_lightOn - Done");
#endif
return ESP_OK;
};
}
esp_err_t handler_lightOff(httpd_req_t *req)
{
#ifdef DEBUG_DETAIL_ON
LogFile.WriteHeapInfo("handler_lightOff - Start");
printf("handler_lightOff uri:\n"); printf(req->uri); printf("\n");
#endif
Camera.LightOnOff(false);
const char* resp_str = (const char*) req->user_ctx;
httpd_resp_send(req, resp_str, strlen(resp_str));
#ifdef DEBUG_DETAIL_ON
LogFile.WriteHeapInfo("handler_lightOff - Start");
ESP_LOGD(TAG, "handler_lightOff uri: %s", req->uri);
#endif
#ifdef DEBUG_DETAIL_ON
LogFile.WriteHeapInfo("handler_lightOff - Done");
#endif
if (Camera.getCameraInitSuccessful())
{
Camera.LightOnOff(false);
const char* resp_str = (const char*) req->user_ctx;
httpd_resp_send(req, resp_str, strlen(resp_str));
}
else
{
httpd_resp_send_err(req, HTTPD_403_FORBIDDEN, "Camera not initialized: REST API /lightoff not available!");
return ESP_ERR_NOT_FOUND;
}
#ifdef DEBUG_DETAIL_ON
LogFile.WriteHeapInfo("handler_lightOff - Done");
#endif
return ESP_OK;
};
}
esp_err_t handler_capture(httpd_req_t *req)
{
#ifdef DEBUG_DETAIL_ON
LogFile.WriteHeapInfo("handler_capture - Start");
#endif
#ifdef DEBUG_DETAIL_ON
LogFile.WriteHeapInfo("handler_capture - Start");
#endif
int quality;
framesize_t res;
Camera.GetCameraParameter(req, quality, res);
#ifdef DEBUG_DETAIL_ON
printf("Size: %d", res); printf(" Quality: %d\n", quality);
#endif
Camera.SetQualitySize(quality, res);
esp_err_t ressult;
ressult = Camera.CaptureToHTTP(req);
#ifdef DEBUG_DETAIL_ON
LogFile.WriteHeapInfo("handler_capture - Done");
#endif
return ressult;
};
esp_err_t handler_capture_with_ligth(httpd_req_t *req)
{
#ifdef DEBUG_DETAIL_ON
LogFile.WriteHeapInfo("handler_capture_with_ligth - Start");
#endif
char _query[100];
char _delay[10];
int quality;
framesize_t res;
int delay = 2500;
if (httpd_req_get_url_query_str(req, _query, 100) == ESP_OK)
if (Camera.getCameraInitSuccessful())
{
printf("Query: "); printf(_query); printf("\n");
if (httpd_query_key_value(_query, "delay", _delay, 10) == ESP_OK)
int quality;
framesize_t res;
Camera.GetCameraParameter(req, quality, res);
#ifdef DEBUG_DETAIL_ON
ESP_LOGD(TAG, "Size: %d, Quality: %d", res, quality);
#endif
Camera.SetQualitySize(quality, res);
esp_err_t result;
result = Camera.CaptureToHTTP(req);
#ifdef DEBUG_DETAIL_ON
LogFile.WriteHeapInfo("handler_capture - Done");
#endif
return result;
}
else
{
httpd_resp_send_err(req, HTTPD_403_FORBIDDEN, "Camera not initialized: REST API /capture not available!");
return ESP_ERR_NOT_FOUND;
}
}
esp_err_t handler_capture_with_light(httpd_req_t *req)
{
#ifdef DEBUG_DETAIL_ON
LogFile.WriteHeapInfo("handler_capture_with_light - Start");
#endif
if (Camera.getCameraInitSuccessful())
{
char _query[100];
char _delay[10];
int quality;
framesize_t res;
int delay = 2500;
if (httpd_req_get_url_query_str(req, _query, 100) == ESP_OK)
{
#ifdef DEBUG_DETAIL_ON
printf("Delay: "); printf(_delay); printf("\n");
#endif
delay = atoi(_delay);
ESP_LOGD(TAG, "Query: %s", _query);
if (httpd_query_key_value(_query, "delay", _delay, 10) == ESP_OK)
{
#ifdef DEBUG_DETAIL_ON
ESP_LOGD(TAG, "Delay: %s", _delay);
#endif
delay = atoi(_delay);
if (delay < 0)
delay = 0;
if (delay < 0)
delay = 0;
}
}
};
Camera.GetCameraParameter(req, quality, res);
Camera.GetCameraParameter(req, quality, res);
#ifdef DEBUG_DETAIL_ON
printf("Size: %d", res); printf(" Quality: %d\n", quality);
#endif
#ifdef DEBUG_DETAIL_ON
ESP_LOGD(TAG, "Size: %d, Quality: %d", res, quality);
#endif
Camera.SetQualitySize(quality, res);
Camera.LightOnOff(true);
const TickType_t xDelay = delay / portTICK_PERIOD_MS;
vTaskDelay( xDelay );
Camera.SetQualitySize(quality, res);
Camera.LightOnOff(true);
const TickType_t xDelay = delay / portTICK_PERIOD_MS;
vTaskDelay( xDelay );
esp_err_t ressult;
ressult = Camera.CaptureToHTTP(req);
esp_err_t result;
result = Camera.CaptureToHTTP(req);
Camera.LightOnOff(false);
Camera.LightOnOff(false);
#ifdef DEBUG_DETAIL_ON
LogFile.WriteHeapInfo("handler_capture_with_ligth - Done");
#endif
return ressult;
};
#ifdef DEBUG_DETAIL_ON
LogFile.WriteHeapInfo("handler_capture_with_light - Done");
#endif
return result;
}
else
{
httpd_resp_send_err(req, HTTPD_403_FORBIDDEN, "Camera not initialized: REST API /capture_with_flashlight not available!");
return ESP_ERR_NOT_FOUND;
}
}
esp_err_t handler_capture_save_to_file(httpd_req_t *req)
{
#ifdef DEBUG_DETAIL_ON
LogFile.WriteHeapInfo("handler_capture_save_to_file - Start");
#endif
#ifdef DEBUG_DETAIL_ON
LogFile.WriteHeapInfo("handler_capture_save_to_file - Start");
#endif
char _query[100];
char _delay[10];
int delay = 0;
char filename[100];
std::string fn = "/sdcard/";
int quality;
framesize_t res;
if (httpd_req_get_url_query_str(req, _query, 100) == ESP_OK)
if (Camera.getCameraInitSuccessful())
{
printf("Query: "); printf(_query); printf("\n");
if (httpd_query_key_value(_query, "filename", filename, 100) == ESP_OK)
char _query[100];
char _delay[10];
int delay = 0;
char filename[100];
std::string fn = "/sdcard/";
int quality;
framesize_t res;
if (httpd_req_get_url_query_str(req, _query, 100) == ESP_OK)
{
fn.append(filename);
#ifdef DEBUG_DETAIL_ON
printf("Filename: "); printf(fn.c_str()); printf("\n");
#endif
ESP_LOGD(TAG, "Query: %s", _query);
if (httpd_query_key_value(_query, "filename", filename, 100) == ESP_OK)
{
fn.append(filename);
#ifdef DEBUG_DETAIL_ON
ESP_LOGD(TAG, "Filename: %s", fn.c_str());
#endif
}
else
fn.append("noname.jpg");
if (httpd_query_key_value(_query, "delay", _delay, 10) == ESP_OK)
{
#ifdef DEBUG_DETAIL_ON
ESP_LOGD(TAG, "Delay: %s", _delay);
#endif
delay = atoi(_delay);
if (delay < 0)
delay = 0;
}
}
else
fn.append("noname.jpg");
if (httpd_query_key_value(_query, "delay", _delay, 10) == ESP_OK)
{
#ifdef DEBUG_DETAIL_ON
printf("Delay: "); printf(_delay); printf("\n");
#endif
delay = atoi(_delay);
Camera.GetCameraParameter(req, quality, res);
#ifdef DEBUG_DETAIL_ON
ESP_LOGD(TAG, "Size: %d, Quality: %d", res, quality);
#endif
Camera.SetQualitySize(quality, res);
if (delay < 0)
delay = 0;
}
esp_err_t result;
result = Camera.CaptureToFile(fn, delay);
const char* resp_str = (const char*) fn.c_str();
httpd_resp_send(req, resp_str, strlen(resp_str));
#ifdef DEBUG_DETAIL_ON
LogFile.WriteHeapInfo("handler_capture_save_to_file - Done");
#endif
return result;
}
else
fn.append("noname.jpg");
Camera.GetCameraParameter(req, quality, res);
#ifdef DEBUG_DETAIL_ON
printf("Size: %d", res); printf(" Quality: %d\n", quality);
#endif
Camera.SetQualitySize(quality, res);
esp_err_t ressult;
ressult = Camera.CaptureToFile(fn, delay);
const char* resp_str = (const char*) fn.c_str();
httpd_resp_send(req, resp_str, strlen(resp_str));
#ifdef DEBUG_DETAIL_ON
LogFile.WriteHeapInfo("handler_capture_save_to_file - Done");
#endif
return ressult;
};
else
{
httpd_resp_send_err(req, HTTPD_403_FORBIDDEN, "Camera not initialized: REST API /save not available!");
return ESP_ERR_NOT_FOUND;
}
}
void register_server_camera_uri(httpd_handle_t server)
{
#ifdef DEBUG_DETAIL_ON
ESP_LOGI(TAGPARTCAMERA, "server_part_camera - Registering URI handlers");
ESP_LOGI(TAG, "server_part_camera - Registering URI handlers");
#endif
httpd_uri_t camuri = { };
@@ -238,7 +279,7 @@ void register_server_camera_uri(httpd_handle_t server)
httpd_register_uri_handler(server, &camuri);
camuri.uri = "/capture_with_flashlight";
camuri.handler = handler_capture_with_ligth;
camuri.handler = handler_capture_with_light;
camuri.user_ctx = NULL;
httpd_register_uri_handler(server, &camuri);

View File

@@ -1,3 +1,5 @@
#pragma once
#ifndef JOMJOL_CONTROLCAMERA_H
#define JOMJOL_CONTROLCAMERA_H

View File

@@ -2,6 +2,6 @@ FILE(GLOB_RECURSE app_sources ${CMAKE_CURRENT_SOURCE_DIR}/*.*)
idf_component_register(SRCS ${app_sources}
INCLUDE_DIRS "." "../../include"
REQUIRES tflite-lib esp_http_server app_update esp_http_client nvs_flash jomjol_tfliteclass jomjol_flowcontroll spiffs jomjol_helper jomjol_controlGPIO)
REQUIRES tflite-lib esp_http_server app_update esp_http_client nvs_flash jomjol_tfliteclass jomjol_flowcontroll spiffs jomjol_helper jomjol_controlGPIO miniz)

File diff suppressed because it is too large Load Diff

View File

@@ -1,12 +1,21 @@
#pragma once
#ifndef SERVERFILE_H
#define SERVERFILE_H
#include <esp_http_server.h>
#include <string>
void register_server_file_uri(httpd_handle_t server, const char *base_path);
void unzip(std::string _in_zip_file, std::string _target_directory);
std::string unzip_new(std::string _in_zip_file, std::string _target_zip, std::string _target_bin, std::string _main = "/sdcard/");
std::string unzip_new(std::string _in_zip_file, std::string _target_zip, std::string _target_bin, std::string _main = "/sdcard/", bool _initial_setup = false);
void delete_all_in_directory(std::string _directory);
esp_err_t get_tflite_file_handler(httpd_req_t *req);
esp_err_t get_data_file_handler(httpd_req_t *req);
esp_err_t get_numbers_file_handler(httpd_req_t *req);
#endif //SERVERFILE_H

View File

@@ -21,29 +21,49 @@ extern "C" {
#include "esp_http_server.h"
static const char *TAG = "serverhelp";
#define SCRATCH_BUFSIZE 8192
char scratch[SCRATCH_BUFSIZE];
#include "../../include/defines.h"
#define IS_FILE_EXT(filename, ext) \
(strcasecmp(&filename[strlen(filename) - sizeof(ext) + 1], ext) == 0)
static const char *TAG = "SERVER HELP";
char scratch[SERVER_HELPER_SCRATCH_BUFSIZE];
bool endsWith(std::string const &str, std::string const &suffix) {
if (str.length() < suffix.length()) {
return false;
}
return str.compare(str.length() - suffix.length(), suffix.length(), suffix) == 0;
}
esp_err_t send_file(httpd_req_t *req, std::string filename)
{
FILE *fd = OpenFileAndWait(filename.c_str(), "r");
FILE *fd = fopen(filename.c_str(), "r");
if (!fd) {
ESP_LOGE(TAG, "Failed to read existing file : %s", filename.c_str());
/* Respond with 500 Internal Server Error */
httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Failed to read existing file");
ESP_LOGE(TAG, "Failed to read file: %s", filename.c_str());
/* Respond with 404 Error */
httpd_resp_send_err(req, HTTPD_404_NOT_FOUND, get404());
return ESP_FAIL;
}
ESP_LOGI(TAG, "Sending file : %s ...", filename.c_str());
ESP_LOGD(TAG, "Sending file: %s ...", filename.c_str());
// httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
/* For all files with the following file extention tell
the webbrowser to cache them for 24h */
if (endsWith(filename, ".html") ||
endsWith(filename, ".htm") ||
endsWith(filename, ".css") ||
endsWith(filename, ".js") ||
endsWith(filename, ".map") ||
endsWith(filename, ".jpg") ||
endsWith(filename, ".jpeg") ||
endsWith(filename, ".ico") ||
endsWith(filename, ".png")) {
httpd_resp_set_hdr(req, "Cache-Control", "max-age=86400");
}
set_content_type_from_file(req, filename.c_str());
/* Retrieve the pointer to scratch buffer for temporary storage */
@@ -51,7 +71,7 @@ esp_err_t send_file(httpd_req_t *req, std::string filename)
size_t chunksize;
do {
/* Read file in chunks into the scratch buffer */
chunksize = fread(chunk, 1, SCRATCH_BUFSIZE, fd);
chunksize = fread(chunk, 1, SERVER_HELPER_SCRATCH_BUFSIZE, fd);
/* Send the buffer contents as HTTP response chunk */
if (httpd_resp_send_chunk(req, chunk, chunksize) != ESP_OK) {
@@ -69,7 +89,7 @@ esp_err_t send_file(httpd_req_t *req, std::string filename)
/* Close file after sending complete */
fclose(fd);
ESP_LOGI(TAG, "File sending complete");
ESP_LOGD(TAG, "File sending complete");
return ESP_OK;
}

View File

@@ -1,3 +1,8 @@
#pragma once
#ifndef SERVERHELP_H
#define SERVERHELP_H
#include <string>
//#include <sys/param.h>
#include "esp_http_server.h"
@@ -7,4 +12,6 @@ const char* get_path_from_uri(char *dest, const char *base_path, const char *uri
esp_err_t send_file(httpd_req_t *req, std::string filename);
esp_err_t set_content_type_from_file(httpd_req_t *req, const char *filename);
esp_err_t set_content_type_from_file(httpd_req_t *req, const char *filename);
#endif //SERVERHELP_H

View File

@@ -29,41 +29,112 @@
#include "server_tflite.h"
#include "server_file.h"
#include "server_GPIO.h"
#ifdef ENABLE_MQTT
#include "interface_mqtt.h"
#endif //ENABLE_MQTT
#include "ClassControllCamera.h"
#include "connect_wlan.h"
#include "ClassLogFile.h"
#include "Helper.h"
// #define DEBUG_DETAIL_ON
#define BUFFSIZE 1024
#define HASH_LEN 32 /* SHA-256 digest length */
#include "../../include/defines.h"
/*an ota data write buffer ready to write to the flash*/
static char ota_write_data[BUFFSIZE + 1] = { 0 };
static char ota_write_data[SERVER_OTA_SCRATCH_BUFSIZE + 1] = { 0 };
#define OTA_URL_SIZE 256
static const char *TAGPARTOTA = "server_ota";
static const char *TAG = "OTA";
esp_err_t handler_reboot(httpd_req_t *req);
static bool ota_update_task(std::string fn);
std::string _file_name_update;
bool initial_setup = false;
static void infinite_loop(void)
{
int i = 0;
ESP_LOGI(TAGPARTOTA, "When a new firmware is available on the server, press the reset button to download it");
ESP_LOGI(TAG, "When a new firmware is available on the server, press the reset button to download it");
while(1) {
ESP_LOGI(TAGPARTOTA, "Waiting for a new firmware ... %d", ++i);
vTaskDelay(2000 / portTICK_PERIOD_MS);
ESP_LOGI(TAG, "Waiting for a new firmware... %d", ++i);
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
}
void task_do_Update_ZIP(void *pvParameter)
{
std::string filetype = toUpper(getFileType(_file_name_update));
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "File: " + _file_name_update + " Filetype: " + filetype);
if (filetype == "ZIP")
{
std::string in, out, outbin, zw, retfirmware;
out = "/sdcard/html";
outbin = "/sdcard/firmware";
retfirmware = unzip_new(_file_name_update, out+"/", outbin+"/", "/sdcard/", initial_setup);
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Files unzipped.");
if (retfirmware.length() > 0)
{
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Found firmware.bin");
ota_update_task(retfirmware);
}
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Trigger reboot due to firmware update.");
doRebootOTA();
} else if (filetype == "BIN")
{
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Do firmware update - file: " + _file_name_update);
ota_update_task(_file_name_update);
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Trigger reboot due to firmware update.");
doRebootOTA();
}
else
{
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Only ZIP-Files support for update during startup!");
}
}
void CheckUpdate()
{
FILE *pfile;
if ((pfile = fopen("/sdcard/update.txt", "r")) == NULL)
{
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "No update triggered.");
return;
}
char zw[1024] = "";
fgets(zw, 1024, pfile);
_file_name_update = std::string(zw);
if (fgets(zw, 1024, pfile))
{
std::string _szw = std::string(zw);
if (_szw == "init")
{
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Inital Setup triggered.");
initial_setup = true; }
}
fclose(pfile);
DeleteFile("/sdcard/update.txt"); // Prevent Boot Loop!!!
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Update during boot triggered - Update File: " + _file_name_update);
xTaskCreate(&task_do_Update_ZIP, "task_do_Update_ZIP", configMINIMAL_STACK_SIZE * 35, NULL, tskIDLE_PRIORITY+1, NULL);
while(1) { // wait until reboot within task_do_Update_ZIP
vTaskDelay(1000 / portTICK_PERIOD_MS);
}
}
static bool ota_update_task(std::string fn)
{
@@ -72,22 +143,22 @@ static bool ota_update_task(std::string fn)
esp_ota_handle_t update_handle = 0 ;
const esp_partition_t *update_partition = NULL;
ESP_LOGI(TAGPARTOTA, "Starting OTA update");
ESP_LOGI(TAG, "Starting OTA update");
const esp_partition_t *configured = esp_ota_get_boot_partition();
const esp_partition_t *running = esp_ota_get_running_partition();
if (configured != running) {
ESP_LOGW(TAGPARTOTA, "Configured OTA boot partition at offset 0x%08x, but running from offset 0x%08x",
ESP_LOGW(TAG, "Configured OTA boot partition at offset 0x%08x, but running from offset 0x%08x",
configured->address, running->address);
ESP_LOGW(TAGPARTOTA, "(This can happen if either the OTA boot data or preferred boot image become somehow corrupted.)");
ESP_LOGW(TAG, "(This can happen if either the OTA boot data or preferred boot image become somehow corrupted.)");
}
ESP_LOGI(TAGPARTOTA, "Running partition type %d subtype %d (offset 0x%08x)",
ESP_LOGI(TAG, "Running partition type %d subtype %d (offset 0x%08x)",
running->type, running->subtype, running->address);
update_partition = esp_ota_get_next_update_partition(NULL);
ESP_LOGI(TAGPARTOTA, "Writing to partition subtype %d at offset 0x%x",
ESP_LOGI(TAG, "Writing to partition subtype %d at offset 0x%x",
update_partition->subtype, update_partition->address);
// assert(update_partition != NULL);
@@ -98,17 +169,17 @@ static bool ota_update_task(std::string fn)
int data_read;
FILE* f = OpenFileAndWait(fn.c_str(), "rb"); // vorher nur "r"
FILE* f = fopen(fn.c_str(), "rb"); // previously only "r
if (f == NULL) { // File does not exist
return false;
}
data_read = fread(ota_write_data, 1, BUFFSIZE, f);
data_read = fread(ota_write_data, 1, SERVER_OTA_SCRATCH_BUFSIZE, f);
while (data_read > 0) {
if (data_read < 0) {
ESP_LOGE(TAGPARTOTA, "Error: SSL data read error");
ESP_LOGE(TAG, "Error: SSL data read error");
return false;
} else if (data_read > 0) {
if (image_header_was_checked == false) {
@@ -116,32 +187,32 @@ static bool ota_update_task(std::string fn)
if (data_read > sizeof(esp_image_header_t) + sizeof(esp_image_segment_header_t) + sizeof(esp_app_desc_t)) {
// check current version with downloading
memcpy(&new_app_info, &ota_write_data[sizeof(esp_image_header_t) + sizeof(esp_image_segment_header_t)], sizeof(esp_app_desc_t));
ESP_LOGI(TAGPARTOTA, "New firmware version: %s", new_app_info.version);
ESP_LOGI(TAG, "New firmware version: %s", new_app_info.version);
esp_app_desc_t running_app_info;
if (esp_ota_get_partition_description(running, &running_app_info) == ESP_OK) {
ESP_LOGI(TAGPARTOTA, "Running firmware version: %s", running_app_info.version);
ESP_LOGI(TAG, "Running firmware version: %s", running_app_info.version);
}
const esp_partition_t* last_invalid_app = esp_ota_get_last_invalid_partition();
esp_app_desc_t invalid_app_info;
if (esp_ota_get_partition_description(last_invalid_app, &invalid_app_info) == ESP_OK) {
ESP_LOGI(TAGPARTOTA, "Last invalid firmware version: %s", invalid_app_info.version);
ESP_LOGI(TAG, "Last invalid firmware version: %s", invalid_app_info.version);
}
// check current version with last invalid partition
if (last_invalid_app != NULL) {
if (memcmp(invalid_app_info.version, new_app_info.version, sizeof(new_app_info.version)) == 0) {
ESP_LOGW(TAGPARTOTA, "New version is the same as invalid version.");
ESP_LOGW(TAGPARTOTA, "Previously, there was an attempt to launch the firmware with %s version, but it failed.", invalid_app_info.version);
ESP_LOGW(TAGPARTOTA, "The firmware has been rolled back to the previous version.");
ESP_LOGW(TAG, "New version is the same as invalid version.");
ESP_LOGW(TAG, "Previously, there was an attempt to launch the firmware with %s version, but it failed.", invalid_app_info.version);
ESP_LOGW(TAG, "The firmware has been rolled back to the previous version.");
infinite_loop();
}
}
/*
if (memcmp(new_app_info.version, running_app_info.version, sizeof(new_app_info.version)) == 0) {
ESP_LOGW(TAGPARTOTA, "Current running version is the same as a new. We will not continue the update.");
ESP_LOGW(TAG, "Current running version is the same as a new. We will not continue the update.");
infinite_loop();
}
*/
@@ -149,12 +220,12 @@ static bool ota_update_task(std::string fn)
err = esp_ota_begin(update_partition, OTA_SIZE_UNKNOWN, &update_handle);
if (err != ESP_OK) {
ESP_LOGE(TAGPARTOTA, "esp_ota_begin failed (%s)", esp_err_to_name(err));
ESP_LOGE(TAG, "esp_ota_begin failed (%s)", esp_err_to_name(err));
return false;
}
ESP_LOGI(TAGPARTOTA, "esp_ota_begin succeeded");
ESP_LOGI(TAG, "esp_ota_begin succeeded");
} else {
ESP_LOGE(TAGPARTOTA, "received package is not fit len");
ESP_LOGE(TAG, "received package is not fit len");
return false;
}
}
@@ -163,38 +234,38 @@ static bool ota_update_task(std::string fn)
return false;
}
binary_file_length += data_read;
ESP_LOGD(TAGPARTOTA, "Written image length %d", binary_file_length);
ESP_LOGD(TAG, "Written image length %d", binary_file_length);
} else if (data_read == 0) {
//
// * As esp_http_client_read never returns negative error code, we rely on
// * `errno` to check for underlying transport connectivity closure if any
//
if (errno == ECONNRESET || errno == ENOTCONN) {
ESP_LOGE(TAGPARTOTA, "Connection closed, errno = %d", errno);
ESP_LOGE(TAG, "Connection closed, errno = %d", errno);
break;
}
}
data_read = fread(ota_write_data, 1, BUFFSIZE, f);
data_read = fread(ota_write_data, 1, SERVER_OTA_SCRATCH_BUFSIZE, f);
}
fclose(f);
ESP_LOGI(TAGPARTOTA, "Total Write binary data length: %d", binary_file_length);
ESP_LOGI(TAG, "Total Write binary data length: %d", binary_file_length);
err = esp_ota_end(update_handle);
if (err != ESP_OK) {
if (err == ESP_ERR_OTA_VALIDATE_FAILED) {
ESP_LOGE(TAGPARTOTA, "Image validation failed, image is corrupted");
ESP_LOGE(TAG, "Image validation failed, image is corrupted");
}
ESP_LOGE(TAGPARTOTA, "esp_ota_end failed (%s)!", esp_err_to_name(err));
ESP_LOGE(TAG, "esp_ota_end failed (%s)!", esp_err_to_name(err));
return false;
}
err = esp_ota_set_boot_partition(update_partition);
if (err != ESP_OK) {
ESP_LOGE(TAGPARTOTA, "esp_ota_set_boot_partition failed (%s)!", esp_err_to_name(err));
ESP_LOGE(TAG, "esp_ota_set_boot_partition failed (%s)!", esp_err_to_name(err));
}
// ESP_LOGI(TAGPARTOTA, "Prepare to restart system!");
// ESP_LOGI(TAG, "Prepare to restart system!");
// esp_restart();
return true ;
@@ -208,7 +279,7 @@ static void print_sha256 (const uint8_t *image_hash, const char *label)
for (int i = 0; i < HASH_LEN; ++i) {
sprintf(&hash_print[i * 2], "%02x", image_hash[i]);
}
ESP_LOGI(TAGPARTOTA, "%s: %s", label, hash_print);
ESP_LOGI(TAG, "%s: %s", label, hash_print);
}
@@ -217,10 +288,10 @@ static bool diagnostic(void)
return true;
}
void CheckOTAUpdate(void)
{
ESP_LOGI(TAGPARTOTA, "Start CheckOTAUpdateCheck ...");
printf("Start CheckOTAUpdateCheck ...\n");
ESP_LOGI(TAG, "Start CheckOTAUpdateCheck...");
uint8_t sha_256[HASH_LEN] = { 0 };
esp_partition_t partition;
@@ -249,31 +320,29 @@ void CheckOTAUpdate(void)
switch (res_stat_partition)
{
case ESP_OK:
printf("CheckOTAUpdate Partition: ESP_OK\n");
ESP_LOGD(TAG, "CheckOTAUpdate Partition: ESP_OK");
if (esp_ota_get_state_partition(running, &ota_state) == ESP_OK) {
if (ota_state == ESP_OTA_IMG_PENDING_VERIFY) {
// run diagnostic function ...
bool diagnostic_is_ok = diagnostic();
if (diagnostic_is_ok) {
ESP_LOGI(TAGPARTOTA, "Diagnostics completed successfully! Continuing execution ...");
printf("Diagnostics completed successfully! Continuing execution ...\n");
ESP_LOGI(TAG, "Diagnostics completed successfully! Continuing execution...");
esp_ota_mark_app_valid_cancel_rollback();
} else {
ESP_LOGE(TAGPARTOTA, "Diagnostics failed! Start rollback to the previous version ...");
printf("Diagnostics failed! Start rollback to the previous version ...\n");
ESP_LOGE(TAG, "Diagnostics failed! Start rollback to the previous version...");
esp_ota_mark_app_invalid_rollback_and_reboot();
}
}
}
break;
case ESP_ERR_INVALID_ARG:
printf("CheckOTAUpdate Partition: ESP_ERR_INVALID_ARG\n");
ESP_LOGD(TAG, "CheckOTAUpdate Partition: ESP_ERR_INVALID_ARG");
break;
case ESP_ERR_NOT_SUPPORTED:
printf("CheckOTAUpdate Partition: ESP_ERR_NOT_SUPPORTED\n");
ESP_LOGD(TAG, "CheckOTAUpdate Partition: ESP_ERR_NOT_SUPPORTED");
break;
case ESP_ERR_NOT_FOUND:
printf("CheckOTAUpdate Partition: ESP_ERR_NOT_FOUND\n");
ESP_LOGD(TAG, "CheckOTAUpdate Partition: ESP_ERR_NOT_FOUND");
break;
}
if (esp_ota_get_state_partition(running, &ota_state) == ESP_OK) {
@@ -281,12 +350,10 @@ void CheckOTAUpdate(void)
// run diagnostic function ...
bool diagnostic_is_ok = diagnostic();
if (diagnostic_is_ok) {
ESP_LOGI(TAGPARTOTA, "Diagnostics completed successfully! Continuing execution ...");
printf("Diagnostics completed successfully! Continuing execution ...\n");
ESP_LOGI(TAG, "Diagnostics completed successfully! Continuing execution...");
esp_ota_mark_app_valid_cancel_rollback();
} else {
ESP_LOGE(TAGPARTOTA, "Diagnostics failed! Start rollback to the previous version ...");
printf("Diagnostics failed! Start rollback to the previous version ...\n");
ESP_LOGE(TAG, "Diagnostics failed! Start rollback to the previous version...");
esp_ota_mark_app_invalid_rollback_and_reboot();
}
}
@@ -294,14 +361,13 @@ void CheckOTAUpdate(void)
}
esp_err_t handler_ota_update(httpd_req_t *req)
{
#ifdef DEBUG_DETAIL_ON
LogFile.WriteHeapInfo("handler_ota_update - Start");
#endif
LogFile.WriteToFile("handler_ota_update");
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "handler_ota_update");
char _query[200];
char _filename[100];
char _valuechar[30];
@@ -311,27 +377,44 @@ esp_err_t handler_ota_update(httpd_req_t *req)
if (httpd_req_get_url_query_str(req, _query, 200) == ESP_OK)
{
printf("Query: "); printf(_query); printf("\n");
ESP_LOGD(TAG, "Query: %s", _query);
if (httpd_query_key_value(_query, "task", _valuechar, 30) == ESP_OK)
{
printf("task is found: "); printf(_valuechar); printf("\n");
ESP_LOGD(TAG, "task is found: %s", _valuechar);
_task = std::string(_valuechar);
}
if (httpd_query_key_value(_query, "file", _filename, 100) == ESP_OK)
{
fn.append(_filename);
printf("File: "); printf(fn.c_str()); printf("\n");
ESP_LOGD(TAG, "File: %s", fn.c_str());
}
if (httpd_query_key_value(_query, "delete", _filename, 100) == ESP_OK)
{
fn.append(_filename);
_file_del = true;
printf("Delete Default File: "); printf(fn.c_str()); printf("\n");
ESP_LOGD(TAG, "Delete Default File: %s", fn.c_str());
}
};
}
if (_task.compare("emptyfirmwaredir") == 0)
{
ESP_LOGD(TAG, "Start empty directory /firmware");
delete_all_in_directory("/sdcard/firmware");
std::string zw = "firmware directory deleted - v2\n";
ESP_LOGD(TAG, "%s", zw.c_str());
printf("Ausgabe: %s\n", zw.c_str());
httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
httpd_resp_send(req, zw.c_str(), strlen(zw.c_str()));
/* Respond with an empty chunk to signal HTTP response completion */
httpd_resp_send_chunk(req, NULL, 0);
ESP_LOGD(TAG, "Done empty directory /firmware");
return ESP_OK;
}
if (_task.compare("update") == 0)
{
@@ -359,30 +442,23 @@ esp_err_t handler_ota_update(httpd_req_t *req)
}
if (filetype == "ZIP")
if ((filetype == "ZIP") || (filetype == "BIN"))
{
std::string in, out, outbin, zw, retfirmware;
FILE *pfile;
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Update for reboot.");
pfile = fopen("/sdcard/update.txt", "w");
fwrite(fn.c_str(), fn.length(), 1, pfile);
fclose(pfile);
out = "/sdcard/html";
outbin = "/sdcard/firmware";
std::string zw = "reboot\n";
httpd_resp_sendstr_chunk(req, zw.c_str());
httpd_resp_sendstr_chunk(req, NULL);
ESP_LOGD(TAG, "Send reboot");
return ESP_OK;
retfirmware = unzip_new(fn, out+"/", outbin+"/");
if (retfirmware.length() > 0)
{
filetype = "BIN";
fn = retfirmware;
}
else
{
zw = "Web Interface Update Successfull!\nNo reboot necessary.\n";
httpd_resp_sendstr_chunk(req, zw.c_str());
httpd_resp_sendstr_chunk(req, NULL);
return ESP_OK;
}
}
/*
if (filetype == "BIN")
{
const char* resp_str;
@@ -394,7 +470,7 @@ esp_err_t handler_ota_update(httpd_req_t *req)
std::string zw = "reboot\n";
httpd_resp_sendstr_chunk(req, zw.c_str());
httpd_resp_sendstr_chunk(req, NULL);
printf("Send reboot\n");
ESP_LOGD(TAG, "Send reboot");
return ESP_OK;
}
@@ -407,7 +483,7 @@ esp_err_t handler_ota_update(httpd_req_t *req)
return ESP_OK;
}
*/
std::string zw = "Update failed - no valid file specified (zip, bin, tfl, tlite)!";
httpd_resp_sendstr_chunk(req, zw.c_str());
@@ -418,7 +494,7 @@ esp_err_t handler_ota_update(httpd_req_t *req)
if (_task.compare("unziphtml") == 0)
{
printf("Task unziphmtl\n");
ESP_LOGD(TAG, "Task unziphtml");
std::string in, out, zw;
in = "/sdcard/firmware/html.zip";
@@ -435,27 +511,35 @@ esp_err_t handler_ota_update(httpd_req_t *req)
if (_file_del)
{
printf("Delete !! _file_del: %s\n", fn.c_str());
ESP_LOGD(TAG, "Delete !! _file_del: %s", fn.c_str());
struct stat file_stat;
int _result = stat(fn.c_str(), &file_stat);
printf("Ergebnis %d\n", _result);
ESP_LOGD(TAG, "Ergebnis %d\n", _result);
if (_result == 0) {
printf("Deleting file : %s\n", fn.c_str());
ESP_LOGD(TAG, "Deleting file: %s", fn.c_str());
/* Delete file */
unlink(fn.c_str());
}
else
{
printf("File does not exist: %s\n", fn.c_str());
ESP_LOGD(TAG, "File does not exist: %s", fn.c_str());
}
/* Respond with an empty chunk to signal HTTP response completion */
std::string zw = "file deleted\n";
printf((zw + "\n").c_str());
ESP_LOGD(TAG, "%s", zw.c_str());
httpd_resp_send(req, zw.c_str(), strlen(zw.c_str()));
httpd_resp_send_chunk(req, NULL, 0);
return ESP_OK;
}
string zw = "ota without parameter - should not be the case!";
httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
httpd_resp_send(req, zw.c_str(), strlen(zw.c_str()));
httpd_resp_send_chunk(req, NULL, 0);
ESP_LOGE(TAG, "ota without parameter - should not be the case!");
/*
const char* resp_str;
KillTFliteTasks();
@@ -470,69 +554,121 @@ esp_err_t handler_ota_update(httpd_req_t *req)
}
httpd_resp_send(req, resp_str, strlen(resp_str));
*/
#ifdef DEBUG_DETAIL_ON
LogFile.WriteHeapInfo("handler_ota_update - Done");
#endif
#ifdef DEBUG_DETAIL_ON
LogFile.WriteHeapInfo("handler_ota_update - Done");
#endif
return ESP_OK;
};
}
void hard_restart() {
void hard_restart()
{
esp_task_wdt_init(1,true);
esp_task_wdt_add(NULL);
while(true);
}
void task_reboot(void *pvParameter)
void task_reboot(void *KillAutoFlow)
{
while(1)
{
vTaskDelay(5000 / portTICK_PERIOD_MS);
esp_restart();
hard_restart();
// write a reboot, to identify a reboot by purpouse
FILE* pfile = fopen("/sdcard/reboot.txt", "w");
std::string _s_zw= "reboot";
fwrite(_s_zw.c_str(), strlen(_s_zw.c_str()), 1, pfile);
fclose(pfile);
vTaskDelay(3000 / portTICK_PERIOD_MS);
if ((bool)KillAutoFlow) {
KillTFliteTasks(); // Kill autoflow task if executed in extra task, if not don't kill parent task
}
vTaskDelete(NULL); //Delete this task if it exits from the loop above
/* Stop service tasks */
#ifdef ENABLE_MQTT
MQTTdestroy_client(true);
#endif //ENABLE_MQTT
gpio_handler_destroy();
esp_camera_deinit();
WIFIDestroy();
vTaskDelay(3000 / portTICK_PERIOD_MS);
esp_restart(); // Reset type: CPU reset (Reset both CPUs)
vTaskDelay(5000 / portTICK_PERIOD_MS);
hard_restart(); // Reset type: System reset (Triggered by watchdog), if esp_restart stalls (WDT needs to be activated)
ESP_LOGE(TAG, "Reboot failed!");
vTaskDelete(NULL); //Delete this task if it comes to this point
}
void doReboot(){
LogFile.SwitchOnOff(true);
LogFile.WriteToFile("Reboot triggered by Software (5s).");
ESP_LOGI(TAGPARTOTA, "Reboot in 5sec");
LogFile.WriteToFile("Reboot in 5sec");
xTaskCreate(&task_reboot, "reboot", configMINIMAL_STACK_SIZE * 64, NULL, 10, NULL);
// KillTFliteTasks(); // kills itself
gpio_handler_destroy();
void doReboot()
{
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Reboot triggered by Software (5s).");
LogFile.WriteToFile(ESP_LOG_WARN, TAG, "Reboot in 5sec");
BaseType_t xReturned = xTaskCreate(&task_reboot, "task_reboot", configMINIMAL_STACK_SIZE * 3, (void*) true, 10, NULL);
if( xReturned != pdPASS )
{
ESP_LOGE(TAG, "task_reboot not created -> force reboot without killing flow");
task_reboot((void*) false);
}
vTaskDelay(10000 / portTICK_PERIOD_MS); // Prevent serving web client fetch response until system is shuting down
}
void doRebootOTA()
{
LogFile.WriteToFile(ESP_LOG_WARN, TAG, "Reboot in 5sec");
esp_camera_deinit();
vTaskDelay(5000 / portTICK_PERIOD_MS);
esp_restart();
hard_restart();
esp_restart(); // Reset type: CPU reset (Reset both CPUs)
vTaskDelay(5000 / portTICK_PERIOD_MS);
hard_restart(); // Reset type: System reset (Triggered by watchdog), if esp_restart stalls (WDT needs to be activated)
}
esp_err_t handler_reboot(httpd_req_t *req)
{
#ifdef DEBUG_DETAIL_ON
LogFile.WriteHeapInfo("handler_reboot - Start");
#endif
#ifdef DEBUG_DETAIL_ON
LogFile.WriteHeapInfo("handler_reboot - Start");
#endif
LogFile.WriteToFile("handler_reboot");
ESP_LOGI(TAGPARTOTA, "!!! System will restart within 5 sec!!!");
const char* resp_str = "<body style='font-family: arial'> <h3 id=t></h3></body><script>var h='Rebooting!<br>The page will automatically reload in about 25s.<br>'; document.getElementById('t').innerHTML=h; setInterval(function (){h +='.'; document.getElementById('t').innerHTML=h; fetch(window.location.hostname,{mode: 'no-cors'}).then(r=>{parent.location.href=('/index.html');})}, 1000);</script>";
httpd_resp_send(req, resp_str, strlen(resp_str));
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "handler_reboot");
ESP_LOGI(TAG, "!!! System will restart within 5 sec!!!");
std::string response =
"<html><head><script>"
"function m(h) {"
"document.getElementById('t').innerHTML=h;"
"setInterval(function (){h +='.'; document.getElementById('t').innerHTML=h;"
"fetch('reboot_page.html',{mode: 'no-cors'}).then(r=>{parent.location.href=('index.html');})}, 1000);"
"}</script></head></html><body style='font-family: arial'><h3 id=t></h3>"
"<script>m('Rebooting!<br>The page will automatically reload in around 25..60s.<br><br>');</script>"
"</body></html>";
httpd_resp_set_hdr(req, "Access-Control-Allow-Origin", "*");
httpd_resp_send(req, response.c_str(), strlen(response.c_str()));
doReboot();
#ifdef DEBUG_DETAIL_ON
LogFile.WriteHeapInfo("handler_reboot - Done");
#endif
#ifdef DEBUG_DETAIL_ON
LogFile.WriteHeapInfo("handler_reboot - Done");
#endif
return ESP_OK;
}
void register_server_ota_sdcard_uri(httpd_handle_t server)
{
ESP_LOGI(TAGPARTOTA, "server_ota - Registering URI handlers");
ESP_LOGI(TAG, "Registering URI handlers");
httpd_uri_t camuri = { };
camuri.method = HTTP_GET;

View File

@@ -1,11 +1,20 @@
#pragma once
#ifndef SERVEROTA_H
#define SERVEROTA_H
#include <esp_log.h>
#include <esp_http_server.h>
//#include "ClassControllCamera.h"
#include <string>
void register_server_ota_sdcard_uri(httpd_handle_t server);
void CheckOTAUpdate();
void doReboot();
void doRebootOTA();
void hard_restart();
void CheckUpdate();
#endif //SERVEROTA_H

View File

@@ -3,7 +3,10 @@
#include <string>
#include <iostream>
#include <string.h>
#include "esp_log.h"
#include "../../include/defines.h"
static const char *TAG = "CLASS";
void ClassFlow::SetInitialParameter(void)
@@ -13,30 +16,6 @@ void ClassFlow::SetInitialParameter(void)
disabled = false;
}
std::vector<string> ClassFlow::ZerlegeZeile(std::string input, std::string delimiter)
{
std::vector<string> Output;
input = trim(input, delimiter);
size_t pos = findDelimiterPos(input, delimiter);
std::string token;
while (pos != std::string::npos) {
token = input.substr(0, pos);
token = trim(token, delimiter);
Output.push_back(token);
input.erase(0, pos + 1);
input = trim(input, delimiter);
pos = findDelimiterPos(input, delimiter);
}
Output.push_back(input);
return Output;
}
bool ClassFlow::isNewParagraph(string input)
{
if ((input[0] == '[') || ((input[0] == ';') && (input[1] == '[')))
@@ -105,7 +84,7 @@ std::string ClassFlow::GetParameterName(std::string _input)
{
_param = _input;
}
// printf("Parameter: %s, Pospunkt: %d\n", _param.c_str(), _pospunkt);
// ESP_LOGD(TAG, "Parameter: %s, Pospunkt: %d", _param.c_str(), _pospunkt);
return _param;
}
@@ -121,18 +100,18 @@ bool ClassFlow::getNextLine(FILE* pfile, string *rt)
if (!fgets(zw, 1024, pfile))
{
*rt = "";
printf("END OF FILE\n");
ESP_LOGD(TAG, "END OF FILE");
return false;
}
printf("%s", zw);
ESP_LOGD(TAG, "%s", zw);
*rt = zw;
*rt = trim(*rt);
while ((zw[0] == ';' || zw[0] == '#' || (rt->size() == 0)) && !(zw[1] == '[')) // Kommentarzeilen (; oder #) und Leerzeilen überspringen, es sei denn es ist ein neuer auskommentierter Paragraph
while ((zw[0] == ';' || zw[0] == '#' || (rt->size() == 0)) && !(zw[1] == '['))
{
*rt = "";
if (!fgets(zw, 1024, pfile))
return false;
printf("%s", zw);
ESP_LOGD(TAG, "%s", zw);
*rt = zw;
*rt = trim(*rt);
}

View File

@@ -1,5 +1,8 @@
#pragma once
#ifndef CLASSFLOW_H
#define CLASSFLOW_H
#include <fstream>
#include <string>
#include <vector>
@@ -9,10 +12,6 @@
using namespace std;
#define LOGFILE_TIME_FORMAT "%Y%m%d-%H%M%S"
#define LOGFILE_TIME_FORMAT_DATE_EXTR substr(0, 8)
#define LOGFILE_TIME_FORMAT_HOUR_EXTR substr(9, 2)
struct HTMLInfo
{
float val;
@@ -26,7 +25,6 @@ struct HTMLInfo
class ClassFlow
{
protected:
std::vector<string> ZerlegeZeile(string input, string delimiter = " =, \t");
bool isNewParagraph(string input);
bool GetNextParagraph(FILE* pfile, string& aktparamgraph);
bool getNextLine(FILE* pfile, string* rt);
@@ -53,3 +51,4 @@ public:
};
#endif //CLASSFLOW_H

View File

@@ -1,15 +1,17 @@
#include "ClassFlowAlignment.h"
#include "ClassFlowMakeImage.h"
#include "ClassFlow.h"
#include "server_tflite.h"
#include "CRotateImage.h"
#include "esp_log.h"
#include "ClassLogFile.h"
#include "../../include/defines.h"
bool AlignmentExtendedDebugging = true;
static const char *TAG = "ALIGN";
// #define DEBUG_DETAIL_ON
@@ -28,11 +30,15 @@ void ClassFlowAlignment::SetInitialParameter(void)
AlignAndCutImage = NULL;
ImageBasis = NULL;
ImageTMP = NULL;
#ifdef ALGROI_LOAD_FROM_MEM_AS_JPG
AlgROI = (ImageData*)heap_caps_malloc(sizeof(ImageData), MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM);
#endif
previousElement = NULL;
disabled = false;
SAD_criteria = 0.05;
}
ClassFlowAlignment::ClassFlowAlignment(std::vector<ClassFlow*>* lfc)
{
SetInitialParameter();
@@ -46,9 +52,9 @@ ClassFlowAlignment::ClassFlowAlignment(std::vector<ClassFlow*>* lfc)
}
}
if (!ImageBasis) // die Funktion Bilder aufnehmen existiert nicht --> muss erst erzeugt werden NUR ZU TESTZWECKEN
if (!ImageBasis) // the function take pictures does not exist --> must be created first ONLY FOR TEST PURPOSES
{
if (AlignmentExtendedDebugging) printf("CImageBasis had to be created\n");
ESP_LOGD(TAG, "CImageBasis had to be created");
ImageBasis = new CImageBasis(namerawimage);
}
}
@@ -56,7 +62,7 @@ ClassFlowAlignment::ClassFlowAlignment(std::vector<ClassFlow*>* lfc)
bool ClassFlowAlignment::ReadParameter(FILE* pfile, string& aktparamgraph)
{
std::vector<string> zerlegt;
std::vector<string> splitted;
int suchex = 40;
int suchey = 40;
int alg_algo = 0;
@@ -68,61 +74,61 @@ bool ClassFlowAlignment::ReadParameter(FILE* pfile, string& aktparamgraph)
if (!this->GetNextParagraph(pfile, aktparamgraph))
return false;
if (aktparamgraph.compare("[Alignment]") != 0) // Paragraph passt nich zu MakeImage
if (aktparamgraph.compare("[Alignment]") != 0) //Paragraph does not fit MakeImage
return false;
while (this->getNextLine(pfile, &aktparamgraph) && !this->isNewParagraph(aktparamgraph))
{
zerlegt = ZerlegeZeile(aktparamgraph);
if ((toUpper(zerlegt[0]) == "FLIPIMAGESIZE") && (zerlegt.size() > 1))
splitted = ZerlegeZeile(aktparamgraph);
if ((toUpper(splitted[0]) == "FLIPIMAGESIZE") && (splitted.size() > 1))
{
if (toUpper(zerlegt[1]) == "TRUE")
if (toUpper(splitted[1]) == "TRUE")
initialflip = true;
}
if ((toUpper(zerlegt[0]) == "INITIALMIRROR") && (zerlegt.size() > 1))
if ((toUpper(splitted[0]) == "INITIALMIRROR") && (splitted.size() > 1))
{
if (toUpper(zerlegt[1]) == "TRUE")
if (toUpper(splitted[1]) == "TRUE")
initialmirror = true;
}
if (((toUpper(zerlegt[0]) == "INITALROTATE") || (toUpper(zerlegt[0]) == "INITIALROTATE")) && (zerlegt.size() > 1))
if (((toUpper(splitted[0]) == "INITALROTATE") || (toUpper(splitted[0]) == "INITIALROTATE")) && (splitted.size() > 1))
{
this->initalrotate = std::stod(zerlegt[1]);
this->initalrotate = std::stod(splitted[1]);
}
if ((toUpper(zerlegt[0]) == "SEARCHFIELDX") && (zerlegt.size() > 1))
if ((toUpper(splitted[0]) == "SEARCHFIELDX") && (splitted.size() > 1))
{
suchex = std::stod(zerlegt[1]);
suchex = std::stod(splitted[1]);
}
if ((toUpper(zerlegt[0]) == "SEARCHFIELDY") && (zerlegt.size() > 1))
if ((toUpper(splitted[0]) == "SEARCHFIELDY") && (splitted.size() > 1))
{
suchey = std::stod(zerlegt[1]);
suchey = std::stod(splitted[1]);
}
if ((toUpper(zerlegt[0]) == "ANTIALIASING") && (zerlegt.size() > 1))
if ((toUpper(splitted[0]) == "ANTIALIASING") && (splitted.size() > 1))
{
if (toUpper(zerlegt[1]) == "TRUE")
if (toUpper(splitted[1]) == "TRUE")
use_antialiasing = true;
}
if ((zerlegt.size() == 3) && (anz_ref < 2))
if ((splitted.size() == 3) && (anz_ref < 2))
{
References[anz_ref].image_file = FormatFileName("/sdcard" + zerlegt[0]);
References[anz_ref].target_x = std::stod(zerlegt[1]);
References[anz_ref].target_y = std::stod(zerlegt[2]);
References[anz_ref].image_file = FormatFileName("/sdcard" + splitted[0]);
References[anz_ref].target_x = std::stod(splitted[1]);
References[anz_ref].target_y = std::stod(splitted[2]);
anz_ref++;
}
if ((toUpper(zerlegt[0]) == "SAVEALLFILES") && (zerlegt.size() > 1))
if ((toUpper(splitted[0]) == "SAVEALLFILES") && (splitted.size() > 1))
{
if (toUpper(zerlegt[1]) == "TRUE")
if (toUpper(splitted[1]) == "TRUE")
SaveAllFiles = true;
}
if ((toUpper(zerlegt[0]) == "ALIGNMENTALGO") && (zerlegt.size() > 1))
if ((toUpper(splitted[0]) == "ALIGNMENTALGO") && (splitted.size() > 1))
{
#ifdef DEBUG_DETAIL_ON
std::string zw2 = "Alignmentmodus gewählt: " + zerlegt[1];
LogFile.WriteToFile(zw2);
#endif
if (toUpper(zerlegt[1]) == "HIGHACCURACY")
#ifdef DEBUG_DETAIL_ON
std::string zw2 = "Alignment mode selected: " + splitted[1];
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, zw2);
#endif
if (toUpper(splitted[1]) == "HIGHACCURACY")
alg_algo = 1;
if (toUpper(zerlegt[1]) == "FAST")
if (toUpper(splitted[1]) == "FAST")
alg_algo = 2;
}
}
@@ -133,10 +139,10 @@ bool ClassFlowAlignment::ReadParameter(FILE* pfile, string& aktparamgraph)
References[i].search_y = suchey;
References[i].fastalg_SAD_criteria = SAD_criteria;
References[i].alignment_algo = alg_algo;
#ifdef DEBUG_DETAIL_ON
std::string zw2 = "Alignmentmodus geschrieben: " + std::to_string(alg_algo);
LogFile.WriteToFile(zw2);
#endif
#ifdef DEBUG_DETAIL_ON
std::string zw2 = "Alignment mode written: " + std::to_string(alg_algo);
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, zw2);
#endif
}
LoadReferenceAlignmentValues();
@@ -145,6 +151,7 @@ bool ClassFlowAlignment::ReadParameter(FILE* pfile, string& aktparamgraph)
}
string ClassFlowAlignment::getHTMLSingleStep(string host)
{
string result;
@@ -158,12 +165,42 @@ string ClassFlowAlignment::getHTMLSingleStep(string host)
bool ClassFlowAlignment::doFlow(string time)
{
if (!ImageTMP)
ImageTMP = new CImageBasis(ImageBasis, 5);
#ifdef ALGROI_LOAD_FROM_MEM_AS_JPG
if (!AlgROI) // AlgROI needs to be allocated before ImageTMP to avoid heap fragmentation
{
AlgROI = (ImageData*)heap_caps_realloc(AlgROI, sizeof(ImageData), MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM);
if (!AlgROI)
{
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Can't allocate AlgROI");
LogFile.WriteHeapInfo("ClassFlowAlignment-doFlow");
}
}
if (AlignAndCutImage)
delete AlignAndCutImage;
AlignAndCutImage = new CAlignAndCutImage(ImageBasis, ImageTMP);
if (AlgROI)
{
ImageBasis->writeToMemoryAsJPG((ImageData*)AlgROI, 90);
}
#endif
if (!ImageTMP)
{
ImageTMP = new CImageBasis(ImageBasis);
if (!ImageTMP)
{
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Can't allocate ImageTMP -> Exec this round aborted!");
LogFile.WriteHeapInfo("ClassFlowAlignment-doFlow");
return false;
}
}
delete AlignAndCutImage;
AlignAndCutImage = new CAlignAndCutImage(ImageBasis, ImageTMP);
if (!AlignAndCutImage)
{
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Can't allocate AlignAndCutImage -> Exec this round aborted!");
LogFile.WriteHeapInfo("ClassFlowAlignment-doFlow");
return false;
}
CRotateImage rt(AlignAndCutImage, ImageTMP, initialflip);
if (initialflip)
@@ -173,10 +210,13 @@ bool ClassFlowAlignment::doFlow(string time)
ImageBasis->width = _zw;
}
if (initialmirror){
printf("do mirror\n");
if (initialmirror)
{
ESP_LOGD(TAG, "do mirror");
rt.Mirror();
if (SaveAllFiles) AlignAndCutImage->SaveToFile(FormatFileName("/sdcard/img_tmp/mirror.jpg"));
if (SaveAllFiles)
AlignAndCutImage->SaveToFile(FormatFileName("/sdcard/img_tmp/mirror.jpg"));
}
if ((initalrotate != 0) || initialflip)
@@ -185,7 +225,9 @@ bool ClassFlowAlignment::doFlow(string time)
rt.RotateAntiAliasing(initalrotate);
else
rt.Rotate(initalrotate);
if (SaveAllFiles) AlignAndCutImage->SaveToFile(FormatFileName("/sdcard/img_tmp/rot.jpg"));
if (SaveAllFiles)
AlignAndCutImage->SaveToFile(FormatFileName("/sdcard/img_tmp/rot.jpg"));
}
if (!AlignAndCutImage->Align(&References[0], &References[1]))
@@ -193,8 +235,15 @@ bool ClassFlowAlignment::doFlow(string time)
SaveReferenceAlignmentValues();
}
if (SaveAllFiles) AlignAndCutImage->SaveToFile(FormatFileName("/sdcard/img_tmp/alg.jpg"));
#ifdef ALGROI_LOAD_FROM_MEM_AS_JPG
if (AlgROI) {
DrawRef(ImageTMP);
tfliteflow.DigitalDrawROI(ImageTMP);
tfliteflow.AnalogDrawROI(ImageTMP);
ImageTMP->writeToMemoryAsJPG((ImageData*)AlgROI, 90);
}
#endif
if (SaveAllFiles)
{
if (initialflip)
@@ -203,15 +252,14 @@ bool ClassFlowAlignment::doFlow(string time)
ImageTMP->width = ImageTMP->height;
ImageTMP->height = _zw;
}
DrawRef(ImageTMP);
AlignAndCutImage->SaveToFile(FormatFileName("/sdcard/img_tmp/alg.jpg"));
ImageTMP->SaveToFile(FormatFileName("/sdcard/img_tmp/alg_roi.jpg"));
}
if (ImageTMP) // nuss gelöscht werden, um Speicherplatz für das Laden von tflite zu haben
{
delete ImageTMP;
ImageTMP = NULL;
}
// must be deleted to have memory space for loading tflite
delete ImageTMP;
ImageTMP = NULL;
LoadReferenceAlignmentValues();
@@ -219,7 +267,6 @@ bool ClassFlowAlignment::doFlow(string time)
}
void ClassFlowAlignment::SaveReferenceAlignmentValues()
{
FILE* pFile;
@@ -259,92 +306,74 @@ void ClassFlowAlignment::SaveReferenceAlignmentValues()
}
bool ClassFlowAlignment::LoadReferenceAlignmentValues(void)
{
FILE* pFile;
char zw[1024];
string zwvalue;
std::vector<string> zerlegt;
std::vector<string> splitted;
// LogFile.WriteToDedicatedFile("/sdcard/alignment.txt", "LoadReferenceAlignmentValues01");
pFile = fopen(FileStoreRefAlignment.c_str(), "r");
if (pFile == NULL)
return false;
// LogFile.WriteToDedicatedFile("/sdcard/alignment.txt", "LoadReferenceAlignmentValues01");
fgets(zw, 1024, pFile);
ESP_LOGD(TAG, "%s", zw);
fgets(zw, 1024, pFile);
printf("%s", zw);
// zwvalue = "LoadReferenceAlignmentValues Time: " + std::string(zw);
// LogFile.WriteToDedicatedFile("/sdcard/alignment.txt", zwvalue);
// LogFile.WriteToDedicatedFile("/sdcard/alignment.txt", "LoadReferenceAlignmentValues02");
fgets(zw, 1024, pFile);
zerlegt = ZerlegeZeile(std::string(zw), " \t");
if (zerlegt.size() < 6)
splitted = ZerlegeZeile(std::string(zw), " \t");
if (splitted.size() < 6)
{
// LogFile.WriteToDedicatedFile("/sdcard/alignment.txt", "Exit 01");
fclose(pFile);
return false;
}
// LogFile.WriteToDedicatedFile("/sdcard/alignment.txt", "LoadReferenceAlignmentValues03");
References[0].fastalg_x = stoi(zerlegt[0]);
References[0].fastalg_y = stoi(zerlegt[1]);
References[0].fastalg_SAD = stof(zerlegt[2]);
References[0].fastalg_min = stoi(zerlegt[3]);
References[0].fastalg_max = stoi(zerlegt[4]);
References[0].fastalg_avg = stof(zerlegt[5]);
References[0].fastalg_x = stoi(splitted[0]);
References[0].fastalg_y = stoi(splitted[1]);
References[0].fastalg_SAD = stof(splitted[2]);
References[0].fastalg_min = stoi(splitted[3]);
References[0].fastalg_max = stoi(splitted[4]);
References[0].fastalg_avg = stof(splitted[5]);
fgets(zw, 1024, pFile);
zerlegt = ZerlegeZeile(std::string(zw));
if (zerlegt.size() < 6)
splitted = ZerlegeZeile(std::string(zw));
if (splitted.size() < 6)
{
// LogFile.WriteToDedicatedFile("/sdcard/alignment.txt", "Exit 02");
fclose(pFile);
return false;
}
// LogFile.WriteToDedicatedFile("/sdcard/alignment.txt", "LoadReferenceAlignmentValues03");
References[1].fastalg_x = stoi(zerlegt[0]);
References[1].fastalg_y = stoi(zerlegt[1]);
References[1].fastalg_SAD = stof(zerlegt[2]);
References[1].fastalg_min = stoi(zerlegt[3]);
References[1].fastalg_max = stoi(zerlegt[4]);
References[1].fastalg_avg = stof(zerlegt[5]);
References[1].fastalg_x = stoi(splitted[0]);
References[1].fastalg_y = stoi(splitted[1]);
References[1].fastalg_SAD = stof(splitted[2]);
References[1].fastalg_min = stoi(splitted[3]);
References[1].fastalg_max = stoi(splitted[4]);
References[1].fastalg_avg = stof(splitted[5]);
fclose(pFile);
#ifdef DEBUG_DETAIL_ON
std::string _zw = "\tLoadReferences[0]\tx,y:\t" + std::to_string(References[0].fastalg_x) + "\t" + std::to_string(References[0].fastalg_x);
_zw = _zw + "\tSAD, min, max, avg:\t" + std::to_string(References[0].fastalg_SAD) + "\t" + std::to_string(References[0].fastalg_min);
_zw = _zw + "\t" + std::to_string(References[0].fastalg_max) + "\t" + std::to_string(References[0].fastalg_avg);
LogFile.WriteToDedicatedFile("/sdcard/alignment.txt", _zw);
_zw = "\tLoadReferences[1]\tx,y:\t" + std::to_string(References[1].fastalg_x) + "\t" + std::to_string(References[1].fastalg_x);
_zw = _zw + "\tSAD, min, max, avg:\t" + std::to_string(References[1].fastalg_SAD) + "\t" + std::to_string(References[1].fastalg_min);
_zw = _zw + "\t" + std::to_string(References[1].fastalg_max) + "\t" + std::to_string(References[1].fastalg_avg);
LogFile.WriteToDedicatedFile("/sdcard/alignment.txt", _zw);
#endif
/*#ifdef DEBUG_DETAIL_ON
std::string _zw = "\tLoadReferences[0]\tx,y:\t" + std::to_string(References[0].fastalg_x) + "\t" + std::to_string(References[0].fastalg_x);
_zw = _zw + "\tSAD, min, max, avg:\t" + std::to_string(References[0].fastalg_SAD) + "\t" + std::to_string(References[0].fastalg_min);
_zw = _zw + "\t" + std::to_string(References[0].fastalg_max) + "\t" + std::to_string(References[0].fastalg_avg);
LogFile.WriteToDedicatedFile("/sdcard/alignment.txt", _zw);
_zw = "\tLoadReferences[1]\tx,y:\t" + std::to_string(References[1].fastalg_x) + "\t" + std::to_string(References[1].fastalg_x);
_zw = _zw + "\tSAD, min, max, avg:\t" + std::to_string(References[1].fastalg_SAD) + "\t" + std::to_string(References[1].fastalg_min);
_zw = _zw + "\t" + std::to_string(References[1].fastalg_max) + "\t" + std::to_string(References[1].fastalg_avg);
LogFile.WriteToDedicatedFile("/sdcard/alignment.txt", _zw);
#endif*/
return true;
}
void ClassFlowAlignment::DrawRef(CImageBasis *_zw)
{
_zw->drawRect(References[0].target_x, References[0].target_y, References[0].width, References[0].height, 255, 0, 0, 2);
_zw->drawRect(References[1].target_x, References[1].target_y, References[1].width, References[1].height, 255, 0, 0, 2);
if (_zw->ImageOkay())
{
_zw->drawRect(References[0].target_x, References[0].target_y, References[0].width, References[0].height, 255, 0, 0, 2);
_zw->drawRect(References[1].target_x, References[1].target_y, References[1].width, References[1].height, 255, 0, 0, 2);
}
}

View File

@@ -1,5 +1,8 @@
#pragma once
#ifndef CLASSFLOWALIGNMENT_H
#define CLASSFLOWALIGNMENT_H
#include "ClassFlow.h"
#include "Helper.h"
#include "CAlignAndCutImage.h"
@@ -31,6 +34,9 @@ protected:
public:
CImageBasis *ImageBasis, *ImageTMP;
#ifdef ALGROI_LOAD_FROM_MEM_AS_JPG
ImageData *AlgROI;
#endif
ClassFlowAlignment(std::vector<ClassFlow*>* lfc);
@@ -44,3 +50,5 @@ public:
string name(){return "ClassFlowAlignment";};
};
#endif //CLASSFLOWALIGNMENT_H

File diff suppressed because it is too large Load Diff

View File

@@ -1,5 +1,7 @@
#ifndef __CLASSCNNGENERAL__
#define __CLASSCNNGENERAL__
#pragma once
#ifndef CLASSFLOWCNNGENERAL_H
#define CLASSFLOWCNNGENERAL_H
#include"ClassFlowDefineTypes.h"
#include "ClassFlowAlignment.h"
@@ -23,14 +25,15 @@ protected:
t_CNNType CNNType;
std::vector<general*> GENERAL;
float CNNGoodThreshold;
float AnalogFehler = 3.0;
float AnalogToDigtalFehler = 0.8;
float DigitalUnschaerfe = 0.2;
int DigitalBand = 3;
float DigitalAnalogerVorgaengerUebergangsbereich = 2;
float DigitalUebergangsbereichVorgaengerAnalogToDigit = 1; // war vorher 2
float DigitalUebergangsbereichVorgaenger = 0.7; // 9.3 - 0.7
float DigitalUebergangsbereichVorlauf = 9.7; // Vorlauf-Nulldurchgang passiert erst ab ca. 9.7
//moved to define.h
//float Analog_error = 3.0;
//float AnalogToDigtalFehler = 0.8;
//float Digital_Uncertainty = 0.2;
//int DigitalBand = 3;
//float Digital_Transition_Range_Predecessor = 2;
//float Digital_Transition_Area_Predecessor = 0.7; // 9.3 - 0.7
//float Digital_Transition_Area_Forward = 9.7; // Pre-run zero crossing only happens from approx. 9.7 onwards
string cnnmodelfile;
int modelxsize, modelysize, modelchannel;
@@ -40,9 +43,9 @@ protected:
bool SaveAllFiles;
int ZeigerEvalAnalogNeu(float zahl, int ziffer_vorgaenger);
int ZeigerEvalAnalogToDigitNeu(float zahl, float ziffer_vorgaenger, int eval_vorgaenger);
int ZeigerEvalHybridNeu(float zahl, float zahl_vorgaenger, int eval_vorgaenger, bool AnalogerVorgaenger = false);
int PointerEvalAnalogNew(float zahl, int numeral_preceder);
int PointerEvalAnalogToDigitNew(float zahl, float numeral_preceder, int eval_predecessors, float analogDigitalTransitionStart);
int PointerEvalHybridNew(float zahl, float number_of_predecessors, int eval_predecessors, bool Analog_Predecessors = false, float analogDigitalTransitionStart=9.2);
@@ -58,13 +61,15 @@ public:
bool doFlow(string time);
string getHTMLSingleStep(string host);
string getReadout(int _analog, bool _extendedResolution = false, int prev = -1, float _vorgaengerAnalog = -1);
string getReadout(int _analog, bool _extendedResolution = false, int prev = -1, float _before_narrow_Analog = -1, float analogDigitalTransitionStart=9.2);
string getReadoutRawString(int _analog);
void DrawROI(CImageBasis *_zw);
std::vector<HTMLInfo*> GetHTMLInfo();
int getAnzahlGENERAL();
int getNumberGENERAL();
general* GetGENERAL(int _analog);
general* GetGENERAL(string _name, bool _create);
general* FindGENERAL(string _name_number);

View File

@@ -19,21 +19,25 @@ extern "C" {
#include "time_sntp.h"
#include "Helper.h"
#include "server_ota.h"
//#include "CImg.h"
#ifdef ENABLE_MQTT
#include "interface_mqtt.h"
#include "server_mqtt.h"
#endif //ENABLE_MQTT
#include "server_help.h"
#include "../../include/defines.h"
//#define DEBUG_DETAIL_ON
static const char* TAG = "CTRL";
static const char* TAG = "flow_controll";
//#define DEBUG_DETAIL_ON
std::string ClassFlowControll::doSingleStep(std::string _stepname, std::string _host){
std::string _classname = "";
std::string result = "";
// printf("_stepname: %s\n", _stepname.c_str());
ESP_LOGD(TAG, "Step %s start", _stepname.c_str());
if ((_stepname.compare("[MakeImage]") == 0) || (_stepname.compare(";[MakeImage]") == 0)){
_classname = "ClassFlowMakeImage";
}
@@ -46,20 +50,27 @@ std::string ClassFlowControll::doSingleStep(std::string _stepname, std::string _
if ((_stepname.compare("[Analog]") == 0) || (_stepname.compare(";[Analog]") == 0)){
_classname = "ClassFlowCNNGeneral";
}
#ifdef ENABLE_MQTT
if ((_stepname.compare("[MQTT]") == 0) || (_stepname.compare(";[MQTT]") == 0)){
_classname = "ClassFlowMQTT";
}
#endif //ENABLE_MQTT
#ifdef ENABLE_INFLUXDB
if ((_stepname.compare("[InfluxDB]") == 0) || (_stepname.compare(";[InfluxDB]") == 0)){
_classname = "ClassFlowInfluxDB";
}
#endif //ENABLE_INFLUXDB
for (int i = 0; i < FlowControll.size(); ++i)
if (FlowControll[i]->name().compare(_classname) == 0){
if (!(FlowControll[i]->name().compare("ClassFlowMakeImage") == 0)) // falls es ein MakeImage ist, braucht das Bild nicht extra aufgenommen zu werden, dass passiert bei html-Abfrage automatisch
if (!(FlowControll[i]->name().compare("ClassFlowMakeImage") == 0)) // if it is a MakeImage, the image does not need to be included, this happens automatically with the html query.
FlowControll[i]->doFlow("");
result = FlowControll[i]->getHTMLSingleStep(_host);
}
ESP_LOGD(TAG, "Step %s end", _stepname.c_str());
return result;
}
@@ -72,14 +83,18 @@ std::string ClassFlowControll::TranslateAktstatus(std::string _input)
return ("Aligning");
if (_input.compare("ClassFlowCNNGeneral") == 0)
return ("Digitalization of ROIs");
if (_input.compare("ClassFlowMQTT") == 0)
return ("Sending MQTT");
if (_input.compare("ClassFlowInfluxDB") == 0)
return ("Sending InfluxDB");
#ifdef ENABLE_MQTT
if (_input.compare("ClassFlowMQTT") == 0)
return ("Sending MQTT");
#endif //ENABLE_MQTT
#ifdef ENABLE_INFLUXDB
if (_input.compare("ClassFlowInfluxDB") == 0)
return ("Sending InfluxDB");
#endif //ENABLE_INFLUXDB
if (_input.compare("ClassFlowPostProcessing") == 0)
return ("Processing");
return ("Post-Processing");
if (_input.compare("ClassFlowWriteList") == 0)
return ("Processing");
return ("Writing List");
return "Unkown Status";
}
@@ -89,7 +104,7 @@ std::vector<HTMLInfo*> ClassFlowControll::GetAllDigital()
{
if (flowdigit)
{
printf("ClassFlowControll::GetAllDigital - flowdigit != NULL\n");
ESP_LOGD(TAG, "ClassFlowControll::GetAllDigital - flowdigit != NULL");
return flowdigit->GetHTMLInfo();
}
@@ -97,6 +112,7 @@ std::vector<HTMLInfo*> ClassFlowControll::GetAllDigital()
return empty;
}
std::vector<HTMLInfo*> ClassFlowControll::GetAllAnalog()
{
if (flowanalog)
@@ -106,6 +122,7 @@ std::vector<HTMLInfo*> ClassFlowControll::GetAllAnalog()
return empty;
}
t_CNNType ClassFlowControll::GetTypeDigital()
{
if (flowdigit)
@@ -114,6 +131,7 @@ t_CNNType ClassFlowControll::GetTypeDigital()
return t_CNNType::None;
}
t_CNNType ClassFlowControll::GetTypeAnalog()
{
if (flowanalog)
@@ -123,40 +141,65 @@ t_CNNType ClassFlowControll::GetTypeAnalog()
}
#ifdef ALGROI_LOAD_FROM_MEM_AS_JPG
void ClassFlowControll::DigitalDrawROI(CImageBasis *_zw)
{
if (flowdigit)
flowdigit->DrawROI(_zw);
}
void ClassFlowControll::AnalogDrawROI(CImageBasis *_zw)
{
if (flowanalog)
flowanalog->DrawROI(_zw);
}
#endif
#ifdef ENABLE_MQTT
string ClassFlowControll::GetMQTTMainTopic()
{
for (int i = 0; i < FlowControll.size(); ++i)
if (FlowControll[i]->name().compare("ClassFlowMQTT") == 0)
return ((ClassFlowMQTT*) (FlowControll[i]))->GetMQTTMainTopic();
return "";
}
bool ClassFlowControll::StartMQTTService() {
/* Start the MQTT service */
for (int i = 0; i < FlowControll.size(); ++i) {
if (FlowControll[i]->name().compare("ClassFlowMQTT") == 0) {
return ((ClassFlowMQTT*) (FlowControll[i]))->Start(AutoIntervall);
}
}
return false;
}
#endif //ENABLE_MQTT
void ClassFlowControll::SetInitialParameter(void)
{
AutoStart = false;
SetupModeActive = false;
AutoIntervall = 10;
AutoIntervall = 10; // Minutes
flowdigit = NULL;
flowanalog = NULL;
flowpostprocessing = NULL;
disabled = false;
aktRunNr = 0;
aktstatus = "Booting ...";
aktstatus = "Flow task not yet created";
}
bool ClassFlowControll::isAutoStart(long &_intervall)
{
_intervall = AutoIntervall * 60 * 1000; // AutoIntervall: Minuten -> ms
_intervall = AutoIntervall * 60 * 1000; // AutoInterval: minutes -> ms
return AutoStart;
}
ClassFlow* ClassFlowControll::CreateClassFlow(std::string _type)
{
ClassFlow* cfc = NULL;
@@ -183,12 +226,14 @@ ClassFlow* ClassFlowControll::CreateClassFlow(std::string _type)
cfc = new ClassFlowCNNGeneral(flowalignment);
flowdigit = (ClassFlowCNNGeneral*) cfc;
}
#ifdef ENABLE_MQTT
if (toUpper(_type).compare("[MQTT]") == 0)
cfc = new ClassFlowMQTT(&FlowControll);
#endif //ENABLE_MQTT
#ifdef ENABLE_INFLUXDB
if (toUpper(_type).compare("[INFLUXDB]") == 0)
cfc = new ClassFlowInfluxDB(&FlowControll);
#endif //ENABLE_INFLUXDB
if (toUpper(_type).compare("[WRITELIST]") == 0)
cfc = new ClassFlowWriteList(&FlowControll);
@@ -198,12 +243,15 @@ ClassFlow* ClassFlowControll::CreateClassFlow(std::string _type)
flowpostprocessing = (ClassFlowPostProcessing*) cfc;
}
if (cfc) // Wird nur angehangen, falls es nicht [AutoTimer] ist, denn dieses ist für FlowControll
if (cfc) // Attached only if it is not [AutoTimer], because this is for FlowControll
FlowControll.push_back(cfc);
if (toUpper(_type).compare("[AUTOTIMER]") == 0)
cfc = this;
if (toUpper(_type).compare("[DATALOGGING]") == 0)
cfc = this;
if (toUpper(_type).compare("[DEBUG]") == 0)
cfc = this;
@@ -213,16 +261,21 @@ ClassFlow* ClassFlowControll::CreateClassFlow(std::string _type)
return cfc;
}
void ClassFlowControll::InitFlow(std::string config)
{
aktstatus = "Initialization";
//#ifdef ENABLE_MQTT
//MQTTPublish(mqttServer_getMainTopic() + "/" + "status", "Initialization", false); // Right now, not possible -> MQTT Service is going to be started later
//#endif //ENABLE_MQTT
string line;
flowpostprocessing = NULL;
ClassFlow* cfc;
FILE* pFile;
config = FormatFileName(config);
pFile = OpenFileAndWait(config.c_str(), "r");
pFile = fopen(config.c_str(), "r");
line = "";
@@ -230,7 +283,7 @@ void ClassFlowControll::InitFlow(std::string config)
if (pFile != NULL)
{
fgets(zw, 1024, pFile);
printf("%s", zw);
ESP_LOGD(TAG, "%s", zw);
line = std::string(zw);
}
@@ -239,7 +292,7 @@ void ClassFlowControll::InitFlow(std::string config)
cfc = CreateClassFlow(line);
if (cfc)
{
printf("Start ReadParameter (%s)\n", line.c_str());
ESP_LOGD(TAG, "Start ReadParameter (%s)", line.c_str());
cfc->ReadParameter(pFile, line);
}
else
@@ -247,68 +300,90 @@ void ClassFlowControll::InitFlow(std::string config)
line = "";
if (fgets(zw, 1024, pFile) && !feof(pFile))
{
printf("Read: %s", zw);
ESP_LOGD(TAG, "Read: %s", zw);
line = std::string(zw);
}
}
}
fclose(pFile);
}
std::string* ClassFlowControll::getActStatus(){
std::string* ClassFlowControll::getActStatus()
{
return &aktstatus;
}
void ClassFlowControll::doFlowMakeImageOnly(string time){
void ClassFlowControll::setActStatus(std::string _aktstatus)
{
aktstatus = _aktstatus;
}
void ClassFlowControll::doFlowMakeImageOnly(string time)
{
std::string zw_time;
for (int i = 0; i < FlowControll.size(); ++i)
{
if (FlowControll[i]->name() == "ClassFlowMakeImage") {
// zw_time = gettimestring("%Y%m%d-%H%M%S");
zw_time = gettimestring("%H:%M:%S");
aktstatus = TranslateAktstatus(FlowControll[i]->name()) + " (" + zw_time + ")";
zw_time = getCurrentTimeString("%H:%M:%S");
std::string flowStatus = TranslateAktstatus(FlowControll[i]->name());
aktstatus = flowStatus + " (" + zw_time + ")";
#ifdef ENABLE_MQTT
MQTTPublish(mqttServer_getMainTopic() + "/" + "status", flowStatus, false);
#endif //ENABLE_MQTT
FlowControll[i]->doFlow(time);
}
}
}
bool ClassFlowControll::doFlow(string time)
{
// CleanTempFolder(); // dazu muss man noch eine Rolling einführen
bool result = true;
std::string zw_time;
int repeat = 0;
#ifdef DEBUG_DETAIL_ON
LogFile.WriteHeapInfo("ClassFlowControll::doFlow - Start");
#endif
#ifdef DEBUG_DETAIL_ON
LogFile.WriteHeapInfo("ClassFlowControll::doFlow - Start");
#endif
/* Check if we have a valid date/time and if not restart the NTP client */
/* if (! getTimeIsSet()) {
LogFile.WriteToFile(ESP_LOG_WARN, TAG, "Time not set, restarting NTP Client!");
restartNtpClient();
}*/
//checkNtpStatus(0);
for (int i = 0; i < FlowControll.size(); ++i)
{
zw_time = gettimestring("%H:%M:%S");
aktstatus = TranslateAktstatus(FlowControll[i]->name()) + " (" + zw_time + ")";
zw_time = getCurrentTimeString("%H:%M:%S");
std::string flowStatus = TranslateAktstatus(FlowControll[i]->name());
aktstatus = flowStatus + " (" + zw_time + ")";
//LogFile.WriteToFile(ESP_LOG_INFO, TAG, aktstatus);
#ifdef ENABLE_MQTT
MQTTPublish(mqttServer_getMainTopic() + "/" + "status", flowStatus, false);
#endif //ENABLE_MQTT
// zw_time = gettimestring("%Y%m%d-%H%M%S");
// aktstatus = zw_time + ": " + FlowControll[i]->name();
string zw = "FlowControll.doFlow - " + FlowControll[i]->name();
LogFile.WriteHeapInfo(zw);
#ifdef DEBUG_DETAIL_ON
string zw = "FlowControll.doFlow - " + FlowControll[i]->name();
LogFile.WriteHeapInfo(zw);
#endif
if (!FlowControll[i]->doFlow(time)){
repeat++;
LogFile.WriteToFile("Fehler im vorheriger Schritt - wird zum " + to_string(repeat) + ". Mal wiederholt");
if (i) i -= 1; // vorheriger Schritt muss wiederholt werden (vermutlich Bilder aufnehmen)
LogFile.WriteToFile(ESP_LOG_WARN, TAG, "Fehler im vorheriger Schritt - wird zum " + to_string(repeat) + ". Mal wiederholt");
if (i) i -= 1; // vPrevious step must be repeated (probably take pictures)
result = false;
if (repeat > 5) {
LogFile.SwitchOnOff(true);
LogFile.WriteToFile("Wiederholung 5x nicht erfolgreich --> reboot");
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Wiederholung 5x nicht erfolgreich --> reboot");
doReboot();
// Schritt wurde 5x wiederholt --> reboot
//Step was repeated 5x --> reboot
}
}
else
@@ -316,13 +391,19 @@ bool ClassFlowControll::doFlow(string time)
result = true;
}
#ifdef DEBUG_DETAIL_ON
LogFile.WriteHeapInfo("ClassFlowControll::doFlow");
#endif
#ifdef DEBUG_DETAIL_ON
LogFile.WriteHeapInfo("ClassFlowControll::doFlow");
#endif
}
zw_time = gettimestring("%H:%M:%S");
aktstatus = "Flow finished (" + zw_time + ")";
zw_time = getCurrentTimeString("%H:%M:%S");
std::string flowStatus = "Flow finished";
aktstatus = flowStatus + " (" + zw_time + ")";
//LogFile.WriteToFile(ESP_LOG_INFO, TAG, aktstatus);
#ifdef ENABLE_MQTT
MQTTPublish(mqttServer_getMainTopic() + "/" + "status", flowStatus, false);
#endif //ENABLE_MQTT
return result;
}
@@ -362,7 +443,7 @@ string ClassFlowControll::getReadoutAll(int _type)
if (i < (*numbers).size()-1)
out = out + "\r\n";
}
// printf("OUT: %s", out.c_str());
// ESP_LOGD(TAG, "OUT: %s", out.c_str());
}
return out;
@@ -392,6 +473,7 @@ string ClassFlowControll::getReadout(bool _rawvalue = false, bool _noerror = fal
return result;
}
string ClassFlowControll::GetPrevalue(std::string _number)
{
if (flowpostprocessing)
@@ -399,16 +481,17 @@ string ClassFlowControll::GetPrevalue(std::string _number)
return flowpostprocessing->GetPreValue(_number);
}
return std::string();
return std::string("");
}
std::string ClassFlowControll::UpdatePrevalue(std::string _newvalue, std::string _numbers, bool _extern)
{
float zw;
char* p;
_newvalue = trim(_newvalue);
// printf("Input UpdatePreValue: %s\n", _newvalue.c_str());
// ESP_LOGD(TAG, "Input UpdatePreValue: %s", _newvalue.c_str());
if (_newvalue.compare("0.0") == 0)
{
@@ -431,9 +514,10 @@ std::string ClassFlowControll::UpdatePrevalue(std::string _newvalue, std::string
return std::string();
}
bool ClassFlowControll::ReadParameter(FILE* pfile, string& aktparamgraph)
{
std::vector<string> zerlegt;
std::vector<string> splitted;
aktparamgraph = trim(aktparamgraph);
@@ -442,78 +526,102 @@ bool ClassFlowControll::ReadParameter(FILE* pfile, string& aktparamgraph)
return false;
if ((toUpper(aktparamgraph).compare("[AUTOTIMER]") != 0) && (toUpper(aktparamgraph).compare("[DEBUG]") != 0) && (toUpper(aktparamgraph).compare("[SYSTEM]") != 0)) // Paragraph passt nicht zu MakeImage
if ((toUpper(aktparamgraph).compare("[AUTOTIMER]") != 0) && (toUpper(aktparamgraph).compare("[DEBUG]") != 0) &&
(toUpper(aktparamgraph).compare("[SYSTEM]") != 0 && (toUpper(aktparamgraph).compare("[DATALOGGING]") != 0))) // Paragraph passt nicht zu MakeImage
return false;
while (this->getNextLine(pfile, &aktparamgraph) && !this->isNewParagraph(aktparamgraph))
{
zerlegt = this->ZerlegeZeile(aktparamgraph, " =");
if ((toUpper(zerlegt[0]) == "AUTOSTART") && (zerlegt.size() > 1))
splitted = ZerlegeZeile(aktparamgraph, " =");
if ((toUpper(splitted[0]) == "AUTOSTART") && (splitted.size() > 1))
{
if (toUpper(zerlegt[1]) == "TRUE")
if (toUpper(splitted[1]) == "TRUE")
{
AutoStart = true;
}
}
if ((toUpper(zerlegt[0]) == "INTERVALL") && (zerlegt.size() > 1))
if ((toUpper(splitted[0]) == "INTERVALL") && (splitted.size() > 1))
{
AutoIntervall = std::stof(zerlegt[1]);
AutoIntervall = std::stof(splitted[1]);
}
if ((toUpper(zerlegt[0]) == "LOGFILE") && (zerlegt.size() > 1))
if ((toUpper(splitted[0]) == "DATALOGACTIVE") && (splitted.size() > 1))
{
if (toUpper(zerlegt[1]) == "TRUE")
if (toUpper(splitted[1]) == "TRUE")
{
LogFile.SwitchOnOff(true);
LogFile.SetDataLogToSD(true);
}
if (toUpper(zerlegt[1]) == "FALSE")
{
LogFile.SwitchOnOff(false);
else {
LogFile.SetDataLogToSD(false);
}
}
if ((toUpper(zerlegt[0]) == "LOGFILERETENTIONINDAYS") && (zerlegt.size() > 1))
{
LogFile.SetRetention(std::stoi(zerlegt[1]));
}
if ((toUpper(zerlegt[0]) == "TIMEZONE") && (zerlegt.size() > 1))
if ((toUpper(splitted[0]) == "DATALOGRETENTIONINDAYS") && (splitted.size() > 1))
{
string zw = "Set TimeZone: " + zerlegt[1];
setTimeZone(zerlegt[1]);
}
LogFile.SetDataLogRetention(std::stoi(splitted[1]));
}
if ((toUpper(zerlegt[0]) == "TIMESERVER") && (zerlegt.size() > 1))
if ((toUpper(splitted[0]) == "LOGFILE") && (splitted.size() > 1))
{
string zw = "Set TimeZone: " + zerlegt[1];
reset_servername(zerlegt[1]);
}
if ((toUpper(zerlegt[0]) == "HOSTNAME") && (zerlegt.size() > 1))
{
if (ChangeHostName("/sdcard/wlan.ini", zerlegt[1]))
/* matches esp_log_level_t */
if ((toUpper(splitted[1]) == "TRUE") || (toUpper(splitted[1]) == "2"))
{
// reboot notwendig damit die neue wlan.ini auch benutzt wird !!!
LogFile.setLogLevel(ESP_LOG_WARN);
}
else if ((toUpper(splitted[1]) == "FALSE") || (toUpper(splitted[1]) == "0") || (toUpper(splitted[1]) == "1"))
{
LogFile.setLogLevel(ESP_LOG_ERROR);
}
else if (toUpper(splitted[1]) == "3")
{
LogFile.setLogLevel(ESP_LOG_INFO);
}
else if (toUpper(splitted[1]) == "4")
{
LogFile.setLogLevel(ESP_LOG_DEBUG);
}
}
if ((toUpper(splitted[0]) == "LOGFILERETENTIONINDAYS") && (splitted.size() > 1))
{
LogFile.SetLogFileRetention(std::stoi(splitted[1]));
}
/* TimeServer and TimeZone got already read from the config, see setupTime () */
if ((toUpper(splitted[0]) == "RSSITHREASHOLD") && (splitted.size() > 1))
{
if (ChangeRSSIThreashold(WLAN_CONFIG_FILE, atoi(splitted[1].c_str())))
{
// reboot necessary so that the new wlan.ini is also used !!!
fclose(pfile);
printf("do reboot\n");
LogFile.SwitchOnOff(true);
LogFile.WriteToFile("Reboot to activate new HOSTNAME.");
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Rebooting to activate new RSSITHREASHOLD ...");
esp_restart();
hard_restart();
doReboot();
}
}
if ((toUpper(zerlegt[0]) == "SETUPMODE") && (zerlegt.size() > 1))
if ((toUpper(splitted[0]) == "HOSTNAME") && (splitted.size() > 1))
{
if (toUpper(zerlegt[1]) == "TRUE")
if (ChangeHostName(WLAN_CONFIG_FILE, splitted[1]))
{
// reboot necessary so that the new wlan.ini is also used !!!
fclose(pfile);
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Rebooting to activate new HOSTNAME...");
esp_restart();
hard_restart();
doReboot();
}
}
if ((toUpper(splitted[0]) == "SETUPMODE") && (splitted.size() > 1))
{
if (toUpper(splitted[1]) == "TRUE")
{
SetupModeActive = true;
}
}
if ((toUpper(zerlegt[0]) == "LOGLEVEL") && (zerlegt.size() > 1))
{
LogFile.setLogLevel(stoi(zerlegt[1]));
}
}
}
return true;
}
@@ -522,10 +630,10 @@ bool ClassFlowControll::ReadParameter(FILE* pfile, string& aktparamgraph)
int ClassFlowControll::CleanTempFolder() {
const char* folderPath = "/sdcard/img_tmp";
ESP_LOGI(TAG, "Clean up temporary folder to avoid damage of sdcard sectors : %s", folderPath);
ESP_LOGD(TAG, "Clean up temporary folder to avoid damage of sdcard sectors: %s", folderPath);
DIR *dir = opendir(folderPath);
if (!dir) {
ESP_LOGE(TAG, "Failed to stat dir : %s", folderPath);
ESP_LOGE(TAG, "Failed to stat dir: %s", folderPath);
return -1;
}
@@ -537,14 +645,14 @@ int ClassFlowControll::CleanTempFolder() {
if (unlink(path.c_str()) == 0) {
deleted ++;
} else {
ESP_LOGE(TAG, "can't delete file : %s", path.c_str());
ESP_LOGE(TAG, "can't delete file: %s", path.c_str());
}
} else if (entry->d_type == DT_DIR) {
deleted += removeFolder(path.c_str(), TAG);
}
}
closedir(dir);
ESP_LOGI(TAG, "%d files deleted", deleted);
ESP_LOGD(TAG, "%d files deleted", deleted);
return 0;
}
@@ -558,97 +666,242 @@ esp_err_t ClassFlowControll::SendRawJPG(httpd_req_t *req)
esp_err_t ClassFlowControll::GetJPGStream(std::string _fn, httpd_req_t *req)
{
printf("ClassFlowControll::GetJPGStream %s\n", _fn.c_str());
ESP_LOGD(TAG, "ClassFlowControll::GetJPGStream %s", _fn.c_str());
#ifdef DEBUG_DETAIL_ON
LogFile.WriteHeapInfo("ClassFlowControll::GetJPGStream - Start");
#endif
CImageBasis *_send = NULL;
esp_err_t result = ESP_FAIL;
bool Dodelete = false;
bool _sendDelete = false;
if (flowalignment == NULL)
{
printf("Can't continue, flowalignment is NULL\n");
return ESP_FAIL;
}
if (_fn == "alg.jpg")
{
_send = flowalignment->ImageBasis;
}
else
{
if (_fn == "alg_roi.jpg")
{
CImageBasis* _imgzw = new CImageBasis(flowalignment->ImageBasis);
flowalignment->DrawRef(_imgzw);
if (flowdigit) flowdigit->DrawROI(_imgzw);
if (flowanalog) flowanalog->DrawROI(_imgzw);
_send = _imgzw;
Dodelete = true;
if (_fn == "alg.jpg") {
if (flowalignment && flowalignment->ImageBasis->ImageOkay()) {
_send = flowalignment->ImageBasis;
}
else
{
std::vector<HTMLInfo*> htmlinfo;
htmlinfo = GetAllDigital();
printf("After getClassFlowControll::GetAllDigital\n");
for (int i = 0; i < htmlinfo.size(); ++i)
{
if (_fn == htmlinfo[i]->filename)
{
if (htmlinfo[i]->image)
_send = htmlinfo[i]->image;
}
if (_fn == htmlinfo[i]->filename_org)
{
if (htmlinfo[i]->image_org)
_send = htmlinfo[i]->image_org;
}
delete htmlinfo[i];
}
htmlinfo.clear();
if (!_send)
{
htmlinfo = GetAllAnalog();
for (int i = 0; i < htmlinfo.size(); ++i)
{
if (_fn == htmlinfo[i]->filename)
{
if (htmlinfo[i]->image)
_send = htmlinfo[i]->image;
}
if (_fn == htmlinfo[i]->filename_org)
{
if (htmlinfo[i]->image_org)
_send = htmlinfo[i]->image_org;
}
delete htmlinfo[i];
}
htmlinfo.clear();
}
else {
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "ClassFlowControll::GetJPGStream: alg.jpg cannot be served");
return ESP_FAIL;
}
}
else if (_fn == "alg_roi.jpg") {
#ifdef ALGROI_LOAD_FROM_MEM_AS_JPG // no CImageBasis needed to create alg_roi.jpg (ca. 790kB less RAM)
if (aktstatus.find("Initialization (delayed)") != -1) {
FILE* file = fopen("/sdcard/html/Flowstate_initialization_delayed.jpg", "rb");
if (!file) {
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "File /sdcard/html/Flowstate_initialization_delayed.jpg not found");
return ESP_FAIL;
}
fseek(file, 0, SEEK_END);
long fileSize = ftell(file); /* how long is the file ? */
fseek(file, 0, SEEK_SET); /* reset */
unsigned char* fileBuffer = (unsigned char*) malloc(fileSize);
if (!fileBuffer) {
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "ClassFlowControll::GetJPGStream: Not enough memory to create fileBuffer: " + std::to_string(fileSize));
fclose(file);
return ESP_FAIL;
}
fread(fileBuffer, fileSize, 1, file);
fclose(file);
httpd_resp_set_type(req, "image/jpeg");
result = httpd_resp_send(req, (const char *)fileBuffer, fileSize);
delete fileBuffer;
}
else if (aktstatus.find("Initialization") != -1) {
FILE* file = fopen("/sdcard/html/Flowstate_initialization.jpg", "rb");
if (!file) {
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "File /sdcard/html/Flowstate_initialization.jpg not found");
return ESP_FAIL;
}
fseek(file, 0, SEEK_END);
long fileSize = ftell(file); /* how long is the file ? */
fseek(file, 0, SEEK_SET); /* reset */
unsigned char* fileBuffer = (unsigned char*) malloc(fileSize);
if (!fileBuffer) {
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "ClassFlowControll::GetJPGStream: Not enough memory to create fileBuffer: " + std::to_string(fileSize));
fclose(file);
return ESP_FAIL;
}
fread(fileBuffer, fileSize, 1, file);
fclose(file);
httpd_resp_set_type(req, "image/jpeg");
result = httpd_resp_send(req, (const char *)fileBuffer, fileSize);
delete fileBuffer;
}
else if (aktstatus.find("Take Image") != -1) {
if (flowalignment && flowalignment->AlgROI) {
FILE* file = fopen("/sdcard/html/Flowstate_take_image.jpg", "rb");
if (!file) {
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "File /sdcard/html/Flowstate_take_image.jpg not found");
return ESP_FAIL;
}
fseek(file, 0, SEEK_END);
flowalignment->AlgROI->size = ftell(file); /* how long is the file ? */
fseek(file, 0, SEEK_SET); /* reset */
if (flowalignment->AlgROI->size > MAX_JPG_SIZE) {
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "File /sdcard/html/Flowstate_take_image.jpg too large: " + std::to_string(flowalignment->AlgROI->size));
fclose(file);
return ESP_FAIL;
}
fread(flowalignment->AlgROI->data, flowalignment->AlgROI->size, 1, file);
fclose(file);
httpd_resp_set_type(req, "image/jpeg");
result = httpd_resp_send(req, (const char *)flowalignment->AlgROI->data, flowalignment->AlgROI->size);
}
else {
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "ClassFlowControll::GetJPGStream: alg_roi.jpg cannot be served -> alg.jpg is going to be served!");
if (flowalignment && flowalignment->ImageBasis->ImageOkay()) {
_send = flowalignment->ImageBasis;
}
else {
httpd_resp_send(req, NULL, 0);
return ESP_OK;
}
}
}
else {
if (flowalignment && flowalignment->AlgROI) {
httpd_resp_set_type(req, "image/jpeg");
result = httpd_resp_send(req, (const char *)flowalignment->AlgROI->data, flowalignment->AlgROI->size);
}
else {
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "ClassFlowControll::GetJPGStream: alg_roi.jpg cannot be served -> alg.jpg is going to be served!");
if (flowalignment && flowalignment->ImageBasis->ImageOkay()) {
_send = flowalignment->ImageBasis;
}
else {
httpd_resp_send(req, NULL, 0);
return ESP_OK;
}
}
}
#else
if (!flowalignment) {
ESP_LOGD(TAG, "ClassFloDControll::GetJPGStream: FlowAlignment is not (yet) initialized. Interrupt serving!");
httpd_resp_send(req, NULL, 0);
return ESP_FAIL;
}
_send = new CImageBasis(flowalignment->ImageBasis);
if (_send->ImageOkay()) {
if (flowalignment) flowalignment->DrawRef(_send);
if (flowdigit) flowdigit->DrawROI(_send);
if (flowanalog) flowanalog->DrawROI(_send);
_sendDelete = true; // delete temporary _send element after sending
}
else {
LogFile.WriteToFile(ESP_LOG_WARN, TAG, "ClassFlowControll::GetJPGStream: Not enough memory to create alg_roi.jpg -> alg.jpg is going to be served!");
if (flowalignment && flowalignment->ImageBasis->ImageOkay()) {
_send = flowalignment->ImageBasis;
}
else {
httpd_resp_send(req, NULL, 0);
return ESP_OK;
}
}
#endif
}
else {
std::vector<HTMLInfo*> htmlinfo;
htmlinfo = GetAllDigital();
ESP_LOGD(TAG, "After getClassFlowControll::GetAllDigital");
for (int i = 0; i < htmlinfo.size(); ++i)
{
if (_fn == htmlinfo[i]->filename)
{
if (htmlinfo[i]->image)
_send = htmlinfo[i]->image;
}
if (_fn == htmlinfo[i]->filename_org)
{
if (htmlinfo[i]->image_org)
_send = htmlinfo[i]->image_org;
}
delete htmlinfo[i];
}
htmlinfo.clear();
if (!_send)
{
htmlinfo = GetAllAnalog();
ESP_LOGD(TAG, "After getClassFlowControll::GetAllAnalog");
for (int i = 0; i < htmlinfo.size(); ++i)
{
if (_fn == htmlinfo[i]->filename)
{
if (htmlinfo[i]->image)
_send = htmlinfo[i]->image;
}
if (_fn == htmlinfo[i]->filename_org)
{
if (htmlinfo[i]->image_org)
_send = htmlinfo[i]->image_org;
}
delete htmlinfo[i];
}
htmlinfo.clear();
}
}
#ifdef DEBUG_DETAIL_ON
LogFile.WriteHeapInfo("ClassFlowControll::GetJPGStream - before send");
#endif
if (_send)
{
ESP_LOGI(TAG, "Sending file : %s ...", _fn.c_str());
ESP_LOGD(TAG, "Sending file: %s ...", _fn.c_str());
set_content_type_from_file(req, _fn.c_str());
result = _send->SendJPGtoHTTP(req);
ESP_LOGI(TAG, "File sending complete");
/* Respond with an empty chunk to signal HTTP response completion */
httpd_resp_send_chunk(req, NULL, 0);
ESP_LOGD(TAG, "File sending complete");
if (_sendDelete)
delete _send;
_send = NULL;
}
if (Dodelete)
{
delete _send;
}
#ifdef DEBUG_DETAIL_ON
LogFile.WriteHeapInfo("ClassFlowControll::GetJPGStream - done");
#endif
return result;
}
string ClassFlowControll::getJSON(std::string _id, std::string _mac)
string ClassFlowControll::getNumbersName()
{
return flowpostprocessing->GetJSON(_id, _mac);
return flowpostprocessing->getNumbersName();
}
string ClassFlowControll::getJSON()
{
return flowpostprocessing->GetJSON();
}

View File

@@ -1,5 +1,7 @@
#ifndef __FLOWCONTROLL__
#define __FLOWCONTROLL__
#pragma once
#ifndef CLASSFLOWCONTROLL_H
#define CLASSFLOWCONTROLL_H
#include <string>
@@ -8,18 +10,15 @@
#include "ClassFlowAlignment.h"
#include "ClassFlowCNNGeneral.h"
#include "ClassFlowPostProcessing.h"
#include "ClassFlowMQTT.h"
#include "ClassFlowInfluxDB.h"
#ifdef ENABLE_MQTT
#include "ClassFlowMQTT.h"
#endif //ENABLE_MQTT
#ifdef ENABLE_INFLUXDB
#include "ClassFlowInfluxDB.h"
#endif //ENABLE_INFLUXDB
#include "ClassFlowCNNGeneral.h"
#include "ClassFlowWriteList.h"
#define READOUT_TYPE_VALUE 0
#define READOUT_TYPE_PREVALUE 1
#define READOUT_TYPE_RAWVALUE 2
#define READOUT_TYPE_ERROR 3
class ClassFlowControll :
public ClassFlow
{
@@ -50,11 +49,19 @@ public:
string UpdatePrevalue(std::string _newvalue, std::string _numbers, bool _extern);
string GetPrevalue(std::string _number = "");
bool ReadParameter(FILE* pfile, string& aktparamgraph);
string getJSON(std::string _id = "", std::string _mac = "");
string getJSON();
string getNumbersName();
string TranslateAktstatus(std::string _input);
#ifdef ENABLE_MQTT
string GetMQTTMainTopic();
#endif //ENABLE_MQTT
#ifdef ALGROI_LOAD_FROM_MEM_AS_JPG
void DigitalDrawROI(CImageBasis *_zw);
void AnalogDrawROI(CImageBasis *_zw);
#endif
esp_err_t GetJPGStream(std::string _fn, httpd_req_t *req);
esp_err_t SendRawJPG(httpd_req_t *req);
@@ -64,12 +71,17 @@ public:
bool isAutoStart(long &_intervall);
std::string* getActStatus();
void setActStatus(std::string _aktstatus);
std::vector<HTMLInfo*> GetAllDigital();
std::vector<HTMLInfo*> GetAllAnalog();
t_CNNType GetTypeDigital();
t_CNNType GetTypeAnalog();
#ifdef ENABLE_MQTT
bool StartMQTTService();
#endif //ENABLE_MQTT
int CleanTempFolder();
@@ -79,3 +91,4 @@ public:
#endif

View File

@@ -1,5 +1,7 @@
#ifndef __CLASSFLOWIMAGE_CLASS__
#define __CLASSFLOWIMAGE_CLASS__
#pragma once
#ifndef CLASSFLOWDEFINETYPES_H
#define CLASSFLOWDEFINETYPES_H
#include "ClassFlowImage.h"
@@ -33,19 +35,20 @@ struct NumberPost {
bool checkDigitIncreaseConsistency;
time_t lastvalue;
string timeStamp;
double FlowRateAct; // m3 / min
double PreValue; // letzter Wert, der gut ausgelesen wurde
double Value; // letzer ausgelesener Wert, inkl. Korrekturen
string ReturnRateValue; // RückgabewertRate
string ReturnChangeAbsolute; // RückgabewertRate
string ReturnRawValue; // Rohwert (mit N & führenden 0)
string ReturnValue; // korrigierter Rückgabewert, ggf. mit Fehlermeldung
string ReturnPreValue; // korrigierter Rückgabewert ohne Fehlermeldung
string ErrorMessageText; // Fehlermeldung bei Consistency Check
double FlowRateAct; // m3 / min
double PreValue; // last value that was read out well
double Value; // last value read out, incl. corrections
string ReturnRateValue; // return value rate
string ReturnChangeAbsolute; // return value rate
string ReturnRawValue; // Raw value (with N & leading 0)
string ReturnValue; // corrected return value, if necessary with error message
string ReturnPreValue; // corrected return value without error message
string ErrorMessageText; // Error message for consistency check
int AnzahlAnalog;
int AnzahlDigital;
int DecimalShift;
int DecimalShiftInitial;
float AnalogDigitalTransitionStart; // When is the digit > x.1, i.e. when does it start to tilt?
int Nachkomma;
bool isExtendedResolution;

View File

@@ -14,13 +14,17 @@ extern "C" {
#include "time_sntp.h"
#include "ClassLogFile.h"
#include "CImageBasis.h"
#include "esp_log.h"
#include "../../include/defines.h"
static const char* TAG = "IMG";
ClassFlowImage::ClassFlowImage(const char* logTag)
{
this->logTag = logTag;
isLogImage = false;
disabled = false;
this->logfileRetentionInDays = 5;
}
ClassFlowImage::ClassFlowImage(std::vector<ClassFlow*> * lfc, const char* logTag) : ClassFlow(lfc)
@@ -28,6 +32,7 @@ ClassFlowImage::ClassFlowImage(std::vector<ClassFlow*> * lfc, const char* logTag
this->logTag = logTag;
isLogImage = false;
disabled = false;
this->logfileRetentionInDays = 5;
}
ClassFlowImage::ClassFlowImage(std::vector<ClassFlow*> * lfc, ClassFlow *_prev, const char* logTag) : ClassFlow(lfc, _prev)
@@ -35,6 +40,7 @@ ClassFlowImage::ClassFlowImage(std::vector<ClassFlow*> * lfc, ClassFlow *_prev,
this->logTag = logTag;
isLogImage = false;
disabled = false;
this->logfileRetentionInDays = 5;
}
@@ -45,8 +51,7 @@ string ClassFlowImage::CreateLogFolder(string time) {
string logPath = LogImageLocation + "/" + time.LOGFILE_TIME_FORMAT_DATE_EXTR + "/" + time.LOGFILE_TIME_FORMAT_HOUR_EXTR;
isLogImage = mkdir_r(logPath.c_str(), S_IRWXU) == 0;
if (!isLogImage) {
ESP_LOGW(logTag, "Can't create log folder for analog images. Path %s", logPath.c_str());
LogFile.WriteToFile("Can't create log folder for analog images. Path " + logPath);
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Can't create log folder for analog images. Path " + logPath);
}
return logPath;
@@ -65,7 +70,7 @@ void ClassFlowImage::LogImage(string logPath, string name, float *resultFloat, i
else
{
sprintf(buf, "%.1f_", *resultFloat);
if (strcmp(buf, "10.0_"))
if (strcmp(buf, "10.0_") == 0)
sprintf(buf, "0.0_");
}
@@ -79,7 +84,7 @@ void ClassFlowImage::LogImage(string logPath, string name, float *resultFloat, i
nm = FormatFileName(nm);
string output = "/sdcard/img_tmp/" + name + ".jpg";
output = FormatFileName(output);
printf("save to file: %s\n", nm.c_str());
ESP_LOGD(logTag, "save to file: %s", nm.c_str());
_img->SaveToFile(nm);
// CopyFile(output, nm);
}
@@ -89,7 +94,7 @@ void ClassFlowImage::RemoveOldLogs()
if (!isLogImage)
return;
ESP_LOGI(logTag, "remove old log images");
ESP_LOGD(TAG, "remove old images");
if (logfileRetentionInDays == 0) {
return;
}
@@ -99,16 +104,17 @@ void ClassFlowImage::RemoveOldLogs()
char cmpfilename[30];
time(&rawtime);
rawtime = addDays(rawtime, -logfileRetentionInDays);
rawtime = addDays(rawtime, -logfileRetentionInDays + 1);
timeinfo = localtime(&rawtime);
//ESP_LOGD(TAG, "ImagefileRetentionInDays: %d", logfileRetentionInDays);
strftime(cmpfilename, 30, LOGFILE_TIME_FORMAT, timeinfo);
//ESP_LOGE(TAG, "log file name to compare: %s", cmpfilename);
//ESP_LOGD(TAG, "file name to compare: %s", cmpfilename);
string folderName = string(cmpfilename).LOGFILE_TIME_FORMAT_DATE_EXTR;
DIR *dir = opendir(LogImageLocation.c_str());
if (!dir) {
ESP_LOGI(logTag, "Failed to stat dir : %s", LogImageLocation.c_str());
ESP_LOGE(TAG, "Failed to stat dir: %s", LogImageLocation.c_str());
return;
}
@@ -118,15 +124,16 @@ void ClassFlowImage::RemoveOldLogs()
while ((entry = readdir(dir)) != NULL) {
string folderPath = LogImageLocation + "/" + entry->d_name;
if (entry->d_type == DT_DIR) {
//ESP_LOGI(logTag, "Compare %s %s", entry->d_name, folderName.c_str());
//ESP_LOGD(TAG, "Compare %s to %s", entry->d_name, folderName.c_str());
if ((strlen(entry->d_name) == folderName.length()) && (strcmp(entry->d_name, folderName.c_str()) < 0)) {
deleted += removeFolder(folderPath.c_str(), logTag);
removeFolder(folderPath.c_str(), logTag);
deleted++;
} else {
notDeleted ++;
}
}
}
ESP_LOGI(logTag, "%d older log files deleted. %d current log files not deleted.", deleted, notDeleted);
ESP_LOGD(TAG, "Image folder deleted: %d | Image folder not deleted: %d", deleted, notDeleted);
closedir(dir);
}

View File

@@ -1,4 +1,8 @@
#pragma once
#ifndef CLASSFLOWIMAGE_H
#define CLASSFLOWIMAGE_H
#include "ClassFlow.h"
using namespace std;
@@ -22,3 +26,5 @@ public:
void RemoveOldLogs();
};
#endif //CLASSFLOWIMAGE_H

View File

@@ -1,3 +1,4 @@
#ifdef ENABLE_INFLUXDB
#include <sstream>
#include "ClassFlowInfluxDB.h"
#include "Helper.h"
@@ -5,10 +6,15 @@
#include "time_sntp.h"
#include "interface_influxdb.h"
#include "ClassFlowPostProcessing.h"
#include "esp_log.h"
#include "../../include/defines.h"
#include <time.h>
static const char* TAG = "class_flow_influxDb";
void ClassFlowInfluxDB::SetInitialParameter(void)
{
uri = "";
@@ -63,7 +69,7 @@ ClassFlowInfluxDB::ClassFlowInfluxDB(std::vector<ClassFlow*>* lfc, ClassFlow *_p
bool ClassFlowInfluxDB::ReadParameter(FILE* pfile, string& aktparamgraph)
{
std::vector<string> zerlegt;
std::vector<string> splitted;
aktparamgraph = trim(aktparamgraph);
@@ -76,37 +82,37 @@ bool ClassFlowInfluxDB::ReadParameter(FILE* pfile, string& aktparamgraph)
while (this->getNextLine(pfile, &aktparamgraph) && !this->isNewParagraph(aktparamgraph))
{
printf("while loop reading line: %s\n", aktparamgraph.c_str());
zerlegt = this->ZerlegeZeile(aktparamgraph);
if ((toUpper(zerlegt[0]) == "USER") && (zerlegt.size() > 1))
ESP_LOGD(TAG, "while loop reading line: %s", aktparamgraph.c_str());
splitted = ZerlegeZeile(aktparamgraph);
if ((toUpper(splitted[0]) == "USER") && (splitted.size() > 1))
{
this->user = zerlegt[1];
this->user = splitted[1];
}
if ((toUpper(zerlegt[0]) == "PASSWORD") && (zerlegt.size() > 1))
if ((toUpper(splitted[0]) == "PASSWORD") && (splitted.size() > 1))
{
this->password = zerlegt[1];
this->password = splitted[1];
}
if ((toUpper(zerlegt[0]) == "URI") && (zerlegt.size() > 1))
if ((toUpper(splitted[0]) == "URI") && (splitted.size() > 1))
{
this->uri = zerlegt[1];
this->uri = splitted[1];
}
if (((toUpper(zerlegt[0]) == "MEASUREMENT")) && (zerlegt.size() > 1))
if (((toUpper(splitted[0]) == "MEASUREMENT")) && (splitted.size() > 1))
{
this->measurement = zerlegt[1];
this->measurement = splitted[1];
}
if (((toUpper(zerlegt[0]) == "DATABASE")) && (zerlegt.size() > 1))
if (((toUpper(splitted[0]) == "DATABASE")) && (splitted.size() > 1))
{
this->database = zerlegt[1];
this->database = splitted[1];
}
}
if ((uri.length() > 0) && (database.length() > 0) && (measurement.length() > 0))
{
printf("Init InfluxDB with uri: %s, measurement: %s, user: %s, password: %s\n", uri.c_str(), measurement.c_str(), user.c_str(), password.c_str());
ESP_LOGD(TAG, "Init InfluxDB with uri: %s, measurement: %s, user: %s, password: %s", uri.c_str(), measurement.c_str(), user.c_str(), password.c_str());
InfluxDBInit(uri, database, measurement, user, password);
InfluxDBenable = true;
} else {
printf("InfluxDB init skipped as we are missing some parameters");
ESP_LOGD(TAG, "InfluxDB init skipped as we are missing some parameters");
}
return true;
@@ -159,3 +165,5 @@ bool ClassFlowInfluxDB::doFlow(string zwtime)
return true;
}
#endif //ENABLE_INFLUXDB

View File

@@ -1,4 +1,10 @@
#ifdef ENABLE_INFLUXDB
#pragma once
#ifndef CLASSFINFLUXDB_H
#define CLASSFINFLUXDB_H
#include "ClassFlow.h"
#include "ClassFlowPostProcessing.h"
@@ -29,3 +35,5 @@ public:
string name(){return "ClassFlowInfluxDB";};
};
#endif //CLASSFINFLUXDB_H
#endif //ENABLE_INFLUXDB

View File

@@ -1,16 +1,28 @@
#ifdef ENABLE_MQTT
#include <sstream>
#include <iomanip>
#include "ClassFlowMQTT.h"
#include "Helper.h"
#include "connect_wlan.h"
#include "ClassLogFile.h"
#include "time_sntp.h"
#include "interface_mqtt.h"
#include "ClassFlowPostProcessing.h"
#include "ClassLogFile.h"
#include "ClassFlowControll.h"
#include "server_mqtt.h"
#include <time.h>
#include "../../include/defines.h"
static const char *TAG = "MQTT";
extern const char* libfive_git_version(void);
extern const char* libfive_git_revision(void);
extern const char* libfive_git_branch(void);
#define __HIDE_PASSWORD
void ClassFlowMQTT::SetInitialParameter(void)
{
@@ -19,22 +31,22 @@ void ClassFlowMQTT::SetInitialParameter(void)
topicError = "";
topicRate = "";
topicTimeStamp = "";
maintopic = "";
mainerrortopic = "";
maintopic = hostname;
topicUptime = "";
topicFreeMem = "";
clientname = "watermeter";
clientname = "AIOTED-" + getMac();
OldValue = "";
flowpostprocessing = NULL;
user = "";
password = "";
SetRetainFlag = 0;
SetRetainFlag = 0;
previousElement = NULL;
ListFlowControll = NULL;
disabled = false;
MQTTenable = false;
keepAlive = 600; // TODO This must be greater than the Flow Interval!
keepAlive = 25*60;
}
ClassFlowMQTT::ClassFlowMQTT()
@@ -75,7 +87,7 @@ ClassFlowMQTT::ClassFlowMQTT(std::vector<ClassFlow*>* lfc, ClassFlow *_prev)
bool ClassFlowMQTT::ReadParameter(FILE* pfile, string& aktparamgraph)
{
std::vector<string> zerlegt;
std::vector<string> splitted;
aktparamgraph = trim(aktparamgraph);
@@ -83,101 +95,85 @@ bool ClassFlowMQTT::ReadParameter(FILE* pfile, string& aktparamgraph)
if (!this->GetNextParagraph(pfile, aktparamgraph))
return false;
if (toUpper(aktparamgraph).compare("[MQTT]") != 0) // Paragraph passt nich zu MakeImage
if (toUpper(aktparamgraph).compare("[MQTT]") != 0) // Paragraph does not fit MakeImage
return false;
while (this->getNextLine(pfile, &aktparamgraph) && !this->isNewParagraph(aktparamgraph))
{
zerlegt = this->ZerlegeZeile(aktparamgraph);
if ((toUpper(zerlegt[0]) == "USER") && (zerlegt.size() > 1))
splitted = ZerlegeZeile(aktparamgraph);
if ((toUpper(splitted[0]) == "USER") && (splitted.size() > 1))
{
this->user = zerlegt[1];
this->user = splitted[1];
}
if ((toUpper(zerlegt[0]) == "PASSWORD") && (zerlegt.size() > 1))
if ((toUpper(splitted[0]) == "PASSWORD") && (splitted.size() > 1))
{
this->password = zerlegt[1];
this->password = splitted[1];
}
if ((toUpper(zerlegt[0]) == "URI") && (zerlegt.size() > 1))
if ((toUpper(splitted[0]) == "URI") && (splitted.size() > 1))
{
this->uri = zerlegt[1];
this->uri = splitted[1];
}
if ((toUpper(zerlegt[0]) == "SETRETAINFLAG") && (zerlegt.size() > 1))
if ((toUpper(splitted[0]) == "SETRETAINFLAG") && (splitted.size() > 1))
{
if (toUpper(zerlegt[1]) == "TRUE")
if (toUpper(splitted[1]) == "TRUE") {
SetRetainFlag = 1;
setMqtt_Server_Retain(SetRetainFlag);
}
}
if ((toUpper(zerlegt[0]) == "CLIENTID") && (zerlegt.size() > 1))
if ((toUpper(splitted[0]) == "HOMEASSISTANTDISCOVERY") && (splitted.size() > 1))
{
this->clientname = zerlegt[1];
if (toUpper(splitted[1]) == "TRUE")
SetHomeassistantDiscoveryEnabled(true);
}
if ((toUpper(splitted[0]) == "METERTYPE") && (splitted.size() > 1)) {
/* Use meter type for the device class
Make sure it is a listed one on https://developers.home-assistant.io/docs/core/entity/sensor/#available-device-classes */
if (toUpper(splitted[1]) == "WATER_M3") {
mqttServer_setMeterType("water", "", "h", "m³/h");
}
else if (toUpper(splitted[1]) == "WATER_L") {
mqttServer_setMeterType("water", "L", "h", "L/h");
}
else if (toUpper(splitted[1]) == "WATER_FT3") {
mqttServer_setMeterType("water", "ft³", "m", "ft³/m"); // Minutes
}
else if (toUpper(splitted[1]) == "WATER_GAL") {
mqttServer_setMeterType("water", "gal", "h", "gal/h");
}
else if (toUpper(splitted[1]) == "GAS_M3") {
mqttServer_setMeterType("gas", "", "h", "m³/h");
}
else if (toUpper(splitted[1]) == "GAS_FT3") {
mqttServer_setMeterType("gas", "ft³", "m", "ft³/m"); // Minutes
}
else if (toUpper(splitted[1]) == "ENERGY_WH") {
mqttServer_setMeterType("energy", "Wh", "h", "W");
}
else if (toUpper(splitted[1]) == "ENERGY_KWH") {
mqttServer_setMeterType("energy", "kWh", "h", "kW");
}
else if (toUpper(splitted[1]) == "ENERGY_MWH") {
mqttServer_setMeterType("energy", "MWh", "h", "MW");
}
}
if (((toUpper(zerlegt[0]) == "TOPIC") || (toUpper(zerlegt[0]) == "MAINTOPIC")) && (zerlegt.size() > 1))
if ((toUpper(splitted[0]) == "CLIENTID") && (splitted.size() > 1))
{
maintopic = zerlegt[1];
this->clientname = splitted[1];
}
if (((toUpper(splitted[0]) == "TOPIC") || (toUpper(splitted[0]) == "MAINTOPIC")) && (splitted.size() > 1))
{
maintopic = splitted[1];
mqttServer_setMainTopic(maintopic);
}
}
#ifdef __HIDE_PASSWORD
printf("Init Read with uri: %s, clientname: %s, user: %s, password: XXXXXX, maintopic: %s\n", uri.c_str(), clientname.c_str(), user.c_str(), mainerrortopic.c_str());
#else
printf("Init Read with uri: %s, clientname: %s, user: %s, password: %s, maintopic: %s\n", uri.c_str(), clientname.c_str(), user.c_str(), password.c_str(), mainerrortopic.c_str());
#endif
/* Note:
* Originally, we started the MQTT client here.
* How ever we need the interval parameter from the ClassFlowControll, but that only gets started later.
* To work around this, we delay the start and trigger it from ClassFlowControll::ReadParameter() */
if (!MQTTisConnected() && (uri.length() > 0) && (maintopic.length() > 0))
{
printf("InitMQTTInit\n");
mainerrortopic = maintopic + "/connection";
#ifdef __HIDE_PASSWORD
printf("Init MQTT with uri: %s, clientname: %s, user: %s, password: XXXXXXXX, maintopic: %s\n", uri.c_str(), clientname.c_str(), user.c_str(), mainerrortopic.c_str());
#else
printf("Init MQTT with uri: %s, clientname: %s, user: %s, password: %s, maintopic: %s\n", uri.c_str(), clientname.c_str(), user.c_str(), password.c_str(), mainerrortopic.c_str());
#endif
if (!MQTTInit(uri, clientname, user, password, mainerrortopic, keepAlive))
{ // Failed
MQTTenable = false;
return true; // We need to return true despite we failed, else it will retry 5x and then reboot!
}
}
// Try sending mainerrortopic. If it fails, re-run init
if (!MQTTPublish(mainerrortopic, "connected", SetRetainFlag))
{ // Failed
LogFile.WriteToFile("MQTT - Re-running init...!");
if (!MQTTInit(this->uri, this->clientname, this->user, this->password, this->mainerrortopic, keepAlive))
{ // Failed
MQTTenable = false;
return false;
}
}
// Try again and quit if it fails
if (!MQTTPublish(mainerrortopic, "connected", SetRetainFlag))
{ // Failed
MQTTenable = false;
return false;
}
/* if (!MQTTPublish(mainerrortopic, "connected", SetRetainFlag))
{ // Failed
LogFile.WriteToFile("MQTT - Could not publish connection status!");
MQTTenable = false;
return true; // We need to return true despite we failed, else it will retry 5x and then reboot!
}*/
/* if(!MQTTPublish(_LWTContext, "", 1))
{
LogFile.WriteToFile("MQTT - Could not publish LWT!");
MQTTenable = false;
return true; // We need to return true despite we failed, else it will retry 5x and then reboot!
}*/
MQTTenable = true;
return true;
}
@@ -188,73 +184,58 @@ string ClassFlowMQTT::GetMQTTMainTopic()
}
bool ClassFlowMQTT::Start(float AutoIntervall)
{
roundInterval = AutoIntervall; // Minutes
keepAlive = roundInterval * 60 * 2.5; // Seconds, make sure it is greater thatn 2 rounds!
std::stringstream stream;
stream << std::fixed << std::setprecision(1) << "Digitizer interval is " << roundInterval <<
" minutes => setting MQTT LWT timeout to " << ((float)keepAlive/60) << " minutes.";
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, stream.str());
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);
if (!MQTTConfigCheck) {
return false;
}
return (MQTT_Init() == 1);
}
bool ClassFlowMQTT::doFlow(string zwtime)
{
// Try sending mainerrortopic. If it fails, re-run init
if (!MQTTPublish(mainerrortopic, "connected", SetRetainFlag))
{ // Failed
LogFile.WriteToFile("MQTT - Re-running init...!");
if (!MQTTInit(this->uri, this->clientname, this->user, this->password, this->mainerrortopic, keepAlive))
{ // Failed
MQTTenable = false;
return true; // We need to return true despite we failed, else it will retry 5x and then reboot!
}
}
// Try again and quit if it fails
if (!MQTTPublish(mainerrortopic, "connected", SetRetainFlag))
{ // Failed
MQTTenable = false;
return true; // We need to return true despite we failed, else it will retry 5x and then reboot!
}
std::string result;
std::string resulterror = "";
std::string resultraw = "";
std::string resultrate = "";
std::string resultpre = "";
std::string resultrate = ""; // Always Unit / Minute
std::string resultRatePerTimeUnit = ""; // According to selection
std::string resulttimestamp = "";
std::string resultchangabs = "";
string zw = "";
string namenumber = "";
// if (!MQTTPublish(mainerrortopic, "connected", SetRetainFlag))
//{ // Failed, skip other topics
// return true; // We need to return true despite we failed, else it will retry 5x and then reboot!
//}
zw = maintopic + "/" + "uptime";
char uptimeStr[11];
sprintf(uptimeStr, "%ld", (long)getUpTime());
MQTTPublish(zw, uptimeStr, SetRetainFlag);
publishSystemData();
zw = maintopic + "/" + "freeMem";
char freeheapmem[11];
sprintf(freeheapmem, "%zu", esp_get_free_heap_size());
if (!MQTTPublish(zw, freeheapmem, SetRetainFlag))
{ // Failed, skip other topics
return true; // We need to return true despite we failed, else it will retry 5x and then reboot!
}
zw = maintopic + "/" + "wifiRSSI";
char rssi[11];
sprintf(rssi, "%d", get_WIFI_RSSI());
MQTTPublish(zw, rssi, SetRetainFlag);
zw = maintopic + "/" + "CPUtemp";
std::string cputemp = std::to_string(temperatureRead());
MQTTPublish(zw, cputemp, SetRetainFlag);
if (flowpostprocessing)
if (flowpostprocessing && getMQTTisConnected())
{
std::vector<NumberPost*>* NUMBERS = flowpostprocessing->GetNumbers();
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Publishing MQTT topics...");
for (int i = 0; i < (*NUMBERS).size(); ++i)
{
result = (*NUMBERS)[i]->ReturnValue;
resultraw = (*NUMBERS)[i]->ReturnRawValue;
resultpre = (*NUMBERS)[i]->ReturnPreValue;
resulterror = (*NUMBERS)[i]->ErrorMessageText;
resultrate = (*NUMBERS)[i]->ReturnRateValue;
resultchangabs = (*NUMBERS)[i]->ReturnChangeAbsolute;
resultrate = (*NUMBERS)[i]->ReturnRateValue; // Unit per minutes
resultchangabs = (*NUMBERS)[i]->ReturnChangeAbsolute; // Units per round
resulttimestamp = (*NUMBERS)[i]->timeStamp;
namenumber = (*NUMBERS)[i]->name;
@@ -263,67 +244,63 @@ bool ClassFlowMQTT::doFlow(string zwtime)
else
namenumber = maintopic + "/" + namenumber + "/";
zw = namenumber + "value";
if (result.length() > 0)
MQTTPublish(zw, result, SetRetainFlag);
MQTTPublish(namenumber + "value", result, SetRetainFlag);
zw = namenumber + "error";
if (resulterror.length() > 0)
MQTTPublish(zw, resulterror, SetRetainFlag);
MQTTPublish(namenumber + "error", resulterror, SetRetainFlag);
zw = namenumber + "rate";
if (resultrate.length() > 0)
MQTTPublish(zw, resultrate, SetRetainFlag);
zw = namenumber + "changeabsolut";
if (resultchangabs.length() > 0)
MQTTPublish(zw, resultchangabs, SetRetainFlag);
zw = namenumber + "raw";
if (resultraw.length() > 0)
MQTTPublish(zw, resultraw, SetRetainFlag);
zw = namenumber + "timestamp";
if (resulttimestamp.length() > 0)
MQTTPublish(zw, resulttimestamp, SetRetainFlag);
std::string json = "";
if (result.length() > 0)
json += "{\"value\":"+result;
else
json += "{\"value\":\"\"";
json += ",\"raw\":\""+resultraw;
json += "\",\"error\":\""+resulterror;
if (resultrate.length() > 0)
json += "\",\"rate\":"+resultrate;
else
json += "\",\"rate\":\"\"";
json += ",\"timestamp\":\""+resulttimestamp+"\"}";
zw = namenumber + "json";
MQTTPublish(zw, json, SetRetainFlag);
}
}
else
{
for (int i = 0; i < ListFlowControll->size(); ++i)
{
zw = (*ListFlowControll)[i]->getReadout();
if (zw.length() > 0)
{
if (result.length() == 0)
result = zw;
else
result = result + "\t" + zw;
if (resultrate.length() > 0) {
MQTTPublish(namenumber + "rate", resultrate, SetRetainFlag);
std::string resultRatePerTimeUnit;
if (getTimeUnit() == "h") { // Need conversion to be per hour
resultRatePerTimeUnit = resultRatePerTimeUnit = to_string((*NUMBERS)[i]->FlowRateAct * 60); // per minutes => per hour
}
else { // Keep per minute
resultRatePerTimeUnit = resultrate;
}
MQTTPublish(namenumber + "rate_per_time_unit", resultRatePerTimeUnit, SetRetainFlag);
}
if (resultchangabs.length() > 0) {
MQTTPublish(namenumber + "changeabsolut", resultchangabs, SetRetainFlag); // Legacy API
MQTTPublish(namenumber + "rate_per_digitalization_round", resultchangabs, SetRetainFlag);
}
if (resultraw.length() > 0)
MQTTPublish(namenumber + "raw", resultraw, SetRetainFlag);
if (resulttimestamp.length() > 0)
MQTTPublish(namenumber + "timestamp", resulttimestamp, SetRetainFlag);
std::string json = flowpostprocessing->getJsonFromNumber(i, "\n");
MQTTPublish(namenumber + "json", json, SetRetainFlag);
}
MQTTPublish(topic, result, SetRetainFlag);
}
/* Disabled because this is no longer a use case */
// else
// {
// for (int i = 0; i < ListFlowControll->size(); ++i)
// {
// zw = (*ListFlowControll)[i]->getReadout();
// if (zw.length() > 0)
// {
// if (result.length() == 0)
// result = zw;
// else
// result = result + "\t" + zw;
// }
// }
// MQTTPublish(topic, result, SetRetainFlag);
// }
OldValue = result;
return true;
}
#endif //ENABLE_MQTT

View File

@@ -1,4 +1,10 @@
#ifdef ENABLE_MQTT
#pragma once
#ifndef CLASSFFLOWMQTT_H
#define CLASSFFLOWMQTT_H
#include "ClassFlow.h"
#include "ClassFlowPostProcessing.h"
@@ -14,10 +20,10 @@ protected:
ClassFlowPostProcessing* flowpostprocessing;
std::string user, password;
int SetRetainFlag;
bool MQTTenable;
int keepAlive;
int keepAlive; // Seconds
float roundInterval; // Minutes
std::string maintopic, mainerrortopic;
std::string maintopic;
void SetInitialParameter(void);
public:
@@ -26,9 +32,11 @@ public:
ClassFlowMQTT(std::vector<ClassFlow*>* lfc, ClassFlow *_prev);
string GetMQTTMainTopic();
bool Start(float AutoIntervall);
bool ReadParameter(FILE* pfile, string& aktparamgraph);
bool doFlow(string time);
string name(){return "ClassFlowMQTT";};
};
#endif //CLASSFFLOWMQTT_H
#endif //ENABLE_MQTT

View File

@@ -6,6 +6,8 @@
#include "ClassControllCamera.h"
#include "esp_wifi.h"
#include "esp_log.h"
#include "../../include/defines.h"
#include <time.h>
@@ -24,14 +26,14 @@ esp_err_t ClassFlowMakeImage::camera_capture(){
return ESP_OK;
}
void ClassFlowMakeImage::takePictureWithFlash(int flashdauer)
void ClassFlowMakeImage::takePictureWithFlash(int flash_duration)
{
// für den Fall, dass das Bild geflippt wird, muss es hier zurück gesetzt werden ////
// in case the image is flipped, it must be reset here //
rawImage->width = image_width;
rawImage->height = image_height;
/////////////////////////////////////////////////////////////////////////////////////
printf("Flashdauer: %d\n", flashdauer);
Camera.CaptureToBasisImage(rawImage, flashdauer);
ESP_LOGD(TAG, "flash_duration: %d", flash_duration);
Camera.CaptureToBasisImage(rawImage, flash_duration);
time(&TimeImageTaken);
localtime(&TimeImageTaken);
@@ -50,18 +52,21 @@ void ClassFlowMakeImage::SetInitialParameter(void)
SaveAllFiles = false;
disabled = false;
FixedExposure = false;
namerawimage = "/sdcard/img_tmp/raw.jpg";
namerawimage = "/sdcard/img_tmp/raw.jpg";
}
ClassFlowMakeImage::ClassFlowMakeImage(std::vector<ClassFlow*>* lfc) : ClassFlowImage(lfc, TAG)
{
LogImageLocation = "/log/source";
logfileRetentionInDays = 5;
SetInitialParameter();
}
bool ClassFlowMakeImage::ReadParameter(FILE* pfile, string& aktparamgraph)
{
std::vector<string> zerlegt;
std::vector<string> splitted;
aktparamgraph = trim(aktparamgraph);
int _brightness = -100;
@@ -72,66 +77,76 @@ bool ClassFlowMakeImage::ReadParameter(FILE* pfile, string& aktparamgraph)
if (!this->GetNextParagraph(pfile, aktparamgraph))
return false;
if (aktparamgraph.compare("[MakeImage]") != 0) // Paragraph passt nich zu MakeImage
if (aktparamgraph.compare("[MakeImage]") != 0) // Paragraph does not fit MakeImage
return false;
while (this->getNextLine(pfile, &aktparamgraph) && !this->isNewParagraph(aktparamgraph))
{
zerlegt = this->ZerlegeZeile(aktparamgraph);
if ((zerlegt[0] == "LogImageLocation") && (zerlegt.size() > 1))
splitted = ZerlegeZeile(aktparamgraph);
if ((splitted[0] == "LogImageLocation") && (splitted.size() > 1))
{
LogImageLocation = "/sdcard" + zerlegt[1];
LogImageLocation = "/sdcard" + splitted[1];
isLogImage = true;
}
if ((zerlegt[0] == "ImageQuality") && (zerlegt.size() > 1))
ImageQuality = std::stod(zerlegt[1]);
if ((splitted[0] == "ImageQuality") && (splitted.size() > 1))
ImageQuality = std::stod(splitted[1]);
if ((zerlegt[0] == "ImageSize") && (zerlegt.size() > 1))
if ((splitted[0] == "ImageSize") && (splitted.size() > 1))
{
ImageSize = Camera.TextToFramesize(zerlegt[1].c_str());
ImageSize = Camera.TextToFramesize(splitted[1].c_str());
isImageSize = true;
}
if ((toUpper(zerlegt[0]) == "SAVEALLFILES") && (zerlegt.size() > 1))
if ((toUpper(splitted[0]) == "SAVEALLFILES") && (splitted.size() > 1))
{
if (toUpper(zerlegt[1]) == "TRUE")
if (toUpper(splitted[1]) == "TRUE")
SaveAllFiles = true;
}
if ((toUpper(zerlegt[0]) == "WAITBEFORETAKINGPICTURE") && (zerlegt.size() > 1))
if ((toUpper(splitted[0]) == "WAITBEFORETAKINGPICTURE") && (splitted.size() > 1))
{
waitbeforepicture = stoi(zerlegt[1]);
waitbeforepicture = stoi(splitted[1]);
}
if ((toUpper(zerlegt[0]) == "BRIGHTNESS") && (zerlegt.size() > 1))
if ((toUpper(splitted[0]) == "LOGFILERETENTIONINDAYS") && (splitted.size() > 1))
{
_brightness = stoi(zerlegt[1]);
this->logfileRetentionInDays = std::stoi(splitted[1]);
}
if ((toUpper(zerlegt[0]) == "CONTRAST") && (zerlegt.size() > 1))
if ((toUpper(splitted[0]) == "BRIGHTNESS") && (splitted.size() > 1))
{
_contrast = stoi(zerlegt[1]);
_brightness = stoi(splitted[1]);
}
if ((toUpper(zerlegt[0]) == "SATURATION") && (zerlegt.size() > 1))
if ((toUpper(splitted[0]) == "CONTRAST") && (splitted.size() > 1))
{
_saturation = stoi(zerlegt[1]);
_contrast = stoi(splitted[1]);
}
if ((toUpper(zerlegt[0]) == "FIXEDEXPOSURE") && (zerlegt.size() > 1))
if ((toUpper(splitted[0]) == "SATURATION") && (splitted.size() > 1))
{
if (toUpper(zerlegt[1]) == "TRUE")
_saturation = stoi(splitted[1]);
}
if ((toUpper(splitted[0]) == "FIXEDEXPOSURE") && (splitted.size() > 1))
{
if (toUpper(splitted[1]) == "TRUE")
FixedExposure = true;
}
if ((toUpper(zerlegt[0]) == "LEDINTENSITY") && (zerlegt.size() > 1))
if ((toUpper(splitted[0]) == "LEDINTENSITY") && (splitted.size() > 1))
{
float ledintensity = stof(zerlegt[1]);
float ledintensity = stof(splitted[1]);
ledintensity = min((float) 100, ledintensity);
ledintensity = max((float) 0, ledintensity);
Camera.SetLEDIntensity(ledintensity);
}
if ((toUpper(splitted[0]) == "DEMO") && (splitted.size() > 1))
{
if (toUpper(splitted[1]) == "TRUE")
Camera.useDemoMode();
}
}
Camera.SetBrightnessContrastSaturation(_brightness, _contrast, _saturation);
@@ -145,18 +160,19 @@ bool ClassFlowMakeImage::ReadParameter(FILE* pfile, string& aktparamgraph)
waitbeforepicture_store = waitbeforepicture;
if (FixedExposure && (waitbeforepicture > 0))
{
// printf("Fixed Exposure enabled!\n");
int flashdauer = (int) (waitbeforepicture * 1000);
Camera.EnableAutoExposure(flashdauer);
// ESP_LOGD(TAG, "Fixed Exposure enabled!");
int flash_duration = (int) (waitbeforepicture * 1000);
Camera.EnableAutoExposure(flash_duration);
waitbeforepicture = 0.2;
// flashdauer = (int) (waitbeforepicture * 1000);
// takePictureWithFlash(flashdauer);
// flash_duration = (int) (waitbeforepicture * 1000);
// takePictureWithFlash(flash_duration);
// rawImage->SaveToFile("/sdcard/init2.jpg");
}
return true;
}
string ClassFlowMakeImage::getHTMLSingleStep(string host)
{
string result;
@@ -164,50 +180,52 @@ string ClassFlowMakeImage::getHTMLSingleStep(string host)
return result;
}
bool ClassFlowMakeImage::doFlow(string zwtime)
{
string logPath = CreateLogFolder(zwtime);
int flashdauer = (int) (waitbeforepicture * 1000);
int flash_duration = (int) (waitbeforepicture * 1000);
#ifdef DEBUG_DETAIL_ON
LogFile.WriteHeapInfo("ClassFlowMakeImage::doFlow - Before takePictureWithFlash");
#endif
#ifdef DEBUG_DETAIL_ON
LogFile.WriteHeapInfo("ClassFlowMakeImage::doFlow - Before takePictureWithFlash");
#endif
#ifdef WIFITURNOFF
esp_wifi_stop(); // to save power usage and
#endif
#ifdef WIFITURNOFF
esp_wifi_stop(); // to save power usage and
#endif
takePictureWithFlash(flashdauer);
takePictureWithFlash(flash_duration);
#ifdef WIFITURNOFF
esp_wifi_start();
#endif
#ifdef WIFITURNOFF
esp_wifi_start();
#endif
#ifdef DEBUG_DETAIL_ON
LogFile.WriteHeapInfo("ClassFlowMakeImage::doFlow - After takePictureWithFlash");
#endif
#ifdef DEBUG_DETAIL_ON
LogFile.WriteHeapInfo("ClassFlowMakeImage::doFlow - After takePictureWithFlash");
#endif
LogImage(logPath, "raw", NULL, NULL, zwtime, rawImage);
RemoveOldLogs();
#ifdef DEBUG_DETAIL_ON
LogFile.WriteHeapInfo("ClassFlowMakeImage::doFlow - After RemoveOldLogs");
#endif
#ifdef DEBUG_DETAIL_ON
LogFile.WriteHeapInfo("ClassFlowMakeImage::doFlow - After RemoveOldLogs");
#endif
return true;
}
esp_err_t ClassFlowMakeImage::SendRawJPG(httpd_req_t *req)
{
int flashdauer = (int) (waitbeforepicture * 1000);
int flash_duration = (int) (waitbeforepicture * 1000);
time(&TimeImageTaken);
localtime(&TimeImageTaken);
return Camera.CaptureToHTTP(req, flashdauer);
return Camera.CaptureToHTTP(req, flash_duration);
}
@@ -215,8 +233,8 @@ ImageData* ClassFlowMakeImage::SendRawImage()
{
CImageBasis *zw = new CImageBasis(rawImage);
ImageData *id;
int flashdauer = (int) (waitbeforepicture * 1000);
Camera.CaptureToBasisImage(zw, flashdauer);
int flash_duration = (int) (waitbeforepicture * 1000);
Camera.CaptureToBasisImage(zw, flash_duration);
time(&TimeImageTaken);
localtime(&TimeImageTaken);

View File

@@ -1,15 +1,14 @@
#pragma once
#ifndef CLASSFFLOWMAKEIMAGE_H
#define CLASSFFLOWMAKEIMAGE_H
#include "ClassFlowImage.h"
#include "ClassControllCamera.h"
#include "../../include/defines.h"
#include <string>
#define BLINK_GPIO GPIO_NUM_4
#define CAMERA_MODEL_AI_THINKER
class ClassFlowMakeImage :
public ClassFlowImage
{
@@ -30,7 +29,7 @@ protected:
void CopyFile(string input, string output);
esp_err_t camera_capture();
void takePictureWithFlash(int flashdauer);
void takePictureWithFlash(int flash_duration);
void SetInitialParameter(void);
@@ -53,3 +52,4 @@ public:
};
#endif //CLASSFFLOWMAKEIMAGE_H

View File

@@ -9,61 +9,88 @@
#include <time.h>
#include "time_sntp.h"
//#define SERIAL_DEBUG // testing debug on serial enabled
#include "esp_log.h"
#include "../../include/defines.h"
#define PREVALUE_TIME_FORMAT_OUTPUT "%Y-%m-%dT%H:%M:%S"
#define PREVALUE_TIME_FORMAT_INPUT "%d-%d-%dT%d:%d:%d"
static const char* TAG = "POSTPROC";
std::string ClassFlowPostProcessing::getNumbersName()
{
std::string ret="";
std::string ClassFlowPostProcessing::GetJSON(std::string _id, std::string _mac, std::string _lineend)
for (int i = 0; i < NUMBERS.size(); ++i)
{
ret += NUMBERS[i]->name;
if (i < NUMBERS.size()-1)
ret = ret + "\t";
}
// ESP_LOGI(TAG, "Result ClassFlowPostProcessing::getNumbersName: %s", ret.c_str());
return ret;
}
std::string ClassFlowPostProcessing::GetJSON(std::string _lineend)
{
std::string json="{" + _lineend;
for (int i = 0; i < NUMBERS.size(); ++i)
{
json += "\"" + NUMBERS[i]->name + "\":" + _lineend;
json += " {" + _lineend;
if (_id.length() > 0)
json += " \"ID\": \"" + _id + "\"," + _lineend;
if (_mac.length() > 0)
json += " \"MAC\": \"" + _mac + "\"," + _lineend;
json += getJsonFromNumber(i, _lineend) + _lineend;
if (NUMBERS[i]->ReturnValue.length() > 0)
json += " \"value\": \"" + NUMBERS[i]->ReturnValue + "\"," + _lineend;
else
json += " \"value\": \"\"," + _lineend;
json += " \"raw\": \"" + NUMBERS[i]->ReturnRawValue + "\"," + _lineend;
json += " \"error\": \"" + NUMBERS[i]->ErrorMessageText + "\"," + _lineend;
if (NUMBERS[i]->ReturnRateValue.length() > 0)
json += " \"rate\": " + NUMBERS[i]->ReturnRateValue + "," + _lineend;
else
json += " \"rate\": \"\"," + _lineend;
json += " \"timestamp\": \"" + NUMBERS[i]->timeStamp + "\"" + _lineend;
if ((i+1) < NUMBERS.size())
json += " }," + _lineend;
else
json += " }" + _lineend;
json += "," + _lineend;
}
json += "}";
return json;
}
string ClassFlowPostProcessing::getJsonFromNumber(int i, std::string _lineend) {
std::string json = "";
json += " {" + _lineend;
if (NUMBERS[i]->ReturnValue.length() > 0)
json += " \"value\": \"" + NUMBERS[i]->ReturnValue + "\"," + _lineend;
else
json += " \"value\": \"\"," + _lineend;
json += " \"raw\": \"" + NUMBERS[i]->ReturnRawValue + "\"," + _lineend;
json += " \"pre\": \"" + NUMBERS[i]->ReturnPreValue + "\"," + _lineend;
json += " \"error\": \"" + NUMBERS[i]->ErrorMessageText + "\"," + _lineend;
if (NUMBERS[i]->ReturnRateValue.length() > 0)
json += " \"rate\": \"" + NUMBERS[i]->ReturnRateValue + "\"," + _lineend;
else
json += " \"rate\": \"\"," + _lineend;
json += " \"timestamp\": \"" + NUMBERS[i]->timeStamp + "\"" + _lineend;
json += " }" + _lineend;
return json;
}
string ClassFlowPostProcessing::GetPreValue(std::string _number)
{
std::string result;
int index = -1;
if (_number == "")
_number = "default";
_number = "default";
for (int i = 0; i < NUMBERS.size(); ++i)
if (NUMBERS[i]->name == _number)
index = i;
if (index == -1)
return std::string("");
result = RundeOutput(NUMBERS[index]->PreValue, NUMBERS[index]->Nachkomma);
return result;
@@ -71,10 +98,10 @@ string ClassFlowPostProcessing::GetPreValue(std::string _number)
void ClassFlowPostProcessing::SetPreValue(double zw, string _numbers, bool _extern)
{
printf("SetPrevalue: %f, %s\n", zw, _numbers.c_str());
ESP_LOGD(TAG, "SetPrevalue: %f, %s", zw, _numbers.c_str());
for (int j = 0; j < NUMBERS.size(); ++j)
{
// printf("Number %d, %s\n", j, NUMBERS[j]->name.c_str());
// ESP_LOGD(TAG, "Number %d, %s", j, NUMBERS[j]->name.c_str());
if (NUMBERS[j]->name == _numbers)
{
NUMBERS[j]->PreValue = zw;
@@ -85,7 +112,7 @@ void ClassFlowPostProcessing::SetPreValue(double zw, string _numbers, bool _exte
time(&(NUMBERS[j]->lastvalue));
localtime(&(NUMBERS[j]->lastvalue));
}
// printf("Found %d! - set to %f\n", j, NUMBERS[j]->PreValue);
// ESP_LOGD(TAG, "Found %d! - set to %f", j, NUMBERS[j]->PreValue);
}
}
UpdatePreValueINI = true;
@@ -95,13 +122,13 @@ void ClassFlowPostProcessing::SetPreValue(double zw, string _numbers, bool _exte
bool ClassFlowPostProcessing::LoadPreValue(void)
{
std::vector<string> zerlegt;
std::vector<string> splitted;
FILE* pFile;
char zw[1024];
string zwtime, zwvalue, name;
bool _done = false;
UpdatePreValueINI = false; // Konvertierung ins neue Format
UpdatePreValueINI = false; // Conversion to the new format
pFile = fopen(FilePreValue.c_str(), "r");
@@ -109,26 +136,26 @@ bool ClassFlowPostProcessing::LoadPreValue(void)
return false;
fgets(zw, 1024, pFile);
printf("Read line Prevalue.ini: %s", zw);
ESP_LOGD(TAG, "Read line Prevalue.ini: %s", zw);
zwtime = trim(std::string(zw));
if (zwtime.length() == 0)
return false;
zerlegt = HelperZerlegeZeile(zwtime, "\t");
if (zerlegt.size() > 1) // neues Format
splitted = HelperZerlegeZeile(zwtime, "\t");
if (splitted.size() > 1) // Conversion to the new format
{
while ((zerlegt.size() > 1) && !_done)
while ((splitted.size() > 1) && !_done)
{
name = trim(zerlegt[0]);
zwtime = trim(zerlegt[1]);
zwvalue = trim(zerlegt[2]);
name = trim(splitted[0]);
zwtime = trim(splitted[1]);
zwvalue = trim(splitted[2]);
for (int j = 0; j < NUMBERS.size(); ++j)
{
if (NUMBERS[j]->name == name)
{
NUMBERS[j]->PreValue = stod(zwvalue.c_str());
NUMBERS[j]->ReturnPreValue = RundeOutput(NUMBERS[j]->PreValue, NUMBERS[j]->Nachkomma + 1); // SIcherheitshalber 1 Stelle mehr, da ggf. Exgtended Resolution an ist (wird erst beim ersten Durchlauf gesetzt)
NUMBERS[j]->ReturnPreValue = RundeOutput(NUMBERS[j]->PreValue, NUMBERS[j]->Nachkomma + 1); // To be on the safe side, 1 digit more, as Exgtended Resolution may be on (will only be set during the first run).
time_t tStart;
int yy, month, dd, hh, mm, ss;
@@ -160,23 +187,23 @@ bool ClassFlowPostProcessing::LoadPreValue(void)
_done = true;
else
{
printf("Read line Prevalue.ini: %s", zw);
zerlegt = HelperZerlegeZeile(trim(std::string(zw)), "\t");
if (zerlegt.size() > 1)
ESP_LOGD(TAG, "Read line Prevalue.ini: %s", zw);
splitted = HelperZerlegeZeile(trim(std::string(zw)), "\t");
if (splitted.size() > 1)
{
name = trim(zerlegt[0]);
zwtime = trim(zerlegt[1]);
zwvalue = trim(zerlegt[2]);
name = trim(splitted[0]);
zwtime = trim(splitted[1]);
zwvalue = trim(splitted[2]);
}
}
}
fclose(pFile);
}
else // altes Format
else // Old Format
{
fgets(zw, 1024, pFile);
fclose(pFile);
printf("%s", zw);
ESP_LOGD(TAG, "%s", zw);
zwvalue = trim(std::string(zw));
NUMBERS[0]->PreValue = stod(zwvalue.c_str());
@@ -193,7 +220,7 @@ bool ClassFlowPostProcessing::LoadPreValue(void)
whenStart.tm_sec = ss;
whenStart.tm_isdst = -1;
printf("TIME: %d, %d, %d, %d, %d, %d\n", whenStart.tm_year, whenStart.tm_mon, whenStart.tm_wday, whenStart.tm_hour, whenStart.tm_min, whenStart.tm_sec);
ESP_LOGD(TAG, "TIME: %d, %d, %d, %d, %d, %d", whenStart.tm_year, whenStart.tm_mon, whenStart.tm_wday, whenStart.tm_hour, whenStart.tm_min, whenStart.tm_sec);
NUMBERS[0]->lastvalue = mktime(&whenStart);
@@ -212,7 +239,7 @@ bool ClassFlowPostProcessing::LoadPreValue(void)
NUMBERS[0]->ReturnValue = RundeOutput(NUMBERS[0]->Value, NUMBERS[0]->Nachkomma);
}
UpdatePreValueINI = true; // Konvertierung ins neue Format
UpdatePreValueINI = true; // Conversion to the new format
SavePreValue();
}
@@ -224,7 +251,7 @@ void ClassFlowPostProcessing::SavePreValue()
FILE* pFile;
string _zw;
if (!UpdatePreValueINI) // PreValues unverändert --> File muss nicht neu geschrieben werden
if (!UpdatePreValueINI) // PreValues unchanged --> File does not have to be rewritten
return;
pFile = fopen(FilePreValue.c_str(), "w");
@@ -235,10 +262,10 @@ void ClassFlowPostProcessing::SavePreValue()
struct tm* timeinfo = localtime(&NUMBERS[j]->lastvalue);
strftime(buffer, 80, PREVALUE_TIME_FORMAT_OUTPUT, timeinfo);
NUMBERS[j]->timeStamp = std::string(buffer);
// printf("SaverPreValue %d, Value: %f, Nachkomma %d\n", j, NUMBERS[j]->PreValue, NUMBERS[j]->Nachkomma);
// ESP_LOGD(TAG, "SaverPreValue %d, Value: %f, Nachkomma %d", j, NUMBERS[j]->PreValue, NUMBERS[j]->Nachkomma);
_zw = NUMBERS[j]->name + "\t" + NUMBERS[j]->timeStamp + "\t" + RundeOutput(NUMBERS[j]->PreValue, NUMBERS[j]->Nachkomma) + "\n";
printf("Write PreValue Zeile: %s\n", _zw.c_str());
ESP_LOGD(TAG, "Write PreValue line: %s", _zw.c_str());
if (pFile) {
fputs(_zw.c_str(), pFile);
}
@@ -277,7 +304,7 @@ void ClassFlowPostProcessing::handleDecimalExtendedResolution(string _decsep, st
{
string _digit, _decpos;
int _pospunkt = _decsep.find_first_of(".");
// printf("Name: %s, Pospunkt: %d\n", _decsep.c_str(), _pospunkt);
// ESP_LOGD(TAG, "Name: %s, Pospunkt: %d", _decsep.c_str(), _pospunkt);
if (_pospunkt > -1)
_digit = _decsep.substr(0, _pospunkt);
else
@@ -290,7 +317,7 @@ void ClassFlowPostProcessing::handleDecimalExtendedResolution(string _decsep, st
if (toUpper(_value) == "TRUE")
_zwdc = true;
if (_digit == "default") // erstmal auf default setzen (falls sonst nichts gesetzt)
if (_digit == "default") // Set to default first (if nothing else is set)
{
NUMBERS[j]->isExtendedResolution = _zwdc;
}
@@ -307,7 +334,7 @@ void ClassFlowPostProcessing::handleDecimalSeparator(string _decsep, string _val
{
string _digit, _decpos;
int _pospunkt = _decsep.find_first_of(".");
// printf("Name: %s, Pospunkt: %d\n", _decsep.c_str(), _pospunkt);
// ESP_LOGD(TAG, "Name: %s, Pospunkt: %d", _decsep.c_str(), _pospunkt);
if (_pospunkt > -1)
_digit = _decsep.substr(0, _pospunkt);
else
@@ -323,10 +350,10 @@ void ClassFlowPostProcessing::handleDecimalSeparator(string _decsep, string _val
}
/* catch(const std::exception& e)
{
printf("ERROR - Decimalshift is not a number: %s\n", _value.c_str());
ESP_LOGD(TAG, "ERROR - Decimalshift is not a number: %s", _value.c_str());
}
*/
if (_digit == "default") // erstmal auf default setzen (falls sonst nichts gesetzt)
if (_digit == "default") // Set to default first (if nothing else is set)
{
NUMBERS[j]->DecimalShift = _zwdc;
NUMBERS[j]->DecimalShiftInitial = _zwdc;
@@ -342,13 +369,66 @@ void ClassFlowPostProcessing::handleDecimalSeparator(string _decsep, string _val
}
}
void ClassFlowPostProcessing::handleAnalogDigitalTransitionStart(string _decsep, string _value)
{
string _digit, _decpos;
int _pospunkt = _decsep.find_first_of(".");
// ESP_LOGD(TAG, "Name: %s, Pospunkt: %d", _decsep.c_str(), _pospunkt);
if (_pospunkt > -1)
_digit = _decsep.substr(0, _pospunkt);
else
_digit = "default";
for (int j = 0; j < NUMBERS.size(); ++j)
{
float _zwdc = 9.2;
{
_zwdc = stof(_value);
}
if (_digit == "default" || NUMBERS[j]->name == _digit) // Set to default first (if nothing else is set)
{
NUMBERS[j]->AnalogDigitalTransitionStart = _zwdc;
}
}
}
void ClassFlowPostProcessing::handleAllowNegativeRate(string _decsep, string _value)
{
string _digit, _decpos;
int _pospunkt = _decsep.find_first_of(".");
// ESP_LOGD(TAG, "Name: %s, Pospunkt: %d", _decsep.c_str(), _pospunkt);
if (_pospunkt > -1)
_digit = _decsep.substr(0, _pospunkt);
else
_digit = "default";
for (int j = 0; j < NUMBERS.size(); ++j)
{
bool _rt = false;
if (toUpper(_value) == "TRUE")
_rt = true;
if (_digit == "default") // Set to default first (if nothing else is set)
{
NUMBERS[j]->AllowNegativeRates = _rt;
}
if (NUMBERS[j]->name == _digit)
{
NUMBERS[j]->AllowNegativeRates = _rt;
}
}
}
void ClassFlowPostProcessing::handleMaxRateType(string _decsep, string _value)
{
string _digit, _decpos;
int _pospunkt = _decsep.find_first_of(".");
// printf("Name: %s, Pospunkt: %d\n", _decsep.c_str(), _pospunkt);
// ESP_LOGD(TAG, "Name: %s, Pospunkt: %d", _decsep.c_str(), _pospunkt);
if (_pospunkt > -1)
_digit = _decsep.substr(0, _pospunkt);
else
@@ -361,7 +441,7 @@ void ClassFlowPostProcessing::handleMaxRateType(string _decsep, string _value)
if (toUpper(_value) == "RATECHANGE")
_rt = RateChange;
if (_digit == "default") // erstmal auf default setzen (falls sonst nichts gesetzt)
if (_digit == "default") // Set to default first (if nothing else is set)
{
NUMBERS[j]->RateType = _rt;
}
@@ -375,36 +455,33 @@ void ClassFlowPostProcessing::handleMaxRateType(string _decsep, string _value)
void ClassFlowPostProcessing::handleMaxRateValue(string _decsep, string _value)
{
string _digit, _decpos;
int _pospunkt = _decsep.find_first_of(".");
// printf("Name: %s, Pospunkt: %d\n", _decsep.c_str(), _pospunkt);
// ESP_LOGD(TAG, "Name: %s, Pospunkt: %d", _decsep.c_str(), _pospunkt);
if (_pospunkt > -1)
_digit = _decsep.substr(0, _pospunkt);
else
_digit = "default";
for (int j = 0; j < NUMBERS.size(); ++j)
{
float _zwdc = 1;
// try
{
_zwdc = stof(_value);
}
/* catch(const std::exception& e)
{
printf("ERROR - MaxRateValue is not a number: %s\n", _value.c_str());
ESP_LOGD(TAG, "ERROR - MaxRateValue is not a number: %s", _value.c_str());
}
*/
if (_digit == "default") // erstmal auf default setzen (falls sonst nichts gesetzt)
if (_digit == "default") // Set to default first (if nothing else is set)
{
NUMBERS[j]->useMaxRateValue = true;
NUMBERS[j]->MaxRateValue = _zwdc;
}
if (NUMBERS[j]->name == _digit)
{
NUMBERS[j]->useMaxRateValue = true;
@@ -416,7 +493,7 @@ void ClassFlowPostProcessing::handleMaxRateValue(string _decsep, string _value)
bool ClassFlowPostProcessing::ReadParameter(FILE* pfile, string& aktparamgraph)
{
std::vector<string> zerlegt;
std::vector<string> splitted;
int _n;
aktparamgraph = trim(aktparamgraph);
@@ -426,7 +503,7 @@ bool ClassFlowPostProcessing::ReadParameter(FILE* pfile, string& aktparamgraph)
return false;
if (aktparamgraph.compare("[PostProcessing]") != 0) // Paragraph passt nich zu MakeImage
if (aktparamgraph.compare("[PostProcessing]") != 0) // Paragraph does not fit MakeImage
return false;
InitNUMBERS();
@@ -434,61 +511,68 @@ bool ClassFlowPostProcessing::ReadParameter(FILE* pfile, string& aktparamgraph)
while (this->getNextLine(pfile, &aktparamgraph) && !this->isNewParagraph(aktparamgraph))
{
zerlegt = this->ZerlegeZeile(aktparamgraph);
std::string _param = GetParameterName(zerlegt[0]);
splitted = ZerlegeZeile(aktparamgraph);
std::string _param = GetParameterName(splitted[0]);
if ((toUpper(_param) == "EXTENDEDRESOLUTION") && (zerlegt.size() > 1))
if ((toUpper(_param) == "EXTENDEDRESOLUTION") && (splitted.size() > 1))
{
handleDecimalExtendedResolution(zerlegt[0], zerlegt[1]);
handleDecimalExtendedResolution(splitted[0], splitted[1]);
}
if ((toUpper(_param) == "DECIMALSHIFT") && (zerlegt.size() > 1))
if ((toUpper(_param) == "DECIMALSHIFT") && (splitted.size() > 1))
{
handleDecimalSeparator(zerlegt[0], zerlegt[1]);
handleDecimalSeparator(splitted[0], splitted[1]);
}
if ((toUpper(_param) == "MAXRATEVALUE") && (zerlegt.size() > 1))
if ((toUpper(_param) == "ANALOGDIGITALTRANSITIONSTART") && (splitted.size() > 1))
{
handleMaxRateValue(zerlegt[0], zerlegt[1]);
handleAnalogDigitalTransitionStart(splitted[0], splitted[1]);
}
if ((toUpper(_param) == "MAXRATETYPE") && (zerlegt.size() > 1))
if ((toUpper(_param) == "MAXRATEVALUE") && (splitted.size() > 1))
{
handleMaxRateType(zerlegt[0], zerlegt[1]);
handleMaxRateValue(splitted[0], splitted[1]);
}
if ((toUpper(_param) == "MAXRATETYPE") && (splitted.size() > 1))
{
handleMaxRateType(splitted[0], splitted[1]);
}
if ((toUpper(_param) == "PREVALUEUSE") && (zerlegt.size() > 1))
if ((toUpper(_param) == "PREVALUEUSE") && (splitted.size() > 1))
{
if (toUpper(zerlegt[1]) == "TRUE")
if (toUpper(splitted[1]) == "TRUE")
{
PreValueUse = true;
}
}
if ((toUpper(_param) == "CHECKDIGITINCREASECONSISTENCY") && (zerlegt.size() > 1))
if ((toUpper(_param) == "CHECKDIGITINCREASECONSISTENCY") && (splitted.size() > 1))
{
if (toUpper(zerlegt[1]) == "TRUE")
if (toUpper(splitted[1]) == "TRUE")
for (_n = 0; _n < NUMBERS.size(); ++_n)
NUMBERS[_n]->checkDigitIncreaseConsistency = true;
}
if ((toUpper(_param) == "ALLOWNEGATIVERATES") && (zerlegt.size() > 1))
if ((toUpper(_param) == "ALLOWNEGATIVERATES") && (splitted.size() > 1))
{
if (toUpper(zerlegt[1]) == "TRUE")
handleAllowNegativeRate(splitted[0], splitted[1]);
/* Updated to allow individual Settings
if (toUpper(splitted[1]) == "TRUE")
for (_n = 0; _n < NUMBERS.size(); ++_n)
NUMBERS[_n]->AllowNegativeRates = true;
*/
}
if ((toUpper(_param) == "ERRORMESSAGE") && (zerlegt.size() > 1))
if ((toUpper(_param) == "ERRORMESSAGE") && (splitted.size() > 1))
{
if (toUpper(zerlegt[1]) == "TRUE")
if (toUpper(splitted[1]) == "TRUE")
ErrorMessage = true;
}
if ((toUpper(_param) == "IGNORELEADINGNAN") && (zerlegt.size() > 1))
if ((toUpper(_param) == "IGNORELEADINGNAN") && (splitted.size() > 1))
{
if (toUpper(zerlegt[1]) == "TRUE")
if (toUpper(splitted[1]) == "TRUE")
IgnoreLeadingNaN = true;
}
if ((toUpper(_param) == "PREVALUEAGESTARTUP") && (zerlegt.size() > 1))
if ((toUpper(_param) == "PREVALUEAGESTARTUP") && (splitted.size() > 1))
{
PreValueAgeStartup = std::stoi(zerlegt[1]);
PreValueAgeStartup = std::stoi(splitted[1]);
}
}
@@ -507,16 +591,16 @@ void ClassFlowPostProcessing::InitNUMBERS()
if (flowDigit)
{
anzDIGIT = flowDigit->getAnzahlGENERAL();
anzDIGIT = flowDigit->getNumberGENERAL();
flowDigit->UpdateNameNumbers(&name_numbers);
}
if (flowAnalog)
{
anzANALOG = flowAnalog->getAnzahlGENERAL();
anzANALOG = flowAnalog->getNumberGENERAL();
flowAnalog->UpdateNameNumbers(&name_numbers);
}
printf("Anzahl NUMBERS: %d - DIGITS: %d, ANALOG: %d\n", name_numbers.size(), anzDIGIT, anzANALOG);
ESP_LOGD(TAG, "Anzahl NUMBERS: %d - DIGITS: %d, ANALOG: %d", name_numbers.size(), anzDIGIT, anzANALOG);
for (int _num = 0; _num < name_numbers.size(); ++_num)
{
@@ -543,9 +627,9 @@ void ClassFlowPostProcessing::InitNUMBERS()
else
_number->AnzahlAnalog = 0;
_number->ReturnRawValue = ""; // Rohwert (mit N & führenden 0)
_number->ReturnValue = ""; // korrigierter Rückgabewert, ggf. mit Fehlermeldung
_number->ErrorMessageText = ""; // Fehlermeldung bei Consistency Check
_number->ReturnRawValue = ""; // Raw value (with N & leading 0).
_number->ReturnValue = ""; // corrected return value, possibly with error message
_number->ErrorMessageText = ""; // Error message for consistency check
_number->ReturnPreValue = "";
_number->PreValueOkay = false;
_number->AllowNegativeRates = false;
@@ -556,14 +640,15 @@ void ClassFlowPostProcessing::InitNUMBERS()
_number->DecimalShift = 0;
_number->DecimalShiftInitial = 0;
_number->isExtendedResolution = false;
_number->AnalogDigitalTransitionStart=9.2;
_number->FlowRateAct = 0; // m3 / min
_number->PreValue = 0; // letzter Wert, der gut ausgelesen wurde
_number->Value = 0; // letzer ausgelesener Wert, inkl. Korrekturen
_number->ReturnRawValue = ""; // Rohwert (mit N & führenden 0)
_number->ReturnValue = ""; // korrigierter Rückgabewert, ggf. mit Fehlermeldung
_number->ErrorMessageText = ""; // Fehlermeldung bei Consistency Check
_number->FlowRateAct = 0; // m3 / min
_number->PreValue = 0; // last value read out well
_number->Value = 0; // last value read out, incl. corrections
_number->ReturnRawValue = ""; // raw value (with N & leading 0)
_number->ReturnValue = ""; // corrected return value, possibly with error message
_number->ErrorMessageText = ""; // Error message for consistency check
_number->Nachkomma = _number->AnzahlAnalog;
@@ -571,7 +656,7 @@ void ClassFlowPostProcessing::InitNUMBERS()
}
for (int i = 0; i < NUMBERS.size(); ++i) {
printf("Number %s, Anz DIG: %d, Anz ANA %d\n", NUMBERS[i]->name.c_str(), NUMBERS[i]->AnzahlDigital, NUMBERS[i]->AnzahlAnalog);
ESP_LOGD(TAG, "Number %s, Anz DIG: %d, Anz ANA %d", NUMBERS[i]->name.c_str(), NUMBERS[i]->AnzahlDigital, NUMBERS[i]->AnzahlAnalog);
}
}
@@ -595,7 +680,7 @@ string ClassFlowPostProcessing::ShiftDecimal(string in, int _decShift){
_pos_dec_neu = _pos_dec_org + _decShift;
if (_pos_dec_neu <= 0) { // Komma ist vor der ersten Ziffer
if (_pos_dec_neu <= 0) { // comma is before the first digit
for (int i = 0; i > _pos_dec_neu; --i){
in = in.insert(0, "0");
}
@@ -603,7 +688,7 @@ string ClassFlowPostProcessing::ShiftDecimal(string in, int _decShift){
return in;
}
if (_pos_dec_neu > in.length()){ // Komma soll hinter String (123 --> 1230)
if (_pos_dec_neu > in.length()){ // Comma should be after string (123 --> 1230)
for (int i = in.length(); i < _pos_dec_neu; ++i){
in = in.insert(in.length(), "0");
}
@@ -628,7 +713,7 @@ bool ClassFlowPostProcessing::doFlow(string zwtime)
time_t imagetime = 0;
string rohwert;
// Update Nachkomma, da sich beim Wechsel von CNNType Auto --> xyz auch die Nachkommastellen ändern können:
// Update decimal point, as the decimal places can also change when changing from CNNType Auto --> xyz:
imagetime = flowMakeImage->getTimeImageTaken();
if (imagetime == 0)
@@ -640,7 +725,7 @@ bool ClassFlowPostProcessing::doFlow(string zwtime)
strftime(strftime_buf, sizeof(strftime_buf), "%Y-%m-%dT%H:%M:%S", timeinfo);
zwtime = std::string(strftime_buf);
printf("Anzahl NUMBERS: %d\n", NUMBERS.size());
ESP_LOGD(TAG, "Quantity NUMBERS: %d", NUMBERS.size());
for (int j = 0; j < NUMBERS.size(); ++j)
{
@@ -650,6 +735,13 @@ bool ClassFlowPostProcessing::doFlow(string zwtime)
NUMBERS[j]->ErrorMessageText = "";
NUMBERS[j]->Value = -1;
/* calculate time difference BEFORE we overwrite the 'lastvalue' */
double difference = difftime(imagetime, NUMBERS[j]->lastvalue); // in seconds
/* TODO:
* We could call `NUMBERS[j]->lastvalue = imagetime;` here and remove all other such calls further down.
* But we should check nothing breaks! */
UpdateNachkommaDecimalShift();
int previous_value = -1;
@@ -665,7 +757,7 @@ bool ClassFlowPostProcessing::doFlow(string zwtime)
}
}
#ifdef SERIAL_DEBUG
printf("After analog->getReadout: ReturnRaw %s\n", NUMBERS[j]->ReturnRawValue.c_str());
ESP_LOGD(TAG, "After analog->getReadout: ReturnRaw %s", NUMBERS[j]->ReturnRawValue.c_str());
#endif
if (NUMBERS[j]->digit_roi && NUMBERS[j]->analog_roi)
NUMBERS[j]->ReturnRawValue = "." + NUMBERS[j]->ReturnRawValue;
@@ -673,17 +765,17 @@ bool ClassFlowPostProcessing::doFlow(string zwtime)
if (NUMBERS[j]->digit_roi)
{
if (NUMBERS[j]->analog_roi)
NUMBERS[j]->ReturnRawValue = flowDigit->getReadout(j, false, previous_value, NUMBERS[j]->analog_roi->ROI[0]->result_float) + NUMBERS[j]->ReturnRawValue;
NUMBERS[j]->ReturnRawValue = flowDigit->getReadout(j, false, previous_value, NUMBERS[j]->analog_roi->ROI[0]->result_float, NUMBERS[j]->AnalogDigitalTransitionStart) + NUMBERS[j]->ReturnRawValue;
else
NUMBERS[j]->ReturnRawValue = flowDigit->getReadout(j, NUMBERS[j]->isExtendedResolution, previous_value); // Extended Resolution nur falls es keine analogen Ziffern gibt
NUMBERS[j]->ReturnRawValue = flowDigit->getReadout(j, NUMBERS[j]->isExtendedResolution, previous_value); // Extended Resolution only if there are no analogue digits
}
#ifdef SERIAL_DEBUG
printf("After digital->getReadout: ReturnRaw %s\n", NUMBERS[j]->ReturnRawValue.c_str());
ESP_LOGD(TAG, "After digital->getReadout: ReturnRaw %s", NUMBERS[j]->ReturnRawValue.c_str());
#endif
NUMBERS[j]->ReturnRawValue = ShiftDecimal(NUMBERS[j]->ReturnRawValue, NUMBERS[j]->DecimalShift);
#ifdef SERIAL_DEBUG
printf("After ShiftDecimal: ReturnRaw %s\n", NUMBERS[j]->ReturnRawValue.c_str());
ESP_LOGD(TAG, "After ShiftDecimal: ReturnRaw %s", NUMBERS[j]->ReturnRawValue.c_str());
#endif
if (IgnoreLeadingNaN)
@@ -691,29 +783,39 @@ bool ClassFlowPostProcessing::doFlow(string zwtime)
NUMBERS[j]->ReturnRawValue.erase(0, 1);
#ifdef SERIAL_DEBUG
printf("After IgnoreLeadingNaN: ReturnRaw %s\n", NUMBERS[j]->ReturnRawValue.c_str());
ESP_LOGD(TAG, "After IgnoreLeadingNaN: ReturnRaw %s", NUMBERS[j]->ReturnRawValue.c_str());
#endif
NUMBERS[j]->ReturnValue = NUMBERS[j]->ReturnRawValue;
if (findDelimiterPos(NUMBERS[j]->ReturnValue, "N") != std::string::npos)
{
if (PreValueUse && NUMBERS[j]->PreValueOkay)
{
NUMBERS[j]->ReturnValue = ErsetzteN(NUMBERS[j]->ReturnValue, NUMBERS[j]->PreValue);
}
else
continue; // es gibt keinen Zahl, da noch ein N vorhanden ist.
{
string _zw = NUMBERS[j]->name + ": Raw: " + NUMBERS[j]->ReturnRawValue + ", Value: " + NUMBERS[j]->ReturnValue + ", Status: " + NUMBERS[j]->ErrorMessageText;
LogFile.WriteToFile(ESP_LOG_INFO, TAG, _zw);
/* TODO to be discussed, see https://github.com/jomjol/AI-on-the-edge-device/issues/1617 */
NUMBERS[j]->lastvalue = imagetime;
WriteDataLog(j);
continue; // there is no number because there is still an N.
}
}
#ifdef SERIAL_DEBUG
printf("After findDelimiterPos: ReturnValue %s\n", NUMBERS[j]->ReturnRawValue.c_str());
ESP_LOGD(TAG, "After findDelimiterPos: ReturnValue %s", NUMBERS[j]->ReturnRawValue.c_str());
#endif
// Lösche führende Nullen (außer es ist nur noch einen 0)
// Delete leading zeros (unless there is only one 0 left)
while ((NUMBERS[j]->ReturnValue.length() > 1) && (NUMBERS[j]->ReturnValue[0] == '0'))
NUMBERS[j]->ReturnValue.erase(0, 1);
#ifdef SERIAL_DEBUG
printf("After removeLeadingZeros: ReturnValue %s\n", NUMBERS[j]->ReturnRawValue.c_str());
ESP_LOGD(TAG, "After removeLeadingZeros: ReturnValue %s", NUMBERS[j]->ReturnRawValue.c_str());
#endif
NUMBERS[j]->Value = std::stod(NUMBERS[j]->ReturnValue);
#ifdef SERIAL_DEBUG
printf("After setting the Value: Value %f and as double is %f\n", NUMBERS[j]->Value, std::stod(NUMBERS[j]->ReturnValue));
ESP_LOGD(TAG, "After setting the Value: Value %f and as double is %f", NUMBERS[j]->Value, std::stod(NUMBERS[j]->ReturnValue));
#endif
if (NUMBERS[j]->checkDigitIncreaseConsistency)
@@ -721,35 +823,54 @@ bool ClassFlowPostProcessing::doFlow(string zwtime)
if (flowDigit)
{
if (flowDigit->getCNNType() != Digital)
printf("checkDigitIncreaseConsistency = true - ignored due to wrong CNN-Type (not Digital Classification)\n");
ESP_LOGD(TAG, "checkDigitIncreaseConsistency = true - ignored due to wrong CNN-Type (not Digital Classification)");
else
NUMBERS[j]->Value = checkDigitConsistency(NUMBERS[j]->Value, NUMBERS[j]->DecimalShift, NUMBERS[j]->analog_roi != NULL, NUMBERS[j]->PreValue);
}
else
{
printf("checkDigitIncreaseConsistency = true - no digital numbers defined!\n");
#ifdef SERIAL_DEBUG
ESP_LOGD(TAG, "checkDigitIncreaseConsistency = true - no digital numbers defined!");
#endif
}
}
#ifdef SERIAL_DEBUG
printf("After checkDigitIncreaseConsistency: Value %f\n", NUMBERS[j]->Value);
ESP_LOGD(TAG, "After checkDigitIncreaseConsistency: Value %f", NUMBERS[j]->Value);
#endif
if (!NUMBERS[j]->AllowNegativeRates)
{
if (NUMBERS[j]->Value < NUMBERS[j]->PreValue)
if ((NUMBERS[j]->Value < NUMBERS[j]->PreValue))
{
NUMBERS[j]->ErrorMessageText = NUMBERS[j]->ErrorMessageText + "Neg. Rate - Read: " + zwvalue + " - Raw: " + NUMBERS[j]->ReturnRawValue + " - Pre: " + RundeOutput(NUMBERS[j]->PreValue, NUMBERS[j]->Nachkomma) + " ";
NUMBERS[j]->Value = NUMBERS[j]->PreValue;
NUMBERS[j]->ReturnValue = "";
continue;
#ifdef SERIAL_DEBUG
ESP_LOGD(TAG, "Neg: value=%f, preValue=%f, preToll%f", NUMBERS[j]->Value, NUMBERS[j]->PreValue,
NUMBERS[j]->PreValue-(2/pow(10, NUMBERS[j]->Nachkomma))
) ;
#endif
// Include inaccuracy of 0.2 for isExtendedResolution.
if (NUMBERS[j]->Value >= (NUMBERS[j]->PreValue-(2/pow(10, NUMBERS[j]->Nachkomma))) && NUMBERS[j]->isExtendedResolution) {
NUMBERS[j]->Value = NUMBERS[j]->PreValue;
NUMBERS[j]->ReturnValue = to_string(NUMBERS[j]->PreValue);
} else {
NUMBERS[j]->ErrorMessageText = NUMBERS[j]->ErrorMessageText + "Neg. Rate - Read: " + zwvalue + " - Raw: " + NUMBERS[j]->ReturnRawValue + " - Pre: " + RundeOutput(NUMBERS[j]->PreValue, NUMBERS[j]->Nachkomma) + " ";
NUMBERS[j]->Value = NUMBERS[j]->PreValue;
NUMBERS[j]->ReturnValue = "";
NUMBERS[j]->lastvalue = imagetime;
string _zw = NUMBERS[j]->name + ": Raw: " + NUMBERS[j]->ReturnRawValue + ", Value: " + NUMBERS[j]->ReturnValue + ", Status: " + NUMBERS[j]->ErrorMessageText;
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, _zw);
WriteDataLog(j);
continue;
}
}
}
#ifdef SERIAL_DEBUG
printf("After AllowNegativeRates: Value %f\n", NUMBERS[j]->Value);
ESP_LOGD(TAG, "After AllowNegativeRates: Value %f", NUMBERS[j]->Value);
#endif
double difference = difftime(imagetime, NUMBERS[j]->lastvalue); // in Sekunden
difference /= 60;
NUMBERS[j]->FlowRateAct = (NUMBERS[j]->Value - NUMBERS[j]->PreValue) / difference;
NUMBERS[j]->ReturnRateValue = to_string(NUMBERS[j]->FlowRateAct);
@@ -764,21 +885,27 @@ bool ClassFlowPostProcessing::doFlow(string zwtime)
if (abs(_ratedifference) > abs(NUMBERS[j]->MaxRateValue))
{
NUMBERS[j]->ErrorMessageText = NUMBERS[j]->ErrorMessageText + "Rate too high - Read: " + RundeOutput(NUMBERS[j]->Value, NUMBERS[j]->Nachkomma) + " - Pre: " + RundeOutput(NUMBERS[j]->PreValue, NUMBERS[j]->Nachkomma);
NUMBERS[j]->ErrorMessageText = NUMBERS[j]->ErrorMessageText + "Rate too high - Read: " + RundeOutput(NUMBERS[j]->Value, NUMBERS[j]->Nachkomma) + " - Pre: " + RundeOutput(NUMBERS[j]->PreValue, NUMBERS[j]->Nachkomma) + " - Rate: " + RundeOutput(_ratedifference, NUMBERS[j]->Nachkomma);
NUMBERS[j]->Value = NUMBERS[j]->PreValue;
NUMBERS[j]->ReturnValue = "";
NUMBERS[j]->ReturnRateValue = "";
NUMBERS[j]->lastvalue = imagetime;
string _zw = NUMBERS[j]->name + ": Raw: " + NUMBERS[j]->ReturnRawValue + ", Value: " + NUMBERS[j]->ReturnValue + ", Status: " + NUMBERS[j]->ErrorMessageText;
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, _zw);
WriteDataLog(j);
continue;
}
}
#ifdef SERIAL_DEBUG
printf("After MaxRateCheck: Value %f\n", NUMBERS[j]->Value);
ESP_LOGD(TAG, "After MaxRateCheck: Value %f", NUMBERS[j]->Value);
#endif
NUMBERS[j]->ReturnChangeAbsolute = RundeOutput(NUMBERS[j]->Value - NUMBERS[j]->PreValue, NUMBERS[j]->Nachkomma);
NUMBERS[j]->lastvalue = imagetime;
NUMBERS[j]->ReturnChangeAbsolute = RundeOutput(NUMBERS[j]->Value - NUMBERS[j]->PreValue, NUMBERS[j]->Nachkomma);
NUMBERS[j]->PreValue = NUMBERS[j]->Value;
NUMBERS[j]->PreValueOkay = true;
NUMBERS[j]->lastvalue = imagetime;
NUMBERS[j]->ReturnValue = RundeOutput(NUMBERS[j]->Value, NUMBERS[j]->Nachkomma);
NUMBERS[j]->ReturnPreValue = RundeOutput(NUMBERS[j]->PreValue, NUMBERS[j]->Nachkomma);
@@ -786,35 +913,62 @@ bool ClassFlowPostProcessing::doFlow(string zwtime)
NUMBERS[j]->ErrorMessageText = "no error";
UpdatePreValueINI = true;
string _zw = "PostProcessing - Raw: " + NUMBERS[j]->ReturnRawValue + " Value: " + NUMBERS[j]->ReturnValue + " Error: " + NUMBERS[j]->ErrorMessageText;
LogFile.WriteToFile(_zw);
string _zw = NUMBERS[j]->name + ": Raw: " + NUMBERS[j]->ReturnRawValue + ", Value: " + NUMBERS[j]->ReturnValue + ", Status: " + NUMBERS[j]->ErrorMessageText;
LogFile.WriteToFile(ESP_LOG_INFO, TAG, _zw);
WriteDataLog(j);
}
SavePreValue();
return true;
}
void ClassFlowPostProcessing::WriteDataLog(int _index)
{
if (!LogFile.GetDataLogToSD()){
return;
}
string analog = "";
string digital = "";
string timezw = "";
char buffer[80];
struct tm* timeinfo = localtime(&NUMBERS[_index]->lastvalue);
strftime(buffer, 80, PREVALUE_TIME_FORMAT_OUTPUT, timeinfo);
timezw = std::string(buffer);
if (flowAnalog)
analog = flowAnalog->getReadoutRawString(_index);
if (flowDigit)
digital = flowDigit->getReadoutRawString(_index);
LogFile.WriteToData(timezw, NUMBERS[_index]->name,
NUMBERS[_index]->ReturnRawValue, NUMBERS[_index]->ReturnValue, NUMBERS[_index]->ReturnPreValue,
NUMBERS[_index]->ReturnRateValue, NUMBERS[_index]->ReturnChangeAbsolute,
NUMBERS[_index]->ErrorMessageText,
digital, analog);
ESP_LOGD(TAG, "WriteDataLog: %s, %s, %s, %s, %s", NUMBERS[_index]->ReturnRawValue.c_str(), NUMBERS[_index]->ReturnValue.c_str(), NUMBERS[_index]->ErrorMessageText.c_str(), digital.c_str(), analog.c_str());
}
void ClassFlowPostProcessing::UpdateNachkommaDecimalShift()
{
for (int j = 0; j < NUMBERS.size(); ++j)
{
if (NUMBERS[j]->digit_roi && !NUMBERS[j]->analog_roi) // es gibt nur digitale ziffern
if (NUMBERS[j]->digit_roi && !NUMBERS[j]->analog_roi) // There are only digital digits
{
// printf("Nurdigital\n");
// ESP_LOGD(TAG, "Nurdigital");
NUMBERS[j]->DecimalShift = NUMBERS[j]->DecimalShiftInitial;
if (NUMBERS[j]->isExtendedResolution && flowDigit->isExtendedResolution()) // extended resolution ist an und soll auch bei dieser Ziffer verwendet werden
if (NUMBERS[j]->isExtendedResolution && flowDigit->isExtendedResolution()) // Extended resolution is on and should also be used for this digit.
NUMBERS[j]->DecimalShift = NUMBERS[j]->DecimalShift-1;
NUMBERS[j]->Nachkomma = -NUMBERS[j]->DecimalShift;
}
if (!NUMBERS[j]->digit_roi && NUMBERS[j]->analog_roi) // es gibt nur analoge ziffern
if (!NUMBERS[j]->digit_roi && NUMBERS[j]->analog_roi)
{
// printf("Nur analog\n");
// ESP_LOGD(TAG, "Nur analog");
NUMBERS[j]->DecimalShift = NUMBERS[j]->DecimalShiftInitial;
if (NUMBERS[j]->isExtendedResolution && flowAnalog->isExtendedResolution()) // extended resolution ist an und soll auch bei dieser Ziffer verwendet werden
if (NUMBERS[j]->isExtendedResolution && flowAnalog->isExtendedResolution())
NUMBERS[j]->DecimalShift = NUMBERS[j]->DecimalShift-1;
NUMBERS[j]->Nachkomma = -NUMBERS[j]->DecimalShift;
@@ -822,17 +976,17 @@ void ClassFlowPostProcessing::UpdateNachkommaDecimalShift()
if (NUMBERS[j]->digit_roi && NUMBERS[j]->analog_roi) // digital + analog
{
// printf("Nur digital + analog\n");
// ESP_LOGD(TAG, "Nur digital + analog");
NUMBERS[j]->DecimalShift = NUMBERS[j]->DecimalShiftInitial;
NUMBERS[j]->Nachkomma = NUMBERS[j]->analog_roi->ROI.size() - NUMBERS[j]->DecimalShift;
if (NUMBERS[j]->isExtendedResolution && flowAnalog->isExtendedResolution()) // extended resolution ist an und soll auch bei dieser Ziffer verwendet werden
if (NUMBERS[j]->isExtendedResolution && flowAnalog->isExtendedResolution()) // Extended resolution is on and should also be used for this digit.
NUMBERS[j]->Nachkomma = NUMBERS[j]->Nachkomma+1;
}
printf("UpdateNachkommaDecShift NUMBER%i: Nachkomma %i, DecShift %i\n", j, NUMBERS[j]->Nachkomma,NUMBERS[j]->DecimalShift);
ESP_LOGD(TAG, "UpdateNachkommaDecShift NUMBER%i: Nachkomma %i, DecShift %i", j, NUMBERS[j]->Nachkomma,NUMBERS[j]->DecimalShift);
}
}
@@ -851,29 +1005,6 @@ string ClassFlowPostProcessing::getReadoutParam(bool _rawValue, bool _noerror, i
return NUMBERS[_number]->ReturnValue;
}
string ClassFlowPostProcessing::RundeOutput(double _in, int _anzNachkomma){
std::stringstream stream;
int _zw = _in;
// printf("AnzNachkomma: %d\n", _anzNachkomma);
if (_anzNachkomma < 0) {
_anzNachkomma = 0;
}
if (_anzNachkomma > 0)
{
stream << std::fixed << std::setprecision(_anzNachkomma) << _in;
return stream.str();
}
else
{
stream << _zw;
}
return stream.str();
}
string ClassFlowPostProcessing::ErsetzteN(string input, double _prevalue)
{
@@ -914,17 +1045,14 @@ float ClassFlowPostProcessing::checkDigitConsistency(double input, int _decilams
bool no_nulldurchgang = false;
pot = _decilamshift;
if (!_isanalog) // falls es keine analogwerte gibt, kann die letzte nicht bewertet werden
if (!_isanalog) // if there are no analogue values, the last one cannot be evaluated
{
pot++;
}
#ifdef SERIAL_DEBUG
printf("checkDigitConsistency: pot=%d, decimalshift=%d\n", pot, _decilamshift);
ESP_LOGD(TAG, "checkDigitConsistency: pot=%d, decimalshift=%d", pot, _decilamshift);
#endif
pot_max = ((int) log10(input)) + 1;
#ifdef SERIAL_DEBUG
printf("checkDigitConsistency: not_checked_input=%f\n", not_checked_input);
#endif
while (pot <= pot_max)
{
zw = input / pow(10, pot-1);
@@ -943,18 +1071,18 @@ float ClassFlowPostProcessing::checkDigitConsistency(double input, int _decilams
{
if (aktdigit != olddigit)
{
input = input + ((float) (olddigit - aktdigit)) * pow(10, pot); // Neue Digit wird durch alte Digit ersetzt;
input = input + ((float) (olddigit - aktdigit)) * pow(10, pot); // New Digit is replaced by old Digit;
}
}
else
{
if (aktdigit == olddigit) // trotz Nulldurchgang wurde Stelle nicht hochgezählt --> addiere 1
if (aktdigit == olddigit) // despite zero crossing, digit was not incremented --> add 1
{
input = input + ((float) (1)) * pow(10, pot); // addiere 1 an der Stelle
input = input + ((float) (1)) * pow(10, pot); // add 1 at the point
}
}
#ifdef SERIAL_DEBUG
printf("checkDigitConsistency: input=%f", input);
ESP_LOGD(TAG, "checkDigitConsistency: input=%f", input);
#endif
pot++;
}
@@ -977,3 +1105,5 @@ string ClassFlowPostProcessing::getReadoutError(int _number)
{
return NUMBERS[_number]->ErrorMessageText;
}

View File

@@ -1,5 +1,7 @@
#ifndef __FLOWPOSTPROCESSING__
#define __FLOWPOSTPROCESSING__
#pragma once
#ifndef CLASSFFLOWPOSTPROCESSING_H
#define CLASSFFLOWPOSTPROCESSING_H
#include "ClassFlow.h"
#include "ClassFlowMakeImage.h"
@@ -18,7 +20,7 @@ protected:
int PreValueAgeStartup;
bool ErrorMessage;
bool IgnoreLeadingNaN; // SPEZIALFALL für User Gustl
bool IgnoreLeadingNaN; // SPECIAL CASE for User Gustl ???
ClassFlowCNNGeneral* flowAnalog;
@@ -34,13 +36,18 @@ protected:
string ErsetzteN(string, double _prevalue);
float checkDigitConsistency(double input, int _decilamshift, bool _isanalog, double _preValue);
string RundeOutput(double _in, int _anzNachkomma);
void InitNUMBERS();
void handleDecimalSeparator(string _decsep, string _value);
void handleMaxRateValue(string _decsep, string _value);
void handleDecimalExtendedResolution(string _decsep, string _value);
void handleMaxRateType(string _decsep, string _value);
void handleAnalogDigitalTransitionStart(string _decsep, string _value);
void handleAllowNegativeRate(string _decsep, string _value);
std::string GetStringReadouts(general);
void WriteDataLog(int _index);
@@ -49,6 +56,7 @@ public:
bool PreValueUse;
ClassFlowPostProcessing(std::vector<ClassFlow*>* lfc, ClassFlowCNNGeneral *_analog, ClassFlowCNNGeneral *_digit);
virtual ~ClassFlowPostProcessing(){};
bool ReadParameter(FILE* pfile, string& aktparamgraph);
bool doFlow(string time);
string getReadout(int _number);
@@ -57,10 +65,12 @@ public:
string getReadoutRate(int _number = 0);
string getReadoutTimeStamp(int _number = 0);
void SavePreValue();
string getJsonFromNumber(int i, std::string _lineend);
string GetPreValue(std::string _number = "");
void SetPreValue(double zw, string _numbers, bool _extern = false);
std::string GetJSON(std::string _id = "", std::string _mac = "", std::string _lineend = "\n");
std::string GetJSON(std::string _lineend = "\n");
std::string getNumbersName();
void UpdateNachkommaDecimalShift();
@@ -70,4 +80,4 @@ public:
};
#endif
#endif //CLASSFFLOWPOSTPROCESSING_H

View File

@@ -3,7 +3,7 @@
#include "Helper.h"
#include "time_sntp.h"
#include "../../include/defines.h"
#include <time.h>
@@ -37,7 +37,7 @@ ClassFlowWriteList::ClassFlowWriteList(std::vector<ClassFlow*>* lfc)
bool ClassFlowWriteList::ReadParameter(FILE* pfile, string& aktparamgraph)
{
std::vector<string> zerlegt;
std::vector<string> splitted;
aktparamgraph = trim(aktparamgraph);
@@ -45,18 +45,12 @@ bool ClassFlowWriteList::ReadParameter(FILE* pfile, string& aktparamgraph)
if (!this->GetNextParagraph(pfile, aktparamgraph))
return false;
if (toUpper(aktparamgraph).compare("[MQTT]") != 0) // Paragraph passt nich zu MakeImage
if (toUpper(aktparamgraph).compare("[MQTT]") != 0)
return false;
while (this->getNextLine(pfile, &aktparamgraph) && !this->isNewParagraph(aktparamgraph))
{
zerlegt = this->ZerlegeZeile(aktparamgraph);
/*
if ((toUpper(zerlegt[0]) == "USER") && (zerlegt.size() > 1))
{
this->user = zerlegt[1];
}
*/
splitted = ZerlegeZeile(aktparamgraph);
}
return true;

View File

@@ -1,4 +1,8 @@
#pragma once
#ifndef CLASSFFLOWPWRITELIST_H
#define CLASSFFLOWPWRITELIST_H
#include "ClassFlow.h"
#include "ClassFlowPostProcessing.h"
@@ -20,3 +24,4 @@ public:
string name(){return "ClassFlowWriteList";};
};
#endif //CLASSFFLOWPWRITELIST_H

View File

@@ -1,101 +0,0 @@
#ifndef CAMERADEFINED
#define CAMERADEFINED
#if defined(CAMERA_MODEL_WROVER_KIT)
#define PWDN_GPIO_NUM -1
#define RESET_GPIO_NUM -1
#define XCLK_GPIO_NUM 21
#define SIOD_GPIO_NUM 26
#define SIOC_GPIO_NUM 27
#define Y9_GPIO_NUM 35
#define Y8_GPIO_NUM 34
#define Y7_GPIO_NUM 39
#define Y6_GPIO_NUM 36
#define Y5_GPIO_NUM 19
#define Y4_GPIO_NUM 18
#define Y3_GPIO_NUM 5
#define Y2_GPIO_NUM 4
#define VSYNC_GPIO_NUM 25
#define HREF_GPIO_NUM 23
#define PCLK_GPIO_NUM 22
#elif defined(CAMERA_MODEL_M5STACK_PSRAM)
#define PWDN_GPIO_NUM -1
#define RESET_GPIO_NUM 15
#define XCLK_GPIO_NUM 27
#define SIOD_GPIO_NUM 25
#define SIOC_GPIO_NUM 23
#define Y9_GPIO_NUM 19
#define Y8_GPIO_NUM 36
#define Y7_GPIO_NUM 18
#define Y6_GPIO_NUM 39
#define Y5_GPIO_NUM 5
#define Y4_GPIO_NUM 34
#define Y3_GPIO_NUM 35
#define Y2_GPIO_NUM 32
#define VSYNC_GPIO_NUM 22
#define HREF_GPIO_NUM 26
#define PCLK_GPIO_NUM 21
#elif defined(CAMERA_MODEL_AI_THINKER)
#define PWDN_GPIO_NUM GPIO_NUM_32
#define RESET_GPIO_NUM -1
#define XCLK_GPIO_NUM GPIO_NUM_0
#define SIOD_GPIO_NUM GPIO_NUM_26
#define SIOC_GPIO_NUM GPIO_NUM_27
#define Y9_GPIO_NUM GPIO_NUM_35
#define Y8_GPIO_NUM GPIO_NUM_34
#define Y7_GPIO_NUM GPIO_NUM_39
#define Y6_GPIO_NUM GPIO_NUM_36
#define Y5_GPIO_NUM GPIO_NUM_21
#define Y4_GPIO_NUM GPIO_NUM_19
#define Y3_GPIO_NUM GPIO_NUM_18
#define Y2_GPIO_NUM GPIO_NUM_5
#define VSYNC_GPIO_NUM GPIO_NUM_25
#define HREF_GPIO_NUM GPIO_NUM_23
#define PCLK_GPIO_NUM GPIO_NUM_22
#else
#error "Camera model not selected"
#endif
static camera_config_t camera_config = {
.pin_pwdn = PWDN_GPIO_NUM,
.pin_reset = RESET_GPIO_NUM,
.pin_xclk = XCLK_GPIO_NUM,
.pin_sscb_sda = SIOD_GPIO_NUM,
.pin_sscb_scl = SIOC_GPIO_NUM,
.pin_d7 = Y9_GPIO_NUM,
.pin_d6 = Y8_GPIO_NUM,
.pin_d5 = Y7_GPIO_NUM,
.pin_d4 = Y6_GPIO_NUM,
.pin_d3 = Y5_GPIO_NUM,
.pin_d2 = Y4_GPIO_NUM,
.pin_d1 = Y3_GPIO_NUM,
.pin_d0 = Y2_GPIO_NUM,
.pin_vsync = VSYNC_GPIO_NUM,
.pin_href = HREF_GPIO_NUM,
.pin_pclk = PCLK_GPIO_NUM,
//XCLK 20MHz or 10MHz for OV2640 double FPS (Experimental)
.xclk_freq_hz = 20000000,
.ledc_timer = LEDC_TIMER_0,
.ledc_channel = LEDC_CHANNEL_0,
.pixel_format = PIXFORMAT_JPEG,//YUV422,GRAYSCALE,RGB565,JPEG
// .pixel_format = PIXFORMAT_RGB888,//YUV422,GRAYSCALE,RGB565,JPEG
// .frame_size = FRAMESIZE_QVGA,//QQVGA-QXGA Do not use sizes above QVGA when not JPEG
.frame_size = FRAMESIZE_SVGA,//QQVGA-QXGA Do not use sizes above QVGA when not JPEG
.jpeg_quality = 12, //0-63 lower number means higher quality
.fb_count = 1 //if more than one, i2s runs in continuous mode. Use only with JPEG
};
#endif

View File

@@ -2,6 +2,6 @@ FILE(GLOB_RECURSE app_sources ${CMAKE_CURRENT_SOURCE_DIR}/*.*)
idf_component_register(SRCS ${app_sources}
INCLUDE_DIRS "."
REQUIRES tflite-lib jomjol_logfile)
REQUIRES tflite-lib jomjol_logfile fatfs sdmmc)

View File

@@ -7,6 +7,12 @@
#include <sys/types.h>
#include <sys/stat.h>
#include <iomanip>
#include <sstream>
#include <fstream>
#include <iostream>
#include <math.h>
#ifdef __cplusplus
extern "C" {
#endif
@@ -17,65 +23,154 @@ extern "C" {
#include <string.h>
#include <esp_log.h>
#include "../../include/defines.h"
#include "ClassLogFile.h"
//#include "ClassLogFile.h"
//#define ISWINDOWS_TRUE
#define PATH_MAX_STRING_SIZE 256
#include "esp_vfs_fat.h"
static const char* TAG = "HELPER";
using namespace std;
unsigned int systemStatus = 0;
sdmmc_cid_t SDCardCid;
sdmmc_csd_t SDCardCsd;
// #define DEBUG_DETAIL_ON
/////////////////////////////////////////////////////////////////////////////////////////////
string getESPHeapInfo(){
string espInfoResultStr = "";
char aMsgBuf[80];
multi_heap_info_t aMultiHead_info ;
heap_caps_get_info (&aMultiHead_info,MALLOC_CAP_8BIT);
size_t aFreeHeapSize = heap_caps_get_free_size(MALLOC_CAP_8BIT);
size_t aMinFreeHeadSize = heap_caps_get_minimum_free_size(MALLOC_CAP_8BIT);
size_t aMinFreeHeapSize = heap_caps_get_minimum_free_size(MALLOC_CAP_8BIT);
size_t aHeapLargestFreeBlockSize = heap_caps_get_largest_free_block(MALLOC_CAP_8BIT);
sprintf(aMsgBuf," Free Heap Size: %ld", (long) aFreeHeapSize);
size_t aFreeSPIHeapSize = heap_caps_get_free_size(MALLOC_CAP_8BIT| MALLOC_CAP_SPIRAM);
size_t aFreeInternalHeapSize = heap_caps_get_free_size(MALLOC_CAP_8BIT| MALLOC_CAP_INTERNAL);
size_t aMinFreeInternalHeapSize = heap_caps_get_minimum_free_size(MALLOC_CAP_8BIT| MALLOC_CAP_INTERNAL);
sprintf(aMsgBuf," Heap: %ld", (long) aFreeHeapSize);
size_t aFreeHeapSize = heap_caps_get_free_size(MALLOC_CAP_8BIT);
size_t aFreeSPIHeapSize = heap_caps_get_free_size(MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM);
size_t aFreeInternalHeapSize = heap_caps_get_free_size(MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL);
size_t aHeapLargestFreeBlockSize = heap_caps_get_largest_free_block(MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM);
size_t aHeapIntLargestFreeBlockSize = heap_caps_get_largest_free_block(MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL);
size_t aMinFreeHeapSize = heap_caps_get_minimum_free_size(MALLOC_CAP_8BIT | MALLOC_CAP_SPIRAM);
size_t aMinFreeInternalHeapSize = heap_caps_get_minimum_free_size(MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL);
sprintf(aMsgBuf,"Heap Total: %ld", (long) aFreeHeapSize);
espInfoResultStr += string(aMsgBuf);
sprintf(aMsgBuf," Min Free: %ld", (long) aMinFreeHeapSize);
sprintf(aMsgBuf," | SPI Free: %ld", (long) aFreeSPIHeapSize);
espInfoResultStr += string(aMsgBuf);
sprintf(aMsgBuf," larg. Block: %ld", (long) aHeapLargestFreeBlockSize);
sprintf(aMsgBuf," | SPI Larg Block: %ld", (long) aHeapLargestFreeBlockSize);
espInfoResultStr += string(aMsgBuf);
sprintf(aMsgBuf," SPI Heap: %ld", (long) aFreeSPIHeapSize);
sprintf(aMsgBuf," | SPI Min Free: %ld", (long) aMinFreeHeapSize);
espInfoResultStr += string(aMsgBuf);
sprintf(aMsgBuf," Min Free Heap Size: %ld", (long) aMinFreeHeadSize);
sprintf(aMsgBuf," NOT_SPI Heap: %ld", (long) (aFreeHeapSize - aFreeSPIHeapSize));
sprintf(aMsgBuf," | Int Free: %ld", (long) (aFreeInternalHeapSize));
espInfoResultStr += string(aMsgBuf);
sprintf(aMsgBuf," largest Block Size: %ld", (long) aHeapLargestFreeBlockSize);
sprintf(aMsgBuf," Internal Heap: %ld", (long) (aFreeInternalHeapSize));
sprintf(aMsgBuf," | Int Larg Block: %ld", (long) aHeapIntLargestFreeBlockSize);
espInfoResultStr += string(aMsgBuf);
sprintf(aMsgBuf," Internal Min Heap free: %ld", (long) (aMinFreeInternalHeapSize));
sprintf(aMsgBuf," | Int Min Free: %ld", (long) (aMinFreeInternalHeapSize));
espInfoResultStr += string(aMsgBuf);
return espInfoResultStr;
}
size_t getESPHeapSize(){
size_t aFreeHeapSize = heap_caps_get_free_size(MALLOC_CAP_8BIT);
return aFreeHeapSize;
}
size_t getInternalESPHeapSize() {
size_t aFreeInternalHeapSize = heap_caps_get_free_size(MALLOC_CAP_8BIT| MALLOC_CAP_INTERNAL);
return aFreeInternalHeapSize;
size_t getESPHeapSize()
{
return heap_caps_get_free_size(MALLOC_CAP_8BIT);
}
size_t getInternalESPHeapSize()
{
return heap_caps_get_free_size(MALLOC_CAP_8BIT| MALLOC_CAP_INTERNAL);
}
string getSDCardPartitionSize(){
FATFS *fs;
uint32_t fre_clust, tot_sect;
/* Get volume information and free clusters of drive 0 */
f_getfree("0:", (DWORD *)&fre_clust, &fs);
tot_sect = ((fs->n_fatent - 2) * fs->csize) /1024 /(1024/SDCardCsd.sector_size); //corrected by SD Card sector size (usually 512 bytes) and convert to MB
//ESP_LOGD(TAG, "%d MB total drive space (Sector size [bytes]: %d)", (int)tot_sect, (int)fs->ssize);
return std::to_string(tot_sect);
}
string getSDCardFreePartitionSpace(){
FATFS *fs;
uint32_t fre_clust, fre_sect;
/* Get volume information and free clusters of drive 0 */
f_getfree("0:", (DWORD *)&fre_clust, &fs);
fre_sect = (fre_clust * fs->csize) / 1024 /(1024/SDCardCsd.sector_size); //corrected by SD Card sector size (usually 512 bytes) and convert to MB
//ESP_LOGD(TAG, "%d MB free drive space (Sector size [bytes]: %d)", (int)fre_sect, (int)fs->ssize);
return std::to_string(fre_sect);
}
string getSDCardPartitionAllocationSize(){
FATFS *fs;
uint32_t fre_clust, allocation_size;
/* Get volume information and free clusters of drive 0 */
f_getfree("0:", (DWORD *)&fre_clust, &fs);
allocation_size = fs->ssize;
//ESP_LOGD(TAG, "SD Card Partition Allocation Size: %d bytes", allocation_size);
return std::to_string(allocation_size);
}
void SaveSDCardInfo(sdmmc_card_t* card) {
SDCardCid = card->cid;
SDCardCsd = card->csd;
}
string getSDCardManufacturer(){
string SDCardManufacturer = SDCardParseManufacturerIDs(SDCardCid.mfg_id);
//ESP_LOGD(TAG, "SD Card Manufacturer: %s", SDCardManufacturer.c_str());
return (SDCardManufacturer + " (ID: " + std::to_string(SDCardCid.mfg_id) + ")");
}
string getSDCardName(){
char *SDCardName = SDCardCid.name;
//ESP_LOGD(TAG, "SD Card Name: %s", SDCardName);
return std::string(SDCardName);
}
string getSDCardCapacity(){
int SDCardCapacity = SDCardCsd.capacity / (1024/SDCardCsd.sector_size) / 1024; // total sectors * sector size --> Byte to MB (1024*1024)
//ESP_LOGD(TAG, "SD Card Capacity: %s", std::to_string(SDCardCapacity).c_str());
return std::to_string(SDCardCapacity);
}
string getSDCardSectorSize(){
int SDCardSectorSize = SDCardCsd.sector_size;
//ESP_LOGD(TAG, "SD Card Sector Size: %s bytes", std::to_string(SDCardSectorSize).c_str());
return std::to_string(SDCardSectorSize);
}
///////////////////////////////////////////////////////////////////////////////////////////////
void memCopyGen(uint8_t* _source, uint8_t* _target, int _size)
@@ -85,38 +180,6 @@ void memCopyGen(uint8_t* _source, uint8_t* _target, int _size)
}
FILE* OpenFileAndWait(const char* nm, const char* _mode, int _waitsec)
{
FILE *pfile;
printf("open file %s in mode %s\n", nm, _mode);
if ((pfile = fopen(nm, _mode)) != NULL) {
printf("File %s successfully opened\n", nm);
}
else {
printf("Error: file %s does not exist!\n", nm);
return NULL;
}
/*
if (pfile == NULL)
{
TickType_t xDelay;
xDelay = _waitsec * 1000 / portTICK_PERIOD_MS;
std::string zw = "File is locked: " + std::string(nm) + " - wait for " + std::to_string(_waitsec) + " seconds";
printf(zw.c_str());
printf("\n");
LogFile.WriteToFile(zw);
vTaskDelay( xDelay );
pfile = fopen(nm, _mode);
}
*/
return pfile;
}
std::string FormatFileName(std::string input)
{
#ifdef ISWINDOWS_TRUE
@@ -129,6 +192,12 @@ std::string FormatFileName(std::string input)
}
std::size_t file_size(const std::string& file_name) {
std::ifstream file(file_name.c_str(),std::ios::in | std::ios::binary);
if (!file) return 0;
file.seekg (0, std::ios::end);
return static_cast<std::size_t>(file.tellg());
}
void FindReplace(std::string& line, std::string& oldString, std::string& newString) {
@@ -155,6 +224,16 @@ void FindReplace(std::string& line, std::string& oldString, std::string& newStri
}
bool MakeDir(std::string _what)
{
int mk_ret = mkdir(_what.c_str(), 0775);
if (mk_ret)
{
ESP_LOGD(TAG, "error with mkdir %s ret %d", _what.c_str(), mk_ret);
return false;
}
return true;
}
bool ctype_space(const char c, string adddelimiter)
@@ -169,6 +248,7 @@ bool ctype_space(const char c, string adddelimiter)
return false;
}
string trim(string istring, string adddelimiter)
{
bool trimmed = false;
@@ -195,6 +275,7 @@ string trim(string istring, string adddelimiter)
}
}
size_t findDelimiterPos(string input, string delimiter)
{
size_t pos = std::string::npos;
@@ -219,58 +300,72 @@ size_t findDelimiterPos(string input, string delimiter)
}
void RenameFile(string from, string to)
bool RenameFile(string from, string to)
{
// ESP_LOGI(logTag, "Deleting file : %s", fn.c_str());
// ESP_LOGI(logTag, "Deleting file: %s", fn.c_str());
/* Delete file */
FILE* fpSourceFile = OpenFileAndWait(from.c_str(), "rb");
FILE* fpSourceFile = fopen(from.c_str(), "rb");
if (!fpSourceFile) // Sourcefile existiert nicht sonst gibt es einen Fehler beim Kopierversuch!
{
printf("DeleteFile: File %s existiert nicht!\n", from.c_str());
return;
ESP_LOGE(TAG, "DeleteFile: File %s existiert nicht!", from.c_str());
return false;
}
fclose(fpSourceFile);
rename(from.c_str(), to.c_str());
return true;
}
void DeleteFile(string fn)
bool FileExists(string filename)
{
// ESP_LOGI(logTag, "Deleting file : %s", fn.c_str());
/* Delete file */
FILE* fpSourceFile = OpenFileAndWait(fn.c_str(), "rb");
FILE* fpSourceFile = fopen(filename.c_str(), "rb");
if (!fpSourceFile) // Sourcefile existiert nicht sonst gibt es einen Fehler beim Kopierversuch!
{
printf("DeleteFile: File %s existiert nicht!\n", fn.c_str());
return;
return false;
}
fclose(fpSourceFile);
return true;
}
bool DeleteFile(string fn)
{
// ESP_LOGI(logTag, "Deleting file: %s", fn.c_str());
/* Delete file */
FILE* fpSourceFile = fopen(fn.c_str(), "rb");
if (!fpSourceFile) // Sourcefile existiert nicht sonst gibt es einen Fehler beim Kopierversuch!
{
ESP_LOGD(TAG, "DeleteFile: File %s existiert nicht!", fn.c_str());
return false;
}
fclose(fpSourceFile);
unlink(fn.c_str());
unlink(fn.c_str());
return true;
}
void CopyFile(string input, string output)
bool CopyFile(string input, string output)
{
input = FormatFileName(input);
output = FormatFileName(output);
if (toUpper(input).compare("/SDCARD/WLAN.INI") == 0)
if (toUpper(input).compare(WLAN_CONFIG_FILE) == 0)
{
printf("wlan.ini kann nicht kopiert werden!\n");
return;
ESP_LOGD(TAG, "wlan.ini kann nicht kopiert werden!");
return false;
}
char cTemp;
FILE* fpSourceFile = OpenFileAndWait(input.c_str(), "rb");
FILE* fpSourceFile = fopen(input.c_str(), "rb");
if (!fpSourceFile) // Sourcefile existiert nicht sonst gibt es einen Fehler beim Kopierversuch!
{
printf("File %s existiert nicht!\n", input.c_str());
return;
ESP_LOGD(TAG, "File %s existiert nicht!", input.c_str());
return false;
}
FILE* fpTargetFile = OpenFileAndWait(output.c_str(), "wb");
FILE* fpTargetFile = fopen(output.c_str(), "wb");
// Code Section
@@ -284,9 +379,11 @@ void CopyFile(string input, string output)
// Close The Files
fclose(fpSourceFile);
fclose(fpTargetFile);
printf("File copied: %s to %s", input.c_str(), output.c_str());
ESP_LOGD(TAG, "File copied: %s to %s", input.c_str(), output.c_str());
return true;
}
string getFileFullFileName(string filename)
{
size_t lastpos = filename.find_last_of('/');
@@ -294,13 +391,14 @@ string getFileFullFileName(string filename)
if (lastpos == string::npos)
return "";
// printf("Last position: %d\n", lastpos);
// ESP_LOGD(TAG, "Last position: %d", lastpos);
string zw = filename.substr(lastpos + 1, filename.size() - lastpos);
return zw;
}
string getDirectory(string filename)
{
size_t lastpos = filename.find('/');
@@ -311,15 +409,16 @@ string getDirectory(string filename)
if (lastpos == string::npos)
return "";
// printf("Directory: %d\n", lastpos);
// ESP_LOGD(TAG, "Directory: %d", lastpos);
string zw = filename.substr(0, lastpos - 1);
return zw;
}
string getFileType(string filename)
{
size_t lastpos = filename.find(".", 0);
size_t lastpos = filename.rfind(".", filename.length());
size_t neu_pos;
while ((neu_pos = filename.find(".", lastpos + 1)) > -1)
{
@@ -335,16 +434,17 @@ string getFileType(string filename)
return zw;
}
/* recursive mkdir */
int mkdir_r(const char *dir, const mode_t mode) {
char tmp[PATH_MAX_STRING_SIZE];
char tmp[FILE_PATH_MAX];
char *p = NULL;
struct stat sb;
size_t len;
/* copy path */
len = strnlen (dir, PATH_MAX_STRING_SIZE);
if (len == 0 || len == PATH_MAX_STRING_SIZE) {
len = strnlen (dir, FILE_PATH_MAX);
if (len == 0 || len == FILE_PATH_MAX) {
return -1;
}
memcpy (tmp, dir, len);
@@ -392,6 +492,7 @@ int mkdir_r(const char *dir, const mode_t mode) {
return 0;
}
string toUpper(string in)
{
for (int i = 0; i < in.length(); ++i)
@@ -400,6 +501,7 @@ string toUpper(string in)
return in;
}
string toLower(string in)
{
for (int i = 0; i < in.length(); ++i)
@@ -408,6 +510,7 @@ string toLower(string in)
return in;
}
// CPU Temp
extern "C" uint8_t temprature_sens_read();
float temperatureRead()
@@ -415,18 +518,20 @@ float temperatureRead()
return (temprature_sens_read() - 32) / 1.8;
}
time_t addDays(time_t startTime, int days) {
struct tm* tm = localtime(&startTime);
tm->tm_mday += days;
return mktime(tm);
}
int removeFolder(const char* folderPath, const char* logTag) {
ESP_LOGI(logTag, "Delete folder %s", folderPath);
//ESP_LOGD(logTag, "Delete content in path %s", folderPath);
DIR *dir = opendir(folderPath);
if (!dir) {
ESP_LOGI(logTag, "Failed to stat dir : %s", folderPath);
ESP_LOGE(logTag, "Failed to stat dir: %s", folderPath);
return -1;
}
@@ -435,10 +540,11 @@ int removeFolder(const char* folderPath, const char* logTag) {
while ((entry = readdir(dir)) != NULL) {
std::string path = string(folderPath) + "/" + entry->d_name;
if (entry->d_type == DT_REG) {
//ESP_LOGD(logTag, "Delete file %s", path.c_str());
if (unlink(path.c_str()) == 0) {
deleted ++;
} else {
ESP_LOGE(logTag, "can't delete file : %s", path.c_str());
ESP_LOGE(logTag, "can't delete file: %s", path.c_str());
}
} else if (entry->d_type == DT_DIR) {
deleted += removeFolder(path.c_str(), logTag);
@@ -447,15 +553,14 @@ int removeFolder(const char* folderPath, const char* logTag) {
closedir(dir);
if (rmdir(folderPath) != 0) {
ESP_LOGE(logTag, "can't delete file : %s", folderPath);
ESP_LOGE(logTag, "can't delete folder: %s", folderPath);
}
ESP_LOGI(logTag, "%d older log files in folder %s deleted.", deleted, folderPath);
ESP_LOGD(logTag, "%d files in folder %s deleted.", deleted, folderPath);
return deleted;
}
std::vector<string> HelperZerlegeZeile(std::string input, std::string _delimiter = "")
{
std::vector<string> Output;
@@ -464,19 +569,334 @@ std::vector<string> HelperZerlegeZeile(std::string input, std::string _delimiter
delimiter = _delimiter;
}
input = trim(input, delimiter);
size_t pos = findDelimiterPos(input, delimiter);
std::string token;
while (pos != std::string::npos) {
token = input.substr(0, pos);
token = trim(token, delimiter);
Output.push_back(token);
input.erase(0, pos + 1);
input = trim(input, delimiter);
pos = findDelimiterPos(input, delimiter);
}
Output.push_back(input);
return Output;
return ZerlegeZeile(input, delimiter);
}
std::vector<string> ZerlegeZeile(std::string input, std::string delimiter)
{
std::vector<string> Output;
input = trim(input, delimiter);
/* The input can have multiple formats:
* - key = value
* - key = value1 value2 value3 ...
* - key value1 value2 value3 ...
*
* Examples:
* - ImageSize = VGA
* - IO0 = input disabled 10 false false
* - main.dig1 28 144 55 100 false
*
* This causes issues eg. if a password key has a whitespace or equal sign in its value.
* As a workaround and to not break any legacy usage, we enforce to only use the
* equal sign, if the key is "password"
*/
if (input.find("password") != string::npos) { // Line contains a password, use the equal sign as the only delimiter and only split on first occurrence
size_t pos = input.find("=");
Output.push_back(trim(input.substr(0, pos), ""));
Output.push_back(trim(input.substr(pos +1, string::npos), ""));
}
else { // Legacy Mode
size_t pos = findDelimiterPos(input, delimiter);
std::string token;
while (pos != std::string::npos) {
token = input.substr(0, pos);
token = trim(token, delimiter);
Output.push_back(token);
input.erase(0, pos + 1);
input = trim(input, delimiter);
pos = findDelimiterPos(input, delimiter);
}
Output.push_back(input);
}
return Output;
}
std::string ReplaceString(std::string subject, const std::string& search,
const std::string& replace) {
size_t pos = 0;
while ((pos = subject.find(search, pos)) != std::string::npos) {
subject.replace(pos, search.length(), replace);
pos += replace.length();
}
return subject;
}
/* Source: https://git.kernel.org/pub/scm/utils/mmc/mmc-utils.git/tree/lsmmc.c */
/* SD Card Manufacturer Database */
struct SDCard_Manufacturer_database {
string type;
int id;
string manufacturer;
};
/* Source: https://git.kernel.org/pub/scm/utils/mmc/mmc-utils.git/tree/lsmmc.c */
/* SD Card Manufacturer Database */
struct SDCard_Manufacturer_database database[] = {
{
.type = "sd",
.id = 0x01,
.manufacturer = "Panasonic",
},
{
.type = "sd",
.id = 0x02,
.manufacturer = "Toshiba/Kingston/Viking",
},
{
.type = "sd",
.id = 0x03,
.manufacturer = "SanDisk",
},
{
.type = "sd",
.id = 0x08,
.manufacturer = "Silicon Power",
},
{
.type = "sd",
.id = 0x18,
.manufacturer = "Infineon",
},
{
.type = "sd",
.id = 0x1b,
.manufacturer = "Transcend/Samsung",
},
{
.type = "sd",
.id = 0x1c,
.manufacturer = "Transcend",
},
{
.type = "sd",
.id = 0x1d,
.manufacturer = "Corsair/AData",
},
{
.type = "sd",
.id = 0x1e,
.manufacturer = "Transcend",
},
{
.type = "sd",
.id = 0x1f,
.manufacturer = "Kingston",
},
{
.type = "sd",
.id = 0x27,
.manufacturer = "Delkin/Phison",
},
{
.type = "sd",
.id = 0x28,
.manufacturer = "Lexar",
},
{
.type = "sd",
.id = 0x30,
.manufacturer = "SanDisk",
},
{
.type = "sd",
.id = 0x31,
.manufacturer = "Silicon Power",
},
{
.type = "sd",
.id = 0x33,
.manufacturer = "STMicroelectronics",
},
{
.type = "sd",
.id = 0x41,
.manufacturer = "Kingston",
},
{
.type = "sd",
.id = 0x6f,
.manufacturer = "STMicroelectronics",
},
{
.type = "sd",
.id = 0x74,
.manufacturer = "Transcend",
},
{
.type = "sd",
.id = 0x76,
.manufacturer = "Patriot",
},
{
.type = "sd",
.id = 0x82,
.manufacturer = "Gobe/Sony",
},
{
.type = "sd",
.id = 0x89,
.manufacturer = "Unknown",
}
};
/* Parse SD Card Manufacturer Database */
string SDCardParseManufacturerIDs(int id)
{
unsigned int id_cnt = sizeof(database) / sizeof(struct SDCard_Manufacturer_database);
string ret_val = "";
for (int i = 0; i < id_cnt; i++) {
if (database[i].id == id) {
return database[i].manufacturer;
}
else {
ret_val = "ID unknown (not in DB)";
}
}
return ret_val;
}
string RundeOutput(double _in, int _anzNachkomma)
{
std::stringstream stream;
int _zw = _in;
// ESP_LOGD(TAG, "AnzNachkomma: %d", _anzNachkomma);
if (_anzNachkomma < 0) {
_anzNachkomma = 0;
}
if (_anzNachkomma > 0)
{
stream << std::fixed << std::setprecision(_anzNachkomma) << _in;
return stream.str();
}
else
{
stream << _zw;
}
return stream.str();
}
string getMac(void) {
uint8_t macInt[6];
char macFormated[6*2 + 5 + 1]; // AA:BB:CC:DD:EE:FF
esp_read_mac(macInt, ESP_MAC_WIFI_STA);
sprintf(macFormated, "%02X:%02X:%02X:%02X:%02X:%02X", macInt[0], macInt[1], macInt[2], macInt[3], macInt[4], macInt[5]);
return macFormated;
}
void setSystemStatusFlag(SystemStatusFlag_t flag) {
systemStatus = systemStatus | flag; // set bit
char buf[20];
snprintf(buf, sizeof(buf), "0x%08X", getSystemStatus());
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "New System Status: " + std::string(buf));
}
void clearSystemStatusFlag(SystemStatusFlag_t flag) {
systemStatus = systemStatus | ~flag; // clear bit
char buf[20];
snprintf(buf, sizeof(buf), "0x%08X", getSystemStatus());
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "New System Status: " + std::string(buf));
}
int getSystemStatus(void) {
return systemStatus;
}
bool isSetSystemStatusFlag(SystemStatusFlag_t flag) {
//ESP_LOGE(TAG, "Flag (0x%08X) is set (0x%08X): %d", flag, systemStatus , ((systemStatus & flag) == flag));
if ((systemStatus & flag) == flag) {
return true;
}
else {
return false;
}
}
time_t getUpTime(void) {
return (uint32_t)(esp_timer_get_time()/1000/1000); // in seconds
}
string getResetReason(void) {
std::string reasonText;
switch(esp_reset_reason()) {
case ESP_RST_POWERON: reasonText = "Power-on event (or reset button)"; break; //!< Reset due to power-on event
case ESP_RST_EXT: reasonText = "External pin"; break; //!< Reset by external pin (not applicable for ESP32)
case ESP_RST_SW: reasonText = "Via esp_restart"; break; //!< Software reset via esp_restart
case ESP_RST_PANIC: reasonText = "Exception/panic"; break; //!< Software reset due to exception/panic
case ESP_RST_INT_WDT: reasonText = "Interrupt watchdog"; break; //!< Reset (software or hardware) due to interrupt watchdog
case ESP_RST_TASK_WDT: reasonText = "Task watchdog"; break; //!< Reset due to task watchdog
case ESP_RST_WDT: reasonText = "Other watchdogs"; break; //!< Reset due to other watchdogs
case ESP_RST_DEEPSLEEP: reasonText = "Exiting deep sleep mode"; break; //!< Reset after exiting deep sleep mode
case ESP_RST_BROWNOUT: reasonText = "Brownout"; break; //!< Brownout reset (software or hardware)
case ESP_RST_SDIO: reasonText = "SDIO"; break; //!< Reset over SDIO
case ESP_RST_UNKNOWN: //!< Reset reason can not be determined
default:
reasonText = "Unknown";
}
return reasonText;
}
/**
* Returns the current uptime formated ad xxf xxh xxm [xxs]
*/
std::string getFormatedUptime(bool compact) {
char buf[20];
#pragma GCC diagnostic ignored "-Wformat-truncation"
int uptime = getUpTime(); // in seconds
int days = int(floor(uptime / (3600*24)));
int hours = int(floor((uptime - days * 3600*24) / (3600)));
int minutes = int(floor((uptime - days * 3600*24 - hours * 3600) / (60)));
int seconds = uptime - days * 3600*24 - hours * 3600 - minutes * 60;
if (compact) {
snprintf(buf, sizeof(buf), "%dd%02dh%02dm%02ds", days, hours, minutes, seconds);
}
else {
snprintf(buf, sizeof(buf), "%3dd %02dh %02dm %02ds", days, hours, minutes, seconds);
}
return std::string(buf);
}
const char* get404(void) {
return
"<pre>\n\n\n\n"
" _\n"
" .__(.)< ( oh oh! This page does not exist! )\n"
" \\___)\n"
"\n\n"
" You could try your <a href=index.html target=_parent>luck</a> here!</pre>\n"
"<script>document.cookie = \"page=overview.html\"</script>"; // Make sure we load the overview page
}

View File

@@ -1,20 +1,27 @@
#pragma once
#ifndef HELPER_H
#define HELPER_H
#include <string>
#include <fstream>
#include <vector>
#include "sdmmc_cmd.h"
using namespace std;
std::string FormatFileName(std::string input);
std::size_t file_size(const std::string& file_name);
void FindReplace(std::string& line, std::string& oldString, std::string& newString);
void CopyFile(string input, string output);
void DeleteFile(string fn);
void RenameFile(string from, string to);
bool CopyFile(string input, string output);
bool DeleteFile(string fn);
bool RenameFile(string from, string to);
bool MakeDir(std::string _what);
bool FileExists(string filename);
FILE* OpenFileAndWait(const char* nm, const char* _mode, int _waitsec = 1);
string RundeOutput(double _in, int _anzNachkomma);
size_t findDelimiterPos(string input, string delimiter);
//string trim(string istring);
@@ -25,6 +32,7 @@ string getFileType(string filename);
string getFileFullFileName(string filename);
string getDirectory(string filename);
int mkdir_r(const char *dir, const mode_t mode);
int removeFolder(const char* folderPath, const char* logTag);
@@ -38,6 +46,7 @@ time_t addDays(time_t startTime, int days);
void memCopyGen(uint8_t* _source, uint8_t* _target, int _size);
std::vector<string> HelperZerlegeZeile(std::string input, std::string _delimiter);
std::vector<std::string> ZerlegeZeile(std::string input, std::string delimiter = " =, \t");
///////////////////////////
size_t getInternalESPHeapSize();
@@ -45,3 +54,43 @@ size_t getESPHeapSize();
string getESPHeapInfo();
/////////////////////////////
string getSDCardPartitionSize();
string getSDCardFreePartitionSpace();
string getSDCardPartitionAllocationSize();
void SaveSDCardInfo(sdmmc_card_t* card);
string SDCardParseManufacturerIDs(int);
string getSDCardManufacturer();
string getSDCardName();
string getSDCardCapacity();
string getSDCardSectorSize();
string getMac(void);
/* Error bit fields
One bit per error
Make sure it matches https://jomjol.github.io/AI-on-the-edge-device-docs/Error-Codes */
enum SystemStatusFlag_t { // One bit per error
// First Byte
SYSTEM_STATUS_PSRAM_BAD = 1 << 0, // 1, Critical Error
SYSTEM_STATUS_HEAP_TOO_SMALL = 1 << 1, // 2, Critical Error
SYSTEM_STATUS_CAM_BAD = 1 << 2, // 4, Critical Error
// Second Byte
SYSTEM_STATUS_CAM_FB_BAD = 1 << (0+8), // 8, Flow still might work
SYSTEM_STATUS_NTP_BAD = 1 << (1+8), // 9, Flow will work but time will be wrong
};
void setSystemStatusFlag(SystemStatusFlag_t flag);
void clearSystemStatusFlag(SystemStatusFlag_t flag);
int getSystemStatus(void);
bool isSetSystemStatusFlag(SystemStatusFlag_t flag);
time_t getUpTime(void);
string getResetReason(void);
std::string getFormatedUptime(bool compact);
const char* get404(void);
#endif //HELPER_H

View File

@@ -0,0 +1,178 @@
#include "../../include/defines.h"
#ifdef DEBUG_ENABLE_SYSINFO
#include "esp_sys.h"
#include <string>
#include "esp_chip_info.h"
void Restart() {
esp_restart();
}
//source : https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/system/misc_system_api.html#_CPPv416esp_chip_model_t
//https://github.com/espressif/esp-idf/blob/8464186e67e34b417621df6b6f1f289a6c60b859/components/esp_hw_support/include/esp_chip_info.h
/*
typedef enum {
CHIP_ESP32 = 1, //!< ESP32
CHIP_ESP32S2 = 2, //!< ESP32-S2
CHIP_ESP32S3 = 9, //!< ESP32-S3
CHIP_ESP32C3 = 5, //!< ESP32-C3
CHIP_ESP32H4 = 6, //!< ESP32-H4
CHIP_ESP32C2 = 12, //!< ESP32-C2
CHIP_ESP32C6 = 13, //!< ESP32-C6
CHIP_ESP32H2 = 16, //!< ESP32-H2
CHIP_POSIX_LINUX = 999, //!< The code is running on POSIX/Linux simulator
} esp_chip_model_t;
*/
char* GetChipModel(){
esp_chip_info_t chipInfo;
esp_chip_info(&chipInfo);
switch((int)chipInfo.model) {
case 0 : return (char*)"ESP8266";
case (int)esp_chip_model_t::CHIP_ESP32 : return (char*)"ESP32";
#if ESP_IDF_VERSION >= ESP_IDF_VERSION_VAL(4, 0, 0)
case (int)esp_chip_model_t::CHIP_ESP32S2 : return (char*)"ESP32-S2";
case (int)esp_chip_model_t::CHIP_ESP32S3 : return (char*)"ESP32-S3";
case (int)esp_chip_model_t::CHIP_ESP32C3 : return (char*)"ESP32-C3";
case 6 : return (char*)"ESP32-H4";
case 12 : return (char*)"ESP32-C2";
case 13 : return (char*)"ESP32-C6";
//case (int)esp_chip_model_t::CHIP_ESP32H4 : return (char*)"ESP32-H4";
//case (int)esp_chip_model_t::CHIP_ESP32C2 : return (char*)"ESP32-C2";
//case (int)esp_chip_model_t::CHIP_ESP32C6 : return (char*)"ESP32-C6";
//case (int)esp_chip_model_t::CHIP_ESP32H2 : return (char*)"ESP32-H2";
case 16 : return (char*)"ESP32-H2";
//case (int)esp_chip_model_t::CHIP_POSIX_LINUX : return (char*)"CHIP_POSIX_LINUX";
#endif
}
return (char*)"Chip Unknown";
}
uint8_t GetChipCoreCount() {
esp_chip_info_t chipInfo;
esp_chip_info(&chipInfo);
return chipInfo.cores;
}
uint16_t GetChipRevision() {
esp_chip_info_t chipInfo;
esp_chip_info(&chipInfo);
return chipInfo.revision;
}
uint32_t GetChipfeatures() {
esp_chip_info_t chipInfo;
esp_chip_info(&chipInfo);
return chipInfo.features;
}
uint32_t GetFreeHeap() {
return esp_get_free_heap_size();
}
uint32_t GetLeastHeapFreeSinceBoot() {
return esp_get_minimum_free_heap_size();
}
std::string get_device_info()
{
esp_chip_info_t chip_info;
esp_chip_info(&chip_info);
std::string espInfoResultStr = "";
char aMsgBuf[40];
espInfoResultStr += "Device Info:";
espInfoResultStr += "---------------\n";
espInfoResultStr += "Chip Model: " + std::string(GetChipModel()) +"\n";
sprintf(aMsgBuf,"Chip Revision: %d\n", chip_info.revision);
espInfoResultStr += std::string(aMsgBuf);
sprintf(aMsgBuf,"CPU Cores: %d\n", chip_info.cores);
espInfoResultStr += std::string(aMsgBuf);
sprintf(aMsgBuf,"Flash Memory: %dMB\n", spi_flash_get_chip_size()/(1024*1024));
espInfoResultStr += std::string(aMsgBuf);
if(chip_info.features & CHIP_FEATURE_WIFI_BGN)
//espInfoResultStr += "Base MAC: " + std::string(getMac()) +"\n";
espInfoResultStr += "ESP-IDF version: " + std::string(esp_get_idf_version()) +"\n";
if((chip_info.features & CHIP_FEATURE_WIFI_BGN) || (chip_info.features & CHIP_FEATURE_BT) ||
(chip_info.features & CHIP_FEATURE_BLE) || (chip_info.features & CHIP_FEATURE_EMB_FLASH))
{
espInfoResultStr += "Characteristics:\n";
if(chip_info.features & CHIP_FEATURE_WIFI_BGN)
espInfoResultStr += " WiFi 2.4GHz\n";
if(chip_info.features & CHIP_FEATURE_BT)
espInfoResultStr += " Bluetooth Classic\n";
if(chip_info.features & CHIP_FEATURE_BLE)
espInfoResultStr += " Bluetooth Low Energy\n";
if(chip_info.features & CHIP_FEATURE_EMB_FLASH)
espInfoResultStr += " Embedded Flash memory\n";
else
espInfoResultStr += " External Flash memory\n";
}
#ifdef USE_HIMEM_IF_AVAILABLE
sprintf(aMsgBuf,"spiram size %u\n", esp_spiram_get_size());
espInfoResultStr += std::string(aMsgBuf);
sprintf(aMsgBuf,"himem free %u\n", esp_himem_get_free_size());
espInfoResultStr += std::string(aMsgBuf);
sprintf(aMsgBuf,"himem phys %u\n", esp_himem_get_phys_size());
espInfoResultStr += std::string(aMsgBuf);
sprintf(aMsgBuf,"himem reserved %u\n", esp_himem_reserved_area_size());
espInfoResultStr += std::string(aMsgBuf);
#endif
return espInfoResultStr;
}
size_t getFreeMemoryInternal(){ //Current Free Memory
return heap_caps_get_free_size(MALLOC_CAP_8BIT) - heap_caps_get_free_size(MALLOC_CAP_SPIRAM);
}
size_t getFreeMemorySPIRAM(){ //Current Free Memory
return heap_caps_get_free_size(MALLOC_CAP_SPIRAM);
}
size_t getLargestFreeBlockInternal(){ //Largest Free Block
return heap_caps_get_largest_free_block(MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL);
}
size_t getLargestFreeBlockSPIRAM(){ //Largest Free Block
return heap_caps_get_largest_free_block(MALLOC_CAP_SPIRAM);
}
size_t getMinEverFreeMemInternal(){ //Min. Ever Free Size
return heap_caps_get_minimum_free_size(MALLOC_CAP_8BIT | MALLOC_CAP_INTERNAL);
}
size_t getMinEverFreeMemSPIRAM(){ //Min. Ever Free Size
return heap_caps_get_minimum_free_size(MALLOC_CAP_SPIRAM);
}
#ifdef USE_HIMEM_IF_AVAILABLE
size_t getHimemTotSpace(){
return esp_himem_get_phys_size();
}
size_t getHimemFreeSpace(){
return esp_himem_get_free_size();
}
size_t getHimemReservedArea(){
return esp_himem_reserved_area_size();
}
#endif
#endif //DEBUG_ENABLE_SYSINFO

View File

@@ -0,0 +1,54 @@
#pragma once
#include "../../include/defines.h"
#ifdef DEBUG_ENABLE_SYSINFO
#ifndef ESP_SYS_H
#define ESP_SYS_H
#include <string>
// Device libraries (ESP-IDF)
#include <esp_system.h>
#include <esp_spi_flash.h>
#include <esp_heap_caps.h>
// for esp_spiram_get_size
extern "C" {
#include <esp32/spiram.h>
#ifdef USE_HIMEM_IF_AVAILABLE
#include <esp32/himem.h>
#endif
}
void Restart();
char *GetChipModel();
uint8_t GetChipCoreCount();
uint16_t GetChipRevision();
uint32_t GetChipfeatures();
uint32_t GetFreeHeap();
uint32_t GetLeastHeapFreeSinceBoot();
std::string get_device_info();
size_t getFreeMemoryInternal();
size_t getFreeMemorySPIRAM();
size_t getLargestFreeBlockInternal();
size_t getLargestFreeBlockSPIRAM();
size_t getMinEverFreeMemInternal();
size_t getMinEverFreeMemSPIRAM();
#ifdef USE_HIMEM_IF_AVAILABLE
size_t getHimemTotSpace();
size_t getHimemFreeSpace();
size_t getHimemReservedArea();
#endif
#endif //ESP_SYS_H
#endif // DEBUG_ENABLE_SYSINFO

View File

@@ -0,0 +1,115 @@
// need [env:esp32cam-dev-himem]
//CONFIG_SPIRAM_BANKSWITCH_ENABLE=y
//CONFIG_SPIRAM_BANKSWITCH_RESERVE=4
#include "../../include/defines.h"
#ifdef DEBUG_HIMEM_MEMORY_CHECK
#include "himem_memory_check.h"
//source adapted from : https://github.com/espressif/esp-idf/blob/master/examples/system/himem/main/himem_example_main.c
//Fill memory with pseudo-random data generated from the given seed.
//Fills the memory in 32-bit words for speed.
static void fill_mem_seed(int seed, void *mem, int len)
{
uint32_t *p = (uint32_t *)mem;
unsigned int rseed = seed ^ 0xa5a5a5a5;
for (int i = 0; i < len / 4; i++) {
*p++ = rand_r(&rseed);
}
}
//Check the memory filled by fill_mem_seed. Returns true if the data matches the data
//that fill_mem_seed wrote (when given the same seed).
//Returns true if there's a match, false when the region differs from what should be there.
static bool check_mem_seed(int seed, void *mem, int len, int phys_addr)
{
uint32_t *p = (uint32_t *)mem;
unsigned int rseed = seed ^ 0xa5a5a5a5;
for (int i = 0; i < len / 4; i++) {
uint32_t ex = rand_r(&rseed);
if (ex != *p) {
//printf("check_mem_seed: %x has 0x%08"PRIx32" expected 0x%08"PRIx32"\n", phys_addr+((char*)p-(char*)mem), *p, ex);
return false;
}
p++;
}
return true;
}
//Allocate a himem region, fill it with data, check it and release it.
static bool test_region(int check_size, int seed)
{
esp_himem_handle_t mh; //Handle for the address space we're using
esp_himem_rangehandle_t rh; //Handle for the actual RAM.
bool ret = true;
//Allocate the memory we're going to check.
ESP_ERROR_CHECK(esp_himem_alloc(check_size, &mh));
//Allocate a block of address range
ESP_ERROR_CHECK(esp_himem_alloc_map_range(ESP_HIMEM_BLKSZ, &rh));
for (int i = 0; i < check_size; i += ESP_HIMEM_BLKSZ) {
uint32_t *ptr = NULL;
//Map in block, write pseudo-random data, unmap block.
ESP_ERROR_CHECK(esp_himem_map(mh, rh, i, 0, ESP_HIMEM_BLKSZ, 0, (void**)&ptr));
fill_mem_seed(i ^ seed, ptr, ESP_HIMEM_BLKSZ); //
ESP_ERROR_CHECK(esp_himem_unmap(rh, ptr, ESP_HIMEM_BLKSZ));
}
vTaskDelay(5); //give the OS some time to do things so the task watchdog doesn't bark
for (int i = 0; i < check_size; i += ESP_HIMEM_BLKSZ) {
uint32_t *ptr;
//Map in block, check against earlier written pseudo-random data, unmap block.
ESP_ERROR_CHECK(esp_himem_map(mh, rh, i, 0, ESP_HIMEM_BLKSZ, 0, (void**)&ptr));
if (!check_mem_seed(i ^ seed, ptr, ESP_HIMEM_BLKSZ, i)) {
//printf("Error in block %d\n", i / ESP_HIMEM_BLKSZ);
ret = false;
}
ESP_ERROR_CHECK(esp_himem_unmap(rh, ptr, ESP_HIMEM_BLKSZ));
if (!ret) break; //don't check rest of blocks if error occurred
}
//Okay, all done!
ESP_ERROR_CHECK(esp_himem_free(mh));
ESP_ERROR_CHECK(esp_himem_free_map_range(rh));
return ret;
}
std::string himem_memory_check()
{
size_t memcnt=esp_himem_get_phys_size();
size_t memfree=esp_himem_get_free_size();
std::string espInfoResultStr = "";
char aMsgBuf[40];
espInfoResultStr += "Running HIMEM memory check";
sprintf(aMsgBuf,"Himem has %dKiB of memory", (int)memcnt/1024);
espInfoResultStr += std::string(aMsgBuf);
sprintf(aMsgBuf,"%dKiB of which is free", (int)memfree/1024);
espInfoResultStr += std::string(aMsgBuf);
espInfoResultStr += "\n please wait ....\n";
//running memory checks
//assert(test_region(memfree, 0xaaaa));
if(test_region(memfree, 0xaaaa)) {
espInfoResultStr += "Himem check Failed!\n";
} else {
espInfoResultStr += "Himem check Done!\n";
}
return espInfoResultStr;
}
#endif // DEBUG_HIMEM_MEMORY_CHECK

View File

@@ -0,0 +1,41 @@
// need [env:esp32cam-dev-himem]
//CONFIG_SPIRAM_BANKSWITCH_ENABLE=y
//CONFIG_SPIRAM_BANKSWITCH_RESERVE=4
#pragma once
#include "../../include/defines.h"
#ifdef DEBUG_HIMEM_MEMORY_CHECK
#ifndef HIMEM_MEMORY_CHECK_H
#define HIMEM_MEMORY_CHECK_H
//source : //source : https://github.com/espressif/esp-idf/blob/master/examples/system/himem/main/himem_example_main.c
#include <stdio.h>
#include <stdbool.h>
#include <stdint.h>
#include <inttypes.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "esp_system.h"
#include "esp_heap_caps.h"
#include "esp32/himem.h"
#include <string>
#include "esp32/himem.h"
std::string himem_memory_check();
#endif //HIMEM_MEMORY_CHECK_H
#endif // DEBUG_HIMEM_MEMORY_CHECK

View File

@@ -0,0 +1,87 @@
//source : https://github.com/Carbon225/esp32-perfmon
#include "../../include/defines.h"
/*
ESP32 CPU usage monitor
Gives you a rough idea of how the Xtensa cores are utilized.
Works by attaching idle hooks and measuring how often they get called. The core usage is calculated: usage% = idle ticks since last measurement / expected idle ticks if core were idle * 100%. The expected idle tick count was measured by running an empty program.
Limitations:
Should only be used for user information, not in logic that needs accurate values
New IDF versions could optimize performance and therefore introduce an error to usage estimation.
When one core is at 100% the other might report a negative value
Usage:
#include "perfmon.h"
Call perfmon_start() once
*/
#ifdef DEBUG_ENABLE_PERFMON
#include "perfmon.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_freertos_hooks.h"
#include "sdkconfig.h"
#include "esp_log.h"
static const char *TAG = "perfmon";
static uint64_t idle0Calls = 0;
static uint64_t idle1Calls = 0;
#if defined(CONFIG_ESP32_DEFAULT_CPU_FREQ_240)
static const uint64_t MaxIdleCalls = 1855000;
#elif defined(CONFIG_ESP32_DEFAULT_CPU_FREQ_160)
static const uint64_t MaxIdleCalls = 1233100;
#else
#error "Unsupported CPU frequency"
#endif
static bool idle_task_0()
{
idle0Calls += 1;
return false;
}
static bool idle_task_1()
{
idle1Calls += 1;
return false;
}
static void perfmon_task(void *args)
{
while (1)
{
float idle0 = idle0Calls;
float idle1 = idle1Calls;
idle0Calls = 0;
idle1Calls = 0;
int cpu0 = 100.f - idle0 / MaxIdleCalls * 100.f;
int cpu1 = 100.f - idle1 / MaxIdleCalls * 100.f;
ESP_LOGI(TAG, "Core 0 at %d%%", cpu0);
ESP_LOGI(TAG, "Core 1 at %d%%", cpu1);
// TODO configurable delay
vTaskDelay(5000 / portTICK_PERIOD_MS);
}
vTaskDelete(NULL);
}
esp_err_t perfmon_start()
{
ESP_ERROR_CHECK(esp_register_freertos_idle_hook_for_cpu(idle_task_0, 0));
ESP_ERROR_CHECK(esp_register_freertos_idle_hook_for_cpu(idle_task_1, 1));
// TODO calculate optimal stack size
xTaskCreate(perfmon_task, "perfmon", 2048, NULL, 1, NULL);
return ESP_OK;
}
#endif // DEBUG_ENABLE_PERFMON

View File

@@ -0,0 +1,24 @@
#include "../../include/defines.h"
#ifdef DEBUG_ENABLE_PERFMON
#ifndef COMPONENTS_PERFMON_INCLUDE_PERFMON_H_
#define COMPONENTS_PERFMON_INCLUDE_PERFMON_H_
#ifdef __cplusplus
extern "C" {
#endif
#include "esp_err.h"
esp_err_t perfmon_start();
#ifdef __cplusplus
}
#endif
#endif /* COMPONENTS_PERFMON_INCLUDE_PERFMON_H_ */
#endif //DEBUG_ENABLE_PERFMON

View File

@@ -2,14 +2,12 @@
#include "CRotateImage.h"
#include "ClassLogFile.h"
#define _USE_MATH_DEFINES
#include <math.h>
#include <algorithm>
#include <esp_log.h>
#include "../../include/defines.h"
//#define GET_MEMORY malloc
#define GET_MEMORY(X) heap_caps_malloc(X, MALLOC_CAP_SPIRAM)
static const char* TAG = "c_align_and_cut_image";
CAlignAndCutImage::CAlignAndCutImage(CImageBasis *_org, CImageBasis *_temp)
{
@@ -43,14 +41,14 @@ bool CAlignAndCutImage::Align(RefInfo *_temp1, RefInfo *_temp2)
r0_x = _temp1->target_x;
r0_y = _temp1->target_y;
printf("Vor ft->FindTemplate(_temp1); %s\n", _temp1->image_file.c_str());
ESP_LOGD(TAG, "Before ft->FindTemplate(_temp1); %s", _temp1->image_file.c_str());
isSimilar1 = ft->FindTemplate(_temp1);
_temp1->width = ft->tpl_width;
_temp1->height = ft->tpl_height;
r1_x = _temp2->target_x;
r1_y = _temp2->target_y;
printf("Vor ft->FindTemplate(_temp2); %s\n", _temp2->image_file.c_str());
ESP_LOGD(TAG, "Before ft->FindTemplate(_temp2); %s", _temp2->image_file.c_str());
isSimilar2 = ft->FindTemplate(_temp2);
_temp2->width = ft->tpl_width;
_temp2->height = ft->tpl_height;
@@ -74,19 +72,19 @@ bool CAlignAndCutImage::Align(RefInfo *_temp1, RefInfo *_temp2)
d_winkel = (w_ist - w_org) * 180 / M_PI;
#ifdef DEBUG_DETAIL_ON
/*#ifdef DEBUG_DETAIL_ON
std::string zw = "\tdx:\t" + std::to_string(dx) + "\tdy:\t" + std::to_string(dy) + "\td_winkel:\t" + std::to_string(d_winkel);
zw = zw + "\tt1_x_y:\t" + std::to_string(_temp1->found_x) + "\t" + std::to_string(_temp1->found_y);
zw = zw + "\tpara1_found_min_avg_max_SAD:\t" + std::to_string(_temp1->fastalg_min) + "\t" + std::to_string(_temp1->fastalg_avg) + "\t" + std::to_string(_temp1->fastalg_max) + "\t"+ std::to_string(_temp1->fastalg_SAD);
zw = zw + "\tt2_x_y:\t" + std::to_string(_temp2->found_x) + "\t" + std::to_string(_temp2->found_y);
zw = zw + "\tpara2_found_min_avg_max:\t" + std::to_string(_temp2->fastalg_min) + "\t" + std::to_string(_temp2->fastalg_avg) + "\t" + std::to_string(_temp2->fastalg_max) + "\t"+ std::to_string(_temp2->fastalg_SAD);
LogFile.WriteToDedicatedFile("/sdcard/alignment.txt", zw);
#endif
#endif*/
CRotateImage rt(this, ImageTMP);
rt.Translate(dx, dy);
rt.Rotate(d_winkel, _temp1->target_x, _temp1->target_y);
printf("Alignment: dx %d - dy %d - rot %f\n", dx, dy, d_winkel);
ESP_LOGD(TAG, "Alignment: dx %d - dy %d - rot %f", dx, dy, d_winkel);
return (isSimilar1 && isSimilar2);
}
@@ -125,8 +123,12 @@ void CAlignAndCutImage::CutAndSave(std::string _template1, int x1, int y1, int d
p_target[_channels] = p_source[_channels];
}
// stbi_write_jpg(_template1.c_str(), dx, dy, channels, odata, 0);
#ifdef STBI_ONLY_JPEG
stbi_write_jpg(_template1.c_str(), dx, dy, channels, odata, 100);
#else
stbi_write_bmp(_template1.c_str(), dx, dy, channels, odata);
#endif
RGBImageRelease();
@@ -147,7 +149,7 @@ void CAlignAndCutImage::CutAndSave(int x1, int y1, int dx, int dy, CImageBasis *
if ((_target->height != dy) || (_target->width != dx) || (_target->channels != channels))
{
printf("CAlignAndCutImage::CutAndSave - Image size does not match !!");
ESP_LOGD(TAG, "CAlignAndCutImage::CutAndSave - Image size does not match!");
return;
}

View File

@@ -1,3 +1,8 @@
#pragma once
#ifndef CALIGNANDCUTIMAGE_H
#define CALIGNANDCUTIMAGE_H
#include "CImageBasis.h"
#include "CFindTemplate.h"
@@ -19,3 +24,4 @@ class CAlignAndCutImage : public CImageBasis
void GetRefSize(int *ref_dx, int *ref_dy);
};
#endif //CALIGNANDCUTIMAGE_H

View File

@@ -1,15 +1,33 @@
#include "CFindTemplate.h"
#include "ClassLogFile.h"
#include "Helper.h"
#include "../../include/defines.h"
#include <esp_log.h>
static const char* TAG = "C FIND TEMPL";
// #define DEBUG_DETAIL_ON
bool CFindTemplate::FindTemplate(RefInfo *_ref)
{
uint8_t* rgb_template = stbi_load(_ref->image_file.c_str(), &tpl_width, &tpl_height, &tpl_bpp, channels);
uint8_t* rgb_template;
// printf("FindTemplate 01\n");
if (file_size(_ref->image_file.c_str()) == 0) {
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, _ref->image_file + " is empty!");
return false;
}
rgb_template = stbi_load(_ref->image_file.c_str(), &tpl_width, &tpl_height, &tpl_bpp, channels);
if (rgb_template == NULL) {
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Failed to load " + _ref->image_file + "! Is it corrupted?");
return false;
}
// ESP_LOGD(TAG, "FindTemplate 01");
int ow, ow_start, ow_stop;
int oh, oh_start, oh_stop;
@@ -45,32 +63,35 @@ bool CFindTemplate::FindTemplate(RefInfo *_ref)
int min, max;
bool isSimilar = false;
// printf("FindTemplate 02\n");
// ESP_LOGD(TAG, "FindTemplate 02");
if ((_ref->alignment_algo == 2) && (_ref->fastalg_x > -1) && (_ref->fastalg_y > -1)) // für Testzwecke immer Berechnen
{
isSimilar = CalculateSimularities(rgb_template, _ref->fastalg_x, _ref->fastalg_y, ow, oh, min, avg, max, SAD, _ref->fastalg_SAD, _ref->fastalg_SAD_criteria);
#ifdef DEBUG_DETAIL_ON
/*#ifdef DEBUG_DETAIL_ON
std::string zw = "\t" + _ref->image_file + "\tt1_x_y:\t" + std::to_string(_ref->fastalg_x) + "\t" + std::to_string(_ref->fastalg_y);
zw = zw + "\tpara1_found_min_avg_max_SAD:\t" + std::to_string(min) + "\t" + std::to_string(avg) + "\t" + std::to_string(max) + "\t"+ std::to_string(SAD);
LogFile.WriteToDedicatedFile("/sdcard/alignment.txt", zw);
#endif
#endif*/
}
// printf("FindTemplate 03\n");
// ESP_LOGD(TAG, "FindTemplate 03");
if (isSimilar)
{
#ifdef DEBUG_DETAIL_ON
LogFile.WriteToFile("Use FastAlignment sucessfull");
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Use FastAlignment sucessfull");
#endif
_ref->found_x = _ref->fastalg_x;
_ref->found_y = _ref->fastalg_y;
stbi_image_free(rgb_template);
return true;
}
// printf("FindTemplate 04\n");
// ESP_LOGD(TAG, "FindTemplate 04");
double aktSAD;
@@ -78,7 +99,7 @@ bool CFindTemplate::FindTemplate(RefInfo *_ref)
RGBImageLock();
// printf("FindTemplate 05\n");
// ESP_LOGD(TAG, "FindTemplate 05");
int xouter, youter, tpl_x, tpl_y, _ch;
int _anzchannels = channels;
if (_ref->alignment_algo == 0) // 0 = "Default" (nur R-Kanal)
@@ -106,14 +127,14 @@ bool CFindTemplate::FindTemplate(RefInfo *_ref)
}
}
// printf("FindTemplate 06\n");
// ESP_LOGD(TAG, "FindTemplate 06");
if (_ref->alignment_algo == 2)
CalculateSimularities(rgb_template, _ref->found_x, _ref->found_y, ow, oh, min, avg, max, SAD, _ref->fastalg_SAD, _ref->fastalg_SAD_criteria);
// printf("FindTemplate 07\n");
// ESP_LOGD(TAG, "FindTemplate 07");
_ref->fastalg_x = _ref->found_x;
_ref->fastalg_y = _ref->found_y;
@@ -123,16 +144,16 @@ bool CFindTemplate::FindTemplate(RefInfo *_ref)
_ref->fastalg_SAD = SAD;
#ifdef DEBUG_DETAIL_ON
/*#ifdef DEBUG_DETAIL_ON
std::string zw = "\t" + _ref->image_file + "\tt1_x_y:\t" + std::to_string(_ref->fastalg_x) + "\t" + std::to_string(_ref->fastalg_y);
zw = zw + "\tpara1_found_min_avg_max_SAD:\t" + std::to_string(min) + "\t" + std::to_string(avg) + "\t" + std::to_string(max) + "\t"+ std::to_string(SAD);
LogFile.WriteToDedicatedFile("/sdcard/alignment.txt", zw);
#endif
#endif*/
RGBImageRelease();
stbi_image_free(rgb_template);
// printf("FindTemplate 08\n");
// ESP_LOGD(TAG, "FindTemplate 08");
return false;
}
@@ -173,7 +194,7 @@ bool CFindTemplate::CalculateSimularities(uint8_t* _rgb_tmpl, int _startx, int _
float _SADdif = abs(SAD - _SADold);
printf("Anzahl %ld, avgDifSum %fd, avg %f, SAD_neu: %fd, _SAD_old: %f, _SAD_crit:%f\n", anz, avgDifSum, avg, SAD, _SADold, _SADdif);
ESP_LOGD(TAG, "Anzahl %ld, avgDifSum %fd, avg %f, SAD_neu: %fd, _SAD_old: %f, _SAD_crit:%f", anz, avgDifSum, avg, SAD, _SADold, _SADdif);
if (_SADdif <= _SADcrit)
return true;

View File

@@ -1,5 +1,7 @@
#ifndef __CFINDTEMPLATE_CLASS
#define __CFINDTEMPLATE_CLASS
#pragma once
#ifndef CFINDTEMPLATE_H
#define CFINDTEMPLATE_H
#include "CImageBasis.h"
@@ -37,4 +39,4 @@ class CFindTemplate : public CImageBasis
bool CalculateSimularities(uint8_t* _rgb_tmpl, int _startx, int _starty, int _sizex, int _sizey, int &min, float &avg, int &max, float &SAD, float _SADold, float _SADcrit);
};
#endif
#endif //CFINDTEMPLATE_H

View File

@@ -4,33 +4,30 @@
#include "server_ota.h"
#include <esp_log.h>
#include "../../include/defines.h"
#include "esp_system.h"
#include <cstring>
#define _USE_MATH_DEFINES
#include <math.h>
#include <algorithm>
#define _ESP32_PSRAM
using namespace std;
static const char *TAG = "CImageBasis";
//#define DEBUG_DETAIL_ON
static const char *TAG = "C IMG BASIS";
//#define DEBUG_DETAIL_ON
uint8_t * CImageBasis::RGBImageLock(int _waitmaxsec)
{
if (islocked)
{
#ifdef DEBUG_DETAIL_ON
printf("Image is locked: sleep for : %ds\n", _waitmaxsec);
#endif
#ifdef DEBUG_DETAIL_ON
ESP_LOGD(TAG, "Image is locked: sleep for: %ds", _waitmaxsec);
#endif
TickType_t xDelay;
xDelay = 1000 / portTICK_PERIOD_MS;
for (int i = 0; i <= _waitmaxsec; ++i)
@@ -47,21 +44,22 @@ uint8_t * CImageBasis::RGBImageLock(int _waitmaxsec)
return rgb_image;
}
void CImageBasis::RGBImageRelease()
{
islocked = false;
}
uint8_t * CImageBasis::RGBImageGet()
{
return rgb_image;
}
void writejpghelp(void *context, void *data, int size)
{
// printf("Size all: %d, size %d\n", ((ImageData*)context)->size, size);
// ESP_LOGD(TAG, "Size all: %d, size %d", ((ImageData*)context)->size, size);
ImageData* _zw = (ImageData*) context;
uint8_t *voidstart = _zw->data;
uint8_t *datastart = (uint8_t*) data;
@@ -74,8 +72,6 @@ void writejpghelp(void *context, void *data, int size)
}
ImageData* CImageBasis::writeToMemoryAsJPG(const int quality)
{
ImageData* ii = new ImageData;
@@ -87,7 +83,19 @@ ImageData* CImageBasis::writeToMemoryAsJPG(const int quality)
return ii;
}
#define HTTP_BUFFER_SENT 1024
void CImageBasis::writeToMemoryAsJPG(ImageData* i, const int quality)
{
ImageData* ii = new ImageData;
RGBImageLock();
stbi_write_jpg_to_func(writejpghelp, ii, width, height, channels, rgb_image, quality);
RGBImageRelease();
memCopy((uint8_t*) ii, (uint8_t*) i, sizeof(ImageData));
delete ii;
}
struct SendJPGHTTP
{
@@ -97,13 +105,13 @@ struct SendJPGHTTP
int size = 0;
};
inline void writejpgtohttphelp(void *context, void *data, int size)
{
SendJPGHTTP* _send = (SendJPGHTTP*) context;
if ((_send->size + size) >= HTTP_BUFFER_SENT) // data passt nich mehr in buffer
if ((_send->size + size) >= HTTP_BUFFER_SENT) // data no longer fits in buffer
{
httpd_req_t *_req = _send->req;
if (httpd_resp_send_chunk(_req, _send->buf, _send->size) != ESP_OK)
if (httpd_resp_send_chunk(_send->req, _send->buf, _send->size) != ESP_OK)
{
ESP_LOGE(TAG, "File sending failed!");
_send->res = ESP_FAIL;
@@ -115,7 +123,6 @@ inline void writejpgtohttphelp(void *context, void *data, int size)
}
esp_err_t CImageBasis::SendJPGtoHTTP(httpd_req_t *_req, const int quality)
{
SendJPGHTTP ii;
@@ -125,28 +132,28 @@ esp_err_t CImageBasis::SendJPGtoHTTP(httpd_req_t *_req, const int quality)
RGBImageLock();
stbi_write_jpg_to_func(writejpgtohttphelp, &ii, width, height, channels, rgb_image, quality);
RGBImageRelease();
if (ii.size > 0)
{
if (httpd_resp_send_chunk(_req, (char*) ii.buf, ii.size) != ESP_OK) // verschicke noch den Rest
if (httpd_resp_send_chunk(_req, (char*) ii.buf, ii.size) != ESP_OK) //still send the rest
{
ESP_LOGE(TAG, "File sending failed!");
ii.res = ESP_FAIL;
}
}
RGBImageRelease();
return ii.res;
}
bool CImageBasis::CopyFromMemory(uint8_t* _source, int _size)
{
int gr = height * width * channels;
if (gr != _size) // Größe passt nicht
if (gr != _size) // Size does not fit
{
printf("Cannot copy image from memory - sizes do not match: should be %d, but is %d\n", _size, gr);
ESP_LOGE(TAG, "Cannot copy image from memory - sizes do not match: should be %d, but is %d", _size, gr);
return false;
}
@@ -157,6 +164,7 @@ bool CImageBasis::CopyFromMemory(uint8_t* _source, int _size)
return true;
}
uint8_t CImageBasis::GetPixelColor(int x, int y, int ch)
{
stbi_uc* p_source;
@@ -175,6 +183,7 @@ void CImageBasis::memCopy(uint8_t* _source, uint8_t* _target, int _size)
#endif
}
bool CImageBasis::isInImage(int x, int y)
{
if ((x < 0) || (x > width - 1))
@@ -186,6 +195,7 @@ bool CImageBasis::isInImage(int x, int y)
return true;
}
void CImageBasis::setPixelColor(int x, int y, int r, int g, int b)
{
stbi_uc* p_source;
@@ -201,6 +211,7 @@ void CImageBasis::setPixelColor(int x, int y, int r, int g, int b)
RGBImageRelease();
}
void CImageBasis::drawRect(int x, int y, int dx, int dy, int r, int g, int b, int thickness)
{
int zwx1, zwx2, zwy1, zwy2;
@@ -210,6 +221,9 @@ void CImageBasis::drawRect(int x, int y, int dx, int dy, int r, int g, int b, in
zwx2 = x + dx + thickness - 1;
zwy1 = y;
zwy2 = y;
RGBImageLock();
for (_thick = 0; _thick < thickness; _thick++)
for (_x = zwx1; _x <= zwx2; ++_x)
for (_y = zwy1; _y <= zwy2; _y++)
@@ -246,14 +260,18 @@ void CImageBasis::drawRect(int x, int y, int dx, int dy, int r, int g, int b, in
if (isInImage(_x, _y))
setPixelColor(_x + _thick, _y, r, g, b);
RGBImageRelease();
}
void CImageBasis::drawLine(int x1, int y1, int x2, int y2, int r, int g, int b, int thickness)
{
int _x, _y, _thick;
int _zwy1, _zwy2;
thickness = (thickness-1) / 2;
RGBImageLock();
for (_thick = 0; _thick <= thickness; ++_thick)
for (_x = x1 - _thick; _x <= x2 + _thick; ++_x)
{
@@ -272,8 +290,11 @@ void CImageBasis::drawLine(int x1, int y1, int x2, int y2, int r, int g, int b,
if (isInImage(_x, _y))
setPixelColor(_x, _y, r, g, b);
}
RGBImageRelease();
}
void CImageBasis::drawEllipse(int x1, int y1, int radx, int rady, int r, int g, int b, int thickness)
{
float deltarad, aktrad;
@@ -285,6 +306,8 @@ void CImageBasis::drawEllipse(int x1, int y1, int radx, int rady, int r, int g,
deltarad = 1 / (4 * M_PI * (rad + thickness - 1));
RGBImageLock();
for (aktrad = 0; aktrad <= (2 * M_PI); aktrad += deltarad)
for (_thick = 0; _thick < thickness; ++_thick)
{
@@ -293,6 +316,8 @@ void CImageBasis::drawEllipse(int x1, int y1, int radx, int rady, int r, int g,
if (isInImage(_x, _y))
setPixelColor(_x, _y, r, g, b);
}
RGBImageRelease();
}
@@ -303,6 +328,8 @@ void CImageBasis::drawCircle(int x1, int y1, int rad, int r, int g, int b, int t
deltarad = 1 / (4 * M_PI * (rad + thickness - 1));
RGBImageLock();
for (aktrad = 0; aktrad <= (2 * M_PI); aktrad += deltarad)
for (_thick = 0; _thick < thickness; ++_thick)
{
@@ -311,8 +338,11 @@ void CImageBasis::drawCircle(int x1, int y1, int rad, int r, int g, int b, int t
if (isInImage(_x, _y))
setPixelColor(_x, _y, r, g, b);
}
RGBImageRelease();
}
CImageBasis::CImageBasis()
{
externalImage = false;
@@ -323,6 +353,7 @@ CImageBasis::CImageBasis()
islocked = false;
}
void CImageBasis::CreateEmptyImage(int _width, int _height, int _channels)
{
bpp = _channels;
@@ -332,10 +363,21 @@ void CImageBasis::CreateEmptyImage(int _width, int _height, int _channels)
RGBImageLock();
#ifdef DEBUG_DETAIL_ON
LogFile.WriteHeapInfo("CImageBasis::CreateEmptyImage");
#endif
int memsize = width * height * channels;
rgb_image = (unsigned char*)GET_MEMORY(memsize);
if (rgb_image == NULL)
{
//ESP_LOGE(TAG, "CImageBasis::CreateEmptyImage: No more free memory!! Needed: %d %d %d %d", width, height, channels, memsize);
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "CImageBasis::CreateEmptyImage: Can't allocate enough memory: " + std::to_string(memsize));
LogFile.WriteHeapInfo("CImageBasis::CreateEmptyImage");
RGBImageRelease();
return;
}
stbi_uc* p_source;
@@ -348,34 +390,55 @@ void CImageBasis::CreateEmptyImage(int _width, int _height, int _channels)
}
RGBImageRelease();
}
void CImageBasis::EmptyImage()
{
#ifdef DEBUG_DETAIL_ON
LogFile.WriteHeapInfo("CImageBasis::EmptyImage");
#endif
stbi_uc* p_source;
RGBImageLock();
for (int x = 0; x < width; ++x)
for (int y = 0; y < height; ++y)
{
p_source = rgb_image + (channels * (y * width + x));
for (int _channels = 0; _channels < channels; ++_channels)
p_source[_channels] = (uint8_t) 0;
}
RGBImageRelease();
}
void CImageBasis::LoadFromMemory(stbi_uc *_buffer, int len)
{
RGBImageLock();
if (rgb_image)
stbi_image_free(rgb_image);
rgb_image = stbi_load_from_memory(_buffer, len, &width, &height, &channels, 3);
bpp = channels;
printf("Image loaded from memory: %d, %d, %d\n", width, height, channels);
ESP_LOGD(TAG, "Image loaded from memory: %d, %d, %d", width, height, channels);
if ((width * height * channels) == 0)
{
ESP_LOGE(TAG, "Image with size 0 loaded --> reboot to be done! "
"Check that your camera module is working and connected properly.");
LogFile.SwitchOnOff(true);
LogFile.WriteToFile("Image with size 0 loaded --> reboot to be done! "
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Image with size 0 loaded --> reboot to be done! "
"Check that your camera module is working and connected properly.");
LogFile.WriteHeapInfo("CImageBasis::LoadFromMemory");
doReboot();
}
RGBImageRelease();
}
CImageBasis::CImageBasis(CImageBasis *_copyfrom, int _anzrepeat)
CImageBasis::CImageBasis(CImageBasis *_copyfrom)
{
islocked = false;
externalImage = false;
@@ -386,30 +449,30 @@ CImageBasis::CImageBasis(CImageBasis *_copyfrom, int _anzrepeat)
RGBImageLock();
#ifdef DEBUG_DETAIL_ON
LogFile.WriteHeapInfo("CImageBasis::CImageBasis_copyfrom - Start");
#endif
int memsize = width * height * channels;
rgb_image = (unsigned char*)GET_MEMORY(memsize);
int anz = 1;
while (!rgb_image && (anz < _anzrepeat))
if (rgb_image == NULL)
{
printf("Create Image from Copy - Memory is full - try again: %d.\n", anz);
rgb_image = (unsigned char*) malloc(memsize);
anz++;
}
if (!rgb_image)
{
printf(getESPHeapInfo().c_str());
printf("\nNo more free memory!! Needed: %d %d %d %d\n", width, height, channels, memsize);
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "CImageBasis::CImageBasis-Copyfrom: Can't allocate enough memory: " + std::to_string(memsize));
LogFile.WriteHeapInfo("CImageBasis::CImageBasis-Copyfrom");
RGBImageRelease();
return;
}
memCopy(_copyfrom->rgb_image, rgb_image, memsize);
RGBImageRelease();
#ifdef DEBUG_DETAIL_ON
LogFile.WriteHeapInfo("CImageBasis::CImageBasis_copyfrom - done");
#endif
}
CImageBasis::CImageBasis(int _width, int _height, int _channels)
{
islocked = false;
@@ -419,15 +482,28 @@ CImageBasis::CImageBasis(int _width, int _height, int _channels)
height = _height;
bpp = _channels;
int memsize = width * height * channels;
RGBImageLock();
#ifdef DEBUG_DETAIL_ON
LogFile.WriteHeapInfo("CImageBasis::CImageBasis_width,height,ch - Start");
#endif
int memsize = width * height * channels;
rgb_image = (unsigned char*)GET_MEMORY(memsize);
if (!rgb_image)
if (rgb_image == NULL)
{
printf(getESPHeapInfo().c_str());
printf("\nNo more free memory!! Needed: %d %d %d %d\n", width, height, channels, memsize);
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "CImageBasis::CImageBasis-width,height,ch: Can't allocate enough memory: " + std::to_string(memsize));
LogFile.WriteHeapInfo("CImageBasis::CImageBasis-width,height,ch");
RGBImageRelease();
return;
}
RGBImageRelease();
#ifdef DEBUG_DETAIL_ON
LogFile.WriteHeapInfo("CImageBasis::CImageBasis_width,height,ch - done");
#endif
}
@@ -437,29 +513,46 @@ CImageBasis::CImageBasis(std::string _image)
channels = 3;
externalImage = false;
filename = _image;
long zwld = esp_get_free_heap_size();
printf("freeheapsize before: %ld\n", zwld);
if (file_size(_image.c_str()) == 0) {
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, _image + " is empty!");
return;
}
RGBImageLock();
#ifdef DEBUG_DETAIL_ON
LogFile.WriteHeapInfo("CImageBasis::CImageBasis_image - Start");
#endif
rgb_image = stbi_load(_image.c_str(), &width, &height, &bpp, channels);
if (rgb_image == NULL) {
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "CImageBasis::CImageBasis-image: Failed to load " + _image + "! Is it corrupted?");
LogFile.WriteHeapInfo("CImageBasis::CImageBasis-image");
RGBImageRelease();
return;
}
RGBImageRelease();
zwld = esp_get_free_heap_size();
printf("freeheapsize after : %ld\n", zwld);
std::string zw = "Image Load failed:" + _image + "\n";
if (rgb_image == NULL)
printf(zw.c_str());
zw = "CImageBasis after load " + _image + "\n";
printf(zw.c_str());
printf("w %d, h %d, b %d, c %d\n", width, height, bpp, channels);
#ifdef DEBUG_DETAIL_ON
std::string zw = "CImageBasis after load " + _image;
ESP_LOGD(TAG, "%s", zw.c_str());
ESP_LOGD(TAG, "w %d, h %d, b %d, c %d", width, height, bpp, channels);
#endif
#ifdef DEBUG_DETAIL_ON
LogFile.WriteHeapInfo("CImageBasis::CImageBasis_image - done");
#endif
}
bool CImageBasis::ImageOkay(){
return rgb_image != NULL;
}
CImageBasis::CImageBasis(uint8_t* _rgb_image, int _channels, int _width, int _height, int _bpp)
{
islocked = false;
@@ -471,6 +564,7 @@ CImageBasis::CImageBasis(uint8_t* _rgb_image, int _channels, int _width, int _he
externalImage = true;
}
void CImageBasis::Contrast(float _contrast) //input range [-100..100]
{
stbi_uc* p_source;
@@ -492,28 +586,35 @@ void CImageBasis::Contrast(float _contrast) //input range [-100..100]
RGBImageRelease();
}
CImageBasis::~CImageBasis()
{
RGBImageLock();
if (!externalImage)
stbi_image_free(rgb_image);
RGBImageRelease();
}
void CImageBasis::SaveToFile(std::string _imageout)
{
string typ = getFileType(_imageout);
RGBImageLock();
if ((typ == "jpg") || (typ == "JPG")) // ACHTUNG PROBLEMATISCH IM ESP32
if ((typ == "jpg") || (typ == "JPG")) // CAUTION PROBLEMATIC IN ESP32
{
stbi_write_jpg(_imageout.c_str(), width, height, channels, rgb_image, 0);
}
#ifndef STBI_ONLY_JPEG
if ((typ == "bmp") || (typ == "BMP"))
{
stbi_write_bmp(_imageout.c_str(), width, height, channels, rgb_image);
}
#endif
RGBImageRelease();
}
@@ -525,25 +626,24 @@ void CImageBasis::Resize(int _new_dx, int _new_dy)
RGBImageLock();
stbir_resize_uint8(rgb_image, width, height, 0, odata, _new_dx, _new_dy, 0, channels);
stbi_image_free(rgb_image);
rgb_image = (unsigned char*)GET_MEMORY(memsize);
memCopy(odata, rgb_image, memsize);
RGBImageRelease();
width = _new_dx;
height = _new_dy;
stbi_image_free(odata);
RGBImageRelease();
}
void CImageBasis::Resize(int _new_dx, int _new_dy, CImageBasis *_target)
{
if ((_target->height != _new_dy) || (_target->width != _new_dx) || (_target->channels != channels))
{
printf("CImageBasis::Resize - Target image size does not fit !!");
ESP_LOGE(TAG, "CImageBasis::Resize - Target image size does not fit!");
return;
}
@@ -551,6 +651,7 @@ void CImageBasis::Resize(int _new_dx, int _new_dy, CImageBasis *_target)
uint8_t* odata = _target->rgb_image;
stbir_resize_uint8(rgb_image, width, height, 0, odata, _new_dx, _new_dy, 0, channels);
RGBImageRelease();
}

View File

@@ -1,13 +1,14 @@
#pragma once
#ifndef __CIMAGEBASIS
#define __CIMAGEBASIS
#ifndef CIMAGEBASIS_H
#define CIMAGEBASIS_H
#include <stdint.h>
#include <string>
#include <esp_http_server.h>
#define _USE_MATH_DEFINES
#include "../../include/defines.h"
#include <math.h>
#include "stb_image.h"
@@ -16,13 +17,6 @@
#include "esp_heap_caps.h"
//#define GET_MEMORY malloc
#define GET_MEMORY(X) heap_caps_malloc(X, MALLOC_CAP_SPIRAM)
#define MAX_JPG_SIZE 128000
struct ImageData
{
uint8_t data[MAX_JPG_SIZE];
@@ -67,20 +61,22 @@ class CImageBasis
void SetIndepended(){externalImage = false;};
void CreateEmptyImage(int _width, int _height, int _channels);
void EmptyImage();
CImageBasis();
CImageBasis(std::string _image);
CImageBasis(uint8_t* _rgb_image, int _channels, int _width, int _height, int _bpp);
CImageBasis(int _width, int _height, int _channels);
CImageBasis(CImageBasis *_copyfrom, int _anzrepeat = 0);
CImageBasis(CImageBasis *_copyfrom);
void Resize(int _new_dx, int _new_dy);
void Resize(int _new_dx, int _new_dy, CImageBasis *_target);
void LoadFromMemory(stbi_uc *_buffer, int len);
ImageData* writeToMemoryAsJPG(const int quality = 90);
ImageData* writeToMemoryAsJPG(const int quality = 90);
void writeToMemoryAsJPG(ImageData* ii, const int quality = 90);
esp_err_t SendJPGtoHTTP(httpd_req_t *req, const int quality = 90);
@@ -92,5 +88,5 @@ class CImageBasis
};
#endif
#endif //CIMAGEBASIS_H

View File

@@ -280,13 +280,13 @@ void CRotateImage::RotateAntiAliasing(float _angle, int _centerx, int _centery)
void CRotateImage::Rotate(float _angle)
{
// printf("width %d, height %d\n", width, height);
// ESP_LOGD(TAG, "width %d, height %d", width, height);
Rotate(_angle, width / 2, height / 2);
}
void CRotateImage::RotateAntiAliasing(float _angle)
{
// printf("width %d, height %d\n", width, height);
// ESP_LOGD(TAG, "width %d, height %d", width, height);
RotateAntiAliasing(_angle, width / 2, height / 2);
}

View File

@@ -1,3 +1,8 @@
#pragma once
#ifndef CROTATEIMAGE_H
#define CROTATEIMAGE_H
#include "CImageBasis.h"
@@ -19,3 +24,5 @@ class CRotateImage: public CImageBasis
void Translate(int _dx, int _dy);
void Mirror();
};
#endif //CROTATEIMAGE_H

View File

@@ -1,6 +1,8 @@
#include <stdint.h>
#include <string>
#include "../../include/defines.h"
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"

View File

@@ -1,14 +1,14 @@
#ifdef ENABLE_INFLUXDB
#include "interface_influxdb.h"
//#define LOG_LOCAL_LEVEL ESP_LOG_DEBUG
#include "esp_log.h"
#include <time.h>
#include "ClassLogFile.h"
#include "esp_http_client.h"
#include "../../include/defines.h"
#define MAX_HTTP_OUTPUT_BUFFER 2048
static const char *TAG_INTERFACEINFLUXDB = "interface_influxdb";
static const char *TAG = "INFLUXDB";
std::string _influxDBURI;
std::string _influxDBDatabase;
@@ -21,25 +21,25 @@ static esp_err_t http_event_handler(esp_http_client_event_t *evt)
switch(evt->event_id)
{
case HTTP_EVENT_ERROR:
ESP_LOGE(TAG_INTERFACEINFLUXDB, "HTTP Client Error encountered");
ESP_LOGE(TAG, "HTTP Client Error encountered");
break;
case HTTP_EVENT_ON_CONNECTED:
ESP_LOGI(TAG_INTERFACEINFLUXDB, "HTTP Client Connected");
ESP_LOGI(TAG, "HTTP Client Connected");
break;
case HTTP_EVENT_HEADERS_SENT:
ESP_LOGV(TAG_INTERFACEINFLUXDB, "HTTP Client sent all request headers");
ESP_LOGV(TAG, "HTTP Client sent all request headers");
break;
case HTTP_EVENT_ON_HEADER:
ESP_LOGV(TAG_INTERFACEINFLUXDB, "Header: key=%s, value=%s", evt->header_key, evt->header_value);
ESP_LOGV(TAG, "Header: key=%s, value=%s", evt->header_key, evt->header_value);
break;
case HTTP_EVENT_ON_DATA:
ESP_LOGV(TAG_INTERFACEINFLUXDB, "HTTP Client data recevied: len=%d", evt->data_len);
ESP_LOGV(TAG, "HTTP Client data recevied: len=%d", evt->data_len);
break;
case HTTP_EVENT_ON_FINISH:
ESP_LOGI(TAG_INTERFACEINFLUXDB, "HTTP Client finished");
ESP_LOGI(TAG, "HTTP Client finished");
break;
case HTTP_EVENT_DISCONNECTED:
ESP_LOGI(TAG_INTERFACEINFLUXDB, "HTTP Client Disconnected");
ESP_LOGI(TAG, "HTTP Client Disconnected");
break;
}
return ESP_OK;
@@ -69,31 +69,31 @@ void InfluxDBPublish(std::string _key, std::string _content, std::string _timest
std::string payload = _influxDBMeasurement + " " + _key + "=" + _content + " " + nowTimestamp;
payload.shrink_to_fit();
ESP_LOGI(TAG_INTERFACEINFLUXDB, "sending line to influxdb: %s\n", payload.c_str());
ESP_LOGI(TAG, "sending line to influxdb: %s\n", payload.c_str());
// use the default retention policy of the database
std::string apiURI = _influxDBURI + "/api/v2/write?bucket=" + _influxDBDatabase + "/";
apiURI.shrink_to_fit();
http_config.url = apiURI.c_str();
ESP_LOGI(TAG_INTERFACEINFLUXDB, "API URI: %s", apiURI.c_str());
ESP_LOGI(TAG, "API URI: %s", apiURI.c_str());
esp_http_client_handle_t http_client = esp_http_client_init(&http_config);
ESP_LOGI(TAG_INTERFACEINFLUXDB, "client is initialized%s\n", "");
ESP_LOGI(TAG, "client is initialized%s\n", "");
esp_http_client_set_header(http_client, "Content-Type", "text/plain");
ESP_LOGI(TAG_INTERFACEINFLUXDB, "header is set%s\n", "");
ESP_LOGI(TAG, "header is set%s\n", "");
ESP_ERROR_CHECK(esp_http_client_set_post_field(http_client, payload.c_str(), payload.length()));
ESP_LOGI(TAG_INTERFACEINFLUXDB, "post payload is set%s\n", "");
ESP_LOGI(TAG, "post payload is set%s\n", "");
esp_err_t err = ESP_ERROR_CHECK_WITHOUT_ABORT(esp_http_client_perform(http_client));
if( err == ESP_OK ) {
ESP_LOGI(TAG_INTERFACEINFLUXDB, "HTTP request was performed%s\n", "");
ESP_LOGI(TAG, "HTTP request was performed%s\n", "");
int status_code = esp_http_client_get_status_code(http_client);
ESP_LOGI(TAG_INTERFACEINFLUXDB, "HTTP status code %d\n", status_code);
ESP_LOGI(TAG, "HTTP status code %d\n", status_code);
} else {
ESP_LOGW(TAG_INTERFACEINFLUXDB, "HTTP request failed%s\n", "");
ESP_LOGW(TAG, "HTTP request failed%s\n", "");
}
esp_http_client_cleanup(http_client);
}
@@ -111,4 +111,4 @@ void InfluxDBInit(std::string _uri, std::string _database, std::string _measurem
void InfluxDBdestroy() {
}
#endif //ENABLE_INFLUXDB

View File

@@ -1,3 +1,6 @@
#ifdef ENABLE_INFLUXDB
#pragma once
#ifndef INTERFACE_INFLUXDB_H
#define INTERFACE_INFLUXDB_H
@@ -11,3 +14,4 @@ void InfluxDBdestroy();
void InfluxDBPublish(std::string _key, std::string _content, std::string _timestamp);
#endif //INTERFACE_INFLUXDB_H
#endif //ENABLE_INFLUXDB

View File

@@ -1,8 +1,10 @@
#include "ClassLogFile.h"
#include "time_sntp.h"
#include "esp_log.h"
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <algorithm>
#ifdef __cplusplus
extern "C" {
@@ -13,111 +15,25 @@ extern "C" {
#endif
#include "Helper.h"
#include "../../include/defines.h"
static const char *TAG = "log";
static const char *TAG = "LOGFILE";
ClassLogFile LogFile("/sdcard/log/message", "log_%Y-%m-%d.txt", "/sdcard/log/data", "data_%Y-%m-%d.csv");
ClassLogFile LogFile("/sdcard/log/message", "log_%Y-%m-%d.txt");
void ClassLogFile::WriteHeapInfo(std::string _id)
{
std::string _zw = "\t" + _id;
if (loglevel > 0)
_zw = _zw + "\t" + getESPHeapInfo();
WriteToFile(_zw);
if (loglevel >= ESP_LOG_DEBUG) {
std::string _zw = _id + "\t" + getESPHeapInfo();
WriteToFile(ESP_LOG_DEBUG, "HEAP", _zw);
}
}
std::string ClassLogFile::getESPHeapInfo(){
string espInfoResultStr = "";
char aMsgBuf[80];
multi_heap_info_t aMultiHead_info ;
heap_caps_get_info (&aMultiHead_info,MALLOC_CAP_8BIT);
size_t aFreeHeapSize = heap_caps_get_free_size(MALLOC_CAP_8BIT);
size_t aMinFreeHeadSize = heap_caps_get_minimum_free_size(MALLOC_CAP_8BIT);
size_t aMinFreeHeapSize = heap_caps_get_minimum_free_size(MALLOC_CAP_8BIT);
size_t aHeapLargestFreeBlockSize = heap_caps_get_largest_free_block(MALLOC_CAP_8BIT);
sprintf(aMsgBuf,"Free Heap Size: \t%ld", (long) aFreeHeapSize);
size_t aFreeSPIHeapSize = heap_caps_get_free_size(MALLOC_CAP_8BIT| MALLOC_CAP_SPIRAM);
size_t aFreeInternalHeapSize = heap_caps_get_free_size(MALLOC_CAP_8BIT| MALLOC_CAP_INTERNAL);
size_t aMinFreeInternalHeapSize = heap_caps_get_minimum_free_size(MALLOC_CAP_8BIT| MALLOC_CAP_INTERNAL);
sprintf(aMsgBuf,"\tHeap:\t%ld", (long) aFreeHeapSize);
espInfoResultStr += string(aMsgBuf);
sprintf(aMsgBuf,"\tMin Free:\t%ld", (long) aMinFreeHeapSize);
espInfoResultStr += string(aMsgBuf);
sprintf(aMsgBuf,"\tlarg. Block: \t%ld", (long) aHeapLargestFreeBlockSize);
espInfoResultStr += string(aMsgBuf);
sprintf(aMsgBuf,"\tSPI Heap:\t%ld", (long) aFreeSPIHeapSize);
espInfoResultStr += string(aMsgBuf);
sprintf(aMsgBuf,"\tMin Free Heap Size:\t%ld", (long) aMinFreeHeadSize);
sprintf(aMsgBuf,"\tNOT_SPI Heap:\t%ld", (long) (aFreeHeapSize - aFreeSPIHeapSize));
espInfoResultStr += string(aMsgBuf);
sprintf(aMsgBuf,"\tlargest Block Size: \t%ld", (long) aHeapLargestFreeBlockSize);
sprintf(aMsgBuf,"\tInternal Heap:\t%ld", (long) (aFreeInternalHeapSize));
espInfoResultStr += string(aMsgBuf);
sprintf(aMsgBuf,"\tInternal Min Heap free:\t%ld", (long) (aMinFreeInternalHeapSize));
espInfoResultStr += string(aMsgBuf);
return espInfoResultStr;
}
void ClassLogFile::WriteToDedicatedFile(std::string _fn, std::string info, bool _time)
void ClassLogFile::WriteToData(std::string _timestamp, std::string _name, std::string _ReturnRawValue, std::string _ReturnValue, std::string _ReturnPreValue, std::string _ReturnRateValue, std::string _ReturnChangeAbsolute, std::string _ErrorMessageText, std::string _digital, std::string _analog)
{
FILE* pFile;
std::string zwtime;
if (!doLogFile){
return;
}
// pFile = OpenFileAndWait(_fn.c_str(), "a");
pFile = fopen(_fn.c_str(), "a+");
// printf("Logfile opened: %s\n", _fn.c_str());
if (pFile!=NULL) {
if (_time)
{
time_t rawtime;
struct tm* timeinfo;
char buffer[80];
time(&rawtime);
timeinfo = localtime(&rawtime);
strftime(buffer, 80, "%Y-%m-%dT%H:%M:%S", timeinfo);
zwtime = std::string(buffer);
info = zwtime + ": " + info;
}
fputs(info.c_str(), pFile);
fputs("\n", pFile);
fclose(pFile);
} else {
ESP_LOGI(TAG, "Can't open log file %s", _fn.c_str());
}
}
void ClassLogFile::SwitchOnOff(bool _doLogFile){
doLogFile = _doLogFile;
};
void ClassLogFile::SetRetention(unsigned short _retentionInDays){
retentionInDays = _retentionInDays;
};
void ClassLogFile::WriteToFile(std::string info, bool _time)
{
/*
struct stat path_stat;
if (stat(logroot.c_str(), &path_stat) != 0) {
ESP_LOGI(TAG, "Create log folder: %s", logroot.c_str());
if (mkdir_r(logroot.c_str(), S_IRWXU) == -1) {
ESP_LOGI(TAG, "Can't create log folder");
}
}
*/
ESP_LOGD(TAG, "Start WriteToData");
time_t rawtime;
struct tm* timeinfo;
char buffer[30];
@@ -125,13 +41,232 @@ void ClassLogFile::WriteToFile(std::string info, bool _time)
time(&rawtime);
timeinfo = localtime(&rawtime);
strftime(buffer, 30, logfile.c_str(), timeinfo);
std::string logpath = logroot + "/" + buffer;
strftime(buffer, 30, datafile.c_str(), timeinfo);
std::string logpath = dataroot + "/" + buffer;
WriteToDedicatedFile(logpath, info, _time);
printf((info + "\n").c_str());
FILE* pFile;
std::string zwtime;
ESP_LOGD(TAG, "Datalogfile: %s", logpath.c_str());
pFile = fopen(logpath.c_str(), "a+");
if (pFile!=NULL) {
fputs(_timestamp.c_str(), pFile);
fputs(",", pFile);
fputs(_name.c_str(), pFile);
fputs(",", pFile);
fputs(_ReturnRawValue.c_str(), pFile);
fputs(",", pFile);
fputs(_ReturnValue.c_str(), pFile);
fputs(",", pFile);
fputs(_ReturnPreValue.c_str(), pFile);
fputs(",", pFile);
fputs(_ReturnRateValue.c_str(), pFile);
fputs(",", pFile);
fputs(_ReturnChangeAbsolute.c_str(), pFile);
fputs(",", pFile);
fputs(_ErrorMessageText.c_str(), pFile);
fputs(_digital.c_str(), pFile);
fputs(_analog.c_str(), pFile);
fputs("\n", pFile);
fclose(pFile);
} else {
ESP_LOGE(TAG, "Can't open data file %s", logpath.c_str());
}
}
void ClassLogFile::setLogLevel(esp_log_level_t _logLevel){
loglevel = _logLevel;
std::string levelText;
switch(_logLevel) {
case ESP_LOG_WARN:
levelText = "WARNING";
break;
case ESP_LOG_INFO:
levelText = "INFO";
break;
case ESP_LOG_DEBUG:
levelText = "DEBUG";
break;
case ESP_LOG_ERROR:
default:
levelText = "ERROR";
break;
}
ESP_LOGI(TAG, "Log Level set to %s", levelText.c_str());
/*
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Test");
LogFile.WriteToFile(ESP_LOG_WARN, TAG, "Test");
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Test");
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Test");
*/
}
void ClassLogFile::SetLogFileRetention(unsigned short _LogFileRetentionInDays){
logFileRetentionInDays = _LogFileRetentionInDays;
}
void ClassLogFile::SetDataLogRetention(unsigned short _DataLogRetentionInDays){
dataLogRetentionInDays = _DataLogRetentionInDays;
}
void ClassLogFile::SetDataLogToSD(bool _doDataLogToSD){
doDataLogToSD = _doDataLogToSD;
}
bool ClassLogFile::GetDataLogToSD(){
return doDataLogToSD;
}
static FILE* logFileAppendHandle = NULL;
std::string fileNameDate;
void ClassLogFile::WriteToFile(esp_log_level_t level, std::string tag, std::string message, bool _time)
{
time_t rawtime;
struct tm* timeinfo;
std::string fileNameDateNew;
std::string zwtime;
std::string ntpTime = "";
time(&rawtime);
timeinfo = localtime(&rawtime);
char buf[30];
strftime(buf, sizeof(buf), logfile.c_str(), timeinfo);
fileNameDateNew = std::string(buf);
std::replace(message.begin(), message.end(), '\n', ' '); // Replace all newline characters
if (tag != "") {
ESP_LOG_LEVEL(level, tag.c_str(), "%s", message.c_str());
message = "[" + tag + "] " + message;
}
else {
ESP_LOG_LEVEL(level, "", "%s", message.c_str());
}
if (level > loglevel) {// Only write to file if loglevel is below threshold
return;
}
if (_time)
{
char logLineDate[30];
strftime(logLineDate, sizeof(logLineDate), "%Y-%m-%dT%H:%M:%S", timeinfo);
ntpTime = std::string(logLineDate);
}
std::string loglevelString;
switch(level) {
case ESP_LOG_ERROR:
loglevelString = "ERR";
break;
case ESP_LOG_WARN:
loglevelString = "WRN";
break;
case ESP_LOG_INFO:
loglevelString = "INF";
break;
case ESP_LOG_DEBUG:
loglevelString = "DBG";
break;
case ESP_LOG_VERBOSE:
loglevelString = "VER";
break;
case ESP_LOG_NONE:
default:
loglevelString = "NONE";
break;
}
std::string formatedUptime = getFormatedUptime(true);
std::string fullmessage = "[" + formatedUptime + "] " + ntpTime + "\t<" + loglevelString + ">\t" + message + "\n";
#ifdef KEEP_LOGFILE_OPEN_FOR_APPENDING
if (fileNameDateNew != fileNameDate) { // Filename changed
// Make sure each day gets its own logfile
// Also we need to re-open it in case it needed to get closed for reading
std::string logpath = logroot + "/" + fileNameDateNew;
ESP_LOGI(TAG, "Opening logfile %s for appending", logpath.c_str());
logFileAppendHandle = fopen(logpath.c_str(), "a+");
if (logFileAppendHandle==NULL) {
ESP_LOGE(TAG, "Can't open log file %s", logpath.c_str());
return;
}
fileNameDate = fileNameDateNew;
}
#else
std::string logpath = logroot + "/" + fileNameDateNew;
logFileAppendHandle = fopen(logpath.c_str(), "a+");
if (logFileAppendHandle==NULL) {
ESP_LOGE(TAG, "Can't open log file %s", logpath.c_str());
return;
}
#endif
fputs(fullmessage.c_str(), logFileAppendHandle);
#ifdef KEEP_LOGFILE_OPEN_FOR_APPENDING
fflush(logFileAppendHandle);
fsync(fileno(logFileAppendHandle));
#else
CloseLogFileAppendHandle();
#endif
}
void ClassLogFile::CloseLogFileAppendHandle() {
if (logFileAppendHandle != NULL) {
fclose(logFileAppendHandle);
logFileAppendHandle = NULL;
fileNameDate = "";
}
}
void ClassLogFile::WriteToFile(esp_log_level_t level, std::string tag, std::string message) {
LogFile.WriteToFile(level, tag, message, true);
}
std::string ClassLogFile::GetCurrentFileNameData()
{
time_t rawtime;
struct tm* timeinfo;
char buffer[60];
time(&rawtime);
timeinfo = localtime(&rawtime);
strftime(buffer, 60, datafile.c_str(), timeinfo);
std::string logpath = dataroot + "/" + buffer;
return logpath;
}
std::string ClassLogFile::GetCurrentFileName()
{
time_t rawtime;
@@ -147,26 +282,31 @@ std::string ClassLogFile::GetCurrentFileName()
return logpath;
}
void ClassLogFile::RemoveOld()
void ClassLogFile::RemoveOldLogFile()
{
if (retentionInDays == 0) {
if (logFileRetentionInDays == 0) {
return;
}
ESP_LOGD(TAG, "Remove old log files");
time_t rawtime;
struct tm* timeinfo;
char cmpfilename[30];
time(&rawtime);
rawtime = addDays(rawtime, -retentionInDays);
rawtime = addDays(rawtime, -logFileRetentionInDays + 1);
timeinfo = localtime(&rawtime);
//ESP_LOGD(TAG, "logFileRetentionInDays: %d", logFileRetentionInDays);
strftime(cmpfilename, 30, logfile.c_str(), timeinfo);
//ESP_LOGE(TAG, "log file name to compare: %s", cmpfilename);
//ESP_LOGD(TAG, "log file name to compare: %s", cmpfilename);
DIR *dir = opendir(logroot.c_str());
if (!dir) {
ESP_LOGI(TAG, "Failed to stat dir : %s", logroot.c_str());
ESP_LOGE(TAG, "Failed to stat dir: %s", logroot.c_str());
return;
}
@@ -175,29 +315,96 @@ void ClassLogFile::RemoveOld()
int notDeleted = 0;
while ((entry = readdir(dir)) != NULL) {
if (entry->d_type == DT_REG) {
//ESP_LOGI(TAG, "list log file : %s %s", entry->d_name, cmpfilename);
//ESP_LOGD(TAG, "compare log file: %s to %s", entry->d_name, cmpfilename);
if ((strlen(entry->d_name) == strlen(cmpfilename)) && (strcmp(entry->d_name, cmpfilename) < 0)) {
ESP_LOGI(TAG, "delete log file : %s", entry->d_name);
//ESP_LOGD(TAG, "delete log file: %s", entry->d_name);
std::string filepath = logroot + "/" + entry->d_name;
if (unlink(filepath.c_str()) == 0) {
deleted ++;
} else {
ESP_LOGE(TAG, "can't delete file : %s", entry->d_name);
ESP_LOGE(TAG, "can't delete file: %s", entry->d_name);
notDeleted ++;
}
} else {
notDeleted ++;
}
}
}
ESP_LOGI(TAG, "%d older log files deleted. %d current log files not deleted.", deleted, notDeleted);
ESP_LOGD(TAG, "log files deleted: %d | files not deleted (incl. leer.txt): %d", deleted, notDeleted);
closedir(dir);
}
ClassLogFile::ClassLogFile(std::string _logroot, std::string _logfile)
void ClassLogFile::RemoveOldDataLog()
{
if (dataLogRetentionInDays == 0 || !doDataLogToSD) {
return;
}
ESP_LOGD(TAG, "Remove old data files");
time_t rawtime;
struct tm* timeinfo;
char cmpfilename[30];
time(&rawtime);
rawtime = addDays(rawtime, -dataLogRetentionInDays + 1);
timeinfo = localtime(&rawtime);
//ESP_LOGD(TAG, "dataLogRetentionInDays: %d", dataLogRetentionInDays);
strftime(cmpfilename, 30, datafile.c_str(), timeinfo);
//ESP_LOGD(TAG, "data file name to compare: %s", cmpfilename);
DIR *dir = opendir(dataroot.c_str());
if (!dir) {
ESP_LOGE(TAG, "Failed to stat dir: %s", dataroot.c_str());
return;
}
struct dirent *entry;
int deleted = 0;
int notDeleted = 0;
while ((entry = readdir(dir)) != NULL) {
if (entry->d_type == DT_REG) {
//ESP_LOGD(TAG, "Compare data file: %s to %s", entry->d_name, cmpfilename);
if ((strlen(entry->d_name) == strlen(cmpfilename)) && (strcmp(entry->d_name, cmpfilename) < 0)) {
//ESP_LOGD(TAG, "delete data file: %s", entry->d_name);
std::string filepath = dataroot + "/" + entry->d_name;
if (unlink(filepath.c_str()) == 0) {
deleted ++;
} else {
ESP_LOGE(TAG, "can't delete file: %s", entry->d_name);
notDeleted ++;
}
} else {
notDeleted ++;
}
}
}
ESP_LOGD(TAG, "data files deleted: %d | files not deleted (incl. leer.txt): %d", deleted, notDeleted);
closedir(dir);
}
void ClassLogFile::CreateLogDirectories()
{
MakeDir("/sdcard/log");
MakeDir("/sdcard/log/data");
MakeDir("/sdcard/log/analog");
MakeDir("/sdcard/log/digit");
MakeDir("/sdcard/log/message");
MakeDir("/sdcard/log/source");
}
ClassLogFile::ClassLogFile(std::string _logroot, std::string _logfile, std::string _logdatapath, std::string _datafile)
{
logroot = _logroot;
logfile = _logfile;
doLogFile = true;
retentionInDays = 10;
loglevel = 0;
datafile = _datafile;
dataroot = _logdatapath;
logFileRetentionInDays = 3;
dataLogRetentionInDays = 3;
doDataLogToSD = true;
loglevel = ESP_LOG_INFO;
}

View File

@@ -1,5 +1,11 @@
#pragma once
#ifndef CLASSLOGFILE_H
#define CLASSLOGFILE_H
#include <string>
#include "esp_log.h"
class ClassLogFile
@@ -7,26 +13,40 @@ class ClassLogFile
private:
std::string logroot;
std::string logfile;
bool doLogFile;
unsigned short retentionInDays;
int loglevel;
std::string dataroot;
std::string datafile;
unsigned short logFileRetentionInDays;
unsigned short dataLogRetentionInDays;
bool doDataLogToSD;
esp_log_level_t loglevel;
public:
ClassLogFile(std::string _logpath, std::string _logfile);
std::string getESPHeapInfo();
void setLogLevel(int i){loglevel = i;};
ClassLogFile(std::string _logpath, std::string _logfile, std::string _logdatapath, std::string _datafile);
void WriteHeapInfo(std::string _id);
void SwitchOnOff(bool _doLogFile);
void SetRetention(unsigned short _retentionInDays);
void setLogLevel(esp_log_level_t _logLevel);
void SetLogFileRetention(unsigned short _LogFileRetentionInDays);
void SetDataLogRetention(unsigned short _DataLogRetentionInDays);
void SetDataLogToSD(bool _doDataLogToSD);
bool GetDataLogToSD();
void WriteToFile(esp_log_level_t level, std::string tag, std::string message, bool _time);
void WriteToFile(esp_log_level_t level, std::string tag, std::string message);
void CloseLogFileAppendHandle();
void CreateLogDirectories();
void RemoveOldLogFile();
void RemoveOldDataLog();
// void WriteToData(std::string _ReturnRawValue, std::string _ReturnValue, std::string _ReturnPreValue, std::string _ErrorMessageText, std::string _digital, std::string _analog);
void WriteToData(std::string _timestamp, std::string _name, std::string _ReturnRawValue, std::string _ReturnValue, std::string _ReturnPreValue, std::string _ReturnRateValue, std::string _ReturnChangeAbsolute, std::string _ErrorMessageText, std::string _digital, std::string _analog);
void WriteToFile(std::string info, bool _time = true);
void WriteToDedicatedFile(std::string _fn, std::string info, bool _time = true);
void RemoveOld();
std::string GetCurrentFileName();
std::string GetCurrentFileNameData();
};
extern ClassLogFile LogFile;
extern ClassLogFile LogFile;
#endif //CLASSLOGFILE_H

View File

@@ -2,6 +2,4 @@ FILE(GLOB_RECURSE app_sources ${CMAKE_CURRENT_SOURCE_DIR}/*.*)
idf_component_register(SRCS ${app_sources}
INCLUDE_DIRS "."
REQUIRES tflite-lib mqtt jomjol_logfile)
REQUIRES tflite-lib mqtt jomjol_tfliteclass jomjol_helper jomjol_mqtt jomjol_wlan)

View File

@@ -1,222 +1,353 @@
#ifdef ENABLE_MQTT
#include "interface_mqtt.h"
//#define LOG_LOCAL_LEVEL ESP_LOG_DEBUG
#include "esp_log.h"
#include "connect_wlan.h"
#include "mqtt_client.h"
#include "ClassLogFile.h"
#include "server_tflite.h"
#include "../../include/defines.h"
#define __HIDE_PASSWORD
static const char *TAG_INTERFACEMQTT = "interface_mqtt";
static const char *TAG = "MQTT IF";
std::map<std::string, std::function<void()>>* connectFunktionMap = NULL;
std::map<std::string, std::function<bool(std::string, char*, int)>>* subscribeFunktionMap = NULL;
bool debugdetail = true;
std::map<std::string, std::function<bool(std::string, char*, int)>>* subscribeFunktionMap = NULL;
// #define CONFIG_BROKER_URL "mqtt://192.168.178.43:1883"
esp_mqtt_event_id_t esp_mmqtt_ID = MQTT_EVENT_ANY;
int failedOnRound = -1;
esp_mqtt_event_id_t esp_mqtt_ID = MQTT_EVENT_ANY;
// ESP_EVENT_ANY_ID
bool mqtt_enabled = false;
bool mqtt_configOK = false;
bool mqtt_initialized = false;
bool mqtt_connected = false;
esp_mqtt_client_handle_t client = NULL;
bool MQTTPublish(std::string _key, std::string _content, int retained_flag){
int msg_id;
std::string zw;
msg_id = esp_mqtt_client_publish(client, _key.c_str(), _content.c_str(), 0, 1, retained_flag);
if (msg_id < 0) {
LogFile.WriteToFile("MQTT - Failed to publish '" + _key + "'!");
esp_mqtt_client_handle_t client = NULL;
std::string uri, client_id, lwt_topic, lwt_connected, lwt_disconnected, user, password, maintopic;
int keepalive, SetRetainFlag;
void (*callbackOnConnected)(std::string, int) = NULL;
bool MQTTPublish(std::string _key, std::string _content, int retained_flag)
{
if (!mqtt_enabled) { // MQTT sevice not started / configured (MQTT_Init not called before)
return false;
}
if (failedOnRound == getCountFlowRounds()) { // we already failed in this round, do not retry until the next round
return true; // Fail quietly
}
#ifdef DEBUG_DETAIL_ON
LogFile.WriteHeapInfo("MQTT Publish");
#endif
MQTT_Init(); // Re-Init client if not initialized yet/anymore
if (mqtt_initialized && mqtt_connected) {
#ifdef DEBUG_DETAIL_ON
long long int starttime = esp_timer_get_time();
#endif
int msg_id = esp_mqtt_client_publish(client, _key.c_str(), _content.c_str(), 0, 1, retained_flag);
#ifdef DEBUG_DETAIL_ON
ESP_LOGD(TAG, "Publish msg_id %d in %lld ms", msg_id, (esp_timer_get_time() - starttime)/1000);
#endif
if (msg_id == -1) {
LogFile.WriteToFile(ESP_LOG_WARN, TAG, "Failed to publish topic '" + _key + "', re-trying...");
#ifdef DEBUG_DETAIL_ON
starttime = esp_timer_get_time();
#endif
msg_id = esp_mqtt_client_publish(client, _key.c_str(), _content.c_str(), 0, 1, retained_flag);
#ifdef DEBUG_DETAIL_ON
ESP_LOGD(TAG, "Publish msg_id %d in %lld ms", msg_id, (esp_timer_get_time() - starttime)/1000);
#endif
if (msg_id == -1) {
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Failed to publish topic '" + _key + "', skipping all MQTT publishings in this round!");
failedOnRound = getCountFlowRounds();
return false;
}
}
if (_content.length() > 80) { // Truncate message if too long
_content.resize(80);
_content.append("..");
}
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Published topic: " + _key + ", content: " + _content + " (msg_id=" + std::to_string(msg_id) + ")");
return true;
}
else {
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Publish skipped. Client not initalized or not connected. (topic: " + _key + ")");
return false;
}
zw = "MQTT - sent publish successful in MQTTPublish, msg_id=" + std::to_string(msg_id) + ", " + _key + ", " + _content;
if (debugdetail) LogFile.WriteToFile(zw);
ESP_LOGD(TAG_INTERFACEMQTT, "sent publish successful in MQTTPublish, msg_id=%d, %s, %s", msg_id, _key.c_str(), _content.c_str());
return true;
}
static esp_err_t mqtt_event_handler_cb(esp_mqtt_event_handle_t event)
{
int msg_id;
static esp_err_t mqtt_event_handler_cb(esp_mqtt_event_handle_t event) {
std::string topic = "";
switch (event->event_id) {
case MQTT_EVENT_BEFORE_CONNECT:
ESP_LOGI(TAG_INTERFACEMQTT, "MQTT_EVENT_BEFORE_CONNECT");
ESP_LOGD(TAG, "MQTT_EVENT_BEFORE_CONNECT");
mqtt_initialized = true;
break;
case MQTT_EVENT_CONNECTED:
ESP_LOGI(TAG_INTERFACEMQTT, "MQTT_EVENT_CONNECTED");
ESP_LOGD(TAG, "MQTT_EVENT_CONNECTED");
mqtt_initialized = true;
mqtt_connected = true;
MQTTconnected();
break;
case MQTT_EVENT_DISCONNECTED:
ESP_LOGI(TAG_INTERFACEMQTT, "MQTT_EVENT_DISCONNECTED");
ESP_LOGD(TAG, "MQTT_EVENT_DISCONNECTED");
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Disconnected from broker");
mqtt_connected = false;
break;
case MQTT_EVENT_SUBSCRIBED:
ESP_LOGI(TAG_INTERFACEMQTT, "MQTT_EVENT_SUBSCRIBED, msg_id=%d", event->msg_id);
msg_id = esp_mqtt_client_publish(client, "/topic/qos0", "data", 0, 0, 0);
ESP_LOGI(TAG_INTERFACEMQTT, "sent publish successful, msg_id=%d", msg_id);
ESP_LOGD(TAG, "MQTT_EVENT_SUBSCRIBED, msg_id=%d", event->msg_id);
break;
case MQTT_EVENT_UNSUBSCRIBED:
ESP_LOGI(TAG_INTERFACEMQTT, "MQTT_EVENT_UNSUBSCRIBED, msg_id=%d", event->msg_id);
ESP_LOGD(TAG, "MQTT_EVENT_UNSUBSCRIBED, msg_id=%d", event->msg_id);
break;
case MQTT_EVENT_PUBLISHED:
ESP_LOGI(TAG_INTERFACEMQTT, "MQTT_EVENT_PUBLISHED, msg_id=%d", event->msg_id);
ESP_LOGD(TAG, "MQTT_EVENT_PUBLISHED, msg_id=%d", event->msg_id);
break;
case MQTT_EVENT_DATA:
ESP_LOGI(TAG_INTERFACEMQTT, "MQTT_EVENT_DATA");
ESP_LOGI(TAG_INTERFACEMQTT, "TOPIC=%.*s\r\n", event->topic_len, event->topic);
ESP_LOGI(TAG_INTERFACEMQTT, "DATA=%.*s\r\n", event->data_len, event->data);
ESP_LOGD(TAG, "MQTT_EVENT_DATA");
ESP_LOGD(TAG, "TOPIC=%.*s", event->topic_len, event->topic);
ESP_LOGD(TAG, "DATA=%.*s", event->data_len, event->data);
topic.assign(event->topic, event->topic_len);
if (subscribeFunktionMap != NULL) {
if (subscribeFunktionMap->find(topic) != subscribeFunktionMap->end()) {
ESP_LOGD(TAG_INTERFACEMQTT, "call handler function\r\n");
ESP_LOGD(TAG, "call subcribe function for topic %s", topic.c_str());
(*subscribeFunktionMap)[topic](topic, event->data, event->data_len);
}
} else {
ESP_LOGW(TAG_INTERFACEMQTT, "no handler available\r\n");
ESP_LOGW(TAG, "no handler available\r\n");
}
break;
case MQTT_EVENT_ERROR:
ESP_LOGI(TAG_INTERFACEMQTT, "MQTT_EVENT_ERROR");
#ifdef DEBUG_DETAIL_ON
ESP_LOGD(TAG, "MQTT_EVENT_ERROR - esp_mqtt_error_codes:");
ESP_LOGD(TAG, "error_type:%d", event->error_handle->error_type);
ESP_LOGD(TAG, "connect_return_code:%d", event->error_handle->connect_return_code);
ESP_LOGD(TAG, "esp_transport_sock_errno:%d", event->error_handle->esp_transport_sock_errno);
ESP_LOGD(TAG, "esp_tls_last_esp_err:%d", event->error_handle->esp_tls_last_esp_err);
ESP_LOGD(TAG, "esp_tls_stack_err:%d", event->error_handle->esp_tls_stack_err);
ESP_LOGD(TAG, "esp_tls_cert_verify_flags:%d", event->error_handle->esp_tls_cert_verify_flags);
#endif
mqtt_connected = false;
break;
default:
ESP_LOGI(TAG_INTERFACEMQTT, "Other event id:%d", event->event_id);
ESP_LOGD(TAG, "Other event id:%d", event->event_id);
break;
}
return ESP_OK;
}
static void mqtt_event_handler(void *handler_args, esp_event_base_t base, int32_t event_id, void *event_data) {
ESP_LOGD(TAG_INTERFACEMQTT, "Event dispatched from event loop base=%s, event_id=%d", base, event_id);
ESP_LOGD(TAG, "Event dispatched from event loop base=%s, event_id=%d", base, event_id);
mqtt_event_handler_cb((esp_mqtt_event_handle_t) event_data);
}
bool MQTTInit(std::string _mqttURI, std::string _clientid, std::string _user, std::string _password, std::string _LWTContext, int _keepalive){
std::string _zwmessage = "connection lost";
int _lzw = _zwmessage.length();
/* LWTContext = _LWTContext;
mqtt_cfg.uri = _mqttURI.c_str();
mqtt_cfg.client_id = _clientid.c_str();
mqtt_cfg.lwt_topic = _LWTContext.c_str();
mqtt_cfg.lwt_msg = _zwmessage.c_str();
mqtt_cfg.lwt_retain = 1;
mqtt_cfg.lwt_msg_len = _lzw;
mqtt_cfg.keepalive = _keepalive;
*/
esp_mqtt_client_config_t mqtt_cfg = {
.uri = _mqttURI.c_str(),
.client_id = _clientid.c_str(),
.lwt_topic = _LWTContext.c_str(),
.lwt_msg = _zwmessage.c_str(),
.lwt_retain = 1,
.lwt_msg_len = _lzw,
.keepalive = _keepalive
};
LogFile.WriteToFile("MQTT - Init");
if (_user.length() && _password.length()){
mqtt_cfg.username = _user.c_str();
mqtt_cfg.password = _password.c_str();
#ifdef __HIDE_PASSWORD
ESP_LOGI(TAG_INTERFACEMQTT, "Connect to MQTT: %s, XXXXXXXX", mqtt_cfg.username);
#else
ESP_LOGI(TAG_INTERFACEMQTT, "Connect to MQTT: %s, %s", mqtt_cfg.username, mqtt_cfg.password);
#endif
};
MQTTdestroy();
client = esp_mqtt_client_init(&mqtt_cfg);
if (client)
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,
int _keepalive, int _SetRetainFlag, void *_callbackOnConnected) {
if ((_mqttURI.length() == 0) || (_maintopic.length() == 0) || (_clientid.length() == 0))
{
if (esp_mqtt_client_register_event(client, esp_mmqtt_ID, mqtt_event_handler, client) != ESP_OK)
{
LogFile.WriteToFile("MQTT - Could not register event!");
return false;
}
if (esp_mqtt_client_start(client) != ESP_OK)
{
LogFile.WriteToFile("MQTT - Could not start client!");
return false;
}
/* if(!MQTTPublish(_LWTContext, "", 1))
{
LogFile.WriteToFile("MQTT - Could not publish LWT!");
return false;
}*/
}
else
{
LogFile.WriteToFile("MQTT - Could not Init client!");
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Init aborted! Config error (URI, MainTopic or ClientID missing)");
return false;
}
LogFile.WriteToFile("MQTT - Init successful");
uri = _mqttURI;
client_id = _clientid;
lwt_topic = _maintopic + "/" + _lwt;
lwt_connected = _lwt_connected;
lwt_disconnected = _lwt_disconnected;
keepalive = _keepalive;
SetRetainFlag = _SetRetainFlag;
maintopic = _maintopic;
callbackOnConnected = ( void (*)(std::string, int) )(_callbackOnConnected);
if (_user.length() && _password.length()){
user = _user;
password = _password;
}
#ifdef __HIDE_PASSWORD
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "URI: " + uri + ", clientname: " + client_id + ", user: " + user + ", password: XXXXXXXX, maintopic: "
+ maintopic + ", last-will-topic: " + lwt_topic + ", keepAlive: " + std::to_string(keepalive) + ", RetainFlag: " + std::to_string(SetRetainFlag));
#else
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "URI: " + uri + ", clientname: " + client_id + ", user: " + user + ", password: " + password + ", maintopic: "
+ maintopic + ", last-will-topic: " + lwt_topic + ", keepAlive: " + std::to_string(keepalive) + ", RetainFlag: " + std::to_string(SetRetainFlag));
#endif
mqtt_configOK = true;
return true;
}
/*
void MQTTReConnect(){
std::string _zwmessage = "connection lost";
int _lzw = _zwmessage.length();
>>>>>>> Stashed changes
int MQTT_Init() {
if (mqtt_initialized) {
return 0;
}
if (mqtt_configOK) {
mqtt_enabled = true;
} else {
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Init called, but client is not yet configured.");
return 0;
}
if (!getWIFIisConnected()) {
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Init called, but WIFI is not yet connected.");
return 0;
}
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Init");
MQTTdestroy_client(false);
esp_mqtt_client_config_t mqtt_cfg = {
.uri = uri.c_str(),
.client_id = client_id.c_str(),
.lwt_topic = lwt_topic.c_str(),
.lwt_msg = lwt_disconnected.c_str(),
.lwt_retain = 1,
.lwt_msg_len = (int)(lwt_disconnected.length()),
.keepalive = keepalive,
.disable_auto_reconnect = false, // Reconnection routine active (Default: false)
.buffer_size = 1536, // size of MQTT send/receive buffer (Default: 1024)
.reconnect_timeout_ms = 15000, // Try to reconnect to broker (Default: 10000ms)
.network_timeout_ms = 20000, // Network Timeout (Default: 10000ms)
.message_retransmit_timeout = 3000 // Tiem after message resent when broker not acknowledged (QoS1, QoS2)
};
if (user.length() && password.length()){
mqtt_cfg.username = user.c_str();
mqtt_cfg.password = password.c_str();
}
#ifdef DEBUG_DETAIL_ON
LogFile.WriteHeapInfo("MQTT Client Init");
#endif
client = esp_mqtt_client_init(&mqtt_cfg);
if (client)
{
if (esp_mqtt_client_register_event(client, esp_mmqtt_ID, mqtt_event_handler, client) != ESP_OK)
LogFile.WriteToFile("MQTT - Could not register event!");
if (esp_mqtt_client_start(client) != ESP_OK)
LogFile.WriteToFile("MQTT - Could not start client!");
<<<<<<< Updated upstream
if(MQTTPublish(_LWTContext, "", 1)) {
LogFile.WriteToFile("MQTT - Client init successful");
esp_err_t ret = esp_mqtt_client_register_event(client, esp_mqtt_ID, mqtt_event_handler, client);
if (ret != ESP_OK)
{
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Could not register event (ret=" + std::to_string(ret) + ")!");
mqtt_initialized = false;
return -1;
}
=======
if (mqtt_connected)
MQTTPublish(LWTContext, "", 1);
else
LogFile.WriteToFile("Problem with (Re)Connection not successful!");
>>>>>>> Stashed changes
#ifdef DEBUG_DETAIL_ON
LogFile.WriteHeapInfo("MQTT Client Start");
#endif
ret = esp_mqtt_client_start(client);
if (ret != ESP_OK)
{
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Client start failed (retval=" + std::to_string(ret) + ")!");
mqtt_initialized = false;
return -1;
}
else {
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Client started, waiting for established connection...");
mqtt_initialized = true;
return 1;
}
}
else
{
LogFile.WriteToFile("MQTT - Could not Init client!");
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "Init failed, no handle created!");
mqtt_initialized = false;
return -1;
}
}
*/
void MQTTdestroy() {
if (client != NULL) {
void MQTTdestroy_client(bool _disable = false) {
if (client) {
if (mqtt_connected) {
MQTTdestroySubscribeFunction();
esp_mqtt_client_disconnect(client);
mqtt_connected = false;
}
esp_mqtt_client_stop(client);
esp_mqtt_client_destroy(client);
client = NULL;
mqtt_initialized = false;
}
if (_disable) // Disable MQTT service, avoid restart with MQTTPublish
mqtt_configOK = false;
}
bool MQTTisConnected() {
bool getMQTTisEnabled() {
return mqtt_enabled;
}
bool getMQTTisConnected() {
return mqtt_connected;
}
bool mqtt_handler_flow_start(std::string _topic, char* _data, int _data_len) {
ESP_LOGD(TAG, "Handler called: topic %s, data %.*s", _topic.c_str(), _data_len, _data);
if (_data_len > 0) {
MQTTCtrlFlowStart(_topic);
}
return ESP_OK;
}
void MQTTconnected(){
if (mqtt_connected) {
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Connected to broker");
MQTTPublish(lwt_topic, lwt_connected, true); // Publish "connected" to maintopic/connection
if (connectFunktionMap != NULL) {
for(std::map<std::string, std::function<void()>>::iterator it = connectFunktionMap->begin(); it != connectFunktionMap->end(); ++it) {
it->second();
ESP_LOGD(TAG, "call connect function %s", it->first.c_str());
}
}
/* Subcribe to topics */
std::function<bool(std::string topic, char* data, int data_len)> subHandler = mqtt_handler_flow_start;
MQTTregisterSubscribeFunction(maintopic + "/ctrl/flow_start", subHandler); // subcribe to maintopic/ctrl/flow_start
if (subscribeFunktionMap != NULL) {
for(std::map<std::string, std::function<bool(std::string, char*, int)>>::iterator it = subscribeFunktionMap->begin(); it != subscribeFunktionMap->end(); ++it) {
int msg_id = esp_mqtt_client_subscribe(client, it->first.c_str(), 0);
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "topic " + it->first + " subscribe successful, msg_id=" + std::to_string(msg_id));
}
}
vTaskDelay(10000 / portTICK_PERIOD_MS); // Delay execution of callback routine after connection got established
if (callbackOnConnected) { // Call onConnected callback routine --> mqtt_server
callbackOnConnected(maintopic, SetRetainFlag);
}
}
}
void MQTTregisterConnectFunction(std::string name, std::function<void()> func){
ESP_LOGD(TAG_INTERFACEMQTT, "MQTTregisteronnectFunction %s\r\n", name.c_str());
ESP_LOGD(TAG, "MQTTregisteronnectFunction %s\r\n", name.c_str());
if (connectFunktionMap == NULL) {
connectFunktionMap = new std::map<std::string, std::function<void()>>();
}
if ((*connectFunktionMap)[name] != NULL) {
ESP_LOGW(TAG_INTERFACEMQTT, "connect function %s already registred", name.c_str());
ESP_LOGW(TAG, "connect function %s already registred", name.c_str());
return;
}
@@ -227,58 +358,36 @@ void MQTTregisterConnectFunction(std::string name, std::function<void()> func){
}
}
void MQTTunregisterConnectFunction(std::string name){
ESP_LOGD(TAG_INTERFACEMQTT, "MQTTregisteronnectFunction %s\r\n", name.c_str());
ESP_LOGD(TAG, "unregisterConnnectFunction %s\r\n", name.c_str());
if ((connectFunktionMap != NULL) && (connectFunktionMap->find(name) != connectFunktionMap->end())) {
connectFunktionMap->erase(name);
}
}
void MQTTregisterSubscribeFunction(std::string topic, std::function<bool(std::string, char*, int)> func){
ESP_LOGD(TAG_INTERFACEMQTT, "MQTTregisterSubscribeFunction %s\r\n", topic.c_str());
ESP_LOGD(TAG, "registerSubscribeFunction %s", topic.c_str());
if (subscribeFunktionMap == NULL) {
subscribeFunktionMap = new std::map<std::string, std::function<bool(std::string, char*, int)>>();
}
if ((*subscribeFunktionMap)[topic] != NULL) {
ESP_LOGW(TAG_INTERFACEMQTT, "topic %s already registred for subscription", topic.c_str());
ESP_LOGW(TAG, "topic %s already registered for subscription", topic.c_str());
return;
}
(*subscribeFunktionMap)[topic] = func;
if (mqtt_connected) {
int msg_id = esp_mqtt_client_subscribe(client, topic.c_str(), 0);
ESP_LOGD(TAG_INTERFACEMQTT, "topic %s subscribe successful, msg_id=%d", topic.c_str(), msg_id);
}
}
void MQTTconnected(){
if (mqtt_connected) {
LogFile.WriteToFile("MQTT - Connected");
if (connectFunktionMap != NULL) {
for(std::map<std::string, std::function<void()>>::iterator it = connectFunktionMap->begin(); it != connectFunktionMap->end(); ++it) {
it->second();
ESP_LOGD(TAG_INTERFACEMQTT, "call connect function %s", it->first.c_str());
}
}
if (subscribeFunktionMap != NULL) {
for(std::map<std::string, std::function<bool(std::string, char*, int)>>::iterator it = subscribeFunktionMap->begin(); it != subscribeFunktionMap->end(); ++it) {
int msg_id = esp_mqtt_client_subscribe(client, it->first.c_str(), 0);
ESP_LOGD(TAG_INTERFACEMQTT, "topic %s subscribe successful, msg_id=%d", it->first.c_str(), msg_id);
LogFile.WriteToFile("MQTT - topic " + it->first + " subscribe successful, msg_id=" + std::to_string(msg_id));
}
}
}
}
void MQTTdestroySubscribeFunction(){
if (subscribeFunktionMap != NULL) {
if (mqtt_connected) {
for(std::map<std::string, std::function<bool(std::string, char*, int)>>::iterator it = subscribeFunktionMap->begin(); it != subscribeFunktionMap->end(); ++it) {
int msg_id = esp_mqtt_client_unsubscribe(client, it->first.c_str());
ESP_LOGI(TAG_INTERFACEMQTT, "topic %s unsubscribe successful, msg_id=%d", it->first.c_str(), msg_id);
ESP_LOGD(TAG, "topic %s unsubscribe successful, msg_id=%d", it->first.c_str(), msg_id);
}
}
@@ -286,4 +395,5 @@ void MQTTdestroySubscribeFunction(){
delete subscribeFunktionMap;
subscribeFunktionMap = NULL;
}
}
}
#endif //ENABLE_MQTT

View File

@@ -1,3 +1,7 @@
#ifdef ENABLE_MQTT
#pragma once
#ifndef INTERFACE_MQTT_H
#define INTERFACE_MQTT_H
@@ -5,12 +9,16 @@
#include <map>
#include <functional>
bool MQTTInit(std::string _mqttURI, std::string _clientid, std::string _user, std::string _password, std::string _LWTContext, int _keepalive);
void MQTTdestroy();
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,
int _keepalive, int SetRetainFlag, void *callbackOnConnected);
int MQTT_Init();
void MQTTdestroy_client(bool _disable);
bool MQTTPublish(std::string _key, std::string _content, int retained_flag = 1); // retained Flag as Standart
bool MQTTisConnected();
bool getMQTTisEnabled();
bool getMQTTisConnected();
void MQTTregisterConnectFunction(std::string name, std::function<void()> func);
void MQTTunregisterConnectFunction(std::string name);
@@ -18,4 +26,5 @@ void MQTTregisterSubscribeFunction(std::string topic, std::function<bool(std::st
void MQTTdestroySubscribeFunction();
void MQTTconnected();
#endif //INTERFACE_MQTT_H
#endif //INTERFACE_MQTT_H
#endif //#ENABLE_MQTT

View File

@@ -0,0 +1,266 @@
#ifdef ENABLE_MQTT
#include <string>
#include <sstream>
#include <iomanip>
#include <vector>
#include "esp_log.h"
#include "ClassLogFile.h"
#include "connect_wlan.h"
#include "server_mqtt.h"
#include "interface_mqtt.h"
#include "time_sntp.h"
#include "../../include/defines.h"
static const char *TAG = "MQTT SERVER";
extern const char* libfive_git_version(void);
extern const char* libfive_git_revision(void);
extern const char* libfive_git_branch(void);
std::vector<NumberPost*>* NUMBERS;
bool HomeassistantDiscovery = false;
std::string meterType = "";
std::string valueUnit = "";
std::string timeUnit = "";
std::string rateUnit = "Unit/Minute";
float roundInterval; // Minutes
int keepAlive = 0; // Seconds
int retainFlag;
static std::string maintopic;
void mqttServer_setParameter(std::vector<NumberPost*>* _NUMBERS, int _keepAlive, float _roundInterval) {
NUMBERS = _NUMBERS;
keepAlive = _keepAlive;
roundInterval = _roundInterval;
}
void mqttServer_setMeterType(std::string _meterType, std::string _valueUnit, std::string _timeUnit,std::string _rateUnit) {
meterType = _meterType;
valueUnit = _valueUnit;
timeUnit = _timeUnit;
rateUnit = _rateUnit;
}
void sendHomeAssistantDiscoveryTopic(std::string group, std::string field,
std::string name, std::string icon, std::string unit, std::string deviceClass, std::string stateClass, std::string entityCategory) {
std::string version = std::string(libfive_git_version());
if (version == "") {
version = std::string(libfive_git_branch()) + " (" + std::string(libfive_git_revision()) + ")";
}
std::string topicFull;
std::string configTopic;
std::string payload;
configTopic = field;
if (group != "" && (*NUMBERS).size() > 1) { // There is more than one meter, prepend the group so we can differentiate them
configTopic = group + "_" + field;
name = group + " " + name;
}
if (field == "problem") { // Special binary sensor which is based on error topic
topicFull = "homeassistant/binary_sensor/" + maintopic + "/" + configTopic + "/config";
}
else {
topicFull = "homeassistant/sensor/" + maintopic + "/" + configTopic + "/config";
}
/* See https://www.home-assistant.io/docs/mqtt/discovery/ */
payload = string("{") +
"\"~\": \"" + maintopic + "\"," +
"\"unique_id\": \"" + maintopic + "-" + configTopic + "\"," +
"\"object_id\": \"" + maintopic + "_" + configTopic + "\"," + // This used to generate the Entity ID
"\"name\": \"" + name + "\"," +
"\"icon\": \"mdi:" + icon + "\",";
if (group != "") {
if (field == "problem") { // Special binary sensor which is based on error topic
payload += "\"state_topic\": \"~/" + group + "/error\",";
payload += "\"value_template\": \"{{ 'OFF' if 'no error' in value else 'ON'}}\",";
}
else {
payload += "\"state_topic\": \"~/" + group + "/" + field + "\",";
}
}
else {
if (field == "problem") { // Special binary sensor which is based on error topic
payload += "\"state_topic\": \"~/error\",";
payload += "\"value_template\": \"{{ 'OFF' if 'no error' in value else 'ON'}}\",";
}
else {
payload += "\"state_topic\": \"~/" + field + "\",";
}
}
if (unit != "") {
payload += "\"unit_of_meas\": \"" + unit + "\",";
}
if (deviceClass != "") {
payload += "\"device_class\": \"" + deviceClass + "\",";
}
if (stateClass != "") {
payload += "\"state_class\": \"" + stateClass + "\",";
}
if (entityCategory != "") {
payload += "\"entity_category\": \"" + entityCategory + "\",";
}
payload +=
"\"availability_topic\": \"~/" + std::string(LWT_TOPIC) + "\"," +
"\"payload_available\": \"" + LWT_CONNECTED + "\"," +
"\"payload_not_available\": \"" + LWT_DISCONNECTED + "\",";
payload += string("\"device\": {") +
"\"identifiers\": [\"" + maintopic + "\"]," +
"\"name\": \"" + maintopic + "\"," +
"\"model\": \"Meter Digitizer\"," +
"\"manufacturer\": \"AI on the Edge Device\"," +
"\"sw_version\": \"" + version + "\"," +
"\"configuration_url\": \"http://" + *getIPAddress() + "\"" +
"}" +
"}";
MQTTPublish(topicFull, payload, true);
}
void MQTThomeassistantDiscovery() {
if (!getMQTTisConnected())
return;
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "MQTT - Sending Homeassistant Discovery Topics (Meter Type: " + meterType + ", Value Unit: " + valueUnit + " , Rate Unit: " + rateUnit + ")...");
// Group | Field | User Friendly Name | Icon | Unit | Device Class | State Class | Entity Category
sendHomeAssistantDiscoveryTopic("", "uptime", "Uptime", "clock-time-eight-outline", "s", "", "", "diagnostic");
sendHomeAssistantDiscoveryTopic("", "MAC", "MAC Address", "network-outline", "", "", "", "diagnostic");
sendHomeAssistantDiscoveryTopic("", "hostname", "Hostname", "network-outline", "", "", "", "diagnostic");
sendHomeAssistantDiscoveryTopic("", "freeMem", "Free Memory", "memory", "B", "", "measurement", "diagnostic");
sendHomeAssistantDiscoveryTopic("", "wifiRSSI", "Wi-Fi RSSI", "wifi", "dBm", "signal_strength", "", "diagnostic");
sendHomeAssistantDiscoveryTopic("", "CPUtemp", "CPU Temperature", "thermometer", "°C", "temperature", "measurement", "diagnostic");
sendHomeAssistantDiscoveryTopic("", "interval", "Interval", "clock-time-eight-outline", "min", "" , "measurement", "diagnostic");
sendHomeAssistantDiscoveryTopic("", "IP", "IP", "network-outline", "", "", "", "diagnostic");
sendHomeAssistantDiscoveryTopic("", "status", "Status", "list-status", "", "", "", "diagnostic");
for (int i = 0; i < (*NUMBERS).size(); ++i) {
std::string group = (*NUMBERS)[i]->name;
if (group == "default") {
group = "";
}
// Group | Field | User Friendly Name | Icon | Unit | Device Class | State Class | Entity Category
sendHomeAssistantDiscoveryTopic(group, "value", "Value", "gauge", valueUnit, meterType, "total_increasing", "");
sendHomeAssistantDiscoveryTopic(group, "raw", "Raw Value", "raw", valueUnit, "", "total_increasing", "diagnostic");
sendHomeAssistantDiscoveryTopic(group, "error", "Error", "alert-circle-outline", "", "", "", "diagnostic");
/* Not announcing "rate" as it is better to use rate_per_time_unit resp. rate_per_digitalization_round */
// sendHomeAssistantDiscoveryTopic(group, "rate", "Rate (Unit/Minute)", "swap-vertical", "", "", "", ""); // Legacy, always Unit per Minute
sendHomeAssistantDiscoveryTopic(group, "rate_per_time_unit", "Rate (" + rateUnit + ")", "swap-vertical", rateUnit, "", "", "");
sendHomeAssistantDiscoveryTopic(group, "rate_per_digitalization_round", "Change since last digitalization round", "arrow-expand-vertical", valueUnit, "", "measurement", ""); // correctly the Unit is Uint/Interval!
sendHomeAssistantDiscoveryTopic(group, "timestamp", "Timestamp", "clock-time-eight-outline", "", "timestamp", "", "diagnostic");
sendHomeAssistantDiscoveryTopic(group, "json", "JSON", "code-json", "", "", "", "diagnostic");
sendHomeAssistantDiscoveryTopic(group, "problem", "Problem", "alert-outline", "", "problem", "", ""); // Special binary sensor which is based on error topic
}
}
void publishSystemData() {
if (!getMQTTisConnected())
return;
char tmp_char[50];
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Publishing system MQTT topics...");
sprintf(tmp_char, "%ld", (long)getUpTime());
MQTTPublish(maintopic + "/" + "uptime", std::string(tmp_char), retainFlag);
sprintf(tmp_char, "%lu", (long) getESPHeapSize());
MQTTPublish(maintopic + "/" + "freeMem", std::string(tmp_char), retainFlag);
sprintf(tmp_char, "%d", get_WIFI_RSSI());
MQTTPublish(maintopic + "/" + "wifiRSSI", std::string(tmp_char), retainFlag);
sprintf(tmp_char, "%d", (int)temperatureRead());
MQTTPublish(maintopic + "/" + "CPUtemp", std::string(tmp_char), retainFlag);
}
void publishStaticData() {
if (!getMQTTisConnected())
return;
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "Publishing static MQTT topics...");
MQTTPublish(maintopic + "/" + "MAC", getMac(), retainFlag);
MQTTPublish(maintopic + "/" + "IP", *getIPAddress(), retainFlag);
MQTTPublish(maintopic + "/" + "hostname", hostname, retainFlag);
std::stringstream stream;
stream << std::fixed << std::setprecision(1) << roundInterval; // minutes
MQTTPublish(maintopic + "/" + "interval", stream.str(), retainFlag);
}
esp_err_t sendDiscovery_and_static_Topics(httpd_req_t *req) {
if (HomeassistantDiscovery) {
MQTThomeassistantDiscovery();
}
publishStaticData();
const char* resp_str = (const char*) req->user_ctx;
httpd_resp_send(req, resp_str, strlen(resp_str));
return ESP_OK;
}
void GotConnected(std::string maintopic, int retainFlag) {
if (HomeassistantDiscovery) {
MQTThomeassistantDiscovery();
}
publishStaticData();
publishSystemData();
}
void register_server_mqtt_uri(httpd_handle_t server) {
httpd_uri_t uri = { };
uri.method = HTTP_GET;
uri.uri = "/mqtt_publish_discovery";
uri.handler = sendDiscovery_and_static_Topics;
uri.user_ctx = (void*) "MQTT Discovery and Static Topics sent";
httpd_register_uri_handler(server, &uri);
}
std::string getTimeUnit(void) {
return timeUnit;
}
void SetHomeassistantDiscoveryEnabled(bool enabled) {
HomeassistantDiscovery = enabled;
}
void setMqtt_Server_Retain(int _retainFlag) {
retainFlag = _retainFlag;
}
void mqttServer_setMainTopic( std::string _maintopic) {
maintopic = _maintopic;
}
std::string mqttServer_getMainTopic() {
return maintopic;
}
#endif //ENABLE_MQTT

View File

@@ -0,0 +1,26 @@
#ifdef ENABLE_MQTT
#pragma once
#ifndef SERVERMQTT_H
#define SERVERMQTT_H
#include "ClassFlowDefineTypes.h"
void SetHomeassistantDiscoveryEnabled(bool enabled);
void mqttServer_setParameter(std::vector<NumberPost*>* _NUMBERS, int interval, float roundInterval);
void mqttServer_setMeterType(std::string meterType, std::string valueUnit, std::string timeUnit,std::string rateUnit);
void setMqtt_Server_Retain(int SetRetainFlag);
void mqttServer_setMainTopic( std::string maintopic);
std::string mqttServer_getMainTopic();
void register_server_mqtt_uri(httpd_handle_t server);
void publishSystemData();
std::string getTimeUnit(void);
void GotConnected(std::string maintopic, int SetRetainFlag);
#endif //SERVERMQTT_H
#endif //ENABLE_MQTT

View File

@@ -1,11 +1,16 @@
#include "CTfLiteClass.h"
#include "ClassLogFile.h"
#include "Helper.h"
#include "esp_log.h"
#include "../../include/defines.h"
#include <sys/stat.h>
// #define DEBUG_DETAIL_ON
static const char *TAG = "TFLITE";
float CTfLiteClass::GetOutputValue(int nr)
{
TfLiteTensor* output2 = this->interpreter->output(0);
@@ -41,7 +46,7 @@ int CTfLiteClass::GetOutClassification(int _von, int _bis)
return -1;
int numeroutput = output2->dims->data[1];
//printf("\n number output neurons: %d\n\n", numeroutput);
//ESP_LOGD(TAG, "number output neurons: %d", numeroutput);
if (_bis == -1)
_bis = numeroutput -1;
@@ -51,7 +56,7 @@ int CTfLiteClass::GetOutClassification(int _von, int _bis)
if (_bis >= numeroutput)
{
printf("ANZAHL OUTPUT NEURONS passt nicht zu geforderter Classifizierung!");
ESP_LOGD(TAG, "NUMBER OF OUTPUT NEURONS does not match required classification!");
return -1;
}
@@ -69,24 +74,26 @@ int CTfLiteClass::GetOutClassification(int _von, int _bis)
return (zw_class - _von);
}
void CTfLiteClass::GetInputDimension(bool silent = false)
{
TfLiteTensor* input2 = this->interpreter->input(0);
int numdim = input2->dims->size;
if (!silent) printf("NumDimension: %d\n", numdim);
if (!silent) ESP_LOGD(TAG, "NumDimension: %d", numdim);
int sizeofdim;
for (int j = 0; j < numdim; ++j)
{
sizeofdim = input2->dims->data[j];
if (!silent) printf("SizeOfDimension %d: %d\n", j, sizeofdim);
if (!silent) ESP_LOGD(TAG, "SizeOfDimension %d: %d", j, sizeofdim);
if (j == 1) im_height = sizeofdim;
if (j == 2) im_width = sizeofdim;
if (j == 3) im_channel = sizeofdim;
}
}
int CTfLiteClass::ReadInputDimenstion(int _dim)
{
if (_dim == 0)
@@ -100,19 +107,18 @@ int CTfLiteClass::ReadInputDimenstion(int _dim)
}
int CTfLiteClass::GetAnzOutPut(bool silent)
{
TfLiteTensor* output2 = this->interpreter->output(0);
int numdim = output2->dims->size;
if (!silent) printf("NumDimension: %d\n", numdim);
if (!silent) ESP_LOGD(TAG, "NumDimension: %d", numdim);
int sizeofdim;
for (int j = 0; j < numdim; ++j)
{
sizeofdim = output2->dims->data[j];
if (!silent) printf("SizeOfDimension %d: %d\n", j, sizeofdim);
if (!silent) ESP_LOGD(TAG, "SizeOfDimension %d: %d", j, sizeofdim);
}
@@ -123,11 +129,12 @@ int CTfLiteClass::GetAnzOutPut(bool silent)
for (int i = 0; i < numeroutput; ++i)
{
fo = output2->data.f[i];
if (!silent) printf("Result %d: %f\n", i, fo);
if (!silent) ESP_LOGD(TAG, "Result %d: %f", i, fo);
}
return numeroutput;
}
void CTfLiteClass::Invoke()
{
if (interpreter != nullptr)
@@ -135,15 +142,16 @@ void CTfLiteClass::Invoke()
}
bool CTfLiteClass::LoadInputImageBasis(CImageBasis *rs)
{
std::string zw = "ClassFlowCNNGeneral::doNeuralNetwork after LoadInputResizeImage: ";
#ifdef DEBUG_DETAIL_ON
LogFile.WriteHeapInfo("CTfLiteClass::LoadInputImageBasis - Start");
#endif
unsigned int w = rs->width;
unsigned int h = rs->height;
unsigned char red, green, blue;
// printf("Image: %s size: %d x %d\n", _fn.c_str(), w, h);
// ESP_LOGD(TAG, "Image: %s size: %d x %d\n", _fn.c_str(), w, h);
input_i = 0;
float* input_data_ptr = (interpreter->input(0))->data.f;
@@ -162,41 +170,62 @@ bool CTfLiteClass::LoadInputImageBasis(CImageBasis *rs)
input_data_ptr++;
}
#ifdef DEBUG_DETAIL_ON
LogFile.WriteToFile("Nach dem Laden in input");
#endif
#ifdef DEBUG_DETAIL_ON
LogFile.WriteHeapInfo("CTfLiteClass::LoadInputImageBasis - done");
#endif
return true;
}
void CTfLiteClass::MakeAllocate()
bool CTfLiteClass::MakeAllocate()
{
static tflite::AllOpsResolver resolver;
// printf(LogFile.getESPHeapInfo().c_str()); printf("\n");
#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);
// printf(LogFile.getESPHeapInfo().c_str()); printf("\n");
TfLiteStatus allocate_status = this->interpreter->AllocateTensors();
if (allocate_status != kTfLiteOk) {
TF_LITE_REPORT_ERROR(error_reporter, "AllocateTensors() failed");
LogFile.WriteToFile("AllocateTensors() failed");
if (this->interpreter)
{
TfLiteStatus allocate_status = this->interpreter->AllocateTensors();
if (allocate_status != kTfLiteOk) {
TF_LITE_REPORT_ERROR(error_reporter, "AllocateTensors() failed");
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "AllocateTensors() failed");
this->GetInputDimension();
return;
}
// printf("Allocate Done.\n");
this->GetInputDimension();
return false;
}
}
else
{
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "new tflite::MicroInterpreter failed");
LogFile.WriteHeapInfo("CTfLiteClass::MakeAllocate-new tflite::MicroInterpreter failed");
return false;
}
#ifdef DEBUG_DETAIL_ON
LogFile.WriteHeapInfo("CTLiteClass::Alloc done");
#endif
return true;
}
void CTfLiteClass::GetInputTensorSize(){
void CTfLiteClass::GetInputTensorSize()
{
#ifdef DEBUG_DETAIL_ON
float *zw = this->input;
int test = sizeof(zw);
printf("Input Tensor Dimension: %d\n", test);
ESP_LOGD(TAG, "Input Tensor Dimension: %d", test);
#endif
}
long CTfLiteClass::GetFileSize(std::string filename)
{
struct stat stat_buf;
@@ -205,90 +234,95 @@ long CTfLiteClass::GetFileSize(std::string filename)
}
unsigned char* CTfLiteClass::ReadFileToCharArray(std::string _fn)
bool CTfLiteClass::ReadFileToModel(std::string _fn)
{
long size;
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "CTfLiteClass::ReadFileToModel: " + _fn);
size = GetFileSize(_fn);
long size = GetFileSize(_fn);
if (size == -1)
{
printf("\nFile doesn't exist.\n");
return NULL;
ESP_LOGE(TAG, "CTfLiteClass::ReadFileToModel: Model file doesn't exist: %s", _fn.c_str());
return false;
}
unsigned char *result = (unsigned char*) malloc(size);
int anz = 1;
while (!result && (anz < 6)) // maximal 5x versuchen (= 5s)
{
#ifdef DEBUG_DETAIL_ON
printf("Speicher ist voll - Versuche es erneut: %d.\n", anz);
LogFile.WriteHeapInfo("CTLiteClass::Alloc modelfile start");
#endif
result = (unsigned char*) malloc(size);
anz++;
}
modelfile = (unsigned char*)GET_MEMORY(size);
if(result != NULL) {
FILE* f = OpenFileAndWait(_fn.c_str(), "rb"); // vorher nur "r"
fread(result, 1, size, f);
if(modelfile != NULL)
{
FILE* f = fopen(_fn.c_str(), "rb"); // previously only "r
fread(modelfile, 1, size, f);
fclose(f);
}else {
printf("\nNo free memory available.\n");
#ifdef DEBUG_DETAIL_ON
LogFile.WriteHeapInfo("CTLiteClass::Alloc modelfile successful");
#endif
return true;
}
else
{
LogFile.WriteToFile(ESP_LOG_ERROR, TAG, "CTfLiteClass::ReadFileToModel: Can't allocate enough memory: " + std::to_string(size));
LogFile.WriteHeapInfo("CTfLiteClass::ReadFileToModel");
return result;
return false;
}
}
bool CTfLiteClass::LoadModel(std::string _fn){
bool CTfLiteClass::LoadModel(std::string _fn)
{
#ifdef SUPRESS_TFLITE_ERRORS
this->error_reporter = new tflite::OwnMicroErrorReporter;
#else
this->error_reporter = new tflite::MicroErrorReporter;
#endif
modelload = ReadFileToCharArray(_fn.c_str());
LogFile.WriteToFile(ESP_LOG_DEBUG, TAG, "CTfLiteClass::LoadModel");
if (modelload == NULL)
if (!ReadFileToModel(_fn.c_str())) {
return false;
}
model = tflite::GetModel(modelload);
// free(rd);
TFLITE_MINIMAL_CHECK(model != nullptr);
model = tflite::GetModel(modelfile);
if(model == nullptr)
return false;
return true;
}
CTfLiteClass::CTfLiteClass()
{
this->model = nullptr;
this->modelfile = NULL;
this->interpreter = nullptr;
this->input = nullptr;
this->output = nullptr;
this->kTensorArenaSize = 800 * 1024; /// laut testfile: 108000 - bisher 600;; 2021-09-11: 200 * 1024
this->tensor_arena = new uint8_t[kTensorArenaSize];
this->kTensorArenaSize = 800 * 1024; /// according to testfile: 108000 - so far 600;; 2021-09-11: 200 * 1024
this->tensor_arena = (uint8_t*)GET_MEMORY(kTensorArenaSize);
}
CTfLiteClass::~CTfLiteClass()
{
delete this->tensor_arena;
free(modelfile);
free(this->tensor_arena);
delete this->interpreter;
delete this->error_reporter;
if (modelload)
free(modelload);
}
namespace tflite {
int OwnMicroErrorReporter::Report(const char* format, va_list args) {
namespace tflite
{
int OwnMicroErrorReporter::Report(const char* format, va_list args)
{
return 0;
}
}

View File

@@ -1,9 +1,7 @@
#pragma once
#define TFLITE_MINIMAL_CHECK(x) \
if (!(x)) { \
fprintf(stderr, "Error at %s:%d\n", __FILE__, __LINE__); \
exit(1); \
}
#ifndef CTFLITECLASS_H
#define CTFLITECLASS_H
#include "tensorflow/lite/micro/all_ops_resolver.h"
#include "tensorflow/lite/micro/micro_error_reporter.h"
@@ -15,10 +13,6 @@
#include "CImageBasis.h"
#define SUPRESS_TFLITE_ERRORS // use, to avoid error messages from TFLITE
#ifdef SUPRESS_TFLITE_ERRORS
#include "tensorflow/lite/core/api/error_reporter.h"
#include "tensorflow/lite/micro/compatibility.h"
@@ -45,7 +39,7 @@ class CTfLiteClass
int kTensorArenaSize;
uint8_t *tensor_arena;
unsigned char *modelload = NULL;
unsigned char *modelfile = NULL;
float* input;
@@ -53,13 +47,13 @@ class CTfLiteClass
int im_height, im_width, im_channel;
long GetFileSize(std::string filename);
unsigned char* ReadFileToCharArray(std::string _fn);
bool ReadFileToModel(std::string _fn);
public:
CTfLiteClass();
~CTfLiteClass();
bool LoadModel(std::string _fn);
void MakeAllocate();
bool MakeAllocate();
void GetInputTensorSize();
bool LoadInputImageBasis(CImageBasis *rs);
void Invoke();
@@ -74,3 +68,4 @@ class CTfLiteClass
int ReadInputDimenstion(int _dim);
};
#endif //CTFLITECLASS_H

File diff suppressed because it is too large Load Diff

View File

@@ -1,21 +1,33 @@
#pragma once
#ifndef SERVERTFLITE_H
#define SERVERTFLITE_H
#include <esp_log.h>
#include <string>
#include <esp_http_server.h>
#include "CImageBasis.h"
#include "ClassFlowControll.h"
//#include "ClassControllCamera.h"
extern ClassFlowControll tfliteflow;
void register_server_tflite_uri(httpd_handle_t server);
void KillTFliteTasks();
void TFliteDoAutoStart();
bool isSetupModusActive();
int getCountFlowRounds();
std::string GetMQTTMainTopic();
void CheckIsPlannedReboot();
esp_err_t GetJPG(std::string _filename, httpd_req_t *req);
esp_err_t GetRawJPG(httpd_req_t *req);
#ifdef ENABLE_MQTT
std::string GetMQTTMainTopic();
esp_err_t MQTTCtrlFlowStart(std::string);
#endif //ENABLE_MQTT
#endif //SERVERTFLITE_H

View File

@@ -2,6 +2,6 @@ FILE(GLOB_RECURSE app_sources ${CMAKE_CURRENT_SOURCE_DIR}/*.*)
idf_component_register(SRCS ${app_sources}
INCLUDE_DIRS "."
REQUIRES tflite-lib jomjol_logfile)
REQUIRES tflite-lib jomjol_logfile jomjol_configfile)

View File

@@ -12,21 +12,24 @@
#include "esp_attr.h"
#include "esp_sleep.h"
#include "esp_sntp.h"
#include "../../include/defines.h"
#include "ClassLogFile.h"
static const char *TAG = "sntp";
#include "configFile.h"
#include "Helper.h"
bool setTimeAlwaysOnReboot = true;
time_t bootTime;
static void obtain_time(void);
static void initialize_sntp(void);
static const char *TAG = "SNTP";
static std::string timeZone = "";
static std::string timeServer = "undefined";
static bool useNtp = true;
std::string getNtpStatusText(sntp_sync_status_t status);
static void setTimeZone(std::string _tzstring);
static std::string getServerName(void);
void time_sync_notification_cb(struct timeval *tv)
{
ESP_LOGI(TAG, "Notification of a time synchronization event");
}
std::string ConvertTimeToString(time_t _time, const char * frm)
{
@@ -39,7 +42,8 @@ std::string ConvertTimeToString(time_t _time, const char * frm)
return result;
}
std::string gettimestring(const char * frm)
std::string getCurrentTimeString(const char * frm)
{
time_t now;
struct tm timeinfo;
@@ -52,91 +56,177 @@ std::string gettimestring(const char * frm)
return result;
}
void setup_time()
void time_sync_notification_cb(struct timeval *tv)
{
time_t now;
struct tm timeinfo;
time(&now);
localtime_r(&now, &timeinfo);
// Is time set? If not, tm_year will be (1970 - 1900).
if ((timeinfo.tm_year < (2016 - 1900)) || setTimeAlwaysOnReboot) {
ESP_LOGI(TAG, "Time is not set yet. Connecting to WiFi and getting time over NTP.");
initialize_sntp();
obtain_time();
// update 'now' variable with current time
time(&now);
}
char strftime_buf[64];
setTimeZone("CET-1CEST,M3.5.0,M10.5.0/3");
localtime_r(&now, &timeinfo);
strftime(strftime_buf, sizeof(strftime_buf), "%c", &timeinfo);
ESP_LOGI(TAG, "The current date/time in Berlin is: %s", strftime_buf);
strftime(strftime_buf, sizeof(strftime_buf), "%Y-%m-%d_%H:%M", &timeinfo);
ESP_LOGI(TAG, "The current date/time in Berlin is: %s", strftime_buf);
std::string zw = gettimestring("%Y%m%d-%H%M%S");
printf("timeist %s\n", zw.c_str());
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Time is now successfully synced with NTP Server " +
getServerName() + ": " + getCurrentTimeString("%Y-%m-%d %H:%M:%S"));
}
void setTimeZone(std::string _tzstring)
{
setenv("TZ", _tzstring.c_str(), 1);
tzset();
printf("TimeZone set to %s\n", _tzstring.c_str());
_tzstring = "Time zone set to " + _tzstring;
LogFile.WriteToFile(_tzstring);
LogFile.WriteToFile(ESP_LOG_INFO, TAG, _tzstring);
}
static void obtain_time(void)
{
time_t now = 0;
struct tm timeinfo = {};
int retry = 0;
const int retry_count = 10;
time(&now);
localtime_r(&now, &timeinfo);
while (sntp_get_sync_status() == SNTP_SYNC_STATUS_RESET && ++retry < retry_count) {
ESP_LOGI(TAG, "Waiting for system time to be set... (%d/%d)", retry, retry_count);
vTaskDelay(2000 / portTICK_PERIOD_MS);
std::string getNtpStatusText(sntp_sync_status_t status) {
if (status == SNTP_SYNC_STATUS_COMPLETED) {
return "Synchronized";
}
else if (status == SNTP_SYNC_STATUS_IN_PROGRESS) {
return "In Progress";
}
else { // SNTP_SYNC_STATUS_RESET
return "Reset";
}
}
bool getTimeIsSet(void) {
time_t now;
struct tm timeinfo;
time(&now);
localtime_r(&now, &timeinfo);
// Is time set? If not, tm_year will be (1970 - 1900).
if ((timeinfo.tm_year < (2022 - 1900))) {
return false;
}
else {
return true;
}
}
void reset_servername(std::string _servername)
{
printf("Set SNTP-Server: %s\n", _servername.c_str());
sntp_stop();
sntp_setoperatingmode(SNTP_OPMODE_POLL);
sntp_setservername(0, _servername.c_str());
sntp_init();
obtain_time();
std::string zw = gettimestring("%Y%m%d-%H%M%S");
printf("Time ist %s\n", zw.c_str());
/*void restartNtpClient(void) {
// sntp_restart();
// obtain_time();
}*/
bool getUseNtp(void) {
return useNtp;
}
static void initialize_sntp(void)
{
ESP_LOGI(TAG, "Initializing SNTP");
sntp_setoperatingmode(SNTP_OPMODE_POLL);
sntp_setservername(0, "pool.ntp.org");
// sntp_set_time_sync_notification_cb(time_sync_notification_cb);
sntp_init();
std::string getServerName(void) {
char buf[100];
if (sntp_getservername(0)){
snprintf(buf, sizeof(buf), "%s", sntp_getservername(0));
return std::string(buf);
}
else { // we have either IPv4 or IPv6 address
ip_addr_t const *ip = sntp_getserver(0);
if (ipaddr_ntoa_r(ip, buf, sizeof(buf)) != NULL) {
return std::string(buf);
}
}
return "";
}
void setBootTime()
{
time(&bootTime);
}
time_t getUpTime()
{
/**
* Load the TimeZone and TimeServer from the config file and initialize the NTP client
*/
bool setupTime() {
time_t now;
time(&now);
struct tm timeinfo;
char strftime_buf[64];
return now - bootTime;
}
ConfigFile configFile = ConfigFile(CONFIG_FILE);
if (!configFile.ConfigFileExists()){
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "No ConfigFile defined - exit setupTime() ");
return false;
}
std::vector<std::string> splitted;
std::string line = "";
bool disabledLine = false;
bool eof = false;
/* Load config from config file */
while ((!configFile.GetNextParagraph(line, disabledLine, eof) ||
(line.compare("[System]") != 0)) && !eof) {}
if (eof) {
return false;
}
if (disabledLine) {
return false;
}
while (configFile.getNextLine(&line, disabledLine, eof) &&
!configFile.isNewParagraph(line)) {
splitted = ZerlegeZeile(line);
if (toUpper(splitted[0]) == "TIMEZONE") {
timeZone = splitted[1];
}
if (toUpper(splitted[0]) == "TIMESERVER") {
if (splitted.size() <= 1) { // Key has no value => we use this to show it as disabled
timeServer = "";
}
else {
timeServer = splitted[1];
}
}
}
/* Setup NTP Server and Timezone */
if (timeServer == "undefined") {
timeServer = "pool.ntp.org";
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "TimeServer not defined, using default: " + timeServer);
}
else if (timeServer == "") {
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "TimeServer config empty, disabling NTP");
useNtp = false;
}
else {
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "TimeServer: " + timeServer);
}
if (timeZone == "") {
timeZone = "CET-1CEST,M3.5.0,M10.5.0/3";
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "TimeZone not set, using default: " + timeZone);
}
if (useNtp) {
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Configuring NTP Client...");
sntp_setoperatingmode(SNTP_OPMODE_POLL);
sntp_setservername(0, timeServer.c_str());
sntp_init();
sntp_set_time_sync_notification_cb(time_sync_notification_cb);
setTimeZone(timeZone);
}
/* The RTC keeps the time after a restart (Except on Power On or Pin Reset)
* There should only be a minor correction through NTP */
// Get current time from RTC
time(&now);
localtime_r(&now, &timeinfo);
strftime(strftime_buf, sizeof(strftime_buf), "%Y-%m-%d %H:%M:%S", &timeinfo);
if (getTimeIsSet()) {
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Time is already set: " + std::string(strftime_buf));
}
else {
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "The local time is unknown, starting with " + std::string(strftime_buf));
if (useNtp) {
LogFile.WriteToFile(ESP_LOG_INFO, TAG, "Once the NTP server provides a time, we will switch to that one");
}
}
return true;
}

View File

@@ -1,3 +1,9 @@
#pragma once
#ifndef TIMESNTP_H
#define TIMESNTP_H
#include <string>
#include <time.h>
#include <sys/time.h>
@@ -9,16 +15,15 @@
#include "esp_log.h"
#include "esp_attr.h"
#include "esp_sleep.h"
// #include "nvs_flash.h"
#include "esp_sntp.h"
void setup_time(void);
std::string gettimestring(const char * frm);
std::string getCurrentTimeString(const char * frm);
std::string ConvertTimeToString(time_t _time, const char * frm);
void setTimeZone(std::string _tzstring);
void reset_servername(std::string _servername);
void setBootTime();
time_t getUpTime();
bool getTimeIsSet(void);
bool getUseNtp(void);
bool setupTime();
#endif //TIMESNTP_H

View File

@@ -2,6 +2,6 @@ FILE(GLOB_RECURSE app_sources ${CMAKE_CURRENT_SOURCE_DIR}/*.*)
idf_component_register(SRCS ${app_sources}
INCLUDE_DIRS "."
REQUIRES nvs_flash jomjol_helper)
REQUIRES nvs_flash jomjol_helper jomjol_mqtt wpa_supplicant)

View File

@@ -13,6 +13,9 @@
#include "lwip/err.h"
#include "lwip/sys.h"
#ifdef ENABLE_MQTT
#include "interface_mqtt.h"
#endif //ENABLE_MQTT
#include <fstream>
#include <string>
@@ -20,27 +23,36 @@
#include <sstream>
#include <iostream>
#define __HIDE_PASSWORD
//////////////////////
#include <string.h>
#include <stdlib.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/event_groups.h"
#include "esp_wifi.h"
#include "esp_wnm.h"
#include "esp_rrm.h"
#include "esp_mbo.h"
#include "esp_event.h"
#include "esp_log.h"
#include "esp_mac.h"
#include "nvs_flash.h"
#include "esp_netif.h"
/////////////////////
#include "../../include/defines.h"
#define EXAMPLE_ESP_MAXIMUM_RETRY 1000
/* FreeRTOS event group to signal when we are connected*/
static EventGroupHandle_t s_wifi_event_group;
/* The event group allows multiple bits for each event, but we only care about two events:
* - we are connected to the AP with an IP
* - we failed to connect after the maximum amount of retries */
#define WIFI_CONNECTED_BIT BIT0
#define WIFI_FAIL_BIT BIT1
static const char *TAG = "wifi station";
static const char *TAG = "WIFI";
static int s_retry_num = 0;
bool WIFIConnected = false;
///////////////////////////////////////////////////////////
#define BLINK_GPIO GPIO_NUM_33
int BlinkDauer;
int BlinkAnzahl;
@@ -51,12 +63,248 @@ std::string hostname = "";
std::string std_hostname = "watermeter";
std::string ipadress = "";
std::string ssid = "";
int RSSIThreashold;
/////////////////////////////////
/////////////////////////////////
#ifdef WLAN_USE_MESH_ROAMING
int RSSI_Threshold = WLAN_WIFI_RSSI_THRESHOLD;
/* rrm ctx */
int rrm_ctx = 0;
/* FreeRTOS event group to signal when we are connected & ready to make a request */
static EventGroupHandle_t wifi_event_group;
/* esp netif object representing the WIFI station */
static esp_netif_t *sta_netif = NULL;
//static const char *TAG = "roaming_example";
static inline uint32_t WPA_GET_LE32(const uint8_t *a)
{
return ((uint32_t) a[3] << 24) | (a[2] << 16) | (a[1] << 8) | a[0];
}
#ifndef WLAN_EID_MEASURE_REPORT
#define WLAN_EID_MEASURE_REPORT 39
#endif
#ifndef MEASURE_TYPE_LCI
#define MEASURE_TYPE_LCI 9
#endif
#ifndef MEASURE_TYPE_LOCATION_CIVIC
#define MEASURE_TYPE_LOCATION_CIVIC 11
#endif
#ifndef WLAN_EID_NEIGHBOR_REPORT
#define WLAN_EID_NEIGHBOR_REPORT 52
#endif
#ifndef ETH_ALEN
#define ETH_ALEN 6
#endif
#define MAX_NEIGHBOR_LEN 512
static char * get_btm_neighbor_list(uint8_t *report, size_t report_len)
{
size_t len = 0;
const uint8_t *data;
int ret = 0;
/*
* Neighbor Report element (IEEE P802.11-REVmc/D5.0)
* BSSID[6]
* BSSID Information[4]
* Operating Class[1]
* Channel Number[1]
* PHY Type[1]
* Optional Subelements[variable]
*/
#define NR_IE_MIN_LEN (ETH_ALEN + 4 + 1 + 1 + 1)
if (!report || report_len == 0) {
ESP_LOGI(TAG, "RRM neighbor report is not valid");
return NULL;
}
char *buf = (char*) calloc(1, MAX_NEIGHBOR_LEN);
data = report;
while (report_len >= 2 + NR_IE_MIN_LEN) {
const uint8_t *nr;
char lci[256 * 2 + 1];
char civic[256 * 2 + 1];
uint8_t nr_len = data[1];
const uint8_t *pos = data, *end;
if (pos[0] != WLAN_EID_NEIGHBOR_REPORT ||
nr_len < NR_IE_MIN_LEN) {
ESP_LOGI(TAG, "CTRL: Invalid Neighbor Report element: id=%u len=%u",
data[0], nr_len);
ret = -1;
goto cleanup;
}
if (2U + nr_len > report_len) {
ESP_LOGI(TAG, "CTRL: Invalid Neighbor Report element: id=%u len=%zu nr_len=%u",
data[0], report_len, nr_len);
ret = -1;
goto cleanup;
}
pos += 2;
end = pos + nr_len;
nr = pos;
pos += NR_IE_MIN_LEN;
lci[0] = '\0';
civic[0] = '\0';
while (end - pos > 2) {
uint8_t s_id, s_len;
s_id = *pos++;
s_len = *pos++;
if (s_len > end - pos) {
ret = -1;
goto cleanup;
}
if (s_id == WLAN_EID_MEASURE_REPORT && s_len > 3) {
/* Measurement Token[1] */
/* Measurement Report Mode[1] */
/* Measurement Type[1] */
/* Measurement Report[variable] */
switch (pos[2]) {
case MEASURE_TYPE_LCI:
if (lci[0])
break;
memcpy(lci, pos, s_len);
break;
case MEASURE_TYPE_LOCATION_CIVIC:
if (civic[0])
break;
memcpy(civic, pos, s_len);
break;
}
}
pos += s_len;
}
ESP_LOGI(TAG, "RMM neigbor report bssid=" MACSTR
" info=0x%x op_class=%u chan=%u phy_type=%u%s%s%s%s",
MAC2STR(nr), WPA_GET_LE32(nr + ETH_ALEN),
nr[ETH_ALEN + 4], nr[ETH_ALEN + 5],
nr[ETH_ALEN + 6],
lci[0] ? " lci=" : "", lci,
civic[0] ? " civic=" : "", civic);
/* neighbor start */
len += snprintf(buf + len, MAX_NEIGHBOR_LEN - len, " neighbor=");
/* bssid */
len += snprintf(buf + len, MAX_NEIGHBOR_LEN - len, MACSTR, MAC2STR(nr));
/* , */
len += snprintf(buf + len, MAX_NEIGHBOR_LEN - len, ",");
/* bssid info */
len += snprintf(buf + len, MAX_NEIGHBOR_LEN - len, "0x%04x", WPA_GET_LE32(nr + ETH_ALEN));
len += snprintf(buf + len, MAX_NEIGHBOR_LEN - len, ",");
/* operating class */
len += snprintf(buf + len, MAX_NEIGHBOR_LEN - len, "%u", nr[ETH_ALEN + 4]);
len += snprintf(buf + len, MAX_NEIGHBOR_LEN - len, ",");
/* channel number */
len += snprintf(buf + len, MAX_NEIGHBOR_LEN - len, "%u", nr[ETH_ALEN + 5]);
len += snprintf(buf + len, MAX_NEIGHBOR_LEN - len, ",");
/* phy type */
len += snprintf(buf + len, MAX_NEIGHBOR_LEN - len, "%u", nr[ETH_ALEN + 6]);
/* optional elements, skip */
data = end;
report_len -= 2 + nr_len;
}
cleanup:
if (ret < 0) {
free(buf);
buf = NULL;
}
return buf;
}
void neighbor_report_recv_cb(void *ctx, const uint8_t *report, size_t report_len)
{
int *val = (int*) ctx;
uint8_t *pos = (uint8_t *)report;
int cand_list = 0;
if (!report) {
ESP_LOGE(TAG, "report is null");
return;
}
if (*val != rrm_ctx) {
ESP_LOGE(TAG, "rrm_ctx value didn't match, not initiated by us");
return;
}
/* dump report info */
ESP_LOGI(TAG, "rrm: neighbor report len=%d", report_len);
ESP_LOG_BUFFER_HEXDUMP(TAG, pos, report_len, ESP_LOG_INFO);
/* create neighbor list */
char *neighbor_list = get_btm_neighbor_list(pos + 1, report_len - 1);
/* In case neighbor list is not present issue a scan and get the list from that */
if (!neighbor_list) {
/* issue scan */
wifi_scan_config_t params;
memset(&params, 0, sizeof(wifi_scan_config_t));
if (esp_wifi_scan_start(&params, true) < 0) {
goto cleanup;
}
/* cleanup from net802.11 */
uint16_t number = 1;
wifi_ap_record_t ap_records;
esp_wifi_scan_get_ap_records(&number, &ap_records);
cand_list = 1;
}
/* send AP btm query, this will cause STA to roam as well */
esp_wnm_send_bss_transition_mgmt_query(REASON_FRAME_LOSS, neighbor_list, cand_list);
cleanup:
if (neighbor_list)
free(neighbor_list);
}
static void esp_bss_rssi_low_handler(void* arg, esp_event_base_t event_base,
int32_t event_id, void* event_data)
{
wifi_event_bss_rssi_low_t *event = (wifi_event_bss_rssi_low_t*) event_data;
ESP_LOGI(TAG, "%s:bss rssi is=%d", __func__, event->rssi);
/* Lets check channel conditions */
rrm_ctx++;
if (esp_rrm_send_neighbor_rep_request(neighbor_report_recv_cb, &rrm_ctx) < 0) {
/* failed to send neighbor report request */
ESP_LOGI(TAG, "failed to send neighbor report request");
if (esp_wnm_send_bss_transition_mgmt_query(REASON_FRAME_LOSS, NULL, 0) < 0) {
ESP_LOGI(TAG, "failed to send btm query");
}
}
}
#endif
//////////////////////////////////
//////////////////////////////////
std::string* getIPAddress()
{
return &ipadress;
}
std::string* getSSID()
{
return &ssid;
@@ -99,23 +347,27 @@ void task_doBlink(void *pvParameter)
vTaskDelete(NULL); //Delete this task if it exits from the loop above
}
void LEDBlinkTask(int _dauer, int _anz, bool _off)
{
BlinkDauer = _dauer;
BlinkAnzahl = _anz;
BlinkOff = _off;
xTaskCreate(&task_doBlink, "task_doBlink", configMINIMAL_STACK_SIZE * 8, NULL, tskIDLE_PRIORITY+1, NULL);
xTaskCreate(&task_doBlink, "task_doBlink", 4 * 1024, NULL, tskIDLE_PRIORITY+1, NULL);
}
/////////////////////////////////////////////////////////
static void event_handler(void* arg, esp_event_base_t event_base,
int32_t event_id, void* event_data)
{
if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_START) {
WIFIConnected = false;
LEDBlinkTask(200, 1, true);
esp_wifi_connect();
} else if (event_base == WIFI_EVENT && event_id == WIFI_EVENT_STA_DISCONNECTED) {
WIFIConnected = false;
// if (s_retry_num < EXAMPLE_ESP_MAXIMUM_RETRY) {
esp_wifi_connect();
s_retry_num++;
@@ -131,9 +383,18 @@ static void event_handler(void* arg, esp_event_base_t event_base,
s_retry_num = 0;
xEventGroupSetBits(s_wifi_event_group, WIFI_CONNECTED_BIT);
LEDBlinkTask(1000, 5, true);
WIFIConnected = true;
#ifdef ENABLE_MQTT
if (getMQTTisEnabled()) {
vTaskDelay(5000 / portTICK_PERIOD_MS);
MQTT_Init(); // Init when WIFI is getting connected
}
#endif //ENABLE_MQTT
}
}
void strinttoip4(const char *ip, int &a, int &b, int &c, int &d) {
std::string zw = std::string(ip);
std::stringstream s(zw);
@@ -142,8 +403,9 @@ void strinttoip4(const char *ip, int &a, int &b, int &c, int &d) {
}
void wifi_init_sta(const char *_ssid, const char *_password, const char *_hostname, const char *_ipadr, const char *_gw, const char *_netmask, const char *_dns)
void wifi_init_sta(const char *_ssid, const char *_password, const char *_hostname, const char *_ipadr, const char *_gw, const char *_netmask, const char *_dns, int _rssithreashold)
{
RSSI_Threshold = _rssithreashold;
s_wifi_event_group = xEventGroupCreate();
ESP_ERROR_CHECK(esp_netif_init());
@@ -153,20 +415,6 @@ void wifi_init_sta(const char *_ssid, const char *_password, const char *_hostna
if ((_ipadr != NULL) && (_gw != NULL) && (_netmask != NULL))
{
/*
tcpip_adapter_dhcpc_stop(TCPIP_ADAPTER_IF_STA);
tcpip_adapter_ip_info_t ip_info;
int a, b, c, d;
strinttoip4(_ipadr, a, b, c, d);
IP4_ADDR(&ip_info.ip, a, b, c, d);
strinttoip4(_gw, a, b, c, d);
IP4_ADDR(&ip_info.gw, a, b, c, d);
strinttoip4(_netmask, a, b, c, d);
IP4_ADDR(&ip_info.netmask, a, b, c, d);
tcpip_adapter_set_ip_info(TCPIP_ADAPTER_IF_STA, &ip_info);
*/
ESP_LOGI(TAG, "set IP %s, GW %s, Netmask %s manual", _ipadr, _gw, _netmask);
esp_netif_dhcpc_stop(my_sta);
@@ -199,11 +447,9 @@ void wifi_init_sta(const char *_ssid, const char *_password, const char *_hostna
ESP_ERROR_CHECK(esp_netif_set_dns_info(my_sta, ESP_NETIF_DNS_MAIN, &dns_info));
}
esp_event_handler_instance_t instance_any_id;
esp_event_handler_instance_t instance_got_ip;
esp_event_handler_instance_t instance_bss_rssi_low;
ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,
ESP_EVENT_ANY_ID,
&event_handler,
@@ -214,6 +460,15 @@ void wifi_init_sta(const char *_ssid, const char *_password, const char *_hostna
&event_handler,
NULL,
&instance_got_ip));
#ifdef WLAN_USE_MESH_ROAMING
ESP_ERROR_CHECK(esp_event_handler_instance_register(WIFI_EVENT,
WIFI_EVENT_STA_BSS_RSSI_LOW,
&esp_bss_rssi_low_handler,
NULL,
&instance_bss_rssi_low));
#endif
wifi_config_t wifi_config = { };
strcpy((char*)wifi_config.sta.ssid, (const char*)_ssid);
@@ -228,10 +483,10 @@ void wifi_init_sta(const char *_ssid, const char *_password, const char *_hostna
esp_err_t ret = tcpip_adapter_set_hostname(TCPIP_ADAPTER_IF_STA , _hostname);
hostname = std::string(_hostname);
if(ret != ESP_OK ){
ESP_LOGE(TAG,"failed to set hostname:%d",ret);
ESP_LOGE(TAG,"Failed to set hostname: %d",ret);
}
else {
ESP_LOGE(TAG,"Set Hostname to:%s", _hostname);
ESP_LOGI(TAG,"Set hostname to: %s", _hostname);
}
}
@@ -249,17 +504,17 @@ void wifi_init_sta(const char *_ssid, const char *_password, const char *_hostna
/* xEventGroupWaitBits() returns the bits before the call returned, hence we can test which event actually
* happened. */
if (bits & WIFI_CONNECTED_BIT) {
#ifdef __HIDE_PASSWORD
ESP_LOGI(TAG, "connected to ap SSID: %s, password: XXXXXXX", _ssid);
#else
ESP_LOGI(TAG, "connected to ap SSID: %s, password: %s", _ssid, _password);
#endif
#ifdef __HIDE_PASSWORD
ESP_LOGI(TAG, "Connected with AP: %s, password: XXXXXXX", _ssid);
#else
ESP_LOGI(TAG, "Connected with AP: %s, password: %s", _ssid, _password);
#endif
} else if (bits & WIFI_FAIL_BIT) {
#ifdef __HIDE_PASSWORD
ESP_LOGI(TAG, "Failed to connect to SSID: %s, password: XXXXXXXX", _ssid);
#else
ESP_LOGI(TAG, "Failed to connect to SSID: %s, password: %s", _ssid, _password);
#endif
#ifdef __HIDE_PASSWORD
ESP_LOGI(TAG, "Failed to connect with AP: %s, password: XXXXXXXX", _ssid);
#else
ESP_LOGI(TAG, "Failed to connect with AP: %s, password: %s", _ssid, _password);
#endif
} else {
ESP_LOGE(TAG, "UNEXPECTED EVENT");
}
@@ -272,6 +527,7 @@ void wifi_init_sta(const char *_ssid, const char *_password, const char *_hostna
// vEventGroupDelete(s_wifi_event_group);
}
int get_WIFI_RSSI()
{
wifi_ap_record_t ap;
@@ -279,13 +535,34 @@ int get_WIFI_RSSI()
return ap.rssi;
}
void wifi_init_sta(const char *_ssid, const char *_password, const char *_hostname)
{
wifi_init_sta(_ssid, _password, _hostname, NULL, NULL, NULL, NULL);
wifi_init_sta(_ssid, _password, _hostname, NULL, NULL, NULL, NULL, 0);
}
void wifi_init_sta(const char *_ssid, const char *_password)
{
wifi_init_sta(_ssid, _password, NULL, NULL, NULL, NULL, NULL);
wifi_init_sta(_ssid, _password, NULL, NULL, NULL, NULL, NULL, 0);
}
bool getWIFIisConnected()
{
return WIFIConnected;
}
void WIFIDestroy()
{
esp_event_handler_unregister(IP_EVENT, IP_EVENT_STA_GOT_IP, event_handler);
esp_event_handler_unregister(WIFI_EVENT, ESP_EVENT_ANY_ID, event_handler);
#ifdef WLAN_USE_MESH_ROAMING
esp_event_handler_unregister(WIFI_EVENT, WIFI_EVENT_STA_BSS_RSSI_LOW, esp_bss_rssi_low_handler);
#endif
esp_wifi_stop();
esp_wifi_deinit();
}

View File

@@ -1,17 +1,22 @@
#pragma once
#ifndef CONNECT_WLAN_H
#define CONNECT_WLAN_H
#include <string>
void wifi_init_sta(const char *_ssid, const char *_password, const char *_hostname, const char *_ipadr, const char *_gw, const char *_netmask, const char *_dns);
void wifi_init_sta(const char *_ssid, const char *_password, const char *_hostname, const char *_ipadr, const char *_gw, const char *_netmask, const char *_dns, int _rssithreashold);
void wifi_init_sta(const char *_ssid, const char *_password, const char *_hostname);
void wifi_init_sta(const char *_ssid, const char *_password);
std::string* getIPAddress();
std::string* getSSID();
int get_WIFI_RSSI();
bool getWIFIisConnected();
void WIFIDestroy();
extern std::string hostname;
extern std::string std_hostname;
extern int RSSIThreashold;
#endif
#endif //CONNECT_WLAN_H

View File

@@ -10,7 +10,10 @@
#include <sstream>
#include <iostream>
#include <string.h>
#include "esp_log.h"
#include "../../include/defines.h"
static const char *TAG = "WLAN.INI";
std::vector<string> ZerlegeZeileWLAN(std::string input, std::string _delimiter = "")
{
@@ -23,7 +26,7 @@ std::vector<string> ZerlegeZeileWLAN(std::string input, std::string _delimiter =
input = trim(input, delimiter);
size_t pos = findDelimiterPos(input, delimiter);
std::string token;
if (pos != std::string::npos) // Zerlegt nur bis ersten Gleichheitszeichen !!! Sonderfall für WLAN.ini
if (pos != std::string::npos) // splitted only up to first equal sign !!! Special case for WLAN.ini
{
token = input.substr(0, pos);
token = trim(token, delimiter);
@@ -38,7 +41,7 @@ std::vector<string> ZerlegeZeileWLAN(std::string input, std::string _delimiter =
void LoadWlanFromFile(std::string fn, char *&_ssid, char *&_password, char *&_hostname, char *&_ipadr, char *&_gw, char *&_netmask, char *&_dns)
bool LoadWlanFromFile(std::string fn, char *&_ssid, char *&_password, char *&_hostname, char *&_ipadr, char *&_gw, char *&_netmask, char *&_dns, int &_rssithreashold)
{
std::string ssid = "";
std::string passphrase = "";
@@ -46,19 +49,23 @@ void LoadWlanFromFile(std::string fn, char *&_ssid, char *&_password, char *&_ho
std::string gw = "";
std::string netmask = "";
std::string dns = "";
int rssithreshold = 0;
std::string line = "";
std::vector<string> zerlegt;
std::vector<string> splitted;
hostname = std_hostname;
FILE* pFile;
fn = FormatFileName(fn);
pFile = OpenFileAndWait(fn.c_str(), "r");
printf("file loaded\n");
pFile = fopen(fn.c_str(), "r");
if (!pFile)
return false;
ESP_LOGD(TAG, "file loaded");
if (pFile == NULL)
return;
return false;
char zw[1024];
fgets(zw, 1024, pFile);
@@ -66,54 +73,63 @@ void LoadWlanFromFile(std::string fn, char *&_ssid, char *&_password, char *&_ho
while ((line.size() > 0) || !(feof(pFile)))
{
// printf("%s", line.c_str());
zerlegt = ZerlegeZeileWLAN(line, "=");
zerlegt[0] = trim(zerlegt[0], " ");
// ESP_LOGD(TAG, "%s", line.c_str());
splitted = ZerlegeZeileWLAN(line, "=");
splitted[0] = trim(splitted[0], " ");
if ((zerlegt.size() > 1) && (toUpper(zerlegt[0]) == "HOSTNAME")){
hostname = trim(zerlegt[1]);
if ((splitted.size() > 1) && (toUpper(splitted[0]) == "HOSTNAME")){
hostname = trim(splitted[1]);
if ((hostname[0] == '"') && (hostname[hostname.length()-1] == '"')){
hostname = hostname.substr(1, hostname.length()-2);
}
}
if ((zerlegt.size() > 1) && (toUpper(zerlegt[0]) == "SSID")){
ssid = trim(zerlegt[1]);
if ((splitted.size() > 1) && (toUpper(splitted[0]) == "SSID")){
ssid = trim(splitted[1]);
if ((ssid[0] == '"') && (ssid[ssid.length()-1] == '"')){
ssid = ssid.substr(1, ssid.length()-2);
}
}
if ((zerlegt.size() > 1) && (toUpper(zerlegt[0]) == "PASSWORD")){
passphrase = zerlegt[1];
if ((splitted.size() > 1) && (toUpper(splitted[0]) == "RSSITHREASHOLD")){
string _s = trim(splitted[1]);
if ((_s[0] == '"') && (_s[_s.length()-1] == '"')){
_s = _s.substr(1, ssid.length()-2);
}
rssithreshold = atoi(_s.c_str());
}
if ((splitted.size() > 1) && (toUpper(splitted[0]) == "PASSWORD")){
passphrase = splitted[1];
if ((passphrase[0] == '"') && (passphrase[passphrase.length()-1] == '"')){
passphrase = passphrase.substr(1, passphrase.length()-2);
}
}
if ((zerlegt.size() > 1) && (toUpper(zerlegt[0]) == "IP")){
ipaddress = zerlegt[1];
if ((splitted.size() > 1) && (toUpper(splitted[0]) == "IP")){
ipaddress = splitted[1];
if ((ipaddress[0] == '"') && (ipaddress[ipaddress.length()-1] == '"')){
ipaddress = ipaddress.substr(1, ipaddress.length()-2);
}
}
if ((zerlegt.size() > 1) && (toUpper(zerlegt[0]) == "GATEWAY")){
gw = zerlegt[1];
if ((splitted.size() > 1) && (toUpper(splitted[0]) == "GATEWAY")){
gw = splitted[1];
if ((gw[0] == '"') && (gw[gw.length()-1] == '"')){
gw = gw.substr(1, gw.length()-2);
}
}
if ((zerlegt.size() > 1) && (toUpper(zerlegt[0]) == "NETMASK")){
netmask = zerlegt[1];
if ((splitted.size() > 1) && (toUpper(splitted[0]) == "NETMASK")){
netmask = splitted[1];
if ((netmask[0] == '"') && (netmask[netmask.length()-1] == '"')){
netmask = netmask.substr(1, netmask.length()-2);
}
}
if ((zerlegt.size() > 1) && (toUpper(zerlegt[0]) == "DNS")){
dns = zerlegt[1];
if ((splitted.size() > 1) && (toUpper(splitted[0]) == "DNS")){
dns = splitted[1];
if ((dns[0] == '"') && (dns[dns.length()-1] == '"')){
dns = dns.substr(1, dns.length()-2);
}
@@ -177,6 +193,10 @@ void LoadWlanFromFile(std::string fn, char *&_ssid, char *&_password, char *&_ho
}
else
_dns = NULL;
_rssithreashold = rssithreshold;
RSSIThreashold = rssithreshold;
return true;
}
@@ -188,7 +208,7 @@ bool ChangeHostName(std::string fn, std::string _newhostname)
return false;
string line = "";
std::vector<string> zerlegt;
std::vector<string> splitted;
bool found = false;
@@ -196,9 +216,9 @@ bool ChangeHostName(std::string fn, std::string _newhostname)
FILE* pFile;
fn = FormatFileName(fn);
pFile = OpenFileAndWait(fn.c_str(), "r");
pFile = fopen(fn.c_str(), "r");
printf("file loaded\n");
ESP_LOGD(TAG, "file loaded\n");
if (pFile == NULL)
return false;
@@ -209,11 +229,11 @@ bool ChangeHostName(std::string fn, std::string _newhostname)
while ((line.size() > 0) || !(feof(pFile)))
{
printf("%s", line.c_str());
zerlegt = ZerlegeZeileWLAN(line, "=");
zerlegt[0] = trim(zerlegt[0], " ");
ESP_LOGD(TAG, "%s", line.c_str());
splitted = ZerlegeZeileWLAN(line, "=");
splitted[0] = trim(splitted[0], " ");
if ((zerlegt.size() > 1) && (toUpper(zerlegt[0]) == "HOSTNAME")){
if ((splitted.size() > 1) && (toUpper(splitted[0]) == "HOSTNAME")){
line = "hostname = \"" + _newhostname + "\"\n";
found = true;
}
@@ -238,17 +258,89 @@ bool ChangeHostName(std::string fn, std::string _newhostname)
fclose(pFile);
pFile = OpenFileAndWait(fn.c_str(), "w+");
pFile = fopen(fn.c_str(), "w+");
for (int i = 0; i < neuesfile.size(); ++i)
{
printf(neuesfile[i].c_str());
ESP_LOGD(TAG, "%s", neuesfile[i].c_str());
fputs(neuesfile[i].c_str(), pFile);
}
fclose(pFile);
printf("*** Hostname update done ***\n");
ESP_LOGD(TAG, "*** Hostname update done ***");
return true;
}
bool ChangeRSSIThreashold(std::string fn, int _newrssithreashold)
{
if (RSSIThreashold == _newrssithreashold)
return false;
string line = "";
std::vector<string> splitted;
bool found = false;
std::vector<string> neuesfile;
FILE* pFile;
fn = FormatFileName(fn);
pFile = fopen(fn.c_str(), "r");
ESP_LOGD(TAG, "file loaded\n");
if (pFile == NULL)
return false;
char zw[1024];
fgets(zw, 1024, pFile);
line = std::string(zw);
while ((line.size() > 0) || !(feof(pFile)))
{
ESP_LOGD(TAG, "%s", line.c_str());
splitted = ZerlegeZeileWLAN(line, "=");
splitted[0] = trim(splitted[0], " ");
if ((splitted.size() > 1) && (toUpper(splitted[0]) == "RSSITHREASHOLD")){
line = "RSSIThreashold = " + to_string(_newrssithreashold) + "\n";
found = true;
}
neuesfile.push_back(line);
if (fgets(zw, 1024, pFile) == NULL)
{
line = "";
}
else
{
line = std::string(zw);
}
}
if (!found)
{
line = "RSSIThreashold = " + to_string(_newrssithreashold) + "\n";
neuesfile.push_back(line);
}
fclose(pFile);
pFile = fopen(fn.c_str(), "w+");
for (int i = 0; i < neuesfile.size(); ++i)
{
ESP_LOGD(TAG, "%s", neuesfile[i].c_str());
fputs(neuesfile[i].c_str(), pFile);
}
fclose(pFile);
ESP_LOGD(TAG, "*** RSSIThreashold update done ***");
return true;
}

View File

@@ -1,11 +1,14 @@
#pragma once
#ifndef READ_WLANINI_H
#define READ_WLANINI_H
#include <string>
void LoadWlanFromFile(std::string fn, char *&_ssid, char *&_password, char *&_hostname, char *&_ipadr, char *&_gw, char *&_netmask, char *&_dns);
bool LoadWlanFromFile(std::string fn, char *&_ssid, char *&_password, char *&_hostname, char *&_ipadr, char *&_gw, char *&_netmask, char *&_dns, int &_rssithreashold);
bool ChangeHostName(std::string fn, std::string _newhostname);
bool ChangeRSSIThreashold(std::string fn, int _newrssithreashold);
#endif
#endif //READ_WLANINI_H

View File

@@ -0,0 +1,6 @@
FILE(GLOB_RECURSE app_sources ${CMAKE_CURRENT_SOURCE_DIR}/*.*)
idf_component_register(SRCS ${app_sources}
INCLUDE_DIRS "." "../../include")

View File

@@ -0,0 +1,235 @@
## Changelog
### 3.0.1
- Fix compilation error with MINIZ_USE_UNALIGNED_LOADS_AND_STORES=1
### 3.0.0
- Reduce memory usage for inflate. This changes `struct tinfl_decompressor_tag` and therefore requires a major version bump (breaks ABI compatibility)
- Add padding to structures so it continues to work if features differ. This also changes some structures
- Use _ftelli64, _fseeki64 and stat with MinGW32 and OpenWatcom
- Fix varios warnings with OpenWatcom compiler
- Avoid using unaligned memory access in UBSan builds
- Set MINIZ_LITTLE_ENDIAN only if not set
- Add MINIZ_NO_DEFLATE_APIS and MINIZ_NO_INFLATE_APIS
- Fix use of uninitialized memory in tinfl_decompress_mem_to_callback()
- Use wfopen on windows
- Use _wstat64 instead _stat64 on windows
- Use level_and_flags after MZ_DEFAULT_COMPRESSION has been handled
- Improve endianess detection
- Don't use unaligned stores and loads per default
- Fix function declaration if MINIZ_NO_STDIO is used
- Fix MZ_ZIP_GENERAL_PURPOSE_BIT_FLAG_UTF8 not being set
- Remove total files check (its 32-bit uint)
- tinfl_decompress: avoid NULL ptr arithmetic UB
- miniz_zip: fix mz_zip_reader_extract_to_heap to read correct sizes
- Eliminate 64-bit operations on 32-bit machines
- Disable treating warnings as error with MSVC
- Disable building shared lib via CMake by default
- Fixed alignment problems on MacOS
- Fixed get error string for MZ_ZIP_TOTAL_ERRORS
- Write correct FLEVEL 2-bit value in zlib header
- miniz.pc.in: fix include path not containing the "miniz" suffix
- Fix compatibility with FreeBSD
- pkg-config tweaks
- Fix integer overflow in header corruption check
- Fix some warnings
- tdefl_compress_normal: Avoid NULL ptr arithmetic UB
- replace use of stdint.h types with mz_ variants
### 2.2.0
- Fix examples with amalgamation
- Modified cmake script to support shared library mode and find_package
- Fix for misleading doc comment on `mz_zip_reader_init_cfile` function
- Add include location tolerance and stop forcing `_GNU_SOURCE`
- Fix: mz_zip_reader_locate_file_v2 returns an mz_bool
- Fix large file system checks
- Add #elif to enable an external mz_crc32() to be linked in
- Write with dynamic size (size of file/data to be added not known before adding)
- Added uncompress2 for zlib compatibility
- Add support for building as a Meson subproject
- Added OSSFuzz support; Integrate with CIFuzz
- Add pkg-config file
- Fixed use-of-uninitialized value msan error when copying dist bytes with no output bytes written.
- mz_zip_validate_file(): fix memory leak on errors
- Fixed MSAN use-of-uninitialized in tinfl_decompress when invalid dist is decoded. In this instance dist was 31 which s_dist_base translates as 0
- Add flag to set (compressed) size in local file header
- avoid use of uninitialized value in tdefl_record_literal
### 2.1.0
- More instances of memcpy instead of cast and use memcpy per default
- Remove inline for c90 support
- New function to read files via callback functions when adding them
- Fix out of bounds read while reading Zip64 extended information
- guard memcpy when n == 0 because buffer may be NULL
- Implement inflateReset() function
- Move comp/decomp alloc/free prototypes under guarding #ifndef MZ_NO_MALLOC
- Fix large file support under Windows
- Don't warn if _LARGEFILE64_SOURCE is not defined to 1
- Fixes for MSVC warnings
- Remove check that path of file added to archive contains ':' or '\'
- Add !defined check on MINIZ_USE_ALIGNED_LOADS_AND_STORES
### 2.0.8
- Remove unimplemented functions (mz_zip_locate_file and mz_zip_locate_file_v2)
- Add license, changelog, readme and example files to release zip
- Fix heap overflow to user buffer in tinfl_status tinfl_decompress
- Fix corrupt archive if uncompressed file smaller than 4 byte and the file is added by mz_zip_writer_add_mem*
### 2.0.7
- Removed need in C++ compiler in cmake build
- Fixed a lot of uninitialized value errors found with Valgrind by memsetting m_dict to 0 in tdefl_init
- Fix resource leak in mz_zip_reader_init_file_v2
- Fix assert with mz_zip_writer_add_mem* w/MZ_DEFAULT_COMPRESSION
- cmake build: install library and headers
- Remove _LARGEFILE64_SOURCE requirement from apple defines for large files
### 2.0.6
- Improve MZ_ZIP_FLAG_WRITE_ZIP64 documentation
- Remove check for cur_archive_file_ofs > UINT_MAX because cur_archive_file_ofs is not used after this point
- Add cmake debug configuration
- Fix PNG height when creating png files
- Add "iterative" file extraction method based on mz_zip_reader_extract_to_callback.
- Option to use memcpy for unaligned data access
- Define processor/arch macros as zero if not set to one
### 2.0.4/2.0.5
- Fix compilation with the various omission compile definitions
### 2.0.3
- Fix GCC/clang compile warnings
- Added callback for periodic flushes (for ZIP file streaming)
- Use UTF-8 for file names in ZIP files per default
### 2.0.2
- Fix source backwards compatibility with 1.x
- Fix a ZIP bit not being set correctly
### 2.0.1
- Added some tests
- Added CI
- Make source code ANSI C compatible
### 2.0.0 beta
- Matthew Sitton merged miniz 1.x to Rich Geldreich's vogl ZIP64 changes. Miniz is now licensed as MIT since the vogl code base is MIT licensed
- Miniz is now split into several files
- Miniz does now not seek backwards when creating ZIP files. That is the ZIP files can be streamed
- Miniz automatically switches to the ZIP64 format when the created ZIP files goes over ZIP file limits
- Similar to [SQLite](https://www.sqlite.org/amalgamation.html) the Miniz source code is amalgamated into one miniz.c/miniz.h pair in a build step (amalgamate.sh). Please use miniz.c/miniz.h in your projects
- Miniz 2 is only source back-compatible with miniz 1.x. It breaks binary compatibility because structures changed
### v1.16 BETA Oct 19, 2013
Still testing, this release is downloadable from [here](http://www.tenacioussoftware.com/miniz_v116_beta_r1.7z). Two key inflator-only robustness and streaming related changes. Also merged in tdefl_compressor_alloc(), tdefl_compressor_free() helpers to make script bindings easier for rustyzip. I would greatly appreciate any help with testing or any feedback.
The inflator in raw (non-zlib) mode is now usable on gzip or similar streams that have a bunch of bytes following the raw deflate data (problem discovered by rustyzip author williamw520). This version should never read beyond the last byte of the raw deflate data independent of how many bytes you pass into the input buffer.
The inflator now has a new failure status TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS (-4). Previously, if the inflator was starved of bytes and could not make progress (because the input buffer was empty and the caller did not set the TINFL_FLAG_HAS_MORE_INPUT flag - say on truncated or corrupted compressed data stream) it would append all 0's to the input and try to soldier on. This is scary behavior if the caller didn't know when to stop accepting output (because it didn't know how much uncompressed data was expected, or didn't enforce a sane maximum). v1.16 will instead return TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS immediately if it needs 1 or more bytes to make progress, the input buf is empty, and the caller has indicated that no more input is available. This is a "soft" failure, so you can call the inflator again with more input and it will try to continue, or you can give up and fail. This could be very useful in network streaming scenarios.
- The inflator coroutine func. is subtle and complex so I'm being cautious about this release. I would greatly appreciate any help with testing or any feedback.
I feel good about these changes, and they've been through several hours of automated testing, but they will probably not fix anything for the majority of prev. users so I'm
going to mark this release as beta for a few weeks and continue testing it at work/home on various things.
- The inflator in raw (non-zlib) mode is now usable on gzip or similar data streams that have a bunch of bytes following the raw deflate data (problem discovered by rustyzip author williamw520).
This version should *never* read beyond the last byte of the raw deflate data independent of how many bytes you pass into the input buffer. This issue was caused by the various Huffman bitbuffer lookahead optimizations, and
would not be an issue if the caller knew and enforced the precise size of the raw compressed data *or* if the compressed data was in zlib format (i.e. always followed by the byte aligned zlib adler32).
So in other words, you can now call the inflator on deflate streams that are followed by arbitrary amounts of data and it's guaranteed that decompression will stop exactly on the last byte.
- The inflator now has a new failure status: TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS (-4). Previously, if the inflator was starved of bytes and could not make progress (because the input buffer was empty and the
caller did not set the TINFL_FLAG_HAS_MORE_INPUT flag - say on truncated or corrupted compressed data stream) it would append all 0's to the input and try to soldier on.
This is scary, because in the worst case, I believe it was possible for the prev. inflator to start outputting large amounts of literal data. If the caller didn't know when to stop accepting output
(because it didn't know how much uncompressed data was expected, or didn't enforce a sane maximum) it could continue forever. v1.16 cannot fall into this failure mode, instead it'll return
TINFL_STATUS_FAILED_CANNOT_MAKE_PROGRESS immediately if it needs 1 or more bytes to make progress, the input buf is empty, and the caller has indicated that no more input is available. This is a "soft"
failure, so you can call the inflator again with more input and it will try to continue, or you can give up and fail. This could be very useful in network streaming scenarios.
- Added documentation to all the tinfl return status codes, fixed miniz_tester so it accepts double minus params for Linux, tweaked example1.c, added a simple "follower bytes" test to miniz_tester.cpp.
### v1.15 r4 STABLE - Oct 13, 2013
Merged over a few very minor bug fixes that I fixed in the zip64 branch. This is downloadable from [here](http://code.google.com/p/miniz/downloads/list) and also in SVN head (as of 10/19/13).
### v1.15 - Oct. 13, 2013
Interim bugfix release while I work on the next major release with zip64 and streaming compression/decompression support. Fixed the MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY bug (thanks kahmyong.moon@hp.com), which could cause the locate files func to not find files when this flag was specified. Also fixed a bug in mz_zip_reader_extract_to_mem_no_alloc() with user provided read buffers (thanks kymoon). I also merged lots of compiler fixes from various github repo branches and Google Code issue reports. I finally added cmake support (only tested under for Linux so far), compiled and tested with clang v3.3 and gcc 4.6 (under Linux), added defl_write_image_to_png_file_in_memory_ex() (supports Y flipping for OpenGL use, real-time compression), added a new PNG example (example6.c - Mandelbrot), and I added 64-bit file I/O support (stat64(), etc.) for glibc.
- Critical fix for the MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY bug (thanks kahmyong.moon@hp.com) which could cause locate files to not find files. This bug
would only have occurred in earlier versions if you explicitly used this flag, OR if you used mz_zip_extract_archive_file_to_heap() or mz_zip_add_mem_to_archive_file_in_place()
(which used this flag). If you can't switch to v1.15 but want to fix this bug, just remove the uses of this flag from both helper funcs (and of course don't use the flag).
- Bugfix in mz_zip_reader_extract_to_mem_no_alloc() from kymoon when pUser_read_buf is not NULL and compressed size is > uncompressed size
- Fixing mz_zip_reader_extract_*() funcs so they don't try to extract compressed data from directory entries, to account for weird zipfiles which contain zero-size compressed data on dir entries.
Hopefully this fix won't cause any issues on weird zip archives, because it assumes the low 16-bits of zip external attributes are DOS attributes (which I believe they always are in practice).
- Fixing mz_zip_reader_is_file_a_directory() so it doesn't check the internal attributes, just the filename and external attributes
- mz_zip_reader_init_file() - missing MZ_FCLOSE() call if the seek failed
- Added cmake support for Linux builds which builds all the examples, tested with clang v3.3 and gcc v4.6.
- Clang fix for tdefl_write_image_to_png_file_in_memory() from toffaletti
- Merged MZ_FORCEINLINE fix from hdeanclark
- Fix <time.h> include before config #ifdef, thanks emil.brink
- Added tdefl_write_image_to_png_file_in_memory_ex(): supports Y flipping (super useful for OpenGL apps), and explicit control over the compression level (so you can
set it to 1 for real-time compression).
- Merged in some compiler fixes from paulharris's github repro.
- Retested this build under Windows (VS 2010, including static analysis), tcc 0.9.26, gcc v4.6 and clang v3.3.
- Added example6.c, which dumps an image of the mandelbrot set to a PNG file.
- Modified example2 to help test the MZ_ZIP_FLAG_DO_NOT_SORT_CENTRAL_DIRECTORY flag more.
- In r3: Bugfix to mz_zip_writer_add_file() found during merge: Fix possible src file fclose() leak if alignment bytes+local header file write faiiled
- In r4: Minor bugfix to mz_zip_writer_add_from_zip_reader(): Was pushing the wrong central dir header offset, appears harmless in this release, but it became a problem in the zip64 branch
### v1.14 - May 20, 2012
(SVN Only) Minor tweaks to get miniz.c compiling with the Tiny C Compiler, added #ifndef MINIZ_NO_TIME guards around utime.h includes. Adding mz_free() function, so the caller can free heap blocks returned by miniz using whatever heap functions it has been configured to use, MSVC specific fixes to use "safe" variants of several functions (localtime_s, fopen_s, freopen_s).
MinGW32/64 GCC 4.6.1 compiler fixes: added MZ_FORCEINLINE, #include <time.h> (thanks fermtect).
Compiler specific fixes, some from fermtect. I upgraded to TDM GCC 4.6.1 and now static __forceinline is giving it fits, so I'm changing all usage of __forceinline to MZ_FORCEINLINE and forcing gcc to use __attribute__((__always_inline__)) (and MSVC to use __forceinline). Also various fixes from fermtect for MinGW32: added #include , 64-bit ftell/fseek fixes.
### v1.13 - May 19, 2012
From jason@cornsyrup.org and kelwert@mtu.edu - Most importantly, fixed mz_crc32() so it doesn't compute the wrong CRC-32's when mz_ulong is 64-bits. Temporarily/locally slammed in "typedef unsigned long mz_ulong" and re-ran a randomized regression test on ~500k files. Other stuff:
Eliminated a bunch of warnings when compiling with GCC 32-bit/64. Ran all examples, miniz.c, and tinfl.c through MSVC 2008's /analyze (static analysis) option and fixed all warnings (except for the silly "Use of the comma-operator in a tested expression.." analysis warning, which I purposely use to work around a MSVC compiler warning).
Created 32-bit and 64-bit Codeblocks projects/workspace. Built and tested Linux executables. The codeblocks workspace is compatible with Linux+Win32/x64. Added miniz_tester solution/project, which is a useful little app derived from LZHAM's tester app that I use as part of the regression test. Ran miniz.c and tinfl.c through another series of regression testing on ~500,000 files and archives. Modified example5.c so it purposely disables a bunch of high-level functionality (MINIZ_NO_STDIO, etc.). (Thanks to corysama for the MINIZ_NO_STDIO bug report.)
Fix ftell() usage in a few of the examples so they exit with an error on files which are too large (a limitation of the examples, not miniz itself). Fix fail logic handling in mz_zip_add_mem_to_archive_file_in_place() so it always calls mz_zip_writer_finalize_archive() and mz_zip_writer_end(), even if the file add fails.
- From jason@cornsyrup.org and kelwert@mtu.edu - Fix mz_crc32() so it doesn't compute the wrong CRC-32's when mz_ulong is 64-bit.
- Temporarily/locally slammed in "typedef unsigned long mz_ulong" and re-ran a randomized regression test on ~500k files.
- Eliminated a bunch of warnings when compiling with GCC 32-bit/64.
- Ran all examples, miniz.c, and tinfl.c through MSVC 2008's /analyze (static analysis) option and fixed all warnings (except for the silly
"Use of the comma-operator in a tested expression.." analysis warning, which I purposely use to work around a MSVC compiler warning).
- Created 32-bit and 64-bit Codeblocks projects/workspace. Built and tested Linux executables. The codeblocks workspace is compatible with Linux+Win32/x64.
- Added miniz_tester solution/project, which is a useful little app derived from LZHAM's tester app that I use as part of the regression test.
- Ran miniz.c and tinfl.c through another series of regression testing on ~500,000 files and archives.
- Modified example5.c so it purposely disables a bunch of high-level functionality (MINIZ_NO_STDIO, etc.). (Thanks to corysama for the MINIZ_NO_STDIO bug report.)
- Fix ftell() usage in examples so they exit with an error on files which are too large (a limitation of the examples, not miniz itself).
### v1.12 - 4/12/12
More comments, added low-level example5.c, fixed a couple minor level_and_flags issues in the archive API's.
level_and_flags can now be set to MZ_DEFAULT_COMPRESSION. Thanks to Bruce Dawson <bruced@valvesoftware.com> for the feedback/bug report.
### v1.11 - 5/28/11
Added statement from unlicense.org
### v1.10 - 5/27/11
- Substantial compressor optimizations:
- Level 1 is now ~4x faster than before. The L1 compressor's throughput now varies between 70-110MB/sec. on a Core i7 (actual throughput varies depending on the type of data, and x64 vs. x86).
- Improved baseline L2-L9 compression perf. Also, greatly improved compression perf. issues on some file types.
- Refactored the compression code for better readability and maintainability.
- Added level 10 compression level (L10 has slightly better ratio than level 9, but could have a potentially large drop in throughput on some files).
### v1.09 - 5/15/11
Initial stable release.

Some files were not shown because too many files have changed in this diff Show More