diff --git a/README.md b/README.md
index a0202a0..598ebd5 100644
--- a/README.md
+++ b/README.md
@@ -49,7 +49,7 @@ See the "[Connecting via Ethernet](#connecting-via-ethernet-optional)" section f
## Recommended ESP32 devices
-- If WIFI6 is required: ESP32-C6
+- If WIFI6 is absolutely required: ESP32-C6
- If PoE is required: Any of the above mentioned devices with PoE or any other ESP device in combination with a SPI Ethernet module ([W5500](https://www.aliexpress.com/w/wholesale-w5500.html)) and [PoE to Ethernet and USB type B/C splitter](https://aliexpress.com/w/wholesale-poe-splitter-usb-c.html)
- If you want maximum performance and intend to run any or multiple of the following:
- a Nuki Lock and Nuki Opener and/or
@@ -69,17 +69,17 @@ The ESP32-S3 is a dual-core CPU with many GPIO's, ability to enlarge RAM using P
| Feature | Nuki Hub | Nuki Bridge |
|---|---|---|
| Bridge API | | x |
-| Smart Lock remote control | (optional via smarthome solution) | x |
+| Smart Lock remote control | x | x |
| Smart Home integration via Matter | | x |
| Apple HomeKit integration via Matter | | x |
-| MQTT API | x | x (only for SL > 3, Pro models) |
+| MQTT API | x | x (only for SL 3, 4 and 4 Pro models) |
| Wired LAN support | x | |
| Power over Ethernet (PoE) | x (if supported by LAN/ESP module) | |
-| WLAN support | x | x (only for SL > 3, Pro Models) || Home Assistant integration | x (full integration of most Nuki features) | x |
+| WLAN support | x | x (only for SL 3 and 4 Pro Models) || Home Assistant integration | x (full integration of most Nuki features) | x |
| Home Automation platform integration | x | x |
-| Cloud support | (optional via smarthome solution) | x |
-| Cloud-less operation | x | x (since fw 3.8.2, to be tested) |
-| Smarthome app integration | | x |
+| Cloud support | x (optional via smarthome solution) | x |
+| Cloud-less operation | x | x (since fw 3.8.2) |
+| Official Nuki app integration | | x |
| Nuki Smartlocks all models | x | x |
| Nuki opener | x | x |
| Nuki Keypad (1.0 and 2.0) | x | x |
@@ -87,14 +87,12 @@ The ESP32-S3 is a dual-core CPU with many GPIO's, ability to enlarge RAM using P
| Fine-grained access control of MQTT API | x | |
| Export of lock actions via MQTT API | x | |
| Control via GPIO | x | |
-| Hybrid mode for Pro locks | x | |
-
-
+| Hybrid mode for WiFI and Thread connected locks | x | |
## Support Nuki Hub development
If you haven't ordered your Nuki product yet, you can support me by using my referrer code when placing your order:
-REF443RM5HR5X
+REF2BJHFVHZKK
This will also give you a 10% discount on your order.
This project is free to use for everyone. However if you feel like donating, you can buy me a coffee at ko-fi.com:
@@ -345,39 +343,39 @@ After importing the device will reboot.
- opener/retry: Reports the current number of retries for the current command. 0 when command is successful, "failed" if the number of retries is greater than the maximum configured number of retries.
### Configuration
-- [lock/opener]/configuration/buttonEnabled: 1 if the Nuki Lock/Opener button is enabled, otherwise 0.
-- [lock/opener]/configuration/ledEnabled: 1 if the Nuki Lock/Opener LED is enabled, otherwise 0.
-- [lock/opener]/configuration/ledBrightness: Set to the brightness of the LED on the Nuki Lock (0=min; 5=max) (Lock only).
-- [lock/opener]/configuration/singleLock: 0 if the Nuki Lock is set to double-lock the door, otherwise 1 (= single-lock) (Lock only).
-- [lock/opener]/configuration/autoLock: 1 if the Nuki Lock is set to Auto Lock, otherwise 0 (Lock only).
-- [lock/opener]/configuration/autoUnlock: 1 if the Nuki Lock is set to Auto Unlock, otherwise 0 (Lock only).
-- [lock/opener]/configuration/soundLevel: Set to the volume for sounds the Nuki Opener plays (0 = min; 255 = max) (Opener only).
-- [lock/opener]/configuration/action: Allows changing configuration settings of the Nuki Lock/Opener using a JSON formatted value. After receiving the action, the value is set to "--". See the "[Changing Nuki Lock/Opener Configuration](#changing-nuki-lockopener-configuration)" section of this README for possible actions/values
-- [lock/opener]/configuration/commandResult: Result of the last configuration change action as JSON data. See the "[Changing Nuki Lock/Opener Configuration](#changing-nuki-lockopener-configuration)" section of this README for possible values
-- [lock/opener]/configuration/basicJson: The current basic configuration of the Nuki Lock/Opener as JSON data. See [Nuki Smart Lock API](https://developer.nuki.io/page/nuki-smart-lock-api-2/2/#heading--set-config) and [Nuki Opener API](https://developer.nuki.io/page/nuki-opener-api-1/7/#heading--set-config) for available settings. Please note: Longitude and Latitude of the Lock/Opener are not published to MQTT by design. These values can still be changed though.
-- [lock/opener]/configuration/advancedJson: The current advanced configuration of the Nuki Lock/Opener as JSON data. See [Nuki Smart Lock API](https://developer.nuki.io/page/nuki-smart-lock-api-2/2/#heading--advanced-config) and [Nuki Opener API](https://developer.nuki.io/page/nuki-opener-api-1/7/#heading--advanced-config) for available settings.
+- [lock/opener/]configuration/buttonEnabled: 1 if the Nuki Lock/Opener button is enabled, otherwise 0.
+- [lock/opener/]configuration/ledEnabled: 1 if the Nuki Lock/Opener LED is enabled, otherwise 0.
+- [lock/opener/]configuration/ledBrightness: Set to the brightness of the LED on the Nuki Lock (0=min; 5=max) (Lock only).
+- [lock/opener/]configuration/singleLock: 0 if the Nuki Lock is set to double-lock the door, otherwise 1 (= single-lock) (Lock only).
+- [lock/opener/]configuration/autoLock: 1 if the Nuki Lock is set to Auto Lock, otherwise 0 (Lock only).
+- [lock/opener/]configuration/autoUnlock: 1 if the Nuki Lock is set to Auto Unlock, otherwise 0 (Lock only).
+- [lock/opener/]configuration/soundLevel: Set to the volume for sounds the Nuki Opener plays (0 = min; 255 = max) (Opener only).
+- [lock/opener/]configuration/action: Allows changing configuration settings of the Nuki Lock/Opener using a JSON formatted value. After receiving the action, the value is set to "--". See the "[Changing Nuki Lock/Opener Configuration](#changing-nuki-lockopener-configuration)" section of this README for possible actions/values
+- [lock/opener/]configuration/commandResult: Result of the last configuration change action as JSON data. See the "[Changing Nuki Lock/Opener Configuration](#changing-nuki-lockopener-configuration)" section of this README for possible values
+- [lock/opener/]configuration/basicJson: The current basic configuration of the Nuki Lock/Opener as JSON data. See [Nuki Smart Lock API](https://developer.nuki.io/page/nuki-smart-lock-api-2/2/#heading--set-config) and [Nuki Opener API](https://developer.nuki.io/page/nuki-opener-api-1/7/#heading--set-config) for available settings. Please note: Longitude and Latitude of the Lock/Opener are not published to MQTT by design. These values can still be changed though.
+- [lock/opener/]configuration/advancedJson: The current advanced configuration of the Nuki Lock/Opener as JSON data. See [Nuki Smart Lock API](https://developer.nuki.io/page/nuki-smart-lock-api-2/2/#heading--advanced-config) and [Nuki Opener API](https://developer.nuki.io/page/nuki-opener-api-1/7/#heading--advanced-config) for available settings.
### Query
-- [lock/opener]/query/lockstate: Set to 1 to trigger query lockstate. Auto-resets to 0.
-- [lock/opener]/query/config: Set to 1 to trigger query config. Auto-resets to 0.
-- [lock/opener]/query/keypad: Set to 1 to trigger query keypad. Auto-resets to 0.
-- [lock/opener]/query/battery: Set to 1 to trigger query battery. Auto-resets to 0.
-- [lock/opener]/query/lockstateCommandResult: Set to 1 to trigger query lockstate command result. Auto-resets to 0.
+- [lock/opener/]query/lockstate: Set to 1 to trigger query lockstate. Auto-resets to 0.
+- [lock/opener/]query/config: Set to 1 to trigger query config. Auto-resets to 0.
+- [lock/opener/]query/keypad: Set to 1 to trigger query keypad. Auto-resets to 0.
+- [lock/opener/]query/battery: Set to 1 to trigger query battery. Auto-resets to 0.
+- [lock/opener/]query/lockstateCommandResult: Set to 1 to trigger query lockstate command result. Auto-resets to 0.
### Battery
-- [lock/opener]/battery/level: Battery level in percent (Lock only).
-- [lock/opener]/battery/critical: 1 if battery level is critical, otherwise 0.
-- [lock/opener]/battery/charging: 1 if charging, otherwise 0 (Lock only).
-- [lock/opener]/battery/voltage: Current Battery voltage (V).
-- [lock/opener]/battery/drain: The drain of the last lock action in Milliwattseconds (mWs) (Lock only).
-- [lock/opener]/battery/maxTurnCurrent: The highest current of the turn motor during the last lock action (A) (Lock only).
-- [lock/opener]/battery/lockDistance: The total distance during the last lock action in centidegrees (Lock only).
-- [lock/opener]/battery/keypadCritical: 1 if the battery level of a connected keypad is critical, otherwise 0.
-- [lock/opener]/battery/doorSensorCritical (only available in hybdrid mode): 1 if the battery level of a connected doorsensor is critical, otherwise 0.
-- [lock/opener]/battery/basicJson: The current battery state (critical, charging, level and keypad critical) of the Nuki Lock/Opener as JSON data.
-- [lock/opener]/battery/advancedJson: : The current battery state (critical, batteryDrain, batteryVoltage, lockAction, startVoltage, lowestVoltage, lockDistance, startTemperature, maxTurnCurrent and batteryResistance) of the Nuki Lock/Opener as JSON data.
+- [lock/opener/]battery/level: Battery level in percent (Lock only).
+- [lock/opener/]battery/critical: 1 if battery level is critical, otherwise 0.
+- [lock/opener/]battery/charging: 1 if charging, otherwise 0 (Lock only).
+- [lock/opener/]battery/voltage: Current Battery voltage (V).
+- [lock/opener/]battery/drain: The drain of the last lock action in Milliwattseconds (mWs) (Lock only).
+- [lock/opener/]battery/maxTurnCurrent: The highest current of the turn motor during the last lock action (A) (Lock only).
+- [lock/opener/]battery/lockDistance: The total distance during the last lock action in centidegrees (Lock only).
+- [lock/opener/]battery/keypadCritical: 1 if the battery level of a connected keypad is critical, otherwise 0.
+- [lock/opener/]battery/doorSensorCritical (only available in hybrid mode): 1 if the battery level of a connected doorsensor is critical, otherwise 0.
+- [lock/opener/]battery/basicJson: The current battery state (critical, charging, level and keypad critical) of the Nuki Lock/Opener as JSON data.
+- [lock/opener/]battery/advancedJson: : The current battery state (critical, batteryDrain, batteryVoltage, lockAction, startVoltage, lowestVoltage, lockDistance, startTemperature, maxTurnCurrent and batteryResistance) of the Nuki Lock/Opener as JSON data.
### Keypad
@@ -390,8 +388,8 @@ After importing the device will reboot.
### Info
- info/nukiHubVersion: Set to the current version number of the Nuki Hub firmware.
-- info/firmwareVersion: Set to the current version number of the Nuki Lock/Opener firmware.
-- info/hardwareVersion: Set to the hardware version number of the Nuki Lock/Opener.
+- [lock/opener/]info/firmwareVersion: Set to the current version number of the Nuki Lock/Opener firmware.
+- [lock/opener/]info/hardwareVersion: Set to the hardware version number of the Nuki Lock/Opener.
- info/nukiHubIp: Set to the IP of the Nuki Hub.
- info/nukiHubLatest: Set to the latest available Nuki Hub firmware version number (if update checking is enabled in the settings).
@@ -519,10 +517,10 @@ If Home Assistant discovery is enabled (see the [Home Assistant Discovery](#hom
After the initial installation of the Nuki Hub firmware via serial connection, further updates can be deployed via OTA update from a browser.
In the configuration portal, select "Firmware update" from the main page.
-The easiest way to upgrade Nuki Hub, if Nuki Hub is connected to the internet, is to select "Auto Update".
+The easiest way to upgrade Nuki Hub, if Nuki Hub is connected to the internet, is to select "Update to latest version".
This will download the latest Nuki Hub and Nuki Hub updater and automatically upgrade both applications.
Nuki Hub will reboot 3 times during this process, which will take about 5 minutes.
-If you have enabled "Allow updating using MQTT" you can also use the Home Assistant updater or write "1" to the `nukihub/maintanance/reset` topic to start the update process.
+If you have enabled "Allow updating using MQTT" you can also use the Home Assistant updater or write "1" to the `nukihub/maintanance/update` topic to start the update process.
Alternatively you can select a binary file from your file system to update Nuki Hub or the Nuki Hub updator manually
You can only update Nuki Hub from the Nuki Hub updater and update the updater only from Nuki Hub
@@ -566,7 +564,7 @@ openssl req -new -key server.key -out server.csr -subj "/C=US/ST=YourState/L=You
## Home Assistant Discovery (optional)
This software supports [MQTT Discovery](https://www.home-assistant.io/docs/mqtt/discovery/) for integrating Nuki Hub with Home Assistant.
-To enable autodiscovery, supply the discovery topic that is configured in your Home Assistant instance (If you have not changed this setting in Home Assistant the default is "homeassistant") in the MQTT Configuration page.
+To enable autodiscovery, enable the checkbox on the "MQTT Configuration" page.
Once enabled, the Nuki Lock and/or Opener and related entities should automatically appear in your Home Assistant MQTT devices.
The following mapping between Home Assistant services and Nuki commands is setup when enabling autodiscovery:
@@ -734,7 +732,7 @@ To enable GPIO control, go the the "GPIO Configuration" page where each GPIO can
If you prefer to connect to via Ethernet instead of Wi-Fi, you either use one of the supported ESP32 modules with built-in ethernet (see "[Supported devices](#supported-devices)" section)
or wire a seperate SPI Ethernet module.
Currently the Wiznet W5x00 Module (W5100, W5200, W5500), DN9051 and KSZ8851SNL chips are supported.
-To use a supported module, flash the firmware, connect via Wi-Fi and select the correct network hardware in the "MQTT and Network Configuration" section.
+To use a supported module, flash the firmware, connect via Wi-Fi and select the correct network hardware in the "Network Configuration" section.
To wire an external W5x00 module to the ESP, use this wiring scheme:
@@ -749,7 +747,7 @@ To wire an external W5x00 module to the ESP, use this wiring scheme:
Now connect via Wi-Fi and change the network hardware to "Generic W5500".
-If Ethernet hwardware isn't detected, Wi-Fi is used as a fallback, unless this is disabled in the settings.
+If Ethernet hardware isn't detected or initialised properly after changing the network device, Wi-Fi will be used as a fallback.
Note: LAN8720 modules are only supported on the ESP32 and ESP32-Solo1, not on the ESP32-S3, ESP32-C3 or ESP-C6
@@ -758,7 +756,7 @@ Note: LAN8720 modules are only supported on the ESP32 and ESP32-Solo1, not on th
### Random Wi-Fi disconnects
Unfortunately the ESP32 has problems with some access points and reconnecting fails.
-As a workaround you can navigate to "MQTT and Network Configuration" and enable "Restart on disconnect".
+As a workaround you can navigate to "Network Configuration" and enable "Restart on disconnect".
This will reboot the ESP as soon as it gets disconnected from Wi-Fi.
Also, this reduces the config portal timeout to three minutes to prevent the ESP being stuck in config mode in case an access point is offline temporarily.
If this still doesn't fix the disconnects and the ESP becomes unreachable, the "Restart timer" option can be used as a last resort.
@@ -781,7 +779,7 @@ A note about the [M5Stack PoESP32 Unit](https://docs.m5stack.com/en/unit/poesp32
Make sure you are using at least version 2023.8.0 of Home Assistant.
The Home Assistant developers have made changes to MQTT auto discovery which break support for older version and Nuki Hub has adopted these changes.
-This unfortunately means that older versions of Home Assistant are not supported by the Nuki Hub discovery implemenation anymore.
+This unfortunately means that older versions of Home Assistant are not supported by the Nuki Hub discovery implementation anymore.
## FAQ
@@ -815,7 +813,7 @@ This button is disabled by default, but can be enabled in the Home Assistant UI.
### When controlling two locks (or openers) connected to two ESPs, both devices react to the same command. When using Home Asistant, the same status is display for both locks.
When using multiple Nuki devices, different paths for each device have to be configured.
-Navigate to "Nuki Configuration" and change the "MQTT Nuki Smartlock Path" or "MQTT Nuki Opener Path" under "Basic Nuki Configuration" for at least one of the devices.
+Navigate to "MQTT Configuration" and change the "MQTT NukiHub Path" under "Basic MQTT Configuration" for at least one of the devices.
### The Nuki battery is draining quickly.
diff --git a/clion/CMakeLists.txt b/clion/CMakeLists.txt
index 741aea4..0d93523 100644
--- a/clion/CMakeLists.txt
+++ b/clion/CMakeLists.txt
@@ -49,6 +49,7 @@ set(SRCFILES
../src/util/NetworkUtil.cpp
../src/enums/NetworkDeviceType.h
../src/util/NetworkDeviceInstantiator.cpp
+ ../src/HomeAssistantDiscovery.cpp
../src/NukiOfficial.cpp
../src/NukiPublisher.cpp
../src/EspMillis.h
diff --git a/lib/nuki_ble b/lib/nuki_ble
index 19e82ce..edc9586 160000
--- a/lib/nuki_ble
+++ b/lib/nuki_ble
@@ -1 +1 @@
-Subproject commit 19e82cea9739cadeebfbfac46c189e7cfdad2896
+Subproject commit edc9586c6d9805e05d0f2513364105ded44911ae
diff --git a/src/Config.h b/src/Config.h
index fc4c53e..cf7ca8a 100644
--- a/src/Config.h
+++ b/src/Config.h
@@ -4,7 +4,7 @@
#define NUKI_HUB_VERSION "9.02"
#define NUKI_HUB_BUILD "unknownbuildnr"
-#define NUKI_HUB_DATE "2024-11-06"
+#define NUKI_HUB_DATE "2024-11-08"
#define GITHUB_LATEST_RELEASE_URL (char*)"https://github.com/technyon/nuki_hub/releases/latest"
#define GITHUB_OTA_MANIFEST_URL (char*)"https://raw.githubusercontent.com/technyon/nuki_hub/binary/ota/manifest.json"
@@ -22,6 +22,7 @@
#define GITHUB_BETA_UPDATER_BINARY_URL_DBG (char*)"https://raw.githubusercontent.com/technyon/nuki_hub/binary/ota/debug/beta/nuki_hub_updater_esp32c3.bin"
#define GITHUB_MASTER_RELEASE_BINARY_URL_DBG (char*)"https://raw.githubusercontent.com/technyon/nuki_hub/binary/ota/debug/master/nuki_hub_esp32c3.bin"
#define GITHUB_MASTER_UPDATER_BINARY_URL_DBG (char*)"https://raw.githubusercontent.com/technyon/nuki_hub/binary/ota/debug/master/nuki_hub_updater_esp32c3.bin"
+#define NUKI_HUB_HW (char*)"ESP32-C3"
#elif defined(CONFIG_IDF_TARGET_ESP32S3)
#if defined(CONFIG_SPIRAM_MODE_OCT)
#define GITHUB_LATEST_RELEASE_BINARY_URL (char*)"https://raw.githubusercontent.com/technyon/nuki_hub/binary/ota/nuki_hub_esp32s3oct.bin"
@@ -36,6 +37,7 @@
#define GITHUB_BETA_UPDATER_BINARY_URL_DBG (char*)"https://raw.githubusercontent.com/technyon/nuki_hub/binary/ota/debug/beta/nuki_hub_updater_esp32s3oct.bin"
#define GITHUB_MASTER_RELEASE_BINARY_URL_DBG (char*)"https://raw.githubusercontent.com/technyon/nuki_hub/binary/ota/debug/master/nuki_hub_esp32s3oct.bin"
#define GITHUB_MASTER_UPDATER_BINARY_URL_DBG (char*)"https://raw.githubusercontent.com/technyon/nuki_hub/binary/ota/debug/master/nuki_hub_updater_esp32s3oct.bin"
+#define NUKI_HUB_HW (char*)"ESP32-S3 (Octal PSRAM)"
#else
#define GITHUB_LATEST_RELEASE_BINARY_URL (char*)"https://raw.githubusercontent.com/technyon/nuki_hub/binary/ota/nuki_hub_esp32s3.bin"
#define GITHUB_LATEST_UPDATER_BINARY_URL (char*)"https://raw.githubusercontent.com/technyon/nuki_hub/binary/ota/nuki_hub_updater_esp32s3.bin"
@@ -49,6 +51,7 @@
#define GITHUB_BETA_UPDATER_BINARY_URL_DBG (char*)"https://raw.githubusercontent.com/technyon/nuki_hub/binary/ota/debug/beta/nuki_hub_updater_esp32s3.bin"
#define GITHUB_MASTER_RELEASE_BINARY_URL_DBG (char*)"https://raw.githubusercontent.com/technyon/nuki_hub/binary/ota/debug/master/nuki_hub_esp32s3.bin"
#define GITHUB_MASTER_UPDATER_BINARY_URL_DBG (char*)"https://raw.githubusercontent.com/technyon/nuki_hub/binary/ota/debug/master/nuki_hub_updater_esp32s3.bin"
+#define NUKI_HUB_HW (char*)"ESP32-S3"
#endif
#elif defined(CONFIG_IDF_TARGET_ESP32C6)
#define GITHUB_LATEST_RELEASE_BINARY_URL (char*)"https://raw.githubusercontent.com/technyon/nuki_hub/binary/ota/nuki_hub_esp32c6.bin"
@@ -63,6 +66,7 @@
#define GITHUB_BETA_UPDATER_BINARY_URL_DBG (char*)"https://raw.githubusercontent.com/technyon/nuki_hub/binary/ota/debug/beta/nuki_hub_updater_esp32c6.bin"
#define GITHUB_MASTER_RELEASE_BINARY_URL_DBG (char*)"https://raw.githubusercontent.com/technyon/nuki_hub/binary/ota/debug/master/nuki_hub_esp32c6.bin"
#define GITHUB_MASTER_UPDATER_BINARY_URL_DBG (char*)"https://raw.githubusercontent.com/technyon/nuki_hub/binary/ota/debug/master/nuki_hub_updater_esp32c6.bin"
+#define NUKI_HUB_HW (char*)"ESP32-C6"
#elif defined(CONFIG_IDF_TARGET_ESP32H2)
#define GITHUB_LATEST_RELEASE_BINARY_URL (char*)"https://raw.githubusercontent.com/technyon/nuki_hub/binary/ota/nuki_hub_esp32h2.bin"
#define GITHUB_LATEST_UPDATER_BINARY_URL (char*)"https://raw.githubusercontent.com/technyon/nuki_hub/binary/ota/nuki_hub_updater_esp32h2.bin"
@@ -76,6 +80,7 @@
#define GITHUB_BETA_UPDATER_BINARY_URL_DBG (char*)"https://raw.githubusercontent.com/technyon/nuki_hub/binary/ota/debug/beta/nuki_hub_updater_esp32h2.bin"
#define GITHUB_MASTER_RELEASE_BINARY_URL_DBG (char*)"https://raw.githubusercontent.com/technyon/nuki_hub/binary/ota/debug/master/nuki_hub_esp32h2.bin"
#define GITHUB_MASTER_UPDATER_BINARY_URL_DBG (char*)"https://raw.githubusercontent.com/technyon/nuki_hub/binary/ota/debug/master/nuki_hub_updater_esp32h2.bin"
+#define NUKI_HUB_HW (char*)"ESP32-H2"
#else
#if defined(CONFIG_FREERTOS_UNICORE)
#define GITHUB_LATEST_RELEASE_BINARY_URL "https://raw.githubusercontent.com/technyon/nuki_hub/binary/ota/nuki_hub_esp32-solo1.bin"
@@ -90,6 +95,7 @@
#define GITHUB_BETA_UPDATER_BINARY_URL_DBG (char*)"https://raw.githubusercontent.com/technyon/nuki_hub/binary/ota/debug/beta/nuki_hub_updater_esp32-solo1.bin"
#define GITHUB_MASTER_RELEASE_BINARY_URL_DBG (char*)"https://raw.githubusercontent.com/technyon/nuki_hub/binary/ota/debug/master/nuki_hub_esp32-solo1.bin"
#define GITHUB_MASTER_UPDATER_BINARY_URL_DBG (char*)"https://raw.githubusercontent.com/technyon/nuki_hub/binary/ota/debug/master/nuki_hub_updater_esp32-solo1.bin"
+#define NUKI_HUB_HW (char*)"ESP32-SOLO1"
#else
#define GITHUB_LATEST_RELEASE_BINARY_URL "https://raw.githubusercontent.com/technyon/nuki_hub/binary/ota/nuki_hub_esp32.bin"
#define GITHUB_LATEST_UPDATER_BINARY_URL (char*)"https://raw.githubusercontent.com/technyon/nuki_hub/binary/ota/nuki_hub_updater_esp32.bin"
@@ -103,6 +109,7 @@
#define GITHUB_BETA_UPDATER_BINARY_URL_DBG (char*)"https://raw.githubusercontent.com/technyon/nuki_hub/binary/ota/debug/beta/nuki_hub_updater_esp32.bin"
#define GITHUB_MASTER_RELEASE_BINARY_URL_DBG (char*)"https://raw.githubusercontent.com/technyon/nuki_hub/binary/ota/debug/master/nuki_hub_esp32.bin"
#define GITHUB_MASTER_UPDATER_BINARY_URL_DBG (char*)"https://raw.githubusercontent.com/technyon/nuki_hub/binary/ota/debug/master/nuki_hub_updater_esp32.bin"
+#define NUKI_HUB_HW (char*)"ESP32"
#endif
#endif
diff --git a/src/HomeAssistantDiscovery.cpp b/src/HomeAssistantDiscovery.cpp
new file mode 100644
index 0000000..70fc1f5
--- /dev/null
+++ b/src/HomeAssistantDiscovery.cpp
@@ -0,0 +1,3069 @@
+#include "HomeAssistantDiscovery.h"
+#include "Config.h"
+#include "Logger.h"
+#include "PreferencesKeys.h"
+#include "MqttTopics.h"
+
+HomeAssistantDiscovery::HomeAssistantDiscovery(NetworkDevice* device, Preferences *preferences, char* buffer, size_t bufferSize)
+: _device(device),
+ _preferences(preferences),
+ _buffer(buffer),
+ _bufferSize(bufferSize)
+{
+ _discoveryTopic = _preferences->getString(preference_mqtt_hass_discovery, "");
+ _baseTopic = _preferences->getString(preference_mqtt_lock_path);
+ _offEnabled = _preferences->getBool(preference_official_hybrid_enabled, false);
+ _checkUpdates = _preferences->getBool(preference_check_updates, false);
+ _updateFromMQTT = _preferences->getBool(preference_update_from_mqtt, false);
+ _hostname = _preferences->getString(preference_hostname, "");
+ sprintf(_nukiHubUidString, "%u", _preferences->getUInt(preference_device_id_lock, 0));
+}
+
+void HomeAssistantDiscovery::setupHASS(int type, uint32_t nukiId, char* nukiName, const char* firmwareVersion, const char* hardwareVersion, bool hasDoorSensor, bool hasKeypad)
+{
+ char uidString[20];
+ itoa(nukiId, uidString, 16);
+ bool publishAuthData = _preferences->getBool(preference_publish_authdata, false);
+
+ if(type == 0)
+ {
+ publishHASSNukiHubConfig();
+ Log->println("HASS setup for NukiHub completed.");
+ }
+ else if(type == 1)
+ {
+ if(_preferences->getUInt(preference_nuki_id_lock, 0) != nukiId)
+ {
+ return;
+ }
+ String lockTopic = _baseTopic;
+ lockTopic.concat("/lock");
+ publishHASSConfig((char*)"SmartLock", lockTopic.c_str(), nukiName, uidString, firmwareVersion, hardwareVersion, hasDoorSensor, hasKeypad, publishAuthData, (char*)"lock", (char*)"unlock", (char*)"unlatch");
+ Log->println("HASS setup for lock completed.");
+ }
+ else if(type == 2)
+ {
+ if(_preferences->getUInt(preference_nuki_id_opener, 0) != nukiId)
+ {
+ return;
+ }
+ String openerTopic = _baseTopic;
+ openerTopic.concat("/opener");
+ if(_preferences->getBool(preference_opener_continuous_mode, false))
+ {
+ publishHASSConfig((char*)"Opener", openerTopic.c_str(), nukiName, uidString, firmwareVersion, hardwareVersion, hasDoorSensor, hasKeypad, publishAuthData, (char*)"deactivateCM", (char*)"activateCM", (char*)"electricStrikeActuation");
+ }
+ else
+ {
+ publishHASSConfig((char*)"Opener", openerTopic.c_str(), nukiName, uidString, firmwareVersion, hardwareVersion, hasDoorSensor, hasKeypad, publishAuthData, (char*)"deactivateRTO", (char*)"activateRTO", (char*)"electricStrikeActuation");
+ }
+
+ Log->println("HASS setup for opener completed.");
+ }
+}
+
+void HomeAssistantDiscovery::disableHASS()
+{
+ removeHASSConfig(_nukiHubUidString);
+
+ char uidString[20];
+
+ if(_preferences->getUInt(preference_nuki_id_lock, 0) != 0)
+ {
+ itoa(_preferences->getUInt(preference_nuki_id_lock, 0), uidString, 16);
+ removeHASSConfig(uidString);
+ }
+ if(_preferences->getUInt(preference_nuki_id_opener, 0) != 0)
+ {
+ itoa(_preferences->getUInt(preference_nuki_id_opener, 0), uidString, 16);
+ removeHASSConfig(uidString);
+ }
+}
+
+void HomeAssistantDiscovery::publishHASSNukiHubConfig()
+{
+ JsonDocument json;
+ json.clear();
+ JsonObject dev = json["dev"].to();
+ JsonArray ids = dev["ids"].to();
+ ids.add(String("nuki_") + _nukiHubUidString);
+ json["dev"]["mf"] = "Technyon";
+ json["dev"]["mdl"] = "NukiHub";
+ json["dev"]["name"] = _hostname.c_str();
+ json["dev"]["sw"] = NUKI_HUB_VERSION;
+ json["dev"]["hw"] = NUKI_HUB_HW;
+
+ String cuUrl = _preferences->getString(preference_mqtt_hass_cu_url, "");
+
+ if (cuUrl != "")
+ {
+ json["dev"]["cu"] = cuUrl;
+ }
+ else
+ {
+ json["dev"]["cu"] = "http://" + _device->localIP();
+ }
+
+ json["~"] = _baseTopic;
+ json["name"] = "Restart Nuki Hub";
+ json["unique_id"] = String(_nukiHubUidString) + "_reset";
+ json["avty"][0]["t"] = String("~") + mqtt_topic_mqtt_connection_state;
+ json["opt"] = "false";
+ json["stat_t"] = String("~") + mqtt_topic_reset;
+ json["ent_cat"] = "diagnostic";
+ json["cmd_t"] = String("~") + mqtt_topic_reset;
+ json["ic"] = "mdi:restart";
+ json["pl_on"] = "1";
+ json["pl_off"] = "0";
+ json["stat_on"] = "1";
+ json["stat_off"] = "0";
+
+ serializeJson(json, _buffer, _bufferSize);
+
+ String path = _preferences->getString(preference_mqtt_hass_discovery, "homeassistant");
+ path.concat("/switch/");
+ path.concat(_nukiHubUidString);
+ path.concat("/reset/config");
+
+ _device->mqttPublish(path.c_str(), MQTT_QOS_LEVEL, true, _buffer);
+
+#ifndef CONFIG_IDF_TARGET_ESP32H2
+ publishHassTopic("sensor",
+ "wifi_signal_strength",
+ _nukiHubUidString,
+ "_wifi_signal_strength",
+ "WIFI signal strength",
+ _hostname.c_str(),
+ _baseTopic.c_str(),
+ String("~") + mqtt_topic_wifi_rssi,
+ "NukiHub",
+ "signal_strength",
+ "measurement",
+ "diagnostic",
+ "",
+ { {(char*)"unit_of_meas", (char*)"dBm"} });
+#endif
+
+ // MQTT Connected
+ publishHassTopic("binary_sensor",
+ "mqtt_connected",
+ _nukiHubUidString,
+ "_mqtt_connected",
+ "MQTT connected",
+ _hostname.c_str(),
+ _baseTopic.c_str(),
+ String("~") + mqtt_topic_mqtt_connection_state,
+ "NukiHub",
+ "",
+ "",
+ "diagnostic",
+ "",
+ {
+ {(char*)"pl_on", (char*)"online"},
+ {(char*)"pl_off", (char*)"offline"},
+ {(char*)"ic", (char*)"mdi:lan-connect"}
+ });
+
+ // Network device
+ publishHassTopic("sensor",
+ "network_device",
+ _nukiHubUidString,
+ "_network_device",
+ "Network device",
+ _hostname.c_str(),
+ _baseTopic.c_str(),
+ String("~") + mqtt_topic_network_device,
+ "NukiHub",
+ "",
+ "",
+ "diagnostic",
+ "",
+ { { (char*)"en", (char*)"true" }});
+
+ // Nuki Hub Webserver enabled
+ publishHassTopic("switch",
+ "webserver",
+ _nukiHubUidString,
+ "_webserver",
+ "Nuki Hub webserver enabled",
+ _hostname.c_str(),
+ _baseTopic.c_str(),
+ String("~") + mqtt_topic_webserver_state,
+ "NukiHub",
+ "",
+ "",
+ "diagnostic",
+ String("~") + mqtt_topic_webserver_action,
+ {
+ { (char*)"pl_on", (char*)"1" },
+ { (char*)"pl_off", (char*)"0" },
+ { (char*)"stat_on", (char*)"1" },
+ { (char*)"stat_off", (char*)"0" }
+ });
+
+ // Uptime
+ publishHassTopic("sensor",
+ "uptime",
+ _nukiHubUidString,
+ "_uptime",
+ "Uptime",
+ _hostname.c_str(),
+ _baseTopic.c_str(),
+ String("~") + mqtt_topic_uptime,
+ "NukiHub",
+ "duration",
+ "",
+ "diagnostic",
+ "",
+ {
+ { (char*)"en", (char*)"true" },
+ { (char*)"unit_of_meas", (char*)"min"}
+ });
+
+ if(_preferences->getBool(preference_mqtt_log_enabled, false))
+ {
+ // MQTT Log
+ publishHassTopic("sensor",
+ "mqtt_log",
+ _nukiHubUidString,
+ "_mqtt_log",
+ "MQTT Log",
+ _hostname.c_str(),
+ _baseTopic.c_str(),
+ String("~") + mqtt_topic_log,
+ "NukiHub",
+ "",
+ "",
+ "diagnostic",
+ "",
+ { { (char*)"en", (char*)"true" }});
+ }
+ else
+ {
+ removeHassTopic((char*)"sensor", (char*)"mqtt_log", _nukiHubUidString);
+ }
+
+ // Nuki Hub version
+ publishHassTopic("sensor",
+ "nuki_hub_version",
+ _nukiHubUidString,
+ "_nuki_hub_version",
+ "Nuki Hub version",
+ _hostname.c_str(),
+ _baseTopic.c_str(),
+ String("~") + mqtt_topic_info_nuki_hub_version,
+ "NukiHub",
+ "",
+ "",
+ "diagnostic",
+ "",
+ {
+ { (char*)"en", (char*)"true" },
+ {(char*)"ic", (char*)"mdi:counter"}
+ });
+
+ // Nuki Hub build
+ publishHassTopic("sensor",
+ "nuki_hub_build",
+ _nukiHubUidString,
+ "_nuki_hub_build",
+ "Nuki Hub build",
+ _hostname.c_str(),
+ _baseTopic.c_str(),
+ String("~") + mqtt_topic_info_nuki_hub_build,
+ "NukiHub",
+ "",
+ "",
+ "diagnostic",
+ "",
+ {
+ { (char*)"en", (char*)"true" },
+ {(char*)"ic", (char*)"mdi:counter"}
+ });
+
+ // Nuki Hub restart reason
+ publishHassTopic("sensor",
+ "nuki_hub_restart_reason",
+ _nukiHubUidString,
+ "_nuki_hub_restart_reason",
+ "Nuki Hub restart reason",
+ _hostname.c_str(),
+ _baseTopic.c_str(),
+ String("~") + mqtt_topic_restart_reason_fw,
+ "NukiHub",
+ "",
+ "",
+ "diagnostic",
+ "",
+ { { (char*)"en", (char*)"true" }});
+
+ // Nuki Hub restart reason ESP
+ publishHassTopic("sensor",
+ "nuki_hub_restart_reason_esp",
+ _nukiHubUidString,
+ "_nuki_hub_restart_reason_esp",
+ "Nuki Hub restart reason ESP",
+ _hostname.c_str(),
+ _baseTopic.c_str(),
+ String("~") + mqtt_topic_restart_reason_esp,
+ "NukiHub",
+ "",
+ "",
+ "diagnostic",
+ "",
+ { { (char*)"en", (char*)"true" }});
+
+ if(_checkUpdates)
+ {
+ // NUKI Hub latest
+ publishHassTopic("sensor",
+ "nuki_hub_latest",
+ _nukiHubUidString,
+ "_nuki_hub_latest",
+ "NUKI Hub latest",
+ _hostname.c_str(),
+ _baseTopic.c_str(),
+ String("~") + mqtt_topic_info_nuki_hub_latest,
+ "NukiHub",
+ "",
+ "",
+ "diagnostic",
+ "",
+ {
+ { (char*)"en", (char*)"true" },
+ {(char*)"ic", (char*)"mdi:counter"}
+ });
+
+ // NUKI Hub update
+ char latest_version_topic[250];
+ _baseTopic.toCharArray(latest_version_topic,_baseTopic.length() + 1);
+ strcat(latest_version_topic, mqtt_topic_info_nuki_hub_latest);
+
+ if(!_updateFromMQTT)
+ {
+ publishHassTopic("update",
+ "nuki_hub_update",
+ _nukiHubUidString,
+ "_nuki_hub_update",
+ "NUKI Hub firmware update",
+ _hostname.c_str(),
+ _baseTopic.c_str(),
+ String("~") + mqtt_topic_info_nuki_hub_version,
+ "NukiHub",
+ "firmware",
+ "",
+ "diagnostic",
+ "",
+ {
+ { (char*)"en", (char*)"true" },
+ { (char*)"ent_pic", (char*)"https://raw.githubusercontent.com/technyon/nuki_hub/master/icon/favicon-32x32.png" },
+ { (char*)"rel_u", (char*)GITHUB_LATEST_RELEASE_URL },
+ { (char*)"l_ver_t", (char*)latest_version_topic }
+ });
+ }
+ else
+ {
+ publishHassTopic("update",
+ "nuki_hub_update",
+ _nukiHubUidString,
+ "_nuki_hub_update",
+ "NUKI Hub firmware update",
+ _hostname.c_str(),
+ _baseTopic.c_str(),
+ String("~") + mqtt_topic_info_nuki_hub_version,
+ "NukiHub",
+ "firmware",
+ "",
+ "diagnostic",
+ String("~") + mqtt_topic_update,
+ {
+ { (char*)"en", (char*)"true" },
+ { (char*)"pl_inst", (char*)"1" },
+ { (char*)"ent_pic", (char*)"https://raw.githubusercontent.com/technyon/nuki_hub/master/icon/favicon-32x32.png" },
+ { (char*)"rel_u", (char*)GITHUB_LATEST_RELEASE_URL },
+ { (char*)"l_ver_t", (char*)latest_version_topic }
+ });
+ }
+ }
+ else
+ {
+ removeHassTopic((char*)"sensor", (char*)"nuki_hub_latest", _nukiHubUidString);
+ removeHassTopic((char*)"update", (char*)"nuki_hub_update", _nukiHubUidString);
+ }
+
+ // Nuki Hub IP Address
+ publishHassTopic("sensor",
+ "nuki_hub_ip",
+ _nukiHubUidString,
+ "_nuki_hub_ip",
+ "Nuki Hub IP",
+ _hostname.c_str(),
+ _baseTopic.c_str(),
+ String("~") + mqtt_topic_info_nuki_hub_ip,
+ "NukiHub",
+ "",
+ "",
+ "diagnostic",
+ "",
+ {
+ { (char*)"en", (char*)"true" },
+ {(char*)"ic", (char*)"mdi:ip"}
+ });
+}
+
+void HomeAssistantDiscovery::publishHASSConfig(char *deviceType, const char *baseTopic, char *name, char *uidString, const char *softwareVersion, const char *hardwareVersion, const bool& hasDoorSensor, const bool& hasKeypad, const bool& publishAuthData, char *lockAction, char *unlockAction, char *openAction)
+{
+ String availabilityTopic = _baseTopic;
+ availabilityTopic.concat(mqtt_topic_mqtt_connection_state);
+
+ publishHASSDeviceConfig(deviceType, baseTopic, name, uidString, softwareVersion, hardwareVersion, availabilityTopic.c_str(), hasKeypad, lockAction, unlockAction, openAction);
+
+ if(strcmp(deviceType, "SmartLock") == 0)
+ {
+ publishHASSConfigAdditionalLockEntities(deviceType, baseTopic, name, uidString);
+ }
+ else
+ {
+ publishHASSConfigAdditionalOpenerEntities(deviceType, baseTopic, name, uidString);
+ }
+ if(hasDoorSensor)
+ {
+ publishHASSConfigDoorSensor(deviceType, baseTopic, name, uidString);
+ }
+ else
+ {
+ removeHASSConfigTopic((char*)"binary_sensor", (char*)"door_sensor", uidString);
+ }
+ if(publishAuthData)
+ {
+ publishHASSConfigAccessLog(deviceType, baseTopic, name, uidString);
+ }
+ else
+ {
+ removeHASSConfigTopic((char*)"sensor", (char*)"last_action_authorization", uidString);
+ removeHASSConfigTopic((char*)"sensor", (char*)"rolling_log", uidString);
+ }
+ if(hasKeypad)
+ {
+ publishHASSConfigKeypad(deviceType, baseTopic, name, uidString);
+ }
+ else
+ {
+ removeHASSConfigTopic((char*)"sensor", (char*)"keypad_status", uidString);
+ removeHASSConfigTopic((char*)"binary_sensor", (char*)"keypad_battery_low", uidString);
+ }
+}
+
+void HomeAssistantDiscovery::publishHASSDeviceConfig(char* deviceType, const char* baseTopic, char* name, char* uidString, const char *softwareVersion, const char *hardwareVersion, const char* availabilityTopic, const bool& hasKeypad, char* lockAction, char* unlockAction, char* openAction)
+{
+ JsonDocument json;
+ json.clear();
+ JsonObject dev = json["dev"].to();
+ JsonArray ids = dev["ids"].to();
+ ids.add(String("nuki_") + uidString);
+ json["dev"]["mf"] = "Nuki";
+ json["dev"]["mdl"] = deviceType;
+ json["dev"]["name"] = name;
+ json["dev"]["sw"] = softwareVersion;
+ json["dev"]["hw"] = hardwareVersion;
+ json["dev"]["via_device"] = String("nuki_") + _nukiHubUidString;
+
+ String cuUrl = _preferences->getString(preference_mqtt_hass_cu_url, "");
+
+ if (cuUrl != "")
+ {
+ json["dev"]["cu"] = cuUrl;
+ }
+ else
+ {
+ json["dev"]["cu"] = "http://" + _device->localIP();
+ }
+
+ json["~"] = baseTopic;
+ json["name"] = nullptr;
+ json["unique_id"] = String(uidString) + "_lock";
+ json["cmd_t"] = String("~") + String(mqtt_topic_lock_action);
+ json["avty"][0]["t"] = availabilityTopic;
+ json["pl_lock"] = lockAction;
+ json["pl_unlk"] = unlockAction;
+
+ uint32_t aclPrefs[17];
+ _preferences->getBytes(preference_acl, &aclPrefs, sizeof(aclPrefs));
+
+ if((strcmp(deviceType, "SmartLock") == 0 && (int)aclPrefs[2]) || (strcmp(deviceType, "SmartLock") != 0 && (int)aclPrefs[11]))
+ {
+ json["pl_open"] = openAction;
+ }
+
+ json["stat_t"] = String("~") + mqtt_topic_lock_ha_state;
+ json["stat_jam"] = "jammed";
+ json["stat_locked"] = "locked";
+ json["stat_locking"] = "locking";
+ json["stat_unlocked"] = "unlocked";
+ json["stat_unlocking"] = "unlocking";
+ json["stat_open"] = "open";
+ json["stat_opening"] = "opening";
+ json["opt"] = "false";
+
+ serializeJson(json, _buffer, _bufferSize);
+
+ String path = _preferences->getString(preference_mqtt_hass_discovery, "homeassistant");
+ path.concat("/lock/");
+ path.concat(uidString);
+ path.concat("/smartlock/config");
+
+ _device->mqttPublish(path.c_str(), MQTT_QOS_LEVEL, true, _buffer);
+
+
+ // Firmware version
+ publishHassTopic("sensor",
+ "firmware_version",
+ uidString,
+ "_firmware_version",
+ "Firmware version",
+ name,
+ baseTopic,
+ String("~") + mqtt_topic_info_firmware_version,
+ deviceType,
+ "",
+ "",
+ "diagnostic",
+ "",
+ {
+ { (char*)"en", (char*)"true" },
+ {(char*)"ic", (char*)"mdi:counter"}
+ });
+
+ // Hardware version
+ publishHassTopic("sensor",
+ "hardware_version",
+ uidString,
+ "_hardware_version",
+ "Hardware version",
+ name,
+ baseTopic,
+ String("~") + mqtt_topic_info_hardware_version,
+ deviceType,
+ "",
+ "",
+ "diagnostic",
+ "",
+ {
+ { (char*)"en", (char*)"true" },
+ {(char*)"ic", (char*)"mdi:counter"}
+ });
+
+ // Battery critical
+ publishHassTopic("binary_sensor",
+ "battery_low",
+ uidString,
+ "_battery_low",
+ "Battery low",
+ name,
+ baseTopic,
+ String("~") + mqtt_topic_battery_basic_json,
+ deviceType,
+ "battery",
+ "",
+ "diagnostic",
+ "",
+ {
+ {(char*)"pl_on", (char*)"1"},
+ {(char*)"pl_off", (char*)"0"},
+ {(char*)"val_tpl", (char*)"{{value_json.critical}}" }
+ });
+
+ // Battery voltage
+ publishHassTopic("sensor",
+ "battery_voltage",
+ uidString,
+ "_battery_voltage",
+ "Battery voltage",
+ name,
+ baseTopic,
+ String("~") + mqtt_topic_battery_advanced_json,
+ deviceType,
+ "voltage",
+ "measurement",
+ "diagnostic",
+ "",
+ {
+ {(char*)"unit_of_meas", (char*)"V"},
+ {(char*)"val_tpl", (char*)"{{value_json.batteryVoltage}}" }
+ });
+
+ // Trigger
+ publishHassTopic("sensor",
+ "trigger",
+ uidString,
+ "_trigger",
+ "Trigger",
+ name,
+ baseTopic,
+ String("~") + mqtt_topic_lock_trigger,
+ deviceType,
+ "",
+ "",
+ "diagnostic",
+ "",
+ { { (char*)"en", (char*)"true" } });
+
+ if(_offEnabled)
+ {
+ // Hybrid connected
+ String hybridPath = _baseTopic;
+ hybridPath.concat("/lock");
+ hybridPath.concat(mqtt_topic_hybrid_state);
+ publishHassTopic("binary_sensor",
+ "hybrid_connected",
+ uidString,
+ "_hybrid_connected",
+ "Hybrid connected",
+ name,
+ baseTopic,
+ hybridPath,
+ deviceType,
+ "",
+ "",
+ "diagnostic",
+ "",
+ {
+ {(char*)"pl_on", (char*)"1"},
+ {(char*)"pl_off", (char*)"0"},
+ { (char*)"en", (char*)"true" }
+ });
+ }
+ else
+ {
+ removeHassTopic((char*)"binary_sensor", (char*)"hybrid_connected", uidString);
+ }
+
+ // Query Lock State
+ publishHassTopic("button",
+ "query_lockstate",
+ uidString,
+ "_query_lockstate",
+ "Query lock state",
+ name,
+ baseTopic,
+ "",
+ deviceType,
+ "",
+ "",
+ "diagnostic",
+ String("~") + mqtt_topic_query_lockstate,
+ {
+ { (char*)"en", (char*)"false" },
+ { (char*)"pl_prs", (char*)"1" }
+ });
+
+ // Query Config
+ publishHassTopic("button",
+ "query_config",
+ uidString,
+ "_query_config",
+ "Query config",
+ name,
+ baseTopic,
+ "",
+ deviceType,
+ "",
+ "",
+ "diagnostic",
+ String("~") + mqtt_topic_query_config,
+ {
+ { (char*)"en", (char*)"false" },
+ { (char*)"pl_prs", (char*)"1" }
+ });
+
+ // Query Lock State Command result
+ publishHassTopic("button",
+ "query_commandresult",
+ uidString,
+ "_query_commandresult",
+ "Query lock state command result",
+ name,
+ baseTopic,
+ "",
+ deviceType,
+ "",
+ "",
+ "diagnostic",
+ String("~") + mqtt_topic_query_lockstate_command_result,
+ {
+ { (char*)"en", (char*)"false" },
+ { (char*)"pl_prs", (char*)"1" }
+ });
+
+ publishHassTopic("sensor",
+ "bluetooth_signal_strength",
+ uidString,
+ "_bluetooth_signal_strength",
+ "Bluetooth signal strength",
+ name,
+ baseTopic,
+ String("~") + mqtt_topic_lock_rssi,
+ deviceType,
+ "signal_strength",
+ "measurement",
+ "diagnostic",
+ "",
+ { {(char*)"unit_of_meas", (char*)"dBm"} });
+}
+
+void HomeAssistantDiscovery::publishHASSConfigAdditionalLockEntities(char *deviceType, const char *baseTopic, char *name, char *uidString)
+{
+ uint32_t aclPrefs[17];
+ _preferences->getBytes(preference_acl, &aclPrefs, sizeof(aclPrefs));
+
+ uint32_t basicLockConfigAclPrefs[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+ uint32_t advancedLockConfigAclPrefs[22] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+ if(_preferences->getBool(preference_conf_info_enabled, true))
+ {
+ _preferences->getBytes(preference_conf_lock_basic_acl, &basicLockConfigAclPrefs, sizeof(basicLockConfigAclPrefs));
+ _preferences->getBytes(preference_conf_lock_advanced_acl, &advancedLockConfigAclPrefs, sizeof(advancedLockConfigAclPrefs));
+ }
+
+ if((int)aclPrefs[2])
+ {
+ // Unlatch
+ publishHassTopic("button",
+ "unlatch",
+ uidString,
+ "_unlatch",
+ "Open",
+ name,
+ baseTopic,
+ "",
+ deviceType,
+ "",
+ "",
+ "",
+ String("~") + mqtt_topic_lock_action,
+ {
+ { (char*)"en", (char*)"false" },
+ { (char*)"pl_prs", (char*)"unlatch" }
+ });
+ }
+ else
+ {
+ removeHassTopic((char*)"button", (char*)"unlatch", uidString);
+ }
+
+ if((int)aclPrefs[3])
+ {
+ // Lock 'n' Go
+ publishHassTopic("button",
+ "lockngo",
+ uidString,
+ "_lockngo",
+ "Lock 'n' Go",
+ name,
+ baseTopic,
+ "",
+ deviceType,
+ "",
+ "",
+ "",
+ String("~") + mqtt_topic_lock_action,
+ {
+ { (char*)"en", (char*)"false" },
+ { (char*)"pl_prs", (char*)"lockNgo" }
+ });
+ }
+ else
+ {
+ removeHassTopic((char*)"button", (char*)"lockngo", uidString);
+ }
+
+ if((int)aclPrefs[4])
+ {
+ // Lock 'n' Go with unlatch
+ publishHassTopic("button",
+ "lockngounlatch",
+ uidString,
+ "_lockngounlatch",
+ "Lock 'n' Go with unlatch",
+ name,
+ baseTopic,
+ "",
+ deviceType,
+ "",
+ "",
+ "",
+ String("~") + mqtt_topic_lock_action,
+ {
+ { (char*)"en", (char*)"false" },
+ { (char*)"pl_prs", (char*)"lockNgoUnlatch" }
+ });
+ }
+ else
+ {
+ removeHassTopic((char*)"button", (char*)"lockngounlatch", uidString);
+ }
+
+ // Query Battery
+ publishHassTopic("button",
+ "query_battery",
+ uidString,
+ "_query_battery",
+ "Query battery",
+ name,
+ baseTopic,
+ "",
+ deviceType,
+ "",
+ "",
+ "diagnostic",
+ String("~") + mqtt_topic_query_battery,
+ {
+ { (char*)"en", (char*)"false" },
+ { (char*)"pl_prs", (char*)"1" }
+ });
+
+ if((int)basicLockConfigAclPrefs[6] == 1)
+ {
+ // LED enabled
+ publishHassTopic("switch",
+ "led_enabled",
+ uidString,
+ "_led_enabled",
+ "LED enabled",
+ name,
+ baseTopic,
+ String("~") + mqtt_topic_config_basic_json,
+ deviceType,
+ "",
+ "",
+ "config",
+ String("~") + mqtt_topic_config_action,
+ {
+ { (char*)"en", (char*)"true" },
+ { (char*)"ic", (char*)"mdi:led-variant-on" },
+ { (char*)"pl_on", (char*)"{ \"ledEnabled\": \"1\"}" },
+ { (char*)"pl_off", (char*)"{ \"ledEnabled\": \"0\"}" },
+ { (char*)"val_tpl", (char*)"{{value_json.ledEnabled}}" },
+ { (char*)"stat_on", (char*)"1" },
+ { (char*)"stat_off", (char*)"0" }
+ });
+ }
+ else
+ {
+ removeHassTopic((char*)"switch", (char*)"led_enabled", uidString);
+ }
+
+ if((int)basicLockConfigAclPrefs[5] == 1)
+ {
+ // Button enabled
+ publishHassTopic("switch",
+ "button_enabled",
+ uidString,
+ "_button_enabled",
+ "Button enabled",
+ name,
+ baseTopic,
+ String("~") + mqtt_topic_config_basic_json,
+ deviceType,
+ "",
+ "",
+ "config",
+ String("~") + mqtt_topic_config_action,
+ {
+ { (char*)"en", (char*)"true" },
+ { (char*)"ic", (char*)"mdi:radiobox-marked" },
+ { (char*)"pl_on", (char*)"{ \"buttonEnabled\": \"1\"}" },
+ { (char*)"pl_off", (char*)"{ \"buttonEnabled\": \"0\"}" },
+ { (char*)"val_tpl", (char*)"{{value_json.buttonEnabled}}" },
+ { (char*)"stat_on", (char*)"1" },
+ { (char*)"stat_off", (char*)"0" }
+ });
+ }
+ else
+ {
+ removeHassTopic((char*)"switch", (char*)"button_enabled", uidString);
+ }
+
+ if((int)advancedLockConfigAclPrefs[19] == 1)
+ {
+ // Auto Lock
+ publishHassTopic("switch",
+ "auto_lock",
+ uidString,
+ "_auto_lock",
+ "Auto lock",
+ name,
+ baseTopic,
+ String("~") + mqtt_topic_config_advanced_json,
+ deviceType,
+ "",
+ "",
+ "config",
+ String("~") + mqtt_topic_config_action,
+ {
+ { (char*)"en", (char*)"true" },
+ { (char*)"pl_on", (char*)"{ \"autoLockEnabled\": \"1\"}" },
+ { (char*)"pl_off", (char*)"{ \"autoLockEnabled\": \"0\"}" },
+ { (char*)"val_tpl", (char*)"{{value_json.autoLockEnabled}}" },
+ { (char*)"stat_on", (char*)"1" },
+ { (char*)"stat_off", (char*)"0" }
+ });
+ }
+ else
+ {
+ removeHassTopic((char*)"switch", (char*)"auto_lock", uidString);
+ }
+
+ if((int)advancedLockConfigAclPrefs[12] == 1)
+ {
+ // Auto Unlock
+ publishHassTopic("switch",
+ "auto_unlock",
+ uidString,
+ "_auto_unlock",
+ "Auto unlock",
+ name,
+ baseTopic,
+ String("~") + mqtt_topic_config_advanced_json,
+ deviceType,
+ "",
+ "",
+ "config",
+ String("~") + mqtt_topic_config_action,
+ {
+ { (char*)"en", (char*)"true" },
+ { (char*)"pl_on", (char*)"{ \"autoUnLockDisabled\": \"0\"}" },
+ { (char*)"pl_off", (char*)"{ \"autoUnLockDisabled\": \"1\"}" },
+ { (char*)"val_tpl", (char*)"{{value_json.autoUnLockDisabled}}" },
+ { (char*)"stat_on", (char*)"0" },
+ { (char*)"stat_off", (char*)"1" }
+ });
+ }
+ else
+ {
+ removeHassTopic((char*)"switch", (char*)"auto_unlock", uidString);
+ }
+
+ if((int)basicLockConfigAclPrefs[13] == 1)
+ {
+ // Double lock
+ publishHassTopic("switch",
+ "double_lock",
+ uidString,
+ "_double_lock",
+ "Double lock",
+ name,
+ baseTopic,
+ String("~") + mqtt_topic_config_basic_json,
+ deviceType,
+ "",
+ "",
+ "config",
+ String("~") + mqtt_topic_config_action,
+ {
+ { (char*)"en", (char*)"true" },
+ { (char*)"pl_on", (char*)"{ \"singleLock\": \"0\"}" },
+ { (char*)"pl_off", (char*)"{ \"singleLock\": \"1\"}" },
+ { (char*)"val_tpl", (char*)"{{value_json.singleLock}}" },
+ { (char*)"stat_on", (char*)"0" },
+ { (char*)"stat_off", (char*)"1" }
+ });
+ }
+ else
+ {
+ removeHassTopic((char*)"switch", (char*)"double_lock", uidString);
+ }
+
+ publishHassTopic("sensor",
+ "battery_level",
+ uidString,
+ "_battery_level",
+ "Battery level",
+ name,
+ baseTopic,
+ String("~") + mqtt_topic_battery_basic_json,
+ deviceType,
+ "battery",
+ "measurement",
+ "diagnostic",
+ "",
+ {
+ {(char*)"unit_of_meas", (char*)"%"},
+ {(char*)"val_tpl", (char*)"{{value_json.level}}" }
+ });
+
+ if((int)basicLockConfigAclPrefs[7] == 1)
+ {
+ publishHassTopic("number",
+ "led_brightness",
+ uidString,
+ "_led_brightness",
+ "LED brightness",
+ name,
+ baseTopic,
+ String("~") + mqtt_topic_config_basic_json,
+ deviceType,
+ "",
+ "",
+ "config",
+ String("~") + mqtt_topic_config_action,
+ {
+ { (char*)"en", (char*)"true" },
+ { (char*)"ic", (char*)"mdi:brightness-6" },
+ { (char*)"cmd_tpl", (char*)"{ \"ledBrightness\": \"{{ value }}\" }" },
+ { (char*)"val_tpl", (char*)"{{value_json.ledBrightness}}" },
+ { (char*)"min", (char*)"0" },
+ { (char*)"max", (char*)"5" }
+ });
+ }
+ else
+ {
+ removeHassTopic((char*)"number", (char*)"led_brightness", uidString);
+ }
+
+ if((int)basicLockConfigAclPrefs[3] == 1)
+ {
+ // Auto Unlatch
+ publishHassTopic("switch",
+ "auto_unlatch",
+ uidString,
+ "_auto_unlatch",
+ "Auto unlatch",
+ name,
+ baseTopic,
+ String("~") + mqtt_topic_config_basic_json,
+ deviceType,
+ "",
+ "",
+ "config",
+ String("~") + mqtt_topic_config_action,
+ {
+ { (char*)"en", (char*)"true" },
+ { (char*)"pl_on", (char*)"{ \"autoUnlatch\": \"1\"}" },
+ { (char*)"pl_off", (char*)"{ \"autoUnlatch\": \"0\"}" },
+ { (char*)"val_tpl", (char*)"{{value_json.autoUnlatch}}" },
+ { (char*)"stat_on", (char*)"1" },
+ { (char*)"stat_off", (char*)"0" }
+ });
+ }
+ else
+ {
+ removeHassTopic((char*)"switch", (char*)"auto_unlatch", uidString);
+ }
+
+ if((int)basicLockConfigAclPrefs[4] == 1)
+ {
+ // Pairing enabled
+ publishHassTopic("switch",
+ "pairing_enabled",
+ uidString,
+ "_pairing_enabled",
+ "Pairing enabled",
+ name,
+ baseTopic,
+ String("~") + mqtt_topic_config_basic_json,
+ deviceType,
+ "",
+ "",
+ "config",
+ String("~") + mqtt_topic_config_action,
+ {
+ { (char*)"en", (char*)"true" },
+ { (char*)"pl_on", (char*)"{ \"pairingEnabled\": \"1\"}" },
+ { (char*)"pl_off", (char*)"{ \"pairingEnabled\": \"0\"}" },
+ { (char*)"val_tpl", (char*)"{{value_json.pairingEnabled}}" },
+ { (char*)"stat_on", (char*)"1" },
+ { (char*)"stat_off", (char*)"0" }
+ });
+ }
+ else
+ {
+ removeHassTopic((char*)"switch", (char*)"pairing_enabled", uidString);
+ }
+
+ if((int)basicLockConfigAclPrefs[8] == 1)
+ {
+ publishHassTopic("number",
+ "timezone_offset",
+ uidString,
+ "_timezone_offset",
+ "Timezone offset",
+ name,
+ baseTopic,
+ String("~") + mqtt_topic_config_basic_json,
+ deviceType,
+ "",
+ "",
+ "config",
+ String("~") + mqtt_topic_config_action,
+ {
+ { (char*)"en", (char*)"true" },
+ { (char*)"ic", (char*)"mdi:timer-cog-outline" },
+ { (char*)"cmd_tpl", (char*)"{ \"timeZoneOffset\": \"{{ value }}\" }" },
+ { (char*)"val_tpl", (char*)"{{value_json.timeZoneOffset}}" },
+ { (char*)"min", (char*)"0" },
+ { (char*)"max", (char*)"60" }
+ });
+ }
+ else
+ {
+ removeHassTopic((char*)"number", (char*)"timezone_offset", uidString);
+ }
+
+ if((int)basicLockConfigAclPrefs[9] == 1)
+ {
+ // DST Mode
+ publishHassTopic("switch",
+ "dst_mode",
+ uidString,
+ "_dst_mode",
+ "DST mode European",
+ name,
+ baseTopic,
+ String("~") + mqtt_topic_config_basic_json,
+ deviceType,
+ "",
+ "",
+ "config",
+ String("~") + mqtt_topic_config_action,
+ {
+ { (char*)"en", (char*)"true" },
+ { (char*)"pl_on", (char*)"{ \"dstMode\": \"1\"}" },
+ { (char*)"pl_off", (char*)"{ \"dstMode\": \"0\"}" },
+ { (char*)"val_tpl", (char*)"{{value_json.dstMode}}" },
+ { (char*)"stat_on", (char*)"1" },
+ { (char*)"stat_off", (char*)"0" }
+ });
+ }
+ else
+ {
+ removeHassTopic((char*)"switch", (char*)"dst_mode", uidString);
+ }
+
+ if((int)basicLockConfigAclPrefs[10] == 1)
+ {
+ JsonDocument json;
+ json = createHassJson(uidString, "_fob_action_1", "Fob action 1", name, baseTopic, String("~") + mqtt_topic_config_basic_json, deviceType, "", "", "config", String("~") + mqtt_topic_config_action, {{ (char*)"val_tpl", (char*)"{{value_json.fobAction1}}" }, { (char*)"en", (char*)"true" }, { (char*)"cmd_tpl", (char*)"{ \"fobAction1\": \"{{ value }}\" }" }});
+ json["options"][0] = "No Action";
+ json["options"][1] = "Unlock";
+ json["options"][2] = "Lock";
+ json["options"][3] = "Lock n Go";
+ json["options"][4] = "Intelligent";
+ serializeJson(json, _buffer, _bufferSize);
+ String path = createHassTopicPath("select", "fob_action_1", uidString);
+ _device->mqttPublish(path.c_str(), MQTT_QOS_LEVEL, true, _buffer);
+ }
+ else
+ {
+ removeHassTopic((char*)"select", (char*)"fob_action_1", uidString);
+ }
+
+ if((int)basicLockConfigAclPrefs[11] == 1)
+ {
+ JsonDocument json;
+ json = createHassJson(uidString, "_fob_action_2", "Fob action 2", name, baseTopic, String("~") + mqtt_topic_config_basic_json, deviceType, "", "", "config", String("~") + mqtt_topic_config_action, {{ (char*)"val_tpl", (char*)"{{value_json.fobAction2}}" }, { (char*)"en", (char*)"true" }, { (char*)"cmd_tpl", (char*)"{ \"fobAction2\": \"{{ value }}\" }" }});
+ json["options"][0] = "No Action";
+ json["options"][1] = "Unlock";
+ json["options"][2] = "Lock";
+ json["options"][3] = "Lock n Go";
+ json["options"][4] = "Intelligent";
+ serializeJson(json, _buffer, _bufferSize);
+ String path = createHassTopicPath("select", "fob_action_2", uidString);
+ _device->mqttPublish(path.c_str(), MQTT_QOS_LEVEL, true, _buffer);
+ }
+ else
+ {
+ removeHassTopic((char*)"select", (char*)"fob_action_2", uidString);
+ }
+
+ if((int)basicLockConfigAclPrefs[12] == 1)
+ {
+ JsonDocument json;
+ json = createHassJson(uidString, "_fob_action_3", "Fob action 3", name, baseTopic, String("~") + mqtt_topic_config_basic_json, deviceType, "", "", "config", String("~") + mqtt_topic_config_action, {{ (char*)"val_tpl", (char*)"{{value_json.fobAction3}}" }, { (char*)"en", (char*)"true" }, { (char*)"cmd_tpl", (char*)"{ \"fobAction3\": \"{{ value }}\" }" }});
+ json["options"][0] = "No Action";
+ json["options"][1] = "Unlock";
+ json["options"][2] = "Lock";
+ json["options"][3] = "Lock n Go";
+ json["options"][4] = "Intelligent";
+ serializeJson(json, _buffer, _bufferSize);
+ String path = createHassTopicPath("select", "fob_action_3", uidString);
+ _device->mqttPublish(path.c_str(), MQTT_QOS_LEVEL, true, _buffer);
+ }
+ else
+ {
+ removeHassTopic((char*)"select", (char*)"fob_action_3", uidString);
+ }
+
+ if((int)basicLockConfigAclPrefs[14] == 1)
+ {
+ JsonDocument json;
+ json = createHassJson(uidString, "_advertising_mode", "Advertising mode", name, baseTopic, String("~") + mqtt_topic_config_basic_json, deviceType, "", "", "config", String("~") + mqtt_topic_config_action, {{ (char*)"val_tpl", (char*)"{{value_json.advertisingMode}}" }, { (char*)"en", (char*)"true" }, { (char*)"cmd_tpl", (char*)"{ \"advertisingMode\": \"{{ value }}\" }" }});
+ json["options"][0] = "Automatic";
+ json["options"][1] = "Normal";
+ json["options"][2] = "Slow";
+ json["options"][3] = "Slowest";
+ serializeJson(json, _buffer, _bufferSize);
+ String path = createHassTopicPath("select", "advertising_mode", uidString);
+ _device->mqttPublish(path.c_str(), MQTT_QOS_LEVEL, true, _buffer);
+ }
+ else
+ {
+ removeHassTopic((char*)"select", (char*)"advertising_mode", uidString);
+ }
+
+ if((int)basicLockConfigAclPrefs[15] == 1)
+ {
+ JsonDocument json;
+ json = createHassJson(uidString, "_timezone", "Timezone", name, baseTopic, String("~") + mqtt_topic_config_basic_json, deviceType, "", "", "config", String("~") + mqtt_topic_config_action, {{ (char*)"val_tpl", (char*)"{{value_json.timeZone}}" }, { (char*)"en", (char*)"true" }, { (char*)"cmd_tpl", (char*)"{ \"timeZone\": \"{{ value }}\" }" }});
+ json["options"][0] = "Africa/Cairo";
+ json["options"][1] = "Africa/Lagos";
+ json["options"][2] = "Africa/Maputo";
+ json["options"][3] = "Africa/Nairobi";
+ json["options"][4] = "America/Anchorage";
+ json["options"][5] = "America/Argentina/Buenos_Aires";
+ json["options"][6] = "America/Chicago";
+ json["options"][7] = "America/Denver";
+ json["options"][8] = "America/Halifax";
+ json["options"][9] = "America/Los_Angeles";
+ json["options"][10] = "America/Manaus";
+ json["options"][11] = "America/Mexico_City";
+ json["options"][12] = "America/New_York";
+ json["options"][13] = "America/Phoenix";
+ json["options"][14] = "America/Regina";
+ json["options"][15] = "America/Santiago";
+ json["options"][16] = "America/Sao_Paulo";
+ json["options"][17] = "America/St_Johns";
+ json["options"][18] = "Asia/Bangkok";
+ json["options"][19] = "Asia/Dubai";
+ json["options"][20] = "Asia/Hong_Kong";
+ json["options"][21] = "Asia/Jerusalem";
+ json["options"][22] = "Asia/Karachi";
+ json["options"][23] = "Asia/Kathmandu";
+ json["options"][24] = "Asia/Kolkata";
+ json["options"][25] = "Asia/Riyadh";
+ json["options"][26] = "Asia/Seoul";
+ json["options"][27] = "Asia/Shanghai";
+ json["options"][28] = "Asia/Tehran";
+ json["options"][29] = "Asia/Tokyo";
+ json["options"][30] = "Asia/Yangon";
+ json["options"][31] = "Australia/Adelaide";
+ json["options"][32] = "Australia/Brisbane";
+ json["options"][33] = "Australia/Darwin";
+ json["options"][34] = "Australia/Hobart";
+ json["options"][35] = "Australia/Perth";
+ json["options"][36] = "Australia/Sydney";
+ json["options"][37] = "Europe/Berlin";
+ json["options"][38] = "Europe/Helsinki";
+ json["options"][39] = "Europe/Istanbul";
+ json["options"][40] = "Europe/London";
+ json["options"][41] = "Europe/Moscow";
+ json["options"][42] = "Pacific/Auckland";
+ json["options"][43] = "Pacific/Guam";
+ json["options"][44] = "Pacific/Honolulu";
+ json["options"][45] = "Pacific/Pago_Pago";
+ json["options"][46] = "None";
+
+ serializeJson(json, _buffer, _bufferSize);
+ String path = createHassTopicPath("select", "timezone", uidString);
+ _device->mqttPublish(path.c_str(), MQTT_QOS_LEVEL, true, _buffer);
+ }
+ else
+ {
+ removeHassTopic((char*)"select", (char*)"timezone", uidString);
+ }
+
+ if((int)advancedLockConfigAclPrefs[0] == 1)
+ {
+ publishHassTopic("number",
+ "unlocked_position_offset_degrees",
+ uidString,
+ "_unlocked_position_offset_degrees",
+ "Unlocked position offset degrees",
+ name,
+ baseTopic,
+ String("~") + mqtt_topic_config_advanced_json,
+ deviceType,
+ "",
+ "",
+ "config",
+ String("~") + mqtt_topic_config_action,
+ {
+ { (char*)"en", (char*)"true" },
+ { (char*)"cmd_tpl", (char*)"{ \"unlockedPositionOffsetDegrees\": \"{{ value }}\" }" },
+ { (char*)"val_tpl", (char*)"{{value_json.unlockedPositionOffsetDegrees}}" },
+ { (char*)"min", (char*)"-90" },
+ { (char*)"max", (char*)"180" }
+ });
+ }
+ else
+ {
+ removeHassTopic((char*)"number", (char*)"unlocked_position_offset_degrees", uidString);
+ }
+
+ if((int)advancedLockConfigAclPrefs[1] == 1)
+ {
+ publishHassTopic("number",
+ "locked_position_offset_degrees",
+ uidString,
+ "_locked_position_offset_degrees",
+ "Locked position offset degrees",
+ name,
+ baseTopic,
+ String("~") + mqtt_topic_config_advanced_json,
+ deviceType,
+ "",
+ "",
+ "config",
+ String("~") + mqtt_topic_config_action,
+ {
+ { (char*)"en", (char*)"true" },
+ { (char*)"cmd_tpl", (char*)"{ \"lockedPositionOffsetDegrees\": \"{{ value }}\" }" },
+ { (char*)"val_tpl", (char*)"{{value_json.lockedPositionOffsetDegrees}}" },
+ { (char*)"min", (char*)"-180" },
+ { (char*)"max", (char*)"90" }
+ });
+ }
+ else
+ {
+ removeHassTopic((char*)"number", (char*)"locked_position_offset_degrees", uidString);
+ }
+
+ if((int)advancedLockConfigAclPrefs[2] == 1)
+ {
+ publishHassTopic("number",
+ "single_locked_position_offset_degrees",
+ uidString,
+ "_single_locked_position_offset_degrees",
+ "Single locked position offset degrees",
+ name,
+ baseTopic,
+ String("~") + mqtt_topic_config_advanced_json,
+ deviceType,
+ "",
+ "",
+ "config",
+ String("~") + mqtt_topic_config_action,
+ {
+ { (char*)"en", (char*)"true" },
+ { (char*)"cmd_tpl", (char*)"{ \"singleLockedPositionOffsetDegrees\": \"{{ value }}\" }" },
+ { (char*)"val_tpl", (char*)"{{value_json.singleLockedPositionOffsetDegrees}}" },
+ { (char*)"min", (char*)"-180" },
+ { (char*)"max", (char*)"180" }
+ });
+ }
+ else
+ {
+ removeHassTopic((char*)"number", (char*)"single_locked_position_offset_degrees", uidString);
+ }
+
+ if((int)advancedLockConfigAclPrefs[3] == 1)
+ {
+ publishHassTopic("number",
+ "unlocked_locked_transition_offset_degrees",
+ uidString,
+ "_unlocked_locked_transition_offset_degrees",
+ "Unlocked to locked transition offset degrees",
+ name,
+ baseTopic,
+ String("~") + mqtt_topic_config_advanced_json,
+ deviceType,
+ "",
+ "",
+ "config",
+ String("~") + mqtt_topic_config_action,
+ {
+ { (char*)"en", (char*)"true" },
+ { (char*)"cmd_tpl", (char*)"{ \"unlockedToLockedTransitionOffsetDegrees\": \"{{ value }}\" }" },
+ { (char*)"val_tpl", (char*)"{{value_json.unlockedToLockedTransitionOffsetDegrees}}" },
+ { (char*)"min", (char*)"-180" },
+ { (char*)"max", (char*)"180" }
+ });
+ }
+ else
+ {
+ removeHassTopic((char*)"number", (char*)"unlocked_locked_transition_offset_degrees", uidString);
+ }
+
+ if((int)advancedLockConfigAclPrefs[4] == 1)
+ {
+ publishHassTopic("number",
+ "lockngo_timeout",
+ uidString,
+ "_lockngo_timeout",
+ "Lock n Go timeout",
+ name,
+ baseTopic,
+ String("~") + mqtt_topic_config_advanced_json,
+ deviceType,
+ "",
+ "",
+ "config",
+ String("~") + mqtt_topic_config_action,
+ {
+ { (char*)"en", (char*)"true" },
+ { (char*)"cmd_tpl", (char*)"{ \"lockNgoTimeout\": \"{{ value }}\" }" },
+ { (char*)"val_tpl", (char*)"{{value_json.lockNgoTimeout}}" },
+ { (char*)"min", (char*)"5" },
+ { (char*)"max", (char*)"60" }
+ });
+ }
+ else
+ {
+ removeHassTopic((char*)"number", (char*)"lockngo_timeout", uidString);
+ }
+
+ if((int)advancedLockConfigAclPrefs[5] == 1)
+ {
+ JsonDocument json;
+ json = createHassJson(uidString, "_single_button_press_action", "Single button press action", name, baseTopic, String("~") + mqtt_topic_config_advanced_json, deviceType, "", "", "config", String("~") + mqtt_topic_config_action, {{ (char*)"val_tpl", (char*)"{{value_json.singleButtonPressAction}}" }, { (char*)"en", (char*)"true" }, { (char*)"cmd_tpl", (char*)"{ \"singleButtonPressAction\": \"{{ value }}\" }" }});
+ json["options"][0] = "No Action";
+ json["options"][1] = "Intelligent";
+ json["options"][2] = "Unlock";
+ json["options"][3] = "Lock";
+ json["options"][4] = "Unlatch";
+ json["options"][5] = "Lock n Go";
+ json["options"][6] = "Show Status";
+ serializeJson(json, _buffer, _bufferSize);
+ String path = createHassTopicPath("select", "single_button_press_action", uidString);
+ _device->mqttPublish(path.c_str(), MQTT_QOS_LEVEL, true, _buffer);
+ }
+ else
+ {
+ removeHassTopic((char*)"select", (char*)"single_button_press_action", uidString);
+ }
+
+ if((int)advancedLockConfigAclPrefs[6] == 1)
+ {
+ JsonDocument json;
+ json = createHassJson(uidString, "_double_button_press_action", "Double button press action", name, baseTopic, String("~") + mqtt_topic_config_advanced_json, deviceType, "", "", "config", String("~") + mqtt_topic_config_action, {{ (char*)"val_tpl", (char*)"{{value_json.doubleButtonPressAction}}" }, { (char*)"en", (char*)"true" }, { (char*)"cmd_tpl", (char*)"{ \"doubleButtonPressAction\": \"{{ value }}\" }" }});
+ json["options"][0] = "No Action";
+ json["options"][1] = "Intelligent";
+ json["options"][2] = "Unlock";
+ json["options"][3] = "Lock";
+ json["options"][4] = "Unlatch";
+ json["options"][5] = "Lock n Go";
+ json["options"][6] = "Show Status";
+ serializeJson(json, _buffer, _bufferSize);
+ String path = createHassTopicPath("select", "double_button_press_action", uidString);
+ _device->mqttPublish(path.c_str(), MQTT_QOS_LEVEL, true, _buffer);
+ }
+ else
+ {
+ removeHassTopic((char*)"select", (char*)"double_button_press_action", uidString);
+ }
+
+ if((int)advancedLockConfigAclPrefs[7] == 1)
+ {
+ // Detached cylinder
+ publishHassTopic("switch",
+ "detached_cylinder",
+ uidString,
+ "_detached_cylinder",
+ "Detached cylinder",
+ name,
+ baseTopic,
+ String("~") + mqtt_topic_config_advanced_json,
+ deviceType,
+ "",
+ "",
+ "config",
+ String("~") + mqtt_topic_config_action,
+ {
+ { (char*)"en", (char*)"true" },
+ { (char*)"pl_on", (char*)"{ \"detachedCylinder\": \"1\"}" },
+ { (char*)"pl_off", (char*)"{ \"detachedCylinder\": \"0\"}" },
+ { (char*)"val_tpl", (char*)"{{value_json.detachedCylinder}}" },
+ { (char*)"stat_on", (char*)"1" },
+ { (char*)"stat_off", (char*)"0" }
+ });
+ }
+ else
+ {
+ removeHassTopic((char*)"switch", (char*)"detached_cylinder", uidString);
+ }
+
+ if((int)advancedLockConfigAclPrefs[8] == 1)
+ {
+ JsonDocument json;
+ json = createHassJson(uidString, "_battery_type", "Battery type", name, baseTopic, String("~") + mqtt_topic_config_advanced_json, deviceType, "", "", "config", String("~") + mqtt_topic_config_action, {{ (char*)"val_tpl", (char*)"{{value_json.batteryType}}" }, { (char*)"en", (char*)"true" }, { (char*)"cmd_tpl", (char*)"{ \"batteryType\": \"{{ value }}\" }" }});
+ json["options"][0] = "Alkali";
+ json["options"][1] = "Accumulators";
+ json["options"][2] = "Lithium";
+ serializeJson(json, _buffer, _bufferSize);
+ String path = createHassTopicPath("select", "battery_type", uidString);
+ _device->mqttPublish(path.c_str(), MQTT_QOS_LEVEL, true, _buffer);
+ }
+ else
+ {
+ removeHassTopic((char*)"select", (char*)"battery_type", uidString);
+ }
+
+ if((int)advancedLockConfigAclPrefs[9] == 1)
+ {
+ // Automatic battery type detection
+ publishHassTopic("switch",
+ "automatic_battery_type_detection",
+ uidString,
+ "_automatic_battery_type_detection",
+ "Automatic battery type detection",
+ name,
+ baseTopic,
+ String("~") + mqtt_topic_config_advanced_json,
+ deviceType,
+ "",
+ "",
+ "config",
+ String("~") + mqtt_topic_config_action,
+ {
+ { (char*)"en", (char*)"true" },
+ { (char*)"pl_on", (char*)"{ \"automaticBatteryTypeDetection\": \"1\"}" },
+ { (char*)"pl_off", (char*)"{ \"automaticBatteryTypeDetection\": \"0\"}" },
+ { (char*)"val_tpl", (char*)"{{value_json.automaticBatteryTypeDetection}}" },
+ { (char*)"stat_on", (char*)"1" },
+ { (char*)"stat_off", (char*)"0" }
+ });
+ }
+ else
+ {
+ removeHassTopic((char*)"switch", (char*)"automatic_battery_type_detection", uidString);
+ }
+
+ if((int)advancedLockConfigAclPrefs[10] == 1)
+ {
+ publishHassTopic("number",
+ "unlatch_duration",
+ uidString,
+ "_unlatch_duration",
+ "Unlatch duration",
+ name,
+ baseTopic,
+ String("~") + mqtt_topic_config_advanced_json,
+ deviceType,
+ "",
+ "",
+ "config",
+ String("~") + mqtt_topic_config_action,
+ {
+ { (char*)"en", (char*)"true" },
+ { (char*)"cmd_tpl", (char*)"{ \"unlatchDuration\": \"{{ value }}\" }" },
+ { (char*)"val_tpl", (char*)"{{value_json.unlatchDuration}}" },
+ { (char*)"min", (char*)"1" },
+ { (char*)"max", (char*)"30" }
+ });
+ }
+ else
+ {
+ removeHassTopic((char*)"number", (char*)"unlatch_duration", uidString);
+ }
+
+ if((int)advancedLockConfigAclPrefs[11] == 1)
+ {
+ publishHassTopic("number",
+ "auto_lock_timeout",
+ uidString,
+ "_auto_lock_timeout",
+ "Auto lock timeout",
+ name,
+ baseTopic,
+ String("~") + mqtt_topic_config_advanced_json,
+ deviceType,
+ "",
+ "",
+ "config",
+ String("~") + mqtt_topic_config_action,
+ {
+ { (char*)"en", (char*)"true" },
+ { (char*)"cmd_tpl", (char*)"{ \"autoLockTimeOut\": \"{{ value }}\" }" },
+ { (char*)"val_tpl", (char*)"{{value_json.autoLockTimeOut}}" },
+ { (char*)"min", (char*)"30" },
+ { (char*)"max", (char*)"1800" }
+ });
+ }
+ else
+ {
+ removeHassTopic((char*)"number", (char*)"auto_lock_timeout", uidString);
+ }
+
+ if((int)advancedLockConfigAclPrefs[13] == 1)
+ {
+ // Nightmode enabled
+ publishHassTopic("switch",
+ "nightmode_enabled",
+ uidString,
+ "_nightmode_enabled",
+ "Nightmode enabled",
+ name,
+ baseTopic,
+ String("~") + mqtt_topic_config_advanced_json,
+ deviceType,
+ "",
+ "",
+ "config",
+ String("~") + mqtt_topic_config_action,
+ {
+ { (char*)"en", (char*)"true" },
+ { (char*)"pl_on", (char*)"{ \"nightModeEnabled\": \"1\"}" },
+ { (char*)"pl_off", (char*)"{ \"nightModeEnabled\": \"0\"}" },
+ { (char*)"val_tpl", (char*)"{{value_json.nightModeEnabled}}" },
+ { (char*)"stat_on", (char*)"1" },
+ { (char*)"stat_off", (char*)"0" }
+ });
+ }
+ else
+ {
+ removeHassTopic((char*)"switch", (char*)"nightmode_enabled", uidString);
+ }
+
+ if((int)advancedLockConfigAclPrefs[14] == 1)
+ {
+ // Nightmode start time
+ publishHassTopic("text",
+ "nightmode_start_time",
+ uidString,
+ "_nightmode_start_time",
+ "Nightmode start time",
+ name,
+ baseTopic,
+ String("~") + mqtt_topic_config_advanced_json,
+ deviceType,
+ "",
+ "",
+ "config",
+ String("~") + mqtt_topic_config_action,
+ {
+ { (char*)"en", (char*)"true" },
+ { (char*)"pattern", (char*)"([0-1][0-9]|2[0-3]):[0-5][0-9]" },
+ { (char*)"cmd_tpl", (char*)"{ \"nightModeStartTime\": \"{{ value }}\" }" },
+ { (char*)"val_tpl", (char*)"{{value_json.nightModeStartTime}}" },
+ { (char*)"min", (char*)"5" },
+ { (char*)"max", (char*)"5" }
+ });
+ }
+ else
+ {
+ removeHassTopic((char*)"text", (char*)"nightmode_start_time", uidString);
+ }
+
+ if((int)advancedLockConfigAclPrefs[15] == 1)
+ {
+ // Nightmode end time
+ publishHassTopic("text",
+ "nightmode_end_time",
+ uidString,
+ "_nightmode_end_time",
+ "Nightmode end time",
+ name,
+ baseTopic,
+ String("~") + mqtt_topic_config_advanced_json,
+ deviceType,
+ "",
+ "",
+ "config",
+ String("~") + mqtt_topic_config_action,
+ {
+ { (char*)"en", (char*)"true" },
+ { (char*)"pattern", (char*)"([0-1][0-9]|2[0-3]):[0-5][0-9]" },
+ { (char*)"cmd_tpl", (char*)"{ \"nightModeEndTime\": \"{{ value }}\" }" },
+ { (char*)"val_tpl", (char*)"{{value_json.nightModeEndTime}}" },
+ { (char*)"min", (char*)"5" },
+ { (char*)"max", (char*)"5" }
+ });
+ }
+ else
+ {
+ removeHassTopic((char*)"text", (char*)"nightmode_end_time", uidString);
+ }
+
+ if((int)advancedLockConfigAclPrefs[16] == 1)
+ {
+ // Nightmode Auto Lock
+ publishHassTopic("switch",
+ "nightmode_auto_lock",
+ uidString,
+ "_nightmode_auto_lock",
+ "Nightmode auto lock",
+ name,
+ baseTopic,
+ String("~") + mqtt_topic_config_advanced_json,
+ deviceType,
+ "",
+ "",
+ "config",
+ String("~") + mqtt_topic_config_action,
+ {
+ { (char*)"en", (char*)"true" },
+ { (char*)"pl_on", (char*)"{ \"nightModeAutoLockEnabled\": \"1\"}" },
+ { (char*)"pl_off", (char*)"{ \"nightModeAutoLockEnabled\": \"0\"}" },
+ { (char*)"val_tpl", (char*)"{{value_json.nightModeAutoLockEnabled}}" },
+ { (char*)"stat_on", (char*)"1" },
+ { (char*)"stat_off", (char*)"0" }
+ });
+ }
+ else
+ {
+ removeHassTopic((char*)"switch", (char*)"nightmode_auto_lock", uidString);
+ }
+
+ if((int)advancedLockConfigAclPrefs[17] == 1)
+ {
+ // Nightmode Auto Unlock
+ publishHassTopic("switch",
+ "nightmode_auto_unlock",
+ uidString,
+ "_nightmode_auto_unlock",
+ "Nightmode auto unlock",
+ name,
+ baseTopic,
+ String("~") + mqtt_topic_config_advanced_json,
+ deviceType,
+ "",
+ "",
+ "config",
+ String("~") + mqtt_topic_config_action,
+ {
+ { (char*)"en", (char*)"true" },
+ { (char*)"pl_on", (char*)"{ \"nightModeAutoUnlockDisabled\": \"0\"}" },
+ { (char*)"pl_off", (char*)"{ \"nightModeAutoUnlockDisabled\": \"1\"}" },
+ { (char*)"val_tpl", (char*)"{{value_json.nightModeAutoUnlockDisabled}}" },
+ { (char*)"stat_on", (char*)"0" },
+ { (char*)"stat_off", (char*)"1" }
+ });
+ }
+ else
+ {
+ removeHassTopic((char*)"switch", (char*)"nightmode_auto_unlock", uidString);
+ }
+
+ if((int)advancedLockConfigAclPrefs[18] == 1)
+ {
+ // Nightmode immediate lock on start
+ publishHassTopic("switch",
+ "nightmode_immediate_lock_start",
+ uidString,
+ "_nightmode_immediate_lock_start",
+ "Nightmode immediate lock on start",
+ name,
+ baseTopic,
+ String("~") + mqtt_topic_config_advanced_json,
+ deviceType,
+ "",
+ "",
+ "config",
+ String("~") + mqtt_topic_config_action,
+ {
+ { (char*)"en", (char*)"true" },
+ { (char*)"pl_on", (char*)"{ \"nightModeImmediateLockOnStart\": \"1\"}" },
+ { (char*)"pl_off", (char*)"{ \"nightModeImmediateLockOnStart\": \"0\"}" },
+ { (char*)"val_tpl", (char*)"{{value_json.nightModeImmediateLockOnStart}}" },
+ { (char*)"stat_on", (char*)"1" },
+ { (char*)"stat_off", (char*)"0" }
+ });
+ }
+ else
+ {
+ removeHassTopic((char*)"switch", (char*)"nightmode_immediate_lock_start", uidString);
+ }
+
+ if((int)advancedLockConfigAclPrefs[20] == 1)
+ {
+ // Immediate auto lock enabled
+ publishHassTopic("switch",
+ "immediate_auto_lock_enabled",
+ uidString,
+ "_immediate_auto_lock_enabled",
+ "Immediate auto lock enabled",
+ name,
+ baseTopic,
+ String("~") + mqtt_topic_config_advanced_json,
+ deviceType,
+ "",
+ "",
+ "config",
+ String("~") + mqtt_topic_config_action,
+ {
+ { (char*)"en", (char*)"true" },
+ { (char*)"pl_on", (char*)"{ \"immediateAutoLockEnabled\": \"1\"}" },
+ { (char*)"pl_off", (char*)"{ \"immediateAutoLockEnabled\": \"0\"}" },
+ { (char*)"val_tpl", (char*)"{{value_json.immediateAutoLockEnabled}}" },
+ { (char*)"stat_on", (char*)"1" },
+ { (char*)"stat_off", (char*)"0" }
+ });
+ }
+ else
+ {
+ removeHassTopic((char*)"switch", (char*)"immediate_auto_lock_enabled", uidString);
+ }
+
+ if((int)advancedLockConfigAclPrefs[21] == 1)
+ {
+ // Auto update enabled
+ publishHassTopic("switch",
+ "auto_update_enabled",
+ uidString,
+ "_auto_update_enabled",
+ "Auto update enabled",
+ name,
+ baseTopic,
+ String("~") + mqtt_topic_config_advanced_json,
+ deviceType,
+ "",
+ "",
+ "config",
+ String("~") + mqtt_topic_config_action,
+ {
+ { (char*)"en", (char*)"true" },
+ { (char*)"pl_on", (char*)"{ \"autoUpdateEnabled\": \"1\"}" },
+ { (char*)"pl_off", (char*)"{ \"autoUpdateEnabled\": \"0\"}" },
+ { (char*)"val_tpl", (char*)"{{value_json.autoUpdateEnabled}}" },
+ { (char*)"stat_on", (char*)"1" },
+ { (char*)"stat_off", (char*)"0" }
+ });
+ }
+ else
+ {
+ removeHassTopic((char*)"switch", (char*)"auto_update_enabled", uidString);
+ }
+}
+
+void HomeAssistantDiscovery::publishHASSConfigDoorSensor(char *deviceType, const char *baseTopic, char *name, char *uidString)
+{
+ publishHassTopic("binary_sensor",
+ "door_sensor",
+ uidString,
+ "_door_sensor",
+ "Door sensor",
+ name,
+ baseTopic,
+ String("~") + mqtt_topic_lock_door_sensor_state,
+ deviceType,
+ "door",
+ "",
+ "",
+ "",
+ {
+ {(char*)"pl_on", (char*)"doorOpened"},
+ {(char*)"pl_off", (char*)"doorClosed"},
+ {(char*)"pl_not_avail", (char*)"unavailable"}
+ });
+}
+
+void HomeAssistantDiscovery::publishHASSConfigAdditionalOpenerEntities(char *deviceType, const char *baseTopic, char *name, char *uidString)
+{
+ uint32_t aclPrefs[17];
+ _preferences->getBytes(preference_acl, &aclPrefs, sizeof(aclPrefs));
+ uint32_t basicOpenerConfigAclPrefs[14] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+ uint32_t advancedOpenerConfigAclPrefs[20] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
+
+ if(_preferences->getBool(preference_conf_info_enabled, true))
+ {
+ _preferences->getBytes(preference_conf_opener_basic_acl, &basicOpenerConfigAclPrefs, sizeof(basicOpenerConfigAclPrefs));
+ _preferences->getBytes(preference_conf_opener_advanced_acl, &advancedOpenerConfigAclPrefs, sizeof(advancedOpenerConfigAclPrefs));
+ }
+
+ if((int)aclPrefs[11])
+ {
+ // Unlatch
+ publishHassTopic("button",
+ "unlatch",
+ uidString,
+ "_unlatch",
+ "Open",
+ name,
+ baseTopic,
+ "",
+ deviceType,
+ "",
+ "",
+ "",
+ String("~") + mqtt_topic_lock_action,
+ {
+ { (char*)"en", (char*)"false" },
+ { (char*)"pl_prs", (char*)"electricStrikeActuation" }
+ });
+ }
+ else
+ {
+ removeHassTopic((char*)"button", (char*)"unlatch", uidString);
+ }
+
+ publishHassTopic("binary_sensor",
+ "continuous_mode",
+ uidString,
+ "_continuous_mode",
+ "Continuous mode",
+ name,
+ baseTopic,
+ String("~") + mqtt_topic_lock_continuous_mode,
+ deviceType,
+ "lock",
+ "",
+ "",
+ "",
+ {
+ {(char*)"pl_on", (char*)"on"},
+ {(char*)"pl_off", (char*)"off"}
+ });
+
+ if((int)aclPrefs[12] == 1 && (int)aclPrefs[13] == 1)
+ {
+ publishHassTopic("switch",
+ "continuous_mode",
+ uidString,
+ "_continuous_mode",
+ "Continuous mode",
+ name,
+ baseTopic,
+ String("~") + mqtt_topic_lock_continuous_mode,
+ deviceType,
+ "",
+ "",
+ "",
+ String("~") + mqtt_topic_lock_action,
+ {
+ { (char*)"en", (char*)"true" },
+ {(char*)"stat_on", (char*)"on"},
+ {(char*)"stat_off", (char*)"off"},
+ {(char*)"pl_on", (char*)"activateCM"},
+ {(char*)"pl_off", (char*)"deactivateCM"}
+ });
+ }
+ else
+ {
+ removeHassTopic((char*)"switch", (char*)"continuous_mode", uidString);
+ }
+
+ publishHassTopic("binary_sensor",
+ "ring_detect",
+ uidString,
+ "_ring_detect",
+ "Ring detect",
+ name,
+ baseTopic,
+ String("~") + mqtt_topic_lock_binary_ring,
+ deviceType,
+ "sound",
+ "",
+ "",
+ "",
+ {
+ {(char*)"pl_on", (char*)"ring"},
+ {(char*)"pl_off", (char*)"standby"}
+ });
+
+ JsonDocument json;
+ json = createHassJson(uidString, "_ring_event", "Ring", name, baseTopic, String("~") + mqtt_topic_lock_ring, deviceType, "doorbell", "", "", "", {{(char*)"val_tpl", (char*)"{ \"event_type\": \"{{ value }}\" }"}});
+ json["event_types"][0] = "ring";
+ json["event_types"][1] = "ringlocked";
+ json["event_types"][2] = "standby";
+ serializeJson(json, _buffer, _bufferSize);
+ String path = createHassTopicPath("event", "ring", uidString);
+ _device->mqttPublish(path.c_str(), MQTT_QOS_LEVEL, true, _buffer);
+
+ if((int)basicOpenerConfigAclPrefs[5] == 1)
+ {
+ // LED enabled
+ publishHassTopic("switch",
+ "led_enabled",
+ uidString,
+ "_led_enabled",
+ "LED enabled",
+ name,
+ baseTopic,
+ String("~") + mqtt_topic_config_basic_json,
+ deviceType,
+ "",
+ "",
+ "config",
+ String("~") + mqtt_topic_config_action,
+ {
+ { (char*)"en", (char*)"true" },
+ { (char*)"ic", (char*)"mdi:led-variant-on" },
+ { (char*)"pl_on", (char*)"{ \"ledFlashEnabled\": \"1\"}" },
+ { (char*)"pl_off", (char*)"{ \"ledFlashEnabled\": \"0\"}" },
+ { (char*)"val_tpl", (char*)"{{value_json.ledFlashEnabled}}" },
+ { (char*)"stat_on", (char*)"1" },
+ { (char*)"stat_off", (char*)"0" }
+ });
+ }
+ else
+ {
+ removeHassTopic((char*)"switch", (char*)"led_enabled", uidString);
+ }
+
+ if((int)basicOpenerConfigAclPrefs[4] == 1)
+ {
+ // Button enabled
+ publishHassTopic("switch",
+ "button_enabled",
+ uidString,
+ "_button_enabled",
+ "Button enabled",
+ name,
+ baseTopic,
+ String("~") + mqtt_topic_config_basic_json,
+ deviceType,
+ "",
+ "",
+ "config",
+ String("~") + mqtt_topic_config_action,
+ {
+ { (char*)"en", (char*)"true" },
+ { (char*)"ic", (char*)"mdi:radiobox-marked" },
+ { (char*)"pl_on", (char*)"{ \"buttonEnabled\": \"1\"}" },
+ { (char*)"pl_off", (char*)"{ \"buttonEnabled\": \"0\"}" },
+ { (char*)"val_tpl", (char*)"{{value_json.buttonEnabled}}" },
+ { (char*)"stat_on", (char*)"1" },
+ { (char*)"stat_off", (char*)"0" }
+ });
+ }
+ else
+ {
+ removeHassTopic((char*)"switch", (char*)"button_enabled", uidString);
+ }
+
+ if((int)advancedOpenerConfigAclPrefs[15] == 1)
+ {
+ publishHassTopic("number",
+ "sound_level",
+ uidString,
+ "_sound_level",
+ "Sound level",
+ name,
+ baseTopic,
+ String("~") + mqtt_topic_config_advanced_json,
+ deviceType,
+ "",
+ "",
+ "config",
+ String("~") + mqtt_topic_config_action,
+ {
+ { (char*)"en", (char*)"true" },
+ { (char*)"ic", (char*)"mdi:volume-source" },
+ { (char*)"cmd_tpl", (char*)"{ \"soundLevel\": \"{{ value }}\" }" },
+ { (char*)"val_tpl", (char*)"{{value_json.soundLevel}}" },
+ { (char*)"min", (char*)"0" },
+ { (char*)"max", (char*)"255" },
+ { (char*)"mode", (char*)"slider" },
+ { (char*)"step", (char*)"25.5" }
+ });
+ }
+ else
+ {
+ removeHassTopic((char*)"number", (char*)"sound_level", uidString);
+ }
+
+ if((int)basicOpenerConfigAclPrefs[3] == 1)
+ {
+ // Pairing enabled
+ publishHassTopic("switch",
+ "pairing_enabled",
+ uidString,
+ "_pairing_enabled",
+ "Pairing enabled",
+ name,
+ baseTopic,
+ String("~") + mqtt_topic_config_basic_json,
+ deviceType,
+ "",
+ "",
+ "config",
+ String("~") + mqtt_topic_config_action,
+ {
+ { (char*)"en", (char*)"true" },
+ { (char*)"pl_on", (char*)"{ \"pairingEnabled\": \"1\"}" },
+ { (char*)"pl_off", (char*)"{ \"pairingEnabled\": \"0\"}" },
+ { (char*)"val_tpl", (char*)"{{value_json.pairingEnabled}}" },
+ { (char*)"stat_on", (char*)"1" },
+ { (char*)"stat_off", (char*)"0" }
+ });
+ }
+ else
+ {
+ removeHassTopic((char*)"switch", (char*)"pairing_enabled", uidString);
+ }
+
+ if((int)basicOpenerConfigAclPrefs[6] == 1)
+ {
+ publishHassTopic("number",
+ "timezone_offset",
+ uidString,
+ "_timezone_offset",
+ "Timezone offset",
+ name,
+ baseTopic,
+ String("~") + mqtt_topic_config_basic_json,
+ deviceType,
+ "",
+ "",
+ "config",
+ String("~") + mqtt_topic_config_action,
+ {
+ { (char*)"en", (char*)"true" },
+ { (char*)"ic", (char*)"mdi:timer-cog-outline" },
+ { (char*)"cmd_tpl", (char*)"{ \"timeZoneOffset\": \"{{ value }}\" }" },
+ { (char*)"val_tpl", (char*)"{{value_json.timeZoneOffset}}" },
+ { (char*)"min", (char*)"0" },
+ { (char*)"max", (char*)"60" }
+ });
+ }
+ else
+ {
+ removeHassTopic((char*)"number", (char*)"timezone_offset", uidString);
+ }
+
+ if((int)basicOpenerConfigAclPrefs[7] == 1)
+ {
+ // DST Mode
+ publishHassTopic("switch",
+ "dst_mode",
+ uidString,
+ "_dst_mode",
+ "DST mode European",
+ name,
+ baseTopic,
+ String("~") + mqtt_topic_config_basic_json,
+ deviceType,
+ "",
+ "",
+ "config",
+ String("~") + mqtt_topic_config_action,
+ {
+ { (char*)"en", (char*)"true" },
+ { (char*)"pl_on", (char*)"{ \"dstMode\": \"1\"}" },
+ { (char*)"pl_off", (char*)"{ \"dstMode\": \"0\"}" },
+ { (char*)"val_tpl", (char*)"{{value_json.dstMode}}" },
+ { (char*)"stat_on", (char*)"1" },
+ { (char*)"stat_off", (char*)"0" }
+ });
+ }
+ else
+ {
+ removeHassTopic((char*)"switch", (char*)"dst_mode", uidString);
+ }
+
+ if((int)basicOpenerConfigAclPrefs[8] == 1)
+ {
+ JsonDocument json;
+ json = createHassJson(uidString, "_fob_action_1", "Fob action 1", name, baseTopic, String("~") + mqtt_topic_config_basic_json, deviceType, "", "", "config", String("~") + mqtt_topic_config_action, {{ (char*)"val_tpl", (char*)"{{value_json.fobAction1}}" }, { (char*)"en", (char*)"true" }, { (char*)"cmd_tpl", (char*)"{ \"fobAction1\": \"{{ value }}\" }" }});
+ json["options"][0] = "No Action";
+ json["options"][1] = "Toggle RTO";
+ json["options"][2] = "Activate RTO";
+ json["options"][3] = "Deactivate RTO";
+ json["options"][4] = "Open";
+ json["options"][5] = "Ring";
+ serializeJson(json, _buffer, _bufferSize);
+ String path = createHassTopicPath("select", "fob_action_1", uidString);
+ _device->mqttPublish(path.c_str(), MQTT_QOS_LEVEL, true, _buffer);
+ }
+ else
+ {
+ removeHassTopic((char*)"select", (char*)"fob_action_1", uidString);
+ }
+
+ if((int)basicOpenerConfigAclPrefs[9] == 1)
+ {
+ JsonDocument json;
+ json = createHassJson(uidString, "_fob_action_2", "Fob action 2", name, baseTopic, String("~") + mqtt_topic_config_basic_json, deviceType, "", "", "config", String("~") + mqtt_topic_config_action, {{ (char*)"val_tpl", (char*)"{{value_json.fobAction2}}" }, { (char*)"en", (char*)"true" }, { (char*)"cmd_tpl", (char*)"{ \"fobAction2\": \"{{ value }}\" }" }});
+ json["options"][0] = "No Action";
+ json["options"][1] = "Toggle RTO";
+ json["options"][2] = "Activate RTO";
+ json["options"][3] = "Deactivate RTO";
+ json["options"][4] = "Open";
+ json["options"][5] = "Ring";
+ serializeJson(json, _buffer, _bufferSize);
+ String path = createHassTopicPath("select", "fob_action_2", uidString);
+ _device->mqttPublish(path.c_str(), MQTT_QOS_LEVEL, true, _buffer);
+ }
+ else
+ {
+ removeHassTopic((char*)"select", (char*)"fob_action_2", uidString);
+ }
+
+ if((int)basicOpenerConfigAclPrefs[10] == 1)
+ {
+ JsonDocument json;
+ json = createHassJson(uidString, "_fob_action_3", "Fob action 3", name, baseTopic, String("~") + mqtt_topic_config_basic_json, deviceType, "", "", "config", String("~") + mqtt_topic_config_action, {{ (char*)"val_tpl", (char*)"{{value_json.fobAction3}}" }, { (char*)"en", (char*)"true" }, { (char*)"cmd_tpl", (char*)"{ \"fobAction3\": \"{{ value }}\" }" }});
+ json["options"][0] = "No Action";
+ json["options"][1] = "Toggle RTO";
+ json["options"][2] = "Activate RTO";
+ json["options"][3] = "Deactivate RTO";
+ json["options"][4] = "Open";
+ json["options"][5] = "Ring";
+ serializeJson(json, _buffer, _bufferSize);
+ String path = createHassTopicPath("select", "fob_action_3", uidString);
+ _device->mqttPublish(path.c_str(), MQTT_QOS_LEVEL, true, _buffer);
+ }
+ else
+ {
+ removeHassTopic((char*)"select", (char*)"fob_action_3", uidString);
+ }
+
+ if((int)basicOpenerConfigAclPrefs[12] == 1)
+ {
+ JsonDocument json;
+ json = createHassJson(uidString, "_advertising_mode", "Advertising mode", name, baseTopic, String("~") + mqtt_topic_config_basic_json, deviceType, "", "", "config", String("~") + mqtt_topic_config_action, {{ (char*)"val_tpl", (char*)"{{value_json.advertisingMode}}" }, { (char*)"en", (char*)"true" }, { (char*)"cmd_tpl", (char*)"{ \"advertisingMode\": \"{{ value }}\" }" }});
+ json["options"][0] = "Automatic";
+ json["options"][1] = "Normal";
+ json["options"][2] = "Slow";
+ json["options"][3] = "Slowest";
+ serializeJson(json, _buffer, _bufferSize);
+ String path = createHassTopicPath("select", "advertising_mode", uidString);
+ _device->mqttPublish(path.c_str(), MQTT_QOS_LEVEL, true, _buffer);
+ }
+ else
+ {
+ removeHassTopic((char*)"select", (char*)"advertising_mode", uidString);
+ }
+
+ if((int)basicOpenerConfigAclPrefs[13] == 1)
+ {
+ JsonDocument json;
+ json = createHassJson(uidString, "_timezone", "Timezone", name, baseTopic, String("~") + mqtt_topic_config_basic_json, deviceType, "", "", "config", String("~") + mqtt_topic_config_action, {{ (char*)"val_tpl", (char*)"{{value_json.timeZone}}" }, { (char*)"en", (char*)"true" }, { (char*)"cmd_tpl", (char*)"{ \"timeZone\": \"{{ value }}\" }" }});
+ json["options"][0] = "Africa/Cairo";
+ json["options"][1] = "Africa/Lagos";
+ json["options"][2] = "Africa/Maputo";
+ json["options"][3] = "Africa/Nairobi";
+ json["options"][4] = "America/Anchorage";
+ json["options"][5] = "America/Argentina/Buenos_Aires";
+ json["options"][6] = "America/Chicago";
+ json["options"][7] = "America/Denver";
+ json["options"][8] = "America/Halifax";
+ json["options"][9] = "America/Los_Angeles";
+ json["options"][10] = "America/Manaus";
+ json["options"][11] = "America/Mexico_City";
+ json["options"][12] = "America/New_York";
+ json["options"][13] = "America/Phoenix";
+ json["options"][14] = "America/Regina";
+ json["options"][15] = "America/Santiago";
+ json["options"][16] = "America/Sao_Paulo";
+ json["options"][17] = "America/St_Johns";
+ json["options"][18] = "Asia/Bangkok";
+ json["options"][19] = "Asia/Dubai";
+ json["options"][20] = "Asia/Hong_Kong";
+ json["options"][21] = "Asia/Jerusalem";
+ json["options"][22] = "Asia/Karachi";
+ json["options"][23] = "Asia/Kathmandu";
+ json["options"][24] = "Asia/Kolkata";
+ json["options"][25] = "Asia/Riyadh";
+ json["options"][26] = "Asia/Seoul";
+ json["options"][27] = "Asia/Shanghai";
+ json["options"][28] = "Asia/Tehran";
+ json["options"][29] = "Asia/Tokyo";
+ json["options"][30] = "Asia/Yangon";
+ json["options"][31] = "Australia/Adelaide";
+ json["options"][32] = "Australia/Brisbane";
+ json["options"][33] = "Australia/Darwin";
+ json["options"][34] = "Australia/Hobart";
+ json["options"][35] = "Australia/Perth";
+ json["options"][36] = "Australia/Sydney";
+ json["options"][37] = "Europe/Berlin";
+ json["options"][38] = "Europe/Helsinki";
+ json["options"][39] = "Europe/Istanbul";
+ json["options"][40] = "Europe/London";
+ json["options"][41] = "Europe/Moscow";
+ json["options"][42] = "Pacific/Auckland";
+ json["options"][43] = "Pacific/Guam";
+ json["options"][44] = "Pacific/Honolulu";
+ json["options"][45] = "Pacific/Pago_Pago";
+ json["options"][46] = "None";
+
+ serializeJson(json, _buffer, _bufferSize);
+ String path = createHassTopicPath("select", "timezone", uidString);
+ _device->mqttPublish(path.c_str(), MQTT_QOS_LEVEL, true, _buffer);
+ }
+ else
+ {
+ removeHassTopic((char*)"select", (char*)"timezone", uidString);
+ }
+
+ if((int)basicOpenerConfigAclPrefs[11] == 1)
+ {
+ JsonDocument json;
+ json = createHassJson(uidString, "_operating_mode", "Operating mode", name, baseTopic, String("~") + mqtt_topic_config_basic_json, deviceType, "", "", "config", String("~") + mqtt_topic_config_action, {{ (char*)"val_tpl", (char*)"{{value_json.operatingMode}}" }, { (char*)"en", (char*)"true" }, { (char*)"cmd_tpl", (char*)"{ \"operatingMode\": \"{{ value }}\" }" }});
+ json["options"][0] = "Generic door opener";
+ json["options"][1] = "Analogue intercom";
+ json["options"][2] = "Digital intercom";
+ json["options"][3] = "Siedle";
+ json["options"][4] = "TCS";
+ json["options"][5] = "Bticino";
+ json["options"][6] = "Siedle HTS";
+ json["options"][7] = "STR";
+ json["options"][8] = "Ritto";
+ json["options"][9] = "Fermax";
+ json["options"][10] = "Comelit";
+ json["options"][11] = "Urmet BiBus";
+ json["options"][12] = "Urmet 2Voice";
+ json["options"][13] = "Golmar";
+ json["options"][14] = "SKS";
+ json["options"][15] = "Spare";
+ serializeJson(json, _buffer, _bufferSize);
+ String path = createHassTopicPath("select", "operating_mode", uidString);
+ _device->mqttPublish(path.c_str(), MQTT_QOS_LEVEL, true, _buffer);
+ }
+ else
+ {
+ removeHassTopic((char*)"select", (char*)"operating_mode", uidString);
+ }
+
+ if((int)advancedOpenerConfigAclPrefs[1] == 1)
+ {
+ // BUS mode switch analogue
+ publishHassTopic("switch",
+ "bus_mode_switch",
+ uidString,
+ "_bus_mode_switch",
+ "BUS mode switch analogue",
+ name,
+ baseTopic,
+ String("~") + mqtt_topic_config_advanced_json,
+ deviceType,
+ "",
+ "",
+ "config",
+ String("~") + mqtt_topic_config_action,
+ {
+ { (char*)"en", (char*)"true" },
+ { (char*)"pl_on", (char*)"{ \"busModeSwitch\": \"1\"}" },
+ { (char*)"pl_off", (char*)"{ \"busModeSwitch\": \"0\"}" },
+ { (char*)"val_tpl", (char*)"{{value_json.busModeSwitch}}" },
+ { (char*)"stat_on", (char*)"1" },
+ { (char*)"stat_off", (char*)"0" }
+ });
+ }
+ else
+ {
+ removeHassTopic((char*)"switch", (char*)"bus_mode_switch", uidString);
+ }
+
+ if((int)advancedOpenerConfigAclPrefs[2] == 1)
+ {
+ publishHassTopic("number",
+ "short_circuit_duration",
+ uidString,
+ "_short_circuit_duration",
+ "Short circuit duration",
+ name,
+ baseTopic,
+ String("~") + mqtt_topic_config_advanced_json,
+ deviceType,
+ "",
+ "",
+ "config",
+ String("~") + mqtt_topic_config_action,
+ {
+ { (char*)"en", (char*)"true" },
+ { (char*)"cmd_tpl", (char*)"{ \"shortCircuitDuration\": \"{{ value }}\" }" },
+ { (char*)"val_tpl", (char*)"{{value_json.shortCircuitDuration}}" },
+ { (char*)"min", (char*)"0" }
+ });
+ }
+ else
+ {
+ removeHassTopic((char*)"number", (char*)"short_circuit_duration", uidString);
+ }
+
+ if((int)advancedOpenerConfigAclPrefs[3] == 1)
+ {
+ publishHassTopic("number",
+ "electric_strike_delay",
+ uidString,
+ "_electric_strike_delay",
+ "Electric strike delay",
+ name,
+ baseTopic,
+ String("~") + mqtt_topic_config_advanced_json,
+ deviceType,
+ "",
+ "",
+ "config",
+ String("~") + mqtt_topic_config_action,
+ {
+ { (char*)"en", (char*)"true" },
+ { (char*)"cmd_tpl", (char*)"{ \"electricStrikeDelay\": \"{{ value }}\" }" },
+ { (char*)"val_tpl", (char*)"{{value_json.electricStrikeDelay}}" },
+ { (char*)"min", (char*)"0" },
+ { (char*)"max", (char*)"30000" },
+ { (char*)"step", (char*)"3000" }
+ });
+ }
+ else
+ {
+ removeHassTopic((char*)"number", (char*)"electric_strike_delay", uidString);
+ }
+
+ if((int)advancedOpenerConfigAclPrefs[4] == 1)
+ {
+ // Random Electric Strike Delay
+ publishHassTopic("switch",
+ "random_electric_strike_delay",
+ uidString,
+ "_random_electric_strike_delay",
+ "Random electric strike delay",
+ name,
+ baseTopic,
+ String("~") + mqtt_topic_config_advanced_json,
+ deviceType,
+ "",
+ "",
+ "config",
+ String("~") + mqtt_topic_config_action,
+ {
+ { (char*)"en", (char*)"true" },
+ { (char*)"pl_on", (char*)"{ \"randomElectricStrikeDelay\": \"1\"}" },
+ { (char*)"pl_off", (char*)"{ \"randomElectricStrikeDelay\": \"0\"}" },
+ { (char*)"val_tpl", (char*)"{{value_json.randomElectricStrikeDelay}}" },
+ { (char*)"stat_on", (char*)"1" },
+ { (char*)"stat_off", (char*)"0" }
+ });
+ }
+ else
+ {
+ removeHassTopic((char*)"switch", (char*)"random_electric_strike_delay", uidString);
+ }
+
+ if((int)advancedOpenerConfigAclPrefs[5] == 1)
+ {
+ publishHassTopic("number",
+ "electric_strike_duration",
+ uidString,
+ "_electric_strike_duration",
+ "Electric strike duration",
+ name,
+ baseTopic,
+ String("~") + mqtt_topic_config_advanced_json,
+ deviceType,
+ "",
+ "",
+ "config",
+ String("~") + mqtt_topic_config_action,
+ {
+ { (char*)"en", (char*)"true" },
+ { (char*)"cmd_tpl", (char*)"{ \"electricStrikeDuration\": \"{{ value }}\" }" },
+ { (char*)"val_tpl", (char*)"{{value_json.electricStrikeDuration}}" },
+ { (char*)"min", (char*)"1000" },
+ { (char*)"max", (char*)"30000" },
+ { (char*)"step", (char*)"3000" }
+ });
+ }
+ else
+ {
+ removeHassTopic((char*)"number", (char*)"electric_strike_duration", uidString);
+ }
+
+ if((int)advancedOpenerConfigAclPrefs[6] == 1)
+ {
+ // Disable RTO after ring
+ publishHassTopic("switch",
+ "disable_rto_after_ring",
+ uidString,
+ "_disable_rto_after_ring",
+ "Disable RTO after ring",
+ name,
+ baseTopic,
+ String("~") + mqtt_topic_config_advanced_json,
+ deviceType,
+ "",
+ "",
+ "config",
+ String("~") + mqtt_topic_config_action,
+ {
+ { (char*)"en", (char*)"true" },
+ { (char*)"pl_on", (char*)"{ \"disableRtoAfterRing\": \"1\"}" },
+ { (char*)"pl_off", (char*)"{ \"disableRtoAfterRing\": \"0\"}" },
+ { (char*)"val_tpl", (char*)"{{value_json.disableRtoAfterRing}}" },
+ { (char*)"stat_on", (char*)"1" },
+ { (char*)"stat_off", (char*)"0" }
+ });
+ }
+ else
+ {
+ removeHassTopic((char*)"switch", (char*)"disable_rto_after_ring", uidString);
+ }
+
+ if((int)advancedOpenerConfigAclPrefs[7] == 1)
+ {
+ publishHassTopic("number",
+ "rto_timeout",
+ uidString,
+ "_rto_timeout",
+ "RTO timeout",
+ name,
+ baseTopic,
+ String("~") + mqtt_topic_config_advanced_json,
+ deviceType,
+ "",
+ "",
+ "config",
+ String("~") + mqtt_topic_config_action,
+ {
+ { (char*)"en", (char*)"true" },
+ { (char*)"cmd_tpl", (char*)"{ \"rtoTimeout\": \"{{ value }}\" }" },
+ { (char*)"val_tpl", (char*)"{{value_json.rtoTimeout}}" },
+ { (char*)"min", (char*)"5" },
+ { (char*)"max", (char*)"60" }
+ });
+ }
+ else
+ {
+ removeHassTopic((char*)"number", (char*)"rto_timeout", uidString);
+ }
+
+ if((int)advancedOpenerConfigAclPrefs[8] == 1)
+ {
+ JsonDocument json;
+ json = createHassJson(uidString, "_doorbell_suppression", "Doorbell suppression", name, baseTopic, String("~") + mqtt_topic_config_advanced_json, deviceType, "", "", "config", String("~") + mqtt_topic_config_action, {{ (char*)"val_tpl", (char*)"{{value_json.doorbellSuppression}}" }, { (char*)"en", (char*)"true" }, { (char*)"cmd_tpl", (char*)"{ \"doorbellSuppression\": \"{{ value }}\" }" }});
+ json["options"][0] = "Off";
+ json["options"][1] = "CM";
+ json["options"][2] = "RTO";
+ json["options"][3] = "CM & RTO";
+ json["options"][4] = "Ring";
+ json["options"][5] = "CM & Ring";
+ json["options"][6] = "RTO & Ring";
+ json["options"][7] = "CM & RTO & Ring";
+ serializeJson(json, _buffer, _bufferSize);
+ String path = createHassTopicPath("select", "doorbell_suppression", uidString);
+ _device->mqttPublish(path.c_str(), MQTT_QOS_LEVEL, true, _buffer);
+ }
+ else
+ {
+ removeHassTopic((char*)"select", (char*)"doorbell_suppression", uidString);
+ }
+
+ if((int)advancedOpenerConfigAclPrefs[9] == 1)
+ {
+ publishHassTopic("number",
+ "doorbell_suppression_duration",
+ uidString,
+ "_doorbell_suppression_duration",
+ "Doorbell suppression duration",
+ name,
+ baseTopic,
+ String("~") + mqtt_topic_config_advanced_json,
+ deviceType,
+ "",
+ "",
+ "config",
+ String("~") + mqtt_topic_config_action,
+ {
+ { (char*)"en", (char*)"true" },
+ { (char*)"cmd_tpl", (char*)"{ \"doorbellSuppressionDuration\": \"{{ value }}\" }" },
+ { (char*)"val_tpl", (char*)"{{value_json.doorbellSuppressionDuration}}" },
+ { (char*)"min", (char*)"500" },
+ { (char*)"max", (char*)"10000" },
+ { (char*)"step", (char*)"1000" }
+ });
+ }
+ else
+ {
+ removeHassTopic((char*)"number", (char*)"doorbell_suppression_duration", uidString);
+ }
+
+ if((int)advancedOpenerConfigAclPrefs[10] == 1)
+ {
+ JsonDocument json;
+ json = createHassJson(uidString, "_sound_ring", "Sound ring", name, baseTopic, String("~") + mqtt_topic_config_advanced_json, deviceType, "", "", "config", String("~") + mqtt_topic_config_action, {{ (char*)"val_tpl", (char*)"{{value_json.soundRing}}" }, { (char*)"en", (char*)"true" }, { (char*)"cmd_tpl", (char*)"{ \"soundRing\": \"{{ value }}\" }" }});
+ json["options"][0] = "No Sound";
+ json["options"][1] = "Sound 1";
+ json["options"][2] = "Sound 2";
+ json["options"][3] = "Sound 3";
+ serializeJson(json, _buffer, _bufferSize);
+ String path = createHassTopicPath("select", "sound_ring", uidString);
+ _device->mqttPublish(path.c_str(), MQTT_QOS_LEVEL, true, _buffer);
+ }
+ else
+ {
+ removeHassTopic((char*)"select", (char*)"sound_ring", uidString);
+ }
+
+ if((int)advancedOpenerConfigAclPrefs[11] == 1)
+ {
+ JsonDocument json;
+ json = createHassJson(uidString, "_sound_open", "Sound open", name, baseTopic, String("~") + mqtt_topic_config_advanced_json, deviceType, "", "", "config", String("~") + mqtt_topic_config_action, {{ (char*)"val_tpl", (char*)"{{value_json.soundOpen}}" }, { (char*)"en", (char*)"true" }, { (char*)"cmd_tpl", (char*)"{ \"soundOpen\": \"{{ value }}\" }" }});
+ json["options"][0] = "No Sound";
+ json["options"][1] = "Sound 1";
+ json["options"][2] = "Sound 2";
+ json["options"][3] = "Sound 3";
+ serializeJson(json, _buffer, _bufferSize);
+ String path = createHassTopicPath("select", "sound_open", uidString);
+ _device->mqttPublish(path.c_str(), MQTT_QOS_LEVEL, true, _buffer);
+ }
+ else
+ {
+ removeHassTopic((char*)"select", (char*)"sound_open", uidString);
+ }
+
+ if((int)advancedOpenerConfigAclPrefs[12] == 1)
+ {
+ JsonDocument json;
+ json = createHassJson(uidString, "_sound_rto", "Sound RTO", name, baseTopic, String("~") + mqtt_topic_config_advanced_json, deviceType, "", "", "config", String("~") + mqtt_topic_config_action, {{ (char*)"val_tpl", (char*)"{{value_json.soundRto}}" }, { (char*)"en", (char*)"true" }, { (char*)"cmd_tpl", (char*)"{ \"soundRto\": \"{{ value }}\" }" }});
+ json["options"][0] = "No Sound";
+ json["options"][1] = "Sound 1";
+ json["options"][2] = "Sound 2";
+ json["options"][3] = "Sound 3";
+ serializeJson(json, _buffer, _bufferSize);
+ String path = createHassTopicPath("select", "sound_rto", uidString);
+ _device->mqttPublish(path.c_str(), MQTT_QOS_LEVEL, true, _buffer);
+ }
+ else
+ {
+ removeHassTopic((char*)"select", (char*)"sound_rto", uidString);
+ }
+
+ if((int)advancedOpenerConfigAclPrefs[13] == 1)
+ {
+ JsonDocument json;
+ json = createHassJson(uidString, "_sound_cm", "Sound CM", name, baseTopic, String("~") + mqtt_topic_config_advanced_json, deviceType, "", "", "config", String("~") + mqtt_topic_config_action, {{ (char*)"val_tpl", (char*)"{{value_json.soundCm}}" }, { (char*)"en", (char*)"true" }, { (char*)"cmd_tpl", (char*)"{ \"soundCm\": \"{{ value }}\" }" }});
+ json["options"][0] = "No Sound";
+ json["options"][1] = "Sound 1";
+ json["options"][2] = "Sound 2";
+ json["options"][3] = "Sound 3";
+ serializeJson(json, _buffer, _bufferSize);
+ String path = createHassTopicPath("select", "sound_cm", uidString);
+ _device->mqttPublish(path.c_str(), MQTT_QOS_LEVEL, true, _buffer);
+ }
+ else
+ {
+ removeHassTopic((char*)"select", (char*)"sound_cm", uidString);
+ }
+
+ if((int)advancedOpenerConfigAclPrefs[14] == 1)
+ {
+ // Sound confirmation
+ publishHassTopic("switch",
+ "sound_confirmation",
+ uidString,
+ "_sound_confirmation",
+ "Sound confirmation",
+ name,
+ baseTopic,
+ String("~") + mqtt_topic_config_advanced_json,
+ deviceType,
+ "",
+ "",
+ "config",
+ String("~") + mqtt_topic_config_action,
+ {
+ { (char*)"en", (char*)"true" },
+ { (char*)"pl_on", (char*)"{ \"soundConfirmation\": \"1\"}" },
+ { (char*)"pl_off", (char*)"{ \"soundConfirmation\": \"0\"}" },
+ { (char*)"val_tpl", (char*)"{{value_json.soundConfirmation}}" },
+ { (char*)"stat_on", (char*)"1" },
+ { (char*)"stat_off", (char*)"0" }
+ });
+ }
+ else
+ {
+ removeHassTopic((char*)"switch", (char*)"sound_confirmation", uidString);
+ }
+
+ if((int)advancedOpenerConfigAclPrefs[16] == 1)
+ {
+ JsonDocument json;
+ json = createHassJson(uidString, "_single_button_press_action", "Single button press action", name, baseTopic, String("~") + mqtt_topic_config_advanced_json, deviceType, "", "", "config", String("~") + mqtt_topic_config_action, {{ (char*)"val_tpl", (char*)"{{value_json.singleButtonPressAction}}" }, { (char*)"en", (char*)"true" }, { (char*)"cmd_tpl", (char*)"{ \"singleButtonPressAction\": \"{{ value }}\" }" }});
+ json["options"][0] = "No Action";
+ json["options"][1] = "Toggle RTO";
+ json["options"][2] = "Activate RTO";
+ json["options"][3] = "Deactivate RTO";
+ json["options"][4] = "Toggle CM";
+ json["options"][5] = "Activate CM";
+ json["options"][6] = "Deactivate CM";
+ json["options"][7] = "Open";
+ serializeJson(json, _buffer, _bufferSize);
+ String path = createHassTopicPath("select", "single_button_press_action", uidString);
+ _device->mqttPublish(path.c_str(), MQTT_QOS_LEVEL, true, _buffer);
+ }
+ else
+ {
+ removeHassTopic((char*)"select", (char*)"single_button_press_action", uidString);
+ }
+
+ if((int)advancedOpenerConfigAclPrefs[17] == 1)
+ {
+ JsonDocument json;
+ json = createHassJson(uidString, "_double_button_press_action", "Double button press action", name, baseTopic, String("~") + mqtt_topic_config_advanced_json, deviceType, "", "", "config", String("~") + mqtt_topic_config_action, {{ (char*)"val_tpl", (char*)"{{value_json.doubleButtonPressAction}}" }, { (char*)"en", (char*)"true" }, { (char*)"cmd_tpl", (char*)"{ \"doubleButtonPressAction\": \"{{ value }}\" }" }});
+ json["options"][0] = "No Action";
+ json["options"][1] = "Toggle RTO";
+ json["options"][2] = "Activate RTO";
+ json["options"][3] = "Deactivate RTO";
+ json["options"][4] = "Toggle CM";
+ json["options"][5] = "Activate CM";
+ json["options"][6] = "Deactivate CM";
+ json["options"][7] = "Open";
+ serializeJson(json, _buffer, _bufferSize);
+ String path = createHassTopicPath("select", "double_button_press_action", uidString);
+ _device->mqttPublish(path.c_str(), MQTT_QOS_LEVEL, true, _buffer);
+ }
+ else
+ {
+ removeHassTopic((char*)"select", (char*)"double_button_press_action", uidString);
+ }
+
+ if((int)advancedOpenerConfigAclPrefs[18] == 1)
+ {
+ JsonDocument json;
+ json = createHassJson(uidString, "_battery_type", "Battery type", name, baseTopic, String("~") + mqtt_topic_config_advanced_json, deviceType, "", "", "config", String("~") + mqtt_topic_config_action, {{ (char*)"val_tpl", (char*)"{{value_json.batteryType}}" }, { (char*)"en", (char*)"true" }, { (char*)"cmd_tpl", (char*)"{ \"batteryType\": \"{{ value }}\" }" }});
+ json["options"][0] = "Alkali";
+ json["options"][1] = "Accumulators";
+ json["options"][2] = "Lithium";
+ serializeJson(json, _buffer, _bufferSize);
+ String path = createHassTopicPath("select", "battery_type", uidString);
+ _device->mqttPublish(path.c_str(), MQTT_QOS_LEVEL, true, _buffer);
+ }
+ else
+ {
+ removeHassTopic((char*)"select", (char*)"battery_type", uidString);
+ }
+
+ if((int)advancedOpenerConfigAclPrefs[19] == 1)
+ {
+ // Automatic battery type detection
+ publishHassTopic("switch",
+ "automatic_battery_type_detection",
+ uidString,
+ "_automatic_battery_type_detection",
+ "Automatic battery type detection",
+ name,
+ baseTopic,
+ String("~") + mqtt_topic_config_advanced_json,
+ deviceType,
+ "",
+ "",
+ "config",
+ String("~") + mqtt_topic_config_action,
+ {
+ { (char*)"en", (char*)"true" },
+ { (char*)"pl_on", (char*)"{ \"automaticBatteryTypeDetection\": \"1\"}" },
+ { (char*)"pl_off", (char*)"{ \"automaticBatteryTypeDetection\": \"0\"}" },
+ { (char*)"val_tpl", (char*)"{{value_json.automaticBatteryTypeDetection}}" },
+ { (char*)"stat_on", (char*)"1" },
+ { (char*)"stat_off", (char*)"0" }
+ });
+ }
+ else
+ {
+ removeHassTopic((char*)"switch", (char*)"automatic_battery_type_detection", uidString);
+ }
+}
+
+void HomeAssistantDiscovery::publishHASSConfigAccessLog(char *deviceType, const char *baseTopic, char *name, char *uidString)
+{
+ publishHassTopic("sensor",
+ "last_action_authorization",
+ uidString,
+ "_last_action_authorization",
+ "Last action authorization",
+ name,
+ baseTopic,
+ String("~") + mqtt_topic_lock_log,
+ deviceType,
+ "",
+ "",
+ "diagnostic",
+ "",
+ {
+ { (char*)"ic", (char*)"mdi:format-list-bulleted" },
+ { (char*)"val_tpl", (char*)"{{ (value_json|selectattr('type', 'eq', 'LockAction')|selectattr('action', 'in', ['Lock', 'Unlock', 'Unlatch'])|first|default).authorizationName|default }}" }
+ });
+
+ String rollingSate = "~";
+ rollingSate.concat(mqtt_topic_lock_log_rolling);
+
+ publishHassTopic("sensor",
+ "rolling_log",
+ uidString,
+ "_rolling_log",
+ "Rolling authorization log",
+ name,
+ baseTopic,
+ String("~") + mqtt_topic_lock_log_rolling,
+ deviceType,
+ "",
+ "",
+ "diagnostic",
+ "",
+ {
+ { (char*)"ic", (char*)"mdi:format-list-bulleted" },
+ { (char*)"json_attr_t", (char*)rollingSate.c_str() },
+ { (char*)"val_tpl", (char*)"{{value_json.index}}" }
+ });
+}
+
+void HomeAssistantDiscovery::publishHASSConfigKeypad(char *deviceType, const char *baseTopic, char *name, char *uidString)
+{
+ // Keypad battery critical
+ publishHassTopic("binary_sensor",
+ "keypad_battery_low",
+ uidString,
+ "_keypad_battery_low",
+ "Keypad battery low",
+ name,
+ baseTopic,
+ String("~") + mqtt_topic_battery_basic_json,
+ deviceType,
+ "battery",
+ "",
+ "diagnostic",
+ "",
+ {
+ {(char*)"pl_on", (char*)"1"},
+ {(char*)"pl_off", (char*)"0"},
+ {(char*)"val_tpl", (char*)"{{value_json.keypadCritical}}" }
+ });
+
+ // Query Keypad
+ publishHassTopic("button",
+ "query_keypad",
+ uidString,
+ "_query_keypad",
+ "Query keypad",
+ name,
+ baseTopic,
+ "",
+ deviceType,
+ "",
+ "",
+ "diagnostic",
+ String("~") + mqtt_topic_query_keypad,
+ {
+ { (char*)"en", (char*)"false" },
+ { (char*)"pl_prs", (char*)"1" }
+ });
+
+ publishHassTopic("sensor",
+ "keypad_status",
+ uidString,
+ "_keypad_stats",
+ "Keypad status",
+ name,
+ baseTopic,
+ String("~") + mqtt_topic_lock_log,
+ deviceType,
+ "",
+ "",
+ "diagnostic",
+ "",
+ {
+ { (char*)"ic", (char*)"mdi:drag-vertical" },
+ { (char*)"val_tpl", (char*)"{{ (value_json|selectattr('type', 'eq', 'KeypadAction')|first|default).completionStatus|default }}" }
+ });
+}
+
+void HomeAssistantDiscovery::publishHassTopic(const String& mqttDeviceType,
+ const String& mqttDeviceName,
+ const String& uidString,
+ const String& uidStringPostfix,
+ const String& displayName,
+ const String& name,
+ const String& baseTopic,
+ const String& stateTopic,
+ const String& deviceType,
+ const String& deviceClass,
+ const String& stateClass,
+ const String& entityCat,
+ const String& commandTopic,
+ std::vector> additionalEntries
+ )
+{
+ if (_discoveryTopic != "")
+ {
+ JsonDocument json;
+ json = createHassJson(uidString, uidStringPostfix, displayName, name, baseTopic, stateTopic, deviceType, deviceClass, stateClass, entityCat, commandTopic, additionalEntries);
+ serializeJson(json, _buffer, _bufferSize);
+ String path = createHassTopicPath(mqttDeviceType, mqttDeviceName, uidString);
+ _device->mqttPublish(path.c_str(), MQTT_QOS_LEVEL, true, _buffer);
+ }
+}
+
+String HomeAssistantDiscovery::createHassTopicPath(const String& mqttDeviceType, const String& mqttDeviceName, const String& uidString)
+{
+ String path = _discoveryTopic;
+ path.concat("/");
+ path.concat(mqttDeviceType);
+ path.concat("/");
+ path.concat(uidString);
+ path.concat("/");
+ path.concat(mqttDeviceName);
+ path.concat("/config");
+
+ return path;
+}
+
+void HomeAssistantDiscovery::removeHassTopic(const String& mqttDeviceType, const String& mqttDeviceName, const String& uidString)
+{
+ if (_discoveryTopic != "")
+ {
+ String path = createHassTopicPath(mqttDeviceType, mqttDeviceName, uidString);
+ _device->mqttPublish(path.c_str(), MQTT_QOS_LEVEL, true, "");
+ }
+}
+
+void HomeAssistantDiscovery::removeHASSConfig(char* uidString)
+{
+ removeHassTopic((char*)"lock", (char*)"smartlock", uidString);
+ removeHassTopic((char*)"binary_sensor", (char*)"battery_low", uidString);
+ removeHassTopic((char*)"binary_sensor", (char*)"keypad_battery_low", uidString);
+ removeHassTopic((char*)"sensor", (char*)"battery_voltage", uidString);
+ removeHassTopic((char*)"sensor", (char*)"trigger", uidString);
+ removeHassTopic((char*)"binary_sensor", (char*)"mqtt_connected", uidString);
+ removeHassTopic((char*)"switch", (char*)"reset", uidString);
+ removeHassTopic((char*)"sensor", (char*)"firmware_version", uidString);
+ removeHassTopic((char*)"sensor", (char*)"hardware_version", uidString);
+ removeHassTopic((char*)"sensor", (char*)"nuki_hub_version", uidString);
+ removeHassTopic((char*)"sensor", (char*)"nuki_hub_build", uidString);
+ removeHassTopic((char*)"sensor", (char*)"nuki_hub_latest", uidString);
+ removeHassTopic((char*)"update", (char*)"nuki_hub_update", uidString);
+ removeHassTopic((char*)"sensor", (char*)"nuki_hub_ip", uidString);
+ removeHassTopic((char*)"button", (char*)"unlatch", uidString);
+ removeHassTopic((char*)"button", (char*)"lockngo", uidString);
+ removeHassTopic((char*)"button", (char*)"lockngounlatch", uidString);
+ removeHassTopic((char*)"sensor", (char*)"battery_level", uidString);
+ removeHassTopic((char*)"binary_sensor", (char*)"door_sensor", uidString);
+ removeHassTopic((char*)"binary_sensor", (char*)"ring_detect", uidString);
+ removeHassTopic((char*)"sensor", (char*)"sound_level", uidString);
+ removeHassTopic((char*)"sensor", (char*)"last_action_authorization", uidString);
+ removeHassTopic((char*)"sensor", (char*)"keypad_status", uidString);
+ removeHassTopic((char*)"sensor", (char*)"rolling_log", uidString);
+ removeHassTopic((char*)"sensor", (char*)"wifi_signal_strength", uidString);
+ removeHassTopic((char*)"sensor", (char*)"bluetooth_signal_strength", uidString);
+ removeHassTopic((char*)"binary_sensor", (char*)"continuous_mode", uidString);
+ removeHassTopic((char*)"switch", (char*)"continuous_mode", uidString);
+ removeHassTopic((char*)"button", (char*)"query_lockstate", uidString);
+ removeHassTopic((char*)"button", (char*)"query_config", uidString);
+ removeHassTopic((char*)"button", (char*)"query_keypad", uidString);
+ removeHassTopic((char*)"button", (char*)"query_battery", uidString);
+ removeHassTopic((char*)"button", (char*)"query_commandresult", uidString);
+ removeHassTopic((char*)"switch", (char*)"auto_lock", uidString);
+ removeHassTopic((char*)"switch", (char*)"auto_unlock", uidString);
+ removeHassTopic((char*)"switch", (char*)"double_lock", uidString);
+ removeHassTopic((char*)"switch", (char*)"automatic_battery_type_detection", uidString);
+ removeHassTopic((char*)"select", (char*)"battery_type", uidString);
+ removeHassTopic((char*)"select", (char*)"double_button_press_action", uidString);
+ removeHassTopic((char*)"select", (char*)"single_button_press_action", uidString);
+ removeHassTopic((char*)"switch", (char*)"sound_confirmation", uidString);
+ removeHassTopic((char*)"select", (char*)"sound_cm", uidString);
+ removeHassTopic((char*)"select", (char*)"sound_rto", uidString);
+ removeHassTopic((char*)"select", (char*)"sound_open", uidString);
+ removeHassTopic((char*)"select", (char*)"sound_ring", uidString);
+ removeHassTopic((char*)"number", (char*)"doorbell_suppression_duration", uidString);
+ removeHassTopic((char*)"select", (char*)"doorbell_suppression", uidString);
+ removeHassTopic((char*)"number", (char*)"rto_timeout", uidString);
+ removeHassTopic((char*)"switch", (char*)"disable_rto_after_ring", uidString);
+ removeHassTopic((char*)"number", (char*)"electric_strike_duration", uidString);
+ removeHassTopic((char*)"switch", (char*)"random_electric_strike_delay", uidString);
+ removeHassTopic((char*)"number", (char*)"electric_strike_delay", uidString);
+ removeHassTopic((char*)"number", (char*)"short_circuit_duration", uidString);
+ removeHassTopic((char*)"switch", (char*)"bus_mode_switch", uidString);
+ removeHassTopic((char*)"select", (char*)"operating_mode", uidString);
+ removeHassTopic((char*)"select", (char*)"timezone", uidString);
+ removeHassTopic((char*)"select", (char*)"advertising_mode", uidString);
+ removeHassTopic((char*)"select", (char*)"fob_action_3", uidString);
+ removeHassTopic((char*)"select", (char*)"fob_action_2", uidString);
+ removeHassTopic((char*)"select", (char*)"fob_action_1", uidString);
+ removeHassTopic((char*)"switch", (char*)"dst_mode", uidString);
+ removeHassTopic((char*)"number", (char*)"timezone_offset", uidString);
+ removeHassTopic((char*)"switch", (char*)"pairing_enabled", uidString);
+ removeHassTopic((char*)"number", (char*)"sound_level", uidString);
+ removeHassTopic((char*)"switch", (char*)"button_enabled", uidString);
+ removeHassTopic((char*)"switch", (char*)"led_enabled", uidString);
+ removeHassTopic((char*)"number", (char*)"led_brightness", uidString);
+ removeHassTopic((char*)"switch", (char*)"auto_update_enabled", uidString);
+ removeHassTopic((char*)"switch", (char*)"immediate_auto_lock_enabled", uidString);
+ removeHassTopic((char*)"switch", (char*)"nightmode_immediate_lock_start", uidString);
+ removeHassTopic((char*)"switch", (char*)"nightmode_auto_unlock", uidString);
+ removeHassTopic((char*)"switch", (char*)"nightmode_auto_lock", uidString);
+ removeHassTopic((char*)"text", (char*)"nightmode_end_time", uidString);
+ removeHassTopic((char*)"text", (char*)"nightmode_start_time", uidString);
+ removeHassTopic((char*)"switch", (char*)"nightmode_enabled", uidString);
+ removeHassTopic((char*)"number", (char*)"auto_lock_timeout", uidString);
+ removeHassTopic((char*)"number", (char*)"unlatch_duration", uidString);
+ removeHassTopic((char*)"switch", (char*)"detached_cylinder", uidString);
+ removeHassTopic((char*)"number", (char*)"lockngo_timeout", uidString);
+ removeHassTopic((char*)"number", (char*)"unlocked_locked_transition_offset_degrees", uidString);
+ removeHassTopic((char*)"number", (char*)"single_locked_position_offset_degrees", uidString);
+ removeHassTopic((char*)"number", (char*)"locked_position_offset_degrees", uidString);
+ removeHassTopic((char*)"number", (char*)"unlocked_position_offset_degrees", uidString);
+ removeHassTopic((char*)"switch", (char*)"pairing_enabled", uidString);
+ removeHassTopic((char*)"switch", (char*)"auto_unlatch", uidString);
+ removeHassTopic((char*)"sensor", (char*)"network_device", uidString);
+ removeHassTopic((char*)"switch", (char*)"webserver", uidString);
+ removeHassTopic((char*)"sensor", (char*)"uptime", uidString);
+ removeHassTopic((char*)"sensor", (char*)"mqtt_log", uidString);
+ removeHassTopic((char*)"binary_sensor", (char*)"hybrid_connected", uidString);
+ removeHassTopic((char*)"sensor", (char*)"nuki_hub_restart_reason", uidString);
+ removeHassTopic((char*)"sensor", (char*)"nuki_hub_restart_reason_esp", uidString);
+}
+
+void HomeAssistantDiscovery::removeHASSConfigTopic(char *deviceType, char *name, char *uidString)
+{
+ removeHassTopic(deviceType, name, uidString);
+}
+
+JsonDocument HomeAssistantDiscovery::createHassJson(const String& uidString,
+ const String& uidStringPostfix,
+ const String& displayName,
+ const String& name,
+ const String& baseTopic,
+ const String& stateTopic,
+ const String& deviceType,
+ const String& deviceClass,
+ const String& stateClass,
+ const String& entityCat,
+ const String& commandTopic,
+ std::vector> additionalEntries
+ )
+{
+ JsonDocument json;
+ json.clear();
+ JsonObject dev = json["dev"].to();
+ JsonArray ids = dev["ids"].to();
+ ids.add(String("nuki_") + uidString);
+
+ json["~"] = baseTopic;
+ json["name"] = displayName;
+ json["unique_id"] = String(uidString) + uidStringPostfix;
+
+ if(deviceClass != "")
+ {
+ json["dev_cla"] = deviceClass;
+ }
+
+ if(stateTopic != "")
+ {
+ json["stat_t"] = stateTopic;
+ }
+
+ if(stateClass != "")
+ {
+ json["stat_cla"] = stateClass;
+ }
+
+ if(entityCat != "")
+ {
+ json["ent_cat"] = entityCat;
+ }
+
+ if(commandTopic != "")
+ {
+ json["cmd_t"] = commandTopic;
+ }
+
+ json["avty"]["t"] = _baseTopic + mqtt_topic_mqtt_connection_state;
+
+ for(const auto& entry : additionalEntries)
+ {
+ if(strcmp(entry.second, "true") == 0)
+ {
+ json[entry.first] = true;
+ }
+ else if(strcmp(entry.second, "false") == 0)
+ {
+ json[entry.first] = false;
+ }
+ else
+ {
+ json[entry.first] = entry.second;
+ }
+ }
+
+ return json;
+}
diff --git a/src/HomeAssistantDiscovery.h b/src/HomeAssistantDiscovery.h
new file mode 100644
index 0000000..967de52
--- /dev/null
+++ b/src/HomeAssistantDiscovery.h
@@ -0,0 +1,74 @@
+#pragma once
+#include
+#include
+#include "networkDevices/NetworkDevice.h"
+
+class HomeAssistantDiscovery
+{
+public:
+ explicit HomeAssistantDiscovery(NetworkDevice* device, Preferences* preferences, char* buffer, size_t bufferSize);
+ void setupHASS(int type, uint32_t nukiId, char* nukiName, const char* firmwareVersion, const char* hardwareVersion, bool hasDoorSensor, bool hasKeypad);
+ void disableHASS();
+ void removeHassTopic(const String& mqttDeviceType, const String& mqttDeviceName, const String& uidString);
+ void publishHassTopic(const String& mqttDeviceType,
+ const String& mqttDeviceName,
+ const String& uidString,
+ const String& uidStringPostfix,
+ const String& displayName,
+ const String& name,
+ const String& baseTopic,
+ const String& stateTopic,
+ const String& deviceType,
+ const String& deviceClass,
+ const String& stateClass = "",
+ const String& entityCat = "",
+ const String& commandTopic = "",
+ std::vector> additionalEntries = {}
+ );
+private:
+ void publishHASSConfig(char *deviceType, const char *baseTopic, char *name, char *uidString, const char *softwareVersion, const char *hardwareVersion, const bool& hasDoorSensor, const bool& hasKeypad, const bool& publishAuthData, char *lockAction, char *unlockAction, char *openAction);
+ void publishHASSDeviceConfig(char* deviceType, const char* baseTopic, char* name, char* uidString, const char *softwareVersion, const char *hardwareVersion, const char* availabilityTopic, const bool& hasKeypad, char* lockAction, char* unlockAction, char* openAction);
+ void publishHASSNukiHubConfig();
+
+ void publishHASSConfigAdditionalLockEntities(char* deviceType, const char* baseTopic, char* name, char* uidString);
+ void publishHASSConfigDoorSensor(char* deviceType, const char* baseTopic, char* name, char* uidString);
+ void publishHASSConfigAdditionalOpenerEntities(char* deviceType, const char* baseTopic, char* name, char* uidString);
+ void publishHASSConfigAccessLog(char* deviceType, const char* baseTopic, char* name, char* uidString);
+ void publishHASSConfigKeypad(char* deviceType, const char* baseTopic, char* name, char* uidString);
+ void publishHASSConfigWifiRssi(char* deviceType, const char* baseTopic, char* name, char* uidString);
+
+
+ void removeHASSConfig(char* uidString);
+ void removeHASSConfigTopic(char* deviceType, char* name, char* uidString);
+
+ String createHassTopicPath(const String& mqttDeviceType, const String& mqttDeviceName, const String& uidString);
+ JsonDocument createHassJson(const String& uidString,
+ const String& uidStringPostfix,
+ const String& displayName,
+ const String& name,
+ const String& baseTopic,
+ const String& stateTopic,
+ const String& deviceType,
+ const String& deviceClass,
+ const String& stateClass = "",
+ const String& entityCat = "",
+ const String& commandTopic = "",
+ std::vector> additionalEntries = {}
+ );
+
+ NetworkDevice* _device = nullptr;
+ Preferences* _preferences = nullptr;
+
+ String _discoveryTopic;
+ String _baseTopic;
+ String _hostname;
+
+ char _nukiHubUidString[20];
+
+ bool _offEnabled = false;
+ bool _checkUpdates = false;
+ bool _updateFromMQTT = false;
+
+ char* _buffer;
+ const size_t _bufferSize;
+};
\ No newline at end of file
diff --git a/src/MqttReceiver.h b/src/MqttReceiver.h
index 3db350d..e442919 100644
--- a/src/MqttReceiver.h
+++ b/src/MqttReceiver.h
@@ -1,7 +1,5 @@
#pragma once
-#include
-
class MqttReceiver
{
public:
diff --git a/src/MqttTopics.h b/src/MqttTopics.h
index f842b13..1171ae0 100644
--- a/src/MqttTopics.h
+++ b/src/MqttTopics.h
@@ -110,7 +110,7 @@
#define mqtt_topic_restart_reason_esp "/maintenance/restartReasonNukiEsp"
#define mqtt_topic_mqtt_connection_state "/maintenance/mqttConnectionState"
#define mqtt_topic_network_device "/maintenance/networkDevice"
-#define mqtt_hybrid_state "/hybridConnected"
+#define mqtt_topic_hybrid_state "/hybridConnected"
#define mqtt_topic_gpio_prefix "/gpio"
#define mqtt_topic_gpio_pin "/pin_"
diff --git a/src/NukiNetwork.cpp b/src/NukiNetwork.cpp
index 23cc9fa..730cf04 100644
--- a/src/NukiNetwork.cpp
+++ b/src/NukiNetwork.cpp
@@ -11,10 +11,6 @@
#endif
#include "networkDevices/EthernetDevice.h"
-#ifndef NUKI_HUB_UPDATER
-#include
-#endif
-
NukiNetwork* NukiNetwork::_inst = nullptr;
extern bool wifiFallback;
@@ -42,7 +38,6 @@ NukiNetwork::NukiNetwork(Preferences *preferences)
_inst = this;
_webEnabled = _preferences->getBool(preference_webserver_enabled, true);
- _updateFromMQTT = _preferences->getBool(preference_update_from_mqtt, false);
#ifndef NUKI_HUB_UPDATER
memset(_maintenancePathPrefix, 0, sizeof(_maintenancePathPrefix));
@@ -146,7 +141,10 @@ void NukiNetwork::setupDevice()
{
onMqttDisconnect(reason);
});
+
+ _hadiscovery = new HomeAssistantDiscovery(_device, _preferences, _buffer, _bufferSize);
#endif
+
}
void NukiNetwork::reconfigureDevice()
@@ -244,7 +242,7 @@ void NukiNetwork::initialize()
{
_nukiHubPath[i] = mqttPath.charAt(i);
}
-
+
_hostname = _preferences->getString(preference_hostname, "");
if(_hostname == "")
@@ -337,8 +335,6 @@ void NukiNetwork::initialize()
}
}
- _discoveryTopic = _preferences->getString(preference_mqtt_hass_discovery, "");
- _offEnabled = _preferences->getBool(preference_official_hybrid_enabled, false);
readSettings();
}
}
@@ -638,7 +634,7 @@ bool NukiNetwork::reconnect()
_device->mqttSetCredentials(_mqttUser, _mqttPass);
}
- _device->setWill(_mqttConnectionStateTopic, 1, true, _lastWillPayload);
+ _device->mqttSetWill(_mqttConnectionStateTopic, 1, true, _lastWillPayload);
_device->mqttSetServer(_mqttBrokerAddr, _mqttPort);
_device->mqttConnect();
@@ -681,7 +677,12 @@ bool NukiNetwork::reconnect()
publishString(_maintenancePathPrefix, mqtt_topic_network_device, _device->deviceName().c_str(), true);
for(const auto& it : _initTopics)
{
- _device->mqttPublish(it.first.c_str(), MQTT_QOS_LEVEL, true, it.second.c_str());
+ publish(it.first.c_str(), it.second.c_str(), true);
+ }
+
+ if(_preferences->getBool(preference_mqtt_hass_enabled, false))
+ {
+ setupHASS(0, 0, {0}, {0}, {0}, false, false);
}
}
@@ -701,8 +702,7 @@ bool NukiNetwork::reconnect()
}
else
{
- Log->print(F("MQTT connect failed, rc="));
- _device->printError();
+ Log->print(F("MQTT connect failed"));
_mqttConnectionState = 0;
_nextReconnect = espMillis() + 5000;
//_device->mqttDisconnect(true);
@@ -803,7 +803,7 @@ void NukiNetwork::onMqttDataReceived(const espMqttClientTypes::MessageProperties
if(_mqttConnectedTs == -1 || (millis() - _mqttConnectedTs < 2000)) return;
parseGpioTopics(properties, topic, payload, len, index, total);
-
+
onMqttDataReceived(topic, (byte*)payload, index);
for(auto receiver : _mqttReceivers)
@@ -815,7 +815,7 @@ void NukiNetwork::onMqttDataReceived(const espMqttClientTypes::MessageProperties
void NukiNetwork::onMqttDataReceived(const char* topic, byte* payload, const unsigned int length)
{
char* data = (char*)payload;
-
+
if(comparePrefixedPath(topic, mqtt_topic_reset) && strcmp(data, "1") == 0)
{
Log->println(F("Restart requested via MQTT."));
@@ -959,7 +959,7 @@ void NukiNetwork::onMqttDataReceived(const char* topic, byte* payload, const uns
clearWifiFallback();
delay(200);
restartEsp(RestartReason::ReconfigureWebServer);
- }
+ }
}
void NukiNetwork::parseGpioTopics(const espMqttClientTypes::MessageProperties &properties, const char *topic, const uint8_t *payload, size_t& len, size_t& index, size_t& total)
@@ -1026,7 +1026,7 @@ void NukiNetwork::publishFloat(const char* prefix, const char* topic, const floa
dtostrf(value, 0, precision, str);
char path[200] = {0};
buildMqttPath(path, { prefix, topic });
- _device->mqttPublish(path, MQTT_QOS_LEVEL, retain, str);
+ publish(path, str, retain);
}
void NukiNetwork::publishInt(const char* prefix, const char *topic, const int value, bool retain)
@@ -1035,7 +1035,7 @@ void NukiNetwork::publishInt(const char* prefix, const char *topic, const int va
itoa(value, str, 10);
char path[200] = {0};
buildMqttPath(path, { prefix, topic });
- _device->mqttPublish(path, MQTT_QOS_LEVEL, retain, str);
+ publish(path, str, retain);
}
void NukiNetwork::publishUInt(const char* prefix, const char *topic, const unsigned int value, bool retain)
@@ -1044,7 +1044,7 @@ void NukiNetwork::publishUInt(const char* prefix, const char *topic, const unsig
utoa(value, str, 10);
char path[200] = {0};
buildMqttPath(path, { prefix, topic });
- _device->mqttPublish(path, MQTT_QOS_LEVEL, retain, str);
+ publish(path, str, retain);
}
void NukiNetwork::publishULong(const char* prefix, const char *topic, const unsigned long value, bool retain)
@@ -1053,7 +1053,7 @@ void NukiNetwork::publishULong(const char* prefix, const char *topic, const unsi
utoa(value, str, 10);
char path[200] = {0};
buildMqttPath(path, { prefix, topic });
- _device->mqttPublish(path, MQTT_QOS_LEVEL, retain, str);
+ publish(path, str, retain);
}
void NukiNetwork::publishLongLong(const char* prefix, const char *topic, int64_t value, bool retain)
@@ -1074,7 +1074,7 @@ void NukiNetwork::publishLongLong(const char* prefix, const char *topic, int64_t
}
char path[200] = {0};
buildMqttPath(path, { prefix, topic });
- _device->mqttPublish(path, MQTT_QOS_LEVEL, retain, result);
+ publish(path, result, retain);
}
void NukiNetwork::publishBool(const char* prefix, const char *topic, const bool value, bool retain)
@@ -1083,2718 +1083,41 @@ void NukiNetwork::publishBool(const char* prefix, const char *topic, const bool
str[0] = value ? '1' : '0';
char path[200] = {0};
buildMqttPath(path, { prefix, topic });
- _device->mqttPublish(path, MQTT_QOS_LEVEL, retain, str);
+ publish(path, str, retain);
}
void NukiNetwork::publishString(const char* prefix, const char *topic, const char *value, bool retain)
{
char path[200] = {0};
buildMqttPath(path, { prefix, topic });
- _device->mqttPublish(path, MQTT_QOS_LEVEL, retain, value);
+ publish(path, value, retain);
}
-void NukiNetwork::publishHASSConfig(char* deviceType, const char* baseTopic, char* name, char* uidString, const char *softwareVersion, const char *hardwareVersion, const char* availabilityTopic, const bool& hasKeypad, char* lockAction, char* unlockAction, char* openAction)
+void NukiNetwork::publish(const char *topic, const char *value, bool retain)
{
- JsonDocument json;
- json.clear();
- JsonObject dev = json["dev"].to();
- JsonArray ids = dev["ids"].to();
- ids.add(String("nuki_") + uidString);
- json["dev"]["mf"] = "Nuki";
- json["dev"]["mdl"] = deviceType;
- json["dev"]["name"] = name;
- json["dev"]["sw"] = softwareVersion;
- json["dev"]["hw"] = hardwareVersion;
-
- String cuUrl = _preferences->getString(preference_mqtt_hass_cu_url, "");
-
- if (cuUrl != "")
- {
- json["dev"]["cu"] = cuUrl;
- }
- else
- {
- json["dev"]["cu"] = "http://" + _device->localIP();
- }
-
- json["~"] = baseTopic;
- json["name"] = nullptr;
- json["unique_id"] = String(uidString) + "_lock";
- json["cmd_t"] = String("~") + String(mqtt_topic_lock_action);
- json["avty"][0]["t"] = availabilityTopic;
- json["pl_lock"] = lockAction;
- json["pl_unlk"] = unlockAction;
-
- uint32_t aclPrefs[17];
- _preferences->getBytes(preference_acl, &aclPrefs, sizeof(aclPrefs));
-
- if((strcmp(deviceType, "SmartLock") == 0 && (int)aclPrefs[2]) || (strcmp(deviceType, "SmartLock") != 0 && (int)aclPrefs[11]))
- {
- json["pl_open"] = openAction;
- }
-
- json["stat_t"] = String("~") + mqtt_topic_lock_ha_state;
- json["stat_jam"] = "jammed";
- json["stat_locked"] = "locked";
- json["stat_locking"] = "locking";
- json["stat_unlocked"] = "unlocked";
- json["stat_unlocking"] = "unlocking";
- json["stat_open"] = "open";
- json["stat_opening"] = "opening";
- json["opt"] = "false";
-
- serializeJson(json, _buffer, _bufferSize);
-
- String path = _preferences->getString(preference_mqtt_hass_discovery, "homeassistant");
- path.concat("/lock/");
- path.concat(uidString);
- path.concat("/smartlock/config");
-
- _device->mqttPublish(path.c_str(), MQTT_QOS_LEVEL, true, _buffer);
-
- // Battery critical
- publishHassTopic("binary_sensor",
- "battery_low",
- uidString,
- "_battery_low",
- "Battery low",
- name,
- baseTopic,
- String("~") + mqtt_topic_battery_basic_json,
- deviceType,
- "battery",
- "",
- "diagnostic",
- "",
- {
- {(char*)"pl_on", (char*)"1"},
- {(char*)"pl_off", (char*)"0"},
- {(char*)"val_tpl", (char*)"{{value_json.critical}}" }
- });
-
- // Battery voltage
- publishHassTopic("sensor",
- "battery_voltage",
- uidString,
- "_battery_voltage",
- "Battery voltage",
- name,
- baseTopic,
- String("~") + mqtt_topic_battery_advanced_json,
- deviceType,
- "voltage",
- "measurement",
- "diagnostic",
- "",
- {
- {(char*)"unit_of_meas", (char*)"V"},
- {(char*)"val_tpl", (char*)"{{value_json.batteryVoltage}}" }
- });
-
- // Trigger
- publishHassTopic("sensor",
- "trigger",
- uidString,
- "_trigger",
- "Trigger",
- name,
- baseTopic,
- String("~") + mqtt_topic_lock_trigger,
- deviceType,
- "",
- "",
- "diagnostic",
- "",
- { { (char*)"en", (char*)"true" } });
-
- // MQTT Connected
- publishHassTopic("binary_sensor",
- "mqtt_connected",
- uidString,
- "_mqtt_connected",
- "MQTT connected",
- name,
- baseTopic,
- _lockPath + mqtt_topic_mqtt_connection_state,
- deviceType,
- "",
- "",
- "diagnostic",
- "",
- {
- {(char*)"pl_on", (char*)"online"},
- {(char*)"pl_off", (char*)"offline"},
- {(char*)"ic", (char*)"mdi:lan-connect"}
- });
-
- // Reset
- publishHassTopic("switch",
- "reset",
- uidString,
- "_reset",
- "Restart Nuki Hub",
- name,
- baseTopic,
- _lockPath + mqtt_topic_reset,
- deviceType,
- "",
- "",
- "diagnostic",
- _lockPath + mqtt_topic_reset,
- {
- { (char*)"ic", (char*)"mdi:restart" },
- { (char*)"pl_on", (char*)"1" },
- { (char*)"pl_off", (char*)"0" },
- { (char*)"stat_on", (char*)"1" },
- { (char*)"stat_off", (char*)"0" }
- });
-
- // Network device
- publishHassTopic("sensor",
- "network_device",
- uidString,
- "_network_device",
- "Network device",
- name,
- baseTopic,
- _lockPath + mqtt_topic_network_device,
- deviceType,
- "",
- "",
- "diagnostic",
- "",
- { { (char*)"en", (char*)"true" }});
-
- // Nuki Hub Webserver enabled
- publishHassTopic("switch",
- "webserver",
- uidString,
- "_webserver",
- "Nuki Hub webserver enabled",
- name,
- baseTopic,
- _lockPath + mqtt_topic_webserver_state,
- deviceType,
- "",
- "",
- "diagnostic",
- _lockPath + mqtt_topic_webserver_action,
- {
- { (char*)"pl_on", (char*)"1" },
- { (char*)"pl_off", (char*)"0" },
- { (char*)"stat_on", (char*)"1" },
- { (char*)"stat_off", (char*)"0" }
- });
-
- // Uptime
- publishHassTopic("sensor",
- "uptime",
- uidString,
- "_uptime",
- "Uptime",
- name,
- baseTopic,
- _lockPath + mqtt_topic_uptime,
- deviceType,
- "duration",
- "",
- "diagnostic",
- "",
- {
- { (char*)"en", (char*)"true" },
- { (char*)"unit_of_meas", (char*)"min"}
- });
-
- if(_preferences->getBool(preference_mqtt_log_enabled, false))
- {
- // MQTT Log
- publishHassTopic("sensor",
- "mqtt_log",
- uidString,
- "_mqtt_log",
- "MQTT Log",
- name,
- baseTopic,
- _lockPath + mqtt_topic_log,
- deviceType,
- "",
- "",
- "diagnostic",
- "",
- { { (char*)"en", (char*)"true" }});
- }
- else
- {
- removeHassTopic((char*)"sensor", (char*)"mqtt_log", uidString);
- }
-
- if(_offEnabled)
- {
- // Hybrid connected
- String hybridPath = _lockPath;
- hybridPath.concat("/lock");
- hybridPath.concat(mqtt_hybrid_state);
- publishHassTopic("binary_sensor",
- "hybrid_connected",
- uidString,
- "_hybrid_connected",
- "Hybrid connected",
- name,
- baseTopic,
- hybridPath,
- deviceType,
- "",
- "",
- "diagnostic",
- "",
- {
- {(char*)"pl_on", (char*)"1"},
- {(char*)"pl_off", (char*)"0"},
- { (char*)"en", (char*)"true" }
- });
- }
- else
- {
- removeHassTopic((char*)"binary_sensor", (char*)"hybrid_connected", uidString);
- }
-
- // Firmware version
- publishHassTopic("sensor",
- "firmware_version",
- uidString,
- "_firmware_version",
- "Firmware version",
- name,
- baseTopic,
- String("~") + mqtt_topic_info_firmware_version,
- deviceType,
- "",
- "",
- "diagnostic",
- "",
- {
- { (char*)"en", (char*)"true" },
- {(char*)"ic", (char*)"mdi:counter"}
- });
-
- // Hardware version
- publishHassTopic("sensor",
- "hardware_version",
- uidString,
- "_hardware_version",
- "Hardware version",
- name,
- baseTopic,
- String("~") + mqtt_topic_info_hardware_version,
- deviceType,
- "",
- "",
- "diagnostic",
- "",
- {
- { (char*)"en", (char*)"true" },
- {(char*)"ic", (char*)"mdi:counter"}
- });
-
- // Nuki Hub version
- publishHassTopic("sensor",
- "nuki_hub_version",
- uidString,
- "_nuki_hub_version",
- "Nuki Hub version",
- name,
- baseTopic,
- _lockPath + mqtt_topic_info_nuki_hub_version,
- deviceType,
- "",
- "",
- "diagnostic",
- "",
- {
- { (char*)"en", (char*)"true" },
- {(char*)"ic", (char*)"mdi:counter"}
- });
-
- // Nuki Hub build
- publishHassTopic("sensor",
- "nuki_hub_build",
- uidString,
- "_nuki_hub_build",
- "Nuki Hub build",
- name,
- baseTopic,
- _lockPath + mqtt_topic_info_nuki_hub_build,
- deviceType,
- "",
- "",
- "diagnostic",
- "",
- {
- { (char*)"en", (char*)"true" },
- {(char*)"ic", (char*)"mdi:counter"}
- });
-
- // Nuki Hub restart reason
- publishHassTopic("sensor",
- "nuki_hub_restart_reason",
- uidString,
- "_nuki_hub_restart_reason",
- "Nuki Hub restart reason",
- name,
- baseTopic,
- _lockPath + mqtt_topic_restart_reason_fw,
- deviceType,
- "",
- "",
- "diagnostic",
- "",
- { { (char*)"en", (char*)"true" }});
-
- // Nuki Hub restart reason ESP
- publishHassTopic("sensor",
- "nuki_hub_restart_reason_esp",
- uidString,
- "_nuki_hub_restart_reason_esp",
- "Nuki Hub restart reason ESP",
- name,
- baseTopic,
- _lockPath + mqtt_topic_restart_reason_esp,
- deviceType,
- "",
- "",
- "diagnostic",
- "",
- { { (char*)"en", (char*)"true" }});
-
- if(_checkUpdates)
- {
- // NUKI Hub latest
- publishHassTopic("sensor",
- "nuki_hub_latest",
- uidString,
- "_nuki_hub_latest",
- "NUKI Hub latest",
- name,
- baseTopic,
- _lockPath + mqtt_topic_info_nuki_hub_latest,
- deviceType,
- "",
- "",
- "diagnostic",
- "",
- {
- { (char*)"en", (char*)"true" },
- {(char*)"ic", (char*)"mdi:counter"}
- });
-
- // NUKI Hub update
- char latest_version_topic[250];
- _lockPath.toCharArray(latest_version_topic,_lockPath.length() + 1);
- strcat(latest_version_topic, mqtt_topic_info_nuki_hub_latest);
-
- if(!_updateFromMQTT)
- {
- publishHassTopic("update",
- "nuki_hub_update",
- uidString,
- "_nuki_hub_update",
- "NUKI Hub firmware update",
- name,
- baseTopic,
- _lockPath + mqtt_topic_info_nuki_hub_version,
- deviceType,
- "firmware",
- "",
- "diagnostic",
- "",
- {
- { (char*)"en", (char*)"true" },
- { (char*)"ent_pic", (char*)"https://raw.githubusercontent.com/technyon/nuki_hub/master/icon/favicon-32x32.png" },
- { (char*)"rel_u", (char*)GITHUB_LATEST_RELEASE_URL },
- { (char*)"l_ver_t", (char*)latest_version_topic }
- });
- }
- else
- {
- publishHassTopic("update",
- "nuki_hub_update",
- uidString,
- "_nuki_hub_update",
- "NUKI Hub firmware update",
- name,
- baseTopic,
- _lockPath + mqtt_topic_info_nuki_hub_version,
- deviceType,
- "firmware",
- "",
- "diagnostic",
- _lockPath + mqtt_topic_update,
- {
- { (char*)"en", (char*)"true" },
- { (char*)"pl_inst", (char*)"1" },
- { (char*)"ent_pic", (char*)"https://raw.githubusercontent.com/technyon/nuki_hub/master/icon/favicon-32x32.png" },
- { (char*)"rel_u", (char*)GITHUB_LATEST_RELEASE_URL },
- { (char*)"l_ver_t", (char*)latest_version_topic }
- });
- }
- }
- else
- {
- removeHassTopic((char*)"sensor", (char*)"nuki_hub_latest", uidString);
- removeHassTopic((char*)"update", (char*)"nuki_hub_update", uidString);
- }
-
- // Nuki Hub IP Address
- publishHassTopic("sensor",
- "nuki_hub_ip",
- uidString,
- "_nuki_hub_ip",
- "Nuki Hub IP",
- name,
- baseTopic,
- _lockPath + mqtt_topic_info_nuki_hub_ip,
- deviceType,
- "",
- "",
- "diagnostic",
- "",
- {
- { (char*)"en", (char*)"true" },
- {(char*)"ic", (char*)"mdi:ip"}
- });
-
- // Query Lock State
- publishHassTopic("button",
- "query_lockstate",
- uidString,
- "_query_lockstate",
- "Query lock state",
- name,
- baseTopic,
- "",
- deviceType,
- "",
- "",
- "diagnostic",
- String("~") + mqtt_topic_query_lockstate,
- {
- { (char*)"en", (char*)"false" },
- { (char*)"pl_prs", (char*)"1" }
- });
-
- // Query Config
- publishHassTopic("button",
- "query_config",
- uidString,
- "_query_config",
- "Query config",
- name,
- baseTopic,
- "",
- deviceType,
- "",
- "",
- "diagnostic",
- String("~") + mqtt_topic_query_config,
- {
- { (char*)"en", (char*)"false" },
- { (char*)"pl_prs", (char*)"1" }
- });
-
- // Query Lock State Command result
- publishHassTopic("button",
- "query_commandresult",
- uidString,
- "_query_commandresult",
- "Query lock state command result",
- name,
- baseTopic,
- "",
- deviceType,
- "",
- "",
- "diagnostic",
- String("~") + mqtt_topic_query_lockstate_command_result,
- {
- { (char*)"en", (char*)"false" },
- { (char*)"pl_prs", (char*)"1" }
- });
-
- publishHassTopic("sensor",
- "bluetooth_signal_strength",
- uidString,
- "_bluetooth_signal_strength",
- "Bluetooth signal strength",
- name,
- baseTopic,
- String("~") + mqtt_topic_lock_rssi,
- deviceType,
- "signal_strength",
- "measurement",
- "diagnostic",
- "",
- { {(char*)"unit_of_meas", (char*)"dBm"} });
+ _device->mqttPublish(topic, MQTT_QOS_LEVEL, retain, value);
}
-void NukiNetwork::publishHASSConfigAdditionalLockEntities(char *deviceType, const char *baseTopic, char *name, char *uidString)
+void NukiNetwork::removeTopic(const String& mqttPath, const String& mqttTopic)
{
- uint32_t aclPrefs[17];
- _preferences->getBytes(preference_acl, &aclPrefs, sizeof(aclPrefs));
+ String path = mqttPath;
+ path.concat(mqttTopic);
+ publish(path.c_str(), "", true);
- uint32_t basicLockConfigAclPrefs[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
- uint32_t advancedLockConfigAclPrefs[22] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
-
- if(_preferences->getBool(preference_conf_info_enabled, true))
- {
- _preferences->getBytes(preference_conf_lock_basic_acl, &basicLockConfigAclPrefs, sizeof(basicLockConfigAclPrefs));
- _preferences->getBytes(preference_conf_lock_advanced_acl, &advancedLockConfigAclPrefs, sizeof(advancedLockConfigAclPrefs));
- }
-
- if((int)aclPrefs[2])
- {
- // Unlatch
- publishHassTopic("button",
- "unlatch",
- uidString,
- "_unlatch",
- "Open",
- name,
- baseTopic,
- "",
- deviceType,
- "",
- "",
- "",
- String("~") + mqtt_topic_lock_action,
- {
- { (char*)"en", (char*)"false" },
- { (char*)"pl_prs", (char*)"unlatch" }
- });
- }
- else
- {
- removeHassTopic((char*)"button", (char*)"unlatch", uidString);
- }
-
- if((int)aclPrefs[3])
- {
- // Lock 'n' Go
- publishHassTopic("button",
- "lockngo",
- uidString,
- "_lockngo",
- "Lock 'n' Go",
- name,
- baseTopic,
- "",
- deviceType,
- "",
- "",
- "",
- String("~") + mqtt_topic_lock_action,
- {
- { (char*)"en", (char*)"false" },
- { (char*)"pl_prs", (char*)"lockNgo" }
- });
- }
- else
- {
- removeHassTopic((char*)"button", (char*)"lockngo", uidString);
- }
-
- if((int)aclPrefs[4])
- {
- // Lock 'n' Go with unlatch
- publishHassTopic("button",
- "lockngounlatch",
- uidString,
- "_lockngounlatch",
- "Lock 'n' Go with unlatch",
- name,
- baseTopic,
- "",
- deviceType,
- "",
- "",
- "",
- String("~") + mqtt_topic_lock_action,
- {
- { (char*)"en", (char*)"false" },
- { (char*)"pl_prs", (char*)"lockNgoUnlatch" }
- });
- }
- else
- {
- removeHassTopic((char*)"button", (char*)"lockngounlatch", uidString);
- }
-
- // Query Battery
- publishHassTopic("button",
- "query_battery",
- uidString,
- "_query_battery",
- "Query battery",
- name,
- baseTopic,
- "",
- deviceType,
- "",
- "",
- "diagnostic",
- String("~") + mqtt_topic_query_battery,
- {
- { (char*)"en", (char*)"false" },
- { (char*)"pl_prs", (char*)"1" }
- });
-
- if((int)basicLockConfigAclPrefs[6] == 1)
- {
- // LED enabled
- publishHassTopic("switch",
- "led_enabled",
- uidString,
- "_led_enabled",
- "LED enabled",
- name,
- baseTopic,
- String("~") + mqtt_topic_config_basic_json,
- deviceType,
- "",
- "",
- "config",
- String("~") + mqtt_topic_config_action,
- {
- { (char*)"en", (char*)"true" },
- { (char*)"ic", (char*)"mdi:led-variant-on" },
- { (char*)"pl_on", (char*)"{ \"ledEnabled\": \"1\"}" },
- { (char*)"pl_off", (char*)"{ \"ledEnabled\": \"0\"}" },
- { (char*)"val_tpl", (char*)"{{value_json.ledEnabled}}" },
- { (char*)"stat_on", (char*)"1" },
- { (char*)"stat_off", (char*)"0" }
- });
- }
- else
- {
- removeHassTopic((char*)"switch", (char*)"led_enabled", uidString);
- }
-
- if((int)basicLockConfigAclPrefs[5] == 1)
- {
- // Button enabled
- publishHassTopic("switch",
- "button_enabled",
- uidString,
- "_button_enabled",
- "Button enabled",
- name,
- baseTopic,
- String("~") + mqtt_topic_config_basic_json,
- deviceType,
- "",
- "",
- "config",
- String("~") + mqtt_topic_config_action,
- {
- { (char*)"en", (char*)"true" },
- { (char*)"ic", (char*)"mdi:radiobox-marked" },
- { (char*)"pl_on", (char*)"{ \"buttonEnabled\": \"1\"}" },
- { (char*)"pl_off", (char*)"{ \"buttonEnabled\": \"0\"}" },
- { (char*)"val_tpl", (char*)"{{value_json.buttonEnabled}}" },
- { (char*)"stat_on", (char*)"1" },
- { (char*)"stat_off", (char*)"0" }
- });
- }
- else
- {
- removeHassTopic((char*)"switch", (char*)"button_enabled", uidString);
- }
-
- if((int)advancedLockConfigAclPrefs[19] == 1)
- {
- // Auto Lock
- publishHassTopic("switch",
- "auto_lock",
- uidString,
- "_auto_lock",
- "Auto lock",
- name,
- baseTopic,
- String("~") + mqtt_topic_config_advanced_json,
- deviceType,
- "",
- "",
- "config",
- String("~") + mqtt_topic_config_action,
- {
- { (char*)"en", (char*)"true" },
- { (char*)"pl_on", (char*)"{ \"autoLockEnabled\": \"1\"}" },
- { (char*)"pl_off", (char*)"{ \"autoLockEnabled\": \"0\"}" },
- { (char*)"val_tpl", (char*)"{{value_json.autoLockEnabled}}" },
- { (char*)"stat_on", (char*)"1" },
- { (char*)"stat_off", (char*)"0" }
- });
- }
- else
- {
- removeHassTopic((char*)"switch", (char*)"auto_lock", uidString);
- }
-
- if((int)advancedLockConfigAclPrefs[12] == 1)
- {
- // Auto Unlock
- publishHassTopic("switch",
- "auto_unlock",
- uidString,
- "_auto_unlock",
- "Auto unlock",
- name,
- baseTopic,
- String("~") + mqtt_topic_config_advanced_json,
- deviceType,
- "",
- "",
- "config",
- String("~") + mqtt_topic_config_action,
- {
- { (char*)"en", (char*)"true" },
- { (char*)"pl_on", (char*)"{ \"autoUnLockDisabled\": \"0\"}" },
- { (char*)"pl_off", (char*)"{ \"autoUnLockDisabled\": \"1\"}" },
- { (char*)"val_tpl", (char*)"{{value_json.autoUnLockDisabled}}" },
- { (char*)"stat_on", (char*)"0" },
- { (char*)"stat_off", (char*)"1" }
- });
- }
- else
- {
- removeHassTopic((char*)"switch", (char*)"auto_unlock", uidString);
- }
-
- if((int)basicLockConfigAclPrefs[13] == 1)
- {
- // Double lock
- publishHassTopic("switch",
- "double_lock",
- uidString,
- "_double_lock",
- "Double lock",
- name,
- baseTopic,
- String("~") + mqtt_topic_config_basic_json,
- deviceType,
- "",
- "",
- "config",
- String("~") + mqtt_topic_config_action,
- {
- { (char*)"en", (char*)"true" },
- { (char*)"pl_on", (char*)"{ \"singleLock\": \"0\"}" },
- { (char*)"pl_off", (char*)"{ \"singleLock\": \"1\"}" },
- { (char*)"val_tpl", (char*)"{{value_json.singleLock}}" },
- { (char*)"stat_on", (char*)"0" },
- { (char*)"stat_off", (char*)"1" }
- });
- }
- else
- {
- removeHassTopic((char*)"switch", (char*)"double_lock", uidString);
- }
-
- publishHassTopic("sensor",
- "battery_level",
- uidString,
- "_battery_level",
- "Battery level",
- name,
- baseTopic,
- String("~") + mqtt_topic_battery_basic_json,
- deviceType,
- "battery",
- "measurement",
- "diagnostic",
- "",
- {
- {(char*)"unit_of_meas", (char*)"%"},
- {(char*)"val_tpl", (char*)"{{value_json.level}}" }
- });
-
- if((int)basicLockConfigAclPrefs[7] == 1)
- {
- publishHassTopic("number",
- "led_brightness",
- uidString,
- "_led_brightness",
- "LED brightness",
- name,
- baseTopic,
- String("~") + mqtt_topic_config_basic_json,
- deviceType,
- "",
- "",
- "config",
- String("~") + mqtt_topic_config_action,
- {
- { (char*)"en", (char*)"true" },
- { (char*)"ic", (char*)"mdi:brightness-6" },
- { (char*)"cmd_tpl", (char*)"{ \"ledBrightness\": \"{{ value }}\" }" },
- { (char*)"val_tpl", (char*)"{{value_json.ledBrightness}}" },
- { (char*)"min", (char*)"0" },
- { (char*)"max", (char*)"5" }
- });
- }
- else
- {
- removeHassTopic((char*)"number", (char*)"led_brightness", uidString);
- }
-
- if((int)basicLockConfigAclPrefs[3] == 1)
- {
- // Auto Unlatch
- publishHassTopic("switch",
- "auto_unlatch",
- uidString,
- "_auto_unlatch",
- "Auto unlatch",
- name,
- baseTopic,
- String("~") + mqtt_topic_config_basic_json,
- deviceType,
- "",
- "",
- "config",
- String("~") + mqtt_topic_config_action,
- {
- { (char*)"en", (char*)"true" },
- { (char*)"pl_on", (char*)"{ \"autoUnlatch\": \"1\"}" },
- { (char*)"pl_off", (char*)"{ \"autoUnlatch\": \"0\"}" },
- { (char*)"val_tpl", (char*)"{{value_json.autoUnlatch}}" },
- { (char*)"stat_on", (char*)"1" },
- { (char*)"stat_off", (char*)"0" }
- });
- }
- else
- {
- removeHassTopic((char*)"switch", (char*)"auto_unlatch", uidString);
- }
-
- if((int)basicLockConfigAclPrefs[4] == 1)
- {
- // Pairing enabled
- publishHassTopic("switch",
- "pairing_enabled",
- uidString,
- "_pairing_enabled",
- "Pairing enabled",
- name,
- baseTopic,
- String("~") + mqtt_topic_config_basic_json,
- deviceType,
- "",
- "",
- "config",
- String("~") + mqtt_topic_config_action,
- {
- { (char*)"en", (char*)"true" },
- { (char*)"pl_on", (char*)"{ \"pairingEnabled\": \"1\"}" },
- { (char*)"pl_off", (char*)"{ \"pairingEnabled\": \"0\"}" },
- { (char*)"val_tpl", (char*)"{{value_json.pairingEnabled}}" },
- { (char*)"stat_on", (char*)"1" },
- { (char*)"stat_off", (char*)"0" }
- });
- }
- else
- {
- removeHassTopic((char*)"switch", (char*)"pairing_enabled", uidString);
- }
-
- if((int)basicLockConfigAclPrefs[8] == 1)
- {
- publishHassTopic("number",
- "timezone_offset",
- uidString,
- "_timezone_offset",
- "Timezone offset",
- name,
- baseTopic,
- String("~") + mqtt_topic_config_basic_json,
- deviceType,
- "",
- "",
- "config",
- String("~") + mqtt_topic_config_action,
- {
- { (char*)"en", (char*)"true" },
- { (char*)"ic", (char*)"mdi:timer-cog-outline" },
- { (char*)"cmd_tpl", (char*)"{ \"timeZoneOffset\": \"{{ value }}\" }" },
- { (char*)"val_tpl", (char*)"{{value_json.timeZoneOffset}}" },
- { (char*)"min", (char*)"0" },
- { (char*)"max", (char*)"60" }
- });
- }
- else
- {
- removeHassTopic((char*)"number", (char*)"timezone_offset", uidString);
- }
-
- if((int)basicLockConfigAclPrefs[9] == 1)
- {
- // DST Mode
- publishHassTopic("switch",
- "dst_mode",
- uidString,
- "_dst_mode",
- "DST mode European",
- name,
- baseTopic,
- String("~") + mqtt_topic_config_basic_json,
- deviceType,
- "",
- "",
- "config",
- String("~") + mqtt_topic_config_action,
- {
- { (char*)"en", (char*)"true" },
- { (char*)"pl_on", (char*)"{ \"dstMode\": \"1\"}" },
- { (char*)"pl_off", (char*)"{ \"dstMode\": \"0\"}" },
- { (char*)"val_tpl", (char*)"{{value_json.dstMode}}" },
- { (char*)"stat_on", (char*)"1" },
- { (char*)"stat_off", (char*)"0" }
- });
- }
- else
- {
- removeHassTopic((char*)"switch", (char*)"dst_mode", uidString);
- }
-
- if((int)basicLockConfigAclPrefs[10] == 1)
- {
- JsonDocument json;
- json = createHassJson(uidString, "_fob_action_1", "Fob action 1", name, baseTopic, String("~") + mqtt_topic_config_basic_json, deviceType, "", "", "config", String("~") + mqtt_topic_config_action, {{ (char*)"val_tpl", (char*)"{{value_json.fobAction1}}" }, { (char*)"en", (char*)"true" }, { (char*)"cmd_tpl", (char*)"{ \"fobAction1\": \"{{ value }}\" }" }});
- json["options"][0] = "No Action";
- json["options"][1] = "Unlock";
- json["options"][2] = "Lock";
- json["options"][3] = "Lock n Go";
- json["options"][4] = "Intelligent";
- serializeJson(json, _buffer, _bufferSize);
- String path = createHassTopicPath("select", "fob_action_1", uidString);
- _device->mqttPublish(path.c_str(), MQTT_QOS_LEVEL, true, _buffer);
- }
- else
- {
- removeHassTopic((char*)"select", (char*)"fob_action_1", uidString);
- }
-
- if((int)basicLockConfigAclPrefs[11] == 1)
- {
- JsonDocument json;
- json = createHassJson(uidString, "_fob_action_2", "Fob action 2", name, baseTopic, String("~") + mqtt_topic_config_basic_json, deviceType, "", "", "config", String("~") + mqtt_topic_config_action, {{ (char*)"val_tpl", (char*)"{{value_json.fobAction2}}" }, { (char*)"en", (char*)"true" }, { (char*)"cmd_tpl", (char*)"{ \"fobAction2\": \"{{ value }}\" }" }});
- json["options"][0] = "No Action";
- json["options"][1] = "Unlock";
- json["options"][2] = "Lock";
- json["options"][3] = "Lock n Go";
- json["options"][4] = "Intelligent";
- serializeJson(json, _buffer, _bufferSize);
- String path = createHassTopicPath("select", "fob_action_2", uidString);
- _device->mqttPublish(path.c_str(), MQTT_QOS_LEVEL, true, _buffer);
- }
- else
- {
- removeHassTopic((char*)"select", (char*)"fob_action_2", uidString);
- }
-
- if((int)basicLockConfigAclPrefs[12] == 1)
- {
- JsonDocument json;
- json = createHassJson(uidString, "_fob_action_3", "Fob action 3", name, baseTopic, String("~") + mqtt_topic_config_basic_json, deviceType, "", "", "config", String("~") + mqtt_topic_config_action, {{ (char*)"val_tpl", (char*)"{{value_json.fobAction3}}" }, { (char*)"en", (char*)"true" }, { (char*)"cmd_tpl", (char*)"{ \"fobAction3\": \"{{ value }}\" }" }});
- json["options"][0] = "No Action";
- json["options"][1] = "Unlock";
- json["options"][2] = "Lock";
- json["options"][3] = "Lock n Go";
- json["options"][4] = "Intelligent";
- serializeJson(json, _buffer, _bufferSize);
- String path = createHassTopicPath("select", "fob_action_3", uidString);
- _device->mqttPublish(path.c_str(), MQTT_QOS_LEVEL, true, _buffer);
- }
- else
- {
- removeHassTopic((char*)"select", (char*)"fob_action_3", uidString);
- }
-
- if((int)basicLockConfigAclPrefs[14] == 1)
- {
- JsonDocument json;
- json = createHassJson(uidString, "_advertising_mode", "Advertising mode", name, baseTopic, String("~") + mqtt_topic_config_basic_json, deviceType, "", "", "config", String("~") + mqtt_topic_config_action, {{ (char*)"val_tpl", (char*)"{{value_json.advertisingMode}}" }, { (char*)"en", (char*)"true" }, { (char*)"cmd_tpl", (char*)"{ \"advertisingMode\": \"{{ value }}\" }" }});
- json["options"][0] = "Automatic";
- json["options"][1] = "Normal";
- json["options"][2] = "Slow";
- json["options"][3] = "Slowest";
- serializeJson(json, _buffer, _bufferSize);
- String path = createHassTopicPath("select", "advertising_mode", uidString);
- _device->mqttPublish(path.c_str(), MQTT_QOS_LEVEL, true, _buffer);
- }
- else
- {
- removeHassTopic((char*)"select", (char*)"advertising_mode", uidString);
- }
-
- if((int)basicLockConfigAclPrefs[15] == 1)
- {
- JsonDocument json;
- json = createHassJson(uidString, "_timezone", "Timezone", name, baseTopic, String("~") + mqtt_topic_config_basic_json, deviceType, "", "", "config", String("~") + mqtt_topic_config_action, {{ (char*)"val_tpl", (char*)"{{value_json.timeZone}}" }, { (char*)"en", (char*)"true" }, { (char*)"cmd_tpl", (char*)"{ \"timeZone\": \"{{ value }}\" }" }});
- json["options"][0] = "Africa/Cairo";
- json["options"][1] = "Africa/Lagos";
- json["options"][2] = "Africa/Maputo";
- json["options"][3] = "Africa/Nairobi";
- json["options"][4] = "America/Anchorage";
- json["options"][5] = "America/Argentina/Buenos_Aires";
- json["options"][6] = "America/Chicago";
- json["options"][7] = "America/Denver";
- json["options"][8] = "America/Halifax";
- json["options"][9] = "America/Los_Angeles";
- json["options"][10] = "America/Manaus";
- json["options"][11] = "America/Mexico_City";
- json["options"][12] = "America/New_York";
- json["options"][13] = "America/Phoenix";
- json["options"][14] = "America/Regina";
- json["options"][15] = "America/Santiago";
- json["options"][16] = "America/Sao_Paulo";
- json["options"][17] = "America/St_Johns";
- json["options"][18] = "Asia/Bangkok";
- json["options"][19] = "Asia/Dubai";
- json["options"][20] = "Asia/Hong_Kong";
- json["options"][21] = "Asia/Jerusalem";
- json["options"][22] = "Asia/Karachi";
- json["options"][23] = "Asia/Kathmandu";
- json["options"][24] = "Asia/Kolkata";
- json["options"][25] = "Asia/Riyadh";
- json["options"][26] = "Asia/Seoul";
- json["options"][27] = "Asia/Shanghai";
- json["options"][28] = "Asia/Tehran";
- json["options"][29] = "Asia/Tokyo";
- json["options"][30] = "Asia/Yangon";
- json["options"][31] = "Australia/Adelaide";
- json["options"][32] = "Australia/Brisbane";
- json["options"][33] = "Australia/Darwin";
- json["options"][34] = "Australia/Hobart";
- json["options"][35] = "Australia/Perth";
- json["options"][36] = "Australia/Sydney";
- json["options"][37] = "Europe/Berlin";
- json["options"][38] = "Europe/Helsinki";
- json["options"][39] = "Europe/Istanbul";
- json["options"][40] = "Europe/London";
- json["options"][41] = "Europe/Moscow";
- json["options"][42] = "Pacific/Auckland";
- json["options"][43] = "Pacific/Guam";
- json["options"][44] = "Pacific/Honolulu";
- json["options"][45] = "Pacific/Pago_Pago";
- json["options"][46] = "None";
-
- serializeJson(json, _buffer, _bufferSize);
- String path = createHassTopicPath("select", "timezone", uidString);
- _device->mqttPublish(path.c_str(), MQTT_QOS_LEVEL, true, _buffer);
- }
- else
- {
- removeHassTopic((char*)"select", (char*)"timezone", uidString);
- }
-
- if((int)advancedLockConfigAclPrefs[0] == 1)
- {
- publishHassTopic("number",
- "unlocked_position_offset_degrees",
- uidString,
- "_unlocked_position_offset_degrees",
- "Unlocked position offset degrees",
- name,
- baseTopic,
- String("~") + mqtt_topic_config_advanced_json,
- deviceType,
- "",
- "",
- "config",
- String("~") + mqtt_topic_config_action,
- {
- { (char*)"en", (char*)"true" },
- { (char*)"cmd_tpl", (char*)"{ \"unlockedPositionOffsetDegrees\": \"{{ value }}\" }" },
- { (char*)"val_tpl", (char*)"{{value_json.unlockedPositionOffsetDegrees}}" },
- { (char*)"min", (char*)"-90" },
- { (char*)"max", (char*)"180" }
- });
- }
- else
- {
- removeHassTopic((char*)"number", (char*)"unlocked_position_offset_degrees", uidString);
- }
-
- if((int)advancedLockConfigAclPrefs[1] == 1)
- {
- publishHassTopic("number",
- "locked_position_offset_degrees",
- uidString,
- "_locked_position_offset_degrees",
- "Locked position offset degrees",
- name,
- baseTopic,
- String("~") + mqtt_topic_config_advanced_json,
- deviceType,
- "",
- "",
- "config",
- String("~") + mqtt_topic_config_action,
- {
- { (char*)"en", (char*)"true" },
- { (char*)"cmd_tpl", (char*)"{ \"lockedPositionOffsetDegrees\": \"{{ value }}\" }" },
- { (char*)"val_tpl", (char*)"{{value_json.lockedPositionOffsetDegrees}}" },
- { (char*)"min", (char*)"-180" },
- { (char*)"max", (char*)"90" }
- });
- }
- else
- {
- removeHassTopic((char*)"number", (char*)"locked_position_offset_degrees", uidString);
- }
-
- if((int)advancedLockConfigAclPrefs[2] == 1)
- {
- publishHassTopic("number",
- "single_locked_position_offset_degrees",
- uidString,
- "_single_locked_position_offset_degrees",
- "Single locked position offset degrees",
- name,
- baseTopic,
- String("~") + mqtt_topic_config_advanced_json,
- deviceType,
- "",
- "",
- "config",
- String("~") + mqtt_topic_config_action,
- {
- { (char*)"en", (char*)"true" },
- { (char*)"cmd_tpl", (char*)"{ \"singleLockedPositionOffsetDegrees\": \"{{ value }}\" }" },
- { (char*)"val_tpl", (char*)"{{value_json.singleLockedPositionOffsetDegrees}}" },
- { (char*)"min", (char*)"-180" },
- { (char*)"max", (char*)"180" }
- });
- }
- else
- {
- removeHassTopic((char*)"number", (char*)"single_locked_position_offset_degrees", uidString);
- }
-
- if((int)advancedLockConfigAclPrefs[3] == 1)
- {
- publishHassTopic("number",
- "unlocked_locked_transition_offset_degrees",
- uidString,
- "_unlocked_locked_transition_offset_degrees",
- "Unlocked to locked transition offset degrees",
- name,
- baseTopic,
- String("~") + mqtt_topic_config_advanced_json,
- deviceType,
- "",
- "",
- "config",
- String("~") + mqtt_topic_config_action,
- {
- { (char*)"en", (char*)"true" },
- { (char*)"cmd_tpl", (char*)"{ \"unlockedToLockedTransitionOffsetDegrees\": \"{{ value }}\" }" },
- { (char*)"val_tpl", (char*)"{{value_json.unlockedToLockedTransitionOffsetDegrees}}" },
- { (char*)"min", (char*)"-180" },
- { (char*)"max", (char*)"180" }
- });
- }
- else
- {
- removeHassTopic((char*)"number", (char*)"unlocked_locked_transition_offset_degrees", uidString);
- }
-
- if((int)advancedLockConfigAclPrefs[4] == 1)
- {
- publishHassTopic("number",
- "lockngo_timeout",
- uidString,
- "_lockngo_timeout",
- "Lock n Go timeout",
- name,
- baseTopic,
- String("~") + mqtt_topic_config_advanced_json,
- deviceType,
- "",
- "",
- "config",
- String("~") + mqtt_topic_config_action,
- {
- { (char*)"en", (char*)"true" },
- { (char*)"cmd_tpl", (char*)"{ \"lockNgoTimeout\": \"{{ value }}\" }" },
- { (char*)"val_tpl", (char*)"{{value_json.lockNgoTimeout}}" },
- { (char*)"min", (char*)"5" },
- { (char*)"max", (char*)"60" }
- });
- }
- else
- {
- removeHassTopic((char*)"number", (char*)"lockngo_timeout", uidString);
- }
-
- if((int)advancedLockConfigAclPrefs[5] == 1)
- {
- JsonDocument json;
- json = createHassJson(uidString, "_single_button_press_action", "Single button press action", name, baseTopic, String("~") + mqtt_topic_config_advanced_json, deviceType, "", "", "config", String("~") + mqtt_topic_config_action, {{ (char*)"val_tpl", (char*)"{{value_json.singleButtonPressAction}}" }, { (char*)"en", (char*)"true" }, { (char*)"cmd_tpl", (char*)"{ \"singleButtonPressAction\": \"{{ value }}\" }" }});
- json["options"][0] = "No Action";
- json["options"][1] = "Intelligent";
- json["options"][2] = "Unlock";
- json["options"][3] = "Lock";
- json["options"][4] = "Unlatch";
- json["options"][5] = "Lock n Go";
- json["options"][6] = "Show Status";
- serializeJson(json, _buffer, _bufferSize);
- String path = createHassTopicPath("select", "single_button_press_action", uidString);
- _device->mqttPublish(path.c_str(), MQTT_QOS_LEVEL, true, _buffer);
- }
- else
- {
- removeHassTopic((char*)"select", (char*)"single_button_press_action", uidString);
- }
-
- if((int)advancedLockConfigAclPrefs[6] == 1)
- {
- JsonDocument json;
- json = createHassJson(uidString, "_double_button_press_action", "Double button press action", name, baseTopic, String("~") + mqtt_topic_config_advanced_json, deviceType, "", "", "config", String("~") + mqtt_topic_config_action, {{ (char*)"val_tpl", (char*)"{{value_json.doubleButtonPressAction}}" }, { (char*)"en", (char*)"true" }, { (char*)"cmd_tpl", (char*)"{ \"doubleButtonPressAction\": \"{{ value }}\" }" }});
- json["options"][0] = "No Action";
- json["options"][1] = "Intelligent";
- json["options"][2] = "Unlock";
- json["options"][3] = "Lock";
- json["options"][4] = "Unlatch";
- json["options"][5] = "Lock n Go";
- json["options"][6] = "Show Status";
- serializeJson(json, _buffer, _bufferSize);
- String path = createHassTopicPath("select", "double_button_press_action", uidString);
- _device->mqttPublish(path.c_str(), MQTT_QOS_LEVEL, true, _buffer);
- }
- else
- {
- removeHassTopic((char*)"select", (char*)"double_button_press_action", uidString);
- }
-
- if((int)advancedLockConfigAclPrefs[7] == 1)
- {
- // Detached cylinder
- publishHassTopic("switch",
- "detached_cylinder",
- uidString,
- "_detached_cylinder",
- "Detached cylinder",
- name,
- baseTopic,
- String("~") + mqtt_topic_config_advanced_json,
- deviceType,
- "",
- "",
- "config",
- String("~") + mqtt_topic_config_action,
- {
- { (char*)"en", (char*)"true" },
- { (char*)"pl_on", (char*)"{ \"detachedCylinder\": \"1\"}" },
- { (char*)"pl_off", (char*)"{ \"detachedCylinder\": \"0\"}" },
- { (char*)"val_tpl", (char*)"{{value_json.detachedCylinder}}" },
- { (char*)"stat_on", (char*)"1" },
- { (char*)"stat_off", (char*)"0" }
- });
- }
- else
- {
- removeHassTopic((char*)"switch", (char*)"detached_cylinder", uidString);
- }
-
- if((int)advancedLockConfigAclPrefs[8] == 1)
- {
- JsonDocument json;
- json = createHassJson(uidString, "_battery_type", "Battery type", name, baseTopic, String("~") + mqtt_topic_config_advanced_json, deviceType, "", "", "config", String("~") + mqtt_topic_config_action, {{ (char*)"val_tpl", (char*)"{{value_json.batteryType}}" }, { (char*)"en", (char*)"true" }, { (char*)"cmd_tpl", (char*)"{ \"batteryType\": \"{{ value }}\" }" }});
- json["options"][0] = "Alkali";
- json["options"][1] = "Accumulators";
- json["options"][2] = "Lithium";
- serializeJson(json, _buffer, _bufferSize);
- String path = createHassTopicPath("select", "battery_type", uidString);
- _device->mqttPublish(path.c_str(), MQTT_QOS_LEVEL, true, _buffer);
- }
- else
- {
- removeHassTopic((char*)"select", (char*)"battery_type", uidString);
- }
-
- if((int)advancedLockConfigAclPrefs[9] == 1)
- {
- // Automatic battery type detection
- publishHassTopic("switch",
- "automatic_battery_type_detection",
- uidString,
- "_automatic_battery_type_detection",
- "Automatic battery type detection",
- name,
- baseTopic,
- String("~") + mqtt_topic_config_advanced_json,
- deviceType,
- "",
- "",
- "config",
- String("~") + mqtt_topic_config_action,
- {
- { (char*)"en", (char*)"true" },
- { (char*)"pl_on", (char*)"{ \"automaticBatteryTypeDetection\": \"1\"}" },
- { (char*)"pl_off", (char*)"{ \"automaticBatteryTypeDetection\": \"0\"}" },
- { (char*)"val_tpl", (char*)"{{value_json.automaticBatteryTypeDetection}}" },
- { (char*)"stat_on", (char*)"1" },
- { (char*)"stat_off", (char*)"0" }
- });
- }
- else
- {
- removeHassTopic((char*)"switch", (char*)"automatic_battery_type_detection", uidString);
- }
-
- if((int)advancedLockConfigAclPrefs[10] == 1)
- {
- publishHassTopic("number",
- "unlatch_duration",
- uidString,
- "_unlatch_duration",
- "Unlatch duration",
- name,
- baseTopic,
- String("~") + mqtt_topic_config_advanced_json,
- deviceType,
- "",
- "",
- "config",
- String("~") + mqtt_topic_config_action,
- {
- { (char*)"en", (char*)"true" },
- { (char*)"cmd_tpl", (char*)"{ \"unlatchDuration\": \"{{ value }}\" }" },
- { (char*)"val_tpl", (char*)"{{value_json.unlatchDuration}}" },
- { (char*)"min", (char*)"1" },
- { (char*)"max", (char*)"30" }
- });
- }
- else
- {
- removeHassTopic((char*)"number", (char*)"unlatch_duration", uidString);
- }
-
- if((int)advancedLockConfigAclPrefs[11] == 1)
- {
- publishHassTopic("number",
- "auto_lock_timeout",
- uidString,
- "_auto_lock_timeout",
- "Auto lock timeout",
- name,
- baseTopic,
- String("~") + mqtt_topic_config_advanced_json,
- deviceType,
- "",
- "",
- "config",
- String("~") + mqtt_topic_config_action,
- {
- { (char*)"en", (char*)"true" },
- { (char*)"cmd_tpl", (char*)"{ \"autoLockTimeOut\": \"{{ value }}\" }" },
- { (char*)"val_tpl", (char*)"{{value_json.autoLockTimeOut}}" },
- { (char*)"min", (char*)"30" },
- { (char*)"max", (char*)"1800" }
- });
- }
- else
- {
- removeHassTopic((char*)"number", (char*)"auto_lock_timeout", uidString);
- }
-
- if((int)advancedLockConfigAclPrefs[13] == 1)
- {
- // Nightmode enabled
- publishHassTopic("switch",
- "nightmode_enabled",
- uidString,
- "_nightmode_enabled",
- "Nightmode enabled",
- name,
- baseTopic,
- String("~") + mqtt_topic_config_advanced_json,
- deviceType,
- "",
- "",
- "config",
- String("~") + mqtt_topic_config_action,
- {
- { (char*)"en", (char*)"true" },
- { (char*)"pl_on", (char*)"{ \"nightModeEnabled\": \"1\"}" },
- { (char*)"pl_off", (char*)"{ \"nightModeEnabled\": \"0\"}" },
- { (char*)"val_tpl", (char*)"{{value_json.nightModeEnabled}}" },
- { (char*)"stat_on", (char*)"1" },
- { (char*)"stat_off", (char*)"0" }
- });
- }
- else
- {
- removeHassTopic((char*)"switch", (char*)"nightmode_enabled", uidString);
- }
-
- if((int)advancedLockConfigAclPrefs[14] == 1)
- {
- // Nightmode start time
- publishHassTopic("text",
- "nightmode_start_time",
- uidString,
- "_nightmode_start_time",
- "Nightmode start time",
- name,
- baseTopic,
- String("~") + mqtt_topic_config_advanced_json,
- deviceType,
- "",
- "",
- "config",
- String("~") + mqtt_topic_config_action,
- {
- { (char*)"en", (char*)"true" },
- { (char*)"pattern", (char*)"([0-1][0-9]|2[0-3]):[0-5][0-9]" },
- { (char*)"cmd_tpl", (char*)"{ \"nightModeStartTime\": \"{{ value }}\" }" },
- { (char*)"val_tpl", (char*)"{{value_json.nightModeStartTime}}" },
- { (char*)"min", (char*)"5" },
- { (char*)"max", (char*)"5" }
- });
- }
- else
- {
- removeHassTopic((char*)"text", (char*)"nightmode_start_time", uidString);
- }
-
- if((int)advancedLockConfigAclPrefs[15] == 1)
- {
- // Nightmode end time
- publishHassTopic("text",
- "nightmode_end_time",
- uidString,
- "_nightmode_end_time",
- "Nightmode end time",
- name,
- baseTopic,
- String("~") + mqtt_topic_config_advanced_json,
- deviceType,
- "",
- "",
- "config",
- String("~") + mqtt_topic_config_action,
- {
- { (char*)"en", (char*)"true" },
- { (char*)"pattern", (char*)"([0-1][0-9]|2[0-3]):[0-5][0-9]" },
- { (char*)"cmd_tpl", (char*)"{ \"nightModeEndTime\": \"{{ value }}\" }" },
- { (char*)"val_tpl", (char*)"{{value_json.nightModeEndTime}}" },
- { (char*)"min", (char*)"5" },
- { (char*)"max", (char*)"5" }
- });
- }
- else
- {
- removeHassTopic((char*)"text", (char*)"nightmode_end_time", uidString);
- }
-
- if((int)advancedLockConfigAclPrefs[16] == 1)
- {
- // Nightmode Auto Lock
- publishHassTopic("switch",
- "nightmode_auto_lock",
- uidString,
- "_nightmode_auto_lock",
- "Nightmode auto lock",
- name,
- baseTopic,
- String("~") + mqtt_topic_config_advanced_json,
- deviceType,
- "",
- "",
- "config",
- String("~") + mqtt_topic_config_action,
- {
- { (char*)"en", (char*)"true" },
- { (char*)"pl_on", (char*)"{ \"nightModeAutoLockEnabled\": \"1\"}" },
- { (char*)"pl_off", (char*)"{ \"nightModeAutoLockEnabled\": \"0\"}" },
- { (char*)"val_tpl", (char*)"{{value_json.nightModeAutoLockEnabled}}" },
- { (char*)"stat_on", (char*)"1" },
- { (char*)"stat_off", (char*)"0" }
- });
- }
- else
- {
- removeHassTopic((char*)"switch", (char*)"nightmode_auto_lock", uidString);
- }
-
- if((int)advancedLockConfigAclPrefs[17] == 1)
- {
- // Nightmode Auto Unlock
- publishHassTopic("switch",
- "nightmode_auto_unlock",
- uidString,
- "_nightmode_auto_unlock",
- "Nightmode auto unlock",
- name,
- baseTopic,
- String("~") + mqtt_topic_config_advanced_json,
- deviceType,
- "",
- "",
- "config",
- String("~") + mqtt_topic_config_action,
- {
- { (char*)"en", (char*)"true" },
- { (char*)"pl_on", (char*)"{ \"nightModeAutoUnlockDisabled\": \"0\"}" },
- { (char*)"pl_off", (char*)"{ \"nightModeAutoUnlockDisabled\": \"1\"}" },
- { (char*)"val_tpl", (char*)"{{value_json.nightModeAutoUnlockDisabled}}" },
- { (char*)"stat_on", (char*)"0" },
- { (char*)"stat_off", (char*)"1" }
- });
- }
- else
- {
- removeHassTopic((char*)"switch", (char*)"nightmode_auto_unlock", uidString);
- }
-
- if((int)advancedLockConfigAclPrefs[18] == 1)
- {
- // Nightmode immediate lock on start
- publishHassTopic("switch",
- "nightmode_immediate_lock_start",
- uidString,
- "_nightmode_immediate_lock_start",
- "Nightmode immediate lock on start",
- name,
- baseTopic,
- String("~") + mqtt_topic_config_advanced_json,
- deviceType,
- "",
- "",
- "config",
- String("~") + mqtt_topic_config_action,
- {
- { (char*)"en", (char*)"true" },
- { (char*)"pl_on", (char*)"{ \"nightModeImmediateLockOnStart\": \"1\"}" },
- { (char*)"pl_off", (char*)"{ \"nightModeImmediateLockOnStart\": \"0\"}" },
- { (char*)"val_tpl", (char*)"{{value_json.nightModeImmediateLockOnStart}}" },
- { (char*)"stat_on", (char*)"1" },
- { (char*)"stat_off", (char*)"0" }
- });
- }
- else
- {
- removeHassTopic((char*)"switch", (char*)"nightmode_immediate_lock_start", uidString);
- }
-
- if((int)advancedLockConfigAclPrefs[20] == 1)
- {
- // Immediate auto lock enabled
- publishHassTopic("switch",
- "immediate_auto_lock_enabled",
- uidString,
- "_immediate_auto_lock_enabled",
- "Immediate auto lock enabled",
- name,
- baseTopic,
- String("~") + mqtt_topic_config_advanced_json,
- deviceType,
- "",
- "",
- "config",
- String("~") + mqtt_topic_config_action,
- {
- { (char*)"en", (char*)"true" },
- { (char*)"pl_on", (char*)"{ \"immediateAutoLockEnabled\": \"1\"}" },
- { (char*)"pl_off", (char*)"{ \"immediateAutoLockEnabled\": \"0\"}" },
- { (char*)"val_tpl", (char*)"{{value_json.immediateAutoLockEnabled}}" },
- { (char*)"stat_on", (char*)"1" },
- { (char*)"stat_off", (char*)"0" }
- });
- }
- else
- {
- removeHassTopic((char*)"switch", (char*)"immediate_auto_lock_enabled", uidString);
- }
-
- if((int)advancedLockConfigAclPrefs[21] == 1)
- {
- // Auto update enabled
- publishHassTopic("switch",
- "auto_update_enabled",
- uidString,
- "_auto_update_enabled",
- "Auto update enabled",
- name,
- baseTopic,
- String("~") + mqtt_topic_config_advanced_json,
- deviceType,
- "",
- "",
- "config",
- String("~") + mqtt_topic_config_action,
- {
- { (char*)"en", (char*)"true" },
- { (char*)"pl_on", (char*)"{ \"autoUpdateEnabled\": \"1\"}" },
- { (char*)"pl_off", (char*)"{ \"autoUpdateEnabled\": \"0\"}" },
- { (char*)"val_tpl", (char*)"{{value_json.autoUpdateEnabled}}" },
- { (char*)"stat_on", (char*)"1" },
- { (char*)"stat_off", (char*)"0" }
- });
- }
- else
- {
- removeHassTopic((char*)"switch", (char*)"auto_update_enabled", uidString);
- }
+#ifdef DEBUG_NUKIHUB
+ Log->print(F("Removing MQTT topic: "));
+ Log->println(path.c_str());
+#endif
}
-void NukiNetwork::publishHASSConfigDoorSensor(char *deviceType, const char *baseTopic, char *name, char *uidString)
+void NukiNetwork::setupHASS(int type, uint32_t nukiId, char* nukiName, const char* firmwareVersion, const char* hardwareVersion, bool hasDoorSensor, bool hasKeypad)
{
- publishHassTopic("binary_sensor",
- "door_sensor",
- uidString,
- "_door_sensor",
- "Door sensor",
- name,
- baseTopic,
- String("~") + mqtt_topic_lock_door_sensor_state,
- deviceType,
- "door",
- "",
- "",
- "",
- {
- {(char*)"pl_on", (char*)"doorOpened"},
- {(char*)"pl_off", (char*)"doorClosed"},
- {(char*)"pl_not_avail", (char*)"unavailable"}
- });
+ _hadiscovery->setupHASS(type, nukiId, nukiName, firmwareVersion, hardwareVersion, hasDoorSensor, hasKeypad);
}
-void NukiNetwork::publishHASSConfigAdditionalOpenerEntities(char *deviceType, const char *baseTopic, char *name, char *uidString)
+void NukiNetwork::disableHASS()
{
- uint32_t aclPrefs[17];
- _preferences->getBytes(preference_acl, &aclPrefs, sizeof(aclPrefs));
- uint32_t basicOpenerConfigAclPrefs[14] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
- uint32_t advancedOpenerConfigAclPrefs[20] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
-
- if(_preferences->getBool(preference_conf_info_enabled, true))
- {
- _preferences->getBytes(preference_conf_opener_basic_acl, &basicOpenerConfigAclPrefs, sizeof(basicOpenerConfigAclPrefs));
- _preferences->getBytes(preference_conf_opener_advanced_acl, &advancedOpenerConfigAclPrefs, sizeof(advancedOpenerConfigAclPrefs));
- }
-
- if((int)aclPrefs[11])
- {
- // Unlatch
- publishHassTopic("button",
- "unlatch",
- uidString,
- "_unlatch",
- "Open",
- name,
- baseTopic,
- "",
- deviceType,
- "",
- "",
- "",
- String("~") + mqtt_topic_lock_action,
- {
- { (char*)"en", (char*)"false" },
- { (char*)"pl_prs", (char*)"electricStrikeActuation" }
- });
- }
- else
- {
- removeHassTopic((char*)"button", (char*)"unlatch", uidString);
- }
-
- publishHassTopic("binary_sensor",
- "continuous_mode",
- uidString,
- "_continuous_mode",
- "Continuous mode",
- name,
- baseTopic,
- String("~") + mqtt_topic_lock_continuous_mode,
- deviceType,
- "lock",
- "",
- "",
- "",
- {
- {(char*)"pl_on", (char*)"on"},
- {(char*)"pl_off", (char*)"off"}
- });
-
- if((int)aclPrefs[12] == 1 && (int)aclPrefs[13] == 1)
- {
- publishHassTopic("switch",
- "continuous_mode",
- uidString,
- "_continuous_mode",
- "Continuous mode",
- name,
- baseTopic,
- String("~") + mqtt_topic_lock_continuous_mode,
- deviceType,
- "",
- "",
- "",
- String("~") + mqtt_topic_lock_action,
- {
- { (char*)"en", (char*)"true" },
- {(char*)"stat_on", (char*)"on"},
- {(char*)"stat_off", (char*)"off"},
- {(char*)"pl_on", (char*)"activateCM"},
- {(char*)"pl_off", (char*)"deactivateCM"}
- });
- }
- else
- {
- removeHassTopic((char*)"switch", (char*)"continuous_mode", uidString);
- }
-
- publishHassTopic("binary_sensor",
- "ring_detect",
- uidString,
- "_ring_detect",
- "Ring detect",
- name,
- baseTopic,
- String("~") + mqtt_topic_lock_binary_ring,
- deviceType,
- "sound",
- "",
- "",
- "",
- {
- {(char*)"pl_on", (char*)"ring"},
- {(char*)"pl_off", (char*)"standby"}
- });
-
- JsonDocument json;
- json = createHassJson(uidString, "_ring_event", "Ring", name, baseTopic, String("~") + mqtt_topic_lock_ring, deviceType, "doorbell", "", "", "", {{(char*)"val_tpl", (char*)"{ \"event_type\": \"{{ value }}\" }"}});
- json["event_types"][0] = "ring";
- json["event_types"][1] = "ringlocked";
- json["event_types"][2] = "standby";
- serializeJson(json, _buffer, _bufferSize);
- String path = createHassTopicPath("event", "ring", uidString);
- _device->mqttPublish(path.c_str(), MQTT_QOS_LEVEL, true, _buffer);
-
- if((int)basicOpenerConfigAclPrefs[5] == 1)
- {
- // LED enabled
- publishHassTopic("switch",
- "led_enabled",
- uidString,
- "_led_enabled",
- "LED enabled",
- name,
- baseTopic,
- String("~") + mqtt_topic_config_basic_json,
- deviceType,
- "",
- "",
- "config",
- String("~") + mqtt_topic_config_action,
- {
- { (char*)"en", (char*)"true" },
- { (char*)"ic", (char*)"mdi:led-variant-on" },
- { (char*)"pl_on", (char*)"{ \"ledEnabled\": \"1\"}" },
- { (char*)"pl_off", (char*)"{ \"ledEnabled\": \"0\"}" },
- { (char*)"val_tpl", (char*)"{{value_json.ledEnabled}}" },
- { (char*)"stat_on", (char*)"1" },
- { (char*)"stat_off", (char*)"0" }
- });
- }
- else
- {
- removeHassTopic((char*)"switch", (char*)"led_enabled", uidString);
- }
-
- if((int)basicOpenerConfigAclPrefs[4] == 1)
- {
- // Button enabled
- publishHassTopic("switch",
- "button_enabled",
- uidString,
- "_button_enabled",
- "Button enabled",
- name,
- baseTopic,
- String("~") + mqtt_topic_config_basic_json,
- deviceType,
- "",
- "",
- "config",
- String("~") + mqtt_topic_config_action,
- {
- { (char*)"en", (char*)"true" },
- { (char*)"ic", (char*)"mdi:radiobox-marked" },
- { (char*)"pl_on", (char*)"{ \"buttonEnabled\": \"1\"}" },
- { (char*)"pl_off", (char*)"{ \"buttonEnabled\": \"0\"}" },
- { (char*)"val_tpl", (char*)"{{value_json.buttonEnabled}}" },
- { (char*)"stat_on", (char*)"1" },
- { (char*)"stat_off", (char*)"0" }
- });
- }
- else
- {
- removeHassTopic((char*)"switch", (char*)"button_enabled", uidString);
- }
-
- if((int)advancedOpenerConfigAclPrefs[15] == 1)
- {
- publishHassTopic("number",
- "sound_level",
- uidString,
- "_sound_level",
- "Sound level",
- name,
- baseTopic,
- String("~") + mqtt_topic_config_advanced_json,
- deviceType,
- "",
- "",
- "config",
- String("~") + mqtt_topic_config_action,
- {
- { (char*)"en", (char*)"true" },
- { (char*)"ic", (char*)"mdi:volume-source" },
- { (char*)"cmd_tpl", (char*)"{ \"soundLevel\": \"{{ value }}\" }" },
- { (char*)"val_tpl", (char*)"{{value_json.soundLevel}}" },
- { (char*)"min", (char*)"0" },
- { (char*)"max", (char*)"255" },
- { (char*)"mode", (char*)"slider" },
- { (char*)"step", (char*)"25.5" }
- });
- }
- else
- {
- removeHassTopic((char*)"number", (char*)"sound_level", uidString);
- }
-
- if((int)basicOpenerConfigAclPrefs[3] == 1)
- {
- // Pairing enabled
- publishHassTopic("switch",
- "pairing_enabled",
- uidString,
- "_pairing_enabled",
- "Pairing enabled",
- name,
- baseTopic,
- String("~") + mqtt_topic_config_basic_json,
- deviceType,
- "",
- "",
- "config",
- String("~") + mqtt_topic_config_action,
- {
- { (char*)"en", (char*)"true" },
- { (char*)"pl_on", (char*)"{ \"pairingEnabled\": \"1\"}" },
- { (char*)"pl_off", (char*)"{ \"pairingEnabled\": \"0\"}" },
- { (char*)"val_tpl", (char*)"{{value_json.pairingEnabled}}" },
- { (char*)"stat_on", (char*)"1" },
- { (char*)"stat_off", (char*)"0" }
- });
- }
- else
- {
- removeHassTopic((char*)"switch", (char*)"pairing_enabled", uidString);
- }
-
- if((int)basicOpenerConfigAclPrefs[6] == 1)
- {
- publishHassTopic("number",
- "timezone_offset",
- uidString,
- "_timezone_offset",
- "Timezone offset",
- name,
- baseTopic,
- String("~") + mqtt_topic_config_basic_json,
- deviceType,
- "",
- "",
- "config",
- String("~") + mqtt_topic_config_action,
- {
- { (char*)"en", (char*)"true" },
- { (char*)"ic", (char*)"mdi:timer-cog-outline" },
- { (char*)"cmd_tpl", (char*)"{ \"timeZoneOffset\": \"{{ value }}\" }" },
- { (char*)"val_tpl", (char*)"{{value_json.timeZoneOffset}}" },
- { (char*)"min", (char*)"0" },
- { (char*)"max", (char*)"60" }
- });
- }
- else
- {
- removeHassTopic((char*)"number", (char*)"timezone_offset", uidString);
- }
-
- if((int)basicOpenerConfigAclPrefs[7] == 1)
- {
- // DST Mode
- publishHassTopic("switch",
- "dst_mode",
- uidString,
- "_dst_mode",
- "DST mode European",
- name,
- baseTopic,
- String("~") + mqtt_topic_config_basic_json,
- deviceType,
- "",
- "",
- "config",
- String("~") + mqtt_topic_config_action,
- {
- { (char*)"en", (char*)"true" },
- { (char*)"pl_on", (char*)"{ \"dstMode\": \"1\"}" },
- { (char*)"pl_off", (char*)"{ \"dstMode\": \"0\"}" },
- { (char*)"val_tpl", (char*)"{{value_json.dstMode}}" },
- { (char*)"stat_on", (char*)"1" },
- { (char*)"stat_off", (char*)"0" }
- });
- }
- else
- {
- removeHassTopic((char*)"switch", (char*)"dst_mode", uidString);
- }
-
- if((int)basicOpenerConfigAclPrefs[8] == 1)
- {
- JsonDocument json;
- json = createHassJson(uidString, "_fob_action_1", "Fob action 1", name, baseTopic, String("~") + mqtt_topic_config_basic_json, deviceType, "", "", "config", String("~") + mqtt_topic_config_action, {{ (char*)"val_tpl", (char*)"{{value_json.fobAction1}}" }, { (char*)"en", (char*)"true" }, { (char*)"cmd_tpl", (char*)"{ \"fobAction1\": \"{{ value }}\" }" }});
- json["options"][0] = "No Action";
- json["options"][1] = "Toggle RTO";
- json["options"][2] = "Activate RTO";
- json["options"][3] = "Deactivate RTO";
- json["options"][4] = "Open";
- json["options"][5] = "Ring";
- serializeJson(json, _buffer, _bufferSize);
- String path = createHassTopicPath("select", "fob_action_1", uidString);
- _device->mqttPublish(path.c_str(), MQTT_QOS_LEVEL, true, _buffer);
- }
- else
- {
- removeHassTopic((char*)"select", (char*)"fob_action_1", uidString);
- }
-
- if((int)basicOpenerConfigAclPrefs[9] == 1)
- {
- JsonDocument json;
- json = createHassJson(uidString, "_fob_action_2", "Fob action 2", name, baseTopic, String("~") + mqtt_topic_config_basic_json, deviceType, "", "", "config", String("~") + mqtt_topic_config_action, {{ (char*)"val_tpl", (char*)"{{value_json.fobAction2}}" }, { (char*)"en", (char*)"true" }, { (char*)"cmd_tpl", (char*)"{ \"fobAction2\": \"{{ value }}\" }" }});
- json["options"][0] = "No Action";
- json["options"][1] = "Toggle RTO";
- json["options"][2] = "Activate RTO";
- json["options"][3] = "Deactivate RTO";
- json["options"][4] = "Open";
- json["options"][5] = "Ring";
- serializeJson(json, _buffer, _bufferSize);
- String path = createHassTopicPath("select", "fob_action_2", uidString);
- _device->mqttPublish(path.c_str(), MQTT_QOS_LEVEL, true, _buffer);
- }
- else
- {
- removeHassTopic((char*)"select", (char*)"fob_action_2", uidString);
- }
-
- if((int)basicOpenerConfigAclPrefs[10] == 1)
- {
- JsonDocument json;
- json = createHassJson(uidString, "_fob_action_3", "Fob action 3", name, baseTopic, String("~") + mqtt_topic_config_basic_json, deviceType, "", "", "config", String("~") + mqtt_topic_config_action, {{ (char*)"val_tpl", (char*)"{{value_json.fobAction3}}" }, { (char*)"en", (char*)"true" }, { (char*)"cmd_tpl", (char*)"{ \"fobAction3\": \"{{ value }}\" }" }});
- json["options"][0] = "No Action";
- json["options"][1] = "Toggle RTO";
- json["options"][2] = "Activate RTO";
- json["options"][3] = "Deactivate RTO";
- json["options"][4] = "Open";
- json["options"][5] = "Ring";
- serializeJson(json, _buffer, _bufferSize);
- String path = createHassTopicPath("select", "fob_action_3", uidString);
- _device->mqttPublish(path.c_str(), MQTT_QOS_LEVEL, true, _buffer);
- }
- else
- {
- removeHassTopic((char*)"select", (char*)"fob_action_3", uidString);
- }
-
- if((int)basicOpenerConfigAclPrefs[12] == 1)
- {
- JsonDocument json;
- json = createHassJson(uidString, "_advertising_mode", "Advertising mode", name, baseTopic, String("~") + mqtt_topic_config_basic_json, deviceType, "", "", "config", String("~") + mqtt_topic_config_action, {{ (char*)"val_tpl", (char*)"{{value_json.advertisingMode}}" }, { (char*)"en", (char*)"true" }, { (char*)"cmd_tpl", (char*)"{ \"advertisingMode\": \"{{ value }}\" }" }});
- json["options"][0] = "Automatic";
- json["options"][1] = "Normal";
- json["options"][2] = "Slow";
- json["options"][3] = "Slowest";
- serializeJson(json, _buffer, _bufferSize);
- String path = createHassTopicPath("select", "advertising_mode", uidString);
- _device->mqttPublish(path.c_str(), MQTT_QOS_LEVEL, true, _buffer);
- }
- else
- {
- removeHassTopic((char*)"select", (char*)"advertising_mode", uidString);
- }
-
- if((int)basicOpenerConfigAclPrefs[13] == 1)
- {
- JsonDocument json;
- json = createHassJson(uidString, "_timezone", "Timezone", name, baseTopic, String("~") + mqtt_topic_config_basic_json, deviceType, "", "", "config", String("~") + mqtt_topic_config_action, {{ (char*)"val_tpl", (char*)"{{value_json.timeZone}}" }, { (char*)"en", (char*)"true" }, { (char*)"cmd_tpl", (char*)"{ \"timeZone\": \"{{ value }}\" }" }});
- json["options"][0] = "Africa/Cairo";
- json["options"][1] = "Africa/Lagos";
- json["options"][2] = "Africa/Maputo";
- json["options"][3] = "Africa/Nairobi";
- json["options"][4] = "America/Anchorage";
- json["options"][5] = "America/Argentina/Buenos_Aires";
- json["options"][6] = "America/Chicago";
- json["options"][7] = "America/Denver";
- json["options"][8] = "America/Halifax";
- json["options"][9] = "America/Los_Angeles";
- json["options"][10] = "America/Manaus";
- json["options"][11] = "America/Mexico_City";
- json["options"][12] = "America/New_York";
- json["options"][13] = "America/Phoenix";
- json["options"][14] = "America/Regina";
- json["options"][15] = "America/Santiago";
- json["options"][16] = "America/Sao_Paulo";
- json["options"][17] = "America/St_Johns";
- json["options"][18] = "Asia/Bangkok";
- json["options"][19] = "Asia/Dubai";
- json["options"][20] = "Asia/Hong_Kong";
- json["options"][21] = "Asia/Jerusalem";
- json["options"][22] = "Asia/Karachi";
- json["options"][23] = "Asia/Kathmandu";
- json["options"][24] = "Asia/Kolkata";
- json["options"][25] = "Asia/Riyadh";
- json["options"][26] = "Asia/Seoul";
- json["options"][27] = "Asia/Shanghai";
- json["options"][28] = "Asia/Tehran";
- json["options"][29] = "Asia/Tokyo";
- json["options"][30] = "Asia/Yangon";
- json["options"][31] = "Australia/Adelaide";
- json["options"][32] = "Australia/Brisbane";
- json["options"][33] = "Australia/Darwin";
- json["options"][34] = "Australia/Hobart";
- json["options"][35] = "Australia/Perth";
- json["options"][36] = "Australia/Sydney";
- json["options"][37] = "Europe/Berlin";
- json["options"][38] = "Europe/Helsinki";
- json["options"][39] = "Europe/Istanbul";
- json["options"][40] = "Europe/London";
- json["options"][41] = "Europe/Moscow";
- json["options"][42] = "Pacific/Auckland";
- json["options"][43] = "Pacific/Guam";
- json["options"][44] = "Pacific/Honolulu";
- json["options"][45] = "Pacific/Pago_Pago";
- json["options"][46] = "None";
-
- serializeJson(json, _buffer, _bufferSize);
- String path = createHassTopicPath("select", "timezone", uidString);
- _device->mqttPublish(path.c_str(), MQTT_QOS_LEVEL, true, _buffer);
- }
- else
- {
- removeHassTopic((char*)"select", (char*)"timezone", uidString);
- }
-
- if((int)basicOpenerConfigAclPrefs[11] == 1)
- {
- JsonDocument json;
- json = createHassJson(uidString, "_operating_mode", "Operating mode", name, baseTopic, String("~") + mqtt_topic_config_basic_json, deviceType, "", "", "config", String("~") + mqtt_topic_config_action, {{ (char*)"val_tpl", (char*)"{{value_json.operatingMode}}" }, { (char*)"en", (char*)"true" }, { (char*)"cmd_tpl", (char*)"{ \"operatingMode\": \"{{ value }}\" }" }});
- json["options"][0] = "Generic door opener";
- json["options"][1] = "Analogue intercom";
- json["options"][2] = "Digital intercom";
- json["options"][3] = "Siedle";
- json["options"][4] = "TCS";
- json["options"][5] = "Bticino";
- json["options"][6] = "Siedle HTS";
- json["options"][7] = "STR";
- json["options"][8] = "Ritto";
- json["options"][9] = "Fermax";
- json["options"][10] = "Comelit";
- json["options"][11] = "Urmet BiBus";
- json["options"][12] = "Urmet 2Voice";
- json["options"][13] = "Golmar";
- json["options"][14] = "SKS";
- json["options"][15] = "Spare";
- serializeJson(json, _buffer, _bufferSize);
- String path = createHassTopicPath("select", "operating_mode", uidString);
- _device->mqttPublish(path.c_str(), MQTT_QOS_LEVEL, true, _buffer);
- }
- else
- {
- removeHassTopic((char*)"select", (char*)"operating_mode", uidString);
- }
-
- if((int)advancedOpenerConfigAclPrefs[1] == 1)
- {
- // BUS mode switch analogue
- publishHassTopic("switch",
- "bus_mode_switch",
- uidString,
- "_bus_mode_switch",
- "BUS mode switch analogue",
- name,
- baseTopic,
- String("~") + mqtt_topic_config_advanced_json,
- deviceType,
- "",
- "",
- "config",
- String("~") + mqtt_topic_config_action,
- {
- { (char*)"en", (char*)"true" },
- { (char*)"pl_on", (char*)"{ \"busModeSwitch\": \"1\"}" },
- { (char*)"pl_off", (char*)"{ \"busModeSwitch\": \"0\"}" },
- { (char*)"val_tpl", (char*)"{{value_json.busModeSwitch}}" },
- { (char*)"stat_on", (char*)"1" },
- { (char*)"stat_off", (char*)"0" }
- });
- }
- else
- {
- removeHassTopic((char*)"switch", (char*)"bus_mode_switch", uidString);
- }
-
- if((int)advancedOpenerConfigAclPrefs[2] == 1)
- {
- publishHassTopic("number",
- "short_circuit_duration",
- uidString,
- "_short_circuit_duration",
- "Short circuit duration",
- name,
- baseTopic,
- String("~") + mqtt_topic_config_advanced_json,
- deviceType,
- "",
- "",
- "config",
- String("~") + mqtt_topic_config_action,
- {
- { (char*)"en", (char*)"true" },
- { (char*)"cmd_tpl", (char*)"{ \"shortCircuitDuration\": \"{{ value }}\" }" },
- { (char*)"val_tpl", (char*)"{{value_json.shortCircuitDuration}}" },
- { (char*)"min", (char*)"0" }
- });
- }
- else
- {
- removeHassTopic((char*)"number", (char*)"short_circuit_duration", uidString);
- }
-
- if((int)advancedOpenerConfigAclPrefs[3] == 1)
- {
- publishHassTopic("number",
- "electric_strike_delay",
- uidString,
- "_electric_strike_delay",
- "Electric strike delay",
- name,
- baseTopic,
- String("~") + mqtt_topic_config_advanced_json,
- deviceType,
- "",
- "",
- "config",
- String("~") + mqtt_topic_config_action,
- {
- { (char*)"en", (char*)"true" },
- { (char*)"cmd_tpl", (char*)"{ \"electricStrikeDelay\": \"{{ value }}\" }" },
- { (char*)"val_tpl", (char*)"{{value_json.electricStrikeDelay}}" },
- { (char*)"min", (char*)"0" },
- { (char*)"max", (char*)"30000" },
- { (char*)"step", (char*)"3000" }
- });
- }
- else
- {
- removeHassTopic((char*)"number", (char*)"electric_strike_delay", uidString);
- }
-
- if((int)advancedOpenerConfigAclPrefs[4] == 1)
- {
- // Random Electric Strike Delay
- publishHassTopic("switch",
- "random_electric_strike_delay",
- uidString,
- "_random_electric_strike_delay",
- "Random electric strike delay",
- name,
- baseTopic,
- String("~") + mqtt_topic_config_advanced_json,
- deviceType,
- "",
- "",
- "config",
- String("~") + mqtt_topic_config_action,
- {
- { (char*)"en", (char*)"true" },
- { (char*)"pl_on", (char*)"{ \"randomElectricStrikeDelay\": \"1\"}" },
- { (char*)"pl_off", (char*)"{ \"randomElectricStrikeDelay\": \"0\"}" },
- { (char*)"val_tpl", (char*)"{{value_json.randomElectricStrikeDelay}}" },
- { (char*)"stat_on", (char*)"1" },
- { (char*)"stat_off", (char*)"0" }
- });
- }
- else
- {
- removeHassTopic((char*)"switch", (char*)"random_electric_strike_delay", uidString);
- }
-
- if((int)advancedOpenerConfigAclPrefs[5] == 1)
- {
- publishHassTopic("number",
- "electric_strike_duration",
- uidString,
- "_electric_strike_duration",
- "Electric strike duration",
- name,
- baseTopic,
- String("~") + mqtt_topic_config_advanced_json,
- deviceType,
- "",
- "",
- "config",
- String("~") + mqtt_topic_config_action,
- {
- { (char*)"en", (char*)"true" },
- { (char*)"cmd_tpl", (char*)"{ \"electricStrikeDuration\": \"{{ value }}\" }" },
- { (char*)"val_tpl", (char*)"{{value_json.electricStrikeDuration}}" },
- { (char*)"min", (char*)"1000" },
- { (char*)"max", (char*)"30000" },
- { (char*)"step", (char*)"3000" }
- });
- }
- else
- {
- removeHassTopic((char*)"number", (char*)"electric_strike_duration", uidString);
- }
-
- if((int)advancedOpenerConfigAclPrefs[6] == 1)
- {
- // Disable RTO after ring
- publishHassTopic("switch",
- "disable_rto_after_ring",
- uidString,
- "_disable_rto_after_ring",
- "Disable RTO after ring",
- name,
- baseTopic,
- String("~") + mqtt_topic_config_advanced_json,
- deviceType,
- "",
- "",
- "config",
- String("~") + mqtt_topic_config_action,
- {
- { (char*)"en", (char*)"true" },
- { (char*)"pl_on", (char*)"{ \"disableRtoAfterRing\": \"1\"}" },
- { (char*)"pl_off", (char*)"{ \"disableRtoAfterRing\": \"0\"}" },
- { (char*)"val_tpl", (char*)"{{value_json.disableRtoAfterRing}}" },
- { (char*)"stat_on", (char*)"1" },
- { (char*)"stat_off", (char*)"0" }
- });
- }
- else
- {
- removeHassTopic((char*)"switch", (char*)"disable_rto_after_ring", uidString);
- }
-
- if((int)advancedOpenerConfigAclPrefs[7] == 1)
- {
- publishHassTopic("number",
- "rto_timeout",
- uidString,
- "_rto_timeout",
- "RTO timeout",
- name,
- baseTopic,
- String("~") + mqtt_topic_config_advanced_json,
- deviceType,
- "",
- "",
- "config",
- String("~") + mqtt_topic_config_action,
- {
- { (char*)"en", (char*)"true" },
- { (char*)"cmd_tpl", (char*)"{ \"rtoTimeout\": \"{{ value }}\" }" },
- { (char*)"val_tpl", (char*)"{{value_json.rtoTimeout}}" },
- { (char*)"min", (char*)"5" },
- { (char*)"max", (char*)"60" }
- });
- }
- else
- {
- removeHassTopic((char*)"number", (char*)"rto_timeout", uidString);
- }
-
- if((int)advancedOpenerConfigAclPrefs[8] == 1)
- {
- JsonDocument json;
- json = createHassJson(uidString, "_doorbell_suppression", "Doorbell suppression", name, baseTopic, String("~") + mqtt_topic_config_advanced_json, deviceType, "", "", "config", String("~") + mqtt_topic_config_action, {{ (char*)"val_tpl", (char*)"{{value_json.doorbellSuppression}}" }, { (char*)"en", (char*)"true" }, { (char*)"cmd_tpl", (char*)"{ \"doorbellSuppression\": \"{{ value }}\" }" }});
- json["options"][0] = "Off";
- json["options"][1] = "CM";
- json["options"][2] = "RTO";
- json["options"][3] = "CM & RTO";
- json["options"][4] = "Ring";
- json["options"][5] = "CM & Ring";
- json["options"][6] = "RTO & Ring";
- json["options"][7] = "CM & RTO & Ring";
- serializeJson(json, _buffer, _bufferSize);
- String path = createHassTopicPath("select", "doorbell_suppression", uidString);
- _device->mqttPublish(path.c_str(), MQTT_QOS_LEVEL, true, _buffer);
- }
- else
- {
- removeHassTopic((char*)"select", (char*)"doorbell_suppression", uidString);
- }
-
- if((int)advancedOpenerConfigAclPrefs[9] == 1)
- {
- publishHassTopic("number",
- "doorbell_suppression_duration",
- uidString,
- "_doorbell_suppression_duration",
- "Doorbell suppression duration",
- name,
- baseTopic,
- String("~") + mqtt_topic_config_advanced_json,
- deviceType,
- "",
- "",
- "config",
- String("~") + mqtt_topic_config_action,
- {
- { (char*)"en", (char*)"true" },
- { (char*)"cmd_tpl", (char*)"{ \"doorbellSuppressionDuration\": \"{{ value }}\" }" },
- { (char*)"val_tpl", (char*)"{{value_json.doorbellSuppressionDuration}}" },
- { (char*)"min", (char*)"500" },
- { (char*)"max", (char*)"10000" },
- { (char*)"step", (char*)"1000" }
- });
- }
- else
- {
- removeHassTopic((char*)"number", (char*)"doorbell_suppression_duration", uidString);
- }
-
- if((int)advancedOpenerConfigAclPrefs[10] == 1)
- {
- JsonDocument json;
- json = createHassJson(uidString, "_sound_ring", "Sound ring", name, baseTopic, String("~") + mqtt_topic_config_advanced_json, deviceType, "", "", "config", String("~") + mqtt_topic_config_action, {{ (char*)"val_tpl", (char*)"{{value_json.soundRing}}" }, { (char*)"en", (char*)"true" }, { (char*)"cmd_tpl", (char*)"{ \"soundRing\": \"{{ value }}\" }" }});
- json["options"][0] = "No Sound";
- json["options"][1] = "Sound 1";
- json["options"][2] = "Sound 2";
- json["options"][3] = "Sound 3";
- serializeJson(json, _buffer, _bufferSize);
- String path = createHassTopicPath("select", "sound_ring", uidString);
- _device->mqttPublish(path.c_str(), MQTT_QOS_LEVEL, true, _buffer);
- }
- else
- {
- removeHassTopic((char*)"select", (char*)"sound_ring", uidString);
- }
-
- if((int)advancedOpenerConfigAclPrefs[11] == 1)
- {
- JsonDocument json;
- json = createHassJson(uidString, "_sound_open", "Sound open", name, baseTopic, String("~") + mqtt_topic_config_advanced_json, deviceType, "", "", "config", String("~") + mqtt_topic_config_action, {{ (char*)"val_tpl", (char*)"{{value_json.soundOpen}}" }, { (char*)"en", (char*)"true" }, { (char*)"cmd_tpl", (char*)"{ \"soundOpen\": \"{{ value }}\" }" }});
- json["options"][0] = "No Sound";
- json["options"][1] = "Sound 1";
- json["options"][2] = "Sound 2";
- json["options"][3] = "Sound 3";
- serializeJson(json, _buffer, _bufferSize);
- String path = createHassTopicPath("select", "sound_open", uidString);
- _device->mqttPublish(path.c_str(), MQTT_QOS_LEVEL, true, _buffer);
- }
- else
- {
- removeHassTopic((char*)"select", (char*)"sound_open", uidString);
- }
-
- if((int)advancedOpenerConfigAclPrefs[12] == 1)
- {
- JsonDocument json;
- json = createHassJson(uidString, "_sound_rto", "Sound RTO", name, baseTopic, String("~") + mqtt_topic_config_advanced_json, deviceType, "", "", "config", String("~") + mqtt_topic_config_action, {{ (char*)"val_tpl", (char*)"{{value_json.soundRto}}" }, { (char*)"en", (char*)"true" }, { (char*)"cmd_tpl", (char*)"{ \"soundRto\": \"{{ value }}\" }" }});
- json["options"][0] = "No Sound";
- json["options"][1] = "Sound 1";
- json["options"][2] = "Sound 2";
- json["options"][3] = "Sound 3";
- serializeJson(json, _buffer, _bufferSize);
- String path = createHassTopicPath("select", "sound_rto", uidString);
- _device->mqttPublish(path.c_str(), MQTT_QOS_LEVEL, true, _buffer);
- }
- else
- {
- removeHassTopic((char*)"select", (char*)"sound_rto", uidString);
- }
-
- if((int)advancedOpenerConfigAclPrefs[13] == 1)
- {
- JsonDocument json;
- json = createHassJson(uidString, "_sound_cm", "Sound CM", name, baseTopic, String("~") + mqtt_topic_config_advanced_json, deviceType, "", "", "config", String("~") + mqtt_topic_config_action, {{ (char*)"val_tpl", (char*)"{{value_json.soundCm}}" }, { (char*)"en", (char*)"true" }, { (char*)"cmd_tpl", (char*)"{ \"soundCm\": \"{{ value }}\" }" }});
- json["options"][0] = "No Sound";
- json["options"][1] = "Sound 1";
- json["options"][2] = "Sound 2";
- json["options"][3] = "Sound 3";
- serializeJson(json, _buffer, _bufferSize);
- String path = createHassTopicPath("select", "sound_cm", uidString);
- _device->mqttPublish(path.c_str(), MQTT_QOS_LEVEL, true, _buffer);
- }
- else
- {
- removeHassTopic((char*)"select", (char*)"sound_cm", uidString);
- }
-
- if((int)advancedOpenerConfigAclPrefs[14] == 1)
- {
- // Sound confirmation
- publishHassTopic("switch",
- "sound_confirmation",
- uidString,
- "_sound_confirmation",
- "Sound confirmation",
- name,
- baseTopic,
- String("~") + mqtt_topic_config_advanced_json,
- deviceType,
- "",
- "",
- "config",
- String("~") + mqtt_topic_config_action,
- {
- { (char*)"en", (char*)"true" },
- { (char*)"pl_on", (char*)"{ \"soundConfirmation\": \"1\"}" },
- { (char*)"pl_off", (char*)"{ \"soundConfirmation\": \"0\"}" },
- { (char*)"val_tpl", (char*)"{{value_json.soundConfirmation}}" },
- { (char*)"stat_on", (char*)"1" },
- { (char*)"stat_off", (char*)"0" }
- });
- }
- else
- {
- removeHassTopic((char*)"switch", (char*)"sound_confirmation", uidString);
- }
-
- if((int)advancedOpenerConfigAclPrefs[16] == 1)
- {
- JsonDocument json;
- json = createHassJson(uidString, "_single_button_press_action", "Single button press action", name, baseTopic, String("~") + mqtt_topic_config_advanced_json, deviceType, "", "", "config", String("~") + mqtt_topic_config_action, {{ (char*)"val_tpl", (char*)"{{value_json.singleButtonPressAction}}" }, { (char*)"en", (char*)"true" }, { (char*)"cmd_tpl", (char*)"{ \"singleButtonPressAction\": \"{{ value }}\" }" }});
- json["options"][0] = "No Action";
- json["options"][1] = "Toggle RTO";
- json["options"][2] = "Activate RTO";
- json["options"][3] = "Deactivate RTO";
- json["options"][4] = "Toggle CM";
- json["options"][5] = "Activate CM";
- json["options"][6] = "Deactivate CM";
- json["options"][7] = "Open";
- serializeJson(json, _buffer, _bufferSize);
- String path = createHassTopicPath("select", "single_button_press_action", uidString);
- _device->mqttPublish(path.c_str(), MQTT_QOS_LEVEL, true, _buffer);
- }
- else
- {
- removeHassTopic((char*)"select", (char*)"single_button_press_action", uidString);
- }
-
- if((int)advancedOpenerConfigAclPrefs[17] == 1)
- {
- JsonDocument json;
- json = createHassJson(uidString, "_double_button_press_action", "Double button press action", name, baseTopic, String("~") + mqtt_topic_config_advanced_json, deviceType, "", "", "config", String("~") + mqtt_topic_config_action, {{ (char*)"val_tpl", (char*)"{{value_json.doubleButtonPressAction}}" }, { (char*)"en", (char*)"true" }, { (char*)"cmd_tpl", (char*)"{ \"doubleButtonPressAction\": \"{{ value }}\" }" }});
- json["options"][0] = "No Action";
- json["options"][1] = "Toggle RTO";
- json["options"][2] = "Activate RTO";
- json["options"][3] = "Deactivate RTO";
- json["options"][4] = "Toggle CM";
- json["options"][5] = "Activate CM";
- json["options"][6] = "Deactivate CM";
- json["options"][7] = "Open";
- serializeJson(json, _buffer, _bufferSize);
- String path = createHassTopicPath("select", "double_button_press_action", uidString);
- _device->mqttPublish(path.c_str(), MQTT_QOS_LEVEL, true, _buffer);
- }
- else
- {
- removeHassTopic((char*)"select", (char*)"double_button_press_action", uidString);
- }
-
- if((int)advancedOpenerConfigAclPrefs[18] == 1)
- {
- JsonDocument json;
- json = createHassJson(uidString, "_battery_type", "Battery type", name, baseTopic, String("~") + mqtt_topic_config_advanced_json, deviceType, "", "", "config", String("~") + mqtt_topic_config_action, {{ (char*)"val_tpl", (char*)"{{value_json.batteryType}}" }, { (char*)"en", (char*)"true" }, { (char*)"cmd_tpl", (char*)"{ \"batteryType\": \"{{ value }}\" }" }});
- json["options"][0] = "Alkali";
- json["options"][1] = "Accumulators";
- json["options"][2] = "Lithium";
- serializeJson(json, _buffer, _bufferSize);
- String path = createHassTopicPath("select", "battery_type", uidString);
- _device->mqttPublish(path.c_str(), MQTT_QOS_LEVEL, true, _buffer);
- }
- else
- {
- removeHassTopic((char*)"select", (char*)"battery_type", uidString);
- }
-
- if((int)advancedOpenerConfigAclPrefs[19] == 1)
- {
- // Automatic battery type detection
- publishHassTopic("switch",
- "automatic_battery_type_detection",
- uidString,
- "_automatic_battery_type_detection",
- "Automatic battery type detection",
- name,
- baseTopic,
- String("~") + mqtt_topic_config_advanced_json,
- deviceType,
- "",
- "",
- "config",
- String("~") + mqtt_topic_config_action,
- {
- { (char*)"en", (char*)"true" },
- { (char*)"pl_on", (char*)"{ \"automaticBatteryTypeDetection\": \"1\"}" },
- { (char*)"pl_off", (char*)"{ \"automaticBatteryTypeDetection\": \"0\"}" },
- { (char*)"val_tpl", (char*)"{{value_json.automaticBatteryTypeDetection}}" },
- { (char*)"stat_on", (char*)"1" },
- { (char*)"stat_off", (char*)"0" }
- });
- }
- else
- {
- removeHassTopic((char*)"switch", (char*)"automatic_battery_type_detection", uidString);
- }
-}
-
-void NukiNetwork::publishHASSConfigAccessLog(char *deviceType, const char *baseTopic, char *name, char *uidString)
-{
- publishHassTopic("sensor",
- "last_action_authorization",
- uidString,
- "_last_action_authorization",
- "Last action authorization",
- name,
- baseTopic,
- String("~") + mqtt_topic_lock_log,
- deviceType,
- "",
- "",
- "diagnostic",
- "",
- {
- { (char*)"ic", (char*)"mdi:format-list-bulleted" },
- { (char*)"val_tpl", (char*)"{{ (value_json|selectattr('type', 'eq', 'LockAction')|selectattr('action', 'in', ['Lock', 'Unlock', 'Unlatch'])|first|default).authorizationName|default }}" }
- });
-
- String rollingSate = "~";
- rollingSate.concat(mqtt_topic_lock_log_rolling);
- const char *rollingStateChr = rollingSate.c_str();
-
- publishHassTopic("sensor",
- "rolling_log",
- uidString,
- "_rolling_log",
- "Rolling authorization log",
- name,
- baseTopic,
- String("~") + mqtt_topic_lock_log_rolling,
- deviceType,
- "",
- "",
- "diagnostic",
- "",
- {
- { (char*)"ic", (char*)"mdi:format-list-bulleted" },
- { (char*)"json_attr_t", (char*)rollingStateChr },
- { (char*)"val_tpl", (char*)"{{value_json.index}}" }
- });
-}
-
-void NukiNetwork::publishHASSConfigKeypad(char *deviceType, const char *baseTopic, char *name, char *uidString)
-{
- // Keypad battery critical
- publishHassTopic("binary_sensor",
- "keypad_battery_low",
- uidString,
- "_keypad_battery_low",
- "Keypad battery low",
- name,
- baseTopic,
- String("~") + mqtt_topic_battery_basic_json,
- deviceType,
- "battery",
- "",
- "diagnostic",
- "",
- {
- {(char*)"pl_on", (char*)"1"},
- {(char*)"pl_off", (char*)"0"},
- {(char*)"val_tpl", (char*)"{{value_json.keypadCritical}}" }
- });
-
- // Query Keypad
- publishHassTopic("button",
- "query_keypad",
- uidString,
- "_query_keypad",
- "Query keypad",
- name,
- baseTopic,
- "",
- deviceType,
- "",
- "",
- "diagnostic",
- String("~") + mqtt_topic_query_keypad,
- {
- { (char*)"en", (char*)"false" },
- { (char*)"pl_prs", (char*)"1" }
- });
-
- publishHassTopic("sensor",
- "keypad_status",
- uidString,
- "_keypad_stats",
- "Keypad status",
- name,
- baseTopic,
- String("~") + mqtt_topic_lock_log,
- deviceType,
- "",
- "",
- "diagnostic",
- "",
- {
- { (char*)"ic", (char*)"mdi:drag-vertical" },
- { (char*)"val_tpl", (char*)"{{ (value_json|selectattr('type', 'eq', 'KeypadAction')|first|default).completionStatus|default }}" }
- });
-}
-
-void NukiNetwork::publishHASSWifiRssiConfig(char *deviceType, const char *baseTopic, char *name, char *uidString)
-{
- if(_device->signalStrength() == 127)
- {
- return;
- }
-
- publishHassTopic("sensor",
- "wifi_signal_strength",
- uidString,
- "_wifi_signal_strength",
- "WIFI signal strength",
- name,
- baseTopic,
- _lockPath + mqtt_topic_wifi_rssi,
- deviceType,
- "signal_strength",
- "measurement",
- "diagnostic",
- "",
- { {(char*)"unit_of_meas", (char*)"dBm"} });
+ _hadiscovery->disableHASS();
}
void NukiNetwork::publishHassTopic(const String& mqttDeviceType,
@@ -3813,223 +1136,12 @@ void NukiNetwork::publishHassTopic(const String& mqttDeviceType,
std::vector> additionalEntries
)
{
- if (_discoveryTopic != "")
- {
- JsonDocument json;
- json = createHassJson(uidString, uidStringPostfix, displayName, name, baseTopic, stateTopic, deviceType, deviceClass, stateClass, entityCat, commandTopic, additionalEntries);
- serializeJson(json, _buffer, _bufferSize);
- String path = createHassTopicPath(mqttDeviceType, mqttDeviceName, uidString);
- _device->mqttPublish(path.c_str(), MQTT_QOS_LEVEL, true, _buffer);
- }
-}
-
-String NukiNetwork::createHassTopicPath(const String& mqttDeviceType, const String& mqttDeviceName, const String& uidString)
-{
- String path = _discoveryTopic;
- path.concat("/");
- path.concat(mqttDeviceType);
- path.concat("/");
- path.concat(uidString);
- path.concat("/");
- path.concat(mqttDeviceName);
- path.concat("/config");
-
- return path;
+ _hadiscovery->publishHassTopic(mqttDeviceType, mqttDeviceName, uidString, uidStringPostfix, displayName, name, baseTopic, stateTopic, deviceType, deviceClass, stateClass, entityCat, commandTopic, additionalEntries);
}
void NukiNetwork::removeHassTopic(const String& mqttDeviceType, const String& mqttDeviceName, const String& uidString)
{
- if (_discoveryTopic != "")
- {
- String path = createHassTopicPath(mqttDeviceType, mqttDeviceName, uidString);
- _device->mqttPublish(path.c_str(), MQTT_QOS_LEVEL, true, "");
- }
-}
-
-void NukiNetwork::removeTopic(const String& mqttPath, const String& mqttTopic)
-{
- String path = mqttPath;
- path.concat(mqttTopic);
- _device->mqttPublish(path.c_str(), MQTT_QOS_LEVEL, true, "");
-
-#ifdef DEBUG_NUKIHUB
- Log->print(F("Removing MQTT topic: "));
- Log->println(path.c_str());
-#endif
-}
-
-
-void NukiNetwork::removeHASSConfig(char* uidString)
-{
- removeHassTopic((char*)"lock", (char*)"smartlock", uidString);
- removeHassTopic((char*)"binary_sensor", (char*)"battery_low", uidString);
- removeHassTopic((char*)"binary_sensor", (char*)"keypad_battery_low", uidString);
- removeHassTopic((char*)"sensor", (char*)"battery_voltage", uidString);
- removeHassTopic((char*)"sensor", (char*)"trigger", uidString);
- removeHassTopic((char*)"binary_sensor", (char*)"mqtt_connected", uidString);
- removeHassTopic((char*)"switch", (char*)"reset", uidString);
- removeHassTopic((char*)"sensor", (char*)"firmware_version", uidString);
- removeHassTopic((char*)"sensor", (char*)"hardware_version", uidString);
- removeHassTopic((char*)"sensor", (char*)"nuki_hub_version", uidString);
- removeHassTopic((char*)"sensor", (char*)"nuki_hub_build", uidString);
- removeHassTopic((char*)"sensor", (char*)"nuki_hub_latest", uidString);
- removeHassTopic((char*)"update", (char*)"nuki_hub_update", uidString);
- removeHassTopic((char*)"sensor", (char*)"nuki_hub_ip", uidString);
- removeHassTopic((char*)"button", (char*)"unlatch", uidString);
- removeHassTopic((char*)"button", (char*)"lockngo", uidString);
- removeHassTopic((char*)"button", (char*)"lockngounlatch", uidString);
- removeHassTopic((char*)"sensor", (char*)"battery_level", uidString);
- removeHassTopic((char*)"binary_sensor", (char*)"door_sensor", uidString);
- removeHassTopic((char*)"binary_sensor", (char*)"ring_detect", uidString);
- removeHassTopic((char*)"sensor", (char*)"sound_level", uidString);
- removeHassTopic((char*)"sensor", (char*)"last_action_authorization", uidString);
- removeHassTopic((char*)"sensor", (char*)"keypad_status", uidString);
- removeHassTopic((char*)"sensor", (char*)"rolling_log", uidString);
- removeHassTopic((char*)"sensor", (char*)"wifi_signal_strength", uidString);
- removeHassTopic((char*)"sensor", (char*)"bluetooth_signal_strength", uidString);
- removeHassTopic((char*)"binary_sensor", (char*)"continuous_mode", uidString);
- removeHassTopic((char*)"switch", (char*)"continuous_mode", uidString);
- removeHassTopic((char*)"button", (char*)"query_lockstate", uidString);
- removeHassTopic((char*)"button", (char*)"query_config", uidString);
- removeHassTopic((char*)"button", (char*)"query_keypad", uidString);
- removeHassTopic((char*)"button", (char*)"query_battery", uidString);
- removeHassTopic((char*)"button", (char*)"query_commandresult", uidString);
- removeHassTopic((char*)"switch", (char*)"auto_lock", uidString);
- removeHassTopic((char*)"switch", (char*)"auto_unlock", uidString);
- removeHassTopic((char*)"switch", (char*)"double_lock", uidString);
- removeHassTopic((char*)"switch", (char*)"automatic_battery_type_detection", uidString);
- removeHassTopic((char*)"select", (char*)"battery_type", uidString);
- removeHassTopic((char*)"select", (char*)"double_button_press_action", uidString);
- removeHassTopic((char*)"select", (char*)"single_button_press_action", uidString);
- removeHassTopic((char*)"switch", (char*)"sound_confirmation", uidString);
- removeHassTopic((char*)"select", (char*)"sound_cm", uidString);
- removeHassTopic((char*)"select", (char*)"sound_rto", uidString);
- removeHassTopic((char*)"select", (char*)"sound_open", uidString);
- removeHassTopic((char*)"select", (char*)"sound_ring", uidString);
- removeHassTopic((char*)"number", (char*)"doorbell_suppression_duration", uidString);
- removeHassTopic((char*)"select", (char*)"doorbell_suppression", uidString);
- removeHassTopic((char*)"number", (char*)"rto_timeout", uidString);
- removeHassTopic((char*)"switch", (char*)"disable_rto_after_ring", uidString);
- removeHassTopic((char*)"number", (char*)"electric_strike_duration", uidString);
- removeHassTopic((char*)"switch", (char*)"random_electric_strike_delay", uidString);
- removeHassTopic((char*)"number", (char*)"electric_strike_delay", uidString);
- removeHassTopic((char*)"number", (char*)"short_circuit_duration", uidString);
- removeHassTopic((char*)"switch", (char*)"bus_mode_switch", uidString);
- removeHassTopic((char*)"select", (char*)"operating_mode", uidString);
- removeHassTopic((char*)"select", (char*)"timezone", uidString);
- removeHassTopic((char*)"select", (char*)"advertising_mode", uidString);
- removeHassTopic((char*)"select", (char*)"fob_action_3", uidString);
- removeHassTopic((char*)"select", (char*)"fob_action_2", uidString);
- removeHassTopic((char*)"select", (char*)"fob_action_1", uidString);
- removeHassTopic((char*)"switch", (char*)"dst_mode", uidString);
- removeHassTopic((char*)"number", (char*)"timezone_offset", uidString);
- removeHassTopic((char*)"switch", (char*)"pairing_enabled", uidString);
- removeHassTopic((char*)"number", (char*)"sound_level", uidString);
- removeHassTopic((char*)"switch", (char*)"button_enabled", uidString);
- removeHassTopic((char*)"switch", (char*)"led_enabled", uidString);
- removeHassTopic((char*)"number", (char*)"led_brightness", uidString);
- removeHassTopic((char*)"switch", (char*)"auto_update_enabled", uidString);
- removeHassTopic((char*)"switch", (char*)"immediate_auto_lock_enabled", uidString);
- removeHassTopic((char*)"switch", (char*)"nightmode_immediate_lock_start", uidString);
- removeHassTopic((char*)"switch", (char*)"nightmode_auto_unlock", uidString);
- removeHassTopic((char*)"switch", (char*)"nightmode_auto_lock", uidString);
- removeHassTopic((char*)"text", (char*)"nightmode_end_time", uidString);
- removeHassTopic((char*)"text", (char*)"nightmode_start_time", uidString);
- removeHassTopic((char*)"switch", (char*)"nightmode_enabled", uidString);
- removeHassTopic((char*)"number", (char*)"auto_lock_timeout", uidString);
- removeHassTopic((char*)"number", (char*)"unlatch_duration", uidString);
- removeHassTopic((char*)"switch", (char*)"detached_cylinder", uidString);
- removeHassTopic((char*)"number", (char*)"lockngo_timeout", uidString);
- removeHassTopic((char*)"number", (char*)"unlocked_locked_transition_offset_degrees", uidString);
- removeHassTopic((char*)"number", (char*)"single_locked_position_offset_degrees", uidString);
- removeHassTopic((char*)"number", (char*)"locked_position_offset_degrees", uidString);
- removeHassTopic((char*)"number", (char*)"unlocked_position_offset_degrees", uidString);
- removeHassTopic((char*)"switch", (char*)"pairing_enabled", uidString);
- removeHassTopic((char*)"switch", (char*)"auto_unlatch", uidString);
- removeHassTopic((char*)"sensor", (char*)"network_device", uidString);
- removeHassTopic((char*)"switch", (char*)"webserver", uidString);
- removeHassTopic((char*)"sensor", (char*)"uptime", uidString);
- removeHassTopic((char*)"sensor", (char*)"mqtt_log", uidString);
- removeHassTopic((char*)"binary_sensor", (char*)"hybrid_connected", uidString);
- removeHassTopic((char*)"sensor", (char*)"nuki_hub_restart_reason", uidString);
- removeHassTopic((char*)"sensor", (char*)"nuki_hub_restart_reason_esp", uidString);
-}
-
-void NukiNetwork::removeHASSConfigTopic(char *deviceType, char *name, char *uidString)
-{
- removeHassTopic(deviceType, name, uidString);
-}
-
-JsonDocument NukiNetwork::createHassJson(const String& uidString,
- const String& uidStringPostfix,
- const String& displayName,
- const String& name,
- const String& baseTopic,
- const String& stateTopic,
- const String& deviceType,
- const String& deviceClass,
- const String& stateClass,
- const String& entityCat,
- const String& commandTopic,
- std::vector> additionalEntries
- )
-{
- JsonDocument json;
- json.clear();
- JsonObject dev = json["dev"].to();
- JsonArray ids = dev["ids"].to();
- ids.add(String("nuki_") + uidString);
- json["dev"]["mf"] = "Nuki";
- json["dev"]["mdl"] = deviceType;
- json["dev"]["name"] = name;
- json["~"] = baseTopic;
- json["name"] = displayName;
- json["unique_id"] = String(uidString) + uidStringPostfix;
-
- if(deviceClass != "")
- {
- json["dev_cla"] = deviceClass;
- }
-
- if(stateTopic != "")
- {
- json["stat_t"] = stateTopic;
- }
-
- if(stateClass != "")
- {
- json["stat_cla"] = stateClass;
- }
-
- if(entityCat != "")
- {
- json["ent_cat"] = entityCat;
- }
-
- if(commandTopic != "")
- {
- json["cmd_t"] = commandTopic;
- }
-
- json["avty"]["t"] = _lockPath + mqtt_topic_mqtt_connection_state;
-
- for(const auto& entry : additionalEntries)
- {
- if(strcmp(entry.second, "true") == 0)
- {
- json[entry.first] = true;
- }
- else if(strcmp(entry.second, "false") == 0)
- {
- json[entry.first] = false;
- }
- else
- {
- json[entry.first] = entry.second;
- }
- }
-
- return json;
+ _hadiscovery->removeHassTopic(mqttDeviceType, mqttDeviceName, uidString);
}
void NukiNetwork::batteryTypeToString(const Nuki::BatteryType battype, char* str)
@@ -4246,7 +1358,7 @@ void NukiNetwork::addReconnectedCallback(std::function reconnectedCallba
void NukiNetwork::disableMqtt()
{
- _device->disableMqtt();
+ _device->mqttDisable();
_mqttEnabled = false;
}
diff --git a/src/NukiNetwork.h b/src/NukiNetwork.h
index 0cf6265..ee40c97 100644
--- a/src/NukiNetwork.h
+++ b/src/NukiNetwork.h
@@ -15,6 +15,7 @@
#include "Gpio.h"
#include
#include "NukiConstants.h"
+#include "HomeAssistantDiscovery.h"
#endif
class NukiNetwork
@@ -56,37 +57,31 @@ public:
void publishLongLong(const char* prefix, const char* topic, int64_t value, bool retain);
void publishBool(const char* prefix, const char* topic, const bool value, bool retain);
void publishString(const char* prefix, const char* topic, const char* value, bool retain);
-
- void publishHASSConfig(char* deviceType, const char* baseTopic, char* name, char* uidString, const char *softwareVersion, const char *hardwareVersion, const char* availabilityTopic, const bool& hasKeypad, char* lockAction, char* unlockAction, char* openAction);
- void publishHASSConfigAdditionalLockEntities(char* deviceType, const char* baseTopic, char* name, char* uidString);
- void publishHASSConfigDoorSensor(char* deviceType, const char* baseTopic, char* name, char* uidString);
- void publishHASSConfigAdditionalOpenerEntities(char* deviceType, const char* baseTopic, char* name, char* uidString);
- void publishHASSConfigAccessLog(char* deviceType, const char* baseTopic, char* name, char* uidString);
- void publishHASSConfigKeypad(char* deviceType, const char* baseTopic, char* name, char* uidString);
- void publishHASSWifiRssiConfig(char* deviceType, const char* baseTopic, char* name, char* uidString);
- void removeHASSConfig(char* uidString);
- void removeHASSConfigTopic(char* deviceType, char* name, char* uidString);
- void publishHassTopic(const String& mqttDeviceType,
- const String& mqttDeviceName,
- const String& uidString,
- const String& uidStringPostfix,
- const String& displayName,
- const String& name,
- const String& baseTopic,
- const String& stateTopic,
- const String& deviceType,
- const String& deviceClass,
- const String& stateClass = "",
- const String& entityCat = "",
- const String& commandTopic = "",
- std::vector> additionalEntries = {}
- );
- void removeHassTopic(const String& mqttDeviceType, const String& mqttDeviceName, const String& uidString);
+ void publish(const char *topic, const char *value, bool retain);
void removeTopic(const String& mqttPath, const String& mqttTopic);
void batteryTypeToString(const Nuki::BatteryType battype, char* str);
void advertisingModeToString(const Nuki::AdvertisingMode advmode, char* str);
void timeZoneIdToString(const Nuki::TimeZoneId timeZoneId, char* str);
+ void setupHASS(int type, uint32_t nukiId, char* nukiName, const char* firmwareVersion, const char* hardwareVersion, bool hasDoorSensor, bool hasKeypad);
+ void disableHASS();
+ void publishHassTopic(const String& mqttDeviceType,
+ const String& mqttDeviceName,
+ const String& uidString,
+ const String& uidStringPostfix,
+ const String& displayName,
+ const String& name,
+ const String& baseTopic,
+ const String& stateTopic,
+ const String& deviceType,
+ const String& deviceClass,
+ const String& stateClass,
+ const String& entityCat,
+ const String& commandTopic,
+ std::vector> additionalEntries
+ );
+ void removeHassTopic(const String& mqttDeviceType, const String& mqttDeviceName, const String& uidString);
+
int mqttConnectionState(); // 0 = not connected; 1 = connected; 2 = connected and mqtt processed
bool mqttRecentlyConnected();
bool pathEquals(const char* prefix, const char* path, const char* referencePath);
@@ -113,8 +108,6 @@ private:
NetworkDeviceType _networkDeviceType = (NetworkDeviceType)-1;
bool _firstBootAfterDeviceChange = false;
bool _webEnabled = true;
- bool _updateFromMQTT = false;
- bool _offEnabled = false;
#ifndef NUKI_HUB_UPDATER
static void onMqttDataReceivedCallback(const espMqttClientTypes::MessageProperties& properties, const char* topic, const uint8_t* payload, size_t len, size_t index, size_t total);
@@ -125,30 +118,16 @@ private:
void parseGpioTopics(const espMqttClientTypes::MessageProperties& properties, const char* topic, const uint8_t* payload, size_t& len, size_t& index, size_t& total);
void gpioActionCallback(const GpioAction& action, const int& pin);
bool comparePrefixedPath(const char* fullPath, const char* subPath);
-
- String createHassTopicPath(const String& mqttDeviceType, const String& mqttDeviceName, const String& uidString);
- JsonDocument createHassJson(const String& uidString,
- const String& uidStringPostfix,
- const String& displayName,
- const String& name,
- const String& baseTopic,
- const String& stateTopic,
- const String& deviceType,
- const String& deviceClass,
- const String& stateClass = "",
- const String& entityCat = "",
- const String& commandTopic = "",
- std::vector> additionalEntries = {}
- );
- void buildMqttPath(char* outPath, std::initializer_list paths);
void buildMqttPath(const char *path, char *outPath);
+ void buildMqttPath(char* outPath, std::initializer_list paths);
const char* _lastWillPayload = "offline";
char _mqttConnectionStateTopic[211] = {0};
String _lockPath;
- String _discoveryTopic;
String _brokerAddr;
+ HomeAssistantDiscovery* _hadiscovery = nullptr;
+
Gpio* _gpio;
int _mqttConnectionState = 0;
diff --git a/src/NukiNetworkLock.cpp b/src/NukiNetworkLock.cpp
index 1086f02..9169e3a 100644
--- a/src/NukiNetworkLock.cpp
+++ b/src/NukiNetworkLock.cpp
@@ -1516,53 +1516,6 @@ bool NukiNetworkLock::comparePrefixedPath(const char *fullPath, const char *subP
return strcmp(fullPath, prefixedPath) == 0;
}
-void NukiNetworkLock::publishHASSConfig(char *deviceType, const char *baseTopic, char *name, char *uidString, const char *softwareVersion, const char *hardwareVersion, const bool& hasDoorSensor, const bool& hasKeypad, const bool& publishAuthData, char *lockAction,
- char *unlockAction, char *openAction)
-{
- String availabilityTopic = _preferences->getString(preference_mqtt_lock_path);
- availabilityTopic.concat("/maintenance/mqttConnectionState");
- _network->publishHASSConfig(deviceType, baseTopic, name, uidString, softwareVersion, hardwareVersion, availabilityTopic.c_str(), hasKeypad, lockAction, unlockAction, openAction);
- _network->publishHASSConfigAdditionalLockEntities(deviceType, baseTopic, name, uidString);
-
- if(hasDoorSensor)
- {
- _network->publishHASSConfigDoorSensor(deviceType, baseTopic, name, uidString);
- }
- else
- {
- _network->removeHASSConfigTopic((char*)"binary_sensor", (char*)"door_sensor", uidString);
- }
-
-#ifndef CONFIG_IDF_TARGET_ESP32H2
- _network->publishHASSWifiRssiConfig(deviceType, baseTopic, name, uidString);
-#endif
-
- if(publishAuthData)
- {
- _network->publishHASSConfigAccessLog(deviceType, baseTopic, name, uidString);
- }
- else
- {
- _network->removeHASSConfigTopic((char*)"sensor", (char*)"last_action_authorization", uidString);
- _network->removeHASSConfigTopic((char*)"sensor", (char*)"rolling_log", uidString);
- }
-
- if(hasKeypad)
- {
- _network->publishHASSConfigKeypad(deviceType, baseTopic, name, uidString);
- }
- else
- {
- _network->removeHASSConfigTopic((char*)"sensor", (char*)"keypad_status", uidString);
- _network->removeHASSConfigTopic((char*)"binary_sensor", (char*)"keypad_battery_low", uidString);
- }
-}
-
-void NukiNetworkLock::removeHASSConfig(char *uidString)
-{
- _network->removeHASSConfig(uidString);
-}
-
void NukiNetworkLock::publishOffAction(const int value)
{
_network->publishInt(_nukiOfficial->getMqttPath(), mqtt_topic_official_lock_action, value, false);
@@ -1645,6 +1598,11 @@ uint8_t NukiNetworkLock::queryCommands()
return qc;
}
+void NukiNetworkLock::setupHASS(int type, uint32_t nukiId, char* nukiName, const char* firmwareVersion, const char* hardwareVersion, bool hasDoorSensor, bool hasKeypad)
+{
+ _network->setupHASS(type, nukiId, nukiName, firmwareVersion, hardwareVersion, hasDoorSensor, hasKeypad);
+}
+
void NukiNetworkLock::buttonPressActionToString(const NukiLock::ButtonPressAction btnPressAction, char* str)
{
switch (btnPressAction)
diff --git a/src/NukiNetworkLock.h b/src/NukiNetworkLock.h
index 1dbdb3d..231ce5f 100644
--- a/src/NukiNetworkLock.h
+++ b/src/NukiNetworkLock.h
@@ -37,8 +37,6 @@ public:
void publishRssi(const int& rssi);
void publishRetry(const std::string& message);
void publishBleAddress(const std::string& address);
- void publishHASSConfig(char* deviceType, const char* baseTopic, char* name, char* uidString, const char *softwareVersion, const char *hardwareVersion, const bool& hasDoorSensor, const bool& hasKeypad, const bool& publishAuthData, char* lockAction, char* unlockAction, char* openAction);
- void removeHASSConfig(char* uidString);
void publishKeypad(const std::list& entries, uint maxKeypadCodeCount);
void publishTimeControl(const std::list& timeControlEntries, uint maxTimeControlEntryCount);
void publishAuth(const std::list& authEntries, uint maxAuthEntryCount);
@@ -58,6 +56,7 @@ public:
void setTimeControlCommandReceivedCallback(void (*timeControlCommandReceivedReceivedCallback)(const char* value));
void setAuthCommandReceivedCallback(void (*authCommandReceivedReceivedCallback)(const char* value));
void onMqttDataReceived(const char* topic, byte* payload, const unsigned int length) override;
+ void setupHASS(int type, uint32_t nukiId, char* nukiName, const char* firmwareVersion, const char* hardwareVersion, bool hasDoorSensor, bool hasKeypad);
void publishFloat(const char* topic, const float value, bool retain, const uint8_t precision = 2);
void publishInt(const char* topic, const int value, bool retain);
diff --git a/src/NukiNetworkOpener.cpp b/src/NukiNetworkOpener.cpp
index 3dbf265..08f0e0a 100644
--- a/src/NukiNetworkOpener.cpp
+++ b/src/NukiNetworkOpener.cpp
@@ -859,38 +859,6 @@ void NukiNetworkOpener::publishBleAddress(const std::string &address)
publishString(mqtt_topic_lock_address, address, true);
}
-void NukiNetworkOpener::publishHASSConfig(char* deviceType, const char* baseTopic, char* name, char* uidString, const char *softwareVersion, const char *hardwareVersion, const bool& publishAuthData, const bool& hasKeypad, char* lockAction, char* unlockAction, char* openAction)
-{
- String availabilityTopic = _preferences->getString(preference_mqtt_lock_path);
- availabilityTopic.concat("/maintenance/mqttConnectionState");
-
- _network->publishHASSConfig(deviceType, baseTopic, name, uidString, softwareVersion, hardwareVersion, availabilityTopic.c_str(), hasKeypad, lockAction, unlockAction, openAction);
- _network->publishHASSConfigAdditionalOpenerEntities(deviceType, baseTopic, name, uidString);
- if(publishAuthData)
- {
- _network->publishHASSConfigAccessLog(deviceType, baseTopic, name, uidString);
- }
- else
- {
- _network->removeHASSConfigTopic((char*)"sensor", (char*)"last_action_authorization", uidString);
- _network->removeHASSConfigTopic((char*)"sensor", (char*)"rolling_log", uidString);
- }
- if(hasKeypad)
- {
- _network->publishHASSConfigKeypad(deviceType, baseTopic, name, uidString);
- }
- else
- {
- _network->removeHASSConfigTopic((char*)"sensor", (char*)"keypad_status", uidString);
- _network->removeHASSConfigTopic((char*)"binary_sensor", (char*)"keypad_battery_low", uidString);
- }
-}
-
-void NukiNetworkOpener::removeHASSConfig(char* uidString)
-{
- _network->removeHASSConfig(uidString);
-}
-
void NukiNetworkOpener::publishKeypad(const std::list& entries, uint maxKeypadCodeCount)
{
bool publishCode = _preferences->getBool(preference_keypad_publish_code, false);
@@ -1588,6 +1556,11 @@ uint8_t NukiNetworkOpener::queryCommands()
return qc;
}
+void NukiNetworkOpener::setupHASS(int type, uint32_t nukiId, char* nukiName, const char* firmwareVersion, const char* hardwareVersion, bool hasDoorSensor, bool hasKeypad)
+{
+ _network->setupHASS(type, nukiId, nukiName, firmwareVersion, hardwareVersion, hasDoorSensor, hasKeypad);
+}
+
void NukiNetworkOpener::buttonPressActionToString(const NukiOpener::ButtonPressAction btnPressAction, char* str)
{
switch (btnPressAction)
diff --git a/src/NukiNetworkOpener.h b/src/NukiNetworkOpener.h
index 3facab4..9ccc180 100644
--- a/src/NukiNetworkOpener.h
+++ b/src/NukiNetworkOpener.h
@@ -30,8 +30,6 @@ public:
void publishRssi(const int& rssi);
void publishRetry(const std::string& message);
void publishBleAddress(const std::string& address);
- void publishHASSConfig(char* deviceType, const char* baseTopic, char* name, char* uidString, const char *softwareVersion, const char *hardwareVersion, const bool& publishAuthData, const bool& hasKeypad, char* lockAction, char* unlockAction, char* openAction);
- void removeHASSConfig(char* uidString);
void publishKeypad(const std::list& entries, uint maxKeypadCodeCount);
void publishTimeControl(const std::list& timeControlEntries, uint maxTimeControlEntryCount);
void publishAuth(const std::list& authEntries, uint maxAuthEntryCount);
@@ -49,6 +47,7 @@ public:
void setTimeControlCommandReceivedCallback(void (*timeControlCommandReceivedReceivedCallback)(const char* value));
void setAuthCommandReceivedCallback(void (*authCommandReceivedReceivedCallback)(const char* value));
void onMqttDataReceived(const char* topic, byte* payload, const unsigned int length) override;
+ void setupHASS(int type, uint32_t nukiId, char* nukiName, const char* firmwareVersion, const char* hardwareVersion, bool hasDoorSensor, bool hasKeypad);
int mqttConnectionState();
bool reconnected(); //SETBACK
diff --git a/src/NukiOfficial.cpp b/src/NukiOfficial.cpp
index af10b63..d1bd966 100644
--- a/src/NukiOfficial.cpp
+++ b/src/NukiOfficial.cpp
@@ -13,7 +13,6 @@ NukiOfficial::NukiOfficial(Preferences *preferences)
_disableNonJSON = preferences->getBool(preference_disable_non_json, false);
}
-
void NukiOfficial::setUid(const uint32_t& uid)
{
char uidString[20];
@@ -43,7 +42,6 @@ void NukiOfficial::setPublisher(NukiPublisher *publisher)
_publisher = publisher;
}
-
const char *NukiOfficial::getMqttPath() const
{
return mqttPath;
@@ -88,7 +86,7 @@ void NukiOfficial::onOfficialUpdateReceived(const char *topic, const char *value
bool publishBatteryJson = false;
memset(&str, 0, sizeof(str));
- Log->println("Official Nuki change recieved");
+ Log->println("Official Nuki change received");
Log->print(F("Topic: "));
Log->println(topic);
Log->print(F("Value: "));
@@ -99,14 +97,14 @@ void NukiOfficial::onOfficialUpdateReceived(const char *topic, const char *value
Log->print(F("Connected: "));
Log->println((strcmp(value, "true") == 0 ? 1 : 0));
offConnected = (strcmp(value, "true") == 0 ? 1 : 0);
- _publisher->publishBool(mqtt_hybrid_state, offConnected, true);
+ _publisher->publishBool(mqtt_topic_hybrid_state, offConnected, true);
}
else if(strcmp(topic, mqtt_topic_official_state) == 0)
{
offState = atoi(value);
_statusUpdated = true;
Log->println(F("Lock: Updating status on Hybrid state change"));
- _publisher->publishBool(mqtt_hybrid_state, offConnected, true);
+ _publisher->publishBool(mqtt_topic_hybrid_state, offConnected, true);
NukiLock::lockstateToString((NukiLock::LockState)offState, str);
_publisher->publishString(mqtt_topic_lock_state, str, true);
diff --git a/src/NukiOpenerWrapper.cpp b/src/NukiOpenerWrapper.cpp
index b1b3980..2e70327 100644
--- a/src/NukiOpenerWrapper.cpp
+++ b/src/NukiOpenerWrapper.cpp
@@ -54,7 +54,7 @@ void NukiOpenerWrapper::initialize()
_nukiOpener.setConnectTimeout(3);
_nukiOpener.setDisconnectTimeout(5000);
- _hassEnabled = _preferences->getString(preference_mqtt_hass_discovery) != "";
+ _hassEnabled = _preferences->getBool(preference_mqtt_hass_enabled, false);
readSettings();
}
@@ -313,7 +313,8 @@ void NukiOpenerWrapper::update()
}
if(_hassEnabled && _nukiConfigValid && _nukiAdvancedConfigValid && !_hassSetupCompleted)
{
- setupHASS();
+ _network->setupHASS(2, _nukiConfig.nukiId, (char*)_nukiConfig.name, _firmwareVersion.c_str(), _hardwareVersion.c_str(), false, _hasKeypad);
+ _hassSetupCompleted = true;
}
if(_rssiPublishInterval > 0 && (_nextRssiTs == 0 || ts > _nextRssiTs))
{
@@ -610,13 +611,13 @@ void NukiOpenerWrapper::updateConfig()
}
else
{
- Log->println(F("Invalid/Unexpected opener config recieved, ID does not matched saved ID"));
+ Log->println(F("Invalid/Unexpected opener config received, ID does not matched saved ID"));
expectedConfig = false;
}
}
else
{
- Log->println(F("Invalid/Unexpected opener config recieved, Config is not valid"));
+ Log->println(F("Invalid/Unexpected opener config received, Config is not valid"));
expectedConfig = false;
}
@@ -633,7 +634,7 @@ void NukiOpenerWrapper::updateConfig()
}
else
{
- Log->println(F("Invalid/Unexpected opener advanced config recieved, Advanced config is not valid"));
+ Log->println(F("Invalid/Unexpected opener advanced config received, Advanced config is not valid"));
expectedConfig = false;
}
}
@@ -646,7 +647,7 @@ void NukiOpenerWrapper::updateConfig()
else
{
++_retryConfigCount;
- Log->println(F("Invalid/Unexpected opener config and/or advanced config recieved, retrying in 10 seconds"));
+ Log->println(F("Invalid/Unexpected opener config and/or advanced config received, retrying in 10 seconds"));
int64_t ts = espMillis();
_nextConfigUpdateTs = ts + 10000;
}
@@ -3957,43 +3958,6 @@ void NukiOpenerWrapper::readAdvancedConfig()
postponeBleWatchdog();
}
-void NukiOpenerWrapper::setupHASS()
-{
- if(!_nukiConfigValid)
- {
- return;
- }
- if(_preferences->getUInt(preference_nuki_id_opener, 0) != _nukiConfig.nukiId)
- {
- return;
- }
-
- String baseTopic = _preferences->getString(preference_mqtt_lock_path);
- baseTopic.concat("/opener");
- char uidString[20];
- itoa(_nukiConfig.nukiId, uidString, 16);
-
- if(_preferences->getBool(preference_opener_continuous_mode, false))
- {
- _network->publishHASSConfig((char*)"Opener", baseTopic.c_str(), (char*)_nukiConfig.name, uidString, _firmwareVersion.c_str(), _hardwareVersion.c_str(), _publishAuthData, _hasKeypad, (char*)"deactivateCM", (char*)"activateCM", (char*)"electricStrikeActuation");
- }
- else
- {
- _network->publishHASSConfig((char*)"Opener", baseTopic.c_str(), (char*)_nukiConfig.name, uidString, _firmwareVersion.c_str(), _hardwareVersion.c_str(), _publishAuthData, _hasKeypad, (char*)"deactivateRTO", (char*)"activateRTO", (char*)"electricStrikeActuation");
- }
-
- _hassSetupCompleted = true;
-
- Log->println("HASS setup for opener completed.");
-}
-
-void NukiOpenerWrapper::disableHASS()
-{
- char uidString[20];
- itoa(_preferences->getUInt(preference_nuki_id_opener, 0), uidString, 16);
- _network->removeHASSConfig(uidString);
-}
-
void NukiOpenerWrapper::printCommandResult(Nuki::CmdResult result)
{
char resultStr[15];
diff --git a/src/NukiOpenerWrapper.h b/src/NukiOpenerWrapper.h
index f0c892f..aea104d 100644
--- a/src/NukiOpenerWrapper.h
+++ b/src/NukiOpenerWrapper.h
@@ -31,9 +31,6 @@ public:
uint16_t getPin();
void unpair();
-
- void disableHASS();
-
void disableWatchdog();
const NukiOpener::OpenerState& keyTurnerState();
@@ -77,8 +74,6 @@ private:
void readConfig();
void readAdvancedConfig();
- void setupHASS();
-
void printCommandResult(Nuki::CmdResult result);
NukiOpener::LockAction lockActionToEnum(const char* str); // char array at least 14 characters
diff --git a/src/NukiWrapper.cpp b/src/NukiWrapper.cpp
index 49aba9a..c680edd 100644
--- a/src/NukiWrapper.cpp
+++ b/src/NukiWrapper.cpp
@@ -1,6 +1,3 @@
-#ifndef CONFIG_IDF_TARGET_ESP32H2
-#include "esp_wifi.h"
-#endif
#include "NukiWrapper.h"
#include "PreferencesKeys.h"
#include "MqttTopics.h"
@@ -50,7 +47,7 @@ NukiWrapper::~NukiWrapper()
}
-void NukiWrapper::initialize(const bool& firstStart)
+void NukiWrapper::initialize()
{
_nukiLock.initialize();
_nukiLock.registerBleScanner(_bleScanner);
@@ -58,75 +55,7 @@ void NukiWrapper::initialize(const bool& firstStart)
_nukiLock.setConnectTimeout(3);
_nukiLock.setDisconnectTimeout(5000);
- if(firstStart)
- {
- Log->println("First start, setting preference defaults");
-
-#ifndef CONFIG_IDF_TARGET_ESP32H2
- wifi_config_t wifi_cfg;
- if(esp_wifi_get_config(WIFI_IF_STA, &wifi_cfg) != ESP_OK)
- {
- Log->println("Failed to get Wi-Fi configuration in RAM");
- }
-
- if (esp_wifi_set_storage(WIFI_STORAGE_FLASH) != ESP_OK)
- {
- Log->println("Failed to set storage Wi-Fi");
- }
-
- memset(wifi_cfg.sta.ssid, 0, sizeof(wifi_cfg.sta.ssid));
- memset(wifi_cfg.sta.password, 0, sizeof(wifi_cfg.sta.password));
-
- if (esp_wifi_set_config(WIFI_IF_STA, &wifi_cfg) != ESP_OK)
- {
- Log->println("Failed to clear NVS Wi-Fi configuration");
- }
-#endif
- _preferences->putString(preference_mqtt_lock_path, "nukihub");
-
- _preferences->putBool(preference_check_updates, true);
- _preferences->putBool(preference_opener_continuous_mode, false);
- _preferences->putBool(preference_official_hybrid_enabled, false);
- _preferences->putBool(preference_official_hybrid_actions, false);
- _preferences->putBool(preference_official_hybrid_retry, false);
- _preferences->putBool(preference_disable_non_json, false);
- _preferences->putBool(preference_update_from_mqtt, false);
- _preferences->putBool(preference_ip_dhcp_enabled, true);
- _preferences->putBool(preference_enable_bootloop_reset, false);
- _preferences->putBool(preference_show_secrets, false);
-
- _preferences->putBool(preference_conf_info_enabled, true);
- _preferences->putBool(preference_keypad_info_enabled, false);
- _preferences->putBool(preference_keypad_topic_per_entry, false);
- _preferences->putBool(preference_keypad_publish_code, false);
- _preferences->putBool(preference_keypad_control_enabled, false);
- _preferences->putBool(preference_timecontrol_info_enabled, false);
- _preferences->putBool(preference_timecontrol_topic_per_entry, false);
- _preferences->putBool(preference_timecontrol_control_enabled, false);
- _preferences->putBool(preference_publish_authdata, false);
- _preferences->putBool(preference_register_as_app, false);
- _preferences->putBool(preference_register_opener_as_app, false);
-
- _preferences->putInt(preference_mqtt_broker_port, 1883);
- _preferences->putInt(preference_buffer_size, CHAR_BUFFER_SIZE);
- _preferences->putInt(preference_task_size_network, NETWORK_TASK_SIZE);
- _preferences->putInt(preference_task_size_nuki, NUKI_TASK_SIZE);
- _preferences->putInt(preference_authlog_max_entries, MAX_AUTHLOG);
- _preferences->putInt(preference_keypad_max_entries, MAX_KEYPAD);
- _preferences->putInt(preference_timecontrol_max_entries, MAX_TIMECONTROL);
- _preferences->putInt(preference_query_interval_hybrid_lockstate, 600);
- _preferences->putInt(preference_rssi_publish_interval, 60);
- _preferences->putInt(preference_network_timeout, 60);
- _preferences->putInt(preference_command_nr_of_retries, 3);
- _preferences->putInt(preference_command_retry_delay, 100);
- _preferences->putInt(preference_restart_ble_beacon_lost, 60);
- _preferences->putInt(preference_query_interval_lockstate, 1800);
- _preferences->putInt(preference_query_interval_configuration, 3600);
- _preferences->putInt(preference_query_interval_battery, 1800);
- _preferences->putInt(preference_query_interval_keypad, 1800);
- }
-
- _hassEnabled = _preferences->getString(preference_mqtt_hass_discovery) != "";
+ _hassEnabled = _preferences->getBool(preference_mqtt_hass_enabled, false);
readSettings();
}
@@ -405,7 +334,8 @@ void NukiWrapper::update()
}
if(_hassEnabled && _nukiConfigValid && _nukiAdvancedConfigValid && !_hassSetupCompleted)
{
- setupHASS();
+ _network->setupHASS(1, _nukiConfig.nukiId, (char*)_nukiConfig.name, _firmwareVersion.c_str(), _hardwareVersion.c_str(), hasDoorSensor(), _hasKeypad);
+ _hassSetupCompleted = true;
}
if(_rssiPublishInterval > 0 && (_nextRssiTs == 0 || ts > _nextRssiTs))
{
@@ -693,13 +623,13 @@ void NukiWrapper::updateConfig()
}
else
{
- Log->println(F("Invalid/Unexpected lock config recieved, ID does not matched saved ID"));
+ Log->println(F("Invalid/Unexpected lock config received, ID does not matched saved ID"));
expectedConfig = false;
}
}
else
{
- Log->println(F("Invalid/Unexpected lock config recieved, Config is not valid"));
+ Log->println(F("Invalid/Unexpected lock config received, Config is not valid"));
expectedConfig = false;
}
@@ -716,7 +646,7 @@ void NukiWrapper::updateConfig()
}
else
{
- Log->println(F("Invalid/Unexpected lock advanced config recieved, Advanced config is not valid"));
+ Log->println(F("Invalid/Unexpected lock advanced config received, Advanced config is not valid"));
expectedConfig = false;
}
}
@@ -729,7 +659,7 @@ void NukiWrapper::updateConfig()
else
{
++_retryConfigCount;
- Log->println(F("Invalid/Unexpected lock config and/or advanced config recieved, retrying in 10 seconds"));
+ Log->println(F("Invalid/Unexpected lock config and/or advanced config received, retrying in 10 seconds"));
int64_t ts = espMillis();
_nextConfigUpdateTs = ts + 10000;
}
@@ -4074,28 +4004,6 @@ void NukiWrapper::readAdvancedConfig()
}
}
-void NukiWrapper::setupHASS()
-{
- if(!_nukiConfigValid)
- {
- return;
- }
- if(_preferences->getUInt(preference_nuki_id_lock, 0) != _nukiConfig.nukiId)
- {
- return;
- }
-
- String baseTopic = _preferences->getString(preference_mqtt_lock_path);
- baseTopic.concat("/lock");
- char uidString[20];
- itoa(_nukiConfig.nukiId, uidString, 16);
-
- _network->publishHASSConfig((char*)"SmartLock", baseTopic.c_str(),(char*)_nukiConfig.name, uidString, _firmwareVersion.c_str(), _hardwareVersion.c_str(), hasDoorSensor(), _hasKeypad, _publishAuthData, (char*)"lock", (char*)"unlock", (char*)"unlatch");
- _hassSetupCompleted = true;
-
- Log->println("HASS setup for lock completed.");
-}
-
bool NukiWrapper::hasDoorSensor() const
{
return _keyTurnerState.doorSensorState == Nuki::DoorSensorState::DoorClosed ||
@@ -4103,13 +4011,6 @@ bool NukiWrapper::hasDoorSensor() const
_keyTurnerState.doorSensorState == Nuki::DoorSensorState::Calibrating;
}
-void NukiWrapper::disableHASS()
-{
- char uidString[20];
- itoa(_preferences->getUInt(preference_nuki_id_lock, 0), uidString, 16);
- _network->removeHASSConfig(uidString);
-}
-
const BLEAddress NukiWrapper::getBleAddress() const
{
return _nukiLock.getBleAddress();
diff --git a/src/NukiWrapper.h b/src/NukiWrapper.h
index 2358e02..82484d5 100644
--- a/src/NukiWrapper.h
+++ b/src/NukiWrapper.h
@@ -17,7 +17,7 @@ public:
NukiWrapper(const std::string& deviceName, NukiDeviceId* deviceId, BleScanner::Scanner* scanner, NukiNetworkLock* network, NukiOfficial* nukiOfficial, Gpio* gpio, Preferences* preferences);
virtual ~NukiWrapper();
- void initialize(const bool& firstStart);
+ void initialize();
void readSettings();
void update();
@@ -33,8 +33,6 @@ public:
uint16_t getPin();
void unpair();
- void disableHASS();
-
void disableWatchdog();
const NukiLock::KeyTurnerState& keyTurnerState();
@@ -81,8 +79,6 @@ private:
void readConfig();
void readAdvancedConfig();
- void setupHASS();
-
void printCommandResult(Nuki::CmdResult result);
NukiLock::LockAction lockActionToEnum(const char* str); // char array at least 14 characters
diff --git a/src/PreferencesKeys.h b/src/PreferencesKeys.h
index 8390e0f..7272158 100644
--- a/src/PreferencesKeys.h
+++ b/src/PreferencesKeys.h
@@ -2,6 +2,9 @@
#include
#include "Config.h"
+#ifndef CONFIG_IDF_TARGET_ESP32H2
+#include "esp_wifi.h"
+#endif
//CHANGE REQUIRES REBOOT TO TAKE EFFECT
#define preference_ip_dhcp_enabled (char*)"dhcpena"
@@ -48,6 +51,7 @@
#define preference_gpio_configuration (char*)"gpiocfg"
#define preference_mqtt_hass_enabled (char*)"hassena"
#define preference_mqtt_hass_discovery (char*)"hassdiscovery"
+#define preference_hass_device_discovery (char*)"hassdevdisc"
#define preference_webserver_enabled (char*)"websrvena"
#define preference_update_from_mqtt (char*)"updMqtt"
#define preference_disable_non_json (char*)"disnonjson"
@@ -128,17 +132,17 @@
#define preference_presence_detection_timeout (char*)"prdtimeout"
#define preference_network_wifi_fallback_disabled (char*)"nwwififb"
-inline bool initPreferences(Preferences* preferences)
+inline void initPreferences(Preferences* preferences)
{
#ifdef NUKI_HUB_UPDATER
- bool firstStart = false;
- return firstStart;
+ return;
#else
bool firstStart = !preferences->getBool(preference_started_before);
- #endif
if(firstStart)
{
+ Serial.println("First start, setting preference defaults");
+
preferences->putBool(preference_started_before, true);
preferences->putBool(preference_lock_enabled, true);
uint32_t aclPrefs[17] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
@@ -151,6 +155,69 @@ inline bool initPreferences(Preferences* preferences)
preferences->putBytes(preference_conf_lock_advanced_acl, (byte*)(&advancedLockConfigAclPrefs), sizeof(advancedLockConfigAclPrefs));
uint32_t advancedOpenerConfigAclPrefs[20] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
preferences->putBytes(preference_conf_opener_advanced_acl, (byte*)(&advancedOpenerConfigAclPrefs), sizeof(advancedOpenerConfigAclPrefs));
+
+#ifndef CONFIG_IDF_TARGET_ESP32H2
+ wifi_config_t wifi_cfg;
+ if(esp_wifi_get_config(WIFI_IF_STA, &wifi_cfg) != ESP_OK)
+ {
+ Serial.println("Failed to get Wi-Fi configuration in RAM");
+ }
+
+ if (esp_wifi_set_storage(WIFI_STORAGE_FLASH) != ESP_OK)
+ {
+ Serial.println("Failed to set storage Wi-Fi");
+ }
+
+ memset(wifi_cfg.sta.ssid, 0, sizeof(wifi_cfg.sta.ssid));
+ memset(wifi_cfg.sta.password, 0, sizeof(wifi_cfg.sta.password));
+
+ if (esp_wifi_set_config(WIFI_IF_STA, &wifi_cfg) != ESP_OK)
+ {
+ Serial.println("Failed to clear NVS Wi-Fi configuration");
+ }
+#endif
+ preferences->putString(preference_mqtt_lock_path, "nukihub");
+
+ preferences->putBool(preference_check_updates, true);
+ preferences->putBool(preference_opener_continuous_mode, false);
+ preferences->putBool(preference_official_hybrid_enabled, false);
+ preferences->putBool(preference_official_hybrid_actions, false);
+ preferences->putBool(preference_official_hybrid_retry, false);
+ preferences->putBool(preference_disable_non_json, false);
+ preferences->putBool(preference_update_from_mqtt, false);
+ preferences->putBool(preference_ip_dhcp_enabled, true);
+ preferences->putBool(preference_enable_bootloop_reset, false);
+ preferences->putBool(preference_show_secrets, false);
+
+ preferences->putBool(preference_conf_info_enabled, true);
+ preferences->putBool(preference_keypad_info_enabled, false);
+ preferences->putBool(preference_keypad_topic_per_entry, false);
+ preferences->putBool(preference_keypad_publish_code, false);
+ preferences->putBool(preference_keypad_control_enabled, false);
+ preferences->putBool(preference_timecontrol_info_enabled, false);
+ preferences->putBool(preference_timecontrol_topic_per_entry, false);
+ preferences->putBool(preference_timecontrol_control_enabled, false);
+ preferences->putBool(preference_publish_authdata, false);
+ preferences->putBool(preference_register_as_app, false);
+ preferences->putBool(preference_register_opener_as_app, false);
+
+ preferences->putInt(preference_mqtt_broker_port, 1883);
+ preferences->putInt(preference_buffer_size, CHAR_BUFFER_SIZE);
+ preferences->putInt(preference_task_size_network, NETWORK_TASK_SIZE);
+ preferences->putInt(preference_task_size_nuki, NUKI_TASK_SIZE);
+ preferences->putInt(preference_authlog_max_entries, MAX_AUTHLOG);
+ preferences->putInt(preference_keypad_max_entries, MAX_KEYPAD);
+ preferences->putInt(preference_timecontrol_max_entries, MAX_TIMECONTROL);
+ preferences->putInt(preference_query_interval_hybrid_lockstate, 600);
+ preferences->putInt(preference_rssi_publish_interval, 60);
+ preferences->putInt(preference_network_timeout, 60);
+ preferences->putInt(preference_command_nr_of_retries, 3);
+ preferences->putInt(preference_command_retry_delay, 100);
+ preferences->putInt(preference_restart_ble_beacon_lost, 60);
+ preferences->putInt(preference_query_interval_lockstate, 1800);
+ preferences->putInt(preference_query_interval_configuration, 3600);
+ preferences->putInt(preference_query_interval_battery, 1800);
+ preferences->putInt(preference_query_interval_keypad, 1800);
}
else
{
@@ -265,8 +332,7 @@ inline bool initPreferences(Preferences* preferences)
preferences->putInt(preference_config_version, atof(NUKI_HUB_VERSION) * 100);
}
}
-
- return firstStart;
+ #endif
}
class DebugPreferences
@@ -294,7 +360,7 @@ private:
preference_network_custom_rst, preference_network_custom_cs, preference_network_custom_sck, preference_network_custom_miso, preference_network_custom_mosi,
preference_network_custom_pwr, preference_network_custom_mdio, preference_ntw_reconfigure, preference_lock_max_auth_entry_count, preference_opener_max_auth_entry_count,
preference_auth_control_enabled, preference_auth_topic_per_entry, preference_auth_info_enabled, preference_auth_max_entries, preference_wifi_ssid, preference_wifi_pass,
- preference_keypad_check_code_enabled, preference_disable_network_not_connected, preference_mqtt_hass_enabled
+ preference_keypad_check_code_enabled, preference_disable_network_not_connected, preference_mqtt_hass_enabled, preference_hass_device_discovery
};
std::vector _redact =
{
@@ -309,7 +375,7 @@ private:
preference_timecontrol_control_enabled, preference_timecontrol_info_enabled, preference_register_as_app, preference_register_opener_as_app, preference_ip_dhcp_enabled,
preference_publish_authdata, preference_publish_debug_info, preference_official_hybrid_enabled, preference_mqtt_hass_enabled,
preference_official_hybrid_actions, preference_official_hybrid_retry, preference_conf_info_enabled, preference_disable_non_json, preference_update_from_mqtt,
- preference_auth_control_enabled, preference_auth_topic_per_entry, preference_auth_info_enabled, preference_webserial_enabled,
+ preference_auth_control_enabled, preference_auth_topic_per_entry, preference_auth_info_enabled, preference_webserial_enabled, preference_hass_device_discovery,
preference_ntw_reconfigure, preference_keypad_check_code_enabled, preference_disable_network_not_connected
};
std::vector _bytePrefs =
diff --git a/src/WebCfgServer.cpp b/src/WebCfgServer.cpp
index 61255a7..051a1cc 100644
--- a/src/WebCfgServer.cpp
+++ b/src/WebCfgServer.cpp
@@ -1740,21 +1740,22 @@ bool WebCfgServer::processArgs(PsychicRequest *request, String& message)
//configChanged = true;
}
}
+ else if(key == "HADEVDISC")
+ {
+ if(_preferences->getBool(preference_hass_device_discovery, false) != (value == "1"))
+ {
+ _network->disableHASS();
+ _preferences->putBool(preference_hass_device_discovery, (value == "1"));
+ Log->print(F("Setting changed: "));
+ Log->println(key);
+ configChanged = true;
+ }
+ }
else if(key == "ENHADISC")
{
if(_preferences->getBool(preference_mqtt_hass_enabled, false) != (value == "1"))
{
- if(!_preferences->getBool(preference_mqtt_hass_enabled, false))
- {
- if (_nuki != nullptr)
- {
- _nuki->disableHASS();
- }
- if (_nukiOpener != nullptr)
- {
- _nukiOpener->disableHASS();
- }
- }
+ _network->disableHASS();
_preferences->putBool(preference_mqtt_hass_enabled, (value == "1"));
Log->print(F("Setting changed: "));
Log->println(key);
@@ -1765,14 +1766,7 @@ bool WebCfgServer::processArgs(PsychicRequest *request, String& message)
{
if(_preferences->getString(preference_mqtt_hass_discovery, "") != value)
{
- if (_nuki != nullptr)
- {
- _nuki->disableHASS();
- }
- if (_nukiOpener != nullptr)
- {
- _nukiOpener->disableHASS();
- }
+ _network->disableHASS();
_preferences->putString(preference_mqtt_hass_discovery, value);
Log->print(F("Setting changed: "));
Log->println(key);
@@ -3548,6 +3542,7 @@ esp_err_t WebCfgServer::buildMqttConfigHtml(PsychicRequest *request)
response.print("Advanced MQTT Configuration
");
response.print("");
printInputField(&response, "HASSDISCOVERY", "Home Assistant discovery topic (usually \"homeassistant\")", _preferences->getString(preference_mqtt_hass_discovery).c_str(), 30, "class=\"chkHass\"");
+ //printCheckBox(&response, "HADEVDISC", "Use Home Assistant device based discovery (2024.11+)", _preferences->getBool(preference_hass_device_discovery), "");
if(_preferences->getBool(preference_opener_enabled, false))
{
printCheckBox(&response, "OPENERCONT", "Set Nuki Opener Lock/Unlock action in Home Assistant to Continuous mode", _preferences->getBool(preference_opener_continuous_mode), "");
@@ -4209,7 +4204,7 @@ esp_err_t WebCfgServer::buildInfoHtml(PsychicRequest *request)
response.print(_preferences->getInt(preference_command_nr_of_retries, 3));
response.print("\nBluetooth command retry delay (ms): ");
response.print(_preferences->getInt(preference_command_retry_delay, 100));
- response.print("\nSeconds until reboot when no BLE beacons recieved: ");
+ response.print("\nSeconds until reboot when no BLE beacons received: ");
response.print(_preferences->getInt(preference_restart_ble_beacon_lost, 60));
response.print("\n\n------------ QUERY / PUBLISH SETTINGS ------------");
response.print("\nLock/Opener state query interval (s): ");
@@ -4643,14 +4638,14 @@ esp_err_t WebCfgServer::processUnpair(PsychicRequest *request, bool opener)
if(!opener && _nuki != nullptr)
{
- _nuki->disableHASS();
_nuki->unpair();
}
if(opener && _nukiOpener != nullptr)
{
- _nukiOpener->disableHASS();
_nukiOpener->unpair();
}
+
+ _network->disableHASS();
waitAndProcess(false, 1000);
restartEsp(RestartReason::DeviceUnpaired);
return res;
@@ -4769,15 +4764,14 @@ esp_err_t WebCfgServer::processFactoryReset(PsychicRequest *request)
if(_nuki != nullptr)
{
- _nuki->disableHASS();
_nuki->unpair();
}
if(_nukiOpener != nullptr)
{
- _nukiOpener->disableHASS();
_nukiOpener->unpair();
}
+ _network->disableHASS();
_preferences->clear();
#ifndef CONFIG_IDF_TARGET_ESP32H2
diff --git a/src/WebCfgServer.h b/src/WebCfgServer.h
index 31e7ab7..db6dab0 100644
--- a/src/WebCfgServer.h
+++ b/src/WebCfgServer.h
@@ -2,7 +2,9 @@
#include
#include
+#ifdef CONFIG_ESP_HTTPS_SERVER_ENABLE
#include
+#endif
#include "esp_ota_ops.h"
#include "Config.h"
diff --git a/src/main.cpp b/src/main.cpp
index 013d3a1..0a86511 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -446,7 +446,7 @@ void setup()
preferences = new Preferences();
preferences->begin("nukihub", false);
- bool firstStart = initPreferences(preferences);
+ initPreferences(preferences);
bool doOta = false;
uint8_t partitionType = checkPartition();
@@ -468,13 +468,6 @@ void setup()
doOta = true;
}
-#ifndef NUKI_HUB_UPDATER
- if(preferences->getBool(preference_enable_bootloop_reset, false))
- {
- bootloopDetection();
- }
-#endif
-
#ifdef NUKI_HUB_UPDATER
Log->print(F("Nuki Hub OTA version "));
Log->println(NUKI_HUB_VERSION);
@@ -511,6 +504,11 @@ void setup()
});
}
#else
+ if(preferences->getBool(preference_enable_bootloop_reset, false))
+ {
+ bootloopDetection();
+ }
+
Log->print(F("Nuki Hub version "));
Log->println(NUKI_HUB_VERSION);
Log->print(F("Nuki Hub build "));
@@ -571,7 +569,7 @@ void setup()
}
nuki = new NukiWrapper("NukiHub", deviceIdLock, bleScanner, networkLock, nukiOfficial, gpio, preferences);
- nuki->initialize(firstStart);
+ nuki->initialize();
}
Log->println(openerEnabled ? F("Nuki Opener enabled") : F("Nuki Opener disabled"));
diff --git a/src/networkDevices/EthernetDevice.cpp b/src/networkDevices/EthernetDevice.cpp
index f75277c..f4c5f93 100644
--- a/src/networkDevices/EthernetDevice.cpp
+++ b/src/networkDevices/EthernetDevice.cpp
@@ -1,17 +1,14 @@
#include "EthernetDevice.h"
#include "../PreferencesKeys.h"
#include "../Logger.h"
-#ifndef NUKI_HUB_UPDATER
-#include "../MqttTopics.h"
-#include "espMqttClient.h"
-#endif
#include "../RestartReason.h"
+#include "../EspMillis.h"
extern bool ethCriticalFailure;
extern bool wifiFallback;
EthernetDevice::EthernetDevice(const String& hostname, Preferences* preferences, const IPConfiguration* ipConfiguration, const std::string& deviceName, uint8_t phy_addr, int power, int mdc, int mdio, eth_phy_type_t ethtype, eth_clock_mode_t clock_mode)
- : NetworkDevice(hostname, ipConfiguration),
+ : NetworkDevice(hostname, preferences, ipConfiguration),
_deviceName(deviceName),
_phy_addr(phy_addr),
_power(power),
@@ -22,7 +19,9 @@ EthernetDevice::EthernetDevice(const String& hostname, Preferences* preferences,
_useSpi(false),
_preferences(preferences)
{
- init();
+#ifndef NUKI_HUB_UPDATER
+ NetworkDevice::init();
+#endif
}
EthernetDevice::EthernetDevice(const String &hostname,
@@ -37,7 +36,7 @@ EthernetDevice::EthernetDevice(const String &hostname,
int spi_miso,
int spi_mosi,
eth_phy_type_t ethtype)
- : NetworkDevice(hostname, ipConfiguration),
+ : NetworkDevice(hostname, preferences, ipConfiguration),
_deviceName(deviceName),
_phy_addr(phy_addr),
_cs(cs),
@@ -49,52 +48,9 @@ EthernetDevice::EthernetDevice(const String &hostname,
_type(ethtype),
_useSpi(true),
_preferences(preferences)
-{
- init();
-}
-
-void EthernetDevice::init()
{
#ifndef NUKI_HUB_UPDATER
- size_t caLength = _preferences->getString(preference_mqtt_ca, _ca, TLS_CA_MAX_SIZE);
- size_t crtLength = _preferences->getString(preference_mqtt_crt, _cert, TLS_CERT_MAX_SIZE);
- size_t keyLength = _preferences->getString(preference_mqtt_key, _key, TLS_KEY_MAX_SIZE);
-
- _useEncryption = caLength > 1; // length is 1 when empty
-
- if(_useEncryption)
- {
- Log->println(F("MQTT over TLS."));
- _mqttClientSecure = new espMqttClientSecure(espMqttClientTypes::UseInternalTask::NO);
- _mqttClientSecure->setCACert(_ca);
- if(crtLength > 1 && keyLength > 1) // length is 1 when empty
- {
- Log->println(F("MQTT with client certificate."));
- _mqttClientSecure->setCertificate(_cert);
- _mqttClientSecure->setPrivateKey(_key);
- }
- } else
- {
- Log->println(F("MQTT without TLS."));
- _mqttClient = new espMqttClient(espMqttClientTypes::UseInternalTask::NO);
- }
-
- if(_preferences->getBool(preference_mqtt_log_enabled, false) || _preferences->getBool(preference_webserial_enabled, false))
- {
- MqttLoggerMode mode;
-
- if(_preferences->getBool(preference_mqtt_log_enabled, false) && _preferences->getBool(preference_webserial_enabled, false)) mode = MqttLoggerMode::MqttAndSerialAndWeb;
- else if (_preferences->getBool(preference_webserial_enabled, false)) mode = MqttLoggerMode::SerialAndWeb;
- else mode = MqttLoggerMode::MqttAndSerial;
-
- _path = new char[200];
- memset(_path, 0, sizeof(_path));
-
- String pathStr = _preferences->getString(preference_mqtt_lock_path);
- pathStr.concat(mqtt_topic_log);
- strcpy(_path, pathStr.c_str());
- Log = new MqttLogger(*getMqttClient(), _path, mode);
- }
+ NetworkDevice::init();
#endif
}
diff --git a/src/networkDevices/EthernetDevice.h b/src/networkDevices/EthernetDevice.h
index d5503c8..fb0a737 100644
--- a/src/networkDevices/EthernetDevice.h
+++ b/src/networkDevices/EthernetDevice.h
@@ -11,9 +11,6 @@
#include
#include
#include "NetworkDevice.h"
-#ifndef NUKI_HUB_UPDATER
-#include "espMqttClient.h"
-#endif
class EthernetDevice : public NetworkDevice
{
@@ -61,21 +58,24 @@ public:
private:
Preferences* _preferences;
- void init();
void onDisconnected();
void onNetworkEvent(arduino_event_id_t event, arduino_event_info_t info);
bool _connected = false;
- char* _path;
bool _hardwareInitialized = false;
+ bool _useSpi = false;
+
+ int64_t _checkIpTs = -1;
const std::string _deviceName;
uint8_t _phy_addr;
+ eth_phy_type_t _type;
// LAN8720
int _power;
int _mdc;
int _mdio;
+ eth_clock_mode_t _clock_mode;
// W55000 and DM9051
int _cs;
@@ -84,16 +84,4 @@ private:
int _spi_sck;
int _spi_miso;
int _spi_mosi;
-
- int64_t _checkIpTs = -1;
-
- eth_phy_type_t _type;
- eth_clock_mode_t _clock_mode;
- bool _useSpi = false;
-
- #ifndef NUKI_HUB_UPDATER
- char _ca[TLS_CA_MAX_SIZE] = {0};
- char _cert[TLS_CERT_MAX_SIZE] = {0};
- char _key[TLS_KEY_MAX_SIZE] = {0};
- #endif
};
\ No newline at end of file
diff --git a/src/networkDevices/LAN8720Definitions.h b/src/networkDevices/LAN8720Definitions.h
index f45f5fc..6de25b1 100644
--- a/src/networkDevices/LAN8720Definitions.h
+++ b/src/networkDevices/LAN8720Definitions.h
@@ -2,19 +2,19 @@
#ifndef CONFIG_IDF_TARGET_ESP32
typedef enum {
- ETH_CLOCK_GPIO0_IN = 0,
- ETH_CLOCK_GPIO16_OUT = 2,
- ETH_CLOCK_GPIO17_OUT = 3
- } eth_clock_mode_t;
+ ETH_CLOCK_GPIO0_IN = 0,
+ ETH_CLOCK_GPIO16_OUT = 2,
+ ETH_CLOCK_GPIO17_OUT = 3
+} eth_clock_mode_t;
- #define ETH_PHY_TYPE_LAN8720 ETH_PHY_MAX
+#define ETH_PHY_TYPE_LAN8720 ETH_PHY_MAX
#else
#define ETH_PHY_TYPE_LAN8720 ETH_PHY_LAN8720
#endif
-#define ETH_CLK_MODE_LAN8720 ETH_CLOCK_GPIO0_IN
-#define ETH_PHY_ADDR_LAN8720 0
-#define ETH_PHY_MDC_LAN8720 23
-#define ETH_PHY_MDIO_LAN8720 18
-#define ETH_PHY_POWER_LAN8720 -1
-#define ETH_RESET_PIN_LAN8720 1
\ No newline at end of file
+#define ETH_CLK_MODE_LAN8720 ETH_CLOCK_GPIO0_IN
+#define ETH_PHY_ADDR_LAN8720 0
+#define ETH_PHY_MDC_LAN8720 23
+#define ETH_PHY_MDIO_LAN8720 18
+#define ETH_PHY_POWER_LAN8720 -1
+#define ETH_RESET_PIN_LAN8720 1
\ No newline at end of file
diff --git a/src/networkDevices/NetworkDevice.cpp b/src/networkDevices/NetworkDevice.cpp
index 9e65acd..091a12b 100644
--- a/src/networkDevices/NetworkDevice.cpp
+++ b/src/networkDevices/NetworkDevice.cpp
@@ -2,13 +2,52 @@
#include "NetworkDevice.h"
#include "../Logger.h"
-void NetworkDevice::printError()
-{
- Log->print(F("Free Heap: "));
- Log->println(ESP.getFreeHeap());
-}
-
#ifndef NUKI_HUB_UPDATER
+#include "../MqttTopics.h"
+#include "PreferencesKeys.h"
+
+void NetworkDevice::init()
+{
+ size_t caLength = _preferences->getString(preference_mqtt_ca, _ca, TLS_CA_MAX_SIZE);
+ size_t crtLength = _preferences->getString(preference_mqtt_crt, _cert, TLS_CERT_MAX_SIZE);
+ size_t keyLength = _preferences->getString(preference_mqtt_key, _key, TLS_KEY_MAX_SIZE);
+
+ _useEncryption = caLength > 1; // length is 1 when empty
+
+ if(_useEncryption)
+ {
+ Log->println(F("MQTT over TLS."));
+ _mqttClientSecure = new espMqttClientSecure(espMqttClientTypes::UseInternalTask::NO);
+ _mqttClientSecure->setCACert(_ca);
+ if(crtLength > 1 && keyLength > 1) // length is 1 when empty
+ {
+ Log->println(F("MQTT with client certificate."));
+ _mqttClientSecure->setCertificate(_cert);
+ _mqttClientSecure->setPrivateKey(_key);
+ }
+ } else
+ {
+ Log->println(F("MQTT without TLS."));
+ _mqttClient = new espMqttClient(espMqttClientTypes::UseInternalTask::NO);
+ }
+
+ if(_preferences->getBool(preference_mqtt_log_enabled, false) || _preferences->getBool(preference_webserial_enabled, false))
+ {
+ MqttLoggerMode mode;
+
+ if(_preferences->getBool(preference_mqtt_log_enabled, false) && _preferences->getBool(preference_webserial_enabled, false)) mode = MqttLoggerMode::MqttAndSerialAndWeb;
+ else if (_preferences->getBool(preference_webserial_enabled, false)) mode = MqttLoggerMode::SerialAndWeb;
+ else mode = MqttLoggerMode::MqttAndSerial;
+
+ _path = new char[200];
+ memset(_path, 0, sizeof(_path));
+
+ String pathStr = _preferences->getString(preference_mqtt_lock_path);
+ pathStr.concat(mqtt_topic_log);
+ strcpy(_path, pathStr.c_str());
+ Log = new MqttLogger(*getMqttClient(), _path, mode);
+ }
+}
void NetworkDevice::update()
{
if (_mqttEnabled)
@@ -90,7 +129,7 @@ bool NetworkDevice::mqttDisconnect(bool force)
return getMqttClient()->disconnect(force);
}
-void NetworkDevice::setWill(const char *topic, uint8_t qos, bool retain, const char *payload)
+void NetworkDevice::mqttSetWill(const char *topic, uint8_t qos, bool retain, const char *payload)
{
if (_useEncryption)
{
@@ -155,7 +194,7 @@ uint16_t NetworkDevice::mqttSubscribe(const char *topic, uint8_t qos)
return getMqttClient()->subscribe(topic, qos);
}
-void NetworkDevice::disableMqtt()
+void NetworkDevice::mqttDisable()
{
getMqttClient()->disconnect();
_mqttEnabled = false;
diff --git a/src/networkDevices/NetworkDevice.h b/src/networkDevices/NetworkDevice.h
index f5b2b11..7e99eef 100644
--- a/src/networkDevices/NetworkDevice.h
+++ b/src/networkDevices/NetworkDevice.h
@@ -2,16 +2,15 @@
#ifndef NUKI_HUB_UPDATER
#include "espMqttClient.h"
-#include "MqttClientSetup.h"
#endif
#include "IPConfiguration.h"
-#include "../EspMillis.h"
class NetworkDevice
{
public:
- explicit NetworkDevice(const String& hostname, const IPConfiguration* ipConfiguration)
+ explicit NetworkDevice(const String& hostname, Preferences* preferences, const IPConfiguration* ipConfiguration)
: _hostname(hostname),
+ _preferences(preferences),
_ipConfiguration(ipConfiguration)
{}
@@ -19,7 +18,6 @@ public:
virtual void initialize() = 0;
virtual void reconfigure() = 0;
- virtual void printError();
virtual void update();
virtual void scan(bool passive = false, bool async = true) = 0;
@@ -31,36 +29,45 @@ public:
virtual String BSSIDstr() = 0;
#ifndef NUKI_HUB_UPDATER
+ virtual bool mqttConnect();
+ virtual bool mqttDisconnect(bool force);
+ virtual void mqttDisable();
+ virtual bool mqttConnected() const;
+
+ virtual uint16_t mqttPublish(const char* topic, uint8_t qos, bool retain, const char* payload);
+ virtual uint16_t mqttPublish(const char* topic, uint8_t qos, bool retain, const uint8_t* payload, size_t length);
+ virtual uint16_t mqttSubscribe(const char* topic, uint8_t qos);
+
+ virtual void mqttSetServer(const char* host, uint16_t port);
virtual void mqttSetClientId(const char* clientId);
virtual void mqttSetCleanSession(bool cleanSession);
virtual void mqttSetKeepAlive(uint16_t keepAlive);
- virtual uint16_t mqttPublish(const char* topic, uint8_t qos, bool retain, const char* payload);
- virtual uint16_t mqttPublish(const char* topic, uint8_t qos, bool retain, const uint8_t* payload, size_t length);
- virtual bool mqttConnected() const;
- virtual void mqttSetServer(const char* host, uint16_t port);
- virtual bool mqttConnect();
- virtual bool mqttDisconnect(bool force);
- virtual void setWill(const char* topic, uint8_t qos, bool retain, const char* payload);
+ virtual void mqttSetWill(const char* topic, uint8_t qos, bool retain, const char* payload);
virtual void mqttSetCredentials(const char* username, const char* password);
+
virtual void mqttOnMessage(espMqttClientTypes::OnMessageCallback callback);
virtual void mqttOnConnect(espMqttClientTypes::OnConnectCallback callback);
virtual void mqttOnDisconnect(espMqttClientTypes::OnDisconnectCallback callback);
- virtual void disableMqtt();
-
- virtual uint16_t mqttSubscribe(const char* topic, uint8_t qos);
#endif
protected:
+ const IPConfiguration* _ipConfiguration = nullptr;
+ Preferences* _preferences = nullptr;
#ifndef NUKI_HUB_UPDATER
espMqttClient *_mqttClient = nullptr;
espMqttClientSecure *_mqttClientSecure = nullptr;
- bool _useEncryption = false;
- bool _mqttEnabled = true;
+ void init();
MqttClient *getMqttClient() const;
+
+ bool _useEncryption = false;
+ bool _mqttEnabled = true;
+ char* _path;
+ char _ca[TLS_CA_MAX_SIZE] = {0};
+ char _cert[TLS_CERT_MAX_SIZE] = {0};
+ char _key[TLS_KEY_MAX_SIZE] = {0};
#endif
const String _hostname;
- const IPConfiguration* _ipConfiguration = nullptr;
};
\ No newline at end of file
diff --git a/src/networkDevices/WifiDevice.cpp b/src/networkDevices/WifiDevice.cpp
index bbacc52..0109e7f 100644
--- a/src/networkDevices/WifiDevice.cpp
+++ b/src/networkDevices/WifiDevice.cpp
@@ -1,61 +1,20 @@
+#include "WifiDevice.h"
#include "esp_wifi.h"
#include
-#include "WifiDevice.h"
#include "../PreferencesKeys.h"
#include "../Logger.h"
-#ifndef NUKI_HUB_UPDATER
-#include "../MqttTopics.h"
-#include "espMqttClient.h"
-#endif
#include "../RestartReason.h"
+#include "../EspMillis.h"
WifiDevice::WifiDevice(const String& hostname, Preferences* preferences, const IPConfiguration* ipConfiguration)
- : NetworkDevice(hostname, ipConfiguration),
+ : NetworkDevice(hostname, preferences, ipConfiguration),
_preferences(preferences)
{
- #ifndef NUKI_HUB_UPDATER
- size_t caLength = preferences->getString(preference_mqtt_ca, _ca, TLS_CA_MAX_SIZE);
- size_t crtLength = preferences->getString(preference_mqtt_crt, _cert, TLS_CERT_MAX_SIZE);
- size_t keyLength = preferences->getString(preference_mqtt_key, _key, TLS_KEY_MAX_SIZE);
-
- _useEncryption = caLength > 1; // length is 1 when empty
-
- if(_useEncryption)
- {
- Log->println(F("MQTT over TLS."));
- _mqttClientSecure = new espMqttClientSecure(espMqttClientTypes::UseInternalTask::NO);
- _mqttClientSecure->setCACert(_ca);
- if(crtLength > 1 && keyLength > 1) // length is 1 when empty
- {
- Log->println(F("MQTT with client certificate."));
- _mqttClientSecure->setCertificate(_cert);
- _mqttClientSecure->setPrivateKey(_key);
- }
- }
- else
- {
- Log->println(F("MQTT without TLS."));
- _mqttClient = new espMqttClient(espMqttClientTypes::UseInternalTask::NO);
- }
-
- if(preferences->getBool(preference_mqtt_log_enabled, false) || preferences->getBool(preference_webserial_enabled, false))
- {
- MqttLoggerMode mode;
-
- if(preferences->getBool(preference_mqtt_log_enabled, false) && preferences->getBool(preference_webserial_enabled, false)) mode = MqttLoggerMode::MqttAndSerialAndWeb;
- else if (preferences->getBool(preference_webserial_enabled, false)) mode = MqttLoggerMode::SerialAndWeb;
- else mode = MqttLoggerMode::MqttAndSerial;
- _path = new char[200];
- memset(_path, 0, sizeof(_path));
- String pathStr = preferences->getString(preference_mqtt_lock_path);
- pathStr.concat(mqtt_topic_log);
- strcpy(_path, pathStr.c_str());
- Log = new MqttLogger(*getMqttClient(), _path, mode);
- }
- #endif
+#ifndef NUKI_HUB_UPDATER
+ NetworkDevice::init();
+#endif
}
-
const String WifiDevice::deviceName() const
{
return "Built-in Wi-Fi";
diff --git a/src/networkDevices/WifiDevice.h b/src/networkDevices/WifiDevice.h
index e49d540..ef1915b 100644
--- a/src/networkDevices/WifiDevice.h
+++ b/src/networkDevices/WifiDevice.h
@@ -1,7 +1,5 @@
#pragma once
-#include
-#include
#include
#include "NetworkDevice.h"
#include "IPConfiguration.h"
@@ -29,10 +27,10 @@ private:
void onDisconnected();
void onConnected();
bool connect();
- char* _path;
Preferences* _preferences = nullptr;
+ char* _path;
int _foundNetworks = 0;
int _disconnectCount = 0;
bool _connectOnScanDone = false;
@@ -45,10 +43,4 @@ private:
uint8_t _connectedChannel = 0;
uint8_t* _connectedBSSID;
int64_t _disconnectTs = 0;
-
- #ifndef NUKI_HUB_UPDATER
- char _ca[TLS_CA_MAX_SIZE] = {0};
- char _cert[TLS_CERT_MAX_SIZE] = {0};
- char _key[TLS_KEY_MAX_SIZE] = {0};
- #endif
-};
+};
\ No newline at end of file