From b6bf90eebc4ce120024c490f4913c3959c992f77 Mon Sep 17 00:00:00 2001 From: Robert van den Breemen Date: Sun, 14 Apr 2024 23:29:19 +0200 Subject: [PATCH 01/13] Squashed commit of the following: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit commit ad255a50fabb9de6c075202b18a81f84197bd901 Author: Robert van den Breemen Date: Sat Apr 13 13:40:20 2024 +0200 Cleaning up the fix a bit commit 1c8485af72952f8ec7881c9a86103c9dc28470cd Merge: d0b5fbc 6d6c117 Author: Robert van den Breemen Date: Sat Apr 13 13:37:07 2024 +0200 Merge pull request #243 from DutchessNicole/main added provisions for password field commit d0b5fbcaaf4b9d0542da7090a691bf4db8db924e Author: Robert van den Breemen Date: Sat Apr 13 13:18:01 2024 +0200 fix: hiding the password in the UI commit 6d6c11715d5ab288ea1fd4baa9455fde311c70a6 Author: Nicole Koopmans Date: Fri Apr 12 16:27:56 2024 +0200 added provisions for password field commit 8d9da27f2fd2bf046c5c47e78f6bb7122db463ae Author: Robert van den Breemen Date: Mon Apr 8 21:54:53 2024 +0200 Cleaning up release flow commit 58609c8c5fe6ce25c5b0ea5893a51e1049b6a01f Author: Robert van den Breemen Date: Mon Apr 8 21:50:55 2024 +0200 Hmmm, fixing idents and space in yml commit b4a0b2fbeda6f5594458d0684e34228592164d81 Author: Robert van den Breemen Date: Mon Apr 8 21:47:10 2024 +0200 Adding one more setp commit baec3cb355f149f906d826fd79f98e74d96de13e Author: Robert van den Breemen Date: Mon Apr 8 21:43:27 2024 +0200 fixing the release workflow by adding setup commit 054866b8afacfed6d15d63f0130b83d91cd56673 Author: Robert van den Breemen Date: Mon Apr 8 21:37:27 2024 +0200 trying to call build from release flow commit 20cf3adda714cc7ce1ae631b07136c1bb54dbdb2 Author: Robert van den Breemen Date: Wed Apr 3 23:13:09 2024 +0200 Adding release build artifacts to release commit c6572d40eb7f87d1241232d03d929ff0f14e1df1 Author: Robert van den Breemen Date: Wed Apr 3 23:04:30 2024 +0200 Update release workflow to nodejs20 commit 3f0320f41ffe6aa237c3468df3f3a9b79ef513a4 Author: Robert van den Breemen Date: Tue Apr 2 18:32:39 2024 +0200 rollback changes index.js commit 6752fdfc8e368e09ce9f14ec095152d11714ff51 Author: Robert van den Breemen Date: Mon Apr 1 21:49:18 2024 +0200 Fixed all status functions commit aa4ea299ae0ad3031dfe9d769b403213322f8c85 Author: Robert van den Breemen Date: Mon Apr 1 09:26:25 2024 +0200 Fix APIGW, make it dependend on localURL (index.js) Fix status value for REST API, use OR instead of AND operator commit 121461173af48d2b46b41ffe523597cfa607de09 Author: Robert van den Breemen Date: Mon Mar 18 00:53:33 2024 +0100 Okay, testing workflow action build commit baae5e0b67e51dae50af9793a02291210c8a36c6 Author: Robert van den Breemen Date: Mon Mar 18 00:35:21 2024 +0100 Fix: Fixing filesystem rename commit ea5465777cd135f763806065e7660050110825c5 Author: Robert van den Breemen Date: Mon Mar 18 00:32:26 2024 +0100 Fix: one more change commit ac10b1d8835c3631a08f56cc8f1c38de7a00bbc8 Author: Robert van den Breemen Date: Mon Mar 18 00:26:00 2024 +0100 Fix: Trying to get a clean filesystem rename commit bb0eabe319e125ed63409d222e2c025f8fab3bf7 Author: Robert van den Breemen Date: Mon Mar 18 00:09:33 2024 +0100 Changes to make file, and build action. To simplify it commit 308ce1388dd21e9e06ae64bc5da5c7f8f5ba13c5 Author: Robert van den Breemen Date: Sun Mar 17 23:41:37 2024 +0100 Fix: adding basename to mv command commit 2617630ecee51ceebf4303112f306cae2125abcb Author: Robert van den Breemen Date: Sun Mar 17 23:38:04 2024 +0100 Fix: more difficult than you think commit ddeca02371349765899060b16eb2d4dca770e077 Author: Robert van den Breemen Date: Sun Mar 17 23:30:12 2024 +0100 Fix: filename pattern commit 7fe322e72b3237c56bd42a5be24bd40e8e1df84e Author: Robert van den Breemen Date: Sun Mar 17 23:25:11 2024 +0100 Fix: the moving of the make results commit 0976cca684842edb927136b06817026bcf4565d7 Author: Robert van den Breemen Date: Sun Mar 17 23:11:24 2024 +0100 Fix block mapping commit 42a8c82a9b31498b9158986678b9384c87ceb78f Author: Robert van den Breemen Date: Sun Mar 17 23:08:33 2024 +0100 Fixing move of files after build commit 7fe61d339fd453224356b1f8843938f9cebe3be1 Author: Robert van den Breemen Date: Sun Mar 17 21:56:31 2024 +0100 Fix: remove the double astrix commit 167c54954926c95da0ad92915c14eb5c69bf68d1 Author: Robert van den Breemen Date: Sun Mar 17 21:55:53 2024 +0100 fix: upload artifacts from build directory commit ebc03c86d247fe03410e085d75a20e848ed63d54 Author: Robert van den Breemen Date: Sun Mar 17 21:50:00 2024 +0100 Add create build directory commit de2beaf22c19a7a1f35f23cc5e8dae26dd8a147b Author: Robert van den Breemen Date: Sun Mar 17 21:45:50 2024 +0100 run semver step before rest, and fix filesystem building by adding shell: bash commit 2f34aeb771b616f28f725662c5172f285f8e4a88 Author: Robert van den Breemen Date: Sun Mar 17 18:10:41 2024 +0100 Trying to move & rename in the CI pipeline commit d6c6ddc75ccd078381d6d9bd38635feb52ede92f Author: Robert van den Breemen Date: Sun Mar 17 18:07:19 2024 +0100 renaming all files to correct semver version commit cd083907fc616fd76cf6d6651c149b32b57a146b Author: Robert van den Breemen Date: Sun Mar 17 18:02:02 2024 +0100 Update action.yml commit 912f0e857a5ca0ddd9fa280df1e7f31717ec6b91 Author: Robert van den Breemen Date: Sun Mar 17 17:56:21 2024 +0100 Updates to CI Build actions commit c531dece4607498f4ca4a89e971227cfead4f6e2 Author: Robert van den Breemen Date: Sun Mar 17 12:02:38 2024 +0100 Update main.yml commit 082f2f5c2d1c1ac5767b7b68d2e783216dd2764a Author: Robert van den Breemen Date: Sun Mar 17 11:57:19 2024 +0100 Just to update the binaries and test the workflow in github commit d99f2728705d3b11b3a41c6843e315f7f42d1340 Author: Robert van den Breemen Date: Tue Sep 12 23:29:47 2023 +0200 Another fix by Sergantd commit 827df64c2bee3f914690adef6cbd68260d8fcfef Author: Robert van den Breemen Date: Tue Sep 12 21:08:30 2023 +0200 Fixing a " by sergantd commit ef30af634f2954a4c5aaa9d837465b0c9cbdf717 Author: Robert van den Breemen Date: Sun Jul 23 22:51:08 2023 +0200 Update README.md commit 1ecc24036bcbaba20acb4aa6824810dc69407d4e Merge: 3874336 45dc372 Author: Robert van den Breemen Date: Sun May 14 09:22:31 2023 +0200 Merge branch 'dev' of https://github.com/rvdbreemen/OTGW-firmware into dev commit 3874336409d9d569ea1d02593f9a6c72d66f7575 Author: Robert van den Breemen Date: Wed May 10 20:37:34 2023 +0200 Add more sensors for HA, so SAT will easily integrate commit 45dc37267ce3b717401a234a6ab7666b4a8c6b4f Merge: 4b94231 0c0c071 Author: Robert van den Breemen Date: Wed May 10 20:35:40 2023 +0200 Merge pull request #220 from brhahlen/dev Fix CI Pipeline commit 0c0c0719b115f6358c94d9c474b744d2e222108d Author: Ben Hählen Date: Wed May 10 11:16:34 2023 +0200 Fixing CI Pipeline commit 8fab46bb3afed302747c74e6373bbbec727ae539 Author: Ben Hählen Date: Wed May 10 11:09:25 2023 +0200 Update Makefile commit efa49afa00d8547e534969d842a7881ccf4a91aa Author: Ben Hählen Date: Wed May 10 11:07:39 2023 +0200 Update Makefile Trying to fix build commit 4b94231959131f32070abe77692518ada9d3f949 Author: Robert van den Breemen Date: Tue May 9 23:45:01 2023 +0200 removing renovate.json from tree commit 9000d6cc8f6859dec0d94a9980b716cc61d6cf61 Author: Robert van den Breemen Date: Tue May 9 23:30:36 2023 +0200 cleanup transfer.dat in wrong place commit 259eb21c1d0114c2bc965372dee43ca2449ba079 Merge: 1214689 7b36109 Author: Robert van den Breemen Date: Fri May 5 21:10:24 2023 +0200 Merge pull request #218 from mcc05/dev removed unit_of_measure from items that have none commit 7b36109dce025c830f2051cb940bdc0fa32189f5 Author: mcc05 <38889743+mcc05@users.noreply.github.com> Date: Thu May 4 08:34:05 2023 +0100 removed unit_of_measure from items that have none commit 12146893b84000de05a34d63d68271208d7bc2cc Merge: bba1ca8 af09911 Author: Robert van den Breemen Date: Sat Apr 15 10:29:30 2023 +0200 Merge pull request #216 from hgokduman/dev Update index.js commit af0991142578223c834525aa8419518a8d16e89f Author: Halim Date: Tue Apr 11 09:46:35 2023 +0200 Update index.js Enable support for https when OTGW is behind a reverse proxy. commit bba1ca831315c19e71f7a977e635e66f314b6f94 Author: Robert van den Breemen Date: Sat Mar 18 14:23:12 2023 +0100 Revert "Turning off WTD during setup" This reverts commit 10b24b643a3f5cf2cb60b7c0da87a31145b473a8. commit 10b24b643a3f5cf2cb60b7c0da87a31145b473a8 Author: Robert van den Breemen Date: Thu Mar 16 22:49:59 2023 +0100 Turning off WTD during setup commit 9b6336a8fef4b3099bb4dde185cea1a5f6accfc8 Merge: 42216c5 301d6a1 Author: Robert van den Breemen Date: Thu Mar 16 22:10:07 2023 +0100 Merge branch 'main' into dev commit 42216c539054c7c2dce038fc9cae24092152766d Author: Robert van den Breemen Date: Tue Mar 14 23:13:48 2023 +0100 Update README.md commit cc1c894e54874ff3a9e91873ccf108652191d31f Author: Robert van den Breemen Date: Tue Mar 14 23:13:11 2023 +0100 Update readme for 0.10.2 maintaince release commit c73b2424068415e8361f98c9407ec46ccabb8355 Merge: 67a443e 87e4f7e Author: Robert van den Breemen Date: Tue Mar 14 22:59:47 2023 +0100 Merge branch 'main' into dev commit 67a443e86d31a5fd3402458840597740cfdbedc1 Author: Robert van den Breemen Date: Tue Mar 14 22:53:21 2023 +0100 Update firmware hex files to 6.5 and 5.8 commit 2d64148d127e7d201da92e43683624f498d28459 Author: Robert van den Breemen Date: Tue Mar 14 22:26:17 2023 +0100 fix the 0bytes on update Pic firmware, by downgrading the core to 2.7.4 commit fa737be11ea7eac4b8e333d210d850b25e97a3e7 Author: Robert van den Breemen Date: Sun Feb 26 21:07:11 2023 +0100 Adding a little memory for use with larger settings... NTP longer FQDN fix commit 141d6bf6f73ccfafd8eb3ec6b1788a479cf1df1c Merge: d84c439 d4d33c7 Author: Robert van den Breemen Date: Sat Feb 18 20:31:58 2023 +0100 Merge branch 'dev' into dev-more-actions commit d84c4397a1d89a09c02b25cbb626a7072c3135cf Author: Robert van den Breemen Date: Sat Feb 18 20:26:02 2023 +0100 Trying to build a relase system commit d4d33c7894a023d92dad3812692c709dbac1d274 Author: Robert van den Breemen Date: Mon Feb 13 21:43:43 2023 +0100 Fix for hostname to wifi (credits to @hvxl) commit 1d8f80b046fad79d935da1818b61cfa57ec1982f Author: Robert van den Breemen Date: Sun Feb 12 10:49:12 2023 +0100 updating .gitignore commit 997e93749d64c5b251355c6fa51c2e739e6df1b7 Author: Robert van den Breemen Date: Sat Feb 11 13:29:19 2023 +0100 config .gitignore commit 867432a90409cb855a7f52ae491bdc5bcb3b6e56 Author: Robert van den Breemen Date: Sat Feb 11 13:21:10 2023 +0100 Removing git submodules from src tree --- .github/actions/build/action.yml | 28 ++++++++++------- .github/actions/build/transfer.dat | 28 ----------------- .github/actions/setup/action.yml | 2 +- .github/workflows/main.yml | 2 +- .github/workflows/release.yml | 13 ++++---- LICENSE | 2 +- Makefile | 48 ++++++++++++++++-------------- OTGW-Core.h | 2 +- OTGW-Core.ino | 6 ++-- README.md | 4 +-- data/index.js | 10 +++++-- data/mqttha.cfg | 22 ++++++++++---- renovate.json | 5 ---- restAPI.ino | 5 ++-- version.h | 24 +++++++-------- 15 files changed, 98 insertions(+), 103 deletions(-) delete mode 100644 .github/actions/build/transfer.dat delete mode 100644 renovate.json diff --git a/.github/actions/build/action.yml b/.github/actions/build/action.yml index 2a6f4083..54ef2ac4 100644 --- a/.github/actions/build/action.yml +++ b/.github/actions/build/action.yml @@ -1,24 +1,32 @@ name: arduino-cli build description: Build using arduino-cli and makefile - runs: using: composite steps: + - id: semver + run: cat version.h | sed -n '/^#define _SEMVER_FULL.*$/s/^#.*"\(.*\)"$/semver=\1/p' >> $GITHUB_OUTPUT + shell: bash + - id: create-build-dir + run: mkdir -p build + shell: bash - id: build - run: make -j$(nproc) + run: | + make -j$(nproc) + find build -type f + for file in build/**/*.ino.bin; do mv "$file" "build/$(basename -s .ino.bin ${file})-${{steps.semver.outputs.semver}}.ino.bin"; done + for file in build/**/*.ino.elf; do mv "$file" "build/$(basename -s .ino.elf ${file})-${{steps.semver.outputs.semver}}.ino.elf"; done shell: bash - id: filesys - run: make filesystem - shell: bash - - id: semver - run: cat version.h | sed -n '/^#define _SEMVER_FULL.*$/s/^#.*"\(.*\)"$/semver=\1/p' >> $GITHUB_OUTPUT + run: | + make filesystem + for file in build/*.ino.littlefs.bin; do mv "$file" "build/$(basename -s .ino.littlefs.bin $file).${{steps.semver.outputs.semver}}.littlefs.bin"; done shell: bash + - id: upload - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: OTGW-firmware-${{steps.semver.outputs.semver}} path: | - build/**/*.bin - build/**/*.elf - build/*.bin + build/*.elf + build/*.bin \ No newline at end of file diff --git a/.github/actions/build/transfer.dat b/.github/actions/build/transfer.dat deleted file mode 100644 index 51d0ae6a..00000000 --- a/.github/actions/build/transfer.dat +++ /dev/null @@ -1,28 +0,0 @@ -id version address size mask name -0 3.0 00 1 e0 SavedSettings -1 3.0 01 4 0 FunctionLED -2 3.0 e0 32 0 AlternativeCmd -3 4.0a3 d8 8 0 ThermResponse -4 4.0a6 01 1 0 FunctionGPIO -5 4.0a6 02 2 0 AwaySetpoint -1 4.0a6 04 6 0 FunctionLED -6 4.0a7 aa 16 0 UnknownFlags -1 4.0a9 06 6 0 FunctionLED -6 4.0a9 af 16 0 UnknownFlags -6 4.0a9.1 b1 16 0 UnknownFlags -6 4.0a10 b3 16 0 UnknownFlags -6 4.0a11.1 b5 16 0 UnknownFlags -0 4.0b0 00 1 80 SavedSettings -6 4.0b0 d0 16 0 UnknownFlags -3 4.0b0 d8 0 0 ThermResponse -7 4.0.1.1 130 1 0 ThermostatModel -7 4.1 0d 1 0 ThermostatModel -8 4.2.7 0e 1 cf Configuration -8 4.2.8 0e 1 ca Configuration -8 6.3 0e 1 c2 Configuration -9 5.5 0f 2 0 DHWSetting -9 6.0 0 0 0 DHWSetting -9 6.2 0f 2 0 DHWSetting -10 5.5 11 2 0 MaxCHSetting -10 6.0 0 0 0 MaxCHSetting -10 6.2 11 2 0 MaxCHSetting diff --git a/.github/actions/setup/action.yml b/.github/actions/setup/action.yml index 86236ead..ef108900 100644 --- a/.github/actions/setup/action.yml +++ b/.github/actions/setup/action.yml @@ -5,7 +5,7 @@ runs: using: composite steps: - id: python - uses: actions/setup-python@v4 + uses: actions/setup-python@v5 with: python-version: '3.x' - id: apt diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index e325266c..cb025621 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -13,6 +13,6 @@ jobs: build: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - uses: ./.github/actions/setup - uses: ./.github/actions/build diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 966ae554..0088b021 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -10,15 +10,16 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 + - name: Setup environment + uses: ./.github/actions/setup - name: Build - run: echo ${{ github.sha }} > Release.txt - - name: Test - run: cat Release.txt + uses: ./.github/actions/build - name: Release - uses: softprops/action-gh-release@v1 + uses: softprops/action-gh-release@v2 if: startsWith(github.ref, 'refs/tags/') with: files: | - Release.txt + build/*.elf + build/*.bin LICENSE \ No newline at end of file diff --git a/LICENSE b/LICENSE index dd8dec1f..d1ce6c17 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2021-2022 Robert van den Breemen +Copyright (c) 2021-2024 Robert van den Breemen Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/Makefile b/Makefile index a74a6704..33f4bcf5 100644 --- a/Makefile +++ b/Makefile @@ -11,8 +11,10 @@ CFLAGS = $(CFLAGS_DEFAULT) CLI := arduino-cli PLATFORM := esp8266:esp8266 -CFGFILE := arduino-cli.yaml -# bug in http stream, fallback to 2.7.4 +CFGFILE := $(PWD)/arduino/arduino-cli.yaml +# Add CLICFG command to add config file location to CLI command +CLICFG := $(CLI) --config-file $(CFGFILE) +# bug in http stream, fallback to 2.7.4 # ESP8266URL := https://github.com/esp8266/Arduino/releases/download/3.0.2/package_esp8266com_index.json ESP8266URL := https://github.com/esp8266/Arduino/releases/download/2.7.4/package_esp8266com_index.json LIBRARIES := libraries/WiFiManager libraries/ArduinoJson libraries/PubSubClient libraries/TelnetStream libraries/AceTime libraries/OneWire libraries/DallasTemperature @@ -28,8 +30,8 @@ TOOLS = $(wildcard arduino/packages/esp8266/hardware/esp8266/*/tools) ESPTOOL = python3 $(TOOLS)/esptool/esptool.py BOARD = $(PLATFORM):d1_mini FQBN = $(BOARD):eesz=4M2M,xtal=160 -IMAGE = build/$(subst :,.,$(BOARD))/$(INO).bin -FILESYS = build/littlefs.bin +IMAGE = build/$(INO).bin +FILESYS = build/$(INO).littlefs.bin export PYTHONPATH = $(TOOLS)/pyserial @@ -48,12 +50,12 @@ distclean: clean $(CFGFILE): $(CLI) config init --dest-file $(CFGFILE) - $(CLI) config set board_manager.additional_urls $(ESP8266URL) - $(CLI) config set directories.data $(PWD)/arduino - $(CLI) config set directories.downloads $(PWD)/staging - $(CLI) config set directories.user $(PWD) - $(CLI) config set sketch.always_export_binaries true - $(CLI) config set library.enable_unsafe_install true + $(CLICFG) config set directories.data $(PWD)/arduino + $(CLICFG) config set board_manager.additional_urls $(ESP8266URL) + $(CLICFG) config set directories.downloads $(PWD)/staging + $(CLICFG) config set directories.user $(PWD) + $(CLICFG) config set sketch.always_export_binaries true + $(CLICFG) config set library.enable_unsafe_install true ## # Make sure CFG is updated before libraries are called. @@ -61,43 +63,43 @@ $(CFGFILE): $(LIBRARIES): | $(CFGFILE) $(BOARDS): | $(CFGFILE) - $(CLI) core update-index - $(CLI) core install $(PLATFORM) + $(CLICFG) core update-index + $(CLICFG) core install $(PLATFORM) refresh: | $(CFGFILE) - $(CLI) lib update-index + $(CLICFG) lib update-index flush: | $(CFGFILE) - $(CLI) cache clean + $(CLICFG) cache clean libraries/WiFiManager: | $(BOARDS) - $(CLI) lib install WiFiManager@2.0.15-rc.1 + $(CLICFG) lib install WiFiManager@2.0.15-rc.1 libraries/ArduinoJson: - $(CLI) lib install ArduinoJson@6.17.2 + $(CLICFG) lib install ArduinoJson@6.17.2 libraries/PubSubClient: - $(CLI) lib install pubsubclient@2.8.0 + $(CLICFG) lib install pubsubclient@2.8.0 libraries/TelnetStream: - $(CLI) lib install TelnetStream@1.2.4 + $(CLICFG) lib install TelnetStream@1.2.4 libraries/AceTime: - $(CLI) lib install Acetime@2.0.1 + $(CLICFG) lib install Acetime@2.0.1 # libraries/Time: # $(CLI) lib install --git-url https://github.com/PaulStoffregen/Time # # https://github.com/PaulStoffregen/Time/archive/refs/tags/v1.6.1.zip libraries/OneWire: - $(CLI) lib install OneWire@2.3.6 + $(CLICFG) lib install OneWire@2.3.6 libraries/DallasTemperature: | libraries/OneWire - $(CLI) lib install DallasTemperature@3.9.0 + $(CLICFG) lib install DallasTemperature@3.9.0 $(IMAGE): $(BOARDS) $(LIBRARIES) $(SOURCES) $(info Build code) - $(CLI) compile --config-file $(CFGFILE) --fqbn=$(FQBN) --warnings default --verbose --build-property compiler.cpp.extra_flags="$(CFLAGS)" + $(CLICFG) compile --fqbn=$(FQBN) --warnings default --verbose --build-property compiler.cpp.extra_flags="$(CFLAGS)" filesystem: $(FILESYS) @@ -117,7 +119,7 @@ $(PROJ).zip: $(PROJ)-fw.bin $(PROJ)-fs.bin # Build the image with debugging output debug: CFLAGS = $(CFLAGS_DEFAULT) -DDEBUG debug: $(IMAGE) - + # Load only the sketch into the device upload: $(IMAGE) $(ESPTOOL) --port $(PORT) -b $(BAUD) write_flash 0x0 $(IMAGE) diff --git a/OTGW-Core.h b/OTGW-Core.h index 76687d77..e9485cc5 100644 --- a/OTGW-Core.h +++ b/OTGW-Core.h @@ -327,7 +327,7 @@ enum OpenThermMessageID { { 12, OT_READ , ot_u8u8, "FHBsize", "Size of Fault-History-Buffer supported by slave", "" }, { 13, OT_READ , ot_u8u8, "FHBindexFHBvalue", "Index number / Value of referred-to fault-history buffer entry", "" }, { 14, OT_WRITE , ot_f88, "MaxRelModLevelSetting", "Maximum relative modulation level setting", "%" }, - { 15, OT_READ , ot_u8u8, "MaxCapacityMinModLevell", "Maximum boiler capacity (kW) / Minimum boiler modulation level(%)", "kW/%" }, + { 15, OT_READ , ot_u8u8, "MaxCapacityMinModLevel", "Maximum boiler capacity (kW) / Minimum boiler modulation level(%)", "kW/%" }, { 16, OT_WRITE , ot_f88, "TrSet", "Room Setpoint", "°C" }, { 17, OT_READ , ot_f88, "RelModLevel", "Relative Modulation Level", "%" }, { 18, OT_READ , ot_f88, "CHPressure", "CH water pressure", "bar" }, diff --git a/OTGW-Core.ino b/OTGW-Core.ino index f6a94504..c79a496c 100644 --- a/OTGW-Core.ino +++ b/OTGW-Core.ino @@ -669,7 +669,7 @@ void print_status(uint16_t& value) if (is_value_valid(OTdata, OTlookupitem)){ // AddLogf("Status u16 [%04x] _value [%04x] hb [%02x] lb [%02x]", OTdata.u16(), _value, OTdata.valueHB, OTdata.valueLB); - value = (OTcurrentSystemState.MasterStatus<<8) & OTcurrentSystemState.SlaveStatus; + value = (OTcurrentSystemState.MasterStatus<<8) | OTcurrentSystemState.SlaveStatus; } } @@ -706,7 +706,7 @@ void print_solar_storage_status(uint16_t& value) } if (is_value_valid(OTdata, OTlookupitem)){ //OTGWDebugTf(PSTR("Solar Storage Master / Slave Mode u16 [%04x] _value [%04x] hb [%02x] lb [%02x]"), OTdata.u16(), _value, OTdata.valueHB, OTdata.valueLB); - value = (OTcurrentSystemState.SolarMasterStatus<<8) & OTcurrentSystemState.SolarSlaveStatus; + value = (OTcurrentSystemState.SolarMasterStatus<<8) | OTcurrentSystemState.SolarSlaveStatus; } } @@ -786,7 +786,7 @@ void print_statusVH(uint16_t& value) if (is_value_valid(OTdata, OTlookupitem)){ //OTGWDebugTf(PSTR("Status u16 [%04x] _value [%04x] hb [%02x] lb [%02x]"), OTdata.u16(), _value, OTdata.valueHB, OTdata.valueLB); - value = (OTcurrentSystemState.MasterStatusVH<<8) & OTcurrentSystemState.SlaveStatusVH; + value = (OTcurrentSystemState.MasterStatusVH<<8) | OTcurrentSystemState.SlaveStatusVH; } } diff --git a/README.md b/README.md index f108f7cc..ffda78f7 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ OpenTherm Nodoshop OTGW hardware - an ESP8266 firmware This project is an firmware for the Nodoshop OTGW hardware, based on ESP8266 devkits. -Starting with version 2.3 of the Nodoshop hardware the devkit has changed from NodeMCU to a Wemos D1mini. This is fully supported by the hardware and this firmware. +Starting with version 2.3 of the Nodoshop hardware the devkit has changed from NodeMCU to a Wemos D1mini. This is fully supported by the hardware and this firmware. Supporting hardware version are: | Version | Hardware supported | @@ -56,7 +56,7 @@ To do: - Instant update of webUI using websockets - Showing log of OT messages using websockets -Looking for the documentation, go here (work in progress):
https://github.com/rvdbreemen/OTGW-firmware/wiki/Documentation-of-OTGW-firmware +Looking for the documentation, go here (work in progress):
[Wiki with Documentation](https://github.com/rvdbreemen/OTGW-firmware/wiki) | Version | Release notes | |-|-| diff --git a/data/index.js b/data/index.js index 0b4eff46..5423ef39 100644 --- a/data/index.js +++ b/data/index.js @@ -8,8 +8,8 @@ ** TERMS OF USE: MIT License. See bottom of file. *************************************************************************** */ - const localURL='http://'+window.location.host; - const APIGW='http://'+window.location.host+'/api/'; + const localURL=window.location.protocol+'//'+window.location.host; + const APIGW=window.location.protocol+'//'+window.location.host+'/api/'; "use strict"; @@ -513,6 +513,12 @@ sInput.setAttribute("type", "text"); sInput.setAttribute("maxlength", data[i].maxlen); sInput.setAttribute("size", (data[i].maxlen > 20 ? 20 : data[i].maxlen)); + } + else if (data[i].type == "p") + { + sInput.setAttribute("type", "password"); + sInput.setAttribute("maxlength", data[i].maxlen); + sInput.setAttribute("size", (data[i].maxlen > 20 ? 20 : data[i].maxlen)); } else if (data[i].type == "f") { diff --git a/data/mqttha.cfg b/data/mqttha.cfg index 4cb178e3..5f71e3ea 100644 --- a/data/mqttha.cfg +++ b/data/mqttha.cfg @@ -121,6 +121,16 @@ 58 ; %homeassistant%/sensor/%node_id%/Hcratio/config ; {"avty_t": "%mqtt_pub_topic%", "dev": {"identifiers": "%node_id%", "manufacturer": "Schelte Bron", "model": "otgw-nodo", "name": "OpenTherm Gateway (%hostname%)", "sw_version": "%version%"}, "uniq_id": "%node_id%-Hcratio", "device_class": "temperature", "name": "%hostname%_OTC_heat_curve_ratio", "stat_t": "%mqtt_pub_topic%/DHWFlowRate", "unit_of_measurement": "°C", "value_template": "{{ value }}", "state_class" : "measurement" } 124 ; %homeassistant%/sensor/%node_id%/OpenThermVersionMaster/config ; {"avty_t": "%mqtt_pub_topic%", "dev": {"identifiers": "%node_id%", "manufacturer": "Schelte Bron", "model": "otgw-nodo", "name": "OpenTherm Gateway (%hostname%)", "sw_version": "%version%"}, "uniq_id": "%node_id%-OpenThermVersionMaster", "name": "%hostname%_Master_OT_protocol_version", "stat_t": "%mqtt_pub_topic%/OpenThermVersionMaster", "unit_of_measurement": "", "value_template": "{{ value }}" } 125 ; %homeassistant%/sensor/%node_id%/OpenThermVersionSlave/config ; {"avty_t": "%mqtt_pub_topic%", "dev": {"identifiers": "%node_id%", "manufacturer": "Schelte Bron", "model": "otgw-nodo", "name": "OpenTherm Gateway (%hostname%)", "sw_version": "%version%"}, "uniq_id": "%node_id%-OpenThermVersionSlave", "name": "%hostname%_Slave_OT_protocol_version", "stat_t": "%mqtt_pub_topic%/OpenThermVersionSlave", "unit_of_measurement": "", "value_template": "{{ value }}" } +// boundary values +15 ; %homeassistant%/sensor/%node_id%/MaxCapacityMinModLevel_lb_u8/config ; {"avty_t": "%mqtt_pub_topic%", "dev": {"identifiers": "%node_id%", "manufacturer": "Schelte Bron", "model": "otgw-nodo", "name": "OpenTherm Gateway (%hostname%)", "sw_version": "%version%"}, "uniq_id": "%node_id%-MaxCapacityMinModLevel_lb_u8", "device_class": "power_factor", "name": "%hostname%_MaxCapacityMinModLevel_lb_u8", "stat_t": "%mqtt_pub_topic%/MaxCapacityMinModLevel_lb_u8", "unit_of_measurement": "%", "value_template": "{{ value }}"} +15 ; %homeassistant%/sensor/%node_id%/MaxCapacityMinModLevel_hb_u8/config ; {"avty_t": "%mqtt_pub_topic%", "dev": {"identifiers": "%node_id%", "manufacturer": "Schelte Bron", "model": "otgw-nodo", "name": "OpenTherm Gateway (%hostname%)", "sw_version": "%version%"}, "uniq_id": "%node_id%-MaxCapacityMinModLevel_hb_u8", "device_class": "power", "name": "%hostname%_MaxCapacityMinModLevel_hb_u8", "stat_t": "%mqtt_pub_topic%/MaxCapacityMinModLevel_hb_u8", "unit_of_measurement": "kW", "value_template": "{{ value }}"} +48 ; %homeassistant%/sensor/%node_id%/TdhwSetUBTdhwSetLB_value_lb/config ; {"avty_t": "%mqtt_pub_topic%", "dev": {"identifiers": "%node_id%", "manufacturer": "Schelte Bron", "model": "otgw-nodo", "name": "OpenTherm Gateway (%hostname%)", "sw_version": "%version%"}, "uniq_id": "%node_id%-TdhwSetUBTdhwSetLB_value_lb", "device_class": "temperature", "name": "%hostname%_TdhwSetUBTdhwSetLB_value_lb", "stat_t": "%mqtt_pub_topic%/TdhwSetUBTdhwSetLB_value_lb", "unit_of_measurement": "°C", "value_template": "{{ value }}" } +48 ; %homeassistant%/sensor/%node_id%/TdhwSetUBTdhwSetLB_value_hb/config ; {"avty_t": "%mqtt_pub_topic%", "dev": {"identifiers": "%node_id%", "manufacturer": "Schelte Bron", "model": "otgw-nodo", "name": "OpenTherm Gateway (%hostname%)", "sw_version": "%version%"}, "uniq_id": "%node_id%-TdhwSetUBTdhwSetLB_value_hb", "device_class": "temperature", "name": "%hostname%_TdhwSetUBTdhwSetLB_value_hb", "stat_t": "%mqtt_pub_topic%/TdhwSetUBTdhwSetLB_value_hb", "unit_of_measurement": "°C", "value_template": "{{ value }}" } +49 ; %homeassistant%/sensor/%node_id%/MaxTSetUBMaxTSetLB_value_lb/config ; {"avty_t": "%mqtt_pub_topic%", "dev": {"identifiers": "%node_id%", "manufacturer": "Schelte Bron", "model": "otgw-nodo", "name": "OpenTherm Gateway (%hostname%)", "sw_version": "%version%"}, "uniq_id": "%node_id%-MaxTSetUBMaxTSetLB_value_lb", "device_class": "temperature", "name": "%hostname%_MaxTSetUBMaxTSetLB_value_lb", "stat_t": "%mqtt_pub_topic%/MaxTSetUBMaxTSetLB_value_lb", "unit_of_measurement": "°C", "value_template": "{{ value }}" } +49 ; %homeassistant%/sensor/%node_id%/MaxTSetUBMaxTSetLB_value_hb/config ; {"avty_t": "%mqtt_pub_topic%", "dev": {"identifiers": "%node_id%", "manufacturer": "Schelte Bron", "model": "otgw-nodo", "name": "OpenTherm Gateway (%hostname%)", "sw_version": "%version%"}, "uniq_id": "%node_id%-MaxTSetUBMaxTSetLB_value_hb", "device_class": "temperature", "name": "%hostname%_MaxTSetUBMaxTSetLB_value_hb", "stat_t": "%mqtt_pub_topic%/MaxTSetUBMaxTSetLB_value_hb", "unit_of_measurement": "°C", "value_template": "{{ value }}" } +50 ; %homeassistant%/sensor/%node_id%/HcratioUBHcratioLB_value_lb/config ; {"avty_t": "%mqtt_pub_topic%", "dev": {"identifiers": "%node_id%", "manufacturer": "Schelte Bron", "model": "otgw-nodo", "name": "OpenTherm Gateway (%hostname%)", "sw_version": "%version%"}, "uniq_id": "%node_id%-HcratioUBHcratioLB_value_lb", "device_class": "temperature", "name": "%hostname%_HcratioUBHcratioLB_value_lb", "stat_t": "%mqtt_pub_topic%/HcratioUBHcratioLB_value_lb", "unit_of_measurement": "°C", "value_template": "{{ value }}" } +50 ; %homeassistant%/sensor/%node_id%/HcratioUBHcratioLB_value_hb/config ; {"avty_t": "%mqtt_pub_topic%", "dev": {"identifiers": "%node_id%", "manufacturer": "Schelte Bron", "model": "otgw-nodo", "name": "OpenTherm Gateway (%hostname%)", "sw_version": "%version%"}, "uniq_id": "%node_id%-HcratioUBHcratioLB_value_hb", "device_class": "temperature", "name": "%hostname%_HcratioUBHcratioLB_value_hb", "stat_t": "%mqtt_pub_topic%/HcratioUBHcratioLB_value_hb", "unit_of_measurement": "°C", "value_template": "{{ value }}" } + // Statistics 116 ; %homeassistant%/sensor/%node_id%/BurnerStarts/config ; {"avty_t": "%mqtt_pub_topic%", "dev": {"identifiers": "%node_id%", "manufacturer": "Schelte Bron", "model": "otgw-nodo", "name": "OpenTherm Gateway (%hostname%)", "sw_version": "%version%"}, "uniq_id": "%node_id%-BurnerStarts", "name": "%hostname%_BurnerStarts", "stat_t": "%mqtt_pub_topic%/BurnerStarts", "unit_of_measurement": "", "value_template": "{{ value }}", "state_class" : "total_increasing" } 117 ; %homeassistant%/sensor/%node_id%/CHPumpStarts/config ; {"avty_t": "%mqtt_pub_topic%", "dev": {"identifiers": "%node_id%", "manufacturer": "Schelte Bron", "model": "otgw-nodo", "name": "OpenTherm Gateway (%hostname%)", "sw_version": "%version%"}, "uniq_id": "%node_id%-CHPumpStarts", "name": "%hostname%_CHPumpStarts", "stat_t": "%mqtt_pub_topic%/CHPumpStarts", "unit_of_measurement": "", "value_template": "{{ value }}", "state_class" : "total_increasing" } @@ -133,16 +143,16 @@ 113 ; %homeassistant%/sensor/%node_id%/BurnerUnsuccessfulStarts/config ; {"avty_t": "%mqtt_pub_topic%", "dev": {"identifiers": "%node_id%", "manufacturer": "Schelte Bron", "model": "otgw-nodo", "name": "OpenTherm Gateway (%hostname%)", "sw_version": "%version%"}, "uniq_id": "%node_id%-BurnerUnsuccessfulStarts", "name": "%hostname%_BurnerUnsuccessfulStarts", "stat_t": "%mqtt_pub_topic%/BurnerUnsuccessfulStarts", "unit_of_measurement": "", "value_template": "{{ value }}", "state_class" : "total_increasing" } 114 ; %homeassistant%/sensor/%node_id%/FlameSignalTooLow/config ; {"avty_t": "%mqtt_pub_topic%", "dev": {"identifiers": "%node_id%", "manufacturer": "Schelte Bron", "model": "otgw-nodo", "name": "OpenTherm Gateway (%hostname%)", "sw_version": "%version%"}, "uniq_id": "%node_id%-FlameSignalTooLow", "name": "%hostname%_FlameSignalTooLow", "stat_t": "%mqtt_pub_topic%/FlameSignalTooLow", "unit_of_measurement": "", "value_template": "{{ value }}" } // split -0 ; %homeassistant%/sensor/%node_id%/status_master/config ; {"avty_t": "%mqtt_pub_topic%", "dev": {"identifiers": "%node_id%", "manufacturer": "Schelte Bron", "model": "otgw-nodo", "name": "OpenTherm Gateway (%hostname%)", "sw_version": "%version%"}, "uniq_id": "%node_id%-status_master", "name": "%hostname%_Status_Master", "stat_t": "%mqtt_pub_topic%/status_master", "unit_of_measurement": "", "value_template": "{{ value }}" } -0 ; %homeassistant%/sensor/%node_id%/status_slave/config ; {"avty_t": "%mqtt_pub_topic%", "dev": {"identifiers": "%node_id%", "manufacturer": "Schelte Bron", "model": "otgw-nodo", "name": "OpenTherm Gateway (%hostname%)", "sw_version": "%version%"}, "uniq_id": "%node_id%-status_slave", "name": "%hostname%_Status_Slave", "stat_t": "%mqtt_pub_topic%/status_slave", "unit_of_measurement": "", "value_template": "{{ value }}" } +0 ; %homeassistant%/sensor/%node_id%/status_master/config ; {"avty_t": "%mqtt_pub_topic%", "dev": {"identifiers": "%node_id%", "manufacturer": "Schelte Bron", "model": "otgw-nodo", "name": "OpenTherm Gateway (%hostname%)", "sw_version": "%version%"}, "uniq_id": "%node_id%-status_master", "name": "%hostname%_Status_Master", "stat_t": "%mqtt_pub_topic%/status_master"} +0 ; %homeassistant%/sensor/%node_id%/status_slave/config ; {"avty_t": "%mqtt_pub_topic%", "dev": {"identifiers": "%node_id%", "manufacturer": "Schelte Bron", "model": "otgw-nodo", "name": "OpenTherm Gateway (%hostname%)", "sw_version": "%version%"}, "uniq_id": "%node_id%-status_slave", "name": "%hostname%_Status_Slave", "stat_t": "%mqtt_pub_topic%/status_slave"} // split 5 ; %homeassistant%/sensor/%node_id%/ASF_flags/config ; {"avty_t": "%mqtt_pub_topic%", "dev": {"identifiers": "%node_id%", "manufacturer": "Schelte Bron", "model": "otgw-nodo", "name": "OpenTherm Gateway (%hostname%)", "sw_version": "%version%"}, "uniq_id": "%node_id%-ASF_flags", "name": "%hostname%_Application_Specific_Fault", "stat_t": "%mqtt_pub_topic%/ASF_flags", "unit_of_measurement": "", "value_template": "{{ value }}" } 5 ; %homeassistant%/sensor/%node_id%/OEMFaultCode/config ; {"avty_t": "%mqtt_pub_topic%", "dev": {"identifiers": "%node_id%", "manufacturer": "Schelte Bron", "model": "otgw-nodo", "name": "OpenTherm Gateway (%hostname%)", "sw_version": "%version%"}, "uniq_id": "%node_id%-OEMFaultCode", "name": "%hostname%_OEMFaultCode", "stat_t": "%mqtt_pub_topic%/OEMFaultCode", "unit_of_measurement": "", "value_template": "{{ value }}" } // split -2 ; %homeassistant%/sensor/%node_id%/master_configuration/config ; {"avty_t": "%mqtt_pub_topic%", "dev": {"identifiers": "%node_id%", "manufacturer": "Schelte Bron", "model": "otgw-nodo", "name": "OpenTherm Gateway (%hostname%)", "sw_version": "%version%"}, "uniq_id": "%node_id%-master_configuration", "name": "%hostname%_Status_Master_Configuration", "stat_t": "%mqtt_pub_topic%/master_configuration", "unit_of_measurement": "", "value_template": "{{ value }}" } -2 ; %homeassistant%/sensor/%node_id%/master_memberid_code/config ; {"avty_t": "%mqtt_pub_topic%", "dev": {"identifiers": "%node_id%", "manufacturer": "Schelte Bron", "model": "otgw-nodo", "name": "OpenTherm Gateway (%hostname%)", "sw_version": "%version%"}, "uniq_id": "%node_id%-master_memberid_code", "name": "%hostname%_Status_Master_Memberid_Code", "stat_t": "%mqtt_pub_topic%/master_memberid_code", "unit_of_measurement": "", "value_template": "{{ value }}" } -3 ; %homeassistant%/sensor/%node_id%/slave_configuration/config ; {"avty_t": "%mqtt_pub_topic%", "dev": {"identifiers": "%node_id%", "manufacturer": "Schelte Bron", "model": "otgw-nodo", "name": "OpenTherm Gateway (%hostname%)", "sw_version": "%version%"}, "uniq_id": "%node_id%-slave_configuration", "name": "%hostname%_Status_Slave_Configuration", "stat_t": "%mqtt_pub_topic%/slave_configuration", "unit_of_measurement": "", "value_template": "{{ value }}" } -3 ; %homeassistant%/sensor/%node_id%/slave_memberid_code/config ; {"avty_t": "%mqtt_pub_topic%", "dev": {"identifiers": "%node_id%", "manufacturer": "Schelte Bron", "model": "otgw-nodo", "name": "OpenTherm Gateway (%hostname%)", "sw_version": "%version%"}, "uniq_id": "%node_id%-slave_memberid_code", "name": "%hostname%_Status_Slave_Memberid_Code", "stat_t": "%mqtt_pub_topic%/slave_memberid_code", "unit_of_measurement": "", "value_template": "{{ value }}" } +2 ; %homeassistant%/sensor/%node_id%/master_configuration/config ; {"avty_t": "%mqtt_pub_topic%", "dev": {"identifiers": "%node_id%", "manufacturer": "Schelte Bron", "model": "otgw-nodo", "name": "OpenTherm Gateway (%hostname%)", "sw_version": "%version%"}, "uniq_id": "%node_id%-master_configuration", "name": "%hostname%_Status_Master_Configuration", "stat_t": "%mqtt_pub_topic%/master_configuration"} +2 ; %homeassistant%/sensor/%node_id%/master_memberid_code/config ; {"avty_t": "%mqtt_pub_topic%", "dev": {"identifiers": "%node_id%", "manufacturer": "Schelte Bron", "model": "otgw-nodo", "name": "OpenTherm Gateway (%hostname%)", "sw_version": "%version%"}, "uniq_id": "%node_id%-master_memberid_code", "name": "%hostname%_Status_Master_Memberid_Code", "stat_t": "%mqtt_pub_topic%/master_memberid_code"} +3 ; %homeassistant%/sensor/%node_id%/slave_configuration/config ; {"avty_t": "%mqtt_pub_topic%", "dev": {"identifiers": "%node_id%", "manufacturer": "Schelte Bron", "model": "otgw-nodo", "name": "OpenTherm Gateway (%hostname%)", "sw_version": "%version%"}, "uniq_id": "%node_id%-slave_configuration", "name": "%hostname%_Status_Slave_Configuration", "stat_t": "%mqtt_pub_topic%/slave_configuration"} +3 ; %homeassistant%/sensor/%node_id%/slave_memberid_code/config ; {"avty_t": "%mqtt_pub_topic%", "dev": {"identifiers": "%node_id%", "manufacturer": "Schelte Bron", "model": "otgw-nodo", "name": "OpenTherm Gateway (%hostname%)", "sw_version": "%version%"}, "uniq_id": "%node_id%-slave_memberid_code", "name": "%hostname%_Status_Slave_Memberid_Code", "stat_t": "%mqtt_pub_topic%/slave_memberid_code"} // split 101 ; %homeassistant%/sensor/%node_id%/solar_storage_master_mode/config ; {"avty_t": "%mqtt_pub_topic%", "dev": {"identifiers": "%node_id%", "manufacturer": "Schelte Bron", "model": "otgw-nodo", "name": "OpenTherm Gateway (%hostname%)", "sw_version": "%version%"}, "uniq_id": "%node_id%-solar_storage_master_mode", "name": "%hostname%_solar_storage_master_mode", "stat_t": "%mqtt_pub_topic%/solar_storage_master_mode", "unit_of_measurement": "", "value_template": "{{ value }}" } 101 ; %homeassistant%/sensor/%node_id%/solar_storage_mode_status/config ; {"avty_t": "%mqtt_pub_topic%", "dev": {"identifiers": "%node_id%", "manufacturer": "Schelte Bron", "model": "otgw-nodo", "name": "OpenTherm Gateway (%hostname%)", "sw_version": "%version%"}, "uniq_id": "%node_id%-solar_storage_mode_status", "name": "%hostname%_solar_storage_mode_status", "stat_t": "%mqtt_pub_topic%/solar_storage_mode_status", "unit_of_measurement": "", "value_template": "{{ value }}" } diff --git a/renovate.json b/renovate.json deleted file mode 100644 index f45d8f11..00000000 --- a/renovate.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "extends": [ - "config:base" - ] -} diff --git a/restAPI.ino b/restAPI.ino index 5dee78d2..c2943df5 100644 --- a/restAPI.ino +++ b/restAPI.ino @@ -421,7 +421,8 @@ void sendDeviceSettings() RESTDebugTln(F("sending device settings ...\r")); sendStartJsonObj("settings"); - + + //sendJsonSettingObj("string", settingString, "p", sizeof(settingString)-1); //sendJsonSettingObj("string", settingString, "s", sizeof(settingString)-1); //sendJsonSettingObj("float", settingFloat, "f", 0, 10, 5); //sendJsonSettingObj("intager", settingInteger , "i", 2, 60); @@ -431,7 +432,7 @@ void sendDeviceSettings() sendJsonSettingObj("mqttbroker", CSTR(settingMQTTbroker), "s", 32); sendJsonSettingObj("mqttbrokerport", settingMQTTbrokerPort, "i", 0, 65535); sendJsonSettingObj("mqttuser", CSTR(settingMQTTuser), "s", 32); - sendJsonSettingObj("mqttpasswd", CSTR(settingMQTTpasswd), "s", 100); + sendJsonSettingObj("mqttpasswd", CSTR(settingMQTTpasswd), "p", 100); sendJsonSettingObj("mqtttoptopic", CSTR(settingMQTTtopTopic), "s", 15); sendJsonSettingObj("mqtthaprefix", CSTR(settingMQTThaprefix), "s", 20); sendJsonSettingObj("mqttharebootdetection", settingMQTTharebootdetection, "b"); diff --git a/version.h b/version.h index da47c3f0..37145f1a 100644 --- a/version.h +++ b/version.h @@ -1,16 +1,16 @@ //The version number conforms to semver.org format #define _VERSION_MAJOR 0 #define _VERSION_MINOR 10 -#define _VERSION_PATCH 2 -#define _VERSION_BUILD 2088 -#define _VERSION_GITHASH "50c3ed2" -//#define _VERSION_PRERELEASE beta //uncomment to define prerelease labels: alpha - beta - rc -#define _VERSION_DATE "14-03-2023" -#define _VERSION_TIME "23:58:40" -#define _SEMVER_CORE "0.10.2" -#define _SEMVER_BUILD "0.10.2+2088" -#define _SEMVER_GITHASH "0.10.2+50c3ed2" -#define _SEMVER_FULL "0.10.2+50c3ed2" -#define _SEMVER_NOBUILD "0.10.2 (14-03-2023)" -#define _VERSION "0.10.2+50c3ed2 (14-03-2023)" +#define _VERSION_PATCH 3 +#define _VERSION_BUILD 2112 +#define _VERSION_GITHASH "1c8485a" +#define _VERSION_PRERELEASE beta +#define _VERSION_DATE "13-04-2024" +#define _VERSION_TIME "13:40:09" +#define _SEMVER_CORE "0.10.3" +#define _SEMVER_BUILD "0.10.3+2112" +#define _SEMVER_GITHASH "0.10.3+1c8485a" +#define _SEMVER_FULL "0.10.3-beta+1c8485a" +#define _SEMVER_NOBUILD "0.10.3-beta (13-04-2024)" +#define _VERSION "0.10.3-beta+1c8485a (13-04-2024)" //The version information is created automatically, more information here: https://github.com/rvdbreemen/autoinc-semver From d8e070d25793761ec6d322edbe2ced322843f41d Mon Sep 17 00:00:00 2001 From: Robert van den Breemen Date: Mon, 15 Apr 2024 20:19:21 +0200 Subject: [PATCH 02/13] before update 0.10.3 --- version.h | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/version.h b/version.h index 37145f1a..1cf75b0d 100644 --- a/version.h +++ b/version.h @@ -2,15 +2,15 @@ #define _VERSION_MAJOR 0 #define _VERSION_MINOR 10 #define _VERSION_PATCH 3 -#define _VERSION_BUILD 2112 -#define _VERSION_GITHASH "1c8485a" -#define _VERSION_PRERELEASE beta -#define _VERSION_DATE "13-04-2024" -#define _VERSION_TIME "13:40:09" +#define _VERSION_BUILD 2114 +#define _VERSION_GITHASH "b6bf90e" +//#define _VERSION_PRERELEASE beta //uncomment to define prerelease labels: alpha - beta - rc +#define _VERSION_DATE "14-04-2024" +#define _VERSION_TIME "23:30:44" #define _SEMVER_CORE "0.10.3" -#define _SEMVER_BUILD "0.10.3+2112" -#define _SEMVER_GITHASH "0.10.3+1c8485a" -#define _SEMVER_FULL "0.10.3-beta+1c8485a" -#define _SEMVER_NOBUILD "0.10.3-beta (13-04-2024)" -#define _VERSION "0.10.3-beta+1c8485a (13-04-2024)" +#define _SEMVER_BUILD "0.10.3+2114" +#define _SEMVER_GITHASH "0.10.3+b6bf90e" +#define _SEMVER_FULL "0.10.3+b6bf90e" +#define _SEMVER_NOBUILD "0.10.3 (14-04-2024)" +#define _VERSION "0.10.3+b6bf90e (14-04-2024)" //The version information is created automatically, more information here: https://github.com/rvdbreemen/autoinc-semver From 019a3ca345d04e1a779124baadebf50be7d8f931 Mon Sep 17 00:00:00 2001 From: Robert van den Breemen Date: Mon, 15 Apr 2024 20:22:52 +0200 Subject: [PATCH 03/13] Update version.h --- version.h | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/version.h b/version.h index 1cf75b0d..a898648d 100644 --- a/version.h +++ b/version.h @@ -2,15 +2,15 @@ #define _VERSION_MAJOR 0 #define _VERSION_MINOR 10 #define _VERSION_PATCH 3 -#define _VERSION_BUILD 2114 -#define _VERSION_GITHASH "b6bf90e" +#define _VERSION_BUILD 2116 +#define _VERSION_GITHASH "d8e070d" //#define _VERSION_PRERELEASE beta //uncomment to define prerelease labels: alpha - beta - rc -#define _VERSION_DATE "14-04-2024" -#define _VERSION_TIME "23:30:44" +#define _VERSION_DATE "15-04-2024" +#define _VERSION_TIME "20:22:21" #define _SEMVER_CORE "0.10.3" -#define _SEMVER_BUILD "0.10.3+2114" -#define _SEMVER_GITHASH "0.10.3+b6bf90e" -#define _SEMVER_FULL "0.10.3+b6bf90e" -#define _SEMVER_NOBUILD "0.10.3 (14-04-2024)" -#define _VERSION "0.10.3+b6bf90e (14-04-2024)" +#define _SEMVER_BUILD "0.10.3+2116" +#define _SEMVER_GITHASH "0.10.3+d8e070d" +#define _SEMVER_FULL "0.10.3+d8e070d" +#define _SEMVER_NOBUILD "0.10.3 (15-04-2024)" +#define _VERSION "0.10.3+d8e070d (15-04-2024)" //The version information is created automatically, more information here: https://github.com/rvdbreemen/autoinc-semver From e37be82369519fd1a37a6b83e74c1c57031db88c Mon Sep 17 00:00:00 2001 From: Robert van den Breemen Date: Mon, 15 Apr 2024 23:22:23 +0200 Subject: [PATCH 04/13] before update 0.10.3 --- version.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/version.h b/version.h index a898648d..bf14a5fa 100644 --- a/version.h +++ b/version.h @@ -2,15 +2,15 @@ #define _VERSION_MAJOR 0 #define _VERSION_MINOR 10 #define _VERSION_PATCH 3 -#define _VERSION_BUILD 2116 -#define _VERSION_GITHASH "d8e070d" +#define _VERSION_BUILD 2117 +#define _VERSION_GITHASH "019a3ca" //#define _VERSION_PRERELEASE beta //uncomment to define prerelease labels: alpha - beta - rc #define _VERSION_DATE "15-04-2024" -#define _VERSION_TIME "20:22:21" +#define _VERSION_TIME "23:21:15" #define _SEMVER_CORE "0.10.3" -#define _SEMVER_BUILD "0.10.3+2116" -#define _SEMVER_GITHASH "0.10.3+d8e070d" -#define _SEMVER_FULL "0.10.3+d8e070d" +#define _SEMVER_BUILD "0.10.3+2117" +#define _SEMVER_GITHASH "0.10.3+019a3ca" +#define _SEMVER_FULL "0.10.3+019a3ca" #define _SEMVER_NOBUILD "0.10.3 (15-04-2024)" -#define _VERSION "0.10.3+d8e070d (15-04-2024)" +#define _VERSION "0.10.3+019a3ca (15-04-2024)" //The version information is created automatically, more information here: https://github.com/rvdbreemen/autoinc-semver From 1e5f2edf6c8d8101c83ee0e41e5dbc5844e44eee Mon Sep 17 00:00:00 2001 From: Robert van den Breemen Date: Mon, 15 Apr 2024 23:45:51 +0200 Subject: [PATCH 05/13] before update 0.10.3 --- MQTTstuff.ino.tmp | 698 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 698 insertions(+) create mode 100644 MQTTstuff.ino.tmp diff --git a/MQTTstuff.ino.tmp b/MQTTstuff.ino.tmp new file mode 100644 index 00000000..45be66b6 --- /dev/null +++ b/MQTTstuff.ino.tmp @@ -0,0 +1,698 @@ +/* +*************************************************************************** +** Program : MQTTstuff +** Version : v0.10.2 +** +** Copyright (c) 2021-2023 Robert van den Breemen +** Modified version from (c) 2020 Willem Aandewiel +** +** TERMS OF USE: MIT License. See bottom of file. +*************************************************************************** +*/ + +#include // MQTT client publish and subscribe functionality + +#define MQTTDebugTln(...) ({ if (bDebugMQTT) DebugTln(__VA_ARGS__); }) +#define MQTTDebugln(...) ({ if (bDebugMQTT) Debugln(__VA_ARGS__); }) +#define MQTTDebugTf(...) ({ if (bDebugMQTT) DebugTf(__VA_ARGS__); }) +#define MQTTDebugf(...) ({ if (bDebugMQTT) Debugf(__VA_ARGS__); }) +#define MQTTDebugT(...) ({ if (bDebugMQTT) DebugT(__VA_ARGS__); }) +#define MQTTDebug(...) ({ if (bDebugMQTT) Debug(__VA_ARGS__); }) + +// Declare some variables within global scope + +static IPAddress MQTTbrokerIP; +static char MQTTbrokerIPchar[20]; + +static PubSubClient MQTTclient(wifiClient); + +int8_t reconnectAttempts = 0; +char lastMQTTtimestamp[15] = ""; + +enum states_of_MQTT { MQTT_STATE_INIT, MQTT_STATE_TRY_TO_CONNECT, MQTT_STATE_IS_CONNECTED, MQTT_STATE_WAIT_CONNECTION_ATTEMPT, MQTT_STATE_WAIT_FOR_RECONNECT, MQTT_STATE_ERROR }; +enum states_of_MQTT stateMQTT = MQTT_STATE_INIT; + +String MQTTclientId; +String MQTTPubNamespace = ""; +String MQTTSubNamespace = ""; +String NodeId = ""; + +//set command list +struct MQTT_set_cmd_t +{ + const char* setcmd; + const char* otgwcmd; + const char* ottype; +}; + + +const MQTT_set_cmd_t setcmds[] { + { "command", "", "raw" }, + { "setpoint", "TT", "temp" }, + { "constant", "TC", "temp" }, + { "outside", "OT", "temp" }, + { "hotwater", "HW", "on" }, + { "gatewaymode", "GW", "on" }, + { "setback", "SB", "temp" }, + { "maxchsetpt", "SH", "temp" }, + { "maxdhwsetpt", "SW", "temp" }, + { "maxmodulation", "MM", "level" }, + { "ctrlsetpt", "CS", "temp" }, + { "ctrlsetpt2", "C2", "temp" }, + { "chenable", "CH", "on" }, + { "chenable2", "H2", "on" }, + { "ventsetpt", "VS", "level" }, + { "temperaturesensor", "TS", "function" }, + { "addalternative", "AA", "function" }, + { "delalternative", "DA", "function" }, + { "unknownid", "UI", "function" }, + { "knownid", "KI", "function" }, + { "priomsg", "PM", "function" }, + { "setresponse", "SR", "function" }, + { "clearrespons", "CR", "function" }, + { "resetcounter", "RS", "function" }, + { "ignoretransitations", "IT", "function" }, + { "overridehb", "OH", "function" }, + { "forcethermostat", "FT", "function" }, + { "voltageref", "VR", "function" }, + { "debugptr", "DP", "function" }, +} ; + +const int nrcmds = sizeof(setcmds) / sizeof(setcmds[0]); + +// const char learnmsg[] { "LA", "PR=L", "LB", "PR=L", "LC", "PR=L", "LD", "PR=L", "LE", "PR=L", "LF", "PR=L", "GA", "PR=G", "GB", "PR=G", "VR", "PR=V", "GW", "PR=M", "IT", "PR=T", "SB", "PR=S", "HW", "PR=W" } ; +// const int nrlearnmsg = sizeof(learnmsg) / sizeof(learnmsg[0]); + +//=========================================================================================== +void startMQTT() +{ + if (!settingMQTTenable) return; + stateMQTT = MQTT_STATE_INIT; + //setup for mqtt discovery + clearMQTTConfigDone(); + NodeId = settingMQTTuniqueid; + MQTTPubNamespace = settingMQTTtopTopic + "/value/" + NodeId; + MQTTSubNamespace = settingMQTTtopTopic + "/set/" + NodeId; + handleMQTT(); //initialize the MQTT statemachine + // handleMQTT(); //then try to connect to MQTT + // handleMQTT(); //now you should be connected to MQTT ready to send +} + +bool bHAcycle = false; + +// handles MQTT subscribe incoming stuff +void handleMQTTcallback(char* topic, byte* payload, unsigned int length) { + + if (bDebugMQTT) { + DebugT("Message arrived on topic ["); Debug(topic); Debug("] = ["); + for (unsigned int i = 0; i < length; i++) { + Debug((char)payload[i]); + } + Debug("] ("); Debug(length); Debug(")"); Debugln(); DebugFlush(); + } + + //detect home assistant going down... + char msgPayload[50]; + int msglen = min((int)(length)+1, (int)sizeof(msgPayload)); + strlcpy(msgPayload, (char *)payload, msglen); + if (strcasecmp(topic, "homeassistant/status") == 0) { + //incoming message on status, detect going down + if (!settingMQTTharebootdetection) { + //So if the HA reboot detection is turned of, we will just look for HA going online. + //This means everytime there is "online" message, we will restart MQTT configuration, including the HA Auto Discovery. + bHAcycle = true; + } + if (strcasecmp(msgPayload, "offline") == 0){ + //home assistant went down + DebugTln(F("Home Assistant went offline!")); + bHAcycle = true; //set flag, so it triggers when it goes back online + } else if ((strcasecmp(msgPayload, "online") == 0) && bHAcycle){ + DebugTln(F("Home Assistant went online!")); + bHAcycle = false; //clear flag, so it does not trigger again + //restart stuff, to make sure it works correctly again + startMQTT(); // fixing some issues with hanging HA AutoDiscovery in some scenario's? + } else { + DebugTf(PSTR("Home Assistant Status=[%s] and HA cycle status [%s]\r\n"), msgPayload, CBOOLEAN(bHAcycle)); + } + } + + + // parse the incoming topic and execute commands + char* token; + char otgwcmd[51]={0}; + + //first check toptopic part, it can include the seperator, e.g. "myHome/OTGW" or "OTGW"" + if (strncmp(topic, settingMQTTtopTopic.c_str(), settingMQTTtopTopic.length()) != 0) { + MQTTDebugln(F("MQTT: wrong top topic")); + return; + } else { + //remove the top topic part + MQTTDebugTf(PSTR("Parsing topic: %s/"), settingMQTTtopTopic.c_str()); + topic += settingMQTTtopTopic.length(); + while (*topic == '/') { + topic++; + } + } + // naming convention /set// + token = strtok(topic, "/"); + MQTTDebugf("%s/", token); + if (strcasecmp(token, "set") == 0) { + token = strtok(NULL, "/"); + MQTTDebugf("%s/", token); + if (strcasecmp(token, CSTR(NodeId)) == 0) { + token = strtok(NULL, "/"); + MQTTDebugf("%s", token); + if (token != NULL){ + //loop thru command list + int i; + for (i=0; i= + snprintf(otgwcmd, sizeof(otgwcmd), "%s=%s", setcmds[i].otgwcmd, msgPayload); + MQTTDebugf(" found command, sending payload [%s]\r\n", otgwcmd); + addOTWGcmdtoqueue((char *)otgwcmd, strlen(otgwcmd), true); + } + break; //exit loop + } + } + if (i >= nrcmds){ + //no match found + MQTTDebugln(); + MQTTDebugTf(PSTR("No match found for command: [%s]\r\n"), token); + } + } + } + } +} + +//=========================================================================================== +void handleMQTT() +{ + if (!settingMQTTenable) return; + DECLARE_TIMER_SEC(timerMQTTwaitforconnect, 42, CATCH_UP_MISSED_TICKS); // wait before trying to connect again + DECLARE_TIMER_SEC(timerMQTTwaitforretry, 3, CATCH_UP_MISSED_TICKS); // wait for retry + + //State debug timers + DECLARE_TIMER_SEC(timerMQTTdebugwaitforreconnect, 13); + DECLARE_TIMER_SEC(timerMQTTdebugerrorstate, 13); + DECLARE_TIMER_SEC(timerMQTTdebugwaitconnectionattempt, 1); + DECLARE_TIMER_SEC(timerMQTTdebugisconnected, 60); + + if (MQTTclient.connected()) MQTTclient.loop(); //always do a MQTTclient.loop() first + + switch(stateMQTT) + { + case MQTT_STATE_INIT: + MQTTDebugTln(F("MQTT State: MQTT Initializing")); + WiFi.hostByName(CSTR(settingMQTTbroker), MQTTbrokerIP); // lookup the MQTTbroker convert to IP + sprintf(MQTTbrokerIPchar, "%d.%d.%d.%d", MQTTbrokerIP[0], MQTTbrokerIP[1], MQTTbrokerIP[2], MQTTbrokerIP[3]); + if (isValidIP(MQTTbrokerIP)) + { + MQTTDebugTf(PSTR("[%s] => setServer(%s, %d)\r\n"), CSTR(settingMQTTbroker), MQTTbrokerIPchar, settingMQTTbrokerPort); + MQTTclient.disconnect(); + MQTTclient.setServer(MQTTbrokerIPchar, settingMQTTbrokerPort); + MQTTclient.setCallback(handleMQTTcallback); + MQTTclient.setSocketTimeout(4); + MQTTclientId = String(_HOSTNAME) + WiFi.macAddress(); + //skip try to connect + reconnectAttempts =0; + stateMQTT = MQTT_STATE_TRY_TO_CONNECT; + } + else + { // invalid IP, then goto error state + MQTTDebugTf(PSTR("ERROR: [%s] => is not a valid URL\r\n"), CSTR(settingMQTTbroker)); + stateMQTT = MQTT_STATE_ERROR; + //DebugTln(F("Next State: MQTT_STATE_ERROR")); + } + RESTART_TIMER(timerMQTTwaitforconnect); + break; + + case MQTT_STATE_TRY_TO_CONNECT: + MQTTDebugTln(F("MQTT State: MQTT try to connect")); + MQTTDebugTf(PSTR("MQTT server is [%s], IP[%s]\r\n"), settingMQTTbroker.c_str(), MQTTbrokerIPchar); + + MQTTDebugT(F("Attempting MQTT connection .. ")); + reconnectAttempts++; + + //If no username, then anonymous connection to broker, otherwise assume username/password. + if (settingMQTTuser.length() == 0) + { + MQTTDebug(F("without a Username/Password ")); + if(!MQTTclient.connect(CSTR(MQTTclientId), CSTR(MQTTPubNamespace), 0, true, "offline")) PrintMQTTError(); + } + else + { + MQTTDebugf("Username [%s] ", CSTR(settingMQTTuser)); + if(!MQTTclient.connect(CSTR(MQTTclientId), CSTR(settingMQTTuser), CSTR(settingMQTTpasswd), CSTR(MQTTPubNamespace), 0, true, "offline")) PrintMQTTError(); + } + + //If connection was made succesful, move on to next state... + if (MQTTclient.connected()) + { + reconnectAttempts = 0; + MQTTDebugln(F(" .. connected\r")); + Debugln(F("MQTT connected")); + stateMQTT = MQTT_STATE_IS_CONNECTED; + MQTTDebugTln(F("Next State: MQTT_STATE_IS_CONNECTED")); + // birth message, sendMQTT retains by default + sendMQTT(CSTR(MQTTPubNamespace), "online"); + + // First do AutoConfiguration for Homeassistant + // doAutoConfigure(); + + //Subscribe to topics + char topic[100]; + strcpy(topic, CSTR(MQTTSubNamespace)); + strlcat(topic, "/#", sizeof(topic)); + MQTTDebugTf(PSTR("Subscribe to MQTT: TopicId [%s]\r\n"), topic); + if (MQTTclient.subscribe(topic)){ + MQTTDebugTf(PSTR("MQTT: Subscribed successfully to TopicId [%s]\r\n"), topic); + } + else + { + MQTTDebugTf(PSTR("MQTT: Subscribe TopicId [%s] FAILED! \r\n"), topic); + PrintMQTTError(); + } + MQTTclient.subscribe("homeassistant/status"); //start monitoring the status of homeassistant, if it goes down, then force a restart after it comes back online. + sendMQTTversioninfo(); + } + else + { // no connection, try again, do a non-blocking wait for 3 seconds. + MQTTDebugln(F(" .. \r")); + MQTTDebugTf(PSTR("failed, retrycount=[%d], rc=[%d] .. try again in 3 seconds\r\n"), reconnectAttempts, MQTTclient.state()); + RESTART_TIMER(timerMQTTwaitforretry); + stateMQTT = MQTT_STATE_WAIT_CONNECTION_ATTEMPT; // if the re-connect did not work, then return to wait for reconnect + MQTTDebugTln(F("Next State: MQTT_STATE_WAIT_CONNECTION_ATTEMPT")); + } + + //After 5 attempts... go wait for a while. + if (reconnectAttempts >= 5) + { + MQTTDebugTln(F("5 attempts have failed. Retry wait for next reconnect in 10 minutes\r")); + RESTART_TIMER(timerMQTTwaitforconnect); + stateMQTT = MQTT_STATE_WAIT_FOR_RECONNECT; // if the re-connect did not work, then return to wait for reconnect + MQTTDebugTln(F("Next State: MQTT_STATE_WAIT_FOR_RECONNECT")); + } + break; + + case MQTT_STATE_IS_CONNECTED: + if DUE(timerMQTTdebugisconnected) MQTTDebugTln(F("MQTT State: MQTT is Connected")); + if (MQTTclient.connected()) + { //if the MQTT client is connected, then please do a .loop call... + MQTTclient.loop(); + } + else + { //else go and wait 10 minutes, before trying again. + RESTART_TIMER(timerMQTTwaitforconnect); + stateMQTT = MQTT_STATE_WAIT_FOR_RECONNECT; + MQTTDebugTln(F("Next State: MQTT_STATE_WAIT_FOR_RECONNECT")); + } + break; + + case MQTT_STATE_WAIT_CONNECTION_ATTEMPT: + //do non-blocking wait for 3 seconds + if DUE(timerMQTTdebugwaitconnectionattempt) MQTTDebugTln(F("MQTT State: MQTT_WAIT_CONNECTION_ATTEMPT")); + if (DUE(timerMQTTwaitforretry)) + { + //Try again... after waitforretry non-blocking delay + stateMQTT = MQTT_STATE_TRY_TO_CONNECT; + MQTTDebugTln(F("Next State: MQTT_STATE_TRY_TO_CONNECT")); + } + break; + + case MQTT_STATE_WAIT_FOR_RECONNECT: + //do non-blocking wait for 10 minutes, then try to connect again. + if DUE(timerMQTTdebugwaitforreconnect) MQTTDebugTln(F("MQTT State: MQTT wait for reconnect")); + if (DUE(timerMQTTwaitforconnect)) + { + //remember when you tried last time to reconnect + RESTART_TIMER(timerMQTTwaitforretry); + reconnectAttempts = 0; + stateMQTT = MQTT_STATE_TRY_TO_CONNECT; + MQTTDebugTln(F("Next State: MQTT_STATE_TRY_TO_CONNECT")); + } + break; + + case MQTT_STATE_ERROR: + if DUE(timerMQTTdebugerrorstate) MQTTDebugTln(F("MQTT State: MQTT ERROR, wait for 10 minutes, before trying again")); + //wait for next retry + RESTART_TIMER(timerMQTTwaitforconnect); + stateMQTT = MQTT_STATE_WAIT_FOR_RECONNECT; + MQTTDebugTln(F("Next State: MQTT_STATE_WAIT_FOR_RECONNECT")); + break; + + default: + MQTTDebugTln(F("MQTT State: default, this should NEVER happen!")); + //do nothing, this state should not happen + stateMQTT = MQTT_STATE_INIT; + DebugTln(F("Next State: MQTT_STATE_INIT")); + break; + } + statusMQTTconnection = MQTTclient.connected(); +} // handleMQTT() + +//=========================================================================================== +String trimVal(char *in) +{ + String Out = in; + Out.trim(); + return Out; +} // trimVal() + +void PrintMQTTError(){ + MQTTDebugln(); + switch (MQTTclient.state()) + { + case MQTT_CONNECTION_TIMEOUT : MQTTDebugTln(F("Error: MQTT connection timeout"));break; + case MQTT_CONNECTION_LOST : MQTTDebugTln(F("Error: MQTT connections lost"));break; + case MQTT_CONNECT_FAILED : MQTTDebugTln(F("Error: MQTT connection failed"));break; + case MQTT_DISCONNECTED : MQTTDebugTln(F("Error: MQTT disconnected"));break; + case MQTT_CONNECTED : MQTTDebugTln(F("Error: MQTT connected"));break; + case MQTT_CONNECT_BAD_PROTOCOL : MQTTDebugTln(F("Error: MQTT connect bad protocol"));break; + case MQTT_CONNECT_BAD_CLIENT_ID : MQTTDebugTln(F("Error: MQTT connect bad client id"));break; + case MQTT_CONNECT_UNAVAILABLE : MQTTDebugTln(F("Error: MQTT connect unavailable"));break; + case MQTT_CONNECT_BAD_CREDENTIALS: MQTTDebugTln(F("Error: MQTT connect bad credentials"));break; + case MQTT_CONNECT_UNAUTHORIZED : MQTTDebugTln(F("Error: MQTT connect unauthorized"));break; + default: MQTTDebugTln(F("Error: MQTT unknown error")); + } +} + +/* + topic: , sensor topic, will be automatically prefixed with /value/ + json: , payload to send + retain: , retain mqtt message +*/ +void sendMQTTData(const String topic, const String json, const bool retain = false) +{ + if (!settingMQTTenable) return; + sendMQTTData(CSTR(topic), CSTR(json), retain); +} + +/* + topic: , sensor topic, will be automatically prefixed with /value/ + json: , payload to send + retain: , retain mqtt message +*/ +void sendMQTTData(const char* topic, const char *json, const bool retain = false) +{ + if (!settingMQTTenable) return; + if (!MQTTclient.connected()) {DebugTln(F("Error: MQTT broker not connected.")); PrintMQTTError(); return;} + if (!isValidIP(MQTTbrokerIP)) {DebugTln(F("Error: MQTT broker IP not valid.")); return;} + char full_topic[100]; + snprintf(full_topic, sizeof(full_topic), "%s/", CSTR(MQTTPubNamespace)); + strlcat(full_topic, topic, sizeof(full_topic)); + MQTTDebugTf(PSTR("Sending MQTT: server %s:%d => TopicId [%s] --> Message [%s]\r\n"), settingMQTTbroker.c_str(), settingMQTTbrokerPort, full_topic, json); + if (!MQTTclient.publish(full_topic, json, retain)) PrintMQTTError(); + feedWatchDog();//feed the dog +} // sendMQTTData() + +/* +* topic: , topic will be used as is (no prefixing), retained = true +* json: , payload to send +*/ +//=========================================================================================== +void sendMQTT(String topic, String json){ + if (!settingMQTTenable) return; + sendMQTT(CSTR(topic), CSTR(json), json.length()); +} + +void sendMQTT(const char* topic, const char *json, const size_t len) +{ + if (!settingMQTTenable) return; + if (!MQTTclient.connected()) {DebugTln(F("Error: MQTT broker not connected.")); PrintMQTTError(); return;} + if (!isValidIP(MQTTbrokerIP)) {DebugTln(F("Error: MQTT broker IP not valid.")); return;} + MQTTDebugTf(PSTR("Sending MQTT: server %s:%d => TopicId [%s] --> Message [%s]\r\n"), settingMQTTbroker.c_str(), settingMQTTbrokerPort, topic, json); + if (MQTTclient.getBufferSize() < len) MQTTclient.setBufferSize(len); //resize buffer when needed + + if (MQTTclient.beginPublish(topic, len, true)){ + for (size_t i = 0; i -1) sIn.remove(posC); // strip comments + + if (sIn.length() <= 3) return false; //not enough buffer, skip split + + unsigned int pos = sIn.indexOf(del); //determine first split point + if ((pos <= 0) || (pos == (sIn.length() - 1))) return false; // no key or no value + + unsigned int pos2 = sIn.indexOf(del, pos+1); //determine second split point, starting from the first found + if ((pos2 <= 0) || (pos2 <= pos) || (pos2 == (sIn.length() - 1))) return false; // no key or no value + + String sID = sIn.substring(0, pos); + sID.trim(); + cID = (byte)sID.toInt(); + + cKey = sIn.substring(pos+1, pos2); + cKey.trim(); //before, and trim spaces + + cVal = sIn.substring(pos2 + 1); + cVal.trim(); //after,and trim spaces + + // Debugf("Split line into: [%d] [%s] [%s]\r\n", cID, CSTR(cKey), CSTR(cVal)); DebugFlush(); + + return true; +} +//=========================================================================================== +bool getMQTTConfigDone(const uint8_t MSGid) +{ + uint8_t group = MSGid & 0b11100000; + group = group>>5; + uint8_t index = MSGid & 0b00011111; + uint32_t result = bitRead(MQTTautoConfigMap[group], index); + MQTTDebugTf(PSTR("Reading bit %d from group %d for MSGid %d: result = %d\r\n"), index, group, MSGid, result); + if (result > 0) { + return true; + } else { + return false; + } +} +//=========================================================================================== +bool setMQTTConfigDone(const uint8_t MSGid) +{ + uint8_t group = MSGid & 0b11100000; + group = group>>5; + uint8_t index = MSGid & 0b00011111; + MQTTDebugTf(PSTR("Setting bit %d from group %d for MSGid %d\r\n"), index, group, MSGid); + MQTTDebugTf(PSTR("Value before setting bit %d\r\n"), MQTTautoConfigMap[group]); + if(bitSet(MQTTautoConfigMap[group], index) > 0) { + MQTTDebugTf(PSTR("Value after setting bit %d\r\n"), MQTTautoConfigMap[group]); + return true; + } else { + return false; + } +} +//=========================================================================================== +void clearMQTTConfigDone() +{ + memset(MQTTautoConfigMap, 0, sizeof(MQTTautoConfigMap)); +} +//=========================================================================================== +void doAutoConfigure(bool bForcaAll = false){ + //force all sensors to be sent to auto configuration + for (int i=0; i<255; i++){ + if ((getMQTTConfigDone((byte)i)==true) || bForcaAll) { + MQTTDebugTf(PSTR("Sending auto configuration for sensor %d\r\n"), i); + doAutoConfigureMsgid((byte)i); + doBackgroundTasks(); + } + } +// bool success = doAutoConfigure("config"); // the string "config" should match every line non-comment in mqttha.cfg +} +//=========================================================================================== +bool doAutoConfigureMsgid(byte OTid) +{ + String cfgSensorId = "" ; + // check if foney dataid is called to do autoconfigure for temp sensors, call configsensors instead + if (OTid == OTGWdallasdataid) { + MQTTDebugTf(PSTR("Sending auto configuration for temp sensors %d\r\n"), OTid); + configSensors() ; + return true; + } + else return doAutoConfigureMsgid(OTid, cfgSensorId); + } + + bool doAutoConfigureMsgid(byte OTid, String cfgSensorId ) +{ + bool _result = false; + + if (!settingMQTTenable) { + return _result; + } + if (!MQTTclient.connected()) { + DebugTln(F("Error: MQTT broker not connected.")); + return _result; + } + if (!isValidIP(MQTTbrokerIP)) { + DebugTln(F("Error: MQTT broker IP not valid.")); + return _result; + } + + byte lineID = 39; // 39 is unused in OT protocol so is a safe value + String sMsg = ""; + String sTopic = ""; + + //Let's open the MQTT autoconfig file + File fh; //filehandle + const char *cfgFilename = "/mqttha.cfg"; + LittleFS.begin(); + + if (!LittleFS.exists(cfgFilename)) { + DebugTln(F("Error: confuration file not found.")); + return _result; + } + + fh = LittleFS.open(cfgFilename, "r"); + + if (!fh) { + DebugTln(F("Error: could not open confuration file.")); + return _result; + } + + //Lets go read the config and send it out to MQTT line by line + while (fh.available()) + { + //read file line by line, split and send to MQTT (topic, msg) + feedWatchDog(); //start with feeding the dog + + String sLine = fh.readStringUntil('\n'); + // DebugTf(PSTR("sline[%s]\r\n"), CSTR(sLine)); + if (!splitLine(sLine, ';', lineID, sTopic, sMsg)) { //splitLine() also filters comments + //MQTTDebugTf(PSTR("Either comment or invalid config line: [%s]\r\n"), CSTR(sLine)); + continue; + } + + // DebugTf(PSTR("looking in config file line for %d: [%d][%s] \r\n"), OTid, lineID, CSTR(sTopic)); + + // check if this is the specific line we are looking for + if (lineID != OTid) continue; + + MQTTDebugTf(PSTR("Found line in config file for %d: [%d][%s] \r\n"), OTid, lineID, CSTR(sTopic)); + + // discovery topic prefix + MQTTDebugTf(PSTR("sTopic[%s]==>"), CSTR(sTopic)); + sTopic.replace("%homeassistant%", CSTR(settingMQTThaprefix)); + + /// node + sTopic.replace("%node_id%", CSTR(NodeId)); + + /// SensorId + sTopic.replace("%sensor_id%", CSTR(cfgSensorId)); + + MQTTDebugf("[%s]\r\n", CSTR(sTopic)); + /// ---------------------- + + MQTTDebugTf(PSTR("sMsg[%s]==>"), CSTR(sMsg)); + + /// node + sMsg.replace("%node_id%", CSTR(NodeId)); + + /// SensorId + sMsg.replace("%sensor_id%", CSTR(cfgSensorId)); + + /// hostname + sMsg.replace("%hostname%", CSTR(settingHostname)); + + /// version + sMsg.replace("%version%", _VERSION); + + // pub topics prefix + sMsg.replace("%mqtt_pub_topic%", CSTR(MQTTPubNamespace)); + + // sub topics + sMsg.replace("%mqtt_sub_topic%", CSTR(MQTTSubNamespace)); + + MQTTDebugf("[%s]\r\n", CSTR(sMsg)); + DebugFlush(); + + //sendMQTT(CSTR(sTopic), CSTR(sMsg), (sTopic.length() + sMsg.length()+2)); + sendMQTT(sTopic, sMsg); + resetMQTTBufferSize(); + // delay(10); + _result = true; + + // TODO: enable this break if we are sure the old config dump method is no longer needed + // break; + + } // while available() + + fh.close(); + + // HA discovery msg's are rather large, reset the buffer size to release some memory + resetMQTTBufferSize(); + + return _result; +} + +void sensorAutoConfigure(byte dataid, bool finishflag , String cfgSensorId = "") { + // Special version of Autoconfigure for sensors + // dataid is a foney id, not used by OT + // check wheter MQTT topic needs to be configured + // cfgNodeId can be set to alternate NodeId to allow for multiple temperature sensors, should normally be NodeId + // When finishflag is true, check on dataid is already done and complete the config. On false do the config and leave completion to caller + if(getMQTTConfigDone(dataid)==false or !finishflag) { + MQTTDebugTf(PSTR("Need to set MQTT config for sensor id(%d)\r\n"),dataid); + bool success = doAutoConfigureMsgid(dataid,cfgSensorId); + if(success) { + MQTTDebugTf(PSTR("Successfully sent MQTT config for sensor id(%d)\r\n"),dataid); + if (finishflag) setMQTTConfigDone(dataid); + } else { + MQTTDebugTf(PSTR("Not able to complete MQTT configuration for sensor id(%d)\r\n"),dataid); + } + } else { + // MQTTDebugTf("No need to set MQTT config for sensor id(%d)\r\n",dataid); + } + } + + + + +/*************************************************************************** +* +* Permission is hereby granted, free of charge, to any person obtaining a +* copy of this software and associated documentation files (the +* "Software"), to deal in the Software without restriction, including +* without limitation the rights to use, copy, modify, merge, publish, +* distribute, sublicense, and/or sell copies of the Software, and to permit +* persons to whom the Software is furnished to do so, subject to the +* following conditions: +* +* The above copyright notice and this permission notice shall be included +* in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT +* OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR +* THE USE OR OTHER DEALINGS IN THE SOFTWARE. +* +***************************************************************************/ From d0397d9dfda7dbfa2fdb9797cf2ca1db93d354e2 Mon Sep 17 00:00:00 2001 From: Robert van den Breemen Date: Mon, 15 Apr 2024 23:46:59 +0200 Subject: [PATCH 06/13] before update 0.10.3 --- helperStuff.ino.tmp | 574 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 574 insertions(+) create mode 100644 helperStuff.ino.tmp diff --git a/helperStuff.ino.tmp b/helperStuff.ino.tmp new file mode 100644 index 00000000..b3efd134 --- /dev/null +++ b/helperStuff.ino.tmp @@ -0,0 +1,574 @@ +/* +*************************************************************************** +** Program : helperStuff +** Version : v0.10.2 +** +** Copyright (c) 2021-2023 Robert van den Breemen +** based on Framework ESP8266 from Willem Aandewiel +** +** TERMS OF USE: MIT License. See bottom of file. +*************************************************************************** +*/ + +#include // for type definitions + +template void PROGMEM_readAnything (const T * sce, T& dest) +{ + memcpy_P (&dest, sce, sizeof (T)); +} + +template T PROGMEM_getAnything (const T * sce) +{ + static T temp; + memcpy_P (&temp, sce, sizeof (T)); + return temp; +} + +//=========================================================================================== +// Note: This function returns a pointer to a substring of the original string. +// If the given string was allocated dynamically, the caller must not overwrite +// that pointer with the returned value, since the original pointer must be +// deallocated using the same allocator with which it was allocated. The return +// value must NOT be deallocated using free() etc. +char *trimwhitespace(char *str) +{ + char *end; + + // Trim leading space + while(isspace((unsigned char)*str)) str++; + + if(*str == 0) // All spaces? + return str; + + // Trim trailing space + end = str + strlen(str) - 1; + while(end > str && isspace((unsigned char)*end)) end--; + + // Write new null terminator character + end[1] = '\0'; + + return str; +} + + +//=========================================================================================== +uint8_t splitString(String inStrng, char delimiter, String wOut[], uint8_t maxWords) +{ + uint8_t wordCount = 0; + size_t inxE = 0, inxS = 0; + inStrng.trim(); + while(inxE < inStrng.length() && wordCount < maxWords) + { + inxE = inStrng.indexOf(delimiter, inxS); //finds location of first , + wOut[wordCount] = inStrng.substring(inxS, inxE); //captures first data String + wOut[wordCount].trim(); + //DebugTf(PSTR("[%d] => [%c] @[%d] found[%s]\r\n"), wordCount, delimiter, inxE, wOut[wordCount].c_str()); + inxS = inxE; + inxS++; + wordCount++; + } + // zero rest of the words + for(int i=wordCount; i< maxWords; i++) + { + wOut[wordCount][0] = 0; + } + // if not whole string processed place rest in last word + if (inxS < inStrng.length()) + { + wOut[maxWords-1] = inStrng.substring(inxS, inStrng.length()); // store rest of String + } + + return wordCount; + +} // splitString() + + +//=========================================================================================== +boolean isValidIP(IPAddress ip) +{ + /* Works as follows: + * example: + * 127.0.0.1 + * 1 => 127||0||0||1 = 128>0 = true + * 2 => !(false || false) = true + * 3 => !(false || false || false || false ) = true + * 4 => !(true && true && true && true) = false + * 5 => !(false) = true + * true && true & true && false && true = false ==> correct, this is an invalid addres + * + * 0.0.0.0 + * 1 => 0||0||0||0 = 0>0 = false + * 2 => !(true || true) = false + * 3 => !(false || false || false || false) = true + * 4 => !(true && true && true && tfalse) = true + * 5 => !(false) = true + * false && false && true && true && true = false ==> correct, this is an invalid addres + * + * 192.168.0.1 + * 1 => 192||168||0||1 =233>0 = true + * 2 => !(false || false) = true + * 3 +> !(false || false || false || false) = true + * 4 => !(false && false && true && true) = true + * 5 => !(false) = true + * true & true & true && true && true = true ==> correct, this is a valid address + * + * 255.255.255.255 + * 1 => 255||255||255||255 =255>0 = true + * 2 => !(false || false ) = true + * 3 +> !(true || true || true || true) = false + * 4 => !(false && false && false && false) = true + * 5 => !(true) = false + * true && true && false && true && false = false ==> correct, this is an invalid address + * + * 0.123.12.1 => true && false && true && true && true = false ==> correct, this is an invalid address + * 10.0.0.0 => true && false && true && true && true = false ==> correct, this is an invalid address + * 10.255.0.1 => true && true && false && true && true = false ==> correct, this is an invalid address + * 150.150.255.150 => true && true && false && true && true = false ==> correct, this is an invalid address + * + * 123.21.1.99 => true && true && true && true && true = true ==> correct, this is annvalid address + * 1.1.1.1 => true && true && true && true && true = true ==> correct, this is annvalid address + * + * Some references on valid ip addresses: + * - https://www.quora.com/How-do-you-identify-an-invalid-IP-address + * + */ + boolean _isValidIP = false; + _isValidIP = ((ip[0] || ip[1] || ip[2] || ip[3])>0); // if any bits are set, then it is not 0.0.0.0 + _isValidIP &= !((ip[0]==0) || (ip[3]==0)); // if either the first or last is a 0, then it is invalid + _isValidIP &= !((ip[0]==255) || (ip[1]==255) || (ip[2]==255) || (ip[3]==255)) ; // if any of the octets is 255, then it is invalid + _isValidIP &= !(ip[0]==127 && ip[1]==0 && ip[2]==0 && ip[3]==1); // if not 127.0.0.0 then it might be valid + _isValidIP &= !(ip[0]>=224); // if ip[0] >=224 then reserved space + + // DebugTf( "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]); + // if (_isValidIP) + // Debugln(F(" = Valid IP")); + // else + // Debugln(F(" = Invalid IP!")); + + return _isValidIP; + +} // isValidIP() + + +uint32_t updateRebootCount() +{ + //simple function to keep track of the number of reboots + //return: number of reboots (if it goes as planned) + uint32_t _reboot = 0; + #define REBOOTCNT_FILE "/reboot_count.txt" + if (LittleFS.begin()) { + //start with opening the file + File fh = LittleFS.open(REBOOTCNT_FILE, "r"); + if (fh) { + //read from file + if (fh.available()){ + //read the first line + _reboot = fh.readStringUntil('\n').toInt(); + } + } + fh.close(); + //increment reboot counter + _reboot++; + //write back the reboot counter + fh = LittleFS.open(REBOOTCNT_FILE, "w"); + if (fh) { + //write to _reboot to file + fh.println(_reboot); + } + fh.close(); + } + DebugTf(PSTR("Reboot count = [%d]\r\n"), rebootCount); + return _reboot; +} + +bool updateRebootLog(String text) +{ + #define REBOOTLOG_FILE "/reboot_log.txt" + #define TEMPLOG_FILE "/reboot_log.t.txt" + #define LOG_LINES 20 + #define LOG_LINE_LENGTH 140 + + char log_line[LOG_LINE_LENGTH] = {0}; + char log_line_regs[LOG_LINE_LENGTH] = {0}; + char log_line_excpt[LOG_LINE_LENGTH] = {0}; + uint32_t errorCode = -1; + + //waitforNTPsync(); + loopNTP(); // make sure time is up to date (improved error logging) + + struct rst_info *rtc_info = system_get_rst_info(); + + if (rtc_info == NULL) { + DebugTf(PSTR("no reset info available: %x\r\n"), errorCode); + } else { + + DebugTf(PSTR("reset reason: %x\r\n"), rtc_info->reason); + errorCode = rtc_info->reason; + // Rst cause No. Cause GPIO state + //-------------- ------------------- ------------- + // 0 Power reboot Changed + // 1 Hardware WDT reset Changed + // 2 Fatal exception Unchanged + // 3 Software watchdog reset Unchanged + // 4 Software reset Unchanged + // 5 Deep-sleep Changed + // 6 Hardware reset Changed + + if (rtc_info->reason == REASON_WDT_RST || rtc_info->reason == REASON_EXCEPTION_RST || rtc_info->reason == REASON_SOFT_WDT_RST) { + + //The address of the last crash is printed, which is used to debug garbled output + snprintf(log_line_regs, LOG_LINE_LENGTH,"ESP register contents: epc1=0x%08x, epc2=0x%08x, epc3=0x%08x, excvaddr=0x%08x, depc=0x%08x\r\n", rtc_info->epc1, rtc_info->epc2, rtc_info->epc3, rtc_info->excvaddr, rtc_info->depc); + Debugf(log_line_regs); + } + + if (rtc_info->reason == REASON_EXT_SYS_RST) { + //external reset, so try to fetch the reset reason from the tiny watchdog and print that + snprintf(log_line_regs, LOG_LINE_LENGTH,"External Reason: External Watchdog reason: %s\r\n", CSTR(initWatchDog())); + Debugf(log_line_regs); + } + + if (rtc_info->reason == REASON_EXCEPTION_RST) { + + // Fatal exception No. Description Possible Causes + // ------------------- -------------- ------------------- + // 0 Invalid command 1. Damaged BIN binaries + // 2. Wild pointers + // + // 6 Division by zero Division by zero + // + // 9 Unaligned read/write 1. Unaligned read/write Cache addresses + // operation addresses 2. Wild pointers + // + // 28/29 Access to invalid 1. Access to Cache after it is turned off + // address 2. Wild pointers + // + // more reasons can be found in the "corebits.h" file of the Extensa SDK + + switch(rtc_info->exccause) { + case 0: snprintf(log_line_excpt, LOG_LINE_LENGTH, "- Invalid command (0)"); break; + case 6: snprintf(log_line_excpt, LOG_LINE_LENGTH, "- Division by zero (6)"); break; + case 9: snprintf(log_line_excpt, LOG_LINE_LENGTH, "- Unaligned read/write operation addresses (9)"); break; + case 28: snprintf(log_line_excpt, LOG_LINE_LENGTH, "- Access to invalid address (28)"); break; + case 29: snprintf(log_line_excpt, LOG_LINE_LENGTH, "- Access to invalid address (29)"); break; + default: snprintf(log_line_excpt, LOG_LINE_LENGTH, "- Other (not specified) (%d)", rtc_info->exccause); break; + } + + Debugf("Fatal exception (%d): %s\r\n", rtc_info->exccause, log_line_excpt); + } + } + + TimeZone myTz = timezoneManager.createForZoneName(CSTR(settingNTPtimezone)); + ZonedDateTime myTime = ZonedDateTime::forUnixSeconds64(time(nullptr), myTz); + snprintf(log_line, LOG_LINE_LENGTH, "%d-%02d-%02d %02d:%02d:%02d - reboot cause: %s (%x) %s\r\n", myTime.year(), myTime.month(), myTime.day(), myTime.hour(), myTime.minute(), myTime.second(), CSTR(text), errorCode, log_line_excpt); + + if (LittleFS.begin()) { + //start with opening the file + File outfh = LittleFS.open(TEMPLOG_FILE, "w"); + + if (outfh) { + //write to _reboot to file + outfh.print(log_line); + + if (strlen(log_line_regs)>2) { + outfh.print(log_line_regs); + } + + File infh = LittleFS.open(REBOOTLOG_FILE, "r"); + + int i = 1; + if (infh) { + //read from file + while (infh.available() && (i < LOG_LINES)){ + //read the first line + String line = infh.readStringUntil('\n'); + if (line.length() > 3) { //TODO: check is no longer needed? + outfh.print(line); + } + i++; + } + infh.close(); + } + outfh.close(); + + if (LittleFS.exists(REBOOTLOG_FILE)) { + LittleFS.remove(REBOOTLOG_FILE); + } + + LittleFS.rename(TEMPLOG_FILE, REBOOTLOG_FILE); + + return true; // succesfully logged + } + } + + return false; // logging unsuccesfull +} + + +void doRestart(const char* str) { + DebugTln(str); + delay(2000); // Enough time for messages to be sent. + ESP.restart(); + delay(5000); // Enough time to ensure we don't return. +} + +String upTime() +{ + char calcUptime[20]; + + snprintf(calcUptime, sizeof(calcUptime), "%d(d)-%02d:%02d(H:m)" + , int((upTimeSeconds / (60 * 60 * 24)) % 365) + , int((upTimeSeconds / (60 * 60)) % 24) + , int((upTimeSeconds / (60)) % 60)); + + return calcUptime; + +} // upTime() + +bool prefix(const char *pre, const char *str) +{ + return strncmp(pre, str, strlen(pre)) == 0; +} + +bool yearChanged(){ + static int16_t lastyear = -1; + TimeZone myTz = timezoneManager.createForZoneName(CSTR(settingNTPtimezone)); + ZonedDateTime myTime = ZonedDateTime::forUnixSeconds64(time(nullptr), myTz); + int8_t thisyear = myTime.year(); + bool _ret = (lastyear != thisyear); //year changed + if (_ret) { + //year changed + lastyear = thisyear; + } + return _ret; +} + +bool dayChanged(){ + static int8_t lastday = -1; + TimeZone myTz = timezoneManager.createForZoneName(CSTR(settingNTPtimezone)); + ZonedDateTime myTime = ZonedDateTime::forUnixSeconds64(time(nullptr), myTz); + int8_t thisday = myTime.day(); + bool _ret = (lastday != thisday); + if (_ret) { + //day changed + lastday = thisday; + } + return _ret; +} + +bool hourChanged(){ + static int8_t lasthour = -1; + TimeZone myTz = timezoneManager.createForZoneName(CSTR(settingNTPtimezone)); + ZonedDateTime myTime = ZonedDateTime::forUnixSeconds64(time(nullptr), myTz); + int8_t thishour = myTime.hour(); + bool _ret = (lasthour != thishour); + if (_ret){ + //hour changed + lasthour = thishour; + } + return _ret; +} + +bool minuteChanged(){ + static int8_t lastminute = -1; + TimeZone myTz = timezoneManager.createForZoneName(CSTR(settingNTPtimezone)); + ZonedDateTime myTime = ZonedDateTime::forUnixSeconds64(time(nullptr), myTz); + int8_t thisminute = myTime.minute(); + bool _ret = (lastminute != thisminute); + if (_ret){ + //minute changed + lastminute = thisminute; + } + return _ret; +} + +/* + check if the version githash is in the littlefs as version.hash + +*/ +bool checklittlefshash(){ + #define GITHASH_FILE "/version.hash" + String _githash=""; + if (LittleFS.begin()) { + //start with opening the file + File fh = LittleFS.open(GITHASH_FILE, "r"); + if (fh) { + //read from file + if (fh.available()){ + //read the first line + _githash = fh.readStringUntil('\n'); + } + } + DebugTf(PSTR("Check githash = [%s]\r\n"), CSTR(_githash)); + return (strcasecmp(CSTR(_githash), _VERSION_GITHASH)==0); + } + return false; +} + + +/* +** Does not generate hex character constants. +** Always generates triple-digit octal constants. +** Always generates escapes in preference to octal. +** Escape question mark to ensure no trigraphs are generated by repetitive use. +** Handling of 0x80..0xFF is locale-dependent (might be octal, might be literal). +*/ + +void chr_cstrlit(unsigned char u, char *buffer, size_t buflen) +{ + if (buflen < 2) + *buffer = '\0'; + else if (isprint(u) && u != '\'' && u != '\"' && u != '\\' && u != '\?') + sprintf(buffer, "%c", u); + else if (buflen < 3) + *buffer = '\0'; + else + { + switch (u) + { + case '\a': strcpy(buffer, "\\a"); break; + case '\b': strcpy(buffer, "\\b"); break; + case '\f': strcpy(buffer, "\\f"); break; + case '\n': strcpy(buffer, "\\n"); break; + case '\r': strcpy(buffer, "\\r"); break; + case '\t': strcpy(buffer, "\\t"); break; + case '\v': strcpy(buffer, "\\v"); break; + case '\\': strcpy(buffer, "\\\\"); break; + case '\'': strcpy(buffer, "\\'"); break; + case '\"': strcpy(buffer, "\\\""); break; + case '\?': strcpy(buffer, "\\\?"); break; + default: + if (buflen < 5) + *buffer = '\0'; + else + sprintf(buffer, "\\%03o", u); + break; + } + } +} + +void str_cstrlit(const char *str, char *buffer, size_t buflen) +{ + unsigned char u; + size_t len; + + while ((u = (unsigned char)*str++) != '\0') + { + chr_cstrlit(u, buffer, buflen); + if ((len = strlen(buffer)) == 0) + return; + buffer += len; + buflen -= len; + } + *buffer = '\0'; +} + +String strHTTPmethod(HTTPMethod method) +{ + switch (method) + { + case HTTPMethod::HTTP_GET: + return "GET"; + case HTTPMethod::HTTP_POST: + return "POST"; + case HTTPMethod::HTTP_PUT: + return "PUT"; + case HTTPMethod::HTTP_PATCH: + return "PATCH"; + case HTTPMethod::HTTP_DELETE: + return "DELETE"; + case HTTPMethod::HTTP_OPTIONS: + return "OPTIONS"; + case HTTPMethod::HTTP_HEAD: + return "HEAD"; + default: + return ""; + } +} + +/* + * Written by Ahmad Shamshiri + * with lots of research, this sources was used: + * https://support.randomsolutions.nl/827069-Best-dBm-Values-for-Wifi + * This is approximate percentage calculation of RSSI + * WiFi Signal Strength Calculation + * Written Aug 08, 2019 at 21:45 in Ajax, Ontario, Canada + */ + +int dBmtoPercentage(int dBm) +{ + const int RSSI_MAX =-50;// define maximum strength of signal in dBm + const int RSSI_MIN =-100;// define minimum strength of signal in dBm + int quality; + if(dBm <= RSSI_MIN){ + quality = 0; + } else if(dBm >= RSSI_MAX) { + quality = 100; + } else { + quality = 2 * (dBm + 100); + } + + return quality; +}//dBmtoPercentage + +/* + RSSI signal quality to percentage quad function + https://www.intuitibits.com/2016/03/23/dbm-to-percent-conversion/#comment-9 + https://gist.github.com/senseisimple/002cdba344de92748695a371cef0176a +*/ + +int signal_quality_perc_quad(int rssi) { + const int perfect_rssi = -50; + const int worst_rssi = -85; + int nominal_rssi = perfect_rssi - worst_rssi; + int signal_quality = ceil(100 * nominal_rssi * nominal_rssi - (perfect_rssi - rssi) * (15 * nominal_rssi + 62 * (perfect_rssi - rssi))) / (nominal_rssi * nominal_rssi); + if (signal_quality > 100) { + signal_quality = 100; + } else if (signal_quality < 1) { + signal_quality = 0; + } + return signal_quality; +} + + + +/* + dBm to Quality statement TL:DR + --> https://support.randomsolutions.nl/827069-Best-dBm-Values-for-Wifi + --> https://www.metageek.com/training/resources/wifi-signal-strength-basics/ + TL;DR strings on quality is based on this +*/ +String dBmtoQuality(int dBm) +{ + String _ret="Amazing"; + if (dBm<=-67) { _ret = "Very good";} + if (dBm<=-70) { _ret = "Okay";} + if (dBm<=-80) { _ret = "Not good enough";} + if (dBm<=-90) { _ret = "Unusable";} + //if (dBm<=-30) { _ret = "Amazing";} + + return (_ret); +}//dBmtoPercentage + +/*************************************************************************** +* +* Permission is hereby granted, free of charge, to any person obtaining a +* copy of this software and associated documentation files (the +* "Software"), to deal in the Software without restriction, including +* without limitation the rights to use, copy, modify, merge, publish, +* distribute, sublicense, and/or sell copies of the Software, and to permit +* persons to whom the Software is furnished to do so, subject to the +* following conditions: +* +* The above copyright notice and this permission notice shall be included +* in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT +* OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR +* THE USE OR OTHER DEALINGS IN THE SOFTWARE. +* +**************************************************************************** +*/ From 89fb382462aec3eb692a8ab7af8eff9548a27720 Mon Sep 17 00:00:00 2001 From: Robert van den Breemen Date: Mon, 15 Apr 2024 23:57:10 +0200 Subject: [PATCH 07/13] before update 0.10.3 --- helperStuff.ino.tmp | 574 -------------------------------------------- jsonStuff.ino.tmp | 332 +++++++++++++++++++++++++ 2 files changed, 332 insertions(+), 574 deletions(-) delete mode 100644 helperStuff.ino.tmp create mode 100644 jsonStuff.ino.tmp diff --git a/helperStuff.ino.tmp b/helperStuff.ino.tmp deleted file mode 100644 index b3efd134..00000000 --- a/helperStuff.ino.tmp +++ /dev/null @@ -1,574 +0,0 @@ -/* -*************************************************************************** -** Program : helperStuff -** Version : v0.10.2 -** -** Copyright (c) 2021-2023 Robert van den Breemen -** based on Framework ESP8266 from Willem Aandewiel -** -** TERMS OF USE: MIT License. See bottom of file. -*************************************************************************** -*/ - -#include // for type definitions - -template void PROGMEM_readAnything (const T * sce, T& dest) -{ - memcpy_P (&dest, sce, sizeof (T)); -} - -template T PROGMEM_getAnything (const T * sce) -{ - static T temp; - memcpy_P (&temp, sce, sizeof (T)); - return temp; -} - -//=========================================================================================== -// Note: This function returns a pointer to a substring of the original string. -// If the given string was allocated dynamically, the caller must not overwrite -// that pointer with the returned value, since the original pointer must be -// deallocated using the same allocator with which it was allocated. The return -// value must NOT be deallocated using free() etc. -char *trimwhitespace(char *str) -{ - char *end; - - // Trim leading space - while(isspace((unsigned char)*str)) str++; - - if(*str == 0) // All spaces? - return str; - - // Trim trailing space - end = str + strlen(str) - 1; - while(end > str && isspace((unsigned char)*end)) end--; - - // Write new null terminator character - end[1] = '\0'; - - return str; -} - - -//=========================================================================================== -uint8_t splitString(String inStrng, char delimiter, String wOut[], uint8_t maxWords) -{ - uint8_t wordCount = 0; - size_t inxE = 0, inxS = 0; - inStrng.trim(); - while(inxE < inStrng.length() && wordCount < maxWords) - { - inxE = inStrng.indexOf(delimiter, inxS); //finds location of first , - wOut[wordCount] = inStrng.substring(inxS, inxE); //captures first data String - wOut[wordCount].trim(); - //DebugTf(PSTR("[%d] => [%c] @[%d] found[%s]\r\n"), wordCount, delimiter, inxE, wOut[wordCount].c_str()); - inxS = inxE; - inxS++; - wordCount++; - } - // zero rest of the words - for(int i=wordCount; i< maxWords; i++) - { - wOut[wordCount][0] = 0; - } - // if not whole string processed place rest in last word - if (inxS < inStrng.length()) - { - wOut[maxWords-1] = inStrng.substring(inxS, inStrng.length()); // store rest of String - } - - return wordCount; - -} // splitString() - - -//=========================================================================================== -boolean isValidIP(IPAddress ip) -{ - /* Works as follows: - * example: - * 127.0.0.1 - * 1 => 127||0||0||1 = 128>0 = true - * 2 => !(false || false) = true - * 3 => !(false || false || false || false ) = true - * 4 => !(true && true && true && true) = false - * 5 => !(false) = true - * true && true & true && false && true = false ==> correct, this is an invalid addres - * - * 0.0.0.0 - * 1 => 0||0||0||0 = 0>0 = false - * 2 => !(true || true) = false - * 3 => !(false || false || false || false) = true - * 4 => !(true && true && true && tfalse) = true - * 5 => !(false) = true - * false && false && true && true && true = false ==> correct, this is an invalid addres - * - * 192.168.0.1 - * 1 => 192||168||0||1 =233>0 = true - * 2 => !(false || false) = true - * 3 +> !(false || false || false || false) = true - * 4 => !(false && false && true && true) = true - * 5 => !(false) = true - * true & true & true && true && true = true ==> correct, this is a valid address - * - * 255.255.255.255 - * 1 => 255||255||255||255 =255>0 = true - * 2 => !(false || false ) = true - * 3 +> !(true || true || true || true) = false - * 4 => !(false && false && false && false) = true - * 5 => !(true) = false - * true && true && false && true && false = false ==> correct, this is an invalid address - * - * 0.123.12.1 => true && false && true && true && true = false ==> correct, this is an invalid address - * 10.0.0.0 => true && false && true && true && true = false ==> correct, this is an invalid address - * 10.255.0.1 => true && true && false && true && true = false ==> correct, this is an invalid address - * 150.150.255.150 => true && true && false && true && true = false ==> correct, this is an invalid address - * - * 123.21.1.99 => true && true && true && true && true = true ==> correct, this is annvalid address - * 1.1.1.1 => true && true && true && true && true = true ==> correct, this is annvalid address - * - * Some references on valid ip addresses: - * - https://www.quora.com/How-do-you-identify-an-invalid-IP-address - * - */ - boolean _isValidIP = false; - _isValidIP = ((ip[0] || ip[1] || ip[2] || ip[3])>0); // if any bits are set, then it is not 0.0.0.0 - _isValidIP &= !((ip[0]==0) || (ip[3]==0)); // if either the first or last is a 0, then it is invalid - _isValidIP &= !((ip[0]==255) || (ip[1]==255) || (ip[2]==255) || (ip[3]==255)) ; // if any of the octets is 255, then it is invalid - _isValidIP &= !(ip[0]==127 && ip[1]==0 && ip[2]==0 && ip[3]==1); // if not 127.0.0.0 then it might be valid - _isValidIP &= !(ip[0]>=224); // if ip[0] >=224 then reserved space - - // DebugTf( "%d.%d.%d.%d", ip[0], ip[1], ip[2], ip[3]); - // if (_isValidIP) - // Debugln(F(" = Valid IP")); - // else - // Debugln(F(" = Invalid IP!")); - - return _isValidIP; - -} // isValidIP() - - -uint32_t updateRebootCount() -{ - //simple function to keep track of the number of reboots - //return: number of reboots (if it goes as planned) - uint32_t _reboot = 0; - #define REBOOTCNT_FILE "/reboot_count.txt" - if (LittleFS.begin()) { - //start with opening the file - File fh = LittleFS.open(REBOOTCNT_FILE, "r"); - if (fh) { - //read from file - if (fh.available()){ - //read the first line - _reboot = fh.readStringUntil('\n').toInt(); - } - } - fh.close(); - //increment reboot counter - _reboot++; - //write back the reboot counter - fh = LittleFS.open(REBOOTCNT_FILE, "w"); - if (fh) { - //write to _reboot to file - fh.println(_reboot); - } - fh.close(); - } - DebugTf(PSTR("Reboot count = [%d]\r\n"), rebootCount); - return _reboot; -} - -bool updateRebootLog(String text) -{ - #define REBOOTLOG_FILE "/reboot_log.txt" - #define TEMPLOG_FILE "/reboot_log.t.txt" - #define LOG_LINES 20 - #define LOG_LINE_LENGTH 140 - - char log_line[LOG_LINE_LENGTH] = {0}; - char log_line_regs[LOG_LINE_LENGTH] = {0}; - char log_line_excpt[LOG_LINE_LENGTH] = {0}; - uint32_t errorCode = -1; - - //waitforNTPsync(); - loopNTP(); // make sure time is up to date (improved error logging) - - struct rst_info *rtc_info = system_get_rst_info(); - - if (rtc_info == NULL) { - DebugTf(PSTR("no reset info available: %x\r\n"), errorCode); - } else { - - DebugTf(PSTR("reset reason: %x\r\n"), rtc_info->reason); - errorCode = rtc_info->reason; - // Rst cause No. Cause GPIO state - //-------------- ------------------- ------------- - // 0 Power reboot Changed - // 1 Hardware WDT reset Changed - // 2 Fatal exception Unchanged - // 3 Software watchdog reset Unchanged - // 4 Software reset Unchanged - // 5 Deep-sleep Changed - // 6 Hardware reset Changed - - if (rtc_info->reason == REASON_WDT_RST || rtc_info->reason == REASON_EXCEPTION_RST || rtc_info->reason == REASON_SOFT_WDT_RST) { - - //The address of the last crash is printed, which is used to debug garbled output - snprintf(log_line_regs, LOG_LINE_LENGTH,"ESP register contents: epc1=0x%08x, epc2=0x%08x, epc3=0x%08x, excvaddr=0x%08x, depc=0x%08x\r\n", rtc_info->epc1, rtc_info->epc2, rtc_info->epc3, rtc_info->excvaddr, rtc_info->depc); - Debugf(log_line_regs); - } - - if (rtc_info->reason == REASON_EXT_SYS_RST) { - //external reset, so try to fetch the reset reason from the tiny watchdog and print that - snprintf(log_line_regs, LOG_LINE_LENGTH,"External Reason: External Watchdog reason: %s\r\n", CSTR(initWatchDog())); - Debugf(log_line_regs); - } - - if (rtc_info->reason == REASON_EXCEPTION_RST) { - - // Fatal exception No. Description Possible Causes - // ------------------- -------------- ------------------- - // 0 Invalid command 1. Damaged BIN binaries - // 2. Wild pointers - // - // 6 Division by zero Division by zero - // - // 9 Unaligned read/write 1. Unaligned read/write Cache addresses - // operation addresses 2. Wild pointers - // - // 28/29 Access to invalid 1. Access to Cache after it is turned off - // address 2. Wild pointers - // - // more reasons can be found in the "corebits.h" file of the Extensa SDK - - switch(rtc_info->exccause) { - case 0: snprintf(log_line_excpt, LOG_LINE_LENGTH, "- Invalid command (0)"); break; - case 6: snprintf(log_line_excpt, LOG_LINE_LENGTH, "- Division by zero (6)"); break; - case 9: snprintf(log_line_excpt, LOG_LINE_LENGTH, "- Unaligned read/write operation addresses (9)"); break; - case 28: snprintf(log_line_excpt, LOG_LINE_LENGTH, "- Access to invalid address (28)"); break; - case 29: snprintf(log_line_excpt, LOG_LINE_LENGTH, "- Access to invalid address (29)"); break; - default: snprintf(log_line_excpt, LOG_LINE_LENGTH, "- Other (not specified) (%d)", rtc_info->exccause); break; - } - - Debugf("Fatal exception (%d): %s\r\n", rtc_info->exccause, log_line_excpt); - } - } - - TimeZone myTz = timezoneManager.createForZoneName(CSTR(settingNTPtimezone)); - ZonedDateTime myTime = ZonedDateTime::forUnixSeconds64(time(nullptr), myTz); - snprintf(log_line, LOG_LINE_LENGTH, "%d-%02d-%02d %02d:%02d:%02d - reboot cause: %s (%x) %s\r\n", myTime.year(), myTime.month(), myTime.day(), myTime.hour(), myTime.minute(), myTime.second(), CSTR(text), errorCode, log_line_excpt); - - if (LittleFS.begin()) { - //start with opening the file - File outfh = LittleFS.open(TEMPLOG_FILE, "w"); - - if (outfh) { - //write to _reboot to file - outfh.print(log_line); - - if (strlen(log_line_regs)>2) { - outfh.print(log_line_regs); - } - - File infh = LittleFS.open(REBOOTLOG_FILE, "r"); - - int i = 1; - if (infh) { - //read from file - while (infh.available() && (i < LOG_LINES)){ - //read the first line - String line = infh.readStringUntil('\n'); - if (line.length() > 3) { //TODO: check is no longer needed? - outfh.print(line); - } - i++; - } - infh.close(); - } - outfh.close(); - - if (LittleFS.exists(REBOOTLOG_FILE)) { - LittleFS.remove(REBOOTLOG_FILE); - } - - LittleFS.rename(TEMPLOG_FILE, REBOOTLOG_FILE); - - return true; // succesfully logged - } - } - - return false; // logging unsuccesfull -} - - -void doRestart(const char* str) { - DebugTln(str); - delay(2000); // Enough time for messages to be sent. - ESP.restart(); - delay(5000); // Enough time to ensure we don't return. -} - -String upTime() -{ - char calcUptime[20]; - - snprintf(calcUptime, sizeof(calcUptime), "%d(d)-%02d:%02d(H:m)" - , int((upTimeSeconds / (60 * 60 * 24)) % 365) - , int((upTimeSeconds / (60 * 60)) % 24) - , int((upTimeSeconds / (60)) % 60)); - - return calcUptime; - -} // upTime() - -bool prefix(const char *pre, const char *str) -{ - return strncmp(pre, str, strlen(pre)) == 0; -} - -bool yearChanged(){ - static int16_t lastyear = -1; - TimeZone myTz = timezoneManager.createForZoneName(CSTR(settingNTPtimezone)); - ZonedDateTime myTime = ZonedDateTime::forUnixSeconds64(time(nullptr), myTz); - int8_t thisyear = myTime.year(); - bool _ret = (lastyear != thisyear); //year changed - if (_ret) { - //year changed - lastyear = thisyear; - } - return _ret; -} - -bool dayChanged(){ - static int8_t lastday = -1; - TimeZone myTz = timezoneManager.createForZoneName(CSTR(settingNTPtimezone)); - ZonedDateTime myTime = ZonedDateTime::forUnixSeconds64(time(nullptr), myTz); - int8_t thisday = myTime.day(); - bool _ret = (lastday != thisday); - if (_ret) { - //day changed - lastday = thisday; - } - return _ret; -} - -bool hourChanged(){ - static int8_t lasthour = -1; - TimeZone myTz = timezoneManager.createForZoneName(CSTR(settingNTPtimezone)); - ZonedDateTime myTime = ZonedDateTime::forUnixSeconds64(time(nullptr), myTz); - int8_t thishour = myTime.hour(); - bool _ret = (lasthour != thishour); - if (_ret){ - //hour changed - lasthour = thishour; - } - return _ret; -} - -bool minuteChanged(){ - static int8_t lastminute = -1; - TimeZone myTz = timezoneManager.createForZoneName(CSTR(settingNTPtimezone)); - ZonedDateTime myTime = ZonedDateTime::forUnixSeconds64(time(nullptr), myTz); - int8_t thisminute = myTime.minute(); - bool _ret = (lastminute != thisminute); - if (_ret){ - //minute changed - lastminute = thisminute; - } - return _ret; -} - -/* - check if the version githash is in the littlefs as version.hash - -*/ -bool checklittlefshash(){ - #define GITHASH_FILE "/version.hash" - String _githash=""; - if (LittleFS.begin()) { - //start with opening the file - File fh = LittleFS.open(GITHASH_FILE, "r"); - if (fh) { - //read from file - if (fh.available()){ - //read the first line - _githash = fh.readStringUntil('\n'); - } - } - DebugTf(PSTR("Check githash = [%s]\r\n"), CSTR(_githash)); - return (strcasecmp(CSTR(_githash), _VERSION_GITHASH)==0); - } - return false; -} - - -/* -** Does not generate hex character constants. -** Always generates triple-digit octal constants. -** Always generates escapes in preference to octal. -** Escape question mark to ensure no trigraphs are generated by repetitive use. -** Handling of 0x80..0xFF is locale-dependent (might be octal, might be literal). -*/ - -void chr_cstrlit(unsigned char u, char *buffer, size_t buflen) -{ - if (buflen < 2) - *buffer = '\0'; - else if (isprint(u) && u != '\'' && u != '\"' && u != '\\' && u != '\?') - sprintf(buffer, "%c", u); - else if (buflen < 3) - *buffer = '\0'; - else - { - switch (u) - { - case '\a': strcpy(buffer, "\\a"); break; - case '\b': strcpy(buffer, "\\b"); break; - case '\f': strcpy(buffer, "\\f"); break; - case '\n': strcpy(buffer, "\\n"); break; - case '\r': strcpy(buffer, "\\r"); break; - case '\t': strcpy(buffer, "\\t"); break; - case '\v': strcpy(buffer, "\\v"); break; - case '\\': strcpy(buffer, "\\\\"); break; - case '\'': strcpy(buffer, "\\'"); break; - case '\"': strcpy(buffer, "\\\""); break; - case '\?': strcpy(buffer, "\\\?"); break; - default: - if (buflen < 5) - *buffer = '\0'; - else - sprintf(buffer, "\\%03o", u); - break; - } - } -} - -void str_cstrlit(const char *str, char *buffer, size_t buflen) -{ - unsigned char u; - size_t len; - - while ((u = (unsigned char)*str++) != '\0') - { - chr_cstrlit(u, buffer, buflen); - if ((len = strlen(buffer)) == 0) - return; - buffer += len; - buflen -= len; - } - *buffer = '\0'; -} - -String strHTTPmethod(HTTPMethod method) -{ - switch (method) - { - case HTTPMethod::HTTP_GET: - return "GET"; - case HTTPMethod::HTTP_POST: - return "POST"; - case HTTPMethod::HTTP_PUT: - return "PUT"; - case HTTPMethod::HTTP_PATCH: - return "PATCH"; - case HTTPMethod::HTTP_DELETE: - return "DELETE"; - case HTTPMethod::HTTP_OPTIONS: - return "OPTIONS"; - case HTTPMethod::HTTP_HEAD: - return "HEAD"; - default: - return ""; - } -} - -/* - * Written by Ahmad Shamshiri - * with lots of research, this sources was used: - * https://support.randomsolutions.nl/827069-Best-dBm-Values-for-Wifi - * This is approximate percentage calculation of RSSI - * WiFi Signal Strength Calculation - * Written Aug 08, 2019 at 21:45 in Ajax, Ontario, Canada - */ - -int dBmtoPercentage(int dBm) -{ - const int RSSI_MAX =-50;// define maximum strength of signal in dBm - const int RSSI_MIN =-100;// define minimum strength of signal in dBm - int quality; - if(dBm <= RSSI_MIN){ - quality = 0; - } else if(dBm >= RSSI_MAX) { - quality = 100; - } else { - quality = 2 * (dBm + 100); - } - - return quality; -}//dBmtoPercentage - -/* - RSSI signal quality to percentage quad function - https://www.intuitibits.com/2016/03/23/dbm-to-percent-conversion/#comment-9 - https://gist.github.com/senseisimple/002cdba344de92748695a371cef0176a -*/ - -int signal_quality_perc_quad(int rssi) { - const int perfect_rssi = -50; - const int worst_rssi = -85; - int nominal_rssi = perfect_rssi - worst_rssi; - int signal_quality = ceil(100 * nominal_rssi * nominal_rssi - (perfect_rssi - rssi) * (15 * nominal_rssi + 62 * (perfect_rssi - rssi))) / (nominal_rssi * nominal_rssi); - if (signal_quality > 100) { - signal_quality = 100; - } else if (signal_quality < 1) { - signal_quality = 0; - } - return signal_quality; -} - - - -/* - dBm to Quality statement TL:DR - --> https://support.randomsolutions.nl/827069-Best-dBm-Values-for-Wifi - --> https://www.metageek.com/training/resources/wifi-signal-strength-basics/ - TL;DR strings on quality is based on this -*/ -String dBmtoQuality(int dBm) -{ - String _ret="Amazing"; - if (dBm<=-67) { _ret = "Very good";} - if (dBm<=-70) { _ret = "Okay";} - if (dBm<=-80) { _ret = "Not good enough";} - if (dBm<=-90) { _ret = "Unusable";} - //if (dBm<=-30) { _ret = "Amazing";} - - return (_ret); -}//dBmtoPercentage - -/*************************************************************************** -* -* Permission is hereby granted, free of charge, to any person obtaining a -* copy of this software and associated documentation files (the -* "Software"), to deal in the Software without restriction, including -* without limitation the rights to use, copy, modify, merge, publish, -* distribute, sublicense, and/or sell copies of the Software, and to permit -* persons to whom the Software is furnished to do so, subject to the -* following conditions: -* -* The above copyright notice and this permission notice shall be included -* in all copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT -* OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR -* THE USE OR OTHER DEALINGS IN THE SOFTWARE. -* -**************************************************************************** -*/ diff --git a/jsonStuff.ino.tmp b/jsonStuff.ino.tmp new file mode 100644 index 00000000..f55ca317 --- /dev/null +++ b/jsonStuff.ino.tmp @@ -0,0 +1,332 @@ +/* +*************************************************************************** +** Program : jsonStuff +** Version : v0.10.2 +** +** Copyright (c) 2021-2023 Robert van den Breemen +** based on Framework ESP8266 from Willem Aandewiel +** +** TERMS OF USE: MIT License. See bottom of file. +*************************************************************************** +*/ +static int iIdentlevel = 0; +char sBeforenext[10] =""; +bool bFirst = true; + +//======================================================================= +void sendStartJsonObj(const char *objName) +{ + char sBuff[50] = ""; + sBeforenext[0]='\0'; + + if (strlen(objName)==0){ + snprintf(sBuff, sizeof(sBuff), "{\r\n"); + }else { + snprintf(sBuff, sizeof(sBuff), "{\"%s\":[\r\n", objName); + } + httpServer.sendHeader("Access-Control-Allow-Origin", "*"); + httpServer.setContentLength(CONTENT_LENGTH_UNKNOWN); + httpServer.send(200, "application/json", sBuff); + iIdentlevel++; + bFirst = true; + +} // sendStartJsonObj() + + +//======================================================================= +void sendEndJsonObj(const char *objName) +{ + iIdentlevel--; + if (strlen(objName)==0){ + httpServer.sendContent("\r\n}\r\n"); + } else { + httpServer.sendContent("\r\n]}\r\n"); + } + +} // sendEndJsonObj() +//======================================================================= +void sendStartJsonArray() +{ + httpServer.sendHeader("Access-Control-Allow-Origin", "*"); + httpServer.setContentLength(CONTENT_LENGTH_UNKNOWN); + httpServer.send(200, "application/json", "[\r\n"); + iIdentlevel++; + bFirst = true; + +} // sendStartJsonObj() + + +//======================================================================= +void sendEndJsonArray() +{ + iIdentlevel--; + httpServer.sendContent("\r\n]\r\n"); +} // sendEndJsonObj() +//======================================================================= +void sendIdent(){ + for (int i = iIdentlevel; i >0; i--){ + httpServer.sendContent(" "); + } +} //sendIdent() +//======================================================================= +void sendBeforenext(){ + if (!bFirst){ + httpServer.sendContent(",\r\n"); + } + bFirst = false; +} //sendBeforenext() +//======================================================================= +void sendNestedJsonObj(const char *cName, const char *cValue) +{ + char jsonBuff[JSON_BUFF_MAX] = ""; + + snprintf(jsonBuff, sizeof(jsonBuff), "{\"name\": \"%s\", \"value\": \"%s\"}", cName, cValue); + + sendBeforenext(); + sendIdent(); + httpServer.sendContent(jsonBuff); +} // sendNestedJsonObj(*char, *char) +//======================================================================= +void sendNestedJsonObj(const char *cName, String sValue) +{ + char jsonBuff[JSON_BUFF_MAX] = ""; + + if (sValue.length() > (JSON_BUFF_MAX - 65) ) + { + DebugTf(PSTR("[2] sValue.length() [%d]\r\n"), sValue.length()); + } + + snprintf(jsonBuff, sizeof(jsonBuff), "{\"name\": \"%s\", \"value\": \"%s\"}", cName, sValue.c_str()); + + sendBeforenext(); + sendIdent(); + httpServer.sendContent(jsonBuff); + +} // sendNestedJsonObj(*char, String) + + +//======================================================================= +void sendNestedJsonObj(const char *cName, int32_t iValue) +{ + char jsonBuff[200] = ""; + + snprintf(jsonBuff, sizeof(jsonBuff), "{\"name\": \"%s\", \"value\": %d}", cName, iValue); + + sendBeforenext(); + sendIdent(); + httpServer.sendContent(jsonBuff); + +} // sendNestedJsonObj(*char, int) + +//======================================================================= +void sendNestedJsonObj(const char *cName, uint32_t uValue) +{ + char jsonBuff[200] = ""; + + snprintf(jsonBuff, sizeof(jsonBuff), "{\"name\": \"%s\", \"value\": %u}", cName, uValue); + + sendBeforenext(); + sendIdent(); + httpServer.sendContent(jsonBuff); + +} // sendNestedJsonObj(*char, uint) + + +//======================================================================= +void sendNestedJsonObj(const char *cName, float fValue) +{ + char jsonBuff[200] = ""; + + snprintf(jsonBuff, sizeof(jsonBuff), "{\"name\": \"%s\", \"value\": %.3f}", cName, fValue); + + sendBeforenext(); + sendIdent(); + httpServer.sendContent(jsonBuff); + +} // sendNestedJsonObj(*char, float) + + +//============= build OTmonitor string ======================== +void sendJsonOTmonObj(const char *cName, const char *cValue, const char *cUnit, time_t epoch) +{ + char jsonBuff[JSON_BUFF_MAX] = ""; + + snprintf(jsonBuff, sizeof(jsonBuff), "{\"name\": \"%s\", \"value\": \"%s\", \"unit\": \"%s\", \"epoch\": %d}" + , cName, cValue, cUnit, (uint32_t)epoch); + + sendBeforenext(); + sendIdent(); + httpServer.sendContent(jsonBuff); + +} // sendJsonOTmonObj(*char, *char, *char) + +//======================================================================= +void sendJsonOTmonObj(const char *cName, int32_t iValue, const char *cUnit, time_t epoch) +{ + char jsonBuff[200] = ""; + + snprintf(jsonBuff, sizeof(jsonBuff), "{\"name\": \"%s\", \"value\": %d, \"unit\": \"%s\", \"epoch\": %d}" + , cName, iValue, cUnit, (uint32_t)epoch); + + sendBeforenext(); + sendIdent(); + httpServer.sendContent(jsonBuff); + +} // sendJsonOTmonObj(*char, int, *char) + +//======================================================================= +void sendJsonOTmonObj(const char *cName, uint32_t uValue, const char *cUnit, time_t epoch) +{ + char jsonBuff[200] = ""; + + snprintf(jsonBuff, sizeof(jsonBuff), "{\"name\": \"%s\", \"value\": %u, \"unit\": \"%s\", \"epoch\": %d}" + , cName, uValue, cUnit, (uint32_t)epoch); + + sendBeforenext(); + sendIdent(); + httpServer.sendContent(jsonBuff); + +} // sendNestedJsonObj(*char, uint, *char, time_t) + + +//======================================================================= +void sendJsonOTmonObj(const char *cName, float fValue, const char *cUnit, time_t epoch) +{ + char jsonBuff[200] = ""; + + snprintf(jsonBuff, sizeof(jsonBuff), "{\"name\": \"%s\", \"value\": %.3f, \"unit\": \"%s\", \"epoch\": %d}" + , cName, fValue, cUnit, (uint32_t)epoch); + + sendBeforenext(); + sendIdent(); + httpServer.sendContent(jsonBuff); + +} // sendJsonOTmonObj(*char, float, *char, time_t) +//======================================================================= +void sendJsonOTmonObj(const char *cName, bool bValue, const char *cUnit, time_t epoch) +{ + char jsonBuff[200] = ""; + + snprintf(jsonBuff, sizeof(jsonBuff), "{\"name\": \"%s\", \"value\": %s, \"unit\": \"%s\", \"epoch\": %d}" + , cName, CBOOLEAN(bValue), cUnit, (uint32_t)epoch); + + sendBeforenext(); + sendIdent(); + httpServer.sendContent(jsonBuff); + +} // sendJsonOTmonObj(*char, bool, *char, time_t) +//======================================================================= +// ************ function to build Json Settings string ****************** +//======================================================================= +void sendJsonSettingObj(const char *cName, float fValue, const char *fType, int minValue, int maxValue) +{ + char jsonBuff[200] = ""; + + snprintf(jsonBuff, sizeof(jsonBuff), "{\"name\": \"%s\", \"value\": %.3f, \"type\": \"%s\", \"min\": %d, \"max\": %d}" + , cName, fValue, fType, minValue, maxValue); + + sendBeforenext(); + sendIdent(); + httpServer.sendContent(jsonBuff); + +} // sendJsonSettingObj(*char, float, *char, int, int) + + +//======================================================================= +void sendJsonSettingObj(const char *cName, float fValue, const char *fType, int minValue, int maxValue, int decPlaces) +{ + char jsonBuff[200] = ""; + + switch(decPlaces) { + case 0: + snprintf(jsonBuff, sizeof(jsonBuff), "{\"name\": \"%s\", \"value\": %.0f, \"type\": \"%s\", \"min\": %d, \"max\": %d}" + , cName, fValue, fType, minValue, maxValue); + break; + case 2: + snprintf(jsonBuff, sizeof(jsonBuff), "{\"name\": \"%s\", \"value\": %.2f, \"type\": \"%s\", \"min\": %d, \"max\": %d}" + , cName, fValue, fType, minValue, maxValue); + break; + case 5: + snprintf(jsonBuff, sizeof(jsonBuff), "{\"name\": \"%s\", \"value\": %.5f, \"type\": \"%s\", \"min\": %d, \"max\": %d}" + , cName, fValue, fType, minValue, maxValue); + break; + default: + snprintf(jsonBuff, sizeof(jsonBuff), "{\"name\": \"%s\", \"value\": %f, \"type\": \"%s\", \"min\": %d, \"max\": %d}" + , cName, fValue, fType, minValue, maxValue); + + } + + sendBeforenext(); + sendIdent(); + httpServer.sendContent(jsonBuff); + +} // sendJsonSettingObj(*char, float, *char, int, int, int) + + +//======================================================================= +void sendJsonSettingObj(const char *cName, int iValue, const char *iType, int minValue, int maxValue) +{ + char jsonBuff[200] = ""; + + snprintf(jsonBuff, sizeof(jsonBuff), "{\"name\": \"%s\", \"value\": %d, \"type\": \"%s\", \"min\": %d, \"max\": %d}" + , cName, iValue, iType, minValue, maxValue); + + sendBeforenext(); + sendIdent(); + httpServer.sendContent(jsonBuff); +} // sendJsonSettingObj(*char, int, *char, int, int) + + +//======================================================================= + +void sendJsonSettingObj(const char *cName, const char *cValue, const char *sType, int maxLen) +{ + char jsonBuff[200] = {0}; + char buffer[100] = {0}; + + str_cstrlit(cValue, buffer, sizeof(buffer)); + snprintf(jsonBuff, sizeof(jsonBuff), "{\"name\": \"%s\", \"value\":\"%s\", \"type\": \"%s\", \"maxlen\": %d}" + , cName, cValue, sType, maxLen); + + sendBeforenext(); + sendIdent(); + httpServer.sendContent(jsonBuff); + +} // sendJsonSettingObj(*char, *char, *char, int, int) + +//======================================================================= +void sendJsonSettingObj(const char *cName, bool bValue, const char *sType) +{ + char jsonBuff[200] = ""; + + snprintf(jsonBuff, sizeof(jsonBuff), "{\"name\": \"%s\", \"value\":\"%s\", \"type\": \"%s\"}" + , cName, CBOOLEAN(bValue), sType); + + sendBeforenext(); + sendIdent(); + httpServer.sendContent(jsonBuff); + +} // sendJsonSettingObj(*char, bool, *char) +/*************************************************************************** +* +* Permission is hereby granted, free of charge, to any person obtaining a +* copy of this software and associated documentation files (the +* "Software"), to deal in the Software without restriction, including +* without limitation the rights to use, copy, modify, merge, publish, +* distribute, sublicense, and/or sell copies of the Software, and to permit +* persons to whom the Software is furnished to do so, subject to the +* following conditions: +* +* The above copyright notice and this permission notice shall be included +* in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT +* OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR +* THE USE OR OTHER DEALINGS IN THE SOFTWARE. +* +**************************************************************************** +*/ From 1ab79610ebc242068b53e39e100fdd79dd693eed Mon Sep 17 00:00:00 2001 From: Robert van den Breemen Date: Mon, 15 Apr 2024 23:58:11 +0200 Subject: [PATCH 08/13] update version to 0.10.3 --- MQTTstuff.ino.tmp | 698 ---------------------------------------------- jsonStuff.ino.tmp | 332 ---------------------- 2 files changed, 1030 deletions(-) delete mode 100644 MQTTstuff.ino.tmp delete mode 100644 jsonStuff.ino.tmp diff --git a/MQTTstuff.ino.tmp b/MQTTstuff.ino.tmp deleted file mode 100644 index 45be66b6..00000000 --- a/MQTTstuff.ino.tmp +++ /dev/null @@ -1,698 +0,0 @@ -/* -*************************************************************************** -** Program : MQTTstuff -** Version : v0.10.2 -** -** Copyright (c) 2021-2023 Robert van den Breemen -** Modified version from (c) 2020 Willem Aandewiel -** -** TERMS OF USE: MIT License. See bottom of file. -*************************************************************************** -*/ - -#include // MQTT client publish and subscribe functionality - -#define MQTTDebugTln(...) ({ if (bDebugMQTT) DebugTln(__VA_ARGS__); }) -#define MQTTDebugln(...) ({ if (bDebugMQTT) Debugln(__VA_ARGS__); }) -#define MQTTDebugTf(...) ({ if (bDebugMQTT) DebugTf(__VA_ARGS__); }) -#define MQTTDebugf(...) ({ if (bDebugMQTT) Debugf(__VA_ARGS__); }) -#define MQTTDebugT(...) ({ if (bDebugMQTT) DebugT(__VA_ARGS__); }) -#define MQTTDebug(...) ({ if (bDebugMQTT) Debug(__VA_ARGS__); }) - -// Declare some variables within global scope - -static IPAddress MQTTbrokerIP; -static char MQTTbrokerIPchar[20]; - -static PubSubClient MQTTclient(wifiClient); - -int8_t reconnectAttempts = 0; -char lastMQTTtimestamp[15] = ""; - -enum states_of_MQTT { MQTT_STATE_INIT, MQTT_STATE_TRY_TO_CONNECT, MQTT_STATE_IS_CONNECTED, MQTT_STATE_WAIT_CONNECTION_ATTEMPT, MQTT_STATE_WAIT_FOR_RECONNECT, MQTT_STATE_ERROR }; -enum states_of_MQTT stateMQTT = MQTT_STATE_INIT; - -String MQTTclientId; -String MQTTPubNamespace = ""; -String MQTTSubNamespace = ""; -String NodeId = ""; - -//set command list -struct MQTT_set_cmd_t -{ - const char* setcmd; - const char* otgwcmd; - const char* ottype; -}; - - -const MQTT_set_cmd_t setcmds[] { - { "command", "", "raw" }, - { "setpoint", "TT", "temp" }, - { "constant", "TC", "temp" }, - { "outside", "OT", "temp" }, - { "hotwater", "HW", "on" }, - { "gatewaymode", "GW", "on" }, - { "setback", "SB", "temp" }, - { "maxchsetpt", "SH", "temp" }, - { "maxdhwsetpt", "SW", "temp" }, - { "maxmodulation", "MM", "level" }, - { "ctrlsetpt", "CS", "temp" }, - { "ctrlsetpt2", "C2", "temp" }, - { "chenable", "CH", "on" }, - { "chenable2", "H2", "on" }, - { "ventsetpt", "VS", "level" }, - { "temperaturesensor", "TS", "function" }, - { "addalternative", "AA", "function" }, - { "delalternative", "DA", "function" }, - { "unknownid", "UI", "function" }, - { "knownid", "KI", "function" }, - { "priomsg", "PM", "function" }, - { "setresponse", "SR", "function" }, - { "clearrespons", "CR", "function" }, - { "resetcounter", "RS", "function" }, - { "ignoretransitations", "IT", "function" }, - { "overridehb", "OH", "function" }, - { "forcethermostat", "FT", "function" }, - { "voltageref", "VR", "function" }, - { "debugptr", "DP", "function" }, -} ; - -const int nrcmds = sizeof(setcmds) / sizeof(setcmds[0]); - -// const char learnmsg[] { "LA", "PR=L", "LB", "PR=L", "LC", "PR=L", "LD", "PR=L", "LE", "PR=L", "LF", "PR=L", "GA", "PR=G", "GB", "PR=G", "VR", "PR=V", "GW", "PR=M", "IT", "PR=T", "SB", "PR=S", "HW", "PR=W" } ; -// const int nrlearnmsg = sizeof(learnmsg) / sizeof(learnmsg[0]); - -//=========================================================================================== -void startMQTT() -{ - if (!settingMQTTenable) return; - stateMQTT = MQTT_STATE_INIT; - //setup for mqtt discovery - clearMQTTConfigDone(); - NodeId = settingMQTTuniqueid; - MQTTPubNamespace = settingMQTTtopTopic + "/value/" + NodeId; - MQTTSubNamespace = settingMQTTtopTopic + "/set/" + NodeId; - handleMQTT(); //initialize the MQTT statemachine - // handleMQTT(); //then try to connect to MQTT - // handleMQTT(); //now you should be connected to MQTT ready to send -} - -bool bHAcycle = false; - -// handles MQTT subscribe incoming stuff -void handleMQTTcallback(char* topic, byte* payload, unsigned int length) { - - if (bDebugMQTT) { - DebugT("Message arrived on topic ["); Debug(topic); Debug("] = ["); - for (unsigned int i = 0; i < length; i++) { - Debug((char)payload[i]); - } - Debug("] ("); Debug(length); Debug(")"); Debugln(); DebugFlush(); - } - - //detect home assistant going down... - char msgPayload[50]; - int msglen = min((int)(length)+1, (int)sizeof(msgPayload)); - strlcpy(msgPayload, (char *)payload, msglen); - if (strcasecmp(topic, "homeassistant/status") == 0) { - //incoming message on status, detect going down - if (!settingMQTTharebootdetection) { - //So if the HA reboot detection is turned of, we will just look for HA going online. - //This means everytime there is "online" message, we will restart MQTT configuration, including the HA Auto Discovery. - bHAcycle = true; - } - if (strcasecmp(msgPayload, "offline") == 0){ - //home assistant went down - DebugTln(F("Home Assistant went offline!")); - bHAcycle = true; //set flag, so it triggers when it goes back online - } else if ((strcasecmp(msgPayload, "online") == 0) && bHAcycle){ - DebugTln(F("Home Assistant went online!")); - bHAcycle = false; //clear flag, so it does not trigger again - //restart stuff, to make sure it works correctly again - startMQTT(); // fixing some issues with hanging HA AutoDiscovery in some scenario's? - } else { - DebugTf(PSTR("Home Assistant Status=[%s] and HA cycle status [%s]\r\n"), msgPayload, CBOOLEAN(bHAcycle)); - } - } - - - // parse the incoming topic and execute commands - char* token; - char otgwcmd[51]={0}; - - //first check toptopic part, it can include the seperator, e.g. "myHome/OTGW" or "OTGW"" - if (strncmp(topic, settingMQTTtopTopic.c_str(), settingMQTTtopTopic.length()) != 0) { - MQTTDebugln(F("MQTT: wrong top topic")); - return; - } else { - //remove the top topic part - MQTTDebugTf(PSTR("Parsing topic: %s/"), settingMQTTtopTopic.c_str()); - topic += settingMQTTtopTopic.length(); - while (*topic == '/') { - topic++; - } - } - // naming convention /set// - token = strtok(topic, "/"); - MQTTDebugf("%s/", token); - if (strcasecmp(token, "set") == 0) { - token = strtok(NULL, "/"); - MQTTDebugf("%s/", token); - if (strcasecmp(token, CSTR(NodeId)) == 0) { - token = strtok(NULL, "/"); - MQTTDebugf("%s", token); - if (token != NULL){ - //loop thru command list - int i; - for (i=0; i= - snprintf(otgwcmd, sizeof(otgwcmd), "%s=%s", setcmds[i].otgwcmd, msgPayload); - MQTTDebugf(" found command, sending payload [%s]\r\n", otgwcmd); - addOTWGcmdtoqueue((char *)otgwcmd, strlen(otgwcmd), true); - } - break; //exit loop - } - } - if (i >= nrcmds){ - //no match found - MQTTDebugln(); - MQTTDebugTf(PSTR("No match found for command: [%s]\r\n"), token); - } - } - } - } -} - -//=========================================================================================== -void handleMQTT() -{ - if (!settingMQTTenable) return; - DECLARE_TIMER_SEC(timerMQTTwaitforconnect, 42, CATCH_UP_MISSED_TICKS); // wait before trying to connect again - DECLARE_TIMER_SEC(timerMQTTwaitforretry, 3, CATCH_UP_MISSED_TICKS); // wait for retry - - //State debug timers - DECLARE_TIMER_SEC(timerMQTTdebugwaitforreconnect, 13); - DECLARE_TIMER_SEC(timerMQTTdebugerrorstate, 13); - DECLARE_TIMER_SEC(timerMQTTdebugwaitconnectionattempt, 1); - DECLARE_TIMER_SEC(timerMQTTdebugisconnected, 60); - - if (MQTTclient.connected()) MQTTclient.loop(); //always do a MQTTclient.loop() first - - switch(stateMQTT) - { - case MQTT_STATE_INIT: - MQTTDebugTln(F("MQTT State: MQTT Initializing")); - WiFi.hostByName(CSTR(settingMQTTbroker), MQTTbrokerIP); // lookup the MQTTbroker convert to IP - sprintf(MQTTbrokerIPchar, "%d.%d.%d.%d", MQTTbrokerIP[0], MQTTbrokerIP[1], MQTTbrokerIP[2], MQTTbrokerIP[3]); - if (isValidIP(MQTTbrokerIP)) - { - MQTTDebugTf(PSTR("[%s] => setServer(%s, %d)\r\n"), CSTR(settingMQTTbroker), MQTTbrokerIPchar, settingMQTTbrokerPort); - MQTTclient.disconnect(); - MQTTclient.setServer(MQTTbrokerIPchar, settingMQTTbrokerPort); - MQTTclient.setCallback(handleMQTTcallback); - MQTTclient.setSocketTimeout(4); - MQTTclientId = String(_HOSTNAME) + WiFi.macAddress(); - //skip try to connect - reconnectAttempts =0; - stateMQTT = MQTT_STATE_TRY_TO_CONNECT; - } - else - { // invalid IP, then goto error state - MQTTDebugTf(PSTR("ERROR: [%s] => is not a valid URL\r\n"), CSTR(settingMQTTbroker)); - stateMQTT = MQTT_STATE_ERROR; - //DebugTln(F("Next State: MQTT_STATE_ERROR")); - } - RESTART_TIMER(timerMQTTwaitforconnect); - break; - - case MQTT_STATE_TRY_TO_CONNECT: - MQTTDebugTln(F("MQTT State: MQTT try to connect")); - MQTTDebugTf(PSTR("MQTT server is [%s], IP[%s]\r\n"), settingMQTTbroker.c_str(), MQTTbrokerIPchar); - - MQTTDebugT(F("Attempting MQTT connection .. ")); - reconnectAttempts++; - - //If no username, then anonymous connection to broker, otherwise assume username/password. - if (settingMQTTuser.length() == 0) - { - MQTTDebug(F("without a Username/Password ")); - if(!MQTTclient.connect(CSTR(MQTTclientId), CSTR(MQTTPubNamespace), 0, true, "offline")) PrintMQTTError(); - } - else - { - MQTTDebugf("Username [%s] ", CSTR(settingMQTTuser)); - if(!MQTTclient.connect(CSTR(MQTTclientId), CSTR(settingMQTTuser), CSTR(settingMQTTpasswd), CSTR(MQTTPubNamespace), 0, true, "offline")) PrintMQTTError(); - } - - //If connection was made succesful, move on to next state... - if (MQTTclient.connected()) - { - reconnectAttempts = 0; - MQTTDebugln(F(" .. connected\r")); - Debugln(F("MQTT connected")); - stateMQTT = MQTT_STATE_IS_CONNECTED; - MQTTDebugTln(F("Next State: MQTT_STATE_IS_CONNECTED")); - // birth message, sendMQTT retains by default - sendMQTT(CSTR(MQTTPubNamespace), "online"); - - // First do AutoConfiguration for Homeassistant - // doAutoConfigure(); - - //Subscribe to topics - char topic[100]; - strcpy(topic, CSTR(MQTTSubNamespace)); - strlcat(topic, "/#", sizeof(topic)); - MQTTDebugTf(PSTR("Subscribe to MQTT: TopicId [%s]\r\n"), topic); - if (MQTTclient.subscribe(topic)){ - MQTTDebugTf(PSTR("MQTT: Subscribed successfully to TopicId [%s]\r\n"), topic); - } - else - { - MQTTDebugTf(PSTR("MQTT: Subscribe TopicId [%s] FAILED! \r\n"), topic); - PrintMQTTError(); - } - MQTTclient.subscribe("homeassistant/status"); //start monitoring the status of homeassistant, if it goes down, then force a restart after it comes back online. - sendMQTTversioninfo(); - } - else - { // no connection, try again, do a non-blocking wait for 3 seconds. - MQTTDebugln(F(" .. \r")); - MQTTDebugTf(PSTR("failed, retrycount=[%d], rc=[%d] .. try again in 3 seconds\r\n"), reconnectAttempts, MQTTclient.state()); - RESTART_TIMER(timerMQTTwaitforretry); - stateMQTT = MQTT_STATE_WAIT_CONNECTION_ATTEMPT; // if the re-connect did not work, then return to wait for reconnect - MQTTDebugTln(F("Next State: MQTT_STATE_WAIT_CONNECTION_ATTEMPT")); - } - - //After 5 attempts... go wait for a while. - if (reconnectAttempts >= 5) - { - MQTTDebugTln(F("5 attempts have failed. Retry wait for next reconnect in 10 minutes\r")); - RESTART_TIMER(timerMQTTwaitforconnect); - stateMQTT = MQTT_STATE_WAIT_FOR_RECONNECT; // if the re-connect did not work, then return to wait for reconnect - MQTTDebugTln(F("Next State: MQTT_STATE_WAIT_FOR_RECONNECT")); - } - break; - - case MQTT_STATE_IS_CONNECTED: - if DUE(timerMQTTdebugisconnected) MQTTDebugTln(F("MQTT State: MQTT is Connected")); - if (MQTTclient.connected()) - { //if the MQTT client is connected, then please do a .loop call... - MQTTclient.loop(); - } - else - { //else go and wait 10 minutes, before trying again. - RESTART_TIMER(timerMQTTwaitforconnect); - stateMQTT = MQTT_STATE_WAIT_FOR_RECONNECT; - MQTTDebugTln(F("Next State: MQTT_STATE_WAIT_FOR_RECONNECT")); - } - break; - - case MQTT_STATE_WAIT_CONNECTION_ATTEMPT: - //do non-blocking wait for 3 seconds - if DUE(timerMQTTdebugwaitconnectionattempt) MQTTDebugTln(F("MQTT State: MQTT_WAIT_CONNECTION_ATTEMPT")); - if (DUE(timerMQTTwaitforretry)) - { - //Try again... after waitforretry non-blocking delay - stateMQTT = MQTT_STATE_TRY_TO_CONNECT; - MQTTDebugTln(F("Next State: MQTT_STATE_TRY_TO_CONNECT")); - } - break; - - case MQTT_STATE_WAIT_FOR_RECONNECT: - //do non-blocking wait for 10 minutes, then try to connect again. - if DUE(timerMQTTdebugwaitforreconnect) MQTTDebugTln(F("MQTT State: MQTT wait for reconnect")); - if (DUE(timerMQTTwaitforconnect)) - { - //remember when you tried last time to reconnect - RESTART_TIMER(timerMQTTwaitforretry); - reconnectAttempts = 0; - stateMQTT = MQTT_STATE_TRY_TO_CONNECT; - MQTTDebugTln(F("Next State: MQTT_STATE_TRY_TO_CONNECT")); - } - break; - - case MQTT_STATE_ERROR: - if DUE(timerMQTTdebugerrorstate) MQTTDebugTln(F("MQTT State: MQTT ERROR, wait for 10 minutes, before trying again")); - //wait for next retry - RESTART_TIMER(timerMQTTwaitforconnect); - stateMQTT = MQTT_STATE_WAIT_FOR_RECONNECT; - MQTTDebugTln(F("Next State: MQTT_STATE_WAIT_FOR_RECONNECT")); - break; - - default: - MQTTDebugTln(F("MQTT State: default, this should NEVER happen!")); - //do nothing, this state should not happen - stateMQTT = MQTT_STATE_INIT; - DebugTln(F("Next State: MQTT_STATE_INIT")); - break; - } - statusMQTTconnection = MQTTclient.connected(); -} // handleMQTT() - -//=========================================================================================== -String trimVal(char *in) -{ - String Out = in; - Out.trim(); - return Out; -} // trimVal() - -void PrintMQTTError(){ - MQTTDebugln(); - switch (MQTTclient.state()) - { - case MQTT_CONNECTION_TIMEOUT : MQTTDebugTln(F("Error: MQTT connection timeout"));break; - case MQTT_CONNECTION_LOST : MQTTDebugTln(F("Error: MQTT connections lost"));break; - case MQTT_CONNECT_FAILED : MQTTDebugTln(F("Error: MQTT connection failed"));break; - case MQTT_DISCONNECTED : MQTTDebugTln(F("Error: MQTT disconnected"));break; - case MQTT_CONNECTED : MQTTDebugTln(F("Error: MQTT connected"));break; - case MQTT_CONNECT_BAD_PROTOCOL : MQTTDebugTln(F("Error: MQTT connect bad protocol"));break; - case MQTT_CONNECT_BAD_CLIENT_ID : MQTTDebugTln(F("Error: MQTT connect bad client id"));break; - case MQTT_CONNECT_UNAVAILABLE : MQTTDebugTln(F("Error: MQTT connect unavailable"));break; - case MQTT_CONNECT_BAD_CREDENTIALS: MQTTDebugTln(F("Error: MQTT connect bad credentials"));break; - case MQTT_CONNECT_UNAUTHORIZED : MQTTDebugTln(F("Error: MQTT connect unauthorized"));break; - default: MQTTDebugTln(F("Error: MQTT unknown error")); - } -} - -/* - topic: , sensor topic, will be automatically prefixed with /value/ - json: , payload to send - retain: , retain mqtt message -*/ -void sendMQTTData(const String topic, const String json, const bool retain = false) -{ - if (!settingMQTTenable) return; - sendMQTTData(CSTR(topic), CSTR(json), retain); -} - -/* - topic: , sensor topic, will be automatically prefixed with /value/ - json: , payload to send - retain: , retain mqtt message -*/ -void sendMQTTData(const char* topic, const char *json, const bool retain = false) -{ - if (!settingMQTTenable) return; - if (!MQTTclient.connected()) {DebugTln(F("Error: MQTT broker not connected.")); PrintMQTTError(); return;} - if (!isValidIP(MQTTbrokerIP)) {DebugTln(F("Error: MQTT broker IP not valid.")); return;} - char full_topic[100]; - snprintf(full_topic, sizeof(full_topic), "%s/", CSTR(MQTTPubNamespace)); - strlcat(full_topic, topic, sizeof(full_topic)); - MQTTDebugTf(PSTR("Sending MQTT: server %s:%d => TopicId [%s] --> Message [%s]\r\n"), settingMQTTbroker.c_str(), settingMQTTbrokerPort, full_topic, json); - if (!MQTTclient.publish(full_topic, json, retain)) PrintMQTTError(); - feedWatchDog();//feed the dog -} // sendMQTTData() - -/* -* topic: , topic will be used as is (no prefixing), retained = true -* json: , payload to send -*/ -//=========================================================================================== -void sendMQTT(String topic, String json){ - if (!settingMQTTenable) return; - sendMQTT(CSTR(topic), CSTR(json), json.length()); -} - -void sendMQTT(const char* topic, const char *json, const size_t len) -{ - if (!settingMQTTenable) return; - if (!MQTTclient.connected()) {DebugTln(F("Error: MQTT broker not connected.")); PrintMQTTError(); return;} - if (!isValidIP(MQTTbrokerIP)) {DebugTln(F("Error: MQTT broker IP not valid.")); return;} - MQTTDebugTf(PSTR("Sending MQTT: server %s:%d => TopicId [%s] --> Message [%s]\r\n"), settingMQTTbroker.c_str(), settingMQTTbrokerPort, topic, json); - if (MQTTclient.getBufferSize() < len) MQTTclient.setBufferSize(len); //resize buffer when needed - - if (MQTTclient.beginPublish(topic, len, true)){ - for (size_t i = 0; i -1) sIn.remove(posC); // strip comments - - if (sIn.length() <= 3) return false; //not enough buffer, skip split - - unsigned int pos = sIn.indexOf(del); //determine first split point - if ((pos <= 0) || (pos == (sIn.length() - 1))) return false; // no key or no value - - unsigned int pos2 = sIn.indexOf(del, pos+1); //determine second split point, starting from the first found - if ((pos2 <= 0) || (pos2 <= pos) || (pos2 == (sIn.length() - 1))) return false; // no key or no value - - String sID = sIn.substring(0, pos); - sID.trim(); - cID = (byte)sID.toInt(); - - cKey = sIn.substring(pos+1, pos2); - cKey.trim(); //before, and trim spaces - - cVal = sIn.substring(pos2 + 1); - cVal.trim(); //after,and trim spaces - - // Debugf("Split line into: [%d] [%s] [%s]\r\n", cID, CSTR(cKey), CSTR(cVal)); DebugFlush(); - - return true; -} -//=========================================================================================== -bool getMQTTConfigDone(const uint8_t MSGid) -{ - uint8_t group = MSGid & 0b11100000; - group = group>>5; - uint8_t index = MSGid & 0b00011111; - uint32_t result = bitRead(MQTTautoConfigMap[group], index); - MQTTDebugTf(PSTR("Reading bit %d from group %d for MSGid %d: result = %d\r\n"), index, group, MSGid, result); - if (result > 0) { - return true; - } else { - return false; - } -} -//=========================================================================================== -bool setMQTTConfigDone(const uint8_t MSGid) -{ - uint8_t group = MSGid & 0b11100000; - group = group>>5; - uint8_t index = MSGid & 0b00011111; - MQTTDebugTf(PSTR("Setting bit %d from group %d for MSGid %d\r\n"), index, group, MSGid); - MQTTDebugTf(PSTR("Value before setting bit %d\r\n"), MQTTautoConfigMap[group]); - if(bitSet(MQTTautoConfigMap[group], index) > 0) { - MQTTDebugTf(PSTR("Value after setting bit %d\r\n"), MQTTautoConfigMap[group]); - return true; - } else { - return false; - } -} -//=========================================================================================== -void clearMQTTConfigDone() -{ - memset(MQTTautoConfigMap, 0, sizeof(MQTTautoConfigMap)); -} -//=========================================================================================== -void doAutoConfigure(bool bForcaAll = false){ - //force all sensors to be sent to auto configuration - for (int i=0; i<255; i++){ - if ((getMQTTConfigDone((byte)i)==true) || bForcaAll) { - MQTTDebugTf(PSTR("Sending auto configuration for sensor %d\r\n"), i); - doAutoConfigureMsgid((byte)i); - doBackgroundTasks(); - } - } -// bool success = doAutoConfigure("config"); // the string "config" should match every line non-comment in mqttha.cfg -} -//=========================================================================================== -bool doAutoConfigureMsgid(byte OTid) -{ - String cfgSensorId = "" ; - // check if foney dataid is called to do autoconfigure for temp sensors, call configsensors instead - if (OTid == OTGWdallasdataid) { - MQTTDebugTf(PSTR("Sending auto configuration for temp sensors %d\r\n"), OTid); - configSensors() ; - return true; - } - else return doAutoConfigureMsgid(OTid, cfgSensorId); - } - - bool doAutoConfigureMsgid(byte OTid, String cfgSensorId ) -{ - bool _result = false; - - if (!settingMQTTenable) { - return _result; - } - if (!MQTTclient.connected()) { - DebugTln(F("Error: MQTT broker not connected.")); - return _result; - } - if (!isValidIP(MQTTbrokerIP)) { - DebugTln(F("Error: MQTT broker IP not valid.")); - return _result; - } - - byte lineID = 39; // 39 is unused in OT protocol so is a safe value - String sMsg = ""; - String sTopic = ""; - - //Let's open the MQTT autoconfig file - File fh; //filehandle - const char *cfgFilename = "/mqttha.cfg"; - LittleFS.begin(); - - if (!LittleFS.exists(cfgFilename)) { - DebugTln(F("Error: confuration file not found.")); - return _result; - } - - fh = LittleFS.open(cfgFilename, "r"); - - if (!fh) { - DebugTln(F("Error: could not open confuration file.")); - return _result; - } - - //Lets go read the config and send it out to MQTT line by line - while (fh.available()) - { - //read file line by line, split and send to MQTT (topic, msg) - feedWatchDog(); //start with feeding the dog - - String sLine = fh.readStringUntil('\n'); - // DebugTf(PSTR("sline[%s]\r\n"), CSTR(sLine)); - if (!splitLine(sLine, ';', lineID, sTopic, sMsg)) { //splitLine() also filters comments - //MQTTDebugTf(PSTR("Either comment or invalid config line: [%s]\r\n"), CSTR(sLine)); - continue; - } - - // DebugTf(PSTR("looking in config file line for %d: [%d][%s] \r\n"), OTid, lineID, CSTR(sTopic)); - - // check if this is the specific line we are looking for - if (lineID != OTid) continue; - - MQTTDebugTf(PSTR("Found line in config file for %d: [%d][%s] \r\n"), OTid, lineID, CSTR(sTopic)); - - // discovery topic prefix - MQTTDebugTf(PSTR("sTopic[%s]==>"), CSTR(sTopic)); - sTopic.replace("%homeassistant%", CSTR(settingMQTThaprefix)); - - /// node - sTopic.replace("%node_id%", CSTR(NodeId)); - - /// SensorId - sTopic.replace("%sensor_id%", CSTR(cfgSensorId)); - - MQTTDebugf("[%s]\r\n", CSTR(sTopic)); - /// ---------------------- - - MQTTDebugTf(PSTR("sMsg[%s]==>"), CSTR(sMsg)); - - /// node - sMsg.replace("%node_id%", CSTR(NodeId)); - - /// SensorId - sMsg.replace("%sensor_id%", CSTR(cfgSensorId)); - - /// hostname - sMsg.replace("%hostname%", CSTR(settingHostname)); - - /// version - sMsg.replace("%version%", _VERSION); - - // pub topics prefix - sMsg.replace("%mqtt_pub_topic%", CSTR(MQTTPubNamespace)); - - // sub topics - sMsg.replace("%mqtt_sub_topic%", CSTR(MQTTSubNamespace)); - - MQTTDebugf("[%s]\r\n", CSTR(sMsg)); - DebugFlush(); - - //sendMQTT(CSTR(sTopic), CSTR(sMsg), (sTopic.length() + sMsg.length()+2)); - sendMQTT(sTopic, sMsg); - resetMQTTBufferSize(); - // delay(10); - _result = true; - - // TODO: enable this break if we are sure the old config dump method is no longer needed - // break; - - } // while available() - - fh.close(); - - // HA discovery msg's are rather large, reset the buffer size to release some memory - resetMQTTBufferSize(); - - return _result; -} - -void sensorAutoConfigure(byte dataid, bool finishflag , String cfgSensorId = "") { - // Special version of Autoconfigure for sensors - // dataid is a foney id, not used by OT - // check wheter MQTT topic needs to be configured - // cfgNodeId can be set to alternate NodeId to allow for multiple temperature sensors, should normally be NodeId - // When finishflag is true, check on dataid is already done and complete the config. On false do the config and leave completion to caller - if(getMQTTConfigDone(dataid)==false or !finishflag) { - MQTTDebugTf(PSTR("Need to set MQTT config for sensor id(%d)\r\n"),dataid); - bool success = doAutoConfigureMsgid(dataid,cfgSensorId); - if(success) { - MQTTDebugTf(PSTR("Successfully sent MQTT config for sensor id(%d)\r\n"),dataid); - if (finishflag) setMQTTConfigDone(dataid); - } else { - MQTTDebugTf(PSTR("Not able to complete MQTT configuration for sensor id(%d)\r\n"),dataid); - } - } else { - // MQTTDebugTf("No need to set MQTT config for sensor id(%d)\r\n",dataid); - } - } - - - - -/*************************************************************************** -* -* Permission is hereby granted, free of charge, to any person obtaining a -* copy of this software and associated documentation files (the -* "Software"), to deal in the Software without restriction, including -* without limitation the rights to use, copy, modify, merge, publish, -* distribute, sublicense, and/or sell copies of the Software, and to permit -* persons to whom the Software is furnished to do so, subject to the -* following conditions: -* -* The above copyright notice and this permission notice shall be included -* in all copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT -* OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR -* THE USE OR OTHER DEALINGS IN THE SOFTWARE. -* -***************************************************************************/ diff --git a/jsonStuff.ino.tmp b/jsonStuff.ino.tmp deleted file mode 100644 index f55ca317..00000000 --- a/jsonStuff.ino.tmp +++ /dev/null @@ -1,332 +0,0 @@ -/* -*************************************************************************** -** Program : jsonStuff -** Version : v0.10.2 -** -** Copyright (c) 2021-2023 Robert van den Breemen -** based on Framework ESP8266 from Willem Aandewiel -** -** TERMS OF USE: MIT License. See bottom of file. -*************************************************************************** -*/ -static int iIdentlevel = 0; -char sBeforenext[10] =""; -bool bFirst = true; - -//======================================================================= -void sendStartJsonObj(const char *objName) -{ - char sBuff[50] = ""; - sBeforenext[0]='\0'; - - if (strlen(objName)==0){ - snprintf(sBuff, sizeof(sBuff), "{\r\n"); - }else { - snprintf(sBuff, sizeof(sBuff), "{\"%s\":[\r\n", objName); - } - httpServer.sendHeader("Access-Control-Allow-Origin", "*"); - httpServer.setContentLength(CONTENT_LENGTH_UNKNOWN); - httpServer.send(200, "application/json", sBuff); - iIdentlevel++; - bFirst = true; - -} // sendStartJsonObj() - - -//======================================================================= -void sendEndJsonObj(const char *objName) -{ - iIdentlevel--; - if (strlen(objName)==0){ - httpServer.sendContent("\r\n}\r\n"); - } else { - httpServer.sendContent("\r\n]}\r\n"); - } - -} // sendEndJsonObj() -//======================================================================= -void sendStartJsonArray() -{ - httpServer.sendHeader("Access-Control-Allow-Origin", "*"); - httpServer.setContentLength(CONTENT_LENGTH_UNKNOWN); - httpServer.send(200, "application/json", "[\r\n"); - iIdentlevel++; - bFirst = true; - -} // sendStartJsonObj() - - -//======================================================================= -void sendEndJsonArray() -{ - iIdentlevel--; - httpServer.sendContent("\r\n]\r\n"); -} // sendEndJsonObj() -//======================================================================= -void sendIdent(){ - for (int i = iIdentlevel; i >0; i--){ - httpServer.sendContent(" "); - } -} //sendIdent() -//======================================================================= -void sendBeforenext(){ - if (!bFirst){ - httpServer.sendContent(",\r\n"); - } - bFirst = false; -} //sendBeforenext() -//======================================================================= -void sendNestedJsonObj(const char *cName, const char *cValue) -{ - char jsonBuff[JSON_BUFF_MAX] = ""; - - snprintf(jsonBuff, sizeof(jsonBuff), "{\"name\": \"%s\", \"value\": \"%s\"}", cName, cValue); - - sendBeforenext(); - sendIdent(); - httpServer.sendContent(jsonBuff); -} // sendNestedJsonObj(*char, *char) -//======================================================================= -void sendNestedJsonObj(const char *cName, String sValue) -{ - char jsonBuff[JSON_BUFF_MAX] = ""; - - if (sValue.length() > (JSON_BUFF_MAX - 65) ) - { - DebugTf(PSTR("[2] sValue.length() [%d]\r\n"), sValue.length()); - } - - snprintf(jsonBuff, sizeof(jsonBuff), "{\"name\": \"%s\", \"value\": \"%s\"}", cName, sValue.c_str()); - - sendBeforenext(); - sendIdent(); - httpServer.sendContent(jsonBuff); - -} // sendNestedJsonObj(*char, String) - - -//======================================================================= -void sendNestedJsonObj(const char *cName, int32_t iValue) -{ - char jsonBuff[200] = ""; - - snprintf(jsonBuff, sizeof(jsonBuff), "{\"name\": \"%s\", \"value\": %d}", cName, iValue); - - sendBeforenext(); - sendIdent(); - httpServer.sendContent(jsonBuff); - -} // sendNestedJsonObj(*char, int) - -//======================================================================= -void sendNestedJsonObj(const char *cName, uint32_t uValue) -{ - char jsonBuff[200] = ""; - - snprintf(jsonBuff, sizeof(jsonBuff), "{\"name\": \"%s\", \"value\": %u}", cName, uValue); - - sendBeforenext(); - sendIdent(); - httpServer.sendContent(jsonBuff); - -} // sendNestedJsonObj(*char, uint) - - -//======================================================================= -void sendNestedJsonObj(const char *cName, float fValue) -{ - char jsonBuff[200] = ""; - - snprintf(jsonBuff, sizeof(jsonBuff), "{\"name\": \"%s\", \"value\": %.3f}", cName, fValue); - - sendBeforenext(); - sendIdent(); - httpServer.sendContent(jsonBuff); - -} // sendNestedJsonObj(*char, float) - - -//============= build OTmonitor string ======================== -void sendJsonOTmonObj(const char *cName, const char *cValue, const char *cUnit, time_t epoch) -{ - char jsonBuff[JSON_BUFF_MAX] = ""; - - snprintf(jsonBuff, sizeof(jsonBuff), "{\"name\": \"%s\", \"value\": \"%s\", \"unit\": \"%s\", \"epoch\": %d}" - , cName, cValue, cUnit, (uint32_t)epoch); - - sendBeforenext(); - sendIdent(); - httpServer.sendContent(jsonBuff); - -} // sendJsonOTmonObj(*char, *char, *char) - -//======================================================================= -void sendJsonOTmonObj(const char *cName, int32_t iValue, const char *cUnit, time_t epoch) -{ - char jsonBuff[200] = ""; - - snprintf(jsonBuff, sizeof(jsonBuff), "{\"name\": \"%s\", \"value\": %d, \"unit\": \"%s\", \"epoch\": %d}" - , cName, iValue, cUnit, (uint32_t)epoch); - - sendBeforenext(); - sendIdent(); - httpServer.sendContent(jsonBuff); - -} // sendJsonOTmonObj(*char, int, *char) - -//======================================================================= -void sendJsonOTmonObj(const char *cName, uint32_t uValue, const char *cUnit, time_t epoch) -{ - char jsonBuff[200] = ""; - - snprintf(jsonBuff, sizeof(jsonBuff), "{\"name\": \"%s\", \"value\": %u, \"unit\": \"%s\", \"epoch\": %d}" - , cName, uValue, cUnit, (uint32_t)epoch); - - sendBeforenext(); - sendIdent(); - httpServer.sendContent(jsonBuff); - -} // sendNestedJsonObj(*char, uint, *char, time_t) - - -//======================================================================= -void sendJsonOTmonObj(const char *cName, float fValue, const char *cUnit, time_t epoch) -{ - char jsonBuff[200] = ""; - - snprintf(jsonBuff, sizeof(jsonBuff), "{\"name\": \"%s\", \"value\": %.3f, \"unit\": \"%s\", \"epoch\": %d}" - , cName, fValue, cUnit, (uint32_t)epoch); - - sendBeforenext(); - sendIdent(); - httpServer.sendContent(jsonBuff); - -} // sendJsonOTmonObj(*char, float, *char, time_t) -//======================================================================= -void sendJsonOTmonObj(const char *cName, bool bValue, const char *cUnit, time_t epoch) -{ - char jsonBuff[200] = ""; - - snprintf(jsonBuff, sizeof(jsonBuff), "{\"name\": \"%s\", \"value\": %s, \"unit\": \"%s\", \"epoch\": %d}" - , cName, CBOOLEAN(bValue), cUnit, (uint32_t)epoch); - - sendBeforenext(); - sendIdent(); - httpServer.sendContent(jsonBuff); - -} // sendJsonOTmonObj(*char, bool, *char, time_t) -//======================================================================= -// ************ function to build Json Settings string ****************** -//======================================================================= -void sendJsonSettingObj(const char *cName, float fValue, const char *fType, int minValue, int maxValue) -{ - char jsonBuff[200] = ""; - - snprintf(jsonBuff, sizeof(jsonBuff), "{\"name\": \"%s\", \"value\": %.3f, \"type\": \"%s\", \"min\": %d, \"max\": %d}" - , cName, fValue, fType, minValue, maxValue); - - sendBeforenext(); - sendIdent(); - httpServer.sendContent(jsonBuff); - -} // sendJsonSettingObj(*char, float, *char, int, int) - - -//======================================================================= -void sendJsonSettingObj(const char *cName, float fValue, const char *fType, int minValue, int maxValue, int decPlaces) -{ - char jsonBuff[200] = ""; - - switch(decPlaces) { - case 0: - snprintf(jsonBuff, sizeof(jsonBuff), "{\"name\": \"%s\", \"value\": %.0f, \"type\": \"%s\", \"min\": %d, \"max\": %d}" - , cName, fValue, fType, minValue, maxValue); - break; - case 2: - snprintf(jsonBuff, sizeof(jsonBuff), "{\"name\": \"%s\", \"value\": %.2f, \"type\": \"%s\", \"min\": %d, \"max\": %d}" - , cName, fValue, fType, minValue, maxValue); - break; - case 5: - snprintf(jsonBuff, sizeof(jsonBuff), "{\"name\": \"%s\", \"value\": %.5f, \"type\": \"%s\", \"min\": %d, \"max\": %d}" - , cName, fValue, fType, minValue, maxValue); - break; - default: - snprintf(jsonBuff, sizeof(jsonBuff), "{\"name\": \"%s\", \"value\": %f, \"type\": \"%s\", \"min\": %d, \"max\": %d}" - , cName, fValue, fType, minValue, maxValue); - - } - - sendBeforenext(); - sendIdent(); - httpServer.sendContent(jsonBuff); - -} // sendJsonSettingObj(*char, float, *char, int, int, int) - - -//======================================================================= -void sendJsonSettingObj(const char *cName, int iValue, const char *iType, int minValue, int maxValue) -{ - char jsonBuff[200] = ""; - - snprintf(jsonBuff, sizeof(jsonBuff), "{\"name\": \"%s\", \"value\": %d, \"type\": \"%s\", \"min\": %d, \"max\": %d}" - , cName, iValue, iType, minValue, maxValue); - - sendBeforenext(); - sendIdent(); - httpServer.sendContent(jsonBuff); -} // sendJsonSettingObj(*char, int, *char, int, int) - - -//======================================================================= - -void sendJsonSettingObj(const char *cName, const char *cValue, const char *sType, int maxLen) -{ - char jsonBuff[200] = {0}; - char buffer[100] = {0}; - - str_cstrlit(cValue, buffer, sizeof(buffer)); - snprintf(jsonBuff, sizeof(jsonBuff), "{\"name\": \"%s\", \"value\":\"%s\", \"type\": \"%s\", \"maxlen\": %d}" - , cName, cValue, sType, maxLen); - - sendBeforenext(); - sendIdent(); - httpServer.sendContent(jsonBuff); - -} // sendJsonSettingObj(*char, *char, *char, int, int) - -//======================================================================= -void sendJsonSettingObj(const char *cName, bool bValue, const char *sType) -{ - char jsonBuff[200] = ""; - - snprintf(jsonBuff, sizeof(jsonBuff), "{\"name\": \"%s\", \"value\":\"%s\", \"type\": \"%s\"}" - , cName, CBOOLEAN(bValue), sType); - - sendBeforenext(); - sendIdent(); - httpServer.sendContent(jsonBuff); - -} // sendJsonSettingObj(*char, bool, *char) -/*************************************************************************** -* -* Permission is hereby granted, free of charge, to any person obtaining a -* copy of this software and associated documentation files (the -* "Software"), to deal in the Software without restriction, including -* without limitation the rights to use, copy, modify, merge, publish, -* distribute, sublicense, and/or sell copies of the Software, and to permit -* persons to whom the Software is furnished to do so, subject to the -* following conditions: -* -* The above copyright notice and this permission notice shall be included -* in all copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT -* OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR -* THE USE OR OTHER DEALINGS IN THE SOFTWARE. -* -**************************************************************************** -*/ From 3e0aeac40e6b6c48c3fbf8602ee5fa0b7fefe7c2 Mon Sep 17 00:00:00 2001 From: Robert van den Breemen Date: Mon, 15 Apr 2024 23:59:20 +0200 Subject: [PATCH 09/13] before update 0.10.3 --- version.h | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/version.h b/version.h index bf14a5fa..6d943c1f 100644 --- a/version.h +++ b/version.h @@ -2,15 +2,15 @@ #define _VERSION_MAJOR 0 #define _VERSION_MINOR 10 #define _VERSION_PATCH 3 -#define _VERSION_BUILD 2117 -#define _VERSION_GITHASH "019a3ca" +#define _VERSION_BUILD 2118 +#define _VERSION_GITHASH "1ab7961" //#define _VERSION_PRERELEASE beta //uncomment to define prerelease labels: alpha - beta - rc #define _VERSION_DATE "15-04-2024" -#define _VERSION_TIME "23:21:15" +#define _VERSION_TIME "23:58:59" #define _SEMVER_CORE "0.10.3" -#define _SEMVER_BUILD "0.10.3+2117" -#define _SEMVER_GITHASH "0.10.3+019a3ca" -#define _SEMVER_FULL "0.10.3+019a3ca" +#define _SEMVER_BUILD "0.10.3+2118" +#define _SEMVER_GITHASH "0.10.3+1ab7961" +#define _SEMVER_FULL "0.10.3+1ab7961" #define _SEMVER_NOBUILD "0.10.3 (15-04-2024)" -#define _VERSION "0.10.3+019a3ca (15-04-2024)" +#define _VERSION "0.10.3+1ab7961 (15-04-2024)" //The version information is created automatically, more information here: https://github.com/rvdbreemen/autoinc-semver From a5ccd222efe8d0f3ee1099d5eb604f104ae028ad Mon Sep 17 00:00:00 2001 From: Robert van den Breemen Date: Tue, 16 Apr 2024 00:44:03 +0200 Subject: [PATCH 10/13] before update 0.10.3 --- safeTimers.h.tmp | 274 +++++++++++++++++++++++++++++++++++++++++++++++ version.h | 28 +++-- 2 files changed, 295 insertions(+), 7 deletions(-) create mode 100644 safeTimers.h.tmp diff --git a/safeTimers.h.tmp b/safeTimers.h.tmp new file mode 100644 index 00000000..85be3d2f --- /dev/null +++ b/safeTimers.h.tmp @@ -0,0 +1,274 @@ +/* +*************************************************************************** +** Filename : safeTimers.h +** Version : 0.3.0 +** +** Copyright (c) 2020 Willem Aandewiel +** +** TERMS OF USE: MIT License. See bottom of file. +*************************************************************************** +*/ +#ifndef SAFETIMERS_H +#define SAFETIMERS_H + +/* + * safeTimers.h (original name timers.h) is developed by Erik + * + * Willem Aandewiel and Robert van den Breemen made some changes due + * to the "how can I handle the millis() rollover" by Edgar Bonet and added + * CHANGE_INTERVAL() and RESTART_TIMER() macro's + * + * see: https://arduino.stackexchange.com/questions/12587/how-can-i-handle-the-millis-rollover + * + * DECLARE_TIMER_MIN(timername, interval, ) // interval in minutes + * DECLARE_TIMER_SEC(timername, interval, ) // interval in seconds + * DECLARE_TIMER_MS(timername, interval, ) // interval in milliseconds + * DECLARE_TIMER(timername, interval, ) // interval in milliseconds + * Declares three static vars: + * _due (uint32_t) for next execution + * _interval (uint32_t) for interval in seconds + * _type (byte) + * + * can either be: + * SKIP_MISSED_TICKS + * CATCH_UP_MISSED_TICKS + * SKIP_MISSED_TICKS_WITH_SYNC + * TIMER_TYPE_4 + * + * TIME_LEFT_MIN(timerName) + * returns the time left in minutes + * TIME_LEFT_SEC(timerName) + * returns the time left in seconds + * TIME_LEFT_MS(timerName) + * returns the time left in milliseconds + * TIME_LEFT(timerName) + * returns the time left in milliseconds + * + * CHANGE_INTERVAL_MIN(timername, interval, ) + * CHANGE_INTERVAL_SEC(timername, interval, ) + * CHANGE_INTERVAL_MS(timername, interval, ) + * CHANGE_INTERVAL(timername, interval, ) + * Changes the static vars declared by DECLARE_TIMER(): + * _due (uint32_t) for next execution + * _interval (uint32_t) for interval + * _type (byte) + * + * RESTART_TIMER(timername) + * updates _due = millis() + _interval + * + * DUE(timername) + * returns false (0) if interval hasn't elapsed since last DUE-time + * true (current millis) if it has + * updates _due + * + * Usage example: + * + * DECLARE_TIMER(screenUpdate, 200, SKIP_MISSED_TICKS) // update screen every 200 ms + * ... + * loop() + * { + * .. + * if ( DUE(screenUpdate) ) { + * // update screen code + * } + * + * // to change the screenUpdate interval: + * CHANGE_INTERVAL(screenUpdate, 500, CATCH_UP_MISSED_TICKS); // change interval to 500 ms + * + * // to restart the screenUpdate interval: + * RESTART_TIMER(screenUpdate); // restart timer so next DUE is in 500ms + * } + * +*/ + +//--- timerType's ----------------------- +#define SKIP_MISSED_TICKS 0 +#define CATCH_UP_MISSED_TICKS 1 +#define SKIP_MISSED_TICKS_WITH_SYNC 2 +#define TIMER_TYPE_4 3 + + +#define DECLARE_TIMER_MIN(timerName, ...) \ + static uint32_t timerName##_interval = (getParam(0, __VA_ARGS__, 0) * 60 * 1000),\ + timerName##_due = millis() \ + +timerName##_interval \ + +random(timerName##_interval / 3); \ + static byte timerName##_type = getParam(1, __VA_ARGS__, 0); + +#define DECLARE_TIMER_SEC(timerName, ...) \ + static uint32_t timerName##_interval = (getParam(0, __VA_ARGS__, 0) * 1000),\ + timerName##_due = millis() \ + +timerName##_interval \ + +random(timerName##_interval / 3); \ + static byte timerName##_type = getParam(1, __VA_ARGS__, 0); + +#define DECLARE_TIMER_MS(timerName, ...) \ + static uint32_t timerName##_interval = (getParam(0, __VA_ARGS__, 0)), \ + timerName##_due = millis() \ + +timerName##_interval \ + +random(timerName##_interval / 3); \ + static byte timerName##_type = getParam(1, __VA_ARGS__, 0); + +#define DECLARE_TIMER DECLARE_TIMER_MS + + +#define CHANGE_INTERVAL_MIN(timerName, ...) \ + timerName##_interval = (getParam(0, __VA_ARGS__, 0) *60*1000),\ + timerName##_due = millis() \ + +timerName##_interval \ + +random(timerName##_interval / 3); \ + timerName##_type = getParam(1, __VA_ARGS__, 0); +#define CHANGE_INTERVAL_SEC(timerName, ...) \ + timerName##_interval = (getParam(0, __VA_ARGS__, 0) *1000), \ + timerName##_due = millis() \ + +timerName##_interval \ + +random(timerName##_interval / 3); \ + timerName##_type = getParam(1, __VA_ARGS__, 0); +#define CHANGE_INTERVAL_MS(timerName, ...) \ + timerName##_interval = (getParam(0, __VA_ARGS__, 0) ), \ + timerName##_due = millis() \ + +timerName##_interval \ + +random(timerName##_interval / 3); \ + timerName##_type = getParam(1, __VA_ARGS__, 0); + +#define CHANGE_INTERVAL CHANGE_INTERVAL_MS + +#define TIME_LEFT(timerName) ( __TimeLeft__(timerName##_due) ) +#define TIME_LEFT_MS(timerName) ( (TIME_LEFT(timerName) ) ) +#define TIME_LEFT_MIN(timerName) ( (TIME_LEFT(timerName) ) / (60 * 1000)) +#define TIME_LEFT_SEC(timerName) ( (TIME_LEFT(timerName) ) / 1000 ) + +#define ONCE(timerName) ( __Once__(timerName##_due) ) +#define ONCE_MS(timerName) ( (ONCE(timerName) ) ) +#define ONCE_MIN(timerName) ( (ONCE(timerName) ) / (60 * 1000)) +#define ONCE_SEC(timerName) ( (ONCE(timerName) ) / 1000 ) + +#define TIME_PAST(timerName) ( (timerName##_interval - TIME_LEFT(timerName)) ) +#define TIME_PAST_MS(timerName) ( (TIME_PAST(timerName) ) ) +#define TIME_PAST_SEC(timerName) ( (TIME_PAST(timerName) / 1000) ) +#define TIME_PAST_MIN(timerName) ( (TIME_PAST(timerName) / (60*1000)) ) + +#define RESTART_TIMER(timerName) ( timerName##_due = millis()+timerName##_interval ); + +#define DUE(timerName) ( __Due__(timerName##_due, timerName##_interval, timerName##_type) ) + +uint32_t __Due__(uint32_t &timer_due, uint32_t timer_interval, byte timerType) +{ + if ((int32_t)(millis() - timer_due) >= 0) + { + switch (timerType) { + case CATCH_UP_MISSED_TICKS: + timer_due += timer_interval; + break; + case SKIP_MISSED_TICKS_WITH_SYNC: + // this will calculate the next due, and skips passed due events + // (missing due events) + // timer_due += (((uint32_t)(( timer_due - millis()) / timer_interval)+1) *timer_interval); + while ((int32_t)(millis() - timer_due) >= 0) + { + timer_due += timer_interval; + } + break; + case TIMER_TYPE_4: + if ((millis() - timer_due) >= (uint32_t)(timer_interval * 0.05)) + { + timer_due += timer_interval; + return 0; + } + while ((int32_t)(millis() - timer_due) >= 0) + { + timer_due += timer_interval; + } + break; + // SKIP_MISSED_TICKS is default + default: timer_due = millis() + timer_interval; + break; + } + return timer_due; + } + + return 0; + +} // __Due__() + +uint32_t __TimeLeft__(uint32_t timer_due) +{ + uint32_t tmp; + byte state = 0; + + // timeline 0-------------------------SIGNED-MAX-------------------------UMAX + // state=0 0---------------------------T-|---D--------------------------UMAX + // state=0 0---------------------------d-|---t--------------------------UMAX + // state=0 0-----------------------------|---------------T-------D------UMAX + // state=0 0-----------------------------|---------------d--t-----------UMAX + // state=0 0-------T-D-------------------|------------------------------UMAX + // state=0 0---------d--t----------------|------------------------------UMAX + + // state=1 0---T-------------------------|--------------------------D---UMAX + if ( (timer_due >= INT32_MAX) && (millis() < INT32_MAX) ) state = 1; // millis() rolled-over + + // state=2 0--------D--------------------|---------------------T--------UMAX + if ( (timer_due <= INT32_MAX) && (millis() > INT32_MAX) ) state = 2; // _due rolled-over + + switch(state) { + case 1: //--- millis() rolled-over + case 2: //--- _due rolled-over + if ( (int32_t)((timer_due + UINT32_MAX) - millis()) >= 0 ) + tmp = (timer_due + UINT32_MAX) - millis(); + else tmp = 0; + break; + default: if ( (int32_t)(timer_due - millis()) >= 0 ) + tmp = timer_due - millis(); + else tmp = 0; + } + + return tmp; + +} // __TimeLeft__() + +uint32_t __Once__(uint32_t timer_due) +{ + //false if timer is not due + if (__TimeLeft__(timer_due) > 0) return 0; + else return 1; +} // __Once__() + +// process variadic from macro's +uint32_t getParam(uint32_t i, ...) +{ + uint32_t parm = 0, p; + va_list vl; + va_start(vl,i); + for (p=0; p<=i; p++) + { + parm=va_arg(vl,uint32_t); + } + va_end(vl); + return parm; +} // getParam() + +#endif + +/*************************************************************************** +* +* Permission is hereby granted, free of charge, to any person obtaining a +* copy of this software and associated documentation files (the +* "Software"), to deal in the Software without restriction, including +* without limitation the rights to use, copy, modify, merge, publish, +* distribute, sublicense, and/or sell copies of the Software, and to permit +* persons to whom the Software is furnished to do so, subject to the +* following conditions: +* +* The above copyright notice and this permission notice shall be included +* in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT +* OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR +* THE USE OR OTHER DEALINGS IN THE SOFTWARE. +* +**************************************************************************** +*/ diff --git a/version.h b/version.h index 6d943c1f..6e2daa8b 100644 --- a/version.h +++ b/version.h @@ -2,15 +2,29 @@ #define _VERSION_MAJOR 0 #define _VERSION_MINOR 10 #define _VERSION_PATCH 3 -#define _VERSION_BUILD 2118 -#define _VERSION_GITHASH "1ab7961" +<<<<<<< HEAD +#define _VERSION_BUILD 2114 +#define _VERSION_GITHASH "b6bf90e" +//#define _VERSION_PRERELEASE beta //uncomment to define prerelease labels: alpha - beta - rc +#define _VERSION_DATE "14-04-2024" +#define _VERSION_TIME "23:30:44" +#define _SEMVER_CORE "0.10.3" +#define _SEMVER_BUILD "0.10.3+2114" +#define _SEMVER_GITHASH "0.10.3+b6bf90e" +#define _SEMVER_FULL "0.10.3+b6bf90e" +#define _SEMVER_NOBUILD "0.10.3 (14-04-2024)" +#define _VERSION "0.10.3+b6bf90e (14-04-2024)" +======= +#define _VERSION_BUILD 2117 +#define _VERSION_GITHASH "019a3ca" //#define _VERSION_PRERELEASE beta //uncomment to define prerelease labels: alpha - beta - rc #define _VERSION_DATE "15-04-2024" -#define _VERSION_TIME "23:58:59" +#define _VERSION_TIME "23:21:15" #define _SEMVER_CORE "0.10.3" -#define _SEMVER_BUILD "0.10.3+2118" -#define _SEMVER_GITHASH "0.10.3+1ab7961" -#define _SEMVER_FULL "0.10.3+1ab7961" +#define _SEMVER_BUILD "0.10.3+2117" +#define _SEMVER_GITHASH "0.10.3+019a3ca" +#define _SEMVER_FULL "0.10.3+019a3ca" #define _SEMVER_NOBUILD "0.10.3 (15-04-2024)" -#define _VERSION "0.10.3+1ab7961 (15-04-2024)" +#define _VERSION "0.10.3+019a3ca (15-04-2024)" +>>>>>>> parent of 3e0aeac (before update 0.10.3) //The version information is created automatically, more information here: https://github.com/rvdbreemen/autoinc-semver From 0b96b2b46fe2fc961771ab12ba9e724a8a5e1af4 Mon Sep 17 00:00:00 2001 From: Robert van den Breemen Date: Tue, 16 Apr 2024 00:45:13 +0200 Subject: [PATCH 11/13] before update 0.10.3 --- OTGW-Core.h.tmp | 567 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 567 insertions(+) create mode 100644 OTGW-Core.h.tmp diff --git a/OTGW-Core.h.tmp b/OTGW-Core.h.tmp new file mode 100644 index 00000000..e9485cc5 --- /dev/null +++ b/OTGW-Core.h.tmp @@ -0,0 +1,567 @@ +/* +*************************************************************************** +** Program : Header file: OTGW-Core.h +** Version : v0.10.2 +** +** Copyright (c) 2021-2023 Robert van den Breemen +** Borrowed from OpenTherm library from: +** https://github.com/jpraus/arduino-opentherm +** +** TERMS OF USE: MIT License. See bottom of file. +*************************************************************************** +*/ + +#ifndef OTGWCore_h +#define OTGWCore_h + +// OTGW Serial 2 network port +// #include // https://github.com/jandrassy/TelnetStream/commit/1294a9ee5cc9b1f7e51005091e351d60c8cddecf +#define OTGW_SERIAL_PORT 25238 // changed the port to original default of OTmonitor +TelnetStreamClass OTGWstream(OTGW_SERIAL_PORT); + +//Depends on the library +#define OTGW_COMMAND_TOPIC "command" + +typedef struct { + uint16_t Statusflags = 0; // flag8 / flag8 Master and Slave Status flags. + uint8_t MasterStatus = 0; + uint8_t SlaveStatus = 0; + float TSet = 0.0f; // f8.8 Control setpoint ie CH water temperature setpoint (°C) + uint16_t MasterConfigMemberIDcode = 0; // flag8 / u8 Master Configuration Flags / Master MemberID Code + uint16_t SlaveConfigMemberIDcode = 0; // flag8 / u8 Slave Configuration Flags / Slave MemberID Code + uint16_t Command = 0; // u8 / u8 Remote Command + uint16_t ASFflags = 0; // / OEM-fault-code flag8 / u8 Application-specific fault flags and OEM fault code + uint16_t RBPflags = 0; // flag8 / flag8 Remote boiler parameter transfer-enable & read/write flags + float CoolingControl = 0.0f; // f8.8 Cooling control signal (%) + float TsetCH2 = 0.0f; // f8.8 Control setpoint for 2e CH circuit (°C) + float TrOverride = 0.0f; // f8.8 Remote override room setpoint + uint16_t TSP = 0; // u8 / u8 Number of Transparent-Slave-Parameters supported by slave + uint16_t TSPindexTSPvalue = 0; // u8 / u8 Index number / Value of referred-to transparent slave parameter. + uint16_t FHBsize = 0; // u8 / u8 Size of Fault-History-Buffer supported by slave + uint16_t FHBindexFHBvalue = 0; // u8 / u8 Index number / Value of referred-to fault-history buffer entry. + float MaxRelModLevelSetting = 0.0f; // f8.8 Maximum relative modulation level setting (%) + uint16_t MaxCapacityMinModLevel = 0; // u8 / u8 Maximum boiler capacity (kW) / Minimum boiler modulation level(%) + float TrSet = 0.0f; // f8.8 Room Setpoint (°C) + float RelModLevel = 0.0f; // f8.8 Relative Modulation Level (%) + float CHPressure = 0.0f; // f8.8 Water pressure in CH circuit (bar) + float DHWFlowRate = 0.0f; // f8.8 Water flow rate in DHW circuit. (litres/minute) + uint16_t DayTime = 0; // special / u8 Day of Week and Time of Day + uint16_t Date = 0; // u8 / u8 Calendar date + uint16_t Year = 0; // u16 Calendar year + float TrSetCH2 = 0.0f; // f8.8 Room Setpoint for 2nd CH circuit (°C) + float Tr = 0.0f; // f8.8 Room temperature (°C) + float Tboiler = 0.0f; // f8.8 Boiler flow water temperature (°C) + float Tdhw = 0.0f; // f8.8 DHW temperature (°C) + float Toutside = 0.0f; // f8.8 Outside temperature (°C) + float Tret = 0.0f; // f8.8 Return water temperature (°C) + float Tsolarstorage = 0.0f; // f8.8 Solar storage temperature (°C) + int16_t Tsolarcollector = 0.0f; // s16 Solar collector temperature (°C) + float TflowCH2 = 0.0f; // f8.8 Flow water temperature CH2 circuit (°C) + float Tdhw2 = 0.0f; // f8.8 Domestic hot water temperature 2 (°C) + int16_t Texhaust = 0; // s16 Boiler exhaust temperature (°C) + float Theatexchanger = 0.0f; // f8.8 Heat Exchanger (°C) + uint16_t FanSpeed = 0; // u16 Fan Speed (rpm) + float ElectricalCurrentBurnerFlame = 0.0f; // f88 Electrical current through burner flame (µA) + float TRoomCH2= 0.0f; // f88 Room Temperature for 2nd CH circuit ("°C) + uint16_t RelativeHumidity = 0; // u8 / u8 Relative Humidity (%) + uint16_t TdhwSetUBTdhwSetLB = 0 ; // s8 / s8 DHW setpoint upper & lower bounds for adjustment (°C) + uint16_t MaxTSetUBMaxTSetLB = 0; // s8 / s8 Max CH water setpoint upper & lower bounds for adjustment (°C) + uint16_t HcratioUBHcratioLB = 0; // s8 / s8 OTC heat curve ratio upper & lower bounds for adjustment + uint16_t Remoteparameter4boundaries = 0; // s8 / s8 Remote parameter 4 upper & lower bounds for adjustment + uint16_t Remoteparameter5boundaries = 0; // s8 / s8 Remote parameter 5 upper & lower bounds for adjustment + uint16_t Remoteparameter6boundaries = 0; // s8 / s8 Remote parameter 6 upper & lower bounds for adjustment + uint16_t Remoteparameter7boundaries = 0; // s8 / s8 Remote parameter 7 upper & lower bounds for adjustment + uint16_t Remoteparameter8boundaries = 0; // s8 / s8 Remote parameter 8 upper & lower bounds for adjustment + float TdhwSet = 0.0f; // f8.8 DHW setpoint (°C) (Remote parameter 1) + float MaxTSet = 0.0f; // f8.8 Max CH water setpoint (°C) (Remote parameters 2) + float Hcratio = 0.0f; // f8.8 OTC heat curve ratio (°C) (Remote parameter 3) + float Remoteparameter4 = 0.0f; // f8.8 Remote parameter 4 + float Remoteparameter5 = 0.0f; // f8.8 Remote parameter 5 + float Remoteparameter6 = 0.0f; // f8.8 Remote parameter 6 + float Remoteparameter7 = 0.0f; // f8.8 Remote parameter 7 + float Remoteparameter8 = 0.0f; // f8.8 Remote parameter 8 + + //RF + uint16_t RFstrengthbatterylevel = 0; // u8/ u8 RF strength and battery level + uint16_t OperatingMode_HC1_HC2_DHW = 0; // u8 / u8 Operating Mode HC1, HC2/ DHW + uint16_t RoomRemoteOverrideFunction = 0; // Function of manual and program changes in master and remote room setpoint + + //Electric Producer + uint16_t ElectricityProducerStarts = 0; // u16 Electricity producer starts + uint16_t ElectricityProducerHours = 0; // u16 Electricity producer hours + uint16_t ElectricityProduction = 0; // u16 Electricity production + uint16_t CumulativElectricityProduction = 0; // u16 Cumulativ Electricity production + + //Solar Storage + uint16_t SolarStorageStatus = 0; + uint8_t SolarMasterStatus = 0; + uint8_t SolarSlaveStatus = 0; + uint16_t SolarStorageASFflags = 0; + uint16_t SolarStorageSlaveConfigMemberIDcode = 0; + uint16_t SolarStorageVersionType = 0; + uint16_t SolarStorageTSP = 0; + uint16_t SolarStorageTSPindexTSPvalue = 0; + uint16_t SolarStorageFHBsize = 0; + uint16_t SolarStorageFHBindexFHBvalue = 0; + + //Ventilation/HeatRecovery Msgids + uint16_t StatusVH = 0; + uint8_t MasterStatusVH = 0; + uint8_t SlaveStatusVH = 0; + uint16_t ControlSetpointVH = 0; //should be uint8_t + uint16_t ASFFaultCodeVH = 0; + uint16_t DiagnosticCodeVH = 0; + uint16_t ConfigMemberIDVH = 0; + float OpenthermVersionVH = 0.0f; + uint16_t VersionTypeVH = 0; + uint16_t RelativeVentilation = 0; + uint16_t RelativeHumidityExhaustAir = 0; + uint16_t CO2LevelExhaustAir = 0; + float SupplyInletTemperature = 0.0f; + float SupplyOutletTemperature = 0.0f; + float ExhaustInletTemperature = 0.0f; + float ExhaustOutletTemperature = 0.0f; + uint16_t ActualExhaustFanSpeed = 0; + uint16_t ActualSupplyFanSpeed = 0; + uint16_t RemoteParameterSettingVH = 0; + uint16_t NominalVentilationValue = 0; + uint16_t TSPNumberVH = 0; + uint16_t TSPEntryVH = 0; + uint16_t FaultBufferSizeVH = 0; + uint16_t FaultBufferEntryVH = 0; + + //Statitics + uint16_t BurnerUnsuccessfulStarts = 0; + uint16_t FlameSignalTooLow = 0; + uint16_t RemoteOverrideFunction = 0; // flag8 / - Function of manual and program changes in master and remote room setpoint. + uint16_t OEMDiagnosticCode = 0; // u16 OEM-specific diagnostic/service code + uint16_t BurnerStarts = 0; // u16 Number of starts burner + uint16_t CHPumpStarts = 0; // u16 Number of starts CH pump + uint16_t DHWPumpValveStarts = 0; // u16 Number of starts DHW pump/valve + uint16_t DHWBurnerStarts = 0; // u16 Number of starts burner during DHW mode + uint16_t BurnerOperationHours = 0; // u16 Number of hours that burner is in operation (i.e. flame on) + uint16_t CHPumpOperationHours = 0; // u16 Number of hours that CH pump has been running + uint16_t DHWPumpValveOperationHours = 0; // u16 Number of hours that DHW pump has been running or DHW valve has been opened + uint16_t DHWBurnerOperationHours = 0; // u16 Number of hours that burner is in operation during DHW mode + float OpenThermVersionMaster = 0.0f; // f8.8 The implemented version of the OpenTherm Protocol Specification in the master. + float OpenThermVersionSlave = 0.0f; // f8.8 The implemented version of the OpenTherm Protocol Specification in the slave. + uint16_t MasterVersion = 0; // u8 / u8 Master product version number and type + uint16_t SlaveVersion = 0; // u8 / u8 Slave product version number and type + + //Rehmea + uint16_t RemehadFdUcodes = 0; // u16 Remeha dF-/dU-codes + uint16_t RemehaServicemessage = 0; // u16 Remeha Servicemessage + uint16_t RemehaDetectionConnectedSCU =0; // u16 Remeha detection connected SCU’s + + //errors + uint16_t error01 = 0; + uint16_t error02 = 0; + uint16_t error03 = 0; + uint16_t error04 = 0; + +} OTdataStruct; + +static OTdataStruct OTcurrentSystemState; + + +enum OpenThermResponseStatus { + OT_NONE, + OT_SUCCESS, + OT_INVALID, + OT_TIMEOUT +}; + +enum OpenThermMessageType { + /* Master to Slave */ + OT_READ_DATA = B000, + OT_WRITE_DATA = B001, + OT_INVALID_DATA = B010, + OT_RESERVED = B011, + /* Slave to Master */ + OT_READ_ACK = B100, + OT_WRITE_ACK = B101, + OT_DATA_INVALID = B110, + OT_UNKNOWN_DATA_ID = B111 +}; + +enum OpenThermMessageID { + OT_Statusflags, // flag8 / flag8 Master and Slave Status flags. + OT_TSet, // f8.8 Control setpoint ie CH water temperature setpoint (°C) + OT_MasterConfigMemberIDcode, // flag8 / u8 Master Configuration Flags / Master MemberID Code + OT_SlaveConfigMemberIDcode, // flag8 / u8 Slave Configuration Flags / Slave MemberID Code + OT_Command, // u8 / u8 Remote Command + OT_ASFflags, // / OEM-fault-code flag8 / u8 Application-specific fault flags and OEM fault code + OT_RBPflags, // flag8 / flag8 Remote boiler parameter transfer-enable & read/write flags + OT_CoolingControl, // f8.8 Cooling control signal (%) + OT_TsetCH2, // f8.8 Control setpoint for 2e CH circuit (°C) + OT_TrOverride, // f8.8 Remote override room setpoint + OT_TSP, // u8 / u8 Number of Transparent-Slave-Parameters supported by slave + OT_TSPindexTSPvalue, // u8 / u8 Index number / Value of referred-to transparent slave parameter. + OT_FHBsize, // u8 / u8 Size of Fault-History-Buffer supported by slave + OT_FHBindexFHBvalue, // u8 / u8 Index number / Value of referred-to fault-history buffer entry. + OT_MaxRelModLevelSetting, // f8.8 Maximum relative modulation level setting (%) + OT_MaxCapacityMinModLevel, // u8 / u8 Maximum boiler capacity (kW) / Minimum boiler modulation level(%) + OT_TrSet, // f8.8 Room Setpoint (°C) + OT_RelModLevel, // f8.8 Relative Modulation Level (%) + OT_CHPressure, // f8.8 Water pressure in CH circuit (bar) + OT_DHWFlowRate, // f8.8 Water flow rate in DHW circuit. (litres/minute) + OT_DayTime, // special / u8 Day of Week and Time of Day + OT_Date, // u8 / u8 Calendar date + OT_Year, // u16 Calendar year + OT_TrSetCH2, // f8.8 Room Setpoint for 2nd CH circuit (°C) + OT_Tr, // f8.8 Room temperature (°C) + OT_Tboiler, // f8.8 Boiler flow water temperature (°C) + OT_Tdhw, // f8.8 DHW temperature (°C) + OT_Toutside, // f8.8 Outside temperature (°C) + OT_Tret, // f8.8 Return water temperature (°C) + OT_Tsolarstorage, // f8.8 Solar storage temperature (°C) + OT_Tsolarcollector, // s16 Solar collector temperature (°C) + OT_TflowCH2, // f8.8 Flow water temperature CH2 circuit (°C) + OT_Tdhw2, // f8.8 Domestic hot water temperature 2 (°C) + OT_Texhaust, // s16 Boiler exhaust temperature (°C) + OT_Theatexchanger, // f8.8 Heat exchanger temperature (°C) + OT_FanSpeed = 35, // u16 Fan Speed (rpm) + OT_ElectricalCurrentBurnerFlame, // f88 Electrical current through burner flame (µA) + OT_TRoomCH2, // f88 Room Temperature for 2nd CH circuit ("°C) + OT_RelativeHumidity, // u8 / u8 Relative Humidity (%) + OT_TdhwSetUBTdhwSetLB = 48, // s8 / s8 DHW setpoint upper & lower bounds for adjustment (°C) + OT_MaxTSetUBMaxTSetLB, // s8 / s8 Max CH water setpoint upper & lower bounds for adjustment (°C) + OT_HcratioUBHcratioLB, // s8 / s8 OTC heat curve ratio upper & lower bounds for adjustment + OT_Remoteparameter4boundaries, // s8 / s8 Remote Parameter ratio upper & lower bounds for adjustment + OT_Remoteparameter5boundaries, // s8 / s8 Remote Parameter upper & lower bounds for adjustment + OT_Remoteparameter6boundaries, // s8 / s8 Remote Parameter upper & lower bounds for adjustment + OT_Remoteparameter7boundaries, // s8 / s8 Remote Parameter upper & lower bounds for adjustment + OT_Remoteparameter8boundaries, // s8 / s8 Remote Parameter upper & lower bounds for adjustment + OT_TdhwSet = 56, // f8.8 DHW setpoint (°C) (Remote parameter 1) + OT_MaxTSet, // f8.8 Max CH water setpoint (°C) (Remote parameters 2) + OT_Hcratio, // f8.8 OTC heat curve ratio (°C) (Remote parameter 3) + OT_Remoteparameter4, // f8.8 Remote parameter 4 (°C) (Remote parameter 4) + OT_Remoteparameter5, // f8.8 Remote parameter 5 (°C) (Remote parameter 5) + OT_Remoteparameter6, // f8.8 Remote parameter 6 (°C) (Remote parameter 6) + OT_Remoteparameter7, // f8.8 Remote parameter 7 (°C) (Remote parameter 7) + OT_Remoteparameter8, // f8.8 Remote parameter 8 (°C) (Remote parameter 8) + OT_StatusVH = 70, // flag8 / flag8 Status Ventilation/Heat recovery + OT_ControlSetpointVH, // u8 Control setpoint V/H + OT_ASFFaultCodeVH, // flag8 / u8 Aplication Specific Fault Flags/Code V/H + OT_DiagnosticCodeVH, // u16 Diagnostic Code V/H + OT_ConfigMemberIDVH, // flag8 / u8 Config/Member ID V/H + OT_OpenthermVersionVH, // f8.8 OpenTherm Version V/H + OT_VersionTypeVH, // u8 / u8 Version & Type V/H + OT_RelativeVentilation, // u8 Relative Ventilation (%) + OT_RelativeHumidityExhaustAir, // u8 / u8 Relative Humidity (%) + OT_CO2LevelExhaustAir, // u16 CO2 Level (ppm) + OT_SupplyInletTemperature, // f8.8 Supply Inlet Temperature (°C) + OT_SupplyOutletTemperature, // f8.8 Supply Outlet Temperature(°C) + OT_ExhaustInletTemperature, // f8.8 Exhaust Inlet Temperature (°C) + OT_ExhaustOutletTemperature, // f8.8 Exhaust Outlet Temperature (°C) + OT_ActualExhaustFanSpeed, // u16 Actual Exhaust Fan Speed (rpm) + OT_ActualSupplyFanSpeed, // u16 Actual Supply Fan Speed (rpm) + OT_RemoteParameterSettingVH, // flag8 / flag8 Remote Parameter Setting V/H + OT_NominalVentilationValue, // u8 Nominal Ventilation Value + OT_TSPNumberVH, // u8 / u8 TSP Number V/H + OT_TSPEntryVH, // u8 / u8 TSP Entry V/H + OT_FaultBufferSizeVH, // u8 / u8 Fault Buffer Size V/H + OT_FaultBufferEntryVH, // u8 / u8 Fault Buffer Entry V/H + OT_RFstrengthbatterylevel=98, // u8 / u8 RF strength and battery level + OT_OperatingMode_HC1_HC2_DHW, // u8 / u8 Operating Mode HC1, HC2/ DHW + OT_RemoteOverrideFunction, // flag8 / - Function of manual and program changes in master and remote room setpoint. + OT_SolarStorageMaster, // flag8 / flag8 Solar Storage Master flags. + OT_SolarStorageASFflags, // flag8 / u8 / Solar Storage OEM-fault-code flag8 / u8 Application-specific fault flags and OEM fault code + OT_SolarStorageSlaveConfigMemberIDcode, // flag8 / u8 Solar Storage Master Configuration Flags / Master MemberID Code + OT_SolarStorageVersionType, // u8 / u8 / Solar Storage product version number and type + OT_SolarStorageTSP, // u8 / u8 / Solar Storage Number of Transparent-Slave-Parameters supported + OT_SolarStorageTSPindexTSPvalue, // u8 / u8 / Solar Storage Index number / Value of referred-to transparent slave parameter + OT_SolarStorageFHBsize, // u8 /u8 / Solar Storage Size of Fault-History-Buffer supported by slave + OT_SolarStorageFHBindexFHBvalue, // u8 /u8 / Solar Storage Index number / Value of referred-to fault-history buffer entry + OT_ElectricityProducerStarts, // u16 Electricity producer starts + OT_ElectricityProducerHours, //u16 Electricity producer hours + OT_ElectricityProduction, //u16 Electricity production + OT_CumulativElectricityProduction, // u16 Cumulativ Electricity production + OT_BurnerUnsuccessfulStarts, // u16 Number of Un-successful burner starts + OT_FlameSignalTooLow, //u16 Number of times flame signal too low + OT_OEMDiagnosticCode, // u16 OEM-specific diagnostic/service code + OT_BurnerStarts, // u16 Number of starts burner + OT_CHPumpStarts, // u16 Number of starts CH pump + OT_DHWPumpValveStarts, // u16 Number of starts DHW pump/valve + OT_DHWBurnerStarts, // u16 Number of starts burner during DHW mode + OT_BurnerOperationHours, // u16 Number of hours that burner is in operation (i.e. flame on) + OT_CHPumpOperationHours, // u16 Number of hours that CH pump has been running + OT_DHWPumpValveOperationHours, // u16 Number of hours that DHW pump has been running or DHW valve has been opened + OT_DHWBurnerOperationHours, // u16 Number of hours that burner is in operation during DHW mode + OT_OpenThermVersionMaster, // f8.8 The implemented version of the OpenTherm Protocol Specification in the master. + OT_OpenThermVersionSlave, // f8.8 The implemented version of the OpenTherm Protocol Specification in the slave. + OT_MasterVersion, // u8 / u8 Master product version number and type + OT_SlaveVersion, // u8 / u8 Slave product version number and type + OT_RemehadFdUcodes, // u8 / u8 Remeha dF-/dU-codes + OT_RemehaServicemessage, // u8 / u8 Remeha Servicemessage + OT_RemehaDetectionConnectedSCU, // u8 / u8 Remeha detection connected SCU’s +}; + enum OTtype_t { ot_f88, ot_s16, ot_s8s8, ot_u16, ot_u8u8, ot_flag8, ot_flag8flag8, ot_special, ot_flag8u8, ot_u8, ot_undef}; + enum OTmsgcmd_t { OT_READ, OT_WRITE, OT_RW, OT_UNDEF }; + + struct OTlookup_t + { + int id; + OTmsgcmd_t msgcmd; + OTtype_t type; + const char* label; + const char* friendlyname; + const char* unit; + }; + + OTlookup_t OTlookupitem; + + const OTlookup_t OTmap[] PROGMEM = { + { 0, OT_READ , ot_flag8flag8, "Status", "Master and Slave status", "" }, + { 1, OT_WRITE , ot_f88, "TSet", "Control setpoint", "°C" }, + { 2, OT_WRITE , ot_flag8u8, "MasterConfigMemberIDcode", "Master Config / Member ID", "" }, + { 3, OT_READ , ot_flag8u8, "SlaveConfigMemberIDcode", "Slave Config / Member ID", "" }, + { 4, OT_RW , ot_u8u8, "Command", "Command-Code", "" }, + { 5, OT_READ , ot_flag8u8, "ASFflags", "Application-specific fault", "" }, + { 6, OT_READ , ot_flag8u8, "RBPflags", "Remote-parameter flags", "" }, + { 7, OT_WRITE , ot_f88, "CoolingControl", "Cooling control signal", "%" }, + { 8, OT_WRITE , ot_f88, "TsetCH2", "Control setpoint for 2e CH circuit", "°C" }, + { 9, OT_READ , ot_f88, "TrOverride", "Remote override room setpoint", "°C" }, + { 10, OT_READ , ot_u8u8, "TSP", "Number of TSPs", "" }, + { 11, OT_RW , ot_u8u8, "TSPindexTSPvalue", "Index number / Value of referred-to transparent slave parameter", "" }, + { 12, OT_READ , ot_u8u8, "FHBsize", "Size of Fault-History-Buffer supported by slave", "" }, + { 13, OT_READ , ot_u8u8, "FHBindexFHBvalue", "Index number / Value of referred-to fault-history buffer entry", "" }, + { 14, OT_WRITE , ot_f88, "MaxRelModLevelSetting", "Maximum relative modulation level setting", "%" }, + { 15, OT_READ , ot_u8u8, "MaxCapacityMinModLevel", "Maximum boiler capacity (kW) / Minimum boiler modulation level(%)", "kW/%" }, + { 16, OT_WRITE , ot_f88, "TrSet", "Room Setpoint", "°C" }, + { 17, OT_READ , ot_f88, "RelModLevel", "Relative Modulation Level", "%" }, + { 18, OT_READ , ot_f88, "CHPressure", "CH water pressure", "bar" }, + { 19, OT_READ , ot_f88, "DHWFlowRate", "DHW flow rate", "l/m" }, + { 20, OT_RW , ot_special, "DayTime", "Day of Week and Time of Day", "" }, + { 21, OT_RW , ot_u8u8, "Date", "Calendar date ", "" }, + { 22, OT_RW , ot_u16, "Year", "Calendar year", "" }, + { 23, OT_WRITE , ot_f88, "TrSetCH2", "Room Setpoint CH2", "°C" }, + { 24, OT_WRITE , ot_f88, "Tr", "Room Temperature", "°C" }, + { 25, OT_READ , ot_f88, "Tboiler", "Boiler water temperature", "°C" }, + { 26, OT_READ , ot_f88, "Tdhw", "DHW temperature", "°C" }, + { 27, OT_READ , ot_f88, "Toutside", "Outside temperature", "°C" }, + { 28, OT_READ , ot_f88, "Tret", "Return water temperature", "°C" }, + { 29, OT_READ , ot_f88, "Tsolarstorage", "Solar storage temperature", "°C" }, + { 30, OT_READ , ot_s16, "Tsolarcollector", "Solar collector temperature", "°C" }, + { 31, OT_READ , ot_f88, "TflowCH2", "Flow water temperature CH2", "°C" }, + { 32, OT_READ , ot_f88, "Tdhw2", "DHW2 temperature", "°C" }, + { 33, OT_READ , ot_s16, "Texhaust", "Exhaust temperature", "°C" }, + { 34, OT_READ , ot_f88, "Theatexchanger", "Boiler heat exchanger temperature", "°C" }, + { 35, OT_READ , ot_u8u8, "FanSpeed", "Boiler fan speed and setpoint", "rpm" }, + { 36, OT_READ , ot_f88, "ElectricalCurrentBurnerFlame", "Electrical current through burner flame", "µA" }, + { 37, OT_READ , ot_f88, "TRoomCH2", "Room temperature for 2nd CH circuit", "°C" }, + { 38, OT_READ , ot_u8u8, "RelativeHumidity", "Relative Humidity", "%" }, + { 39, OT_UNDEF , ot_undef, "", "", "" }, + { 40, OT_UNDEF , ot_undef, "", "", "" }, + { 41, OT_UNDEF , ot_undef, "", "", "" }, + { 42, OT_UNDEF , ot_undef, "", "", "" }, + { 43, OT_UNDEF , ot_undef, "", "", "" }, + { 44, OT_UNDEF , ot_undef, "", "", "" }, + { 45, OT_UNDEF , ot_undef, "", "", "" }, + { 46, OT_UNDEF , ot_undef, "", "", "" }, + { 47, OT_UNDEF , ot_undef, "", "", "" }, + { 48, OT_READ , ot_s8s8, "TdhwSetUBTdhwSetLB", "DHW setpoint upper & lower bounds for adjustment", "°C" }, + { 49, OT_READ , ot_s8s8, "MaxTSetUBMaxTSetLB", "Max CH water setpoint upper & lower bounds for adjustment", "°C" }, + { 50, OT_READ , ot_s8s8, "HcratioUBHcratioLB", "OTC heat curve ratio upper & lower bounds for adjustment", "°C" }, + { 51, OT_READ , ot_s8s8, "Remoteparameter4boundaries", "Remote parameter 4 boundaries", "" }, + { 52, OT_READ , ot_s8s8, "Remoteparameter5boundaries", "Remote parameter 5 boundaries", "" }, + { 53, OT_READ , ot_s8s8, "Remoteparameter6boundaries", "Remote parameter 6 boundaries", "" }, + { 54, OT_READ , ot_s8s8, "Remoteparameter7boundaries", "Remote parameter 7 boundaries", "" }, + { 55, OT_READ , ot_s8s8, "Remoteparameter8boundaries", "Remote parameter 8 boundaries", "" }, + { 56, OT_RW , ot_f88, "TdhwSet", "DHW setpoint", "°C" }, + { 57, OT_RW , ot_f88, "MaxTSet", "Max CH water setpoint", "°C" }, + { 58, OT_RW , ot_f88, "Hcratio", "OTC heat curve ratio", "°C" }, + { 59, OT_RW , ot_f88, "Remoteparameter4", "Remote parameter 4", "" }, + { 60, OT_RW , ot_f88, "Remoteparameter5", "Remote parameter 5", "" }, + { 61, OT_RW , ot_f88, "Remoteparameter6", "Remote parameter 6", "" }, + { 62, OT_RW , ot_f88, "Remoteparameter7", "Remote parameter 7", "" }, + { 63, OT_RW , ot_f88, "Remoteparameter8", "Remote parameter 8", "" }, + { 64, OT_UNDEF , ot_undef, "", "", "" }, + { 65, OT_UNDEF , ot_undef, "", "", "" }, + { 66, OT_UNDEF , ot_undef, "", "", "" }, + { 67, OT_UNDEF , ot_undef, "", "", "" }, + { 68, OT_UNDEF , ot_undef, "", "", "" }, + { 69, OT_UNDEF , ot_undef, "", "", "" }, + { 70, OT_READ , ot_flag8flag8, "StatusVH", "Status Ventilation/Heat recovery", "" }, + { 71, OT_WRITE , ot_u8, "ControlSetpointVH", "Control setpoint V/H", "" }, + { 72, OT_READ , ot_flag8u8, "ASFFaultCodeVH", "Application-specific Fault Flags/Code V/H", "" }, + { 73, OT_READ , ot_u16, "DiagnosticCodeVH", "Diagnostic code V/H", "" }, + { 74, OT_READ , ot_flag8u8, "ConfigMemberIDVH", "Config/Member ID V/H", "" }, + { 75, OT_READ , ot_f88, "OpenthermVersionVH", "OpenTherm version V/H", "" }, + { 76, OT_READ , ot_u8u8, "VersionTypeVH", "Product version & type V/H", "" }, + { 77, OT_READ , ot_u8, "RelativeVentilation", "Relative ventilation", "%" }, + { 78, OT_RW , ot_u8u8, "RelativeHumidityExhaustAir", "Relative humidity exhaust air", "%" }, + { 79, OT_RW , ot_u16, "CO2LevelExhaustAir", "CO2 level exhaust air", "ppm" }, + { 80, OT_READ , ot_f88, "SupplyInletTemperature", "Supply inlet temperature", "°C" }, + { 81, OT_READ , ot_f88, "SupplyOutletTemperature", "Supply outlet temperature", "°C" }, + { 82, OT_READ , ot_f88, "ExhaustInletTemperature", "Exhaust inlet temperature", "°C" }, + { 83, OT_READ , ot_f88, "ExhaustOutletTemperature", "Exhaust outlet temperature", "°C" }, + { 84, OT_READ , ot_u16, "ActualExhaustFanSpeed", "Actual exhaust fan speed", "rpm" }, + { 85, OT_READ , ot_u16, "ActualSupplyFanSpeed", "Actual supply fan speed", "rpm" }, + { 86, OT_READ , ot_flag8flag8, "RemoteParameterSettingVH", "Remote Parameter Setting V/H", "" }, + { 87, OT_RW , ot_u8, "NominalVentilationValue", "Nominal Ventilation Value", "" }, + { 88, OT_READ , ot_u8u8, "TSPNumberVH", "TSP Number V/H", "" }, + { 89, OT_RW , ot_u8u8, "TSPEntryVH", "TSP setting V/H", "" }, + { 90, OT_READ , ot_u8u8, "FaultBufferSizeVH", "Fault Buffer Size V/H", "" }, + { 91, OT_READ , ot_u8u8, "FaultBufferEntryVH", "Fault Buffer Entry V/H", "" }, + { 92, OT_UNDEF , ot_undef, "", "", "" }, + { 93, OT_UNDEF , ot_undef, "", "", "" }, + { 94, OT_UNDEF , ot_undef, "", "", "" }, + { 95, OT_UNDEF , ot_undef, "", "", "" }, + { 96, OT_UNDEF , ot_undef, "", "", "" }, + { 97, OT_UNDEF , ot_undef, "", "", "" }, + { 98, OT_READ , ot_u8u8, "RFstrengthbatterylevel", "RF strength and battery level", "" }, + { 99, OT_READ , ot_u8u8, "OperatingMode_HC1_HC2_DHW", "Operating Mode HC1, HC2/ DHW", "" }, + { 100, OT_READ , ot_flag8, "RoomRemoteOverrideFunction", "Function of manual and program changes in master and remote room setpoint.", "" }, + { 101, OT_READ , ot_flag8flag8, "SolarStorageMaster", "Solar Storage Master mode", "" }, + { 102, OT_READ , ot_flag8u8, "SolarStorageASFflags", "Solar Storage Application-specific flags and OEM fault", "" }, + { 103, OT_READ , ot_flag8u8, "SolarStorageSlaveConfigMemberIDcode", "Solar Storage Slave Config / Member ID", "" }, + { 104, OT_READ , ot_u8u8, "SolarStorageVersionType", "Solar Storage product version number and type", "" }, + { 105, OT_READ , ot_u8u8, "SolarStorageTSP", "Solar Storage Number of Transparent-Slave-Parameters supported", "" }, + { 106, OT_RW , ot_u8u8, "SolarStorageTSPindexTSPvalue", "Solar Storage Index number / Value of referred-to transparent slave parameter", "" }, + { 107, OT_READ , ot_u8u8, "SolarStorageFHBsize", "Solar Storage Size of Fault-History-Buffer supported by slave", "" }, + { 108, OT_READ , ot_u8u8, "SolarStorageFHBindexFHBvalue", "Solar Storage Index number / Value of referred-to fault-history buffer entry", "" }, + { 109, OT_READ , ot_u16, "ElectricityProducerStarts", "Electricity producer starts", "" }, + { 110, OT_READ , ot_u16, "ElectricityProducerHours", "Electricity producer hours", "" }, + { 111, OT_READ , ot_u16, "ElectricityProduction", "Electricity production", "" }, + { 112, OT_READ , ot_u16, "CumulativElectricityProduction", "Cumulativ Electricity production", "" }, + { 113, OT_RW , ot_u16, "BurnerUnsuccessfulStarts", "Unsuccessful burner starts", "" }, + { 114, OT_RW , ot_u16, "FlameSignalTooLow", "Flame signal too low count", "" }, + { 115, OT_READ , ot_u16, "OEMDiagnosticCode", "OEM-specific diagnostic/service code", "" }, + { 116, OT_RW , ot_u16, "BurnerStarts", "Burner starts", "" }, + { 117, OT_RW , ot_u16, "CHPumpStarts", "CH pump starts", "" }, + { 118, OT_RW , ot_u16, "DHWPumpValveStarts", "DHW pump/valve starts", "" }, + { 119, OT_RW , ot_u16, "DHWBurnerStarts", "DHW burner starts", "" }, + { 120, OT_RW , ot_u16, "BurnerOperationHours", "Burner operation hours", "hrs" }, + { 121, OT_RW , ot_u16, "CHPumpOperationHours", "CH pump operation hours", "hrs" }, + { 122, OT_RW , ot_u16, "DHWPumpValveOperationHours", "DHW pump/valve operation hours", "hrs" }, + { 123, OT_RW , ot_u16, "DHWBurnerOperationHours", "DHW burner operation hours", "hrs" }, + { 124, OT_READ , ot_f88, "OpenThermVersionMaster", "Master Version OpenTherm Protocol Specification", "" }, + { 125, OT_READ , ot_f88, "OpenThermVersionSlave", "Slave Version OpenTherm Protocol Specification", "" }, + { 126, OT_READ , ot_u8u8, "MasterVersion", "Master product version number and type", "" }, + { 127, OT_READ , ot_u8u8, "SlaveVersion", "Slave product version number and type", "" }, + { 128, OT_UNDEF , ot_undef, "", "", "" }, + { 129, OT_UNDEF , ot_undef, "", "", "" }, + { 130, OT_UNDEF , ot_undef, "", "", "" }, + { 131, OT_RW , ot_u8u8, "RemehadFdUcodes", "Remeha dF-/dU-codes", "" }, + { 132, OT_READ , ot_u8u8, "RemehaServicemessage", "Remeha Servicemessage", "" }, + { 133, OT_READ , ot_u8u8, "RemehaDetectionConnectedSCU", "Remeha detection connected SCU’s", "" }, + // all data ids are not defined above are resevered for future use + // A foney id is used for sensors on GPIO ports, + // 245 for counter and + // 246 for Dallas temperature sensors + }; + +#define OT_MSGID_MAX 133 + +time_t msglastupdated[255] = {0}; //all msg, even if they are unknown + +struct OT_cmd_t { // see all possible commands for PIC here: https://otgw.tclcode.com/firmware.html + char cmd[15]; + int cmdlen; + int retrycnt; + unsigned long due; +}; + +#define CMDQUEUE_MAX 20 +struct OT_cmd_t cmdqueue[CMDQUEUE_MAX]; +static int cmdptr = 0; + +enum OpenThermStatus { + OT_NOT_INITIALIZED, + OT_READY, + OT_DELAY, + OT_REQUEST_SENDING, + OT_RESPONSE_WAITING, + OT_RESPONSE_START_BIT, + OT_RESPONSE_RECEIVING, + OT_RESPONSE_READY, + OT_RESPONSE_INVALID +}; + +/** + * Structure to hold Opentherm data packet content. + * Use f88(), u16() or s16() functions to get appropriate value of data packet accoridng to id of message. + */ +/** + * Structure to hold Opentherm data packet content. + * Use f88(), u16() or s16() functions to get appropriate value of data packet according to id of message. + */ + +enum OTGW_response_type { + OTGW_BOILER, + OTGW_THERMOSTAT, + OTGW_ANSWER_THERMOSTAT, + OTGW_REQUEST_BOILER, + OTGW_PARITY_ERROR, + OTGW_UNDEF +}; +struct OpenthermData_t { + char buf[10]; + byte len; + uint32_t value; + byte masterslave; //0=master, 1=slave + byte type; + byte id; + byte valueHB; + byte valueLB; + byte rsptype; + byte skipthis; //when true, then do not send to MQTT + time_t time; + /** + * @return float representation of data packet value + */ + float f88(); + + /** + * @param float number to set as value of this data packet + */ + void f88(float value); + + /** + * @return unsigned 16b integer representation of data packet value + */ + uint16_t u16(); + + /** + * @param unsigned 16b integer number to set as value of this data packet + */ + void u16(uint16_t value); + + /** + * @return signed 16b integer representation of data packet value + */ + int16_t s16(); + + /** + * @param signed 16b integer number to set as value of this data packet + */ + void s16(int16_t value); +}; + + +#endif + + +/*************************************************************************** +* +* Permission is hereby granted, free of charge, to any person obtaining a +* copy of this software and associated documentation files (the +* "Software"), to deal in the Software without restriction, including +* without limitation the rights to use, copy, modify, merge, publish, +* distribute, sublicense, and/or sell copies of the Software, and to permit +* persons to whom the Software is furnished to do so, subject to the +* following conditions: +* +* The above copyright notice and this permission notice shall be included +* in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT +* OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR +* THE USE OR OTHER DEALINGS IN THE SOFTWARE. +* +***************************************************************************/ From e334c42d99571614817105b3ac8913ea0abb8d9b Mon Sep 17 00:00:00 2001 From: Robert van den Breemen Date: Tue, 16 Apr 2024 00:45:40 +0200 Subject: [PATCH 12/13] before update 0.10.3 --- OTGW-Core.h.tmp | 567 -------------------------------------------- outputs_ext.ino.tmp | 99 ++++++++ 2 files changed, 99 insertions(+), 567 deletions(-) delete mode 100644 OTGW-Core.h.tmp create mode 100644 outputs_ext.ino.tmp diff --git a/OTGW-Core.h.tmp b/OTGW-Core.h.tmp deleted file mode 100644 index e9485cc5..00000000 --- a/OTGW-Core.h.tmp +++ /dev/null @@ -1,567 +0,0 @@ -/* -*************************************************************************** -** Program : Header file: OTGW-Core.h -** Version : v0.10.2 -** -** Copyright (c) 2021-2023 Robert van den Breemen -** Borrowed from OpenTherm library from: -** https://github.com/jpraus/arduino-opentherm -** -** TERMS OF USE: MIT License. See bottom of file. -*************************************************************************** -*/ - -#ifndef OTGWCore_h -#define OTGWCore_h - -// OTGW Serial 2 network port -// #include // https://github.com/jandrassy/TelnetStream/commit/1294a9ee5cc9b1f7e51005091e351d60c8cddecf -#define OTGW_SERIAL_PORT 25238 // changed the port to original default of OTmonitor -TelnetStreamClass OTGWstream(OTGW_SERIAL_PORT); - -//Depends on the library -#define OTGW_COMMAND_TOPIC "command" - -typedef struct { - uint16_t Statusflags = 0; // flag8 / flag8 Master and Slave Status flags. - uint8_t MasterStatus = 0; - uint8_t SlaveStatus = 0; - float TSet = 0.0f; // f8.8 Control setpoint ie CH water temperature setpoint (°C) - uint16_t MasterConfigMemberIDcode = 0; // flag8 / u8 Master Configuration Flags / Master MemberID Code - uint16_t SlaveConfigMemberIDcode = 0; // flag8 / u8 Slave Configuration Flags / Slave MemberID Code - uint16_t Command = 0; // u8 / u8 Remote Command - uint16_t ASFflags = 0; // / OEM-fault-code flag8 / u8 Application-specific fault flags and OEM fault code - uint16_t RBPflags = 0; // flag8 / flag8 Remote boiler parameter transfer-enable & read/write flags - float CoolingControl = 0.0f; // f8.8 Cooling control signal (%) - float TsetCH2 = 0.0f; // f8.8 Control setpoint for 2e CH circuit (°C) - float TrOverride = 0.0f; // f8.8 Remote override room setpoint - uint16_t TSP = 0; // u8 / u8 Number of Transparent-Slave-Parameters supported by slave - uint16_t TSPindexTSPvalue = 0; // u8 / u8 Index number / Value of referred-to transparent slave parameter. - uint16_t FHBsize = 0; // u8 / u8 Size of Fault-History-Buffer supported by slave - uint16_t FHBindexFHBvalue = 0; // u8 / u8 Index number / Value of referred-to fault-history buffer entry. - float MaxRelModLevelSetting = 0.0f; // f8.8 Maximum relative modulation level setting (%) - uint16_t MaxCapacityMinModLevel = 0; // u8 / u8 Maximum boiler capacity (kW) / Minimum boiler modulation level(%) - float TrSet = 0.0f; // f8.8 Room Setpoint (°C) - float RelModLevel = 0.0f; // f8.8 Relative Modulation Level (%) - float CHPressure = 0.0f; // f8.8 Water pressure in CH circuit (bar) - float DHWFlowRate = 0.0f; // f8.8 Water flow rate in DHW circuit. (litres/minute) - uint16_t DayTime = 0; // special / u8 Day of Week and Time of Day - uint16_t Date = 0; // u8 / u8 Calendar date - uint16_t Year = 0; // u16 Calendar year - float TrSetCH2 = 0.0f; // f8.8 Room Setpoint for 2nd CH circuit (°C) - float Tr = 0.0f; // f8.8 Room temperature (°C) - float Tboiler = 0.0f; // f8.8 Boiler flow water temperature (°C) - float Tdhw = 0.0f; // f8.8 DHW temperature (°C) - float Toutside = 0.0f; // f8.8 Outside temperature (°C) - float Tret = 0.0f; // f8.8 Return water temperature (°C) - float Tsolarstorage = 0.0f; // f8.8 Solar storage temperature (°C) - int16_t Tsolarcollector = 0.0f; // s16 Solar collector temperature (°C) - float TflowCH2 = 0.0f; // f8.8 Flow water temperature CH2 circuit (°C) - float Tdhw2 = 0.0f; // f8.8 Domestic hot water temperature 2 (°C) - int16_t Texhaust = 0; // s16 Boiler exhaust temperature (°C) - float Theatexchanger = 0.0f; // f8.8 Heat Exchanger (°C) - uint16_t FanSpeed = 0; // u16 Fan Speed (rpm) - float ElectricalCurrentBurnerFlame = 0.0f; // f88 Electrical current through burner flame (µA) - float TRoomCH2= 0.0f; // f88 Room Temperature for 2nd CH circuit ("°C) - uint16_t RelativeHumidity = 0; // u8 / u8 Relative Humidity (%) - uint16_t TdhwSetUBTdhwSetLB = 0 ; // s8 / s8 DHW setpoint upper & lower bounds for adjustment (°C) - uint16_t MaxTSetUBMaxTSetLB = 0; // s8 / s8 Max CH water setpoint upper & lower bounds for adjustment (°C) - uint16_t HcratioUBHcratioLB = 0; // s8 / s8 OTC heat curve ratio upper & lower bounds for adjustment - uint16_t Remoteparameter4boundaries = 0; // s8 / s8 Remote parameter 4 upper & lower bounds for adjustment - uint16_t Remoteparameter5boundaries = 0; // s8 / s8 Remote parameter 5 upper & lower bounds for adjustment - uint16_t Remoteparameter6boundaries = 0; // s8 / s8 Remote parameter 6 upper & lower bounds for adjustment - uint16_t Remoteparameter7boundaries = 0; // s8 / s8 Remote parameter 7 upper & lower bounds for adjustment - uint16_t Remoteparameter8boundaries = 0; // s8 / s8 Remote parameter 8 upper & lower bounds for adjustment - float TdhwSet = 0.0f; // f8.8 DHW setpoint (°C) (Remote parameter 1) - float MaxTSet = 0.0f; // f8.8 Max CH water setpoint (°C) (Remote parameters 2) - float Hcratio = 0.0f; // f8.8 OTC heat curve ratio (°C) (Remote parameter 3) - float Remoteparameter4 = 0.0f; // f8.8 Remote parameter 4 - float Remoteparameter5 = 0.0f; // f8.8 Remote parameter 5 - float Remoteparameter6 = 0.0f; // f8.8 Remote parameter 6 - float Remoteparameter7 = 0.0f; // f8.8 Remote parameter 7 - float Remoteparameter8 = 0.0f; // f8.8 Remote parameter 8 - - //RF - uint16_t RFstrengthbatterylevel = 0; // u8/ u8 RF strength and battery level - uint16_t OperatingMode_HC1_HC2_DHW = 0; // u8 / u8 Operating Mode HC1, HC2/ DHW - uint16_t RoomRemoteOverrideFunction = 0; // Function of manual and program changes in master and remote room setpoint - - //Electric Producer - uint16_t ElectricityProducerStarts = 0; // u16 Electricity producer starts - uint16_t ElectricityProducerHours = 0; // u16 Electricity producer hours - uint16_t ElectricityProduction = 0; // u16 Electricity production - uint16_t CumulativElectricityProduction = 0; // u16 Cumulativ Electricity production - - //Solar Storage - uint16_t SolarStorageStatus = 0; - uint8_t SolarMasterStatus = 0; - uint8_t SolarSlaveStatus = 0; - uint16_t SolarStorageASFflags = 0; - uint16_t SolarStorageSlaveConfigMemberIDcode = 0; - uint16_t SolarStorageVersionType = 0; - uint16_t SolarStorageTSP = 0; - uint16_t SolarStorageTSPindexTSPvalue = 0; - uint16_t SolarStorageFHBsize = 0; - uint16_t SolarStorageFHBindexFHBvalue = 0; - - //Ventilation/HeatRecovery Msgids - uint16_t StatusVH = 0; - uint8_t MasterStatusVH = 0; - uint8_t SlaveStatusVH = 0; - uint16_t ControlSetpointVH = 0; //should be uint8_t - uint16_t ASFFaultCodeVH = 0; - uint16_t DiagnosticCodeVH = 0; - uint16_t ConfigMemberIDVH = 0; - float OpenthermVersionVH = 0.0f; - uint16_t VersionTypeVH = 0; - uint16_t RelativeVentilation = 0; - uint16_t RelativeHumidityExhaustAir = 0; - uint16_t CO2LevelExhaustAir = 0; - float SupplyInletTemperature = 0.0f; - float SupplyOutletTemperature = 0.0f; - float ExhaustInletTemperature = 0.0f; - float ExhaustOutletTemperature = 0.0f; - uint16_t ActualExhaustFanSpeed = 0; - uint16_t ActualSupplyFanSpeed = 0; - uint16_t RemoteParameterSettingVH = 0; - uint16_t NominalVentilationValue = 0; - uint16_t TSPNumberVH = 0; - uint16_t TSPEntryVH = 0; - uint16_t FaultBufferSizeVH = 0; - uint16_t FaultBufferEntryVH = 0; - - //Statitics - uint16_t BurnerUnsuccessfulStarts = 0; - uint16_t FlameSignalTooLow = 0; - uint16_t RemoteOverrideFunction = 0; // flag8 / - Function of manual and program changes in master and remote room setpoint. - uint16_t OEMDiagnosticCode = 0; // u16 OEM-specific diagnostic/service code - uint16_t BurnerStarts = 0; // u16 Number of starts burner - uint16_t CHPumpStarts = 0; // u16 Number of starts CH pump - uint16_t DHWPumpValveStarts = 0; // u16 Number of starts DHW pump/valve - uint16_t DHWBurnerStarts = 0; // u16 Number of starts burner during DHW mode - uint16_t BurnerOperationHours = 0; // u16 Number of hours that burner is in operation (i.e. flame on) - uint16_t CHPumpOperationHours = 0; // u16 Number of hours that CH pump has been running - uint16_t DHWPumpValveOperationHours = 0; // u16 Number of hours that DHW pump has been running or DHW valve has been opened - uint16_t DHWBurnerOperationHours = 0; // u16 Number of hours that burner is in operation during DHW mode - float OpenThermVersionMaster = 0.0f; // f8.8 The implemented version of the OpenTherm Protocol Specification in the master. - float OpenThermVersionSlave = 0.0f; // f8.8 The implemented version of the OpenTherm Protocol Specification in the slave. - uint16_t MasterVersion = 0; // u8 / u8 Master product version number and type - uint16_t SlaveVersion = 0; // u8 / u8 Slave product version number and type - - //Rehmea - uint16_t RemehadFdUcodes = 0; // u16 Remeha dF-/dU-codes - uint16_t RemehaServicemessage = 0; // u16 Remeha Servicemessage - uint16_t RemehaDetectionConnectedSCU =0; // u16 Remeha detection connected SCU’s - - //errors - uint16_t error01 = 0; - uint16_t error02 = 0; - uint16_t error03 = 0; - uint16_t error04 = 0; - -} OTdataStruct; - -static OTdataStruct OTcurrentSystemState; - - -enum OpenThermResponseStatus { - OT_NONE, - OT_SUCCESS, - OT_INVALID, - OT_TIMEOUT -}; - -enum OpenThermMessageType { - /* Master to Slave */ - OT_READ_DATA = B000, - OT_WRITE_DATA = B001, - OT_INVALID_DATA = B010, - OT_RESERVED = B011, - /* Slave to Master */ - OT_READ_ACK = B100, - OT_WRITE_ACK = B101, - OT_DATA_INVALID = B110, - OT_UNKNOWN_DATA_ID = B111 -}; - -enum OpenThermMessageID { - OT_Statusflags, // flag8 / flag8 Master and Slave Status flags. - OT_TSet, // f8.8 Control setpoint ie CH water temperature setpoint (°C) - OT_MasterConfigMemberIDcode, // flag8 / u8 Master Configuration Flags / Master MemberID Code - OT_SlaveConfigMemberIDcode, // flag8 / u8 Slave Configuration Flags / Slave MemberID Code - OT_Command, // u8 / u8 Remote Command - OT_ASFflags, // / OEM-fault-code flag8 / u8 Application-specific fault flags and OEM fault code - OT_RBPflags, // flag8 / flag8 Remote boiler parameter transfer-enable & read/write flags - OT_CoolingControl, // f8.8 Cooling control signal (%) - OT_TsetCH2, // f8.8 Control setpoint for 2e CH circuit (°C) - OT_TrOverride, // f8.8 Remote override room setpoint - OT_TSP, // u8 / u8 Number of Transparent-Slave-Parameters supported by slave - OT_TSPindexTSPvalue, // u8 / u8 Index number / Value of referred-to transparent slave parameter. - OT_FHBsize, // u8 / u8 Size of Fault-History-Buffer supported by slave - OT_FHBindexFHBvalue, // u8 / u8 Index number / Value of referred-to fault-history buffer entry. - OT_MaxRelModLevelSetting, // f8.8 Maximum relative modulation level setting (%) - OT_MaxCapacityMinModLevel, // u8 / u8 Maximum boiler capacity (kW) / Minimum boiler modulation level(%) - OT_TrSet, // f8.8 Room Setpoint (°C) - OT_RelModLevel, // f8.8 Relative Modulation Level (%) - OT_CHPressure, // f8.8 Water pressure in CH circuit (bar) - OT_DHWFlowRate, // f8.8 Water flow rate in DHW circuit. (litres/minute) - OT_DayTime, // special / u8 Day of Week and Time of Day - OT_Date, // u8 / u8 Calendar date - OT_Year, // u16 Calendar year - OT_TrSetCH2, // f8.8 Room Setpoint for 2nd CH circuit (°C) - OT_Tr, // f8.8 Room temperature (°C) - OT_Tboiler, // f8.8 Boiler flow water temperature (°C) - OT_Tdhw, // f8.8 DHW temperature (°C) - OT_Toutside, // f8.8 Outside temperature (°C) - OT_Tret, // f8.8 Return water temperature (°C) - OT_Tsolarstorage, // f8.8 Solar storage temperature (°C) - OT_Tsolarcollector, // s16 Solar collector temperature (°C) - OT_TflowCH2, // f8.8 Flow water temperature CH2 circuit (°C) - OT_Tdhw2, // f8.8 Domestic hot water temperature 2 (°C) - OT_Texhaust, // s16 Boiler exhaust temperature (°C) - OT_Theatexchanger, // f8.8 Heat exchanger temperature (°C) - OT_FanSpeed = 35, // u16 Fan Speed (rpm) - OT_ElectricalCurrentBurnerFlame, // f88 Electrical current through burner flame (µA) - OT_TRoomCH2, // f88 Room Temperature for 2nd CH circuit ("°C) - OT_RelativeHumidity, // u8 / u8 Relative Humidity (%) - OT_TdhwSetUBTdhwSetLB = 48, // s8 / s8 DHW setpoint upper & lower bounds for adjustment (°C) - OT_MaxTSetUBMaxTSetLB, // s8 / s8 Max CH water setpoint upper & lower bounds for adjustment (°C) - OT_HcratioUBHcratioLB, // s8 / s8 OTC heat curve ratio upper & lower bounds for adjustment - OT_Remoteparameter4boundaries, // s8 / s8 Remote Parameter ratio upper & lower bounds for adjustment - OT_Remoteparameter5boundaries, // s8 / s8 Remote Parameter upper & lower bounds for adjustment - OT_Remoteparameter6boundaries, // s8 / s8 Remote Parameter upper & lower bounds for adjustment - OT_Remoteparameter7boundaries, // s8 / s8 Remote Parameter upper & lower bounds for adjustment - OT_Remoteparameter8boundaries, // s8 / s8 Remote Parameter upper & lower bounds for adjustment - OT_TdhwSet = 56, // f8.8 DHW setpoint (°C) (Remote parameter 1) - OT_MaxTSet, // f8.8 Max CH water setpoint (°C) (Remote parameters 2) - OT_Hcratio, // f8.8 OTC heat curve ratio (°C) (Remote parameter 3) - OT_Remoteparameter4, // f8.8 Remote parameter 4 (°C) (Remote parameter 4) - OT_Remoteparameter5, // f8.8 Remote parameter 5 (°C) (Remote parameter 5) - OT_Remoteparameter6, // f8.8 Remote parameter 6 (°C) (Remote parameter 6) - OT_Remoteparameter7, // f8.8 Remote parameter 7 (°C) (Remote parameter 7) - OT_Remoteparameter8, // f8.8 Remote parameter 8 (°C) (Remote parameter 8) - OT_StatusVH = 70, // flag8 / flag8 Status Ventilation/Heat recovery - OT_ControlSetpointVH, // u8 Control setpoint V/H - OT_ASFFaultCodeVH, // flag8 / u8 Aplication Specific Fault Flags/Code V/H - OT_DiagnosticCodeVH, // u16 Diagnostic Code V/H - OT_ConfigMemberIDVH, // flag8 / u8 Config/Member ID V/H - OT_OpenthermVersionVH, // f8.8 OpenTherm Version V/H - OT_VersionTypeVH, // u8 / u8 Version & Type V/H - OT_RelativeVentilation, // u8 Relative Ventilation (%) - OT_RelativeHumidityExhaustAir, // u8 / u8 Relative Humidity (%) - OT_CO2LevelExhaustAir, // u16 CO2 Level (ppm) - OT_SupplyInletTemperature, // f8.8 Supply Inlet Temperature (°C) - OT_SupplyOutletTemperature, // f8.8 Supply Outlet Temperature(°C) - OT_ExhaustInletTemperature, // f8.8 Exhaust Inlet Temperature (°C) - OT_ExhaustOutletTemperature, // f8.8 Exhaust Outlet Temperature (°C) - OT_ActualExhaustFanSpeed, // u16 Actual Exhaust Fan Speed (rpm) - OT_ActualSupplyFanSpeed, // u16 Actual Supply Fan Speed (rpm) - OT_RemoteParameterSettingVH, // flag8 / flag8 Remote Parameter Setting V/H - OT_NominalVentilationValue, // u8 Nominal Ventilation Value - OT_TSPNumberVH, // u8 / u8 TSP Number V/H - OT_TSPEntryVH, // u8 / u8 TSP Entry V/H - OT_FaultBufferSizeVH, // u8 / u8 Fault Buffer Size V/H - OT_FaultBufferEntryVH, // u8 / u8 Fault Buffer Entry V/H - OT_RFstrengthbatterylevel=98, // u8 / u8 RF strength and battery level - OT_OperatingMode_HC1_HC2_DHW, // u8 / u8 Operating Mode HC1, HC2/ DHW - OT_RemoteOverrideFunction, // flag8 / - Function of manual and program changes in master and remote room setpoint. - OT_SolarStorageMaster, // flag8 / flag8 Solar Storage Master flags. - OT_SolarStorageASFflags, // flag8 / u8 / Solar Storage OEM-fault-code flag8 / u8 Application-specific fault flags and OEM fault code - OT_SolarStorageSlaveConfigMemberIDcode, // flag8 / u8 Solar Storage Master Configuration Flags / Master MemberID Code - OT_SolarStorageVersionType, // u8 / u8 / Solar Storage product version number and type - OT_SolarStorageTSP, // u8 / u8 / Solar Storage Number of Transparent-Slave-Parameters supported - OT_SolarStorageTSPindexTSPvalue, // u8 / u8 / Solar Storage Index number / Value of referred-to transparent slave parameter - OT_SolarStorageFHBsize, // u8 /u8 / Solar Storage Size of Fault-History-Buffer supported by slave - OT_SolarStorageFHBindexFHBvalue, // u8 /u8 / Solar Storage Index number / Value of referred-to fault-history buffer entry - OT_ElectricityProducerStarts, // u16 Electricity producer starts - OT_ElectricityProducerHours, //u16 Electricity producer hours - OT_ElectricityProduction, //u16 Electricity production - OT_CumulativElectricityProduction, // u16 Cumulativ Electricity production - OT_BurnerUnsuccessfulStarts, // u16 Number of Un-successful burner starts - OT_FlameSignalTooLow, //u16 Number of times flame signal too low - OT_OEMDiagnosticCode, // u16 OEM-specific diagnostic/service code - OT_BurnerStarts, // u16 Number of starts burner - OT_CHPumpStarts, // u16 Number of starts CH pump - OT_DHWPumpValveStarts, // u16 Number of starts DHW pump/valve - OT_DHWBurnerStarts, // u16 Number of starts burner during DHW mode - OT_BurnerOperationHours, // u16 Number of hours that burner is in operation (i.e. flame on) - OT_CHPumpOperationHours, // u16 Number of hours that CH pump has been running - OT_DHWPumpValveOperationHours, // u16 Number of hours that DHW pump has been running or DHW valve has been opened - OT_DHWBurnerOperationHours, // u16 Number of hours that burner is in operation during DHW mode - OT_OpenThermVersionMaster, // f8.8 The implemented version of the OpenTherm Protocol Specification in the master. - OT_OpenThermVersionSlave, // f8.8 The implemented version of the OpenTherm Protocol Specification in the slave. - OT_MasterVersion, // u8 / u8 Master product version number and type - OT_SlaveVersion, // u8 / u8 Slave product version number and type - OT_RemehadFdUcodes, // u8 / u8 Remeha dF-/dU-codes - OT_RemehaServicemessage, // u8 / u8 Remeha Servicemessage - OT_RemehaDetectionConnectedSCU, // u8 / u8 Remeha detection connected SCU’s -}; - enum OTtype_t { ot_f88, ot_s16, ot_s8s8, ot_u16, ot_u8u8, ot_flag8, ot_flag8flag8, ot_special, ot_flag8u8, ot_u8, ot_undef}; - enum OTmsgcmd_t { OT_READ, OT_WRITE, OT_RW, OT_UNDEF }; - - struct OTlookup_t - { - int id; - OTmsgcmd_t msgcmd; - OTtype_t type; - const char* label; - const char* friendlyname; - const char* unit; - }; - - OTlookup_t OTlookupitem; - - const OTlookup_t OTmap[] PROGMEM = { - { 0, OT_READ , ot_flag8flag8, "Status", "Master and Slave status", "" }, - { 1, OT_WRITE , ot_f88, "TSet", "Control setpoint", "°C" }, - { 2, OT_WRITE , ot_flag8u8, "MasterConfigMemberIDcode", "Master Config / Member ID", "" }, - { 3, OT_READ , ot_flag8u8, "SlaveConfigMemberIDcode", "Slave Config / Member ID", "" }, - { 4, OT_RW , ot_u8u8, "Command", "Command-Code", "" }, - { 5, OT_READ , ot_flag8u8, "ASFflags", "Application-specific fault", "" }, - { 6, OT_READ , ot_flag8u8, "RBPflags", "Remote-parameter flags", "" }, - { 7, OT_WRITE , ot_f88, "CoolingControl", "Cooling control signal", "%" }, - { 8, OT_WRITE , ot_f88, "TsetCH2", "Control setpoint for 2e CH circuit", "°C" }, - { 9, OT_READ , ot_f88, "TrOverride", "Remote override room setpoint", "°C" }, - { 10, OT_READ , ot_u8u8, "TSP", "Number of TSPs", "" }, - { 11, OT_RW , ot_u8u8, "TSPindexTSPvalue", "Index number / Value of referred-to transparent slave parameter", "" }, - { 12, OT_READ , ot_u8u8, "FHBsize", "Size of Fault-History-Buffer supported by slave", "" }, - { 13, OT_READ , ot_u8u8, "FHBindexFHBvalue", "Index number / Value of referred-to fault-history buffer entry", "" }, - { 14, OT_WRITE , ot_f88, "MaxRelModLevelSetting", "Maximum relative modulation level setting", "%" }, - { 15, OT_READ , ot_u8u8, "MaxCapacityMinModLevel", "Maximum boiler capacity (kW) / Minimum boiler modulation level(%)", "kW/%" }, - { 16, OT_WRITE , ot_f88, "TrSet", "Room Setpoint", "°C" }, - { 17, OT_READ , ot_f88, "RelModLevel", "Relative Modulation Level", "%" }, - { 18, OT_READ , ot_f88, "CHPressure", "CH water pressure", "bar" }, - { 19, OT_READ , ot_f88, "DHWFlowRate", "DHW flow rate", "l/m" }, - { 20, OT_RW , ot_special, "DayTime", "Day of Week and Time of Day", "" }, - { 21, OT_RW , ot_u8u8, "Date", "Calendar date ", "" }, - { 22, OT_RW , ot_u16, "Year", "Calendar year", "" }, - { 23, OT_WRITE , ot_f88, "TrSetCH2", "Room Setpoint CH2", "°C" }, - { 24, OT_WRITE , ot_f88, "Tr", "Room Temperature", "°C" }, - { 25, OT_READ , ot_f88, "Tboiler", "Boiler water temperature", "°C" }, - { 26, OT_READ , ot_f88, "Tdhw", "DHW temperature", "°C" }, - { 27, OT_READ , ot_f88, "Toutside", "Outside temperature", "°C" }, - { 28, OT_READ , ot_f88, "Tret", "Return water temperature", "°C" }, - { 29, OT_READ , ot_f88, "Tsolarstorage", "Solar storage temperature", "°C" }, - { 30, OT_READ , ot_s16, "Tsolarcollector", "Solar collector temperature", "°C" }, - { 31, OT_READ , ot_f88, "TflowCH2", "Flow water temperature CH2", "°C" }, - { 32, OT_READ , ot_f88, "Tdhw2", "DHW2 temperature", "°C" }, - { 33, OT_READ , ot_s16, "Texhaust", "Exhaust temperature", "°C" }, - { 34, OT_READ , ot_f88, "Theatexchanger", "Boiler heat exchanger temperature", "°C" }, - { 35, OT_READ , ot_u8u8, "FanSpeed", "Boiler fan speed and setpoint", "rpm" }, - { 36, OT_READ , ot_f88, "ElectricalCurrentBurnerFlame", "Electrical current through burner flame", "µA" }, - { 37, OT_READ , ot_f88, "TRoomCH2", "Room temperature for 2nd CH circuit", "°C" }, - { 38, OT_READ , ot_u8u8, "RelativeHumidity", "Relative Humidity", "%" }, - { 39, OT_UNDEF , ot_undef, "", "", "" }, - { 40, OT_UNDEF , ot_undef, "", "", "" }, - { 41, OT_UNDEF , ot_undef, "", "", "" }, - { 42, OT_UNDEF , ot_undef, "", "", "" }, - { 43, OT_UNDEF , ot_undef, "", "", "" }, - { 44, OT_UNDEF , ot_undef, "", "", "" }, - { 45, OT_UNDEF , ot_undef, "", "", "" }, - { 46, OT_UNDEF , ot_undef, "", "", "" }, - { 47, OT_UNDEF , ot_undef, "", "", "" }, - { 48, OT_READ , ot_s8s8, "TdhwSetUBTdhwSetLB", "DHW setpoint upper & lower bounds for adjustment", "°C" }, - { 49, OT_READ , ot_s8s8, "MaxTSetUBMaxTSetLB", "Max CH water setpoint upper & lower bounds for adjustment", "°C" }, - { 50, OT_READ , ot_s8s8, "HcratioUBHcratioLB", "OTC heat curve ratio upper & lower bounds for adjustment", "°C" }, - { 51, OT_READ , ot_s8s8, "Remoteparameter4boundaries", "Remote parameter 4 boundaries", "" }, - { 52, OT_READ , ot_s8s8, "Remoteparameter5boundaries", "Remote parameter 5 boundaries", "" }, - { 53, OT_READ , ot_s8s8, "Remoteparameter6boundaries", "Remote parameter 6 boundaries", "" }, - { 54, OT_READ , ot_s8s8, "Remoteparameter7boundaries", "Remote parameter 7 boundaries", "" }, - { 55, OT_READ , ot_s8s8, "Remoteparameter8boundaries", "Remote parameter 8 boundaries", "" }, - { 56, OT_RW , ot_f88, "TdhwSet", "DHW setpoint", "°C" }, - { 57, OT_RW , ot_f88, "MaxTSet", "Max CH water setpoint", "°C" }, - { 58, OT_RW , ot_f88, "Hcratio", "OTC heat curve ratio", "°C" }, - { 59, OT_RW , ot_f88, "Remoteparameter4", "Remote parameter 4", "" }, - { 60, OT_RW , ot_f88, "Remoteparameter5", "Remote parameter 5", "" }, - { 61, OT_RW , ot_f88, "Remoteparameter6", "Remote parameter 6", "" }, - { 62, OT_RW , ot_f88, "Remoteparameter7", "Remote parameter 7", "" }, - { 63, OT_RW , ot_f88, "Remoteparameter8", "Remote parameter 8", "" }, - { 64, OT_UNDEF , ot_undef, "", "", "" }, - { 65, OT_UNDEF , ot_undef, "", "", "" }, - { 66, OT_UNDEF , ot_undef, "", "", "" }, - { 67, OT_UNDEF , ot_undef, "", "", "" }, - { 68, OT_UNDEF , ot_undef, "", "", "" }, - { 69, OT_UNDEF , ot_undef, "", "", "" }, - { 70, OT_READ , ot_flag8flag8, "StatusVH", "Status Ventilation/Heat recovery", "" }, - { 71, OT_WRITE , ot_u8, "ControlSetpointVH", "Control setpoint V/H", "" }, - { 72, OT_READ , ot_flag8u8, "ASFFaultCodeVH", "Application-specific Fault Flags/Code V/H", "" }, - { 73, OT_READ , ot_u16, "DiagnosticCodeVH", "Diagnostic code V/H", "" }, - { 74, OT_READ , ot_flag8u8, "ConfigMemberIDVH", "Config/Member ID V/H", "" }, - { 75, OT_READ , ot_f88, "OpenthermVersionVH", "OpenTherm version V/H", "" }, - { 76, OT_READ , ot_u8u8, "VersionTypeVH", "Product version & type V/H", "" }, - { 77, OT_READ , ot_u8, "RelativeVentilation", "Relative ventilation", "%" }, - { 78, OT_RW , ot_u8u8, "RelativeHumidityExhaustAir", "Relative humidity exhaust air", "%" }, - { 79, OT_RW , ot_u16, "CO2LevelExhaustAir", "CO2 level exhaust air", "ppm" }, - { 80, OT_READ , ot_f88, "SupplyInletTemperature", "Supply inlet temperature", "°C" }, - { 81, OT_READ , ot_f88, "SupplyOutletTemperature", "Supply outlet temperature", "°C" }, - { 82, OT_READ , ot_f88, "ExhaustInletTemperature", "Exhaust inlet temperature", "°C" }, - { 83, OT_READ , ot_f88, "ExhaustOutletTemperature", "Exhaust outlet temperature", "°C" }, - { 84, OT_READ , ot_u16, "ActualExhaustFanSpeed", "Actual exhaust fan speed", "rpm" }, - { 85, OT_READ , ot_u16, "ActualSupplyFanSpeed", "Actual supply fan speed", "rpm" }, - { 86, OT_READ , ot_flag8flag8, "RemoteParameterSettingVH", "Remote Parameter Setting V/H", "" }, - { 87, OT_RW , ot_u8, "NominalVentilationValue", "Nominal Ventilation Value", "" }, - { 88, OT_READ , ot_u8u8, "TSPNumberVH", "TSP Number V/H", "" }, - { 89, OT_RW , ot_u8u8, "TSPEntryVH", "TSP setting V/H", "" }, - { 90, OT_READ , ot_u8u8, "FaultBufferSizeVH", "Fault Buffer Size V/H", "" }, - { 91, OT_READ , ot_u8u8, "FaultBufferEntryVH", "Fault Buffer Entry V/H", "" }, - { 92, OT_UNDEF , ot_undef, "", "", "" }, - { 93, OT_UNDEF , ot_undef, "", "", "" }, - { 94, OT_UNDEF , ot_undef, "", "", "" }, - { 95, OT_UNDEF , ot_undef, "", "", "" }, - { 96, OT_UNDEF , ot_undef, "", "", "" }, - { 97, OT_UNDEF , ot_undef, "", "", "" }, - { 98, OT_READ , ot_u8u8, "RFstrengthbatterylevel", "RF strength and battery level", "" }, - { 99, OT_READ , ot_u8u8, "OperatingMode_HC1_HC2_DHW", "Operating Mode HC1, HC2/ DHW", "" }, - { 100, OT_READ , ot_flag8, "RoomRemoteOverrideFunction", "Function of manual and program changes in master and remote room setpoint.", "" }, - { 101, OT_READ , ot_flag8flag8, "SolarStorageMaster", "Solar Storage Master mode", "" }, - { 102, OT_READ , ot_flag8u8, "SolarStorageASFflags", "Solar Storage Application-specific flags and OEM fault", "" }, - { 103, OT_READ , ot_flag8u8, "SolarStorageSlaveConfigMemberIDcode", "Solar Storage Slave Config / Member ID", "" }, - { 104, OT_READ , ot_u8u8, "SolarStorageVersionType", "Solar Storage product version number and type", "" }, - { 105, OT_READ , ot_u8u8, "SolarStorageTSP", "Solar Storage Number of Transparent-Slave-Parameters supported", "" }, - { 106, OT_RW , ot_u8u8, "SolarStorageTSPindexTSPvalue", "Solar Storage Index number / Value of referred-to transparent slave parameter", "" }, - { 107, OT_READ , ot_u8u8, "SolarStorageFHBsize", "Solar Storage Size of Fault-History-Buffer supported by slave", "" }, - { 108, OT_READ , ot_u8u8, "SolarStorageFHBindexFHBvalue", "Solar Storage Index number / Value of referred-to fault-history buffer entry", "" }, - { 109, OT_READ , ot_u16, "ElectricityProducerStarts", "Electricity producer starts", "" }, - { 110, OT_READ , ot_u16, "ElectricityProducerHours", "Electricity producer hours", "" }, - { 111, OT_READ , ot_u16, "ElectricityProduction", "Electricity production", "" }, - { 112, OT_READ , ot_u16, "CumulativElectricityProduction", "Cumulativ Electricity production", "" }, - { 113, OT_RW , ot_u16, "BurnerUnsuccessfulStarts", "Unsuccessful burner starts", "" }, - { 114, OT_RW , ot_u16, "FlameSignalTooLow", "Flame signal too low count", "" }, - { 115, OT_READ , ot_u16, "OEMDiagnosticCode", "OEM-specific diagnostic/service code", "" }, - { 116, OT_RW , ot_u16, "BurnerStarts", "Burner starts", "" }, - { 117, OT_RW , ot_u16, "CHPumpStarts", "CH pump starts", "" }, - { 118, OT_RW , ot_u16, "DHWPumpValveStarts", "DHW pump/valve starts", "" }, - { 119, OT_RW , ot_u16, "DHWBurnerStarts", "DHW burner starts", "" }, - { 120, OT_RW , ot_u16, "BurnerOperationHours", "Burner operation hours", "hrs" }, - { 121, OT_RW , ot_u16, "CHPumpOperationHours", "CH pump operation hours", "hrs" }, - { 122, OT_RW , ot_u16, "DHWPumpValveOperationHours", "DHW pump/valve operation hours", "hrs" }, - { 123, OT_RW , ot_u16, "DHWBurnerOperationHours", "DHW burner operation hours", "hrs" }, - { 124, OT_READ , ot_f88, "OpenThermVersionMaster", "Master Version OpenTherm Protocol Specification", "" }, - { 125, OT_READ , ot_f88, "OpenThermVersionSlave", "Slave Version OpenTherm Protocol Specification", "" }, - { 126, OT_READ , ot_u8u8, "MasterVersion", "Master product version number and type", "" }, - { 127, OT_READ , ot_u8u8, "SlaveVersion", "Slave product version number and type", "" }, - { 128, OT_UNDEF , ot_undef, "", "", "" }, - { 129, OT_UNDEF , ot_undef, "", "", "" }, - { 130, OT_UNDEF , ot_undef, "", "", "" }, - { 131, OT_RW , ot_u8u8, "RemehadFdUcodes", "Remeha dF-/dU-codes", "" }, - { 132, OT_READ , ot_u8u8, "RemehaServicemessage", "Remeha Servicemessage", "" }, - { 133, OT_READ , ot_u8u8, "RemehaDetectionConnectedSCU", "Remeha detection connected SCU’s", "" }, - // all data ids are not defined above are resevered for future use - // A foney id is used for sensors on GPIO ports, - // 245 for counter and - // 246 for Dallas temperature sensors - }; - -#define OT_MSGID_MAX 133 - -time_t msglastupdated[255] = {0}; //all msg, even if they are unknown - -struct OT_cmd_t { // see all possible commands for PIC here: https://otgw.tclcode.com/firmware.html - char cmd[15]; - int cmdlen; - int retrycnt; - unsigned long due; -}; - -#define CMDQUEUE_MAX 20 -struct OT_cmd_t cmdqueue[CMDQUEUE_MAX]; -static int cmdptr = 0; - -enum OpenThermStatus { - OT_NOT_INITIALIZED, - OT_READY, - OT_DELAY, - OT_REQUEST_SENDING, - OT_RESPONSE_WAITING, - OT_RESPONSE_START_BIT, - OT_RESPONSE_RECEIVING, - OT_RESPONSE_READY, - OT_RESPONSE_INVALID -}; - -/** - * Structure to hold Opentherm data packet content. - * Use f88(), u16() or s16() functions to get appropriate value of data packet accoridng to id of message. - */ -/** - * Structure to hold Opentherm data packet content. - * Use f88(), u16() or s16() functions to get appropriate value of data packet according to id of message. - */ - -enum OTGW_response_type { - OTGW_BOILER, - OTGW_THERMOSTAT, - OTGW_ANSWER_THERMOSTAT, - OTGW_REQUEST_BOILER, - OTGW_PARITY_ERROR, - OTGW_UNDEF -}; -struct OpenthermData_t { - char buf[10]; - byte len; - uint32_t value; - byte masterslave; //0=master, 1=slave - byte type; - byte id; - byte valueHB; - byte valueLB; - byte rsptype; - byte skipthis; //when true, then do not send to MQTT - time_t time; - /** - * @return float representation of data packet value - */ - float f88(); - - /** - * @param float number to set as value of this data packet - */ - void f88(float value); - - /** - * @return unsigned 16b integer representation of data packet value - */ - uint16_t u16(); - - /** - * @param unsigned 16b integer number to set as value of this data packet - */ - void u16(uint16_t value); - - /** - * @return signed 16b integer representation of data packet value - */ - int16_t s16(); - - /** - * @param signed 16b integer number to set as value of this data packet - */ - void s16(int16_t value); -}; - - -#endif - - -/*************************************************************************** -* -* Permission is hereby granted, free of charge, to any person obtaining a -* copy of this software and associated documentation files (the -* "Software"), to deal in the Software without restriction, including -* without limitation the rights to use, copy, modify, merge, publish, -* distribute, sublicense, and/or sell copies of the Software, and to permit -* persons to whom the Software is furnished to do so, subject to the -* following conditions: -* -* The above copyright notice and this permission notice shall be included -* in all copies or substantial portions of the Software. -* -* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS -* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF -* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. -* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY -* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT -* OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR -* THE USE OR OTHER DEALINGS IN THE SOFTWARE. -* -***************************************************************************/ diff --git a/outputs_ext.ino.tmp b/outputs_ext.ino.tmp new file mode 100644 index 00000000..414d2e14 --- /dev/null +++ b/outputs_ext.ino.tmp @@ -0,0 +1,99 @@ +/********* +** Program : output_ext.ino +** Version : v0.10.2 +** +** Copyright (c) 2021-2023 Robert van den Breemen +** Contributed by Sjorsjuhmaniac +** +** TERMS OF USE: MIT License. See bottom of file. +*********/ + + +// adds support to activiate a digital output +// +void setOutputState(bool set_HIGH); + + +void initOutputs() { + DebugTf(PSTR("inside initOutputsO%d...\r\n"), 1); + + if (!settingGPIOOUTPUTSenabled) return; + + DebugTf(PSTR("init GPIO Output on GPIO%d...\r\n"), settingGPIOOUTPUTSpin); + + pinMode(settingGPIOOUTPUTSpin, OUTPUT); + setOutputState(OFF); + + // set the LED with the ledState of the variable: + // digitalWrite(ledPin, ledState); +} + +// still need to hook into processOTGW +void setOutputState(uint8_t status = ON){ + (status == ON) ? setOutputState(true) : setOutputState(false); +} + +void setOutputState(bool set_HIGH = true){ + if(!settingGPIOOUTPUTSenabled) return; + digitalWrite(settingGPIOOUTPUTSpin,set_HIGH?HIGH:LOW); + DebugTf(PSTR("Output GPIO%d set to %d"), settingGPIOOUTPUTSpin, digitalRead(settingGPIOOUTPUTSpin)); +} + +void evalOutputs(){ + if(!settingGPIOOUTPUTSenabled) return; + // master HB + // bit: [clear/0, set/1] + // 0: CH enable [ CH is disabled, CH is enabled] + // 1: DHW enable [ DHW is disabled, DHW is enabled] + // 2: Cooling enable [ Cooling is disabled, Cooling is enabled]] + // 3: OTC active [OTC not active, OTC is active] + // 4: CH2 enable [CH2 is disabled, CH2 is enabled] + // 5: reserved + // 6: reserved + // 7: reserved + + // slave LB + // 0: fault indication [ no fault, fault ] + // 1: CH mode [CH not active, CH active] + // 2: DHW mode [ DHW not active, DHW active] + // 3: Flame status [ flame off, flame on ] + // 4: Cooling status [ cooling mode not active, cooling mode active ] + // 5: CH2 mode [CH2 not active, CH2 active] + // 6: diagnostic indication [no diagnostics, diagnostic event] + // 7: reserved + if (!settingMyDEBUG) return; + settingMyDEBUG = false; + DebugTf(PSTR("current gpio output state: %d \r\n"), digitalRead(settingGPIOOUTPUTSpin)); + DebugFlush(); + + bool bitState = (OTcurrentSystemState.Statusflags & (2^settingGPIOOUTPUTStriggerBit)); + DebugTf(PSTR("bitState: bit: %d , state %d \r\n"), settingGPIOOUTPUTStriggerBit, bitState); + + setOutputState(bitState); + + DebugTf(PSTR("end void: current gpio output state: %d \r\n"), digitalRead(settingGPIOOUTPUTSpin)); +} + +/*************************************************************************** +* +* Permission is hereby granted, free of charge, to any person obtaining a +* copy of this software and associated documentation files (the +* "Software"), to deal in the Software without restriction, including +* without limitation the rights to use, copy, modify, merge, publish, +* distribute, sublicense, and/or sell copies of the Software, and to permit +* persons to whom the Software is furnished to do so, subject to the +* following conditions: +* +* The above copyright notice and this permission notice shall be included +* in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS +* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT +* OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR +* THE USE OR OTHER DEALINGS IN THE SOFTWARE. +* +**************************************************************************** +*/ From 32d9a1d46550624ad8758ee4381205ca4de298cb Mon Sep 17 00:00:00 2001 From: Robert van den Breemen Date: Wed, 17 Apr 2024 06:52:21 +0200 Subject: [PATCH 13/13] Update to version 0.10.3 on file headers --- FSexplorer.ino | 2 +- MQTTstuff.ino | 2 +- OTGW-Core.h | 2 +- OTGW-Core.ino | 2 +- OTGW-firmware.h | 2 +- OTGW-firmware.ino | 2 +- data/FSexplorer.css | 2 +- data/FSexplorer.html | 2 +- data/index.css | 2 +- data/index.js | 2 +- helperStuff.ino | 2 +- jsonStuff.ino | 2 +- networkStuff.h | 2 +- outputs_ext.ino | 2 +- outputs_ext.ino.tmp | 99 --------------------------------- restAPI.ino | 2 +- s0PulseCount.ino | 2 +- sensors_ext.ino | 2 +- settingStuff.ino | 2 +- theme/OTGW_Dark_Theme/index.css | 2 +- theme/OTGW_Dark_Theme/index.js | 2 +- version.h | 32 +++-------- 22 files changed, 29 insertions(+), 142 deletions(-) delete mode 100644 outputs_ext.ino.tmp diff --git a/FSexplorer.ino b/FSexplorer.ino index 4ba11faf..1977c919 100644 --- a/FSexplorer.ino +++ b/FSexplorer.ino @@ -1,7 +1,7 @@ /* *************************************************************************** ** Program : FSexplorer -** Version : v0.10.2 +** Version : v0.10.3 ** ** Mostly stolen from https://www.arduinoforum.de/User-Fips ** For more information visit: https://fipsok.de diff --git a/MQTTstuff.ino b/MQTTstuff.ino index 45be66b6..6c2fa4c5 100644 --- a/MQTTstuff.ino +++ b/MQTTstuff.ino @@ -1,7 +1,7 @@ /* *************************************************************************** ** Program : MQTTstuff -** Version : v0.10.2 +** Version : v0.10.3 ** ** Copyright (c) 2021-2023 Robert van den Breemen ** Modified version from (c) 2020 Willem Aandewiel diff --git a/OTGW-Core.h b/OTGW-Core.h index e9485cc5..e404a20a 100644 --- a/OTGW-Core.h +++ b/OTGW-Core.h @@ -1,7 +1,7 @@ /* *************************************************************************** ** Program : Header file: OTGW-Core.h -** Version : v0.10.2 +** Version : v0.10.3 ** ** Copyright (c) 2021-2023 Robert van den Breemen ** Borrowed from OpenTherm library from: diff --git a/OTGW-Core.ino b/OTGW-Core.ino index c79a496c..ef77842a 100644 --- a/OTGW-Core.ino +++ b/OTGW-Core.ino @@ -1,7 +1,7 @@ /* *************************************************************************** ** Program : OTGW-Core.ino -** Version : v0.10.2 +** Version : v0.10.3 ** ** Copyright (c) 2021-2023 Robert van den Breemen ** Borrowed from OpenTherm library from: diff --git a/OTGW-firmware.h b/OTGW-firmware.h index cb6f8bdc..37b52703 100644 --- a/OTGW-firmware.h +++ b/OTGW-firmware.h @@ -1,7 +1,7 @@ /* *************************************************************************** ** Program : OTGW-firmware.h -** Version : v0.10.2 +** Version : v0.10.3 ** ** Copyright (c) 2021-2023 Robert van den Breemen ** diff --git a/OTGW-firmware.ino b/OTGW-firmware.ino index 37a27b3d..3a628fb8 100644 --- a/OTGW-firmware.ino +++ b/OTGW-firmware.ino @@ -1,7 +1,7 @@ /* *************************************************************************** ** Program : OTGW-firmware.ino -** Version : v0.10.2 +** Version : v0.10.3 ** ** Copyright (c) 2021-2023 Robert van den Breemen ** diff --git a/data/FSexplorer.css b/data/FSexplorer.css index cc5292fb..b86fd1f6 100644 --- a/data/FSexplorer.css +++ b/data/FSexplorer.css @@ -1,7 +1,7 @@ /* *************************************************************************** ** Program : FSexplorer.html -** Version : v0.10.2 +** Version : v0.10.3 ** For more information visit: https://fipsok.de *************************************************************************** */ diff --git a/data/FSexplorer.html b/data/FSexplorer.html index 270023bd..2fa3c992 100644 --- a/data/FSexplorer.html +++ b/data/FSexplorer.html @@ -1,7 +1,7 @@