Merge branch 'master' into pio
This commit is contained in:
29
.github/workflows/build.yml
vendored
29
.github/workflows/build.yml
vendored
@@ -21,46 +21,45 @@ jobs:
|
||||
run: pip install --upgrade platformio
|
||||
- name: Install ESPTool
|
||||
run: pip install --upgrade esptool
|
||||
- name: Build PlatformIO Project esp32dev
|
||||
- name: Build PlatformIO Project esp32
|
||||
run: |
|
||||
pio run --environment esp32dev
|
||||
mkdir -p release/esp32dev
|
||||
cp .pio/build/esp32dev/firmware.bin release/esp32dev/nuki_hub.bin
|
||||
cp .pio/build/esp32dev/firmware.bin release/esp32dev/nuki_hub_esp32.bin
|
||||
cp .pio/build/esp32dev/partitions.bin release/esp32dev/nuki_hub.partitions.bin
|
||||
cp .pio/build/esp32dev/bootloader.bin release/esp32dev/bootloader.bin
|
||||
esptool.py --chip esp32 merge_bin -o release/esp32dev/nuki_hub_esp32.bin --flash_mode dio --flash_freq keep --flash_size keep 0x1000 release/esp32dev/bootloader.bin 0x10000 release/esp32dev/nuki_hub.bin 0x8000 release/esp32dev/nuki_hub.partitions.bin
|
||||
echo "esptool.py --chip esp32 --port /dev/ttyUSB0 --baud 921600 --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_freq keep --flash_size detect 0x1000 bootloader.bin 0x10000 nuki_hub.bin 0x8000 nuki_hub.partitions.bin" > release/esp32dev/flash.sh
|
||||
esptool.py --chip esp32 merge_bin -o release/esp32dev/webflash_nuki_hub_esp32.bin --flash_mode dio --flash_freq keep --flash_size keep 0x1000 release/esp32dev/bootloader.bin 0x10000 release/esp32dev/nuki_hub_esp32.bin 0x8000 release/esp32dev/nuki_hub.partitions.bin
|
||||
echo "esptool.py --chip esp32 --port /dev/ttyUSB0 --baud 921600 --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_freq keep --flash_size detect 0x1000 bootloader.bin 0x10000 nuki_hub_esp32.bin 0x8000 nuki_hub.partitions.bin" > release/esp32dev/flash.sh
|
||||
- name: Build PlatformIO Project esp32-s3
|
||||
run: |
|
||||
pio run --environment esp32-s3
|
||||
mkdir -p release/esp32-s3
|
||||
cp .pio/build/esp32-s3/firmware.bin release/esp32-s3/nuki_hub.bin
|
||||
cp .pio/build/esp32-s3/firmware.bin release/esp32-s3/nuki_hub_esp32s3.bin
|
||||
cp .pio/build/esp32-s3/partitions.bin release/esp32-s3/nuki_hub.partitions.bin
|
||||
cp .pio/build/esp32-s3/bootloader.bin release/esp32-s3/bootloader.bin
|
||||
esptool.py --chip esp32s3 merge_bin -o release/esp32-s3/nuki_hub_esp32s3.bin --flash_mode dio --flash_freq keep --flash_size keep 0x0 release/esp32-s3/bootloader.bin 0x10000 release/esp32-s3/nuki_hub.bin 0x8000 release/esp32-s3/nuki_hub.partitions.bin
|
||||
echo "esptool.py --chip esp32s3 --port /dev/ttyUSB0 --baud 921600 --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_freq keep --flash_size detect 0x0 bootloader.bin 0x10000 nuki_hub.bin 0x8000 nuki_hub.partitions.bin" > release/esp32-s3/flash.sh
|
||||
esptool.py --chip esp32s3 merge_bin -o release/esp32-s3/webflash_nuki_hub_esp32s3.bin --flash_mode dio --flash_freq keep --flash_size keep 0x0 release/esp32-s3/bootloader.bin 0x10000 release/esp32-s3/nuki_hub_esp32s3.bin 0x8000 release/esp32-s3/nuki_hub.partitions.bin
|
||||
echo "esptool.py --chip esp32s3 --port /dev/ttyUSB0 --baud 921600 --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_freq keep --flash_size detect 0x0 bootloader.bin 0x10000 nuki_hub_esp32s3.bin 0x8000 nuki_hub.partitions.bin" > release/esp32-s3/flash.sh
|
||||
- name: Build PlatformIO Project esp32-c3
|
||||
run: |
|
||||
pio run --environment esp32-c3
|
||||
mkdir -p release/esp32-c3
|
||||
cp .pio/build/esp32-c3/firmware.bin release/esp32-c3/nuki_hub.bin
|
||||
cp .pio/build/esp32-c3/firmware.bin release/esp32-c3/nuki_hub_esp32c3.bin
|
||||
cp .pio/build/esp32-c3/partitions.bin release/esp32-c3/nuki_hub.partitions.bin
|
||||
cp .pio/build/esp32-c3/bootloader.bin release/esp32-c3/bootloader.bin
|
||||
esptool.py --chip esp32c3 merge_bin -o release/esp32-c3/nuki_hub_esp32c3.bin --flash_mode dio --flash_freq keep --flash_size keep 0x0 release/esp32-c3/bootloader.bin 0x10000 release/esp32-c3/nuki_hub.bin 0x8000 release/esp32-c3/nuki_hub.partitions.bin
|
||||
echo "esptool.py --chip esp32c3 --port /dev/ttyUSB0 --baud 921600 --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_freq keep --flash_size detect 0x0 bootloader.bin 0x10000 nuki_hub.bin 0x8000 nuki_hub.partitions.bin" > release/esp32-c3/flash.sh
|
||||
esptool.py --chip esp32c3 merge_bin -o release/esp32-c3/webflash_nuki_hub_esp32c3.bin --flash_mode dio --flash_freq keep --flash_size keep 0x0 release/esp32-c3/bootloader.bin 0x10000 release/esp32-c3/nuki_hub_esp32c3.bin 0x8000 release/esp32-c3/nuki_hub.partitions.bin
|
||||
echo "esptool.py --chip esp32c3 --port /dev/ttyUSB0 --baud 921600 --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_freq keep --flash_size detect 0x0 bootloader.bin 0x10000 nuki_hub_esp32c3.bin 0x8000 nuki_hub.partitions.bin" > release/esp32-c3/flash.sh
|
||||
- name: Build PlatformIO Project esp32solo1
|
||||
run: |
|
||||
pio run --environment esp32solo1
|
||||
mkdir -p release/esp32solo1
|
||||
cp .pio/build/esp32solo1/firmware.bin release/esp32solo1/nuki_hub.bin
|
||||
cp .pio/build/esp32solo1/firmware.bin release/esp32solo1/nuki_hub_esp32solo1.bin
|
||||
cp .pio/build/esp32solo1/partitions.bin release/esp32solo1/nuki_hub.partitions.bin
|
||||
cp .pio/build/esp32solo1/bootloader.bin release/esp32solo1/bootloader.bin
|
||||
esptool.py --chip esp32 merge_bin -o release/esp32solo1/nuki_hub_esp32solo1.bin --flash_mode dio --flash_freq keep --flash_size keep 0x1000 release/esp32solo1/bootloader.bin 0x10000 release/esp32solo1/nuki_hub.bin 0x8000 release/esp32solo1/nuki_hub.partitions.bin
|
||||
echo "esptool.py --chip esp32 --port /dev/ttyUSB0 --baud 921600 --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_freq keep --flash_size detect 0x1000 bootloader.bin 0x10000 nuki_hub.bin 0x8000 nuki_hub.partitions.bin" > release/esp32solo1/flash.sh
|
||||
- name: Upload Artifact esp32dev
|
||||
echo "esptool.py --chip esp32 --port /dev/ttyUSB0 --baud 921600 --before default_reset --after hard_reset write_flash -z --flash_mode dio --flash_freq keep --flash_size detect 0x1000 bootloader.bin 0x10000 nuki_hub_esp32solo1.bin 0x8000 nuki_hub.partitions.bin" > release/esp32solo1/flash.sh
|
||||
- name: Upload Artifact esp32
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: esp32dev-assets
|
||||
name: esp32-assets
|
||||
path: release/esp32dev
|
||||
- name: Upload Artifact esp32-s3
|
||||
uses: actions/upload-artifact@v4
|
||||
|
||||
218
README.md
218
README.md
@@ -6,7 +6,7 @@ The Nuki Hub software runs on a ESP32 module and acts as a bridge between Nuki d
|
||||
<br>
|
||||
It communicates with a Nuki Lock and/or Opener through Bluetooth (BLE) and uses MQTT to integrate with other systems.<br>
|
||||
<br>
|
||||
It exposes the lock state (and much more) through MQTT and allows executing commands like locking and unlocking through MQTT.<br>
|
||||
It exposes the lock state (and much more) through MQTT and allows executing commands like locking and unlocking as well as changing the Nuki Lock/Opener configuration through MQTT.<br>
|
||||
|
||||
***Nuki Hub does not integrate with the Nuki mobile app, it can't register itself as a bridge in the official Nuki mobile app.***
|
||||
|
||||
@@ -15,10 +15,12 @@ Feel free to join us on Discord: https://discord.gg/feB9FnMY
|
||||
## Supported devices
|
||||
|
||||
<b>Supported ESP32 devices:</b>
|
||||
- All dual-core ESP32 models with WIFI and BLE which are supported by Arduino Core 2.0.15 should work. Tested builds are provided for the ESP32 and ESP32-S3.
|
||||
- Single-core ESP32 models with WIFI and BLE which are supported by Arduino Core 2.0.15 might work. Untested builds are provided for the ESP32-C3 and ESP32-Solo1.
|
||||
- All ESP32 models with WIFI and BLE which are supported by Arduino Core 2.0.15 should work. Tested builds are provided for the ESP32, ESP32-S3 and ESP32-C3.
|
||||
- Untested builds are provided for the ESP32-Solo1.
|
||||
|
||||
<b>Not supported ESP32 devices:</b>
|
||||
- The ESP32-S2 has no BLE and as such can't run Nuki Hub.
|
||||
- The ESP32-C6 and ESP32-H2 are not supported by Arduino Core 2.0.15 as such can't run Nuki Hub (at this time).
|
||||
- The ESP32-C6 and ESP32-H2 are not supported by Arduino Core 2.0.15 and as such Nuki Hub is not compiled against these targets (at this time).
|
||||
|
||||
<b>Supported Nuki devices:</b>
|
||||
- Nuki Smart Lock 1.0
|
||||
@@ -65,7 +67,7 @@ In a browser navigate to the IP address assigned to the ESP32 via DHCP (often fo
|
||||
Next click on "Edit" below "MQTT and Network Configuration" and enter the address and port (usually 1883) of your MQTT broker and a username and a password if required by your MQTT broker.<br>
|
||||
<br>
|
||||
The firmware supports SSL encryption for MQTT, however most people and especially home users don't use this.<br>
|
||||
In that case leave all fields starting with "MQTT SSL" blank. Otherwise see the "MQTT Encryption" section of this README.
|
||||
In that case leave all fields starting with "MQTT SSL" blank. Otherwise see the "[MQTT Encryption](#mqtt-encryption-optional-wi-fi-and-lan8720-only)" section of this README.
|
||||
|
||||
## Pairing with a Nuki Lock or Opener
|
||||
|
||||
@@ -82,7 +84,7 @@ Enable "Register as app" before pairing to allow this. Otherwise the Bridge will
|
||||
## Support
|
||||
|
||||
If you haven't ordered your Nuki product yet, you can support me by using my referrer code when placing your order:<br>
|
||||
REFNW2959GXR7<br>
|
||||
REFXH49NT9NGP<br>
|
||||
This will also give you a 10% discount on your order.<br>
|
||||
<br>
|
||||
This project is free to use for everyone. However if you feel like donating, you can buy me a coffee at ko-fi.com:<br>
|
||||
@@ -106,11 +108,11 @@ In a browser navigate to the IP address assigned to the ESP32.
|
||||
|
||||
- Home Assistant discovery topic: Set to the Home Assistant auto discovery topic, leave empty to disable auto discovery. Usually "homeassistant" unless you manually changed this setting on the Home Assistant side.
|
||||
- Home Assistant device configuration URL: When using Home Assistant discovery the link to the Nuki Hub Web Configuration will be published to Home Assistant. By default when this setting is left empty this will link to the current IP of the Nuki Hub. When using a reverse proxy to access the Web Configuration you can set a custom URL here.
|
||||
- Set Nuki Opener Lock/Unlock action in Home Assistant to Continuous mode (Opener only): By default the lock entity in Home Assistant will enable Ring-to-Open (RTO) when unlocking and disable RTO when locking. By enabling this setting this behaviour will change and now unlocking will enable Continuous Mode and locking will disable Continuous Mode, for more information see the "Home Assistant Discovery" section of this README.
|
||||
- MQTT SSL CA Certificate: Optionally set to the CA SSL certificate of the MQTT broker, see the "MQTT Encryption" section of this README.
|
||||
- MQTT SSL Client Certificate: Optionally set to the Client SSL certificate of the MQTT broker, see the "MQTT Encryption" section of this README.
|
||||
- MQTT SSL Client Key: Optionally set to the Client SSL key of the MQTT broker, see the "MQTT Encryption" section of this README.
|
||||
- Network hardware: "Wi-Fi only" by default, set to one of the specified ethernet modules if available, see the "Supported Ethernet devices" and "Connecting via Ethernet" section of this README.
|
||||
- Set Nuki Opener Lock/Unlock action in Home Assistant to Continuous mode (Opener only): By default the lock entity in Home Assistant will enable Ring-to-Open (RTO) when unlocking and disable RTO when locking. By enabling this setting this behaviour will change and now unlocking will enable Continuous Mode and locking will disable Continuous Mode, for more information see the "[Home Assistant Discovery](#home-assistant-discovery-optional)" section of this README.
|
||||
- MQTT SSL CA Certificate: Optionally set to the CA SSL certificate of the MQTT broker, see the "[MQTT Encryption](#mqtt-encryption-optional-wi-fi-and-lan8720-only)" section of this README.
|
||||
- MQTT SSL Client Certificate: Optionally set to the Client SSL certificate of the MQTT broker, see the "[MQTT Encryption](#mqtt-encryption-optional-wi-fi-and-lan8720-only)" section of this README.
|
||||
- MQTT SSL Client Key: Optionally set to the Client SSL key of the MQTT broker, see the "[MQTT Encryption](#mqtt-encryption-optional-wi-fi-and-lan8720-only)" section of this README.
|
||||
- Network hardware: "Wi-Fi only" by default, set to one of the specified ethernet modules if available, see the "Supported Ethernet devices" and "[Connecting via Ethernet](#connecting-via-ethernet-optional)" section of this README.
|
||||
- Disable fallback to Wi-Fi / Wi-Fi config portal: By default the Nuki Hub will fallback to Wi-Fi and open the Wi-Fi configuration portal when the network connection fails. Enable this setting to disable this fallback.
|
||||
- RSSI Publish interval: Set to a positive integer to set the amount of seconds between updates to the maintenance/wifiRssi MQTT topic with the current Wi-Fi RSSI, set to -1 to disable, default 60.
|
||||
- Network Timeout until restart: Set to a positive integer to restart the Nuki Hub after the set amount of seconds has passed without an active connection to the MQTT broker, set to -1 to disable, default 60.
|
||||
@@ -143,16 +145,15 @@ In a browser navigate to the IP address assigned to the ESP32.
|
||||
- Query interval keypad (Only available when a Keypad is detected): Set to a positive integer to set the maximum amount of seconds between actively querying the Nuki device for the current keypad state, default 1800.
|
||||
- Number of retries if command failed: Set to a positive integer to define the amount of times the Nuki Hub retries sending commands to the Nuki Lock or Opener when commands are not acknowledged by the device, default 3.
|
||||
- Delay between retries: Set to the amount of milliseconds the Nuki Hub waits between resending not acknowledged commands, default 100.
|
||||
- Nuki Bridge is running alongside Nuki Hub: Enable to allow Nuki Hub to co-exist with a Nuki Bridge by registering Nuki Hub as an (smartphone) app instead of a bridge. Changing this setting will require re-pairing. Enabling this setting is strongly discouraged as described in the "Pairing with a Nuki Lock or Opener" section of this README
|
||||
- Nuki Bridge is running alongside Nuki Hub: Enable to allow Nuki Hub to co-exist with a Nuki Bridge by registering Nuki Hub as an (smartphone) app instead of a bridge. Changing this setting will require re-pairing. Enabling this setting is strongly discouraged as described in the "[Pairing with a Nuki Lock or Opener](#pairing-with-a-nuki-lock-or-opener)" section of this README
|
||||
- Presence detection timeout: Set to a positive integer to set the amount of seconds between updates to the presence/devices MQTT topic with the list of detected bluetooth devices, set to -1 to disable presence detection, default 60.
|
||||
- Restart if bluetooth beacons not received: Set to a positive integer to restart the Nuki Hub after the set amount of seconds has passed without receiving a bluetooth beacon from the Nuki device, set to -1 to disable, default 60. Because the bluetooth stack of the ESP32 can silently fail it is not recommended to disable this setting.
|
||||
|
||||
### Access Level Configuration
|
||||
|
||||
#### Nuki General Access Control
|
||||
- Change Lock/Opener configuration: Allows changing the Nuki Lock/Opener configuration through MQTT.
|
||||
- Publish keypad codes information (Only available when a Keypad is detected): Enable to publish information about keypad codes through MQTT, see the "Keypad control" section of this README
|
||||
- Add, modify and delete keypad codes (Only available when a Keypad is detected): Enable to allow configuration of keypad codes through MQTT, see the "Keypad control" section of this README
|
||||
- Publish keypad codes information (Only available when a Keypad is detected): Enable to publish information about keypad codes through MQTT, see the "[Keypad control](#keypad-control-optional)" section of this README
|
||||
- Add, modify and delete keypad codes (Only available when a Keypad is detected): Enable to allow configuration of keypad codes through MQTT, see the "[Keypad control](#keypad-control-optional)" section of this README
|
||||
- Publish time control information: Enable to publish information about time control entries through MQTT, see the "Time control" section of this README
|
||||
- Add, modify and delete time control entries: Enable to allow configuration of time control entries through MQTT, see the "Time control" section of this README
|
||||
- Publish auth data: Enable to publish authorization data to the MQTT topic lock/log. Requires the Nuki security code / PIN to be set, see "Nuki Lock PIN / Nuki Opener PIN" below.
|
||||
@@ -160,6 +161,10 @@ In a browser navigate to the IP address assigned to the ESP32.
|
||||
#### Nuki Lock/Opener Access Control
|
||||
- Enable or disable executing each available lock action for the Nuki Lock and Nuki Opener through MQTT. Note: GPIO control is not restricted through this setting.
|
||||
|
||||
#### Nuki Lock/Opener Config Control
|
||||
- Enable or disable changing each available configuration setting for the Nuki Lock and Nuki Opener through MQTT.
|
||||
- NOTE: Changing configuration settings requires the Nuki security code / PIN to be set, see "Nuki Lock PIN / Nuki Opener PIN" below.
|
||||
|
||||
### Credentials
|
||||
|
||||
#### Credentials
|
||||
@@ -199,13 +204,6 @@ In a browser navigate to the IP address assigned to the ESP32.
|
||||
- lock/rssi: The signal strenght of the Nuki Lock as measured by the ESP32 and expressed by the RSSI Value in dBm.
|
||||
- lock/address: The BLE address of the Nuki Lock.
|
||||
- lock/retry: Reports the current number of retries for the current command. 0 when command is succesfull, "failed" if the number of retries is greater than the maximum configured number of retries.
|
||||
<br><br>
|
||||
- configuration/autoLock: enable or disable autoLock (0 = disabled; 1 = enabled). Maps to "Auto lock enabled" in the bluetooth API.
|
||||
- configuration/autoUnlock: enable or disable autoLock in general (0 = disabled; 1 = enabled). Maps to "Auto unlock disabled" in the bluetooth API.
|
||||
- configuration/buttonEnabled: enable or disable the button on the lock (0 = disabled; 1 = enabled).
|
||||
- configuration/ledBrightness: Set the brightness of the LED on the lock (0=min; 5=max).
|
||||
- configuration/ledEnabled: enable or disable the LED on the lock (0 = disabled; 1 = enabled).
|
||||
- configuration/singleLock: configures wether to single- or double-lock the door (0 = double; 1 = single).
|
||||
|
||||
### Opener
|
||||
|
||||
@@ -228,10 +226,19 @@ In a browser navigate to the IP address assigned to the ESP32.
|
||||
- lock/rssi: The bluetooth signal strength of the Nuki Lock as measured by the ESP32 and expressed by the RSSI Value in dBm.
|
||||
- lock/address: The BLE address of the Nuki Lock.
|
||||
- lock/retry: Reports the current number of retries for the current command. 0 when command is succesfull, "failed" if the number of retries is greater than the maximum configured number of retries.
|
||||
<br><br>
|
||||
- configuration/buttonEnabled: enable or disable the button on the opener (0 = disabled; 1 = enabled).
|
||||
- configuration/ledEnabled: enable or disable the LED on the opener (0 = disabled; 1 = enabled).
|
||||
- configuration/soundLevel: configures the volume of sounds the opener plays back (0 = min; 255 = max).
|
||||
|
||||
### Configuration
|
||||
- configuration/buttonEnabled: 1 if the Nuki Lock/Opener button is enabled, otherwise 0.
|
||||
- configuration/ledEnabled: 1 if the Nuki Lock/Opener LED is enabled, otherwise 0.
|
||||
- configuration/ledBrightness: Set to the brightness of the LED on the Nuki Lock (0=min; 5=max) (Lock only).
|
||||
- configuration/singleLock: 0 if the Nuki Lock is set to double-lock the door, otherwise 1 (= single-lock) (Lock only).
|
||||
- configuration/autoLock: 1 if the Nuki Lock is set to Auto Lock, otherwise 0 (Lock only).
|
||||
- configuration/autoUnlock: 1 if the Nuki Lock is set to Auto Unlock, otherwise 0 (Lock only).
|
||||
- configuration/soundLevel: Set to the volume for sounds the Nuki Opener plays (0 = min; 255 = max) (Opener only).
|
||||
- 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
|
||||
- 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
|
||||
- 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.
|
||||
- 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
|
||||
|
||||
@@ -254,7 +261,7 @@ In a browser navigate to the IP address assigned to the ESP32.
|
||||
|
||||
### Keypad
|
||||
|
||||
- See the "Keypad control" section of this README.
|
||||
- See the "[Keypad control](#keypad-control-optional)" section of this README.
|
||||
|
||||
### Time Control
|
||||
|
||||
@@ -277,19 +284,125 @@ In a browser navigate to the IP address assigned to the ESP32.
|
||||
- maintenance/wifiRssi: The Wi-Fi signal strength of the Wi-Fi Access Point as measured by the ESP32 and expressed by the RSSI Value in dBm.
|
||||
- maintenance/log: If "Enable MQTT logging" is enabled in the web interface, this topic will be filled with debug log information.
|
||||
- maintenance/freeHeap: Only available when debug mode is enabled. Set to the current size of free heap memory in bytes.
|
||||
- maintenance/restartReasonNukiHub: Only available when debug mode is enabled. Set to the last reason Nuki Hub was restarted. See RestartReason.h for possible values
|
||||
- maintenance/restartReasonNukiEsp: Only available when debug mode is enabled. Set to the last reason the ESP was restarted. See RestartReason.h for possible values
|
||||
- maintenance/restartReasonNukiHub: Only available when debug mode is enabled. Set to the last reason Nuki Hub was restarted. See [RestartReason.h](/RestartReason.h) for possible values
|
||||
- maintenance/restartReasonNukiEsp: Only available when debug mode is enabled. Set to the last reason the ESP was restarted. See [RestartReason.h](/RestartReason.h) for possible values
|
||||
|
||||
### Misc
|
||||
|
||||
- presence/devices: List of detected bluetooth devices as CSV. Can be used for presence detection.
|
||||
|
||||
## Changing Nuki Lock/Opener Configuration
|
||||
|
||||
To change Nuki Lock/Opener settings set the `configuration/action` topic to a JSON formatted value with any of the following settings. Multiple settings can be changed at once. See [Nuki Smart Lock API Basic Config](https://developer.nuki.io/page/nuki-smart-lock-api-2/2/#heading--set-config), [Nuki Smart Lock API Advanced Config](https://developer.nuki.io/page/nuki-smart-lock-api-2/2/#heading--advanced-config), [Nuki Opener API Basic Config](https://developer.nuki.io/page/nuki-opener-api-1/7/#heading--set-config) and [Nuki Opener API Advanced Config](https://developer.nuki.io/page/nuki-opener-api-1/7/#heading--advanced-config) for more information on the available settings.<br>
|
||||
Changing settings has to enabled first in the configuration portal. Check the settings you want to be able to change under "Nuki Lock/Opener Config Control" in "Access Level Configuration" and save the configuration.
|
||||
|
||||
### Nuki Lock Configuration
|
||||
|
||||
| Setting | Usage | Possible values | Example |
|
||||
|-----------------------------------------|--------------------------------------------------------------------------------------------------|-------------------------------------------------------------------|------------------------------------|
|
||||
| name | The name of the Smart Lock. | Alphanumeric string, max length 32 chars |`{ "name": "Frontdoor" }` |
|
||||
| latitude | The latitude of the Smart Locks geoposition. | Float |`{ "latitude": "48.858093" }` |
|
||||
| longitude | The longitude of the Smart Locks geoposition | Float |`{ "longitude": "2.294694" }` |
|
||||
| autoUnlatch | Whether or not the door shall be unlatched by manually operating a door handle from the outside. | 1 = enabled, 0 = disabled |`{ "autoUnlatch": "1" }` |
|
||||
| pairingEnabled | Whether or not activating the pairing mode via button should be enabled. | 1 = enabled, 0 = disabled |`{ "pairingEnabled": "0" }` |
|
||||
| buttonEnabled | Whether or not the button should be enabled. | 1 = enabled, 0 = disabled |`{ "buttonEnabled": "1" }` |
|
||||
| ledEnabled | Whether or not the flashing LED should be enabled to signal an unlocked door. | 1 = enabled, 0 = disabled |`{ "ledEnabled": "1" }` |
|
||||
| ledBrightness | The LED brightness level | 0 = off, …, 5 = max |`{ "ledBrightness": "2" }` |
|
||||
| timeZoneOffset | The timezone offset (UTC) in minutes | Integer between 0 and 60 |`{ "timeZoneOffset": "0" }` |
|
||||
| dstMode | The desired daylight saving time mode. | 0 = disabled, 1 = European |`{ "dstMode": "0" }` |
|
||||
| fobAction1 | The desired action, if a Nuki Fob is pressed once. | "No Action", "Unlock", "Lock", "Lock n Go", "Intelligent" |`{ "fobAction1": "Lock n Go" }` |
|
||||
| fobAction2 | The desired action, if a Nuki Fob is pressed twice. | "No Action", "Unlock", "Lock", "Lock n Go", "Intelligent" |`{ "fobAction2": "Intelligent" }` |
|
||||
| fobAction3 | The desired action, if a Nuki Fob is pressed three times. | "No Action", "Unlock", "Lock", "Lock n Go", "Intelligent" |`{ "fobAction3": "Unlock" }` |
|
||||
| singleLock | Whether only a single lock or double lock should be performed | 0 = double lock, 1 = single lock |`{ "singleLock": "0" }` |
|
||||
| advertisingMode | The desired advertising mode. | "Automatic", "Normal", "Slow", "Slowest" |`{ "advertisingMode": "Normal" }` |
|
||||
| timeZone | The current timezone or "None" if timezones are not supported | "None" or one of the timezones from [Nuki Timezones](https://developer.nuki.io/page/nuki-smart-lock-api-2/2/#heading--list-of-timezone-ids) |`{ "timeZone": "Europe/Berlin" }` |
|
||||
| unlockedPositionOffsetDegrees | Offset that alters the unlocked position in degrees. | Integer between -90 and 180 |`{ "unlockedPositionOffsetDegrees": "-90" }` |
|
||||
| lockedPositionOffsetDegrees | Offset that alters the locked position in degrees. | Integer between -180 and 90 |`{ "lockedPositionOffsetDegrees": "80" }` |
|
||||
| singleLockedPositionOffsetDegrees | Offset that alters the single locked position in degrees. | Integer between -180 and 180 |`{ "singleLockedPositionOffsetDegrees": "120" }` |
|
||||
| unlockedToLockedTransitionOffsetDegrees | Offset that alters the position where transition from unlocked to locked happens in degrees. | Integer between -180 and 180 |`{ "unlockedToLockedTransitionOffsetDegrees": "180" }` |
|
||||
| lockNgoTimeout | Timeout for lock ‘n’ go in seconds | Integer between 5 and 60 |`{ "lockNgoTimeout": "60" }` |
|
||||
| singleButtonPressAction | The desired action, if the button is pressed once. | "No Action", "Intelligent", "Unlock", "Lock", "Unlatch", "Lock n Go", "Show Status" |`{ "singleButtonPressAction": "Lock n Go" }` |
|
||||
| doubleButtonPressAction | The desired action, if the button is pressed twice. | "No Action", "Intelligent", "Unlock", "Lock", "Unlatch", "Lock n Go", "Show Status" |`{ "doubleButtonPressAction": "Show Status" }` |
|
||||
| detachedCylinder | Wheter the inner side of the used cylinder is detached from the outer side. | 0 = not detached, 1 = detached |`{ "detachedCylinder": "1" }` |
|
||||
| batteryType | The type of the batteries present in the smart lock. | "Alkali", "Accumulators", "Lithium" |`{ "batteryType": "Accumulators" }` |
|
||||
| automaticBatteryTypeDetection | Whether the automatic detection of the battery type is enabled. | 1 = enabled, 0 = disabled |`{ "automaticBatteryTypeDetection": "Lock n Go" }` |
|
||||
| unlatchDuration | Duration in seconds for holding the latch in unlatched position. | Integer between 1 and 30 |`{ "unlatchDuration": "3" }` |
|
||||
| autoLockTimeOut | Seconds until the smart lock relocks itself after it has been unlocked. | Integer between 30 and 180 |`{ "autoLockTimeOut": "60" }` |
|
||||
| autoUnLockDisabled | Whether auto unlock should be disabled in general. | 1 = auto unlock disabled, 0 = auto unlock enabled |`{ "autoUnLockDisabled": "1" }` |
|
||||
| nightModeEnabled | Whether nightmode is enabled. | 1 = enabled, 0 = disabled |`{ "nightModeEnabled": "1" }` |
|
||||
| nightModeStartTime | Start time for nightmode if enabled. | Time in "HH:MM" format |`{ "nightModeStartTime": "22:00" }` |
|
||||
| nightModeEndTime | End time for nightmode if enabled. | Time in "HH:MM" format |`{ "nightModeEndTime": "07:00" }` |
|
||||
| nightModeAutoLockEnabled | Whether auto lock should be enabled during nightmode. | 1 = enabled, 0 = disabled |`{ "nightModeAutoLockEnabled": "1" }`|
|
||||
| nightModeAutoUnlockDisabled | Whether auto unlock should be disabled during nightmode. | 1 = auto unlock disabled, 0 = auto unlock enabled |`{ "nightModeAutoUnlockDisabled": "1" }`|
|
||||
| nightModeImmediateLockOnStart | Whether the door should be immediately locked on nightmode start. | 1 = enabled, 0 = disabled |`{ "nightModeImmediateLockOnStart": "1" }`|
|
||||
| autoLockEnabled | Whether auto lock is enabled. | 1 = enabled, 0 = disabled |`{ "autoLockEnabled": "1" }` |
|
||||
| immediateAutoLockEnabled | Whether auto lock should be performed immediately after the door has been closed. | 1 = enabled, 0 = disabled |`{ "immediateAutoLockEnabled": "1" }`|
|
||||
| autoUpdateEnabled | Whether automatic firmware updates should be enabled. | 1 = enabled, 0 = disabled |`{ "autoUpdateEnabled": "1" }` |
|
||||
|
||||
### Nuki Opener Configuration
|
||||
|
||||
| Setting | Usage | Possible values | Example |
|
||||
|-----------------------------------------|--------------------------------------------------------------------------------------------------|-------------------------------------------------------------------|------------------------------------|
|
||||
| name | The name of the Opener. | Alphanumeric string, max length 32 chars |`{ "name": "Frontdoor" }` |
|
||||
| latitude | The latitude of the Openers geoposition. | Float |`{ "latitude": "48.858093" }` |
|
||||
| longitude | The longitude of the Openers geoposition | Float |`{ "longitude": "2.294694" }` |
|
||||
| pairingEnabled | Whether or not activating the pairing mode via button should be enabled. | 1 = enabled, 0 = disabled |`{ "pairingEnabled": "0" }` |
|
||||
| buttonEnabled | Whether or not the button should be enabled. | 1 = enabled, 0 = disabled |`{ "buttonEnabled": "1" }` |
|
||||
| ledFlashEnabled | Whether or not the flashing LED should be enabled to signal CM or RTO. | 1 = enabled, 0 = disabled |`{ "ledFlashEnabled": "1" }` |
|
||||
| timeZoneOffset | The timezone offset (UTC) in minutes | Integer between 0 and 60 |`{ "timeZoneOffset": "0" }` |
|
||||
| dstMode | The desired daylight saving time mode. | 0 = disabled, 1 = European |`{ "dstMode": "0" }` |
|
||||
| fobAction1 | The desired action, if a Nuki Fob is pressed once. | "No Action", "Toggle RTO", "Activate RTO", "Deactivate RTO", "Open", "Ring" |`{ "fobAction1": "Toggle RTO" }` |
|
||||
| fobAction2 | The desired action, if a Nuki Fob is pressed twice. | "No Action", "Toggle RTO", "Activate RTO", "Deactivate RTO", "Open", "Ring" |`{ "fobAction2": "Open" }` |
|
||||
| fobAction3 | The desired action, if a Nuki Fob is pressed three times. | "No Action", "Toggle RTO", "Activate RTO", "Deactivate RTO", "Open", "Ring" |`{ "fobAction3": "Ring" }` |
|
||||
| operatingMode | The desired operating mode | "Generic door opener", "Analogue intercom", "Digital intercom", "Siedle", "TCS", "Bticino", "Siedle HTS", "STR", "Ritto", "Fermax", "Comelit", "Urmet BiBus", "Urmet 2Voice", "Golmar", "SKS", "Spare" |`{ "operatingMode": "TCS" }` |
|
||||
| advertisingMode | The desired advertising mode. | "Automatic", "Normal", "Slow", "Slowest" |`{ "advertisingMode": "Normal" }` |
|
||||
| timeZone | The current timezone or "None" if timezones are not supported | "None" or one of the timezones from [Nuki Timezones](https://developer.nuki.io/page/nuki-smart-lock-api-2/2/#heading--list-of-timezone-ids) |`{ "timeZone": "Europe/Berlin" }` |
|
||||
| intercomID | Database ID of the connected intercom. | Integer |`{ "intercomID": "1" }` |
|
||||
| busModeSwitch | Method to switch between data and analogue mode | 0 = none, 1 =vshort circuit |`{ "busModeSwitch": "0" }` |
|
||||
| shortCircuitDuration | Duration of the short circuit for BUS mode switching in ms. | Integer |`{ "shortCircuitDuration": "250" }` |
|
||||
| electricStrikeDelay | Delay in ms of electric strike activation in case of an electric strike actuation by RTO | Integer between 0 and 30000 |`{ "electricStrikeDelay": "2080" }` |
|
||||
| randomElectricStrikeDelay | Random delay (3-7s) in order to simulate a person inside actuating the electric strike. | 1 = enabled, 0 = disabled |`{ "randomElectricStrikeDelay": "1" }`|
|
||||
| electricStrikeDuration | Duration in ms of electric strike actuation. . | Integer between 1000 and 30000 |`{ "electricStrikeDuration": "5000" }` |
|
||||
| disableRtoAfterRing | Whether to disable RTO after ring. | 1 = disable RTO after ring, 0 = Don't disable RTO after ring |`{ "disableRtoAfterRing": "0" }` |
|
||||
| rtoTimeout | After this period of time in minutes, RTO gets deactivated automatically | Integer between 5 and 60 |`{ "rtoTimeout": "60" }` |
|
||||
| doorbellSuppression | Whether the doorbell is suppressed when Ring, CM and/or RTO are active | "Off", "CM", "RTO", "CM & RTO", "Ring", "CM & Ring", "RTO & Ring", "CM & RTO & Ring"|`{ "doorbellSuppression": "CM & Ring" }`|
|
||||
| doorbellSuppressionDuration | Duration in ms of doorbell suppression. | Integer between 500 and 10000 |`{ "doorbellSuppressionDuration": "2000" }` |
|
||||
| soundRing | The Ring sound | "No Sound", "Sound 1", "Sound 2", "Sound 3" |`{ "soundRing": "No Sound" }` |
|
||||
| soundOpen | The Open sound. | "No Sound", "Sound 1", "Sound 2", "Sound 3" |`{ "soundOpen": "Sound 1" }` |
|
||||
| soundRto | The RTO sound. | "No Sound", "Sound 1", "Sound 2", "Sound 3" |`{ "soundRto": "Sound 2" }` |
|
||||
| soundCm | The CM sound. | "No Sound", "Sound 1", "Sound 2", "Sound 3" |`{ "soundCm": "Sound 3" }` |
|
||||
| soundConfirmation | Sound confirmation | 0 = no sound, 1 = sound |`{ "soundConfirmation": "1" }` |
|
||||
| soundLevel | The sound level for the opener | Integer between 0 and 255 |`{ "soundLevel": "200" }` |
|
||||
| singleButtonPressAction | The desired action, if the button is pressed once. | "No Action", "Toggle RTO", "Activate RTO", "Deactivate RTO", "Toggle CM", "Activate CM", "Deactivate CM", "Open" |`{ "singleButtonPressAction": "Open" }` |
|
||||
| doubleButtonPressAction | The desired action, if the button is pressed twice. | "No Action", "Toggle RTO", "Activate RTO", "Deactivate RTO", "Toggle CM", "Activate CM", "Deactivate CM", "Open" |`{ "doubleButtonPressAction": "No Action" }` |
|
||||
| batteryType | The type of the batteries present in the smart lock. | "Alkali", "Accumulators", "Lithium" |`{ "batteryType": "Accumulators" }` |
|
||||
| automaticBatteryTypeDetection | Whether the automatic detection of the battery type is enabled. | 1 = enabled, 0 = disabled |`{ "automaticBatteryTypeDetection": "1" }` |
|
||||
|
||||
Example usage for changing multiple settings at once:<br>
|
||||
- `{ "buttonEnabled": "1", "lockngoTimeout": "60", "automaticBatteryTypeDetection": "1" }`
|
||||
- `{ "fobAction1": "Unlock", "fobAction2": "Intelligent", "nightModeImmediateLockOnStart": "1" }`
|
||||
|
||||
### Result of attempted configuration changes
|
||||
|
||||
The result of the last configuration change action will be published to the `configuration/commandResult` MQTT topic as JSON data.<br>
|
||||
<br>
|
||||
The JSON data will include a node called "general" and a node for every setting that Nuki Hub detected in the action.<br>
|
||||
Possible values for the "general" node are "noPinSet", "invalidJson", "invalidConfig", "success" and "noChange".<br>
|
||||
Possible values for the node per setting are "unchanged", "noValueSet", "invalidValue", "valueTooLong", "accessDenied", "success", "failed", "timeOut", "working", "notPaired", "error" and "undefined"<br>
|
||||
<br>
|
||||
Example:
|
||||
- `{"advertisingMode":"success","general":"success"}`
|
||||
|
||||
### Home Assistant discovery
|
||||
|
||||
If Home Assistant discovery is enabled (see the [Home Assistant Discovery](#home-assistant-discovery-optional) section of this README) Nuki Hub will create entities for almost all of the above settings. These entities will be disabled by default in Home Assistant, but can be found in the MQTT devices section of the Home Assistant UI under the "Configuration" section of the Nuki Lock/Opener and enabled there.
|
||||
|
||||
## Over-the-air Update (OTA)
|
||||
|
||||
After the initial installation of the Nuki Hub firmware via serial connection, further updates can be deployed via OTA update from a browser.<br>
|
||||
In the configuration portal, scroll down to "Firmware update" and click "Open".<br>
|
||||
Then Click "Browse" and select the new "nuki_hub.bin" file and select "Upload file".<br>
|
||||
After about a minute the new firmware should be installed.
|
||||
After about a minute the new firmware should be installed afterwhich the ESP will reboot automatically.
|
||||
|
||||
## MQTT Encryption (optional; Wi-Fi and LAN8720 only)
|
||||
|
||||
@@ -314,7 +427,7 @@ The following mapping between Home Assistant services and Nuki commands is setup
|
||||
| lock.unlock | Unlock | Enable Ring To Open | Enable Continuous Mode |
|
||||
| lock.open | Unlatch | Electric Strike Actuation | Electric Strike Actuation |
|
||||
|
||||
NOTE: MQTT Discovery uses retained MQTT messages to store devices configurations. In order to avoid orphan configurations on your broker please disable autodiscovery first if you no longer want to use this SW. Retained messages are automatically cleared when unpairing and when changing/disabling autodiscovery topic in MQTT Configuration page.<br>
|
||||
NOTE: MQTT Discovery uses retained MQTT messages to store devices configurations. In order to avoid orphan configurations on your broker please disable autodiscovery first if you no longer want to use this software. Retained messages are automatically cleared when unpairing and when changing/disabling autodiscovery topic in MQTT Configuration page.<br>
|
||||
NOTE2: Home Assistant can be setup manually using the [MQTT Lock integration](https://www.home-assistant.io/integrations/lock.mqtt/), but this is not recommended
|
||||
|
||||
## Keypad control using JSON (optional)
|
||||
@@ -327,21 +440,20 @@ For security reasons, the code itself is not published.
|
||||
|
||||
To change Nuki Lock/Opener keypad settings set the `keypad/actionJson` topic to a JSON formatted value containing the following nodes.
|
||||
|
||||
| Node | Delete | Add | Update | Usage | Possible values |
|
||||
|------------------|----------|----------|----------|------------------------------------------------------------------------------------------|----------------------------------------------------------------|
|
||||
| action | Required | Required | Required | The action to execute | "delete", "add", "update" |
|
||||
| codeId | Required | Not used | Required | The code ID of the existing code to delete or update | Integer |
|
||||
| code | Not used | Required | Required | The code to create or update | 6-digit Integer without zero's |
|
||||
| enabled | Not used | Not used | Optional | Enable or disable the code, enabled if not set | 1 = enabled, 0 = disabled |
|
||||
| name | Not used | Required | Required | The name of the code to create or update | String, max 20 chars |
|
||||
| timeLimited | Not used | Optional | Optional | If this authorization is restricted to access only at certain times, disabled if not set | 1 = enabled, 0 = disabled |
|
||||
| allowedFrom | Not used | Optional | Optional | The start timestamp from which access should be allowed (requires timeLimited = 1) | "YYYY-MM-DD HH:MM:SS" |
|
||||
| allowedUntil | Not used | Optional | Optional | The end timestamp until access should be allowed (requires timeLimited = 1) | "YYYY-MM-DD HH:MM:SS" |
|
||||
| allowedWeekdays | Not used | Optional | Optional | Allowed weekdays on which access should be allowed (requires timeLimited = 1) | Array of days: "mon", "tue", "wed", "thu" , "fri" "sat", "sun" |
|
||||
| allowedFromTime | Not used | Optional | Optional | The start time per day from which access should be allowed (requires timeLimited = 1) | "HH:MM" |
|
||||
| allowedUntilTime | Not used | Optional | Optional | The end time per day until access should be allowed (requires timeLimited = 1) | "HH:MM" |
|
||||
| Node | Delete | Add | Update | Usage | Possible values |
|
||||
|------------------|----------|----------|----------|------------------------------------------------------------------------------------------------------------------|----------------------------------------|
|
||||
| action | Required | Required | Required | The action to execute | "delete", "add", "update" |
|
||||
| codeId | Required | Not used | Required | The code ID of the existing code to delete or update | Integer |
|
||||
| code | Not used | Required | Required | The code to create or update | 6-digit Integer without zero's, can't start with "12"|
|
||||
| enabled | Not used | Not used | Optional | Enable or disable the code, always enabled on add, disabled if not set on update | 1 = enabled, 0 = disabled |
|
||||
| name | Not used | Required | Required | The name of the code to create or update | String, max 20 chars |
|
||||
| timeLimited | Not used | Optional | Optional | If this authorization is restricted to access only at certain times, disabled if not set (requires enabled = 1) | 1 = enabled, 0 = disabled |
|
||||
| allowedFrom | Not used | Optional | Optional | The start timestamp from which access should be allowed (requires enabled = 1 and timeLimited = 1) | "YYYY-MM-DD HH:MM:SS" |
|
||||
| allowedUntil | Not used | Optional | Optional | The end timestamp until access should be allowed (requires enabled = 1 and timeLimited = 1) | "YYYY-MM-DD HH:MM:SS" |
|
||||
| allowedWeekdays | Not used | Optional | Optional | Weekdays on which access should be allowed (requires enabled = 1 and timeLimited = 1) | Array of days: "mon", "tue", "wed", "thu" , "fri" "sat", "sun"|
|
||||
| allowedFromTime | Not used | Optional | Optional | The start time per day from which access should be allowed (requires enabled = 1 and timeLimited = 1) | "HH:MM" |
|
||||
| allowedUntilTime | Not used | Optional | Optional | The end time per day until access should be allowed (requires enabled = 1 and timeLimited = 1) | "HH:MM" |
|
||||
|
||||
Example usage:<br>
|
||||
Examples:
|
||||
- Delete: `{ "action": "delete", "codeId": "1234" }`
|
||||
- Add: `{ "action": "add", "code": "589472", "name": "Test", "timeLimited": "1", "allowedFrom": "2024-04-12 10:00:00", "allowedUntil": "2034-04-12 10:00:00", "allowedWeekdays": [ "wed", "thu", "fri" ], "allowedFromTime": "08:00", "allowedUntilTime": "16:00" }`
|
||||
@@ -358,6 +470,7 @@ If a keypad is connected to the lock, keypad codes can be added, updated and rem
|
||||
This has to enabled first in the configuration portal. Check "Add, modify and delete keypad codes" under "Access Level Configuration" and save the configuration.
|
||||
|
||||
Information about codes is published under "keypad/code_x", x starting from 0 up the number of configured codes. This needs to be enabled separately by checking "Publish keypad codes information" under "Access Level Configuration" and saving the configuration.
|
||||
|
||||
For security reasons, the code itself is not published. To modify keypad codes, a command
|
||||
structure is setup under keypad/command:
|
||||
|
||||
@@ -398,12 +511,11 @@ To change Nuki Lock/Opener time control settings set the `timecontrol/actionJson
|
||||
|------------------|----------|----------|----------|------------------------------------------------------------------------------------------|----------------------------------------------------------------|
|
||||
| action | Required | Required | Required | The action to execute | "delete", "add", "update" |
|
||||
| entryId | Required | Not used | Required | The entry ID of the existing entry to delete or update | Integer |
|
||||
| enabled | Not used | Not used | Optional | Enable or disable the entry, enabled if not set | 1 = enabled, 0 = disabled |
|
||||
| weekdays | Not used | Optional | Optional | Weekdays on which the chosen lock action should be exectued | Array of days: "mon", "tue", "wed", "thu" , "fri" "sat", "sun" |
|
||||
| time | Not used | Required | Required | The time on which the chosen lock action should be executed | "HH:MM" |
|
||||
| lockAction | Not used | Required | Required | The lock action that should be executed on the chosen weekdays at the chosen time | For the Nuki lock: "Unlock", "Lock", "Unlatch", "LockNgo", "LockNgoUnlatch", "FullLock". For the Nuki Opener: "ActivateRTO", "DeactivateRTO", "ElectricStrikeActuation", "ActivateCM", "DeactivateCM" |
|
||||
| enabled | Not used | Not used | Optional | Enable or disable the entry, always enabled on add, disabled if not set on update | 1 = enabled, 0 = disabled |
|
||||
| weekdays | Not used | Optional | Optional | Weekdays on which the chosen lock action should be exectued (requires enabled = 1) | Array of days: "mon", "tue", "wed", "thu" , "fri" "sat", "sun" |
|
||||
| time | Not used | Required | Required | The time on which the chosen lock action should be executed (requires enabled = 1) | "HH:MM" |
|
||||
| lockAction | Not used | Required | Required | The lock action that should be executed on the chosen weekdays at the chosen time (requires enabled = 1) | For the Nuki lock: "Unlock", "Lock", "Unlatch", "LockNgo", "LockNgoUnlatch", "FullLock". For the Nuki Opener: "ActivateRTO", "DeactivateRTO", "ElectricStrikeActuation", "ActivateCM", "DeactivateCM |
|
||||
|
||||
Example usage:<br>
|
||||
Examples:
|
||||
- Delete: `{ "action": "delete", "entryId": "1234" }`
|
||||
- Add: `{ "action": "add", "weekdays": [ "wed", "thu", "fri" ], "time": "08:00", "lockAction": "Unlock" }`
|
||||
@@ -442,7 +554,7 @@ Note: The old setting "Enable control via GPIO" is removed. If you had enabled t
|
||||
|
||||
If you prefer to connect to the MQTT Broker via Ethernet instead of Wi-Fi, you either use one of the supported ESP32 modules (see about section above),
|
||||
or wire a seperate Wiznet W5x00 Module (W5100, W5200, W5500 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 settings section.
|
||||
select the correct network hardware in the "MQTT and Network Configuration" section.
|
||||
|
||||
To wire an external W5x00 module to the ESP, use this wiring scheme:
|
||||
|
||||
@@ -481,7 +593,7 @@ To erase the flash, use the espressif download tool and click the "Erase" button
|
||||
Afterwards flash the firmware as described in the readme within the 7z file.<br>
|
||||
<br>
|
||||
|
||||
Also, there are reports that ESP32 "DEVKIT1" module don't work and pairing is not possible. The reason is unknown, but if you use such a module, try a different one.<br>
|
||||
Also, there are reports that the ESP32 "DEVKIT1" module doesn't work and pairing is not possible. The reason is unknown, but if you use such a module, try a different one.<br>
|
||||
<br>
|
||||
Reported as working are:
|
||||
- [M5Stack ATOM Lite](https://shop.m5stack.com/products/atom-lite-esp32-development-kit)
|
||||
@@ -521,7 +633,7 @@ See the previous point, this functionality needs the correct PIN to be configure
|
||||
|
||||
### Using Home Assistant, it's only possible to lock or unlock the door, but not to unlatch it
|
||||
|
||||
Make sure "Access level" under "Advanced Nuki Configuration" is set to "Full".<br>
|
||||
Make sure the "Unlatch" option is checked under "Access Level Configuration".<br>
|
||||
<br>
|
||||
Unlatching can be triggered using the lock.open service.<br>
|
||||
<br>
|
||||
|
||||
BIN
ota/nuki_hub_esp32.bin
Normal file
BIN
ota/nuki_hub_esp32.bin
Normal file
Binary file not shown.
BIN
ota/nuki_hub_esp32c3.bin
Normal file
BIN
ota/nuki_hub_esp32c3.bin
Normal file
Binary file not shown.
BIN
ota/nuki_hub_esp32s3.bin
Normal file
BIN
ota/nuki_hub_esp32s3.bin
Normal file
Binary file not shown.
BIN
ota/nuki_hub_esp32solo1.bin
Normal file
BIN
ota/nuki_hub_esp32solo1.bin
Normal file
Binary file not shown.
17
src/Config.h
17
src/Config.h
@@ -1,10 +1,23 @@
|
||||
#pragma once
|
||||
|
||||
#define NUKI_HUB_VERSION "8.33"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
#define NUKI_HUB_VERSION "8.34"
|
||||
|
||||
#define GITHUB_LATEST_RELEASE_URL "https://github.com/technyon/nuki_hub/releases/latest"
|
||||
#define GITHUB_LATEST_RELEASE_API_URL "https://api.github.com/repos/technyon/nuki_hub/releases/latest"
|
||||
#define GITHUB_LATEST_RELEASE_BINARY_URL "https://github.com/technyon/nuki_hub/raw/master/webflash/nuki_hub.bin"
|
||||
|
||||
#if defined(CONFIG_IDF_TARGET_ESP32C3)
|
||||
#define GITHUB_LATEST_RELEASE_BINARY_URL "https://github.com/technyon/nuki_hub/raw/master/ota/nuki_hub_esp32c3.bin"
|
||||
#elif defined(CONFIG_IDF_TARGET_ESP32S3)
|
||||
#define GITHUB_LATEST_RELEASE_BINARY_URL "https://github.com/technyon/nuki_hub/raw/master/ota/nuki_hub_esp32s3.bin"
|
||||
#else
|
||||
#if defined(FRAMEWORK_ARDUINO_SOLO1)
|
||||
#define GITHUB_LATEST_RELEASE_BINARY_URL "https://github.com/technyon/nuki_hub/raw/master/ota/nuki_hub_esp32solo1.bin"
|
||||
#else
|
||||
#define GITHUB_LATEST_RELEASE_BINARY_URL "https://github.com/technyon/nuki_hub/raw/master/ota/nuki_hub_esp32.bin"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#define MQTT_QOS_LEVEL 1
|
||||
#define MQTT_CLEAN_SESSIONS false
|
||||
|
||||
@@ -20,6 +20,10 @@
|
||||
#define mqtt_topic_lock_address "/lock/address"
|
||||
#define mqtt_topic_lock_retry "/lock/retry"
|
||||
|
||||
#define mqtt_topic_config_action "/configuration/action"
|
||||
#define mqtt_topic_config_action_command_result "/configuration/commandResult"
|
||||
#define mqtt_topic_config_basic_json "/configuration/basicJson"
|
||||
#define mqtt_topic_config_advanced_json "/configuration/advancedJson"
|
||||
#define mqtt_topic_config_button_enabled "/configuration/buttonEnabled"
|
||||
#define mqtt_topic_config_led_enabled "/configuration/ledEnabled"
|
||||
#define mqtt_topic_config_led_brightness "/configuration/ledBrightness"
|
||||
|
||||
3095
src/Network.cpp
3095
src/Network.cpp
File diff suppressed because it is too large
Load Diff
@@ -10,6 +10,7 @@
|
||||
#include "Gpio.h"
|
||||
#include <ArduinoJson.h>
|
||||
#include <HTTPClient.h>
|
||||
#include "NukiConstants.h"
|
||||
|
||||
enum class NetworkDeviceType
|
||||
{
|
||||
@@ -46,19 +47,17 @@ public:
|
||||
bool publishString(const char* prefix, const char* topic, const char* value);
|
||||
|
||||
void publishHASSConfig(char* deviceType, const char* baseTopic, char* name, char* uidString, const char* availabilityTopic, const bool& hasKeypad, char* lockAction, char* unlockAction, char* openAction);
|
||||
void publishHASSConfigAdditionalButtons(char* deviceType, const char* baseTopic, char* name, char* uidString);
|
||||
void publishHASSConfigBatLevel(char* deviceType, const char* baseTopic, char* name, char* uidString);
|
||||
void publishHASSConfigAdditionalLockEntities(char* deviceType, const char* baseTopic, char* name, char* uidString);
|
||||
void publishHASSConfigDoorSensor(char* deviceType, const char* baseTopic, char* name, char* uidString);
|
||||
void publishHASSConfigRingDetect(char* deviceType, const char* baseTopic, char* name, char* uidString);
|
||||
void publishHASSConfigContinuousMode(char* deviceType, const char* baseTopic, char* name, char* uidString);
|
||||
void publishHASSConfigLedBrightness(char* deviceType, const char* baseTopic, char* name, char* uidString);
|
||||
void publishHASSConfigSoundLevel(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 publishHASSConfigKeypadAttemptInfo(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 publishHASSBleRssiConfig(char* deviceType, const char* baseTopic, char* name, char* uidString);
|
||||
void removeHASSConfig(char* uidString);
|
||||
void removeHASSConfigTopic(char* deviceType, char* name, char* uidString);
|
||||
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 clearWifiFallback();
|
||||
|
||||
|
||||
@@ -13,15 +13,8 @@ NetworkLock::NetworkLock(Network* network, Preferences* preferences, char* buffe
|
||||
_buffer(buffer),
|
||||
_bufferSize(bufferSize)
|
||||
{
|
||||
_configTopics.reserve(5);
|
||||
_configTopics.push_back(mqtt_topic_config_button_enabled);
|
||||
_configTopics.push_back(mqtt_topic_config_led_enabled);
|
||||
_configTopics.push_back(mqtt_topic_config_led_brightness);
|
||||
_configTopics.push_back(mqtt_topic_config_auto_unlock);
|
||||
_configTopics.push_back(mqtt_topic_config_auto_lock);
|
||||
_configTopics.push_back(mqtt_topic_config_single_lock);
|
||||
|
||||
memset(authName, 0, sizeof(authName));
|
||||
memset(_authName, 0, sizeof(_authName));
|
||||
_authName[0] = '\0';
|
||||
|
||||
_network->registerMqttReceiver(this);
|
||||
}
|
||||
@@ -53,10 +46,9 @@ void NetworkLock::initialize()
|
||||
|
||||
_network->initTopic(_mqttPath, mqtt_topic_lock_action, "--");
|
||||
_network->subscribe(_mqttPath, mqtt_topic_lock_action);
|
||||
for(const auto& topic : _configTopics)
|
||||
{
|
||||
_network->subscribe(_mqttPath, topic);
|
||||
}
|
||||
|
||||
_network->initTopic(_mqttPath, mqtt_topic_config_action, "--");
|
||||
_network->subscribe(_mqttPath, mqtt_topic_config_action);
|
||||
|
||||
_network->subscribe(_mqttPath, mqtt_topic_reset);
|
||||
_network->initTopic(_mqttPath, mqtt_topic_reset, "0");
|
||||
@@ -204,15 +196,16 @@ void NetworkLock::onMqttDataReceived(const char* topic, byte* payload, const uns
|
||||
publishString(mqtt_topic_query_battery, "0");
|
||||
}
|
||||
|
||||
for(auto configTopic : _configTopics)
|
||||
if(comparePrefixedPath(topic, mqtt_topic_config_action))
|
||||
{
|
||||
if(comparePrefixedPath(topic, configTopic))
|
||||
if(strcmp(value, "") == 0 || strcmp(value, "--") == 0) return;
|
||||
|
||||
if(_configUpdateReceivedCallback != NULL)
|
||||
{
|
||||
if(_configUpdateReceivedCallback != nullptr)
|
||||
{
|
||||
_configUpdateReceivedCallback(configTopic, value);
|
||||
}
|
||||
_configUpdateReceivedCallback(value);
|
||||
}
|
||||
|
||||
publishString(mqtt_topic_config_action, "--");
|
||||
}
|
||||
|
||||
if(comparePrefixedPath(topic, mqtt_topic_keypad_json_action))
|
||||
@@ -226,7 +219,7 @@ void NetworkLock::onMqttDataReceived(const char* topic, byte* payload, const uns
|
||||
|
||||
publishString(mqtt_topic_keypad_json_action, "--");
|
||||
}
|
||||
|
||||
|
||||
if(comparePrefixedPath(topic, mqtt_topic_timecontrol_action))
|
||||
{
|
||||
if(strcmp(value, "") == 0 || strcmp(value, "--") == 0) return;
|
||||
@@ -316,7 +309,7 @@ void NetworkLock::publishKeyTurnerState(const NukiLock::KeyTurnerState& keyTurne
|
||||
|
||||
if(_firstTunerStatePublish || keyTurnerState.accessoryBatteryState != lastKeyTurnerState.accessoryBatteryState)
|
||||
{
|
||||
if ((keyTurnerState.accessoryBatteryState & (1 << 7)) != 0) {
|
||||
if((keyTurnerState.accessoryBatteryState & (1 << 7)) != 0) {
|
||||
publishBool(mqtt_topic_battery_keypad_critical, (keyTurnerState.accessoryBatteryState & (1 << 6)) != 0);
|
||||
}
|
||||
else
|
||||
@@ -325,8 +318,8 @@ void NetworkLock::publishKeyTurnerState(const NukiLock::KeyTurnerState& keyTurne
|
||||
}
|
||||
}
|
||||
|
||||
json["auth_id"] = authId;
|
||||
json["auth_name"] = authName;
|
||||
json["auth_id"] = _authId;
|
||||
json["auth_name"] = _authName;
|
||||
|
||||
serializeJson(json, _buffer, _bufferSize);
|
||||
publishString(mqtt_topic_lock_json, _buffer);
|
||||
@@ -372,8 +365,10 @@ void NetworkLock::publishAuthorizationInfo(const std::list<NukiLock::LogEntry>&
|
||||
{
|
||||
char str[50];
|
||||
|
||||
bool authFound = false;
|
||||
memset(authName, 0, sizeof(authName));
|
||||
_authId = 0;
|
||||
memset(_authName, 0, sizeof(_authName));
|
||||
_authName[0] = '\0';
|
||||
_authFound = false;
|
||||
|
||||
JsonDocument json;
|
||||
|
||||
@@ -385,18 +380,20 @@ void NetworkLock::publishAuthorizationInfo(const std::list<NukiLock::LogEntry>&
|
||||
break;
|
||||
}
|
||||
--i;
|
||||
if((log.loggingType == NukiLock::LoggingType::LockAction || log.loggingType == NukiLock::LoggingType::KeypadAction) && ! authFound)
|
||||
if((log.loggingType == NukiLock::LoggingType::LockAction || log.loggingType == NukiLock::LoggingType::KeypadAction) && ! _authFound)
|
||||
{
|
||||
authFound = true;
|
||||
authId = log.authId;
|
||||
memcpy(authName, log.name, sizeof(log.name));
|
||||
_authFound = true;
|
||||
_authId = log.authId;
|
||||
int sizeName = sizeof(log.name);
|
||||
memcpy(_authName, log.name, sizeName);
|
||||
if(_authName[sizeName - 1] != '\0') _authName[sizeName] = '\0';
|
||||
}
|
||||
|
||||
auto entry = json.add();
|
||||
auto entry = json.add<JsonVariant>();
|
||||
|
||||
entry["index"] = log.index;
|
||||
entry["authorizationId"] = log.authId;
|
||||
entry["authorizationName"] = log.name;
|
||||
entry["authorizationName"] = _authName;
|
||||
entry["timeYear"] = log.timeStampYear;
|
||||
entry["timeMonth"] = log.timeStampMonth;
|
||||
entry["timeDay"] = log.timeStampDay;
|
||||
@@ -462,10 +459,10 @@ void NetworkLock::publishAuthorizationInfo(const std::list<NukiLock::LogEntry>&
|
||||
serializeJson(json, _buffer, _bufferSize);
|
||||
publishString(mqtt_topic_lock_log, _buffer);
|
||||
|
||||
if(authFound)
|
||||
if(_authFound)
|
||||
{
|
||||
publishUInt(mqtt_topic_lock_auth_id, authId);
|
||||
publishString(mqtt_topic_lock_auth_name, authName);
|
||||
publishUInt(mqtt_topic_lock_auth_id, _authId);
|
||||
publishString(mqtt_topic_lock_auth_name, _authName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -495,6 +492,54 @@ void NetworkLock::publishBatteryReport(const NukiLock::BatteryReport& batteryRep
|
||||
|
||||
void NetworkLock::publishConfig(const NukiLock::Config &config)
|
||||
{
|
||||
char str[50];
|
||||
char curTime[20];
|
||||
sprintf(curTime, "%04d-%02d-%02d %02d:%02d:%02d", config.currentTimeYear, config.currentTimeMonth, config.currentTimeDay, config.currentTimeHour, config.currentTimeMinute, config.currentTimeSecond);
|
||||
char uidString[20];
|
||||
itoa(config.nukiId, uidString, 16);
|
||||
|
||||
JsonDocument json;
|
||||
|
||||
json["nukiID"] = uidString;
|
||||
json["name"] = config.name;
|
||||
//json["latitude"] = config.latitude;
|
||||
//json["longitude"] = config.longitude;
|
||||
json["autoUnlatch"] = config.autoUnlatch;
|
||||
json["pairingEnabled"] = config.pairingEnabled;
|
||||
json["buttonEnabled"] = config.buttonEnabled;
|
||||
json["ledEnabled"] = config.ledEnabled;
|
||||
json["ledBrightness"] = config.ledBrightness;
|
||||
json["currentTime"] = curTime;
|
||||
json["timeZoneOffset"] = config.timeZoneOffset;
|
||||
json["dstMode"] = config.dstMode;
|
||||
json["hasFob"] = config.hasFob;
|
||||
memset(str, 0, sizeof(str));
|
||||
fobActionToString(config.fobAction1, str);
|
||||
json["fobAction1"] = str;
|
||||
memset(str, 0, sizeof(str));
|
||||
fobActionToString(config.fobAction2, str);
|
||||
json["fobAction2"] = str;
|
||||
memset(str, 0, sizeof(str));
|
||||
fobActionToString(config.fobAction3, str);
|
||||
json["fobAction3"] = str;
|
||||
json["singleLock"] = config.singleLock;
|
||||
memset(str, 0, sizeof(str));
|
||||
_network->advertisingModeToString(config.advertisingMode, str);
|
||||
json["advertisingMode"] = str;
|
||||
json["hasKeypad"] = config.hasKeypad;
|
||||
json["hasKeypadV2"] = config.hasKeypadV2;
|
||||
json["firmwareVersion"] = std::to_string(config.firmwareVersion[0]) + "." + std::to_string(config.firmwareVersion[1]) + "." + std::to_string(config.firmwareVersion[2]);
|
||||
json["hardwareRevision"] = std::to_string(config.hardwareRevision[0]) + "." + std::to_string(config.hardwareRevision[1]);
|
||||
memset(str, 0, sizeof(str));
|
||||
homeKitStatusToString(config.homeKitStatus, str);
|
||||
json["homeKitStatus"] = str;
|
||||
memset(str, 0, sizeof(str));
|
||||
_network->timeZoneIdToString(config.timeZoneId, str);
|
||||
json["timeZone"] = str;
|
||||
|
||||
serializeJson(json, _buffer, _bufferSize);
|
||||
publishString(mqtt_topic_config_basic_json, _buffer);
|
||||
|
||||
publishBool(mqtt_topic_config_button_enabled, config.buttonEnabled == 1);
|
||||
publishBool(mqtt_topic_config_led_enabled, config.ledEnabled == 1);
|
||||
publishInt(mqtt_topic_config_led_brightness, config.ledBrightness);
|
||||
@@ -505,6 +550,47 @@ void NetworkLock::publishConfig(const NukiLock::Config &config)
|
||||
|
||||
void NetworkLock::publishAdvancedConfig(const NukiLock::AdvancedConfig &config)
|
||||
{
|
||||
char str[50];
|
||||
char nmst[6];
|
||||
sprintf(nmst, "%02d:%02d", config.nightModeStartTime[0], config.nightModeStartTime[1]);
|
||||
char nmet[6];
|
||||
sprintf(nmet, "%02d:%02d", config.nightModeEndTime[0], config.nightModeEndTime[1]);
|
||||
|
||||
JsonDocument json;
|
||||
|
||||
json["totalDegrees"] = config.totalDegrees;
|
||||
json["unlockedPositionOffsetDegrees"] = config.unlockedPositionOffsetDegrees;
|
||||
json["lockedPositionOffsetDegrees"] = config.lockedPositionOffsetDegrees;
|
||||
json["singleLockedPositionOffsetDegrees"] = config.singleLockedPositionOffsetDegrees;
|
||||
json["unlockedToLockedTransitionOffsetDegrees"] = config.unlockedToLockedTransitionOffsetDegrees;
|
||||
json["lockNgoTimeout"] = config.lockNgoTimeout;
|
||||
memset(str, 0, sizeof(str));
|
||||
buttonPressActionToString(config.singleButtonPressAction, str);
|
||||
json["singleButtonPressAction"] = str;
|
||||
memset(str, 0, sizeof(str));
|
||||
buttonPressActionToString(config.doubleButtonPressAction, str);
|
||||
json["doubleButtonPressAction"] = str;
|
||||
json["detachedCylinder"] = config.detachedCylinder;
|
||||
memset(str, 0, sizeof(str));
|
||||
_network->batteryTypeToString(config.batteryType, str);
|
||||
json["batteryType"] = str;
|
||||
json["automaticBatteryTypeDetection"] = config.automaticBatteryTypeDetection;
|
||||
json["unlatchDuration"] = config.unlatchDuration;
|
||||
json["autoLockTimeOut"] = config.autoLockTimeOut;
|
||||
json["autoUnLockDisabled"] = config.autoUnLockDisabled;
|
||||
json["nightModeEnabled"] = config.nightModeEnabled;
|
||||
json["nightModeStartTime"] = nmst;
|
||||
json["nightModeEndTime"] = nmet;
|
||||
json["nightModeAutoLockEnabled"] = config.nightModeAutoLockEnabled;
|
||||
json["nightModeAutoUnlockDisabled"] = config.nightModeAutoUnlockDisabled;
|
||||
json["nightModeImmediateLockOnStart"] = config.nightModeImmediateLockOnStart;
|
||||
json["autoLockEnabled"] = config.autoLockEnabled;
|
||||
json["immediateAutoLockEnabled"] = config.immediateAutoLockEnabled;
|
||||
json["autoUpdateEnabled"] = config.autoUpdateEnabled;
|
||||
|
||||
serializeJson(json, _buffer, _bufferSize);
|
||||
publishString(mqtt_topic_config_advanced_json, _buffer);
|
||||
|
||||
publishBool(mqtt_topic_config_auto_unlock, config.autoUnLockDisabled == 0);
|
||||
publishBool(mqtt_topic_config_auto_lock, config.autoLockEnabled == 1);
|
||||
}
|
||||
@@ -537,7 +623,7 @@ void NetworkLock::publishKeypad(const std::list<NukiLock::KeypadEntry>& entries,
|
||||
basePath.concat(std::to_string(index).c_str());
|
||||
publishKeypadEntry(basePath, entry);
|
||||
|
||||
auto jsonEntry = json.add();
|
||||
auto jsonEntry = json.add<JsonVariant>();
|
||||
|
||||
jsonEntry["codeId"] = entry.codeId;
|
||||
jsonEntry["enabled"] = entry.enabled;
|
||||
@@ -638,7 +724,7 @@ void NetworkLock::publishTimeControl(const std::list<NukiLock::TimeControlEntry>
|
||||
|
||||
for(const auto& entry : timeControlEntries)
|
||||
{
|
||||
auto jsonEntry = json.add();
|
||||
auto jsonEntry = json.add<JsonVariant>();
|
||||
|
||||
jsonEntry["entryId"] = entry.entryId;
|
||||
jsonEntry["enabled"] = entry.enabled;
|
||||
@@ -703,6 +789,11 @@ void NetworkLock::publishTimeControl(const std::list<NukiLock::TimeControlEntry>
|
||||
publishString(mqtt_topic_timecontrol_json, _buffer);
|
||||
}
|
||||
|
||||
void NetworkLock::publishConfigCommandResult(const char* result)
|
||||
{
|
||||
publishString(mqtt_topic_config_action_command_result, result);
|
||||
}
|
||||
|
||||
void NetworkLock::publishKeypadCommandResult(const char* result)
|
||||
{
|
||||
publishString(mqtt_topic_keypad_command_result, result);
|
||||
@@ -723,7 +814,7 @@ void NetworkLock::setLockActionReceivedCallback(LockActionResult (*lockActionRec
|
||||
_lockActionReceivedCallback = lockActionReceivedCallback;
|
||||
}
|
||||
|
||||
void NetworkLock::setConfigUpdateReceivedCallback(void (*configUpdateReceivedCallback)(const char *, const char *))
|
||||
void NetworkLock::setConfigUpdateReceivedCallback(void (*configUpdateReceivedCallback)(const char *))
|
||||
{
|
||||
_configUpdateReceivedCallback = configUpdateReceivedCallback;
|
||||
}
|
||||
@@ -776,19 +867,16 @@ void NetworkLock::publishHASSConfig(char *deviceType, const char *baseTopic, cha
|
||||
char *unlockAction, char *openAction)
|
||||
{
|
||||
_network->publishHASSConfig(deviceType, baseTopic, name, uidString, "~/maintenance/mqttConnectionState", hasKeypad, lockAction, unlockAction, openAction);
|
||||
_network->publishHASSConfigAdditionalButtons(deviceType, baseTopic, name, uidString);
|
||||
_network->publishHASSConfigBatLevel(deviceType, baseTopic, name, uidString);
|
||||
_network->publishHASSConfigLedBrightness(deviceType, baseTopic, name, uidString);
|
||||
_network->publishHASSConfigAdditionalLockEntities(deviceType, baseTopic, name, uidString);
|
||||
if(hasDoorSensor)
|
||||
{
|
||||
_network->publishHASSConfigDoorSensor(deviceType, baseTopic, name, uidString);
|
||||
}
|
||||
else
|
||||
{
|
||||
_network->removeHASSConfigTopic("binary_sensor", "door_sensor", uidString);
|
||||
_network->removeHASSConfigTopic((char*)"binary_sensor", (char*)"door_sensor", uidString);
|
||||
}
|
||||
_network->publishHASSWifiRssiConfig(deviceType, baseTopic, name, uidString);
|
||||
_network->publishHASSBleRssiConfig(deviceType, baseTopic, name, uidString);
|
||||
|
||||
if(publishAuthData)
|
||||
{
|
||||
@@ -796,16 +884,17 @@ void NetworkLock::publishHASSConfig(char *deviceType, const char *baseTopic, cha
|
||||
}
|
||||
else
|
||||
{
|
||||
_network->removeHASSConfigTopic("sensor", "last_action_authorization", uidString);
|
||||
_network->removeHASSConfigTopic((char*)"sensor", (char*)"last_action_authorization", uidString);
|
||||
}
|
||||
|
||||
if(hasKeypad)
|
||||
{
|
||||
_network->publishHASSConfigKeypadAttemptInfo(deviceType, baseTopic, name, uidString);
|
||||
_network->publishHASSConfigKeypad(deviceType, baseTopic, name, uidString);
|
||||
}
|
||||
else
|
||||
{
|
||||
_network->removeHASSConfigTopic("sensor", "keypad_status", uidString);
|
||||
_network->removeHASSConfigTopic((char*)"sensor", (char*)"keypad_status", uidString);
|
||||
_network->removeHASSConfigTopic((char*)"binary_sensor", (char*)"keypad_battery_low", uidString);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -898,3 +987,75 @@ uint8_t NetworkLock::queryCommands()
|
||||
_queryCommands = 0;
|
||||
return qc;
|
||||
}
|
||||
|
||||
void NetworkLock::buttonPressActionToString(const NukiLock::ButtonPressAction btnPressAction, char* str) {
|
||||
switch (btnPressAction) {
|
||||
case NukiLock::ButtonPressAction::NoAction:
|
||||
strcpy(str, "No Action");
|
||||
break;
|
||||
case NukiLock::ButtonPressAction::Intelligent:
|
||||
strcpy(str, "Intelligent");
|
||||
break;
|
||||
case NukiLock::ButtonPressAction::Unlock:
|
||||
strcpy(str, "Unlock");
|
||||
break;
|
||||
case NukiLock::ButtonPressAction::Lock:
|
||||
strcpy(str, "Lock");
|
||||
break;
|
||||
case NukiLock::ButtonPressAction::Unlatch:
|
||||
strcpy(str, "Unlatch");
|
||||
break;
|
||||
case NukiLock::ButtonPressAction::LockNgo:
|
||||
strcpy(str, "Lock n Go");
|
||||
break;
|
||||
case NukiLock::ButtonPressAction::ShowStatus:
|
||||
strcpy(str, "Show Status");
|
||||
break;
|
||||
default:
|
||||
strcpy(str, "undefined");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void NetworkLock::homeKitStatusToString(const int hkstatus, char* str) {
|
||||
switch (hkstatus) {
|
||||
case 0:
|
||||
strcpy(str, "Not Available");
|
||||
break;
|
||||
case 1:
|
||||
strcpy(str, "Disabled");
|
||||
break;
|
||||
case 2:
|
||||
strcpy(str, "Enabled");
|
||||
break;
|
||||
case 3:
|
||||
strcpy(str, "Enabled & Paired");
|
||||
break;
|
||||
default:
|
||||
strcpy(str, "undefined");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void NetworkLock::fobActionToString(const int fobact, char* str) {
|
||||
switch (fobact) {
|
||||
case 0:
|
||||
strcpy(str, "No Action");
|
||||
break;
|
||||
case 1:
|
||||
strcpy(str, "Unlock");
|
||||
break;
|
||||
case 2:
|
||||
strcpy(str, "Lock");
|
||||
break;
|
||||
case 3:
|
||||
strcpy(str, "Lock n Go");
|
||||
break;
|
||||
case 4:
|
||||
strcpy(str, "Intelligent");
|
||||
break;
|
||||
default:
|
||||
strcpy(str, "undefined");
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -38,12 +38,13 @@ public:
|
||||
void removeHASSConfig(char* uidString);
|
||||
void publishKeypad(const std::list<NukiLock::KeypadEntry>& entries, uint maxKeypadCodeCount);
|
||||
void publishTimeControl(const std::list<NukiLock::TimeControlEntry>& timeControlEntries);
|
||||
void publishConfigCommandResult(const char* result);
|
||||
void publishKeypadCommandResult(const char* result);
|
||||
void publishKeypadJsonCommandResult(const char* result);
|
||||
void publishTimeControlCommandResult(const char* result);
|
||||
|
||||
void setLockActionReceivedCallback(LockActionResult (*lockActionReceivedCallback)(const char* value));
|
||||
void setConfigUpdateReceivedCallback(void (*configUpdateReceivedCallback)(const char* path, const char* value));
|
||||
void setConfigUpdateReceivedCallback(void (*configUpdateReceivedCallback)(const char* value));
|
||||
void setKeypadCommandReceivedCallback(void (*keypadCommandReceivedReceivedCallback)(const char* command, const uint& id, const String& name, const String& code, const int& enabled));
|
||||
void setKeypadJsonCommandReceivedCallback(void (*keypadJsonCommandReceivedReceivedCallback)(const char* value));
|
||||
void setTimeControlCommandReceivedCallback(void (*timeControlCommandReceivedReceivedCallback)(const char* value));
|
||||
@@ -64,6 +65,9 @@ private:
|
||||
bool publishString(const char* topic, const std::string& value);
|
||||
bool publishString(const char* topic, const char* value);
|
||||
void publishKeypadEntry(const String topic, NukiLock::KeypadEntry entry);
|
||||
void buttonPressActionToString(const NukiLock::ButtonPressAction btnPressAction, char* str);
|
||||
void homeKitStatusToString(const int hkstatus, char* str);
|
||||
void fobActionToString(const int fobact, char* str);
|
||||
|
||||
String concat(String a, String b);
|
||||
|
||||
@@ -72,7 +76,6 @@ private:
|
||||
Network* _network;
|
||||
Preferences* _preferences;
|
||||
|
||||
std::vector<char*> _configTopics;
|
||||
char _mqttPath[181] = {0};
|
||||
|
||||
bool _firstTunerStatePublish = true;
|
||||
@@ -84,15 +87,16 @@ private:
|
||||
String _keypadCommandCode = "";
|
||||
uint _keypadCommandId = 0;
|
||||
int _keypadCommandEnabled = 1;
|
||||
uint8_t _queryCommands = 0;
|
||||
uint32_t authId = 0;
|
||||
char authName[33];
|
||||
uint8_t _queryCommands = 0;
|
||||
uint32_t _authId = 0;
|
||||
char _authName[33];
|
||||
bool _authFound = false;
|
||||
|
||||
char* _buffer;
|
||||
size_t _bufferSize;
|
||||
|
||||
LockActionResult (*_lockActionReceivedCallback)(const char* value) = nullptr;
|
||||
void (*_configUpdateReceivedCallback)(const char* path, const char* value) = nullptr;
|
||||
void (*_configUpdateReceivedCallback)(const char* value) = nullptr;
|
||||
void (*_keypadCommandReceivedReceivedCallback)(const char* command, const uint& id, const String& name, const String& code, const int& enabled) = nullptr;
|
||||
void (*_keypadJsonCommandReceivedReceivedCallback)(const char* value) = nullptr;
|
||||
void (*_timeControlCommandReceivedReceivedCallback)(const char* value) = nullptr;
|
||||
|
||||
@@ -12,12 +12,8 @@ NetworkOpener::NetworkOpener(Network* network, Preferences* preferences, char* b
|
||||
_buffer(buffer),
|
||||
_bufferSize(bufferSize)
|
||||
{
|
||||
_configTopics.reserve(5);
|
||||
_configTopics.push_back(mqtt_topic_config_button_enabled);
|
||||
_configTopics.push_back(mqtt_topic_config_led_enabled);
|
||||
_configTopics.push_back(mqtt_topic_config_sound_level);
|
||||
|
||||
memset(authName, 0, sizeof(authName));
|
||||
memset(_authName, 0, sizeof(_authName));
|
||||
_authName[0] = '\0';
|
||||
|
||||
_network->registerMqttReceiver(this);
|
||||
}
|
||||
@@ -43,10 +39,9 @@ void NetworkOpener::initialize()
|
||||
|
||||
_network->initTopic(_mqttPath, mqtt_topic_lock_action, "--");
|
||||
_network->subscribe(_mqttPath, mqtt_topic_lock_action);
|
||||
for(const auto& topic : _configTopics)
|
||||
{
|
||||
_network->subscribe(_mqttPath, topic);
|
||||
}
|
||||
|
||||
_network->initTopic(_mqttPath, mqtt_topic_config_action, "--");
|
||||
_network->subscribe(_mqttPath, mqtt_topic_config_action);
|
||||
|
||||
_network->initTopic(_mqttPath, mqtt_topic_query_config, "0");
|
||||
_network->initTopic(_mqttPath, mqtt_topic_query_lockstate, "0");
|
||||
@@ -193,15 +188,16 @@ void NetworkOpener::onMqttDataReceived(const char* topic, byte* payload, const u
|
||||
publishString(mqtt_topic_query_battery, "0");
|
||||
}
|
||||
|
||||
for(auto configTopic : _configTopics)
|
||||
if(comparePrefixedPath(topic, mqtt_topic_config_action))
|
||||
{
|
||||
if(comparePrefixedPath(topic, configTopic))
|
||||
if(strcmp(value, "") == 0 || strcmp(value, "--") == 0) return;
|
||||
|
||||
if(_configUpdateReceivedCallback != NULL)
|
||||
{
|
||||
if(_configUpdateReceivedCallback != nullptr)
|
||||
{
|
||||
_configUpdateReceivedCallback(configTopic, value);
|
||||
}
|
||||
_configUpdateReceivedCallback(value);
|
||||
}
|
||||
|
||||
publishString(mqtt_topic_config_action, "--");
|
||||
}
|
||||
|
||||
if(comparePrefixedPath(topic, mqtt_topic_keypad_json_action))
|
||||
@@ -297,8 +293,8 @@ void NetworkOpener::publishKeyTurnerState(const NukiOpener::OpenerState& keyTurn
|
||||
publishBool(mqtt_topic_battery_critical, critical);
|
||||
}
|
||||
|
||||
json["auth_id"] = authId;
|
||||
json["auth_name"] = authName;
|
||||
json["auth_id"] = _authId;
|
||||
json["auth_name"] = _authName;
|
||||
|
||||
serializeJson(json, _buffer, _bufferSize);
|
||||
publishString(mqtt_topic_lock_json, _buffer);
|
||||
@@ -308,7 +304,7 @@ void NetworkOpener::publishKeyTurnerState(const NukiOpener::OpenerState& keyTurn
|
||||
|
||||
void NetworkOpener::publishRing(const bool locked)
|
||||
{
|
||||
if (locked)
|
||||
if(locked)
|
||||
{
|
||||
publishString(mqtt_topic_lock_ring, "ringlocked");
|
||||
}
|
||||
@@ -359,8 +355,10 @@ void NetworkOpener::publishAuthorizationInfo(const std::list<NukiOpener::LogEntr
|
||||
{
|
||||
char str[50];
|
||||
|
||||
bool authFound = false;
|
||||
memset(authName, 0, sizeof(authName));
|
||||
_authId = 0;
|
||||
memset(_authName, 0, sizeof(_authName));
|
||||
_authName[0] = '\0';
|
||||
_authFound = false;
|
||||
|
||||
JsonDocument json;
|
||||
|
||||
@@ -373,18 +371,20 @@ void NetworkOpener::publishAuthorizationInfo(const std::list<NukiOpener::LogEntr
|
||||
}
|
||||
--i;
|
||||
|
||||
if((log.loggingType == NukiOpener::LoggingType::LockAction || log.loggingType == NukiOpener::LoggingType::KeypadAction) && ! authFound)
|
||||
if((log.loggingType == NukiOpener::LoggingType::LockAction || log.loggingType == NukiOpener::LoggingType::KeypadAction) && ! _authFound)
|
||||
{
|
||||
authFound = true;
|
||||
authId = log.authId;
|
||||
memcpy(authName, log.name, sizeof(log.name));
|
||||
_authFound = true;
|
||||
_authId = log.authId;
|
||||
int sizeName = sizeof(log.name);
|
||||
memcpy(_authName, log.name, sizeName);
|
||||
if(_authName[sizeName - 1] != '\0') _authName[sizeName] = '\0';
|
||||
}
|
||||
|
||||
auto entry = json.add();
|
||||
auto entry = json.add<JsonVariant>();
|
||||
|
||||
entry["index"] = log.index;
|
||||
entry["authorizationId"] = log.authId;
|
||||
entry["authorizationName"] = log.name;
|
||||
entry["authorizationName"] = _authName;
|
||||
entry["timeYear"] = log.timeStampYear;
|
||||
entry["timeMonth"] = log.timeStampMonth;
|
||||
entry["timeDay"] = log.timeStampDay;
|
||||
@@ -475,10 +475,10 @@ void NetworkOpener::publishAuthorizationInfo(const std::list<NukiOpener::LogEntr
|
||||
serializeJson(json, _buffer, _bufferSize);
|
||||
publishString(mqtt_topic_lock_log, _buffer);
|
||||
|
||||
if(authFound)
|
||||
if(_authFound)
|
||||
{
|
||||
publishUInt(mqtt_topic_lock_auth_id, authId);
|
||||
publishString(mqtt_topic_lock_auth_name, authName);
|
||||
publishUInt(mqtt_topic_lock_auth_id, _authId);
|
||||
publishString(mqtt_topic_lock_auth_name, _authName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -537,6 +537,54 @@ void NetworkOpener::publishBatteryReport(const NukiOpener::BatteryReport& batter
|
||||
|
||||
void NetworkOpener::publishConfig(const NukiOpener::Config &config)
|
||||
{
|
||||
char str[50];
|
||||
char curTime[20];
|
||||
sprintf(curTime, "%04d-%02d-%02d %02d:%02d:%02d", config.currentTimeYear, config.currentTimeMonth, config.currentTimeDay, config.currentTimeHour, config.currentTimeMinute, config.currentTimeSecond);
|
||||
char uidString[20];
|
||||
itoa(config.nukiId, uidString, 16);
|
||||
|
||||
JsonDocument json;
|
||||
|
||||
json["nukiID"] = uidString;
|
||||
json["name"] = config.name;
|
||||
//json["latitude"] = config.latitude;
|
||||
//json["longitude"] = config.longitude;
|
||||
memset(str, 0, sizeof(str));
|
||||
capabilitiesToString(config.capabilities, str);
|
||||
json["capabilities"] = str;
|
||||
json["pairingEnabled"] = config.pairingEnabled;
|
||||
json["buttonEnabled"] = config.buttonEnabled;
|
||||
json["ledFlashEnabled"] = config.ledFlashEnabled;
|
||||
json["currentTime"] = curTime;
|
||||
json["timeZoneOffset"] = config.timeZoneOffset;
|
||||
json["dstMode"] = config.dstMode;
|
||||
json["hasFob"] = config.hasFob;
|
||||
memset(str, 0, sizeof(str));
|
||||
fobActionToString(config.fobAction1, str);
|
||||
json["fobAction1"] = str;
|
||||
memset(str, 0, sizeof(str));
|
||||
fobActionToString(config.fobAction2, str);
|
||||
json["fobAction2"] = str;
|
||||
memset(str, 0, sizeof(str));
|
||||
fobActionToString(config.fobAction3, str);
|
||||
json["fobAction3"] = str;
|
||||
memset(str, 0, sizeof(str));
|
||||
operatingModeToString(config.operatingMode, str);
|
||||
json["operatingMode"] = str;
|
||||
memset(str, 0, sizeof(str));
|
||||
_network->advertisingModeToString(config.advertisingMode, str);
|
||||
json["advertisingMode"] = str;
|
||||
json["hasKeypad"] = config.hasKeypad;
|
||||
json["hasKeypadV2"] = config.hasKeypadV2;
|
||||
json["firmwareVersion"] = std::to_string(config.firmwareVersion[0]) + "." + std::to_string(config.firmwareVersion[1]) + "." + std::to_string(config.firmwareVersion[2]);
|
||||
json["hardwareRevision"] = std::to_string(config.hardwareRevision[0]) + "." + std::to_string(config.hardwareRevision[1]);
|
||||
memset(str, 0, sizeof(str));
|
||||
_network->timeZoneIdToString(config.timeZoneId, str);
|
||||
json["timeZone"] = str;
|
||||
|
||||
serializeJson(json, _buffer, _bufferSize);
|
||||
publishString(mqtt_topic_config_basic_json, _buffer);
|
||||
|
||||
publishBool(mqtt_topic_config_button_enabled, config.buttonEnabled == 1);
|
||||
publishBool(mqtt_topic_config_led_enabled, config.ledFlashEnabled == 1);
|
||||
publishString(mqtt_topic_info_firmware_version, std::to_string(config.firmwareVersion[0]) + "." + std::to_string(config.firmwareVersion[1]) + "." + std::to_string(config.firmwareVersion[2]));
|
||||
@@ -545,6 +593,50 @@ void NetworkOpener::publishConfig(const NukiOpener::Config &config)
|
||||
|
||||
void NetworkOpener::publishAdvancedConfig(const NukiOpener::AdvancedConfig &config)
|
||||
{
|
||||
char str[50];
|
||||
|
||||
JsonDocument json;
|
||||
|
||||
json["intercomID"] = config.intercomID;
|
||||
json["busModeSwitch"] = config.busModeSwitch;
|
||||
json["shortCircuitDuration"] = config.shortCircuitDuration;
|
||||
json["electricStrikeDelay"] = config.electricStrikeDelay;
|
||||
json["randomElectricStrikeDelay"] = config.randomElectricStrikeDelay;
|
||||
json["electricStrikeDuration"] = config.electricStrikeDuration;
|
||||
json["disableRtoAfterRing"] = config.disableRtoAfterRing;
|
||||
json["rtoTimeout"] = config.rtoTimeout;
|
||||
memset(str, 0, sizeof(str));
|
||||
doorbellSuppressionToString(config.doorbellSuppression, str);
|
||||
json["doorbellSuppression"] = str;
|
||||
json["doorbellSuppressionDuration"] = config.doorbellSuppressionDuration;
|
||||
memset(str, 0, sizeof(str));
|
||||
soundToString(config.soundRing, str);
|
||||
json["soundRing"] = str;
|
||||
memset(str, 0, sizeof(str));
|
||||
soundToString(config.soundOpen, str);
|
||||
json["soundOpen"] = str;
|
||||
memset(str, 0, sizeof(str));
|
||||
soundToString(config.soundRto, str);
|
||||
json["soundRto"] = str;
|
||||
memset(str, 0, sizeof(str));
|
||||
soundToString(config.soundCm, str);
|
||||
json["soundCm"] = str;
|
||||
json["soundConfirmation"] = config.soundConfirmation;
|
||||
json["soundLevel"] = config.soundLevel;
|
||||
memset(str, 0, sizeof(str));
|
||||
buttonPressActionToString(config.singleButtonPressAction, str);
|
||||
json["singleButtonPressAction"] = str;
|
||||
memset(str, 0, sizeof(str));
|
||||
buttonPressActionToString(config.doubleButtonPressAction, str);
|
||||
json["doubleButtonPressAction"] = str;
|
||||
memset(str, 0, sizeof(str));
|
||||
_network->batteryTypeToString(config.batteryType, str);
|
||||
json["batteryType"] = str;
|
||||
json["automaticBatteryTypeDetection"] = config.automaticBatteryTypeDetection;
|
||||
|
||||
serializeJson(json, _buffer, _bufferSize);
|
||||
publishString(mqtt_topic_config_advanced_json, _buffer);
|
||||
|
||||
publishUInt(mqtt_topic_config_sound_level, config.soundLevel);
|
||||
}
|
||||
|
||||
@@ -569,10 +661,7 @@ void NetworkOpener::publishHASSConfig(char* deviceType, const char* baseTopic, c
|
||||
availabilityTopic.concat("/maintenance/mqttConnectionState");
|
||||
|
||||
_network->publishHASSConfig(deviceType, baseTopic, name, uidString, availabilityTopic.c_str(), false, lockAction, unlockAction, openAction);
|
||||
_network->publishHASSConfigRingDetect(deviceType, baseTopic, name, uidString);
|
||||
_network->publishHASSConfigContinuousMode(deviceType, baseTopic, name, uidString);
|
||||
_network->publishHASSConfigSoundLevel(deviceType, baseTopic, name, uidString);
|
||||
_network->publishHASSBleRssiConfig(deviceType, baseTopic, name, uidString);
|
||||
_network->publishHASSConfigAdditionalOpenerEntities(deviceType, baseTopic, name, uidString);
|
||||
}
|
||||
|
||||
void NetworkOpener::removeHASSConfig(char* uidString)
|
||||
@@ -593,7 +682,7 @@ void NetworkOpener::publishKeypad(const std::list<NukiLock::KeypadEntry>& entrie
|
||||
basePath.concat(std::to_string(index).c_str());
|
||||
publishKeypadEntry(basePath, entry);
|
||||
|
||||
auto jsonEntry = json.add();
|
||||
auto jsonEntry = json.add<JsonVariant>();
|
||||
|
||||
jsonEntry["codeId"] = entry.codeId;
|
||||
jsonEntry["enabled"] = entry.enabled;
|
||||
@@ -694,7 +783,7 @@ void NetworkOpener::publishTimeControl(const std::list<NukiOpener::TimeControlEn
|
||||
|
||||
for(const auto& entry : timeControlEntries)
|
||||
{
|
||||
auto jsonEntry = json.add();
|
||||
auto jsonEntry = json.add<JsonVariant>();
|
||||
|
||||
jsonEntry["entryId"] = entry.entryId;
|
||||
jsonEntry["enabled"] = entry.enabled;
|
||||
@@ -759,6 +848,11 @@ void NetworkOpener::publishTimeControl(const std::list<NukiOpener::TimeControlEn
|
||||
publishString(mqtt_topic_timecontrol_json, _buffer);
|
||||
}
|
||||
|
||||
void NetworkOpener::publishConfigCommandResult(const char* result)
|
||||
{
|
||||
publishString(mqtt_topic_config_action_command_result, result);
|
||||
}
|
||||
|
||||
void NetworkOpener::publishKeypadCommandResult(const char* result)
|
||||
{
|
||||
publishString(mqtt_topic_keypad_command_result, result);
|
||||
@@ -779,7 +873,7 @@ void NetworkOpener::setLockActionReceivedCallback(LockActionResult (*lockActionR
|
||||
_lockActionReceivedCallback = lockActionReceivedCallback;
|
||||
}
|
||||
|
||||
void NetworkOpener::setConfigUpdateReceivedCallback(void (*configUpdateReceivedCallback)(const char *, const char *))
|
||||
void NetworkOpener::setConfigUpdateReceivedCallback(void (*configUpdateReceivedCallback)(const char *))
|
||||
{
|
||||
_configUpdateReceivedCallback = configUpdateReceivedCallback;
|
||||
}
|
||||
@@ -915,3 +1009,186 @@ uint8_t NetworkOpener::queryCommands()
|
||||
_queryCommands = 0;
|
||||
return qc;
|
||||
}
|
||||
|
||||
void NetworkOpener::buttonPressActionToString(const NukiOpener::ButtonPressAction btnPressAction, char* str) {
|
||||
switch (btnPressAction) {
|
||||
case NukiOpener::ButtonPressAction::NoAction:
|
||||
strcpy(str, "No Action");
|
||||
break;
|
||||
case NukiOpener::ButtonPressAction::ToggleRTO:
|
||||
strcpy(str, "Toggle RTO");
|
||||
break;
|
||||
case NukiOpener::ButtonPressAction::ActivateRTO:
|
||||
strcpy(str, "Activate RTO");
|
||||
break;
|
||||
case NukiOpener::ButtonPressAction::DeactivateRTO:
|
||||
strcpy(str, "Deactivate RTO");
|
||||
break;
|
||||
case NukiOpener::ButtonPressAction::ToggleCM:
|
||||
strcpy(str, "Toggle CM");
|
||||
break;
|
||||
case NukiOpener::ButtonPressAction::ActivateCM:
|
||||
strcpy(str, "Activate CM");
|
||||
break;
|
||||
case NukiOpener::ButtonPressAction::DectivateCM:
|
||||
strcpy(str, "Deactivate CM");
|
||||
break;
|
||||
case NukiOpener::ButtonPressAction::Open:
|
||||
strcpy(str, "Open");
|
||||
break;
|
||||
default:
|
||||
strcpy(str, "undefined");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void NetworkOpener::fobActionToString(const int fobact, char* str) {
|
||||
switch (fobact) {
|
||||
case 0:
|
||||
strcpy(str, "No Action");
|
||||
break;
|
||||
case 1:
|
||||
strcpy(str, "Toggle RTO");
|
||||
break;
|
||||
case 2:
|
||||
strcpy(str, "Activate RTO");
|
||||
break;
|
||||
case 3:
|
||||
strcpy(str, "Deactivate RTO");
|
||||
break;
|
||||
case 7:
|
||||
strcpy(str, "Open");
|
||||
break;
|
||||
case 8:
|
||||
strcpy(str, "Ring");
|
||||
break;
|
||||
default:
|
||||
strcpy(str, "undefined");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void NetworkOpener::capabilitiesToString(const int capabilities, char* str) {
|
||||
switch (capabilities) {
|
||||
case 0:
|
||||
strcpy(str, "Door opener");
|
||||
break;
|
||||
case 1:
|
||||
strcpy(str, "Both");
|
||||
break;
|
||||
case 2:
|
||||
strcpy(str, "RTO");
|
||||
break;
|
||||
default:
|
||||
strcpy(str, "undefined");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void NetworkOpener::operatingModeToString(const int opmode, char* str) {
|
||||
switch (opmode) {
|
||||
case 0:
|
||||
strcpy(str, "Generic door opener");
|
||||
break;
|
||||
case 1:
|
||||
strcpy(str, "Analogue intercom");
|
||||
break;
|
||||
case 2:
|
||||
strcpy(str, "Digital intercom");
|
||||
break;
|
||||
case 3:
|
||||
strcpy(str, "Siedle");
|
||||
break;
|
||||
case 4:
|
||||
strcpy(str, "TCS");
|
||||
break;
|
||||
case 5:
|
||||
strcpy(str, "Bticino");
|
||||
break;
|
||||
case 6:
|
||||
strcpy(str, "Siedle HTS");
|
||||
break;
|
||||
case 7:
|
||||
strcpy(str, "STR");
|
||||
break;
|
||||
case 8:
|
||||
strcpy(str, "Ritto");
|
||||
break;
|
||||
case 9:
|
||||
strcpy(str, "Fermax");
|
||||
break;
|
||||
case 10:
|
||||
strcpy(str, "Comelit");
|
||||
break;
|
||||
case 11:
|
||||
strcpy(str, "Urmet BiBus");
|
||||
break;
|
||||
case 12:
|
||||
strcpy(str, "Urmet 2Voice");
|
||||
break;
|
||||
case 13:
|
||||
strcpy(str, "Golmar");
|
||||
break;
|
||||
case 14:
|
||||
strcpy(str, "SKS");
|
||||
break;
|
||||
case 15:
|
||||
strcpy(str, "Spare");
|
||||
break;
|
||||
default:
|
||||
strcpy(str, "undefined");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void NetworkOpener::doorbellSuppressionToString(const int dbsupr, char* str) {
|
||||
switch (dbsupr) {
|
||||
case 0:
|
||||
strcpy(str, "Off");
|
||||
break;
|
||||
case 1:
|
||||
strcpy(str, "CM");
|
||||
break;
|
||||
case 2:
|
||||
strcpy(str, "RTO");
|
||||
break;
|
||||
case 3:
|
||||
strcpy(str, "CM & RTO");
|
||||
break;
|
||||
case 4:
|
||||
strcpy(str, "Ring");
|
||||
break;
|
||||
case 5:
|
||||
strcpy(str, "CM & Ring");
|
||||
break;
|
||||
case 6:
|
||||
strcpy(str, "RTO & Ring");
|
||||
break;
|
||||
case 7:
|
||||
strcpy(str, "CM & RTO & Ring");
|
||||
break;
|
||||
default:
|
||||
strcpy(str, "undefined");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void NetworkOpener::soundToString(const int sound, char* str) {
|
||||
switch (sound) {
|
||||
case 0:
|
||||
strcpy(str, "No Sound");
|
||||
break;
|
||||
case 1:
|
||||
strcpy(str, "Sound 1");
|
||||
break;
|
||||
case 2:
|
||||
strcpy(str, "Sound 2");
|
||||
break;
|
||||
case 3:
|
||||
strcpy(str, "Sound 3");
|
||||
break;
|
||||
default:
|
||||
strcpy(str, "undefined");
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -35,15 +35,16 @@ public:
|
||||
void removeHASSConfig(char* uidString);
|
||||
void publishKeypad(const std::list<NukiLock::KeypadEntry>& entries, uint maxKeypadCodeCount);
|
||||
void publishTimeControl(const std::list<NukiOpener::TimeControlEntry>& timeControlEntries);
|
||||
void publishConfigCommandResult(const char* result);
|
||||
void publishKeypadCommandResult(const char* result);
|
||||
void publishKeypadJsonCommandResult(const char* result);
|
||||
void publishTimeControlCommandResult(const char* result);
|
||||
|
||||
void setLockActionReceivedCallback(LockActionResult (*lockActionReceivedCallback)(const char* value));
|
||||
void setConfigUpdateReceivedCallback(void (*configUpdateReceivedCallback)(const char* path, const char* value));
|
||||
void setConfigUpdateReceivedCallback(void (*configUpdateReceivedCallback)(const char* value));
|
||||
void setKeypadCommandReceivedCallback(void (*keypadCommandReceivedReceivedCallback)(const char* command, const uint& id, const String& name, const String& code, const int& enabled));
|
||||
void setKeypadJsonCommandReceivedCallback(void (*keypadJsonCommandReceivedReceivedCallback)(const char* value));
|
||||
void setTimeControlCommandReceivedCallback(void (*timeControlCommandReceivedReceivedCallback)(const char* value));
|
||||
void setTimeControlCommandReceivedCallback(void (*timeControlCommandReceivedReceivedCallback)(const char* value));
|
||||
void onMqttDataReceived(const char* topic, byte* payload, const unsigned int length) override;
|
||||
|
||||
bool reconnected();
|
||||
@@ -64,6 +65,12 @@ private:
|
||||
void buildMqttPath(const char* path, char* outPath);
|
||||
void subscribe(const char* path);
|
||||
void logactionCompletionStatusToString(uint8_t value, char* out);
|
||||
void buttonPressActionToString(const NukiOpener::ButtonPressAction btnPressAction, char* str);
|
||||
void fobActionToString(const int fobact, char* str);
|
||||
void operatingModeToString(const int opmode, char* str);
|
||||
void doorbellSuppressionToString(const int dbsupr, char* str);
|
||||
void soundToString(const int sound, char* str);
|
||||
void capabilitiesToString(const int capabilities, char* str);
|
||||
|
||||
String concat(String a, String b);
|
||||
|
||||
@@ -74,8 +81,6 @@ private:
|
||||
char _mqttPath[181] = {0};
|
||||
bool _isConnected = false;
|
||||
|
||||
std::vector<char*> _configTopics;
|
||||
|
||||
bool _firstTunerStatePublish = true;
|
||||
bool _haEnabled= false;
|
||||
bool _reconnected = false;
|
||||
@@ -86,8 +91,9 @@ private:
|
||||
int _keypadCommandEnabled = 1;
|
||||
unsigned long _resetRingStateTs = 0;
|
||||
uint8_t _queryCommands = 0;
|
||||
uint32_t authId = 0;
|
||||
char authName[33];
|
||||
uint32_t _authId = 0;
|
||||
char _authName[33];
|
||||
bool _authFound = false;
|
||||
|
||||
NukiOpener::LockState _currentLockState = NukiOpener::LockState::Undefined;
|
||||
|
||||
@@ -95,7 +101,7 @@ private:
|
||||
const size_t _bufferSize;
|
||||
|
||||
LockActionResult (*_lockActionReceivedCallback)(const char* value) = nullptr;
|
||||
void (*_configUpdateReceivedCallback)(const char* path, const char* value) = nullptr;
|
||||
void (*_configUpdateReceivedCallback)(const char* value) = nullptr;
|
||||
void (*_keypadCommandReceivedReceivedCallback)(const char* command, const uint& id, const String& name, const String& code, const int& enabled) = nullptr;
|
||||
void (*_keypadJsonCommandReceivedReceivedCallback)(const char* value) = nullptr;
|
||||
void (*_timeControlCommandReceivedReceivedCallback)(const char* value) = nullptr;
|
||||
|
||||
@@ -111,7 +111,7 @@ void NukiOpenerWrapper::initialize()
|
||||
|
||||
void NukiOpenerWrapper::update()
|
||||
{
|
||||
if (!_paired)
|
||||
if(!_paired)
|
||||
{
|
||||
Log->println(F("Nuki opener start pairing"));
|
||||
_network->publishBleAddress("");
|
||||
@@ -120,7 +120,7 @@ void NukiOpenerWrapper::update()
|
||||
Nuki::AuthorizationIdType::App :
|
||||
Nuki::AuthorizationIdType::Bridge;
|
||||
|
||||
if (_nukiOpener.pairNuki(idType) == NukiOpener::PairingResult::Success)
|
||||
if(_nukiOpener.pairNuki(idType) == NukiOpener::PairingResult::Success)
|
||||
{
|
||||
Log->println(F("Nuki opener paired"));
|
||||
_paired = true;
|
||||
@@ -216,7 +216,7 @@ void NukiOpenerWrapper::update()
|
||||
_retryCount = 0;
|
||||
_nextLockAction = (NukiOpener::LockAction) 0xff;
|
||||
_network->publishRetry("--");
|
||||
if (_intervalLockstate > 10)
|
||||
if(_intervalLockstate > 10)
|
||||
{
|
||||
_nextLockStateUpdateTs = ts + 10 * 1000;
|
||||
}
|
||||
@@ -508,7 +508,7 @@ void NukiOpenerWrapper::updateKeypad()
|
||||
{
|
||||
std::list<NukiLock::KeypadEntry> entries;
|
||||
_nukiOpener.getKeypadEntries(&entries);
|
||||
|
||||
|
||||
Log->print(F("Opener keypad codes: "));
|
||||
Log->println(entries.size());
|
||||
|
||||
@@ -552,7 +552,7 @@ void NukiOpenerWrapper::updateTimeControl(bool retrieved)
|
||||
{
|
||||
std::list<NukiOpener::TimeControlEntry> timeControlEntries;
|
||||
_nukiOpener.getTimeControlEntries(&timeControlEntries);
|
||||
|
||||
|
||||
Log->print(F("Opener time control entries: "));
|
||||
Log->println(timeControlEntries.size());
|
||||
|
||||
@@ -593,14 +593,18 @@ LockActionResult NukiOpenerWrapper::onLockActionReceivedCallback(const char *val
|
||||
{
|
||||
NukiOpener::LockAction action;
|
||||
|
||||
if(strlen(value) > 0)
|
||||
if(value)
|
||||
{
|
||||
action = nukiOpenerInst->lockActionToEnum(value);
|
||||
|
||||
if((int)action == 0xff)
|
||||
if(strlen(value) > 0)
|
||||
{
|
||||
return LockActionResult::UnknownAction;
|
||||
action = nukiOpenerInst->lockActionToEnum(value);
|
||||
|
||||
if((int)action == 0xff)
|
||||
{
|
||||
return LockActionResult::UnknownAction;
|
||||
}
|
||||
}
|
||||
else return LockActionResult::UnknownAction;
|
||||
}
|
||||
else return LockActionResult::UnknownAction;
|
||||
|
||||
@@ -620,9 +624,628 @@ LockActionResult NukiOpenerWrapper::onLockActionReceivedCallback(const char *val
|
||||
return LockActionResult::AccessDenied;
|
||||
}
|
||||
|
||||
void NukiOpenerWrapper::onConfigUpdateReceivedCallback(const char *topic, const char *value)
|
||||
void NukiOpenerWrapper::onConfigUpdateReceivedCallback(const char *value)
|
||||
{
|
||||
nukiOpenerInst->onConfigUpdateReceived(topic, value);
|
||||
nukiOpenerInst->onConfigUpdateReceived(value);
|
||||
}
|
||||
|
||||
Nuki::AdvertisingMode NukiOpenerWrapper::advertisingModeToEnum(const char *str)
|
||||
{
|
||||
if(strcmp(str, "Automatic") == 0) return Nuki::AdvertisingMode::Automatic;
|
||||
else if(strcmp(str, "Normal") == 0) return Nuki::AdvertisingMode::Normal;
|
||||
else if(strcmp(str, "Slow") == 0) return Nuki::AdvertisingMode::Slow;
|
||||
else if(strcmp(str, "Slowest") == 0) return Nuki::AdvertisingMode::Slowest;
|
||||
return (Nuki::AdvertisingMode)0xff;
|
||||
}
|
||||
|
||||
Nuki::TimeZoneId NukiOpenerWrapper::timeZoneToEnum(const char *str)
|
||||
{
|
||||
if(strcmp(str, "Africa/Cairo") == 0) return Nuki::TimeZoneId::Africa_Cairo;
|
||||
else if(strcmp(str, "Africa/Lagos") == 0) return Nuki::TimeZoneId::Africa_Lagos;
|
||||
else if(strcmp(str, "Africa/Maputo") == 0) return Nuki::TimeZoneId::Africa_Maputo;
|
||||
else if(strcmp(str, "Africa/Nairobi") == 0) return Nuki::TimeZoneId::Africa_Nairobi;
|
||||
else if(strcmp(str, "America/Anchorage") == 0) return Nuki::TimeZoneId::America_Anchorage;
|
||||
else if(strcmp(str, "America/Argentina/Buenos_Aires") == 0) return Nuki::TimeZoneId::America_Argentina_Buenos_Aires;
|
||||
else if(strcmp(str, "America/Chicago") == 0) return Nuki::TimeZoneId::America_Chicago;
|
||||
else if(strcmp(str, "America/Denver") == 0) return Nuki::TimeZoneId::America_Denver;
|
||||
else if(strcmp(str, "America/Halifax") == 0) return Nuki::TimeZoneId::America_Halifax;
|
||||
else if(strcmp(str, "America/Los_Angeles") == 0) return Nuki::TimeZoneId::America_Los_Angeles;
|
||||
else if(strcmp(str, "America/Manaus") == 0) return Nuki::TimeZoneId::America_Manaus;
|
||||
else if(strcmp(str, "America/Mexico_City") == 0) return Nuki::TimeZoneId::America_Mexico_City;
|
||||
else if(strcmp(str, "America/New_York") == 0) return Nuki::TimeZoneId::America_New_York;
|
||||
else if(strcmp(str, "America/Phoenix") == 0) return Nuki::TimeZoneId::America_Phoenix;
|
||||
else if(strcmp(str, "America/Regina") == 0) return Nuki::TimeZoneId::America_Regina;
|
||||
else if(strcmp(str, "America/Santiago") == 0) return Nuki::TimeZoneId::America_Santiago;
|
||||
else if(strcmp(str, "America/Sao_Paulo") == 0) return Nuki::TimeZoneId::America_Sao_Paulo;
|
||||
else if(strcmp(str, "America/St_Johns") == 0) return Nuki::TimeZoneId::America_St_Johns;
|
||||
else if(strcmp(str, "Asia/Bangkok") == 0) return Nuki::TimeZoneId::Asia_Bangkok;
|
||||
else if(strcmp(str, "Asia/Dubai") == 0) return Nuki::TimeZoneId::Asia_Dubai;
|
||||
else if(strcmp(str, "Asia/Hong_Kong") == 0) return Nuki::TimeZoneId::Asia_Hong_Kong;
|
||||
else if(strcmp(str, "Asia/Jerusalem") == 0) return Nuki::TimeZoneId::Asia_Jerusalem;
|
||||
else if(strcmp(str, "Asia/Karachi") == 0) return Nuki::TimeZoneId::Asia_Karachi;
|
||||
else if(strcmp(str, "Asia/Kathmandu") == 0) return Nuki::TimeZoneId::Asia_Kathmandu;
|
||||
else if(strcmp(str, "Asia/Kolkata") == 0) return Nuki::TimeZoneId::Asia_Kolkata;
|
||||
else if(strcmp(str, "Asia/Riyadh") == 0) return Nuki::TimeZoneId::Asia_Riyadh;
|
||||
else if(strcmp(str, "Asia/Seoul") == 0) return Nuki::TimeZoneId::Asia_Seoul;
|
||||
else if(strcmp(str, "Asia/Shanghai") == 0) return Nuki::TimeZoneId::Asia_Shanghai;
|
||||
else if(strcmp(str, "Asia/Tehran") == 0) return Nuki::TimeZoneId::Asia_Tehran;
|
||||
else if(strcmp(str, "Asia/Tokyo") == 0) return Nuki::TimeZoneId::Asia_Tokyo;
|
||||
else if(strcmp(str, "Asia/Yangon") == 0) return Nuki::TimeZoneId::Asia_Yangon;
|
||||
else if(strcmp(str, "Australia/Adelaide") == 0) return Nuki::TimeZoneId::Australia_Adelaide;
|
||||
else if(strcmp(str, "Australia/Brisbane") == 0) return Nuki::TimeZoneId::Australia_Brisbane;
|
||||
else if(strcmp(str, "Australia/Darwin") == 0) return Nuki::TimeZoneId::Australia_Darwin;
|
||||
else if(strcmp(str, "Australia/Hobart") == 0) return Nuki::TimeZoneId::Australia_Hobart;
|
||||
else if(strcmp(str, "Australia/Perth") == 0) return Nuki::TimeZoneId::Australia_Perth;
|
||||
else if(strcmp(str, "Australia/Sydney") == 0) return Nuki::TimeZoneId::Australia_Sydney;
|
||||
else if(strcmp(str, "Europe/Berlin") == 0) return Nuki::TimeZoneId::Europe_Berlin;
|
||||
else if(strcmp(str, "Europe/Helsinki") == 0) return Nuki::TimeZoneId::Europe_Helsinki;
|
||||
else if(strcmp(str, "Europe/Istanbul") == 0) return Nuki::TimeZoneId::Europe_Istanbul;
|
||||
else if(strcmp(str, "Europe/London") == 0) return Nuki::TimeZoneId::Europe_London;
|
||||
else if(strcmp(str, "Europe/Moscow") == 0) return Nuki::TimeZoneId::Europe_Moscow;
|
||||
else if(strcmp(str, "Pacific/Auckland") == 0) return Nuki::TimeZoneId::Pacific_Auckland;
|
||||
else if(strcmp(str, "Pacific/Guam") == 0) return Nuki::TimeZoneId::Pacific_Guam;
|
||||
else if(strcmp(str, "Pacific/Honolulu") == 0) return Nuki::TimeZoneId::Pacific_Honolulu;
|
||||
else if(strcmp(str, "Pacific/Pago_Pago") == 0) return Nuki::TimeZoneId::Pacific_Pago_Pago;
|
||||
else if(strcmp(str, "None") == 0) return Nuki::TimeZoneId::None;
|
||||
return (Nuki::TimeZoneId)0xff;
|
||||
}
|
||||
|
||||
uint8_t NukiOpenerWrapper::fobActionToInt(const char *str)
|
||||
{
|
||||
if(strcmp(str, "No Action") == 0) return 0;
|
||||
else if(strcmp(str, "Toggle RTO") == 0) return 1;
|
||||
else if(strcmp(str, "Activate RTO") == 0) return 2;
|
||||
else if(strcmp(str, "Deactivate RTO") == 0) return 3;
|
||||
else if(strcmp(str, "Open") == 0) return 7;
|
||||
else if(strcmp(str, "Ring") == 0) return 8;
|
||||
return 99;
|
||||
}
|
||||
|
||||
uint8_t NukiOpenerWrapper::operatingModeToInt(const char *str)
|
||||
{
|
||||
if(strcmp(str, "Generic door opener") == 0) return 0;
|
||||
else if(strcmp(str, "Analogue intercom") == 0) return 1;
|
||||
else if(strcmp(str, "Digital intercom") == 0) return 2;
|
||||
else if(strcmp(str, "Siedle") == 0) return 3;
|
||||
else if(strcmp(str, "TCS") == 0) return 4;
|
||||
else if(strcmp(str, "Bticino") == 0) return 5;
|
||||
else if(strcmp(str, "Siedle HTS") == 0) return 6;
|
||||
else if(strcmp(str, "STR") == 0) return 7;
|
||||
else if(strcmp(str, "Ritto") == 0) return 8;
|
||||
else if(strcmp(str, "Fermax") == 0) return 9;
|
||||
else if(strcmp(str, "Comelit") == 0) return 10;
|
||||
else if(strcmp(str, "Urmet BiBus") == 0) return 11;
|
||||
else if(strcmp(str, "Urmet 2Voice") == 0) return 12;
|
||||
else if(strcmp(str, "Golmar") == 0) return 13;
|
||||
else if(strcmp(str, "SKS") == 0) return 14;
|
||||
else if(strcmp(str, "Spare") == 0) return 15;
|
||||
return 99;
|
||||
}
|
||||
|
||||
uint8_t NukiOpenerWrapper::doorbellSuppressionToInt(const char *str)
|
||||
{
|
||||
if(strcmp(str, "Off") == 0) return 0;
|
||||
else if(strcmp(str, "CM") == 0) return 1;
|
||||
else if(strcmp(str, "RTO") == 0) return 2;
|
||||
else if(strcmp(str, "CM & RTO") == 0) return 3;
|
||||
else if(strcmp(str, "Ring") == 0) return 4;
|
||||
else if(strcmp(str, "CM & Ring") == 0) return 5;
|
||||
else if(strcmp(str, "RTO & Ring") == 0) return 6;
|
||||
else if(strcmp(str, "CM & RTO & Ring") == 0) return 7;
|
||||
return 99;
|
||||
}
|
||||
|
||||
uint8_t NukiOpenerWrapper::soundToInt(const char *str)
|
||||
{
|
||||
if(strcmp(str, "No Sound") == 0) return 0;
|
||||
else if(strcmp(str, "Sound 1") == 0) return 1;
|
||||
else if(strcmp(str, "Sound 2") == 0) return 2;
|
||||
else if(strcmp(str, "Sound 3") == 0) return 3;
|
||||
return 99;
|
||||
}
|
||||
|
||||
NukiOpener::ButtonPressAction NukiOpenerWrapper::buttonPressActionToEnum(const char* str)
|
||||
{
|
||||
if(strcmp(str, "No Action") == 0) return NukiOpener::ButtonPressAction::NoAction;
|
||||
else if(strcmp(str, "Toggle RTO") == 0) return NukiOpener::ButtonPressAction::ToggleRTO;
|
||||
else if(strcmp(str, "Activate RTO") == 0) return NukiOpener::ButtonPressAction::ActivateRTO;
|
||||
else if(strcmp(str, "Deactivate RTO") == 0) return NukiOpener::ButtonPressAction::DeactivateRTO;
|
||||
else if(strcmp(str, "Toggle CM") == 0) return NukiOpener::ButtonPressAction::ToggleCM;
|
||||
else if(strcmp(str, "Activate CM") == 0) return NukiOpener::ButtonPressAction::ActivateCM;
|
||||
else if(strcmp(str, "Deactivate CM") == 0) return NukiOpener::ButtonPressAction::DectivateCM;
|
||||
else if(strcmp(str, "Open") == 0) return NukiOpener::ButtonPressAction::Open;
|
||||
return (NukiOpener::ButtonPressAction)0xff;
|
||||
}
|
||||
|
||||
Nuki::BatteryType NukiOpenerWrapper::batteryTypeToEnum(const char* str)
|
||||
{
|
||||
if(strcmp(str, "Alkali") == 0) return Nuki::BatteryType::Alkali;
|
||||
else if(strcmp(str, "Accumulators") == 0) return Nuki::BatteryType::Accumulators;
|
||||
else if(strcmp(str, "Lithium") == 0) return Nuki::BatteryType::Lithium;
|
||||
return (Nuki::BatteryType)0xff;
|
||||
}
|
||||
|
||||
void NukiOpenerWrapper::onConfigUpdateReceived(const char *value)
|
||||
{
|
||||
JsonDocument jsonResult;
|
||||
char _resbuf[2048];
|
||||
|
||||
if(_nukiOpener.getSecurityPincode() == 0)
|
||||
{
|
||||
jsonResult["general"] = "noPinSet";
|
||||
serializeJson(jsonResult, _resbuf, sizeof(_resbuf));
|
||||
_network->publishConfigCommandResult(_resbuf);
|
||||
return;
|
||||
}
|
||||
|
||||
JsonDocument json;
|
||||
DeserializationError jsonError = deserializeJson(json, value);
|
||||
|
||||
if(jsonError)
|
||||
{
|
||||
jsonResult["general"] = "invalidJson";
|
||||
serializeJson(jsonResult, _resbuf, sizeof(_resbuf));
|
||||
_network->publishConfigCommandResult(_resbuf);
|
||||
return;
|
||||
}
|
||||
|
||||
Nuki::CmdResult cmdResult;
|
||||
const char *basicKeys[] = {"name", "latitude", "longitude", "pairingEnabled", "buttonEnabled", "ledFlashEnabled", "timeZoneOffset", "dstMode", "fobAction1", "fobAction2", "fobAction3", "operatingMode", "advertisingMode", "timeZone"};
|
||||
const char *advancedKeys[] = {"intercomID", "busModeSwitch", "shortCircuitDuration", "electricStrikeDelay", "randomElectricStrikeDelay", "electricStrikeDuration", "disableRtoAfterRing", "rtoTimeout", "doorbellSuppression", "doorbellSuppressionDuration", "soundRing", "soundOpen", "soundRto", "soundCm", "soundConfirmation", "soundLevel", "singleButtonPressAction", "doubleButtonPressAction", "batteryType", "automaticBatteryTypeDetection"};
|
||||
bool basicUpdated = false;
|
||||
bool advancedUpdated = false;
|
||||
uint32_t basicOpenerConfigAclPrefs[16];
|
||||
uint32_t advancedOpenerConfigAclPrefs[20];
|
||||
|
||||
nukiOpenerPreferences = new Preferences();
|
||||
nukiOpenerPreferences->begin("nukihub", true);
|
||||
nukiOpenerPreferences->getBytes(preference_conf_opener_basic_acl, &basicOpenerConfigAclPrefs, sizeof(basicOpenerConfigAclPrefs));
|
||||
nukiOpenerPreferences->getBytes(preference_conf_opener_advanced_acl, &advancedOpenerConfigAclPrefs, sizeof(advancedOpenerConfigAclPrefs));
|
||||
|
||||
for(int i=0; i < 16; i++)
|
||||
{
|
||||
if(json[basicKeys[i]])
|
||||
{
|
||||
const char *jsonchar = json[basicKeys[i]].as<const char*>();
|
||||
|
||||
if(strlen(jsonchar) == 0)
|
||||
{
|
||||
jsonResult[basicKeys[i]] = "noValueSet";
|
||||
continue;
|
||||
}
|
||||
|
||||
if((int)basicOpenerConfigAclPrefs[i] == 1)
|
||||
{
|
||||
cmdResult = Nuki::CmdResult::Error;
|
||||
|
||||
if(strcmp(basicKeys[i], "name") == 0)
|
||||
{
|
||||
if(strlen(jsonchar) <= 32)
|
||||
{
|
||||
if(strcmp((const char*)_nukiConfig.name, jsonchar) == 0) jsonResult[basicKeys[i]] = "unchanged";
|
||||
else cmdResult = _nukiOpener.setName(std::string(jsonchar));
|
||||
}
|
||||
else jsonResult[basicKeys[i]] = "valueTooLong";
|
||||
}
|
||||
else if(strcmp(basicKeys[i], "latitude") == 0)
|
||||
{
|
||||
const float keyvalue = atof(jsonchar);
|
||||
|
||||
if(keyvalue > 0)
|
||||
{
|
||||
if(_nukiConfig.latitude == keyvalue) jsonResult[basicKeys[i]] = "unchanged";
|
||||
else cmdResult = _nukiOpener.setLatitude(keyvalue);
|
||||
}
|
||||
else jsonResult[basicKeys[i]] = "invalidValue";
|
||||
}
|
||||
else if(strcmp(basicKeys[i], "longitude") == 0)
|
||||
{
|
||||
const float keyvalue = atof(jsonchar);
|
||||
|
||||
if(keyvalue > 0)
|
||||
{
|
||||
if(_nukiConfig.longitude == keyvalue) jsonResult[basicKeys[i]] = "unchanged";
|
||||
else cmdResult = _nukiOpener.setLongitude(keyvalue);
|
||||
}
|
||||
else jsonResult[basicKeys[i]] = "invalidValue";
|
||||
}
|
||||
else if(strcmp(basicKeys[i], "pairingEnabled") == 0)
|
||||
{
|
||||
const uint8_t keyvalue = atoi(jsonchar);
|
||||
|
||||
if(keyvalue == 0 || keyvalue == 1)
|
||||
{
|
||||
if(_nukiConfig.pairingEnabled == keyvalue) jsonResult[basicKeys[i]] = "unchanged";
|
||||
else cmdResult = _nukiOpener.enablePairing((keyvalue > 0));
|
||||
}
|
||||
else jsonResult[basicKeys[i]] = "invalidValue";
|
||||
}
|
||||
else if(strcmp(basicKeys[i], "buttonEnabled") == 0)
|
||||
{
|
||||
const uint8_t keyvalue = atoi(jsonchar);
|
||||
|
||||
if(keyvalue == 0 || keyvalue == 1)
|
||||
{
|
||||
if(_nukiConfig.buttonEnabled == keyvalue) jsonResult[basicKeys[i]] = "unchanged";
|
||||
else cmdResult = _nukiOpener.enableButton((keyvalue > 0));
|
||||
}
|
||||
else jsonResult[basicKeys[i]] = "invalidValue";
|
||||
}
|
||||
else if(strcmp(basicKeys[i], "ledFlashEnabled") == 0)
|
||||
{
|
||||
const uint8_t keyvalue = atoi(jsonchar);
|
||||
|
||||
if(keyvalue == 0 || keyvalue == 1)
|
||||
{
|
||||
if(_nukiConfig.ledFlashEnabled == keyvalue) jsonResult[basicKeys[i]] = "unchanged";
|
||||
else cmdResult = _nukiOpener.enableLedFlash((keyvalue > 0));
|
||||
}
|
||||
else jsonResult[basicKeys[i]] = "invalidValue";
|
||||
}
|
||||
else if(strcmp(basicKeys[i], "timeZoneOffset") == 0)
|
||||
{
|
||||
const int16_t keyvalue = atoi(jsonchar);
|
||||
|
||||
if(keyvalue >= 0 && keyvalue <= 60)
|
||||
{
|
||||
if(_nukiConfig.timeZoneOffset == keyvalue) jsonResult[basicKeys[i]] = "unchanged";
|
||||
else cmdResult = _nukiOpener.setTimeZoneOffset(keyvalue);
|
||||
}
|
||||
else jsonResult[basicKeys[i]] = "invalidValue";
|
||||
}
|
||||
else if(strcmp(basicKeys[i], "dstMode") == 0)
|
||||
{
|
||||
const uint8_t keyvalue = atoi(jsonchar);
|
||||
|
||||
if(keyvalue == 0 || keyvalue == 1)
|
||||
{
|
||||
if(_nukiConfig.dstMode == keyvalue) jsonResult[basicKeys[i]] = "unchanged";
|
||||
else cmdResult = _nukiOpener.enableDst((keyvalue > 0));
|
||||
}
|
||||
else jsonResult[basicKeys[i]] = "invalidValue";
|
||||
}
|
||||
else if(strcmp(basicKeys[i], "fobAction1") == 0)
|
||||
{
|
||||
const uint8_t fobAct1 = nukiOpenerInst->fobActionToInt(jsonchar);
|
||||
|
||||
if(fobAct1 != 99)
|
||||
{
|
||||
if(_nukiConfig.fobAction1 == fobAct1) jsonResult[basicKeys[i]] = "unchanged";
|
||||
else cmdResult = _nukiOpener.setFobAction(1, fobAct1);
|
||||
}
|
||||
else jsonResult[basicKeys[i]] = "invalidValue";
|
||||
}
|
||||
else if(strcmp(basicKeys[i], "fobAction2") == 0)
|
||||
{
|
||||
const uint8_t fobAct2 = nukiOpenerInst->fobActionToInt(jsonchar);
|
||||
|
||||
if(fobAct2 != 99)
|
||||
{
|
||||
if(_nukiConfig.fobAction2 == fobAct2) jsonResult[basicKeys[i]] = "unchanged";
|
||||
else cmdResult = _nukiOpener.setFobAction(2, fobAct2);
|
||||
}
|
||||
else jsonResult[basicKeys[i]] = "invalidValue";
|
||||
}
|
||||
else if(strcmp(basicKeys[i], "fobAction3") == 0)
|
||||
{
|
||||
const uint8_t fobAct3 = nukiOpenerInst->fobActionToInt(jsonchar);
|
||||
|
||||
if(fobAct3 != 99)
|
||||
{
|
||||
if(_nukiConfig.fobAction3 == fobAct3) jsonResult[basicKeys[i]] = "unchanged";
|
||||
else cmdResult = _nukiOpener.setFobAction(3, fobAct3);
|
||||
}
|
||||
else jsonResult[basicKeys[i]] = "invalidValue";
|
||||
}
|
||||
else if(strcmp(basicKeys[i], "operatingMode") == 0)
|
||||
{
|
||||
const uint8_t opmode = nukiOpenerInst->operatingModeToInt(jsonchar);
|
||||
|
||||
if(opmode != 99)
|
||||
{
|
||||
if(_nukiConfig.operatingMode == opmode) jsonResult[basicKeys[i]] = "unchanged";
|
||||
else cmdResult = _nukiOpener.setOperatingMode(opmode);
|
||||
}
|
||||
else jsonResult[basicKeys[i]] = "invalidValue";
|
||||
}
|
||||
else if(strcmp(basicKeys[i], "advertisingMode") == 0)
|
||||
{
|
||||
Nuki::AdvertisingMode advmode = nukiOpenerInst->advertisingModeToEnum(jsonchar);
|
||||
|
||||
if(!(int)advmode == 0xff)
|
||||
{
|
||||
if(_nukiConfig.advertisingMode == advmode) jsonResult[basicKeys[i]] = "unchanged";
|
||||
else cmdResult = _nukiOpener.setAdvertisingMode(advmode);
|
||||
}
|
||||
else jsonResult[basicKeys[i]] = "invalidValue";
|
||||
}
|
||||
else if(strcmp(basicKeys[i], "timeZone") == 0)
|
||||
{
|
||||
Nuki::TimeZoneId tzid = nukiOpenerInst->timeZoneToEnum(jsonchar);
|
||||
|
||||
if(!(int)tzid == 0xff)
|
||||
{
|
||||
if(_nukiConfig.timeZoneId == tzid) jsonResult[basicKeys[i]] = "unchanged";
|
||||
else cmdResult = _nukiOpener.setTimeZoneId(tzid);
|
||||
}
|
||||
else jsonResult[basicKeys[i]] = "invalidValue";
|
||||
}
|
||||
|
||||
if(cmdResult == Nuki::CmdResult::Success) basicUpdated = true;
|
||||
|
||||
if(!jsonResult[basicKeys[i]]) {
|
||||
char resultStr[15] = {0};
|
||||
NukiOpener::cmdResultToString(cmdResult, resultStr);
|
||||
jsonResult[basicKeys[i]] = resultStr;
|
||||
}
|
||||
}
|
||||
else jsonResult[basicKeys[i]] = "accessDenied";
|
||||
}
|
||||
}
|
||||
|
||||
for(int i=0; i < 20; i++)
|
||||
{
|
||||
if(json[advancedKeys[i]])
|
||||
{
|
||||
const char *jsonchar = json[advancedKeys[i]].as<const char*>();
|
||||
|
||||
if(strlen(jsonchar) == 0)
|
||||
{
|
||||
jsonResult[advancedKeys[i]] = "noValueSet";
|
||||
continue;
|
||||
}
|
||||
|
||||
if((int)advancedOpenerConfigAclPrefs[i] == 1)
|
||||
{
|
||||
cmdResult = Nuki::CmdResult::Error;
|
||||
|
||||
if(strcmp(advancedKeys[i], "intercomID") == 0)
|
||||
{
|
||||
const uint16_t keyvalue = atoi(jsonchar);
|
||||
|
||||
if(keyvalue >= 0)
|
||||
{
|
||||
if(_nukiAdvancedConfig.intercomID == keyvalue) jsonResult[advancedKeys[i]] = "unchanged";
|
||||
else cmdResult = _nukiOpener.setIntercomID(keyvalue);
|
||||
}
|
||||
else jsonResult[advancedKeys[i]] = "invalidValue";
|
||||
}
|
||||
else if(strcmp(advancedKeys[i], "busModeSwitch") == 0)
|
||||
{
|
||||
const uint8_t keyvalue = atoi(jsonchar);
|
||||
|
||||
if(keyvalue == 0 || keyvalue == 1)
|
||||
{
|
||||
if(_nukiAdvancedConfig.busModeSwitch == keyvalue) jsonResult[advancedKeys[i]] = "unchanged";
|
||||
else cmdResult = _nukiOpener.setBusModeSwitch((keyvalue > 0));
|
||||
}
|
||||
else jsonResult[advancedKeys[i]] = "invalidValue";
|
||||
}
|
||||
else if(strcmp(advancedKeys[i], "shortCircuitDuration") == 0)
|
||||
{
|
||||
const uint16_t keyvalue = atoi(jsonchar);
|
||||
|
||||
if(keyvalue >= 0)
|
||||
{
|
||||
if(_nukiAdvancedConfig.shortCircuitDuration == keyvalue) jsonResult[advancedKeys[i]] = "unchanged";
|
||||
else cmdResult = _nukiOpener.setShortCircuitDuration(keyvalue);
|
||||
}
|
||||
else jsonResult[advancedKeys[i]] = "invalidValue";
|
||||
}
|
||||
else if(strcmp(advancedKeys[i], "electricStrikeDelay") == 0)
|
||||
{
|
||||
const uint16_t keyvalue = atoi(jsonchar);
|
||||
|
||||
if(keyvalue >= 0 && keyvalue <= 30000)
|
||||
{
|
||||
if(_nukiAdvancedConfig.electricStrikeDelay == keyvalue) jsonResult[advancedKeys[i]] = "unchanged";
|
||||
else cmdResult = _nukiOpener.setElectricStrikeDelay(keyvalue);
|
||||
}
|
||||
else jsonResult[advancedKeys[i]] = "invalidValue";
|
||||
}
|
||||
else if(strcmp(advancedKeys[i], "randomElectricStrikeDelay") == 0)
|
||||
{
|
||||
const uint8_t keyvalue = atoi(jsonchar);
|
||||
|
||||
if(keyvalue == 0 || keyvalue == 1)
|
||||
{
|
||||
if(_nukiAdvancedConfig.randomElectricStrikeDelay == keyvalue) jsonResult[advancedKeys[i]] = "unchanged";
|
||||
else cmdResult = _nukiOpener.enableRandomElectricStrikeDelay((keyvalue > 0));
|
||||
}
|
||||
else jsonResult[advancedKeys[i]] = "invalidValue";
|
||||
}
|
||||
else if(strcmp(advancedKeys[i], "electricStrikeDuration") == 0)
|
||||
{
|
||||
const uint16_t keyvalue = atoi(jsonchar);
|
||||
|
||||
if(keyvalue >= 1000 && keyvalue <= 30000)
|
||||
{
|
||||
if(_nukiAdvancedConfig.electricStrikeDuration == keyvalue) jsonResult[advancedKeys[i]] = "unchanged";
|
||||
else cmdResult = _nukiOpener.setElectricStrikeDuration(keyvalue);
|
||||
}
|
||||
else jsonResult[advancedKeys[i]] = "invalidValue";
|
||||
}
|
||||
else if(strcmp(advancedKeys[i], "disableRtoAfterRing") == 0)
|
||||
{
|
||||
const uint8_t keyvalue = atoi(jsonchar);
|
||||
|
||||
if(keyvalue == 0 || keyvalue == 1)
|
||||
{
|
||||
if(_nukiAdvancedConfig.disableRtoAfterRing == keyvalue) jsonResult[advancedKeys[i]] = "unchanged";
|
||||
else cmdResult = _nukiOpener.disableRtoAfterRing((keyvalue > 0));
|
||||
}
|
||||
else jsonResult[advancedKeys[i]] = "invalidValue";
|
||||
}
|
||||
else if(strcmp(advancedKeys[i], "rtoTimeout") == 0)
|
||||
{
|
||||
const uint8_t keyvalue = atoi(jsonchar);
|
||||
|
||||
if(keyvalue >= 5 && keyvalue <= 60)
|
||||
{
|
||||
if(_nukiAdvancedConfig.rtoTimeout == keyvalue) jsonResult[advancedKeys[i]] = "unchanged";
|
||||
else cmdResult = _nukiOpener.setRtoTimeout(keyvalue);
|
||||
}
|
||||
else jsonResult[advancedKeys[i]] = "invalidValue";
|
||||
}
|
||||
else if(strcmp(advancedKeys[i], "doorbellSuppression") == 0)
|
||||
{
|
||||
const uint8_t dbsupr = nukiOpenerInst->doorbellSuppressionToInt(jsonchar);
|
||||
|
||||
if(dbsupr != 99)
|
||||
{
|
||||
if(_nukiAdvancedConfig.doorbellSuppression == dbsupr) jsonResult[advancedKeys[i]] = "unchanged";
|
||||
else cmdResult = _nukiOpener.setDoorbellSuppression(dbsupr);
|
||||
}
|
||||
else jsonResult[basicKeys[i]] = "invalidValue";
|
||||
}
|
||||
else if(strcmp(advancedKeys[i], "doorbellSuppressionDuration") == 0)
|
||||
{
|
||||
const uint16_t keyvalue = atoi(jsonchar);
|
||||
|
||||
if(keyvalue >= 500 && keyvalue <= 10000)
|
||||
{
|
||||
if(_nukiAdvancedConfig.doorbellSuppressionDuration == keyvalue) jsonResult[advancedKeys[i]] = "unchanged";
|
||||
else cmdResult = _nukiOpener.setDoorbellSuppressionDuration(keyvalue);
|
||||
}
|
||||
else jsonResult[advancedKeys[i]] = "invalidValue";
|
||||
}
|
||||
else if(strcmp(advancedKeys[i], "soundRing") == 0)
|
||||
{
|
||||
const uint8_t sound = nukiOpenerInst->soundToInt(jsonchar);
|
||||
|
||||
if(sound != 99)
|
||||
{
|
||||
if(_nukiAdvancedConfig.soundRing == sound) jsonResult[advancedKeys[i]] = "unchanged";
|
||||
else cmdResult = _nukiOpener.setSoundRing(sound);
|
||||
}
|
||||
else jsonResult[basicKeys[i]] = "invalidValue";
|
||||
}
|
||||
else if(strcmp(advancedKeys[i], "soundOpen") == 0)
|
||||
{
|
||||
const uint8_t sound = nukiOpenerInst->soundToInt(jsonchar);
|
||||
|
||||
if(sound != 99)
|
||||
{
|
||||
if(_nukiAdvancedConfig.soundOpen == sound) jsonResult[advancedKeys[i]] = "unchanged";
|
||||
else cmdResult = _nukiOpener.setSoundOpen(sound);
|
||||
}
|
||||
else jsonResult[basicKeys[i]] = "invalidValue";
|
||||
}
|
||||
else if(strcmp(advancedKeys[i], "soundRto") == 0)
|
||||
{
|
||||
const uint8_t sound = nukiOpenerInst->soundToInt(jsonchar);
|
||||
|
||||
if(sound != 99)
|
||||
{
|
||||
if(_nukiAdvancedConfig.soundRto == sound) jsonResult[advancedKeys[i]] = "unchanged";
|
||||
else cmdResult = _nukiOpener.setSoundRto(sound);
|
||||
}
|
||||
else jsonResult[basicKeys[i]] = "invalidValue";
|
||||
}
|
||||
else if(strcmp(advancedKeys[i], "soundCm") == 0)
|
||||
{
|
||||
const uint8_t sound = nukiOpenerInst->soundToInt(jsonchar);
|
||||
|
||||
if(sound != 99)
|
||||
{
|
||||
if(_nukiAdvancedConfig.soundCm == sound) jsonResult[advancedKeys[i]] = "unchanged";
|
||||
else cmdResult = _nukiOpener.setSoundCm(sound);
|
||||
}
|
||||
else jsonResult[basicKeys[i]] = "invalidValue";
|
||||
}
|
||||
else if(strcmp(advancedKeys[i], "soundConfirmation") == 0)
|
||||
{
|
||||
const uint8_t keyvalue = atoi(jsonchar);
|
||||
|
||||
if(keyvalue == 0 || keyvalue == 1)
|
||||
{
|
||||
if(_nukiAdvancedConfig.soundConfirmation == keyvalue) jsonResult[advancedKeys[i]] = "unchanged";
|
||||
else cmdResult = _nukiOpener.enableSoundConfirmation((keyvalue > 0));
|
||||
}
|
||||
else jsonResult[advancedKeys[i]] = "invalidValue";
|
||||
}
|
||||
else if(strcmp(advancedKeys[i], "soundLevel") == 0)
|
||||
{
|
||||
const uint8_t keyvalue = atoi(jsonchar);
|
||||
|
||||
if(keyvalue >= 0 && keyvalue <= 255)
|
||||
{
|
||||
if(_nukiAdvancedConfig.soundLevel == keyvalue) jsonResult[basicKeys[i]] = "unchanged";
|
||||
else cmdResult = _nukiOpener.setSoundLevel(keyvalue);
|
||||
}
|
||||
else jsonResult[basicKeys[i]] = "invalidValue";
|
||||
}
|
||||
else if(strcmp(advancedKeys[i], "singleButtonPressAction") == 0)
|
||||
{
|
||||
NukiOpener::ButtonPressAction sbpa = nukiOpenerInst->buttonPressActionToEnum(jsonchar);
|
||||
|
||||
if(!(int)sbpa == 0xff)
|
||||
{
|
||||
if(_nukiAdvancedConfig.singleButtonPressAction == sbpa) jsonResult[advancedKeys[i]] = "unchanged";
|
||||
else cmdResult = _nukiOpener.setSingleButtonPressAction(sbpa);
|
||||
}
|
||||
else jsonResult[advancedKeys[i]] = "invalidValue";
|
||||
}
|
||||
else if(strcmp(advancedKeys[i], "doubleButtonPressAction") == 0)
|
||||
{
|
||||
NukiOpener::ButtonPressAction dbpa = nukiOpenerInst->buttonPressActionToEnum(jsonchar);
|
||||
|
||||
if(!(int)dbpa == 0xff)
|
||||
{
|
||||
if(_nukiAdvancedConfig.doubleButtonPressAction == dbpa) jsonResult[advancedKeys[i]] = "unchanged";
|
||||
else cmdResult = _nukiOpener.setDoubleButtonPressAction(dbpa);
|
||||
}
|
||||
else jsonResult[advancedKeys[i]] = "invalidValue";
|
||||
}
|
||||
else if(strcmp(advancedKeys[i], "batteryType") == 0)
|
||||
{
|
||||
Nuki::BatteryType battype = nukiOpenerInst->batteryTypeToEnum(jsonchar);
|
||||
|
||||
if(!(int)battype == 0xff)
|
||||
{
|
||||
if(_nukiAdvancedConfig.batteryType == battype) jsonResult[advancedKeys[i]] = "unchanged";
|
||||
else cmdResult = _nukiOpener.setBatteryType(battype);
|
||||
}
|
||||
else jsonResult[advancedKeys[i]] = "invalidValue";
|
||||
}
|
||||
else if(strcmp(advancedKeys[i], "automaticBatteryTypeDetection") == 0)
|
||||
{
|
||||
const uint8_t keyvalue = atoi(jsonchar);
|
||||
|
||||
if(keyvalue == 0 || keyvalue == 1)
|
||||
{
|
||||
if(_nukiAdvancedConfig.automaticBatteryTypeDetection == keyvalue) jsonResult[advancedKeys[i]] = "unchanged";
|
||||
else cmdResult = _nukiOpener.enableAutoBatteryTypeDetection((keyvalue > 0));
|
||||
}
|
||||
else jsonResult[advancedKeys[i]] = "invalidValue";
|
||||
}
|
||||
|
||||
if(cmdResult == Nuki::CmdResult::Success) advancedUpdated = true;
|
||||
|
||||
if(!jsonResult[advancedKeys[i]]) {
|
||||
char resultStr[15] = {0};
|
||||
NukiOpener::cmdResultToString(cmdResult, resultStr);
|
||||
jsonResult[advancedKeys[i]] = resultStr;
|
||||
}
|
||||
}
|
||||
else jsonResult[advancedKeys[i]] = "accessDenied";
|
||||
}
|
||||
}
|
||||
|
||||
nukiOpenerPreferences->end();
|
||||
|
||||
if(basicUpdated || advancedUpdated)
|
||||
{
|
||||
jsonResult["general"] = "success";
|
||||
}
|
||||
else jsonResult["general"] = "noChange";
|
||||
|
||||
_nextConfigUpdateTs = millis() + 300;
|
||||
|
||||
serializeJson(jsonResult, _resbuf, sizeof(_resbuf));
|
||||
_network->publishConfigCommandResult(_resbuf);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void NukiOpenerWrapper::onKeypadCommandReceivedCallback(const char *command, const uint &id, const String &name, const String &code, const int& enabled)
|
||||
@@ -660,33 +1283,6 @@ void NukiOpenerWrapper::gpioActionCallback(const GpioAction &action, const int&
|
||||
}
|
||||
}
|
||||
|
||||
void NukiOpenerWrapper::onConfigUpdateReceived(const char *topic, const char *value)
|
||||
{
|
||||
if(!_preferences->getBool(preference_admin_enabled)) return;
|
||||
|
||||
if(strcmp(topic, mqtt_topic_config_button_enabled) == 0)
|
||||
{
|
||||
bool newValue = atoi(value) > 0;
|
||||
if(!_nukiConfigValid || _nukiConfig.buttonEnabled == newValue) return;
|
||||
_nukiOpener.enableButton(newValue);
|
||||
_nextConfigUpdateTs = millis() + 300;
|
||||
}
|
||||
if(strcmp(topic, mqtt_topic_config_led_enabled) == 0)
|
||||
{
|
||||
bool newValue = atoi(value) > 0;
|
||||
if(!_nukiConfigValid || _nukiConfig.ledFlashEnabled == newValue) return;
|
||||
_nukiOpener.enableLedFlash(newValue);
|
||||
_nextConfigUpdateTs = millis() + 300;
|
||||
}
|
||||
if(strcmp(topic, mqtt_topic_config_sound_level) == 0)
|
||||
{
|
||||
uint8_t newValue = atoi(value);
|
||||
if(!_nukiAdvancedConfigValid || _nukiAdvancedConfig.soundLevel == newValue) return;
|
||||
_nukiOpener.setSoundLevel(newValue);
|
||||
_nextConfigUpdateTs = millis() + 300;
|
||||
}
|
||||
}
|
||||
|
||||
void NukiOpenerWrapper::onKeypadCommandReceived(const char *command, const uint &id, const String &name, const String &code, const int& enabled)
|
||||
{
|
||||
if(!_preferences->getBool(preference_keypad_control_enabled))
|
||||
@@ -825,21 +1421,7 @@ void NukiOpenerWrapper::onKeypadJsonCommandReceived(const char *value)
|
||||
_network->publishKeypadJsonCommandResult("keypadNotAvailable");
|
||||
return;
|
||||
}
|
||||
|
||||
updateConfig();
|
||||
|
||||
while (!_nukiConfigValid && _retryConfigCount < 11)
|
||||
{
|
||||
updateConfig();
|
||||
}
|
||||
|
||||
if(_configRead && _nukiConfigValid)
|
||||
{
|
||||
_network->publishKeypadJsonCommandResult("keypadNotAvailable");
|
||||
return;
|
||||
}
|
||||
|
||||
_network->publishKeypadJsonCommandResult("invalidConfig");
|
||||
_network->publishKeypadJsonCommandResult("configNotReady");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -925,7 +1507,7 @@ void NukiOpenerWrapper::onKeypadJsonCommandReceived(const char *value)
|
||||
unsigned int allowedUntilTimeAr[2];
|
||||
uint8_t allowedWeekdaysInt = 0;
|
||||
|
||||
if(timeLimited == 1 && enabled != 0)
|
||||
if(timeLimited == 1)
|
||||
{
|
||||
if(allowedFrom)
|
||||
{
|
||||
@@ -1077,6 +1659,18 @@ void NukiOpenerWrapper::onKeypadJsonCommandReceived(const char *value)
|
||||
}
|
||||
else if (strcmp(action, "update") == 0)
|
||||
{
|
||||
if(!codeId)
|
||||
{
|
||||
_network->publishKeypadJsonCommandResult("noCodeIdSet");
|
||||
return;
|
||||
}
|
||||
|
||||
if(!idExists)
|
||||
{
|
||||
_network->publishKeypadJsonCommandResult("noExistingCodeIdSet");
|
||||
return;
|
||||
}
|
||||
|
||||
NukiOpener::UpdatedKeypadEntry entry;
|
||||
memset(&entry, 0, sizeof(entry));
|
||||
entry.codeId = codeId;
|
||||
@@ -1181,9 +1775,8 @@ void NukiOpenerWrapper::onTimeControlCommandReceived(const char *value)
|
||||
const char *lockAct = json["lockAction"].as<const char*>();
|
||||
NukiOpener::LockAction timeControlLockAction;
|
||||
|
||||
if(strlen(lockAct) > 0)
|
||||
if(lockAct)
|
||||
{
|
||||
|
||||
timeControlLockAction = nukiOpenerInst->lockActionToEnum(lockAct);
|
||||
|
||||
if((int)timeControlLockAction == 0xff)
|
||||
@@ -1192,11 +1785,6 @@ void NukiOpenerWrapper::onTimeControlCommandReceived(const char *value)
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_network->publishTimeControlCommandResult("invalidLockAction");
|
||||
return;
|
||||
}
|
||||
|
||||
if(action)
|
||||
{
|
||||
@@ -1281,6 +1869,12 @@ void NukiOpenerWrapper::onTimeControlCommandReceived(const char *value)
|
||||
}
|
||||
else if (strcmp(action, "update") == 0)
|
||||
{
|
||||
if(!idExists)
|
||||
{
|
||||
_network->publishTimeControlCommandResult("noExistingEntryIdSet");
|
||||
return;
|
||||
}
|
||||
|
||||
NukiOpener::TimeControlEntry entry;
|
||||
memset(&entry, 0, sizeof(entry));
|
||||
entry.entryId = entryId;
|
||||
@@ -1387,13 +1981,13 @@ void NukiOpenerWrapper::setupHASS()
|
||||
char uidString[20];
|
||||
itoa(_nukiConfig.nukiId, uidString, 16);
|
||||
|
||||
if (_preferences->getBool(preference_opener_continuous_mode))
|
||||
if(_preferences->getBool(preference_opener_continuous_mode))
|
||||
{
|
||||
_network->publishHASSConfig("Opener", baseTopic.c_str(), (char*)_nukiConfig.name, uidString, "deactivateCM", "activateCM", "electricStrikeActuation");
|
||||
_network->publishHASSConfig((char*)"Opener", baseTopic.c_str(), (char*)_nukiConfig.name, uidString, (char*)"deactivateCM", (char*)"activateCM", (char*)"electricStrikeActuation");
|
||||
}
|
||||
else
|
||||
{
|
||||
_network->publishHASSConfig("Opener", baseTopic.c_str(), (char*)_nukiConfig.name, uidString, "deactivateRTO", "activateRTO", "electricStrikeActuation");
|
||||
_network->publishHASSConfig((char*)"Opener", baseTopic.c_str(), (char*)_nukiConfig.name, uidString, (char*)"deactivateRTO", (char*)"activateRTO", (char*)"electricStrikeActuation");
|
||||
}
|
||||
|
||||
_hassSetupCompleted = true;
|
||||
@@ -1408,7 +2002,7 @@ void NukiOpenerWrapper::disableHASS()
|
||||
Nuki::CmdResult result = _nukiOpener.requestConfig(&_nukiConfig);
|
||||
_nukiConfigValid = result == Nuki::CmdResult::Success;
|
||||
}
|
||||
if (_nukiConfigValid)
|
||||
if(_nukiConfigValid)
|
||||
{
|
||||
char uidString[20];
|
||||
itoa(_nukiConfig.nukiId, uidString, 16);
|
||||
|
||||
@@ -47,13 +47,13 @@ public:
|
||||
|
||||
private:
|
||||
static LockActionResult onLockActionReceivedCallback(const char* value);
|
||||
static void onConfigUpdateReceivedCallback(const char* topic, const char* value);
|
||||
static void onConfigUpdateReceivedCallback(const char* value);
|
||||
static void onKeypadCommandReceivedCallback(const char* command, const uint& id, const String& name, const String& code, const int& enabled);
|
||||
static void onKeypadJsonCommandReceivedCallback(const char* value);
|
||||
static void onTimeControlCommandReceivedCallback(const char* value);
|
||||
static void gpioActionCallback(const GpioAction& action, const int& pin);
|
||||
void onConfigUpdateReceived(const char* topic, const char* value);
|
||||
void onKeypadCommandReceived(const char* command, const uint& id, const String& name, const String& code, const int& enabled);
|
||||
void onConfigUpdateReceived(const char* value);
|
||||
void onKeypadJsonCommandReceived(const char* value);
|
||||
void onTimeControlCommandReceived(const char* value);
|
||||
|
||||
@@ -75,6 +75,14 @@ private:
|
||||
void printCommandResult(Nuki::CmdResult result);
|
||||
|
||||
NukiOpener::LockAction lockActionToEnum(const char* str); // char array at least 14 characters
|
||||
Nuki::AdvertisingMode advertisingModeToEnum(const char* str);
|
||||
Nuki::TimeZoneId timeZoneToEnum(const char* str);
|
||||
uint8_t fobActionToInt(const char *str);
|
||||
uint8_t operatingModeToInt(const char *str);
|
||||
uint8_t doorbellSuppressionToInt(const char *str);
|
||||
uint8_t soundToInt(const char *str);
|
||||
NukiOpener::ButtonPressAction buttonPressActionToEnum(const char* str);
|
||||
Nuki::BatteryType batteryTypeToEnum(const char* str);
|
||||
|
||||
std::string _deviceName;
|
||||
NukiDeviceId* _deviceId = nullptr;
|
||||
|
||||
@@ -69,9 +69,16 @@ void NukiWrapper::initialize(const bool& firstStart)
|
||||
_preferences->putInt(preference_command_nr_of_retries, 3);
|
||||
_preferences->putInt(preference_command_retry_delay, 1000);
|
||||
_preferences->putInt(preference_restart_ble_beacon_lost, 60);
|
||||
_preferences->putBool(preference_admin_enabled, true);
|
||||
uint32_t aclPrefs[17] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
|
||||
_preferences->putBytes(preference_acl, (byte*)(&aclPrefs), sizeof(aclPrefs));
|
||||
uint32_t basicLockConfigAclPrefs[16] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
|
||||
_preferences->putBytes(preference_conf_lock_basic_acl, (byte*)(&basicLockConfigAclPrefs), sizeof(basicLockConfigAclPrefs));
|
||||
uint32_t basicOpenerConfigAclPrefs[14] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
|
||||
_preferences->putBytes(preference_conf_opener_basic_acl, (byte*)(&basicOpenerConfigAclPrefs), sizeof(basicOpenerConfigAclPrefs));
|
||||
uint32_t advancedLockConfigAclPrefs[22] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
|
||||
_preferences->putBytes(preference_conf_lock_advanced_acl, (byte*)(&advancedLockConfigAclPrefs), sizeof(advancedLockConfigAclPrefs));
|
||||
uint32_t advancedOpenerConfigAclPrefs[20] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
|
||||
_preferences->putBytes(preference_conf_opener_advanced_acl, (byte*)(&advancedOpenerConfigAclPrefs), sizeof(advancedOpenerConfigAclPrefs));
|
||||
}
|
||||
|
||||
if(_retryDelay <= 100)
|
||||
@@ -123,7 +130,7 @@ void NukiWrapper::initialize(const bool& firstStart)
|
||||
|
||||
void NukiWrapper::update()
|
||||
{
|
||||
if (!_paired)
|
||||
if(!_paired)
|
||||
{
|
||||
Log->println(F("Nuki lock start pairing"));
|
||||
_network->publishBleAddress("");
|
||||
@@ -132,7 +139,7 @@ void NukiWrapper::update()
|
||||
Nuki::AuthorizationIdType::App :
|
||||
Nuki::AuthorizationIdType::Bridge;
|
||||
|
||||
if (_nukiLock.pairNuki(idType) == Nuki::PairingResult::Success)
|
||||
if(_nukiLock.pairNuki(idType) == Nuki::PairingResult::Success)
|
||||
{
|
||||
Log->println(F("Nuki paired"));
|
||||
_paired = true;
|
||||
@@ -228,7 +235,7 @@ void NukiWrapper::update()
|
||||
_retryCount = 0;
|
||||
_nextLockAction = (NukiLock::LockAction) 0xff;
|
||||
_network->publishRetry("--");
|
||||
if (_intervalLockstate > 10)
|
||||
if(_intervalLockstate > 10)
|
||||
{
|
||||
_nextLockStateUpdateTs = ts + 10 * 1000;
|
||||
}
|
||||
@@ -568,17 +575,21 @@ LockActionResult NukiWrapper::onLockActionReceivedCallback(const char *value)
|
||||
{
|
||||
NukiLock::LockAction action;
|
||||
|
||||
if(strlen(value) > 0)
|
||||
if(value)
|
||||
{
|
||||
action = nukiInst->lockActionToEnum(value);
|
||||
|
||||
if((int)action == 0xff)
|
||||
if(strlen(value) > 0)
|
||||
{
|
||||
return LockActionResult::UnknownAction;
|
||||
action = nukiInst->lockActionToEnum(value);
|
||||
|
||||
if((int)action == 0xff)
|
||||
{
|
||||
return LockActionResult::UnknownAction;
|
||||
}
|
||||
}
|
||||
else return LockActionResult::UnknownAction;
|
||||
}
|
||||
else return LockActionResult::UnknownAction;
|
||||
|
||||
|
||||
nukiLockPreferences = new Preferences();
|
||||
nukiLockPreferences->begin("nukihub", true);
|
||||
uint32_t aclPrefs[17];
|
||||
@@ -595,9 +606,631 @@ LockActionResult NukiWrapper::onLockActionReceivedCallback(const char *value)
|
||||
return LockActionResult::AccessDenied;
|
||||
}
|
||||
|
||||
void NukiWrapper::onConfigUpdateReceivedCallback(const char *topic, const char *value)
|
||||
void NukiWrapper::onConfigUpdateReceivedCallback(const char *value)
|
||||
{
|
||||
nukiInst->onConfigUpdateReceived(topic, value);
|
||||
nukiInst->onConfigUpdateReceived(value);
|
||||
}
|
||||
|
||||
Nuki::AdvertisingMode NukiWrapper::advertisingModeToEnum(const char *str)
|
||||
{
|
||||
if(strcmp(str, "Automatic") == 0) return Nuki::AdvertisingMode::Automatic;
|
||||
else if(strcmp(str, "Normal") == 0) return Nuki::AdvertisingMode::Normal;
|
||||
else if(strcmp(str, "Slow") == 0) return Nuki::AdvertisingMode::Slow;
|
||||
else if(strcmp(str, "Slowest") == 0) return Nuki::AdvertisingMode::Slowest;
|
||||
return (Nuki::AdvertisingMode)0xff;
|
||||
}
|
||||
|
||||
Nuki::TimeZoneId NukiWrapper::timeZoneToEnum(const char *str)
|
||||
{
|
||||
if(strcmp(str, "Africa/Cairo") == 0) return Nuki::TimeZoneId::Africa_Cairo;
|
||||
else if(strcmp(str, "Africa/Lagos") == 0) return Nuki::TimeZoneId::Africa_Lagos;
|
||||
else if(strcmp(str, "Africa/Maputo") == 0) return Nuki::TimeZoneId::Africa_Maputo;
|
||||
else if(strcmp(str, "Africa/Nairobi") == 0) return Nuki::TimeZoneId::Africa_Nairobi;
|
||||
else if(strcmp(str, "America/Anchorage") == 0) return Nuki::TimeZoneId::America_Anchorage;
|
||||
else if(strcmp(str, "America/Argentina/Buenos_Aires") == 0) return Nuki::TimeZoneId::America_Argentina_Buenos_Aires;
|
||||
else if(strcmp(str, "America/Chicago") == 0) return Nuki::TimeZoneId::America_Chicago;
|
||||
else if(strcmp(str, "America/Denver") == 0) return Nuki::TimeZoneId::America_Denver;
|
||||
else if(strcmp(str, "America/Halifax") == 0) return Nuki::TimeZoneId::America_Halifax;
|
||||
else if(strcmp(str, "America/Los_Angeles") == 0) return Nuki::TimeZoneId::America_Los_Angeles;
|
||||
else if(strcmp(str, "America/Manaus") == 0) return Nuki::TimeZoneId::America_Manaus;
|
||||
else if(strcmp(str, "America/Mexico_City") == 0) return Nuki::TimeZoneId::America_Mexico_City;
|
||||
else if(strcmp(str, "America/New_York") == 0) return Nuki::TimeZoneId::America_New_York;
|
||||
else if(strcmp(str, "America/Phoenix") == 0) return Nuki::TimeZoneId::America_Phoenix;
|
||||
else if(strcmp(str, "America/Regina") == 0) return Nuki::TimeZoneId::America_Regina;
|
||||
else if(strcmp(str, "America/Santiago") == 0) return Nuki::TimeZoneId::America_Santiago;
|
||||
else if(strcmp(str, "America/Sao_Paulo") == 0) return Nuki::TimeZoneId::America_Sao_Paulo;
|
||||
else if(strcmp(str, "America/St_Johns") == 0) return Nuki::TimeZoneId::America_St_Johns;
|
||||
else if(strcmp(str, "Asia/Bangkok") == 0) return Nuki::TimeZoneId::Asia_Bangkok;
|
||||
else if(strcmp(str, "Asia/Dubai") == 0) return Nuki::TimeZoneId::Asia_Dubai;
|
||||
else if(strcmp(str, "Asia/Hong_Kong") == 0) return Nuki::TimeZoneId::Asia_Hong_Kong;
|
||||
else if(strcmp(str, "Asia/Jerusalem") == 0) return Nuki::TimeZoneId::Asia_Jerusalem;
|
||||
else if(strcmp(str, "Asia/Karachi") == 0) return Nuki::TimeZoneId::Asia_Karachi;
|
||||
else if(strcmp(str, "Asia/Kathmandu") == 0) return Nuki::TimeZoneId::Asia_Kathmandu;
|
||||
else if(strcmp(str, "Asia/Kolkata") == 0) return Nuki::TimeZoneId::Asia_Kolkata;
|
||||
else if(strcmp(str, "Asia/Riyadh") == 0) return Nuki::TimeZoneId::Asia_Riyadh;
|
||||
else if(strcmp(str, "Asia/Seoul") == 0) return Nuki::TimeZoneId::Asia_Seoul;
|
||||
else if(strcmp(str, "Asia/Shanghai") == 0) return Nuki::TimeZoneId::Asia_Shanghai;
|
||||
else if(strcmp(str, "Asia/Tehran") == 0) return Nuki::TimeZoneId::Asia_Tehran;
|
||||
else if(strcmp(str, "Asia/Tokyo") == 0) return Nuki::TimeZoneId::Asia_Tokyo;
|
||||
else if(strcmp(str, "Asia/Yangon") == 0) return Nuki::TimeZoneId::Asia_Yangon;
|
||||
else if(strcmp(str, "Australia/Adelaide") == 0) return Nuki::TimeZoneId::Australia_Adelaide;
|
||||
else if(strcmp(str, "Australia/Brisbane") == 0) return Nuki::TimeZoneId::Australia_Brisbane;
|
||||
else if(strcmp(str, "Australia/Darwin") == 0) return Nuki::TimeZoneId::Australia_Darwin;
|
||||
else if(strcmp(str, "Australia/Hobart") == 0) return Nuki::TimeZoneId::Australia_Hobart;
|
||||
else if(strcmp(str, "Australia/Perth") == 0) return Nuki::TimeZoneId::Australia_Perth;
|
||||
else if(strcmp(str, "Australia/Sydney") == 0) return Nuki::TimeZoneId::Australia_Sydney;
|
||||
else if(strcmp(str, "Europe/Berlin") == 0) return Nuki::TimeZoneId::Europe_Berlin;
|
||||
else if(strcmp(str, "Europe/Helsinki") == 0) return Nuki::TimeZoneId::Europe_Helsinki;
|
||||
else if(strcmp(str, "Europe/Istanbul") == 0) return Nuki::TimeZoneId::Europe_Istanbul;
|
||||
else if(strcmp(str, "Europe/London") == 0) return Nuki::TimeZoneId::Europe_London;
|
||||
else if(strcmp(str, "Europe/Moscow") == 0) return Nuki::TimeZoneId::Europe_Moscow;
|
||||
else if(strcmp(str, "Pacific/Auckland") == 0) return Nuki::TimeZoneId::Pacific_Auckland;
|
||||
else if(strcmp(str, "Pacific/Guam") == 0) return Nuki::TimeZoneId::Pacific_Guam;
|
||||
else if(strcmp(str, "Pacific/Honolulu") == 0) return Nuki::TimeZoneId::Pacific_Honolulu;
|
||||
else if(strcmp(str, "Pacific/Pago_Pago") == 0) return Nuki::TimeZoneId::Pacific_Pago_Pago;
|
||||
else if(strcmp(str, "None") == 0) return Nuki::TimeZoneId::None;
|
||||
return (Nuki::TimeZoneId)0xff;
|
||||
}
|
||||
|
||||
uint8_t NukiWrapper::fobActionToInt(const char *str)
|
||||
{
|
||||
if(strcmp(str, "No Action") == 0) return 0;
|
||||
else if(strcmp(str, "Unlock") == 0) return 1;
|
||||
else if(strcmp(str, "Lock") == 0) return 2;
|
||||
else if(strcmp(str, "Lock n Go") == 0) return 3;
|
||||
else if(strcmp(str, "Intelligent") == 0) return 4;
|
||||
return 99;
|
||||
}
|
||||
|
||||
NukiLock::ButtonPressAction NukiWrapper::buttonPressActionToEnum(const char* str)
|
||||
{
|
||||
if(strcmp(str, "No Action") == 0) return NukiLock::ButtonPressAction::NoAction;
|
||||
else if(strcmp(str, "Intelligent") == 0) return NukiLock::ButtonPressAction::Intelligent;
|
||||
else if(strcmp(str, "Unlock") == 0) return NukiLock::ButtonPressAction::Unlock;
|
||||
else if(strcmp(str, "Lock") == 0) return NukiLock::ButtonPressAction::Lock;
|
||||
else if(strcmp(str, "Unlatch") == 0) return NukiLock::ButtonPressAction::Unlatch;
|
||||
else if(strcmp(str, "Lock n Go") == 0) return NukiLock::ButtonPressAction::LockNgo;
|
||||
else if(strcmp(str, "Show Status") == 0) return NukiLock::ButtonPressAction::ShowStatus;
|
||||
return (NukiLock::ButtonPressAction)0xff;
|
||||
}
|
||||
|
||||
Nuki::BatteryType NukiWrapper::batteryTypeToEnum(const char* str)
|
||||
{
|
||||
if(strcmp(str, "Alkali") == 0) return Nuki::BatteryType::Alkali;
|
||||
else if(strcmp(str, "Accumulators") == 0) return Nuki::BatteryType::Accumulators;
|
||||
else if(strcmp(str, "Lithium") == 0) return Nuki::BatteryType::Lithium;
|
||||
return (Nuki::BatteryType)0xff;
|
||||
}
|
||||
|
||||
void NukiWrapper::onConfigUpdateReceived(const char *value)
|
||||
{
|
||||
JsonDocument jsonResult;
|
||||
char _resbuf[2048];
|
||||
|
||||
if(_nukiLock.getSecurityPincode() == 0)
|
||||
{
|
||||
jsonResult["general"] = "noPinSet";
|
||||
serializeJson(jsonResult, _resbuf, sizeof(_resbuf));
|
||||
_network->publishConfigCommandResult(_resbuf);
|
||||
return;
|
||||
}
|
||||
|
||||
JsonDocument json;
|
||||
DeserializationError jsonError = deserializeJson(json, value);
|
||||
|
||||
if(jsonError)
|
||||
{
|
||||
jsonResult["general"] = "invalidJson";
|
||||
serializeJson(jsonResult, _resbuf, sizeof(_resbuf));
|
||||
_network->publishConfigCommandResult(_resbuf);
|
||||
return;
|
||||
}
|
||||
|
||||
Nuki::CmdResult cmdResult;
|
||||
const char *basicKeys[] = {"name", "latitude", "longitude", "autoUnlatch", "pairingEnabled", "buttonEnabled", "ledEnabled", "ledBrightness", "timeZoneOffset", "dstMode", "fobAction1", "fobAction2", "fobAction3", "singleLock", "advertisingMode", "timeZone"};
|
||||
const char *advancedKeys[] = {"unlockedPositionOffsetDegrees", "lockedPositionOffsetDegrees", "singleLockedPositionOffsetDegrees", "unlockedToLockedTransitionOffsetDegrees", "lockNgoTimeout", "singleButtonPressAction", "doubleButtonPressAction", "detachedCylinder", "batteryType", "automaticBatteryTypeDetection", "unlatchDuration", "autoLockTimeOut", "autoUnLockDisabled", "nightModeEnabled", "nightModeStartTime", "nightModeEndTime", "nightModeAutoLockEnabled", "nightModeAutoUnlockDisabled", "nightModeImmediateLockOnStart", "autoLockEnabled", "immediateAutoLockEnabled", "autoUpdateEnabled"};
|
||||
bool basicUpdated = false;
|
||||
bool advancedUpdated = false;
|
||||
uint32_t basicLockConfigAclPrefs[16];
|
||||
uint32_t advancedLockConfigAclPrefs[22];
|
||||
|
||||
nukiLockPreferences = new Preferences();
|
||||
nukiLockPreferences->begin("nukihub", true);
|
||||
nukiLockPreferences->getBytes(preference_conf_lock_basic_acl, &basicLockConfigAclPrefs, sizeof(basicLockConfigAclPrefs));
|
||||
nukiLockPreferences->getBytes(preference_conf_lock_advanced_acl, &advancedLockConfigAclPrefs, sizeof(advancedLockConfigAclPrefs));
|
||||
|
||||
for(int i=0; i < 16; i++)
|
||||
{
|
||||
if(json[basicKeys[i]])
|
||||
{
|
||||
const char *jsonchar = json[basicKeys[i]].as<const char*>();
|
||||
|
||||
if(strlen(jsonchar) == 0)
|
||||
{
|
||||
jsonResult[basicKeys[i]] = "noValueSet";
|
||||
continue;
|
||||
}
|
||||
|
||||
if((int)basicLockConfigAclPrefs[i] == 1)
|
||||
{
|
||||
cmdResult = Nuki::CmdResult::Error;
|
||||
|
||||
if(strcmp(basicKeys[i], "name") == 0)
|
||||
{
|
||||
if(strlen(jsonchar) <= 32)
|
||||
{
|
||||
if(strcmp((const char*)_nukiConfig.name, jsonchar) == 0) jsonResult[basicKeys[i]] = "unchanged";
|
||||
else cmdResult = _nukiLock.setName(std::string(jsonchar));
|
||||
}
|
||||
else jsonResult[basicKeys[i]] = "valueTooLong";
|
||||
}
|
||||
else if(strcmp(basicKeys[i], "latitude") == 0)
|
||||
{
|
||||
const float keyvalue = atof(jsonchar);
|
||||
|
||||
if(keyvalue > 0)
|
||||
{
|
||||
if(_nukiConfig.latitude == keyvalue) jsonResult[basicKeys[i]] = "unchanged";
|
||||
else cmdResult = _nukiLock.setLatitude(keyvalue);
|
||||
}
|
||||
else jsonResult[basicKeys[i]] = "invalidValue";
|
||||
}
|
||||
else if(strcmp(basicKeys[i], "longitude") == 0)
|
||||
{
|
||||
const float keyvalue = atof(jsonchar);
|
||||
|
||||
if(keyvalue > 0)
|
||||
{
|
||||
if(_nukiConfig.longitude == keyvalue) jsonResult[basicKeys[i]] = "unchanged";
|
||||
else cmdResult = _nukiLock.setLongitude(keyvalue);
|
||||
}
|
||||
else jsonResult[basicKeys[i]] = "invalidValue";
|
||||
}
|
||||
else if(strcmp(basicKeys[i], "autoUnlatch") == 0)
|
||||
{
|
||||
const uint8_t keyvalue = atoi(jsonchar);
|
||||
|
||||
if(keyvalue == 0 || keyvalue == 1)
|
||||
{
|
||||
if(_nukiConfig.autoUnlatch == keyvalue) jsonResult[basicKeys[i]] = "unchanged";
|
||||
else cmdResult = _nukiLock.enableAutoUnlatch((keyvalue > 0));
|
||||
}
|
||||
else jsonResult[basicKeys[i]] = "invalidValue";
|
||||
}
|
||||
else if(strcmp(basicKeys[i], "pairingEnabled") == 0)
|
||||
{
|
||||
const uint8_t keyvalue = atoi(jsonchar);
|
||||
|
||||
if(keyvalue == 0 || keyvalue == 1)
|
||||
{
|
||||
if(_nukiConfig.pairingEnabled == keyvalue) jsonResult[basicKeys[i]] = "unchanged";
|
||||
else cmdResult = _nukiLock.enablePairing((keyvalue > 0));
|
||||
}
|
||||
else jsonResult[basicKeys[i]] = "invalidValue";
|
||||
}
|
||||
else if(strcmp(basicKeys[i], "buttonEnabled") == 0)
|
||||
{
|
||||
const uint8_t keyvalue = atoi(jsonchar);
|
||||
|
||||
if(keyvalue == 0 || keyvalue == 1)
|
||||
{
|
||||
if(_nukiConfig.buttonEnabled == keyvalue) jsonResult[basicKeys[i]] = "unchanged";
|
||||
else cmdResult = _nukiLock.enableButton((keyvalue > 0));
|
||||
}
|
||||
else jsonResult[basicKeys[i]] = "invalidValue";
|
||||
}
|
||||
else if(strcmp(basicKeys[i], "ledEnabled") == 0)
|
||||
{
|
||||
const uint8_t keyvalue = atoi(jsonchar);
|
||||
|
||||
if(keyvalue == 0 || keyvalue == 1)
|
||||
{
|
||||
if(_nukiConfig.ledEnabled == keyvalue) jsonResult[basicKeys[i]] = "unchanged";
|
||||
else cmdResult = _nukiLock.enableLedFlash((keyvalue > 0));
|
||||
}
|
||||
else jsonResult[basicKeys[i]] = "invalidValue";
|
||||
}
|
||||
else if(strcmp(basicKeys[i], "ledBrightness") == 0)
|
||||
{
|
||||
const uint8_t keyvalue = atoi(jsonchar);
|
||||
|
||||
if(keyvalue >= 0 && keyvalue <= 5)
|
||||
{
|
||||
if(_nukiConfig.ledBrightness == keyvalue) jsonResult[basicKeys[i]] = "unchanged";
|
||||
else cmdResult = _nukiLock.setLedBrightness(keyvalue);
|
||||
}
|
||||
else jsonResult[basicKeys[i]] = "invalidValue";
|
||||
}
|
||||
else if(strcmp(basicKeys[i], "timeZoneOffset") == 0)
|
||||
{
|
||||
const int16_t keyvalue = atoi(jsonchar);
|
||||
|
||||
if(keyvalue >= 0 && keyvalue <= 60)
|
||||
{
|
||||
if(_nukiConfig.timeZoneOffset == keyvalue) jsonResult[basicKeys[i]] = "unchanged";
|
||||
else cmdResult = _nukiLock.setTimeZoneOffset(keyvalue);
|
||||
}
|
||||
else jsonResult[basicKeys[i]] = "invalidValue";
|
||||
}
|
||||
else if(strcmp(basicKeys[i], "dstMode") == 0)
|
||||
{
|
||||
const uint8_t keyvalue = atoi(jsonchar);
|
||||
|
||||
if(keyvalue == 0 || keyvalue == 1)
|
||||
{
|
||||
if(_nukiConfig.dstMode == keyvalue) jsonResult[basicKeys[i]] = "unchanged";
|
||||
else cmdResult = _nukiLock.enableDst((keyvalue > 0));
|
||||
}
|
||||
else jsonResult[basicKeys[i]] = "invalidValue";
|
||||
}
|
||||
else if(strcmp(basicKeys[i], "fobAction1") == 0)
|
||||
{
|
||||
const uint8_t fobAct1 = nukiInst->fobActionToInt(jsonchar);
|
||||
|
||||
if(fobAct1 != 99)
|
||||
{
|
||||
if(_nukiConfig.fobAction1 == fobAct1) jsonResult[basicKeys[i]] = "unchanged";
|
||||
else cmdResult = _nukiLock.setFobAction(1, fobAct1);
|
||||
}
|
||||
else jsonResult[basicKeys[i]] = "invalidValue";
|
||||
}
|
||||
else if(strcmp(basicKeys[i], "fobAction2") == 0)
|
||||
{
|
||||
const uint8_t fobAct2 = nukiInst->fobActionToInt(jsonchar);
|
||||
|
||||
if(fobAct2 != 99)
|
||||
{
|
||||
if(_nukiConfig.fobAction2 == fobAct2) jsonResult[basicKeys[i]] = "unchanged";
|
||||
else cmdResult = _nukiLock.setFobAction(2, fobAct2);
|
||||
}
|
||||
else jsonResult[basicKeys[i]] = "invalidValue";
|
||||
}
|
||||
else if(strcmp(basicKeys[i], "fobAction3") == 0)
|
||||
{
|
||||
const uint8_t fobAct3 = nukiInst->fobActionToInt(jsonchar);
|
||||
|
||||
if(fobAct3 != 99)
|
||||
{
|
||||
if(_nukiConfig.fobAction3 == fobAct3) jsonResult[basicKeys[i]] = "unchanged";
|
||||
else cmdResult = _nukiLock.setFobAction(3, fobAct3);
|
||||
}
|
||||
else jsonResult[basicKeys[i]] = "invalidValue";
|
||||
}
|
||||
else if(strcmp(basicKeys[i], "singleLock") == 0)
|
||||
{
|
||||
const uint8_t keyvalue = atoi(jsonchar);
|
||||
|
||||
if(keyvalue == 0 || keyvalue == 1)
|
||||
{
|
||||
if(_nukiConfig.singleLock == keyvalue) jsonResult[basicKeys[i]] = "unchanged";
|
||||
else cmdResult = _nukiLock.enableSingleLock((keyvalue > 0));
|
||||
}
|
||||
else jsonResult[basicKeys[i]] = "invalidValue";
|
||||
}
|
||||
else if(strcmp(basicKeys[i], "advertisingMode") == 0)
|
||||
{
|
||||
Nuki::AdvertisingMode advmode = nukiInst->advertisingModeToEnum(jsonchar);
|
||||
|
||||
if((int)advmode != 0xff)
|
||||
{
|
||||
if(_nukiConfig.advertisingMode == advmode) jsonResult[basicKeys[i]] = "unchanged";
|
||||
else cmdResult = _nukiLock.setAdvertisingMode(advmode);
|
||||
}
|
||||
else jsonResult[basicKeys[i]] = "invalidValue";
|
||||
}
|
||||
else if(strcmp(basicKeys[i], "timeZone") == 0)
|
||||
{
|
||||
Nuki::TimeZoneId tzid = nukiInst->timeZoneToEnum(jsonchar);
|
||||
|
||||
if((int)tzid != 0xff)
|
||||
{
|
||||
if(_nukiConfig.timeZoneId == tzid) jsonResult[basicKeys[i]] = "unchanged";
|
||||
else cmdResult = _nukiLock.setTimeZoneId(tzid);
|
||||
}
|
||||
else jsonResult[basicKeys[i]] = "invalidValue";
|
||||
}
|
||||
|
||||
if(cmdResult == Nuki::CmdResult::Success) basicUpdated = true;
|
||||
|
||||
if(!jsonResult[basicKeys[i]]) {
|
||||
char resultStr[15] = {0};
|
||||
NukiLock::cmdResultToString(cmdResult, resultStr);
|
||||
jsonResult[basicKeys[i]] = resultStr;
|
||||
}
|
||||
}
|
||||
else jsonResult[basicKeys[i]] = "accessDenied";
|
||||
}
|
||||
}
|
||||
|
||||
for(int i=0; i < 22; i++)
|
||||
{
|
||||
if(json[advancedKeys[i]])
|
||||
{
|
||||
const char *jsonchar = json[advancedKeys[i]].as<const char*>();
|
||||
|
||||
if(strlen(jsonchar) == 0)
|
||||
{
|
||||
jsonResult[advancedKeys[i]] = "noValueSet";
|
||||
continue;
|
||||
}
|
||||
|
||||
if((int)advancedLockConfigAclPrefs[i] == 1)
|
||||
{
|
||||
cmdResult = Nuki::CmdResult::Error;
|
||||
|
||||
if(strcmp(advancedKeys[i], "unlockedPositionOffsetDegrees") == 0)
|
||||
{
|
||||
const int16_t keyvalue = atoi(jsonchar);
|
||||
|
||||
if(keyvalue >= -90 && keyvalue <= 180)
|
||||
{
|
||||
if(_nukiAdvancedConfig.unlockedPositionOffsetDegrees == keyvalue) jsonResult[advancedKeys[i]] = "unchanged";
|
||||
else cmdResult = _nukiLock.setUnlockedPositionOffsetDegrees(keyvalue);
|
||||
}
|
||||
else jsonResult[advancedKeys[i]] = "invalidValue";
|
||||
}
|
||||
else if(strcmp(advancedKeys[i], "lockedPositionOffsetDegrees") == 0)
|
||||
{
|
||||
const int16_t keyvalue = atoi(jsonchar);
|
||||
|
||||
if(keyvalue >= -180 && keyvalue <= 90)
|
||||
{
|
||||
if(_nukiAdvancedConfig.lockedPositionOffsetDegrees == keyvalue) jsonResult[advancedKeys[i]] = "unchanged";
|
||||
else cmdResult = _nukiLock.setLockedPositionOffsetDegrees(keyvalue);
|
||||
}
|
||||
else jsonResult[advancedKeys[i]] = "invalidValue";
|
||||
}
|
||||
else if(strcmp(advancedKeys[i], "singleLockedPositionOffsetDegrees") == 0)
|
||||
{
|
||||
const int16_t keyvalue = atoi(jsonchar);
|
||||
|
||||
if(keyvalue >= -180 && keyvalue <= 180)
|
||||
{
|
||||
if(_nukiAdvancedConfig.singleLockedPositionOffsetDegrees == keyvalue) jsonResult[advancedKeys[i]] = "unchanged";
|
||||
else cmdResult = _nukiLock.setSingleLockedPositionOffsetDegrees(keyvalue);
|
||||
}
|
||||
else jsonResult[advancedKeys[i]] = "invalidValue";
|
||||
}
|
||||
else if(strcmp(advancedKeys[i], "unlockedToLockedTransitionOffsetDegrees") == 0)
|
||||
{
|
||||
const int16_t keyvalue = atoi(jsonchar);
|
||||
|
||||
if(keyvalue >= -180 && keyvalue <= 180)
|
||||
{
|
||||
if(_nukiAdvancedConfig.unlockedToLockedTransitionOffsetDegrees == keyvalue) jsonResult[advancedKeys[i]] = "unchanged";
|
||||
else cmdResult = _nukiLock.setUnlockedToLockedTransitionOffsetDegrees(keyvalue);
|
||||
}
|
||||
else jsonResult[advancedKeys[i]] = "invalidValue";
|
||||
}
|
||||
else if(strcmp(advancedKeys[i], "lockNgoTimeout") == 0)
|
||||
{
|
||||
const uint8_t keyvalue = atoi(jsonchar);
|
||||
|
||||
if(keyvalue >= 5 && keyvalue <= 60)
|
||||
{
|
||||
if(_nukiAdvancedConfig.lockNgoTimeout == keyvalue) jsonResult[advancedKeys[i]] = "unchanged";
|
||||
else cmdResult = _nukiLock.setLockNgoTimeout(keyvalue);
|
||||
}
|
||||
else jsonResult[advancedKeys[i]] = "invalidValue";
|
||||
}
|
||||
else if(strcmp(advancedKeys[i], "singleButtonPressAction") == 0)
|
||||
{
|
||||
NukiLock::ButtonPressAction sbpa = nukiInst->buttonPressActionToEnum(jsonchar);
|
||||
|
||||
if((int)sbpa != 0xff)
|
||||
{
|
||||
if(_nukiAdvancedConfig.singleButtonPressAction == sbpa) jsonResult[advancedKeys[i]] = "unchanged";
|
||||
else cmdResult = _nukiLock.setSingleButtonPressAction(sbpa);
|
||||
}
|
||||
else jsonResult[advancedKeys[i]] = "invalidValue";
|
||||
}
|
||||
else if(strcmp(advancedKeys[i], "doubleButtonPressAction") == 0)
|
||||
{
|
||||
NukiLock::ButtonPressAction dbpa = nukiInst->buttonPressActionToEnum(jsonchar);
|
||||
|
||||
if((int)dbpa != 0xff)
|
||||
{
|
||||
if(_nukiAdvancedConfig.doubleButtonPressAction == dbpa) jsonResult[advancedKeys[i]] = "unchanged";
|
||||
else cmdResult = _nukiLock.setDoubleButtonPressAction(dbpa);
|
||||
}
|
||||
else jsonResult[advancedKeys[i]] = "invalidValue";
|
||||
}
|
||||
else if(strcmp(advancedKeys[i], "detachedCylinder") == 0)
|
||||
{
|
||||
const uint8_t keyvalue = atoi(jsonchar);
|
||||
|
||||
if(keyvalue == 0 || keyvalue == 1)
|
||||
{
|
||||
if(_nukiAdvancedConfig.detachedCylinder == keyvalue) jsonResult[advancedKeys[i]] = "unchanged";
|
||||
else cmdResult = _nukiLock.enableDetachedCylinder((keyvalue > 0));
|
||||
}
|
||||
else jsonResult[advancedKeys[i]] = "invalidValue";
|
||||
}
|
||||
else if(strcmp(advancedKeys[i], "batteryType") == 0)
|
||||
{
|
||||
Nuki::BatteryType battype = nukiInst->batteryTypeToEnum(jsonchar);
|
||||
|
||||
if((int)battype != 0xff)
|
||||
{
|
||||
if(_nukiAdvancedConfig.batteryType == battype) jsonResult[advancedKeys[i]] = "unchanged";
|
||||
else cmdResult = _nukiLock.setBatteryType(battype);
|
||||
}
|
||||
else jsonResult[advancedKeys[i]] = "invalidValue";
|
||||
}
|
||||
else if(strcmp(advancedKeys[i], "automaticBatteryTypeDetection") == 0)
|
||||
{
|
||||
const uint8_t keyvalue = atoi(jsonchar);
|
||||
|
||||
if(keyvalue == 0 || keyvalue == 1)
|
||||
{
|
||||
if(_nukiAdvancedConfig.automaticBatteryTypeDetection == keyvalue) jsonResult[advancedKeys[i]] = "unchanged";
|
||||
else cmdResult = _nukiLock.enableAutoBatteryTypeDetection((keyvalue > 0));
|
||||
}
|
||||
else jsonResult[advancedKeys[i]] = "invalidValue";
|
||||
}
|
||||
else if(strcmp(advancedKeys[i], "unlatchDuration") == 0)
|
||||
{
|
||||
const uint8_t keyvalue = atoi(jsonchar);
|
||||
|
||||
if(keyvalue >= 1 && keyvalue <= 30)
|
||||
{
|
||||
if(_nukiAdvancedConfig.unlatchDuration == keyvalue) jsonResult[advancedKeys[i]] = "unchanged";
|
||||
else cmdResult = _nukiLock.setUnlatchDuration(keyvalue);
|
||||
}
|
||||
else jsonResult[advancedKeys[i]] = "invalidValue";
|
||||
}
|
||||
else if(strcmp(advancedKeys[i], "autoLockTimeOut") == 0)
|
||||
{
|
||||
const uint8_t keyvalue = atoi(jsonchar);
|
||||
|
||||
if(keyvalue >= 30 && keyvalue <= 180)
|
||||
{
|
||||
if(_nukiAdvancedConfig.autoLockTimeOut == keyvalue) jsonResult[advancedKeys[i]] = "unchanged";
|
||||
else cmdResult = _nukiLock.setAutoLockTimeOut(keyvalue);
|
||||
}
|
||||
else jsonResult[advancedKeys[i]] = "invalidValue";
|
||||
}
|
||||
else if(strcmp(advancedKeys[i], "autoUnLockDisabled") == 0)
|
||||
{
|
||||
const uint8_t keyvalue = atoi(jsonchar);
|
||||
|
||||
if(keyvalue == 0 || keyvalue == 1)
|
||||
{
|
||||
if(_nukiAdvancedConfig.autoUnLockDisabled == keyvalue) jsonResult[advancedKeys[i]] = "unchanged";
|
||||
else cmdResult = _nukiLock.disableAutoUnlock((keyvalue > 0));
|
||||
}
|
||||
else jsonResult[advancedKeys[i]] = "invalidValue";
|
||||
}
|
||||
else if(strcmp(advancedKeys[i], "nightModeEnabled") == 0)
|
||||
{
|
||||
const uint8_t keyvalue = atoi(jsonchar);
|
||||
|
||||
if(keyvalue == 0 || keyvalue == 1)
|
||||
{
|
||||
if(_nukiAdvancedConfig.nightModeEnabled == keyvalue) jsonResult[advancedKeys[i]] = "unchanged";
|
||||
else cmdResult = _nukiLock.enableNightMode((keyvalue > 0));
|
||||
}
|
||||
else jsonResult[advancedKeys[i]] = "invalidValue";
|
||||
}
|
||||
else if(strcmp(advancedKeys[i], "nightModeStartTime") == 0)
|
||||
{
|
||||
String keystr = jsonchar;
|
||||
unsigned char keyvalue[2];
|
||||
keyvalue[0] = (uint8_t)keystr.substring(0, 2).toInt();
|
||||
keyvalue[1] = (uint8_t)keystr.substring(3, 5).toInt();
|
||||
if(keyvalue[0] >= 0 && keyvalue[0] <= 23 && keyvalue[1] >= 0 && keyvalue[1] <= 59)
|
||||
{
|
||||
if(_nukiAdvancedConfig.nightModeStartTime == keyvalue) jsonResult[advancedKeys[i]] = "unchanged";
|
||||
else cmdResult = _nukiLock.setNightModeStartTime(keyvalue);
|
||||
}
|
||||
else jsonResult[advancedKeys[i]] = "invalidValue";
|
||||
}
|
||||
else if(strcmp(advancedKeys[i], "nightModeEndTime") == 0)
|
||||
{
|
||||
String keystr = jsonchar;
|
||||
unsigned char keyvalue[2];
|
||||
keyvalue[0] = (uint8_t)keystr.substring(0, 2).toInt();
|
||||
keyvalue[1] = (uint8_t)keystr.substring(3, 5).toInt();
|
||||
if(keyvalue[0] >= 0 && keyvalue[0] <= 23 && keyvalue[1] >= 0 && keyvalue[1] <= 59)
|
||||
{
|
||||
if(_nukiAdvancedConfig.nightModeEndTime == keyvalue) jsonResult[advancedKeys[i]] = "unchanged";
|
||||
else cmdResult = _nukiLock.setNightModeEndTime(keyvalue);
|
||||
}
|
||||
else jsonResult[advancedKeys[i]] = "invalidValue";
|
||||
}
|
||||
else if(strcmp(advancedKeys[i], "nightModeAutoLockEnabled") == 0)
|
||||
{
|
||||
const uint8_t keyvalue = atoi(jsonchar);
|
||||
|
||||
if(keyvalue == 0 || keyvalue == 1)
|
||||
{
|
||||
if(_nukiAdvancedConfig.nightModeAutoLockEnabled == keyvalue) jsonResult[advancedKeys[i]] = "unchanged";
|
||||
else cmdResult = _nukiLock.enableNightModeAutoLock((keyvalue > 0));
|
||||
}
|
||||
else jsonResult[advancedKeys[i]] = "invalidValue";
|
||||
}
|
||||
else if(strcmp(advancedKeys[i], "nightModeAutoUnlockDisabled") == 0)
|
||||
{
|
||||
const uint8_t keyvalue = atoi(jsonchar);
|
||||
|
||||
if(keyvalue == 0 || keyvalue == 1)
|
||||
{
|
||||
if(_nukiAdvancedConfig.nightModeAutoUnlockDisabled == keyvalue) jsonResult[advancedKeys[i]] = "unchanged";
|
||||
else cmdResult = _nukiLock.disableNightModeAutoUnlock((keyvalue > 0));
|
||||
}
|
||||
else jsonResult[advancedKeys[i]] = "invalidValue";
|
||||
}
|
||||
else if(strcmp(advancedKeys[i], "nightModeImmediateLockOnStart") == 0)
|
||||
{
|
||||
const uint8_t keyvalue = atoi(jsonchar);
|
||||
|
||||
if(keyvalue == 0 || keyvalue == 1)
|
||||
{
|
||||
if(_nukiAdvancedConfig.nightModeImmediateLockOnStart == keyvalue) jsonResult[advancedKeys[i]] = "unchanged";
|
||||
else cmdResult = _nukiLock.enableNightModeImmediateLockOnStart((keyvalue > 0));
|
||||
}
|
||||
else jsonResult[advancedKeys[i]] = "invalidValue";
|
||||
}
|
||||
else if(strcmp(advancedKeys[i], "autoLockEnabled") == 0)
|
||||
{
|
||||
const uint8_t keyvalue = atoi(jsonchar);
|
||||
|
||||
if(keyvalue == 0 || keyvalue == 1)
|
||||
{
|
||||
if(_nukiAdvancedConfig.autoLockEnabled == keyvalue) jsonResult[advancedKeys[i]] = "unchanged";
|
||||
else cmdResult = _nukiLock.enableAutoLock((keyvalue > 0));
|
||||
}
|
||||
else jsonResult[advancedKeys[i]] = "invalidValue";
|
||||
}
|
||||
else if(strcmp(advancedKeys[i], "immediateAutoLockEnabled") == 0)
|
||||
{
|
||||
const uint8_t keyvalue = atoi(jsonchar);
|
||||
|
||||
if(keyvalue == 0 || keyvalue == 1)
|
||||
{
|
||||
if(_nukiAdvancedConfig.immediateAutoLockEnabled == keyvalue) jsonResult[advancedKeys[i]] = "unchanged";
|
||||
else cmdResult = _nukiLock.enableImmediateAutoLock((keyvalue > 0));
|
||||
}
|
||||
else jsonResult[advancedKeys[i]] = "invalidValue";
|
||||
}
|
||||
else if(strcmp(advancedKeys[i], "autoUpdateEnabled") == 0)
|
||||
{
|
||||
const uint8_t keyvalue = atoi(jsonchar);
|
||||
|
||||
if(keyvalue == 0 || keyvalue == 1)
|
||||
{
|
||||
if(_nukiAdvancedConfig.autoUpdateEnabled == keyvalue) jsonResult[advancedKeys[i]] = "unchanged";
|
||||
else cmdResult = _nukiLock.enableAutoUpdate((keyvalue > 0));
|
||||
}
|
||||
else jsonResult[advancedKeys[i]] = "invalidValue";
|
||||
}
|
||||
|
||||
if(cmdResult == Nuki::CmdResult::Success) advancedUpdated = true;
|
||||
|
||||
if(!jsonResult[advancedKeys[i]]) {
|
||||
char resultStr[15] = {0};
|
||||
NukiLock::cmdResultToString(cmdResult, resultStr);
|
||||
jsonResult[advancedKeys[i]] = resultStr;
|
||||
}
|
||||
}
|
||||
else jsonResult[advancedKeys[i]] = "accessDenied";
|
||||
}
|
||||
}
|
||||
|
||||
nukiLockPreferences->end();
|
||||
|
||||
if(basicUpdated || advancedUpdated)
|
||||
{
|
||||
jsonResult["general"] = "success";
|
||||
}
|
||||
else jsonResult["general"] = "noChange";
|
||||
|
||||
_nextConfigUpdateTs = millis() + 300;
|
||||
|
||||
serializeJson(jsonResult, _resbuf, sizeof(_resbuf));
|
||||
_network->publishConfigCommandResult(_resbuf);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void NukiWrapper::onKeypadCommandReceivedCallback(const char *command, const uint &id, const String &name, const String &code, const int& enabled)
|
||||
@@ -637,54 +1270,6 @@ void NukiWrapper::gpioActionCallback(const GpioAction &action, const int& pin)
|
||||
}
|
||||
}
|
||||
|
||||
void NukiWrapper::onConfigUpdateReceived(const char *topic, const char *value)
|
||||
{
|
||||
if(!_preferences->getBool(preference_admin_enabled)) return;
|
||||
|
||||
if(strcmp(topic, mqtt_topic_config_button_enabled) == 0)
|
||||
{
|
||||
bool newValue = atoi(value) > 0;
|
||||
if(!_nukiConfigValid || _nukiConfig.buttonEnabled == newValue) return;
|
||||
_nukiLock.enableButton(newValue);
|
||||
_nextConfigUpdateTs = millis() + 300;
|
||||
}
|
||||
if(strcmp(topic, mqtt_topic_config_led_enabled) == 0)
|
||||
{
|
||||
bool newValue = atoi(value) > 0;
|
||||
if(!_nukiConfigValid || _nukiConfig.ledEnabled == newValue) return;
|
||||
_nukiLock.enableLedFlash(newValue);
|
||||
_nextConfigUpdateTs = millis() + 300;
|
||||
}
|
||||
else if(strcmp(topic, mqtt_topic_config_led_brightness) == 0)
|
||||
{
|
||||
int newValue = atoi(value);
|
||||
if(!_nukiConfigValid || _nukiConfig.ledBrightness == newValue) return;
|
||||
_nukiLock.setLedBrightness(newValue);
|
||||
_nextConfigUpdateTs = millis() + 300;
|
||||
}
|
||||
if(strcmp(topic, mqtt_topic_config_single_lock) == 0)
|
||||
{
|
||||
bool newValue = atoi(value) > 0;
|
||||
if(!_nukiConfigValid || _nukiConfig.singleLock == newValue) return;
|
||||
_nukiLock.enableSingleLock(newValue);
|
||||
_nextConfigUpdateTs = millis() + 300;
|
||||
}
|
||||
else if(strcmp(topic, mqtt_topic_config_auto_unlock) == 0)
|
||||
{
|
||||
bool newValue = !(atoi(value) > 0);
|
||||
if(!_nukiAdvancedConfigValid || _nukiAdvancedConfig.autoUnLockDisabled == newValue) return;
|
||||
_nukiLock.disableAutoUnlock(newValue);
|
||||
_nextConfigUpdateTs = millis() + 300;
|
||||
}
|
||||
else if(strcmp(topic, mqtt_topic_config_auto_lock) == 0)
|
||||
{
|
||||
bool newValue = atoi(value) > 0;
|
||||
if(!_nukiAdvancedConfigValid || _nukiAdvancedConfig.autoLockEnabled == newValue) return;
|
||||
_nukiLock.enableAutoLock(newValue);
|
||||
_nextConfigUpdateTs = millis() + 300;
|
||||
}
|
||||
}
|
||||
|
||||
void NukiWrapper::onKeypadCommandReceived(const char *command, const uint &id, const String &name, const String &code, const int& enabled)
|
||||
{
|
||||
if(!_preferences->getBool(preference_keypad_control_enabled))
|
||||
@@ -823,21 +1408,7 @@ void NukiWrapper::onKeypadJsonCommandReceived(const char *value)
|
||||
_network->publishKeypadJsonCommandResult("keypadNotAvailable");
|
||||
return;
|
||||
}
|
||||
|
||||
updateConfig();
|
||||
|
||||
while (!_nukiConfigValid && _retryConfigCount < 11)
|
||||
{
|
||||
updateConfig();
|
||||
}
|
||||
|
||||
if(_configRead && _nukiConfigValid)
|
||||
{
|
||||
_network->publishKeypadJsonCommandResult("keypadNotAvailable");
|
||||
return;
|
||||
}
|
||||
|
||||
_network->publishKeypadJsonCommandResult("invalidConfig");
|
||||
_network->publishKeypadJsonCommandResult("configNotReady");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -923,7 +1494,7 @@ void NukiWrapper::onKeypadJsonCommandReceived(const char *value)
|
||||
unsigned int allowedUntilTimeAr[2];
|
||||
uint8_t allowedWeekdaysInt = 0;
|
||||
|
||||
if(timeLimited == 1 && enabled != 0)
|
||||
if(timeLimited == 1)
|
||||
{
|
||||
if(allowedFrom)
|
||||
{
|
||||
@@ -1075,6 +1646,18 @@ void NukiWrapper::onKeypadJsonCommandReceived(const char *value)
|
||||
}
|
||||
else if (strcmp(action, "update") == 0)
|
||||
{
|
||||
if(!codeId)
|
||||
{
|
||||
_network->publishKeypadJsonCommandResult("noCodeIdSet");
|
||||
return;
|
||||
}
|
||||
|
||||
if(!idExists)
|
||||
{
|
||||
_network->publishKeypadJsonCommandResult("noExistingCodeIdSet");
|
||||
return;
|
||||
}
|
||||
|
||||
NukiLock::UpdatedKeypadEntry entry;
|
||||
memset(&entry, 0, sizeof(entry));
|
||||
entry.codeId = codeId;
|
||||
@@ -1179,9 +1762,8 @@ void NukiWrapper::onTimeControlCommandReceived(const char *value)
|
||||
const char *lockAct = json["lockAction"].as<const char*>();
|
||||
NukiLock::LockAction timeControlLockAction;
|
||||
|
||||
if(strlen(lockAct) > 0)
|
||||
if(lockAct)
|
||||
{
|
||||
|
||||
timeControlLockAction = nukiInst->lockActionToEnum(lockAct);
|
||||
|
||||
if((int)timeControlLockAction == 0xff)
|
||||
@@ -1190,12 +1772,7 @@ void NukiWrapper::onTimeControlCommandReceived(const char *value)
|
||||
return;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
_network->publishTimeControlCommandResult("invalidLockAction");
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if(action)
|
||||
{
|
||||
bool idExists = false;
|
||||
@@ -1279,6 +1856,12 @@ void NukiWrapper::onTimeControlCommandReceived(const char *value)
|
||||
}
|
||||
else if (strcmp(action, "update") == 0)
|
||||
{
|
||||
if(!idExists)
|
||||
{
|
||||
_network->publishTimeControlCommandResult("noExistingEntryIdSet");
|
||||
return;
|
||||
}
|
||||
|
||||
NukiLock::TimeControlEntry entry;
|
||||
memset(&entry, 0, sizeof(entry));
|
||||
entry.entryId = entryId;
|
||||
@@ -1373,7 +1956,7 @@ void NukiWrapper::setupHASS()
|
||||
char uidString[20];
|
||||
itoa(_nukiConfig.nukiId, uidString, 16);
|
||||
|
||||
_network->publishHASSConfig("SmartLock", baseTopic.c_str(),(char*)_nukiConfig.name, uidString, hasDoorSensor(), _hasKeypad, _publishAuthData, "lock", "unlock", "unlatch");
|
||||
_network->publishHASSConfig((char*)"SmartLock", baseTopic.c_str(),(char*)_nukiConfig.name, uidString, hasDoorSensor(), _hasKeypad, _publishAuthData, (char*)"lock", (char*)"unlock", (char*)"unlatch");
|
||||
_hassSetupCompleted = true;
|
||||
|
||||
Log->println("HASS setup for lock completed.");
|
||||
@@ -1393,7 +1976,7 @@ void NukiWrapper::disableHASS()
|
||||
Nuki::CmdResult result = _nukiLock.requestConfig(&_nukiConfig);
|
||||
_nukiConfigValid = result == Nuki::CmdResult::Success;
|
||||
}
|
||||
if (_nukiConfigValid)
|
||||
if(_nukiConfigValid)
|
||||
{
|
||||
char uidString[20];
|
||||
itoa(_nukiConfig.nukiId, uidString, 16);
|
||||
|
||||
@@ -45,14 +45,13 @@ public:
|
||||
|
||||
private:
|
||||
static LockActionResult onLockActionReceivedCallback(const char* value);
|
||||
static void onConfigUpdateReceivedCallback(const char* topic, const char* value);
|
||||
static void onConfigUpdateReceivedCallback(const char* value);
|
||||
static void onKeypadCommandReceivedCallback(const char* command, const uint& id, const String& name, const String& code, const int& enabled);
|
||||
static void onKeypadJsonCommandReceivedCallback(const char* value);
|
||||
static void onTimeControlCommandReceivedCallback(const char* value);
|
||||
static void gpioActionCallback(const GpioAction& action, const int& pin);
|
||||
|
||||
void onConfigUpdateReceived(const char* topic, const char* value);
|
||||
void onKeypadCommandReceived(const char* command, const uint& id, const String& name, const String& code, const int& enabled);
|
||||
void onConfigUpdateReceived(const char* value);
|
||||
void onKeypadJsonCommandReceived(const char* value);
|
||||
void onTimeControlCommandReceived(const char* value);
|
||||
|
||||
@@ -74,6 +73,11 @@ private:
|
||||
void printCommandResult(Nuki::CmdResult result);
|
||||
|
||||
NukiLock::LockAction lockActionToEnum(const char* str); // char array at least 14 characters
|
||||
Nuki::AdvertisingMode advertisingModeToEnum(const char* str);
|
||||
Nuki::TimeZoneId timeZoneToEnum(const char* str);
|
||||
uint8_t fobActionToInt(const char *str);
|
||||
NukiLock::ButtonPressAction buttonPressActionToEnum(const char* str);
|
||||
Nuki::BatteryType batteryTypeToEnum(const char* str);
|
||||
|
||||
std::string _deviceName;
|
||||
NukiDeviceId* _deviceId = nullptr;
|
||||
|
||||
@@ -2,72 +2,75 @@
|
||||
|
||||
#include <vector>
|
||||
|
||||
#define preference_started_before "run"
|
||||
#define preference_config_version "confVersion"
|
||||
#define preference_device_id_lock "deviceId"
|
||||
#define preference_device_id_opener "deviceIdOp"
|
||||
#define preference_nuki_id_lock "nukiId"
|
||||
#define preference_nuki_id_opener "nukidOp"
|
||||
#define preference_mqtt_broker "mqttbroker"
|
||||
#define preference_mqtt_broker_port "mqttport"
|
||||
#define preference_mqtt_user "mqttuser"
|
||||
#define preference_mqtt_password "mqttpass"
|
||||
#define preference_mqtt_log_enabled "mqttlog"
|
||||
#define preference_lock_enabled "lockena"
|
||||
#define preference_lock_pin_status "lockpin"
|
||||
#define preference_mqtt_lock_path "mqttpath"
|
||||
#define preference_opener_enabled "openerena"
|
||||
#define preference_opener_pin_status "openerpin"
|
||||
#define preference_opener_continuous_mode "openercont"
|
||||
#define preference_mqtt_opener_path "mqttoppath"
|
||||
#define preference_check_updates "checkupdates"
|
||||
#define preference_lock_max_keypad_code_count "maxkpad"
|
||||
#define preference_opener_max_keypad_code_count "opmaxkpad"
|
||||
#define preference_mqtt_ca "mqttca"
|
||||
#define preference_mqtt_crt "mqttcrt"
|
||||
#define preference_mqtt_key "mqttkey"
|
||||
#define preference_mqtt_hass_discovery "hassdiscovery"
|
||||
#define preference_mqtt_hass_cu_url "hassConfigUrl"
|
||||
#define preference_ip_dhcp_enabled "dhcpena"
|
||||
#define preference_ip_address "ipaddr"
|
||||
#define preference_ip_subnet "ipsub"
|
||||
#define preference_ip_gateway "ipgtw"
|
||||
#define preference_ip_dns_server "dnssrv"
|
||||
#define preference_network_hardware "nwhw"
|
||||
#define preference_network_hardware_gpio "nwhwdt" // obsolete
|
||||
#define preference_network_wifi_fallback_disabled "nwwififb"
|
||||
#define preference_rssi_publish_interval "rssipb"
|
||||
#define preference_hostname "hostname"
|
||||
#define preference_network_timeout "nettmout"
|
||||
#define preference_restart_on_disconnect "restdisc"
|
||||
#define preference_restart_timer "resttmr"
|
||||
#define preference_restart_ble_beacon_lost "rstbcn"
|
||||
#define preference_query_interval_lockstate "lockStInterval"
|
||||
#define preference_query_interval_configuration "configInterval"
|
||||
#define preference_query_interval_battery "batInterval"
|
||||
#define preference_query_interval_keypad "kpInterval"
|
||||
#define preference_access_level "accLvl"
|
||||
#define preference_admin_enabled "aclConfig"
|
||||
#define preference_keypad_info_enabled "kpInfoEnabled"
|
||||
#define preference_keypad_control_enabled "kpCntrlEnabled"
|
||||
#define preference_timecontrol_control_enabled "tcCntrlEnabled"
|
||||
#define preference_timecontrol_info_enabled "tcInfoEnabled"
|
||||
#define preference_publish_authdata "pubAuth"
|
||||
#define preference_acl "aclLckOpn"
|
||||
#define preference_register_as_app "regAsApp" // true = register as hub; false = register as app
|
||||
#define preference_command_nr_of_retries "nrRetry"
|
||||
#define preference_command_retry_delay "rtryDelay"
|
||||
#define preference_cred_user "crdusr"
|
||||
#define preference_cred_password "crdpass"
|
||||
#define preference_gpio_locking_enabled "gpiolck" // obsolete
|
||||
#define preference_gpio_configuration "gpiocfg"
|
||||
#define preference_publish_debug_info "pubdbg"
|
||||
#define preference_presence_detection_timeout "prdtimeout"
|
||||
#define preference_has_mac_saved "hasmac"
|
||||
#define preference_has_mac_byte_0 "macb0"
|
||||
#define preference_has_mac_byte_1 "macb1"
|
||||
#define preference_has_mac_byte_2 "macb2"
|
||||
#define preference_latest_version "latest"
|
||||
#define preference_started_before (char*)"run"
|
||||
#define preference_config_version (char*)"confVersion"
|
||||
#define preference_device_id_lock (char*)"deviceId"
|
||||
#define preference_device_id_opener (char*)"deviceIdOp"
|
||||
#define preference_nuki_id_lock (char*)"nukiId"
|
||||
#define preference_nuki_id_opener (char*)"nukidOp"
|
||||
#define preference_mqtt_broker (char*)"mqttbroker"
|
||||
#define preference_mqtt_broker_port (char*)"mqttport"
|
||||
#define preference_mqtt_user (char*)"mqttuser"
|
||||
#define preference_mqtt_password (char*)"mqttpass"
|
||||
#define preference_mqtt_log_enabled (char*)"mqttlog"
|
||||
#define preference_lock_enabled (char*)"lockena"
|
||||
#define preference_lock_pin_status (char*)"lockpin"
|
||||
#define preference_mqtt_lock_path (char*)"mqttpath"
|
||||
#define preference_opener_enabled (char*)"openerena"
|
||||
#define preference_opener_pin_status (char*)"openerpin"
|
||||
#define preference_opener_continuous_mode (char*)"openercont"
|
||||
#define preference_mqtt_opener_path (char*)"mqttoppath"
|
||||
#define preference_check_updates (char*)"checkupdates"
|
||||
#define preference_lock_max_keypad_code_count (char*)"maxkpad"
|
||||
#define preference_opener_max_keypad_code_count (char*)"opmaxkpad"
|
||||
#define preference_mqtt_ca (char*)"mqttca"
|
||||
#define preference_mqtt_crt (char*)"mqttcrt"
|
||||
#define preference_mqtt_key (char*)"mqttkey"
|
||||
#define preference_mqtt_hass_discovery (char*)"hassdiscovery"
|
||||
#define preference_mqtt_hass_cu_url (char*)"hassConfigUrl"
|
||||
#define preference_ip_dhcp_enabled (char*)"dhcpena"
|
||||
#define preference_ip_address (char*)"ipaddr"
|
||||
#define preference_ip_subnet (char*)"ipsub"
|
||||
#define preference_ip_gateway (char*)"ipgtw"
|
||||
#define preference_ip_dns_server (char*)"dnssrv"
|
||||
#define preference_network_hardware (char*)"nwhw"
|
||||
#define preference_network_hardware_gpio (char*)"nwhwdt" // obsolete
|
||||
#define preference_network_wifi_fallback_disabled (char*)"nwwififb"
|
||||
#define preference_rssi_publish_interval (char*)"rssipb"
|
||||
#define preference_hostname (char*)"hostname"
|
||||
#define preference_network_timeout (char*)"nettmout"
|
||||
#define preference_restart_on_disconnect (char*)"restdisc"
|
||||
#define preference_restart_timer (char*)"resttmr"
|
||||
#define preference_restart_ble_beacon_lost (char*)"rstbcn"
|
||||
#define preference_query_interval_lockstate (char*)"lockStInterval"
|
||||
#define preference_query_interval_configuration (char*)"configInterval"
|
||||
#define preference_query_interval_battery (char*)"batInterval"
|
||||
#define preference_query_interval_keypad (char*)"kpInterval"
|
||||
#define preference_access_level (char*)"accLvl"
|
||||
#define preference_keypad_info_enabled (char*)"kpInfoEnabled"
|
||||
#define preference_keypad_control_enabled (char*)"kpCntrlEnabled"
|
||||
#define preference_timecontrol_control_enabled (char*)"tcCntrlEnabled"
|
||||
#define preference_timecontrol_info_enabled (char*)"tcInfoEnabled"
|
||||
#define preference_publish_authdata (char*)"pubAuth"
|
||||
#define preference_acl (char*)"aclLckOpn"
|
||||
#define preference_conf_lock_basic_acl (char*)"confLckBasAcl"
|
||||
#define preference_conf_lock_advanced_acl (char*)"confLckAdvAcl"
|
||||
#define preference_conf_opener_basic_acl (char*)"confOpnBasAcl"
|
||||
#define preference_conf_opener_advanced_acl (char*)"confOpnAdvAcl"
|
||||
#define preference_register_as_app (char*)"regAsApp" // true = register as hub; false = register as app
|
||||
#define preference_command_nr_of_retries (char*)"nrRetry"
|
||||
#define preference_command_retry_delay (char*)"rtryDelay"
|
||||
#define preference_cred_user (char*)"crdusr"
|
||||
#define preference_cred_password (char*)"crdpass"
|
||||
#define preference_gpio_locking_enabled (char*)"gpiolck" // obsolete
|
||||
#define preference_gpio_configuration (char*)"gpiocfg"
|
||||
#define preference_publish_debug_info (char*)"pubdbg"
|
||||
#define preference_presence_detection_timeout (char*)"prdtimeout"
|
||||
#define preference_has_mac_saved (char*)"hasmac"
|
||||
#define preference_has_mac_byte_0 (char*)"macb0"
|
||||
#define preference_has_mac_byte_1 (char*)"macb1"
|
||||
#define preference_has_mac_byte_2 (char*)"macb2"
|
||||
#define preference_latest_version (char*)"latest"
|
||||
|
||||
class DebugPreferences
|
||||
{
|
||||
@@ -83,8 +86,9 @@ private:
|
||||
preference_hostname, preference_network_timeout, preference_restart_on_disconnect,
|
||||
preference_restart_ble_beacon_lost, preference_query_interval_lockstate,
|
||||
preference_query_interval_configuration, preference_query_interval_battery, preference_query_interval_keypad,
|
||||
preference_keypad_control_enabled, preference_admin_enabled, preference_keypad_info_enabled, preference_acl,
|
||||
preference_keypad_control_enabled, preference_keypad_info_enabled, preference_acl,
|
||||
preference_timecontrol_control_enabled, preference_timecontrol_info_enabled,
|
||||
preference_conf_lock_basic_acl, preference_conf_lock_advanced_acl, preference_conf_opener_basic_acl, preference_conf_opener_advanced_acl,
|
||||
preference_access_level, preference_register_as_app, preference_command_nr_of_retries,
|
||||
preference_command_retry_delay, preference_cred_user, preference_cred_password, preference_publish_authdata,
|
||||
preference_publish_debug_info, preference_presence_detection_timeout,
|
||||
@@ -100,7 +104,7 @@ private:
|
||||
std::vector<char*> _boolPrefs =
|
||||
{
|
||||
preference_started_before, preference_mqtt_log_enabled, preference_check_updates, preference_lock_enabled, preference_opener_enabled, preference_opener_continuous_mode,
|
||||
preference_restart_on_disconnect, preference_keypad_control_enabled, preference_admin_enabled, preference_keypad_info_enabled,
|
||||
preference_restart_on_disconnect, preference_keypad_control_enabled, preference_keypad_info_enabled,
|
||||
preference_timecontrol_control_enabled, preference_timecontrol_info_enabled, preference_register_as_app, preference_ip_dhcp_enabled,
|
||||
preference_publish_authdata, preference_has_mac_saved, preference_publish_debug_info, preference_network_wifi_fallback_disabled
|
||||
};
|
||||
|
||||
@@ -263,6 +263,10 @@ bool WebCfgServer::processArgs(String& message)
|
||||
bool clearMqttCredentials = false;
|
||||
bool clearCredentials = false;
|
||||
uint32_t aclPrefs[17] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||
uint32_t basicLockConfigAclPrefs[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||
uint32_t basicOpenerConfigAclPrefs[14] = {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};
|
||||
uint32_t advancedOpenerConfigAclPrefs[20] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||
|
||||
int count = _server.args();
|
||||
|
||||
@@ -465,11 +469,6 @@ bool WebCfgServer::processArgs(String& message)
|
||||
{
|
||||
aclLvlChanged = true;
|
||||
}
|
||||
else if(key == "ACLCNF")
|
||||
{
|
||||
_preferences->putBool(preference_admin_enabled, (value == "1"));
|
||||
configChanged = true;
|
||||
}
|
||||
else if(key == "KPPUB")
|
||||
{
|
||||
_preferences->putBool(preference_keypad_info_enabled, (value == "1"));
|
||||
@@ -563,6 +562,294 @@ bool WebCfgServer::processArgs(String& message)
|
||||
{
|
||||
aclPrefs[16] = ((value == "1") ? 1 : 0);
|
||||
}
|
||||
else if(key == "CONFLCKNAME")
|
||||
{
|
||||
basicLockConfigAclPrefs[0] = ((value == "1") ? 1 : 0);
|
||||
}
|
||||
else if(key == "CONFLCKLAT")
|
||||
{
|
||||
basicLockConfigAclPrefs[1] = ((value == "1") ? 1 : 0);
|
||||
}
|
||||
else if(key == "CONFLCKLONG")
|
||||
{
|
||||
basicLockConfigAclPrefs[2] = ((value == "1") ? 1 : 0);
|
||||
}
|
||||
else if(key == "CONFLCKAUNL")
|
||||
{
|
||||
basicLockConfigAclPrefs[3] = ((value == "1") ? 1 : 0);
|
||||
}
|
||||
else if(key == "CONFLCKPRENA")
|
||||
{
|
||||
basicLockConfigAclPrefs[4] = ((value == "1") ? 1 : 0);
|
||||
}
|
||||
else if(key == "CONFLCKBTENA")
|
||||
{
|
||||
basicLockConfigAclPrefs[5] = ((value == "1") ? 1 : 0);
|
||||
}
|
||||
else if(key == "CONFLCKLEDENA")
|
||||
{
|
||||
basicLockConfigAclPrefs[6] = ((value == "1") ? 1 : 0);
|
||||
}
|
||||
else if(key == "CONFLCKLEDBR")
|
||||
{
|
||||
basicLockConfigAclPrefs[7] = ((value == "1") ? 1 : 0);
|
||||
}
|
||||
else if(key == "CONFLCKTZOFF")
|
||||
{
|
||||
basicLockConfigAclPrefs[8] = ((value == "1") ? 1 : 0);
|
||||
}
|
||||
else if(key == "CONFLCKDSTM")
|
||||
{
|
||||
basicLockConfigAclPrefs[9] = ((value == "1") ? 1 : 0);
|
||||
}
|
||||
else if(key == "CONFLCKFOB1")
|
||||
{
|
||||
basicLockConfigAclPrefs[10] = ((value == "1") ? 1 : 0);
|
||||
}
|
||||
else if(key == "CONFLCKFOB2")
|
||||
{
|
||||
basicLockConfigAclPrefs[11] = ((value == "1") ? 1 : 0);
|
||||
}
|
||||
else if(key == "CONFLCKFOB3")
|
||||
{
|
||||
basicLockConfigAclPrefs[12] = ((value == "1") ? 1 : 0);
|
||||
}
|
||||
else if(key == "CONFLCKSGLLCK")
|
||||
{
|
||||
basicLockConfigAclPrefs[13] = ((value == "1") ? 1 : 0);
|
||||
}
|
||||
else if(key == "CONFLCKADVM")
|
||||
{
|
||||
basicLockConfigAclPrefs[14] = ((value == "1") ? 1 : 0);
|
||||
}
|
||||
else if(key == "CONFLCKTZID")
|
||||
{
|
||||
basicLockConfigAclPrefs[15] = ((value == "1") ? 1 : 0);
|
||||
}
|
||||
else if(key == "CONFLCKUPOD")
|
||||
{
|
||||
advancedLockConfigAclPrefs[0] = ((value == "1") ? 1 : 0);
|
||||
}
|
||||
else if(key == "CONFLCKLPOD")
|
||||
{
|
||||
advancedLockConfigAclPrefs[1] = ((value == "1") ? 1 : 0);
|
||||
}
|
||||
else if(key == "CONFLCKSLPOD")
|
||||
{
|
||||
advancedLockConfigAclPrefs[2] = ((value == "1") ? 1 : 0);
|
||||
}
|
||||
else if(key == "CONFLCKUTLTOD")
|
||||
{
|
||||
advancedLockConfigAclPrefs[3] = ((value == "1") ? 1 : 0);
|
||||
}
|
||||
else if(key == "CONFLCKLNGT")
|
||||
{
|
||||
advancedLockConfigAclPrefs[4] = ((value == "1") ? 1 : 0);
|
||||
}
|
||||
else if(key == "CONFLCKSBPA")
|
||||
{
|
||||
advancedLockConfigAclPrefs[5] = ((value == "1") ? 1 : 0);
|
||||
}
|
||||
else if(key == "CONFLCKDBPA")
|
||||
{
|
||||
advancedLockConfigAclPrefs[6] = ((value == "1") ? 1 : 0);
|
||||
}
|
||||
else if(key == "CONFLCKDC")
|
||||
{
|
||||
advancedLockConfigAclPrefs[7] = ((value == "1") ? 1 : 0);
|
||||
}
|
||||
else if(key == "CONFLCKBATT")
|
||||
{
|
||||
advancedLockConfigAclPrefs[8] = ((value == "1") ? 1 : 0);
|
||||
}
|
||||
else if(key == "CONFLCKABTD")
|
||||
{
|
||||
advancedLockConfigAclPrefs[9] = ((value == "1") ? 1 : 0);
|
||||
}
|
||||
else if(key == "CONFLCKUNLD")
|
||||
{
|
||||
advancedLockConfigAclPrefs[10] = ((value == "1") ? 1 : 0);
|
||||
}
|
||||
else if(key == "CONFLCKALT")
|
||||
{
|
||||
advancedLockConfigAclPrefs[11] = ((value == "1") ? 1 : 0);
|
||||
}
|
||||
else if(key == "CONFLCKAUNLD")
|
||||
{
|
||||
advancedLockConfigAclPrefs[12] = ((value == "1") ? 1 : 0);
|
||||
}
|
||||
else if(key == "CONFLCKNMENA")
|
||||
{
|
||||
advancedLockConfigAclPrefs[13] = ((value == "1") ? 1 : 0);
|
||||
}
|
||||
else if(key == "CONFLCKNMST")
|
||||
{
|
||||
advancedLockConfigAclPrefs[14] = ((value == "1") ? 1 : 0);
|
||||
}
|
||||
else if(key == "CONFLCKNMET")
|
||||
{
|
||||
advancedLockConfigAclPrefs[15] = ((value == "1") ? 1 : 0);
|
||||
}
|
||||
else if(key == "CONFLCKNMALENA")
|
||||
{
|
||||
advancedLockConfigAclPrefs[16] = ((value == "1") ? 1 : 0);
|
||||
}
|
||||
else if(key == "CONFLCKNMAULD")
|
||||
{
|
||||
advancedLockConfigAclPrefs[17] = ((value == "1") ? 1 : 0);
|
||||
}
|
||||
else if(key == "CONFLCKNMLOS")
|
||||
{
|
||||
advancedLockConfigAclPrefs[18] = ((value == "1") ? 1 : 0);
|
||||
}
|
||||
else if(key == "CONFLCKALENA")
|
||||
{
|
||||
advancedLockConfigAclPrefs[19] = ((value == "1") ? 1 : 0);
|
||||
}
|
||||
else if(key == "CONFLCKIALENA")
|
||||
{
|
||||
advancedLockConfigAclPrefs[20] = ((value == "1") ? 1 : 0);
|
||||
}
|
||||
else if(key == "CONFLCKAUENA")
|
||||
{
|
||||
advancedLockConfigAclPrefs[21] = ((value == "1") ? 1 : 0);
|
||||
}
|
||||
else if(key == "CONFOPNNAME")
|
||||
{
|
||||
basicOpenerConfigAclPrefs[0] = ((value == "1") ? 1 : 0);
|
||||
}
|
||||
else if(key == "CONFOPNLAT")
|
||||
{
|
||||
basicOpenerConfigAclPrefs[1] = ((value == "1") ? 1 : 0);
|
||||
}
|
||||
else if(key == "CONFOPNLONG")
|
||||
{
|
||||
basicOpenerConfigAclPrefs[2] = ((value == "1") ? 1 : 0);
|
||||
}
|
||||
else if(key == "CONFOPNPRENA")
|
||||
{
|
||||
basicOpenerConfigAclPrefs[3] = ((value == "1") ? 1 : 0);
|
||||
}
|
||||
else if(key == "CONFOPNBTENA")
|
||||
{
|
||||
basicOpenerConfigAclPrefs[4] = ((value == "1") ? 1 : 0);
|
||||
}
|
||||
else if(key == "CONFOPNLEDENA")
|
||||
{
|
||||
basicOpenerConfigAclPrefs[5] = ((value == "1") ? 1 : 0);
|
||||
}
|
||||
else if(key == "CONFOPNTZOFF")
|
||||
{
|
||||
basicOpenerConfigAclPrefs[6] = ((value == "1") ? 1 : 0);
|
||||
}
|
||||
else if(key == "CONFOPNDSTM")
|
||||
{
|
||||
basicOpenerConfigAclPrefs[7] = ((value == "1") ? 1 : 0);
|
||||
}
|
||||
else if(key == "CONFOPNFOB1")
|
||||
{
|
||||
basicOpenerConfigAclPrefs[8] = ((value == "1") ? 1 : 0);
|
||||
}
|
||||
else if(key == "CONFOPNFOB2")
|
||||
{
|
||||
basicOpenerConfigAclPrefs[9] = ((value == "1") ? 1 : 0);
|
||||
}
|
||||
else if(key == "CONFOPNFOB3")
|
||||
{
|
||||
basicOpenerConfigAclPrefs[10] = ((value == "1") ? 1 : 0);
|
||||
}
|
||||
else if(key == "CONFOPNOPM")
|
||||
{
|
||||
basicOpenerConfigAclPrefs[11] = ((value == "1") ? 1 : 0);
|
||||
}
|
||||
else if(key == "CONFOPNADVM")
|
||||
{
|
||||
basicOpenerConfigAclPrefs[12] = ((value == "1") ? 1 : 0);
|
||||
}
|
||||
else if(key == "CONFOPNTZID")
|
||||
{
|
||||
basicOpenerConfigAclPrefs[13] = ((value == "1") ? 1 : 0);
|
||||
}
|
||||
else if(key == "CONFOPNICID")
|
||||
{
|
||||
advancedOpenerConfigAclPrefs[0] = ((value == "1") ? 1 : 0);
|
||||
}
|
||||
else if(key == "CONFOPNBUSMS")
|
||||
{
|
||||
advancedOpenerConfigAclPrefs[1] = ((value == "1") ? 1 : 0);
|
||||
}
|
||||
else if(key == "CONFOPNSCDUR")
|
||||
{
|
||||
advancedOpenerConfigAclPrefs[2] = ((value == "1") ? 1 : 0);
|
||||
}
|
||||
else if(key == "CONFOPNESD")
|
||||
{
|
||||
advancedOpenerConfigAclPrefs[3] = ((value == "1") ? 1 : 0);
|
||||
}
|
||||
else if(key == "CONFOPNRESD")
|
||||
{
|
||||
advancedOpenerConfigAclPrefs[4] = ((value == "1") ? 1 : 0);
|
||||
}
|
||||
else if(key == "CONFOPNESDUR")
|
||||
{
|
||||
advancedOpenerConfigAclPrefs[5] = ((value == "1") ? 1 : 0);
|
||||
}
|
||||
else if(key == "CONFOPNDRTOAR")
|
||||
{
|
||||
advancedOpenerConfigAclPrefs[6] = ((value == "1") ? 1 : 0);
|
||||
}
|
||||
else if(key == "CONFOPNRTOT")
|
||||
{
|
||||
advancedOpenerConfigAclPrefs[7] = ((value == "1") ? 1 : 0);
|
||||
}
|
||||
else if(key == "CONFOPNDRBSUP")
|
||||
{
|
||||
advancedOpenerConfigAclPrefs[8] = ((value == "1") ? 1 : 0);
|
||||
}
|
||||
else if(key == "CONFOPNDRBSUPDUR")
|
||||
{
|
||||
advancedOpenerConfigAclPrefs[9] = ((value == "1") ? 1 : 0);
|
||||
}
|
||||
else if(key == "CONFOPNSRING")
|
||||
{
|
||||
advancedOpenerConfigAclPrefs[10] = ((value == "1") ? 1 : 0);
|
||||
}
|
||||
else if(key == "CONFOPNSOPN")
|
||||
{
|
||||
advancedOpenerConfigAclPrefs[11] = ((value == "1") ? 1 : 0);
|
||||
}
|
||||
else if(key == "CONFOPNSRTO")
|
||||
{
|
||||
advancedOpenerConfigAclPrefs[12] = ((value == "1") ? 1 : 0);
|
||||
}
|
||||
else if(key == "CONFOPNSCM")
|
||||
{
|
||||
advancedOpenerConfigAclPrefs[13] = ((value == "1") ? 1 : 0);
|
||||
}
|
||||
else if(key == "CONFOPNSCFRM")
|
||||
{
|
||||
advancedOpenerConfigAclPrefs[14] = ((value == "1") ? 1 : 0);
|
||||
}
|
||||
else if(key == "CONFOPNSLVL")
|
||||
{
|
||||
advancedOpenerConfigAclPrefs[15] = ((value == "1") ? 1 : 0);
|
||||
}
|
||||
else if(key == "CONFOPNSBPA")
|
||||
{
|
||||
advancedOpenerConfigAclPrefs[16] = ((value == "1") ? 1 : 0);
|
||||
}
|
||||
else if(key == "CONFOPNDBPA")
|
||||
{
|
||||
advancedOpenerConfigAclPrefs[17] = ((value == "1") ? 1 : 0);
|
||||
}
|
||||
else if(key == "CONFOPNBATT")
|
||||
{
|
||||
advancedOpenerConfigAclPrefs[18] = ((value == "1") ? 1 : 0);
|
||||
}
|
||||
else if(key == "CONFOPNABTD")
|
||||
{
|
||||
advancedOpenerConfigAclPrefs[19] = ((value == "1") ? 1 : 0);
|
||||
}
|
||||
else if(key == "REGAPP")
|
||||
{
|
||||
_preferences->putBool(preference_register_as_app, (value == "1"));
|
||||
@@ -649,6 +936,10 @@ bool WebCfgServer::processArgs(String& message)
|
||||
if(aclLvlChanged)
|
||||
{
|
||||
_preferences->putBytes(preference_acl, (byte*)(&aclPrefs), sizeof(aclPrefs));
|
||||
_preferences->putBytes(preference_conf_lock_basic_acl, (byte*)(&basicLockConfigAclPrefs), sizeof(basicLockConfigAclPrefs));
|
||||
_preferences->putBytes(preference_conf_opener_basic_acl, (byte*)(&basicOpenerConfigAclPrefs), sizeof(basicOpenerConfigAclPrefs));
|
||||
_preferences->putBytes(preference_conf_lock_advanced_acl, (byte*)(&advancedLockConfigAclPrefs), sizeof(advancedLockConfigAclPrefs));
|
||||
_preferences->putBytes(preference_conf_opener_advanced_acl, (byte*)(&advancedOpenerConfigAclPrefs), sizeof(advancedOpenerConfigAclPrefs));
|
||||
configChanged = true;
|
||||
}
|
||||
|
||||
@@ -777,12 +1068,7 @@ void WebCfgServer::buildHtml(String& response)
|
||||
|
||||
printParameter(response, "Firmware", version.c_str(), "/info");
|
||||
|
||||
if(_preferences->getBool(preference_check_updates))
|
||||
{
|
||||
//if(atof(_latestVersion) > atof(NUKI_HUB_VERSION) || (atof(_latestVersion) == atof(NUKI_HUB_VERSION) && _latestVersion != NUKI_HUB_VERSION)) {
|
||||
printParameter(response, "Latest Firmware", _preferences->getString(preference_latest_version).c_str(), "/ota");
|
||||
//}
|
||||
}
|
||||
if(_preferences->getBool(preference_check_updates)) printParameter(response, "Latest Firmware", _preferences->getString(preference_latest_version).c_str(), "/ota");
|
||||
|
||||
response.concat("</table><br><table id=\"tblnav\"><tbody>");
|
||||
response.concat("<tr><td><h3>MQTT and Network Configuration</h3></td><td class=\"tdbtn\">");
|
||||
@@ -949,23 +1235,23 @@ void WebCfgServer::buildMqttConfigHtml(String &response)
|
||||
response.concat("<table>");
|
||||
printInputField(response, "HASSDISCOVERY", "Home Assistant discovery topic (empty to disable; usually homeassistant)", _preferences->getString(preference_mqtt_hass_discovery).c_str(), 30);
|
||||
printInputField(response, "HASSCUURL", "Home Assistant device configuration URL (empty to use http://LOCALIP; fill when using a reverse proxy for example)", _preferences->getString(preference_mqtt_hass_cu_url).c_str(), 261);
|
||||
if(_nukiOpener != nullptr) printCheckBox(response, "OPENERCONT", "Set Nuki Opener Lock/Unlock action in Home Assistant to Continuous mode", _preferences->getBool(preference_opener_continuous_mode));
|
||||
if(_nukiOpener != nullptr) printCheckBox(response, "OPENERCONT", "Set Nuki Opener Lock/Unlock action in Home Assistant to Continuous mode", _preferences->getBool(preference_opener_continuous_mode), "");
|
||||
printTextarea(response, "MQTTCA", "MQTT SSL CA Certificate (*, optional)", _preferences->getString(preference_mqtt_ca).c_str(), TLS_CA_MAX_SIZE, _network->encryptionSupported(), true);
|
||||
printTextarea(response, "MQTTCRT", "MQTT SSL Client Certificate (*, optional)", _preferences->getString(preference_mqtt_crt).c_str(), TLS_CERT_MAX_SIZE, _network->encryptionSupported(), true);
|
||||
printTextarea(response, "MQTTKEY", "MQTT SSL Client Key (*, optional)", _preferences->getString(preference_mqtt_key).c_str(), TLS_KEY_MAX_SIZE, _network->encryptionSupported(), true);
|
||||
printDropDown(response, "NWHW", "Network hardware", String(_preferences->getInt(preference_network_hardware)), getNetworkDetectionOptions());
|
||||
printCheckBox(response, "NWHWWIFIFB", "Disable fallback to Wi-Fi / Wi-Fi config portal", _preferences->getBool(preference_network_wifi_fallback_disabled));
|
||||
printCheckBox(response, "NWHWWIFIFB", "Disable fallback to Wi-Fi / Wi-Fi config portal", _preferences->getBool(preference_network_wifi_fallback_disabled), "");
|
||||
printInputField(response, "RSSI", "RSSI Publish interval (seconds; -1 to disable)", _preferences->getInt(preference_rssi_publish_interval), 6);
|
||||
printInputField(response, "NETTIMEOUT", "Network Timeout until restart (seconds; -1 to disable)", _preferences->getInt(preference_network_timeout), 5);
|
||||
printCheckBox(response, "RSTDISC", "Restart on disconnect", _preferences->getBool(preference_restart_on_disconnect));
|
||||
printCheckBox(response, "MQTTLOG", "Enable MQTT logging", _preferences->getBool(preference_mqtt_log_enabled));
|
||||
printCheckBox(response, "CHECKUPDATE", "Check for Firmware Updates every 24h", _preferences->getBool(preference_check_updates));
|
||||
printCheckBox(response, "RSTDISC", "Restart on disconnect", _preferences->getBool(preference_restart_on_disconnect), "");
|
||||
printCheckBox(response, "MQTTLOG", "Enable MQTT logging", _preferences->getBool(preference_mqtt_log_enabled), "");
|
||||
printCheckBox(response, "CHECKUPDATE", "Check for Firmware Updates every 24h", _preferences->getBool(preference_check_updates), "");
|
||||
response.concat("</table>");
|
||||
response.concat("* If no encryption is configured for the MQTT broker, leave empty. Only supported for Wi-Fi connections.<br><br>");
|
||||
|
||||
response.concat("<h3>IP Address assignment</h3>");
|
||||
response.concat("<table>");
|
||||
printCheckBox(response, "DHCPENA", "Enable DHCP", _preferences->getBool(preference_ip_dhcp_enabled));
|
||||
printCheckBox(response, "DHCPENA", "Enable DHCP", _preferences->getBool(preference_ip_dhcp_enabled), "");
|
||||
printInputField(response, "IPADDR", "Static IP address", _preferences->getString(preference_ip_address).c_str(), 15);
|
||||
printInputField(response, "IPSUB", "Subnet", _preferences->getString(preference_ip_subnet).c_str(), 15);
|
||||
printInputField(response, "IPGTW", "Default gateway", _preferences->getString(preference_ip_gateway).c_str(), 15);
|
||||
@@ -987,46 +1273,154 @@ void WebCfgServer::buildAccLvlHtml(String &response)
|
||||
response.concat("<input type=\"hidden\" name=\"ACLLVLCHANGED\" value=\"1\">");
|
||||
response.concat("<h3>Nuki General Access Control</h3>");
|
||||
response.concat("<table><tr><th>Setting</th><th>Enabled</th></tr>");
|
||||
printCheckBox(response, "ACLCNF", "Change Nuki configuration", _preferences->getBool(preference_admin_enabled));
|
||||
if((_nuki != nullptr && _nuki->hasKeypad()) || (_nukiOpener != nullptr && _nukiOpener->hasKeypad()))
|
||||
{
|
||||
printCheckBox(response, "KPPUB", "Publish keypad codes information", _preferences->getBool(preference_keypad_info_enabled));
|
||||
printCheckBox(response, "KPENA", "Add, modify and delete keypad codes", _preferences->getBool(preference_keypad_control_enabled));
|
||||
printCheckBox(response, "KPPUB", "Publish keypad codes information", _preferences->getBool(preference_keypad_info_enabled), "");
|
||||
printCheckBox(response, "KPENA", "Add, modify and delete keypad codes", _preferences->getBool(preference_keypad_control_enabled), "");
|
||||
}
|
||||
|
||||
printCheckBox(response, "TCPUB", "Publish time control entries information", _preferences->getBool(preference_timecontrol_info_enabled));
|
||||
printCheckBox(response, "TCENA", "Add, modify and delete time control entries", _preferences->getBool(preference_timecontrol_control_enabled));
|
||||
printCheckBox(response, "PUBAUTH", "Publish authorisation log (may reduce battery life)", _preferences->getBool(preference_publish_authdata));
|
||||
printCheckBox(response, "TCPUB", "Publish time control entries information", _preferences->getBool(preference_timecontrol_info_enabled), "");
|
||||
printCheckBox(response, "TCENA", "Add, modify and delete time control entries", _preferences->getBool(preference_timecontrol_control_enabled), "");
|
||||
printCheckBox(response, "PUBAUTH", "Publish authorisation log (may reduce battery life)", _preferences->getBool(preference_publish_authdata), "");
|
||||
response.concat("</table><br>");
|
||||
if(_nuki != nullptr)
|
||||
{
|
||||
uint32_t basicLockConfigAclPrefs[16];
|
||||
_preferences->getBytes(preference_conf_lock_basic_acl, &basicLockConfigAclPrefs, sizeof(basicLockConfigAclPrefs));
|
||||
uint32_t advancedLockConfigAclPrefs[22];
|
||||
_preferences->getBytes(preference_conf_lock_advanced_acl, &advancedLockConfigAclPrefs, sizeof(advancedLockConfigAclPrefs));
|
||||
|
||||
response.concat("<h3>Nuki Lock Access Control</h3>");
|
||||
response.concat("<input type=\"button\" value=\"Allow all\" style=\"margin-right: 10px;\" onclick=\"");
|
||||
response.concat("for(el of document.getElementsByClassName('chk_access_lock')){if(el.constructor.name==='HTMLInputElement'&&el.type==='checkbox')el.checked=true;}\">");
|
||||
response.concat("<input type=\"button\" value=\"Disallow all\" onclick=\"");
|
||||
response.concat("for(el of document.getElementsByClassName('chk_access_lock')){if(el.constructor.name==='HTMLInputElement'&&el.type==='checkbox')el.checked=false;}\">");
|
||||
response.concat("<table><tr><th>Action</th><th>Allowed</th></tr>");
|
||||
|
||||
printCheckBox(response, "ACLLCKLCK", "Lock", ((int)aclPrefs[0] == 1));
|
||||
printCheckBox(response, "ACLLCKUNLCK", "Unlock", ((int)aclPrefs[1] == 1));
|
||||
printCheckBox(response, "ACLLCKUNLTCH", "Unlatch", ((int)aclPrefs[2] == 1));
|
||||
printCheckBox(response, "ACLLCKLNG", "Lock N Go", ((int)aclPrefs[3] == 1));
|
||||
printCheckBox(response, "ACLLCKLNGU", "Lock N Go Unlatch", ((int)aclPrefs[4] == 1));
|
||||
printCheckBox(response, "ACLLCKFLLCK", "Full Lock", ((int)aclPrefs[5] == 1));
|
||||
printCheckBox(response, "ACLLCKFOB1", "Fob Action 1", ((int)aclPrefs[6] == 1));
|
||||
printCheckBox(response, "ACLLCKFOB2", "Fob Action 2", ((int)aclPrefs[7] == 1));
|
||||
printCheckBox(response, "ACLLCKFOB3", "Fob Action 3", ((int)aclPrefs[8] == 1));
|
||||
printCheckBox(response, "ACLLCKLCK", "Lock", ((int)aclPrefs[0] == 1), "chk_access_lock");
|
||||
printCheckBox(response, "ACLLCKUNLCK", "Unlock", ((int)aclPrefs[1] == 1), "chk_access_lock");
|
||||
printCheckBox(response, "ACLLCKUNLTCH", "Unlatch", ((int)aclPrefs[2] == 1), "chk_access_lock");
|
||||
printCheckBox(response, "ACLLCKLNG", "Lock N Go", ((int)aclPrefs[3] == 1), "chk_access_lock");
|
||||
printCheckBox(response, "ACLLCKLNGU", "Lock N Go Unlatch", ((int)aclPrefs[4] == 1), "chk_access_lock");
|
||||
printCheckBox(response, "ACLLCKFLLCK", "Full Lock", ((int)aclPrefs[5] == 1), "chk_access_lock");
|
||||
printCheckBox(response, "ACLLCKFOB1", "Fob Action 1", ((int)aclPrefs[6] == 1), "chk_access_lock");
|
||||
printCheckBox(response, "ACLLCKFOB2", "Fob Action 2", ((int)aclPrefs[7] == 1), "chk_access_lock");
|
||||
printCheckBox(response, "ACLLCKFOB3", "Fob Action 3", ((int)aclPrefs[8] == 1), "chk_access_lock");
|
||||
response.concat("</table><br>");
|
||||
|
||||
response.concat("<h3>Nuki Lock Config Control (Requires PIN to be set)</h3>");
|
||||
response.concat("<input type=\"button\" value=\"Allow all\" style=\"margin-right: 10px;\" onclick=\"");
|
||||
response.concat("for(el of document.getElementsByClassName('chk_config_lock')){if(el.constructor.name==='HTMLInputElement'&&el.type==='checkbox')el.checked=true;}\">");
|
||||
response.concat("<input type=\"button\" value=\"Disallow all\" onclick=\"");
|
||||
response.concat("for(el of document.getElementsByClassName('chk_config_lock')){if(el.constructor.name==='HTMLInputElement'&&el.type==='checkbox')el.checked=false;}\">");
|
||||
response.concat("<table><tr><th>Change</th><th>Allowed</th></tr>");
|
||||
|
||||
printCheckBox(response, "CONFLCKNAME", "Name", ((int)basicLockConfigAclPrefs[0] == 1), "chk_config_lock");
|
||||
printCheckBox(response, "CONFLCKLAT", "Latitude", ((int)basicLockConfigAclPrefs[1] == 1), "chk_config_lock");
|
||||
printCheckBox(response, "CONFLCKLONG", "Longitude", ((int)basicLockConfigAclPrefs[2] == 1), "chk_config_lock");
|
||||
printCheckBox(response, "CONFLCKAUNL", "Auto unlatch", ((int)basicLockConfigAclPrefs[3] == 1), "chk_config_lock");
|
||||
printCheckBox(response, "CONFLCKPRENA", "Pairing enabled", ((int)basicLockConfigAclPrefs[4] == 1), "chk_config_lock");
|
||||
printCheckBox(response, "CONFLCKBTENA", "Button enabled", ((int)basicLockConfigAclPrefs[5] == 1), "chk_config_lock");
|
||||
printCheckBox(response, "CONFLCKLEDENA", "LED flash enabled", ((int)basicLockConfigAclPrefs[6] == 1), "chk_config_lock");
|
||||
printCheckBox(response, "CONFLCKLEDBR", "LED brightness", ((int)basicLockConfigAclPrefs[7] == 1), "chk_config_lock");
|
||||
printCheckBox(response, "CONFLCKTZOFF", "Timezone offset", ((int)basicLockConfigAclPrefs[8] == 1), "chk_config_lock");
|
||||
printCheckBox(response, "CONFLCKDSTM", "DST mode", ((int)basicLockConfigAclPrefs[9] == 1), "chk_config_lock");
|
||||
printCheckBox(response, "CONFLCKFOB1", "Fob Action 1", ((int)basicLockConfigAclPrefs[10] == 1), "chk_config_lock");
|
||||
printCheckBox(response, "CONFLCKFOB2", "Fob Action 2", ((int)basicLockConfigAclPrefs[11] == 1), "chk_config_lock");
|
||||
printCheckBox(response, "CONFLCKFOB3", "Fob Action 3", ((int)basicLockConfigAclPrefs[12] == 1), "chk_config_lock");
|
||||
printCheckBox(response, "CONFLCKSGLLCK", "Single Lock", ((int)basicLockConfigAclPrefs[13] == 1), "chk_config_lock");
|
||||
printCheckBox(response, "CONFLCKADVM", "Advertising Mode", ((int)basicLockConfigAclPrefs[14] == 1), "chk_config_lock");
|
||||
printCheckBox(response, "CONFLCKTZID", "Timezone ID", ((int)basicLockConfigAclPrefs[15] == 1), "chk_config_lock");
|
||||
|
||||
printCheckBox(response, "CONFLCKUPOD", "Unlocked Position Offset Degrees", ((int)advancedLockConfigAclPrefs[0] == 1), "chk_config_lock");
|
||||
printCheckBox(response, "CONFLCKLPOD", "Locked Position Offset Degrees", ((int)advancedLockConfigAclPrefs[1] == 1), "chk_config_lock");
|
||||
printCheckBox(response, "CONFLCKSLPOD", "Single Locked Position Offset Degrees", ((int)advancedLockConfigAclPrefs[2] == 1), "chk_config_lock");
|
||||
printCheckBox(response, "CONFLCKUTLTOD", "Unlocked To Locked Transition Offset Degrees", ((int)advancedLockConfigAclPrefs[3] == 1), "chk_config_lock");
|
||||
printCheckBox(response, "CONFLCKLNGT", "Lock n Go timeout", ((int)advancedLockConfigAclPrefs[4] == 1), "chk_config_lock");
|
||||
printCheckBox(response, "CONFLCKSBPA", "Single button press action", ((int)advancedLockConfigAclPrefs[5] == 1), "chk_config_lock");
|
||||
printCheckBox(response, "CONFLCKDBPA", "Double button press action", ((int)advancedLockConfigAclPrefs[6] == 1), "chk_config_lock");
|
||||
printCheckBox(response, "CONFLCKDC", "Detached cylinder", ((int)advancedLockConfigAclPrefs[7] == 1), "chk_config_lock");
|
||||
printCheckBox(response, "CONFLCKBATT", "Battery type", ((int)advancedLockConfigAclPrefs[8] == 1), "chk_config_lock");
|
||||
printCheckBox(response, "CONFLCKABTD", "Automatic battery type detection", ((int)advancedLockConfigAclPrefs[9] == 1), "chk_config_lock");
|
||||
printCheckBox(response, "CONFLCKUNLD", "Unlatch duration", ((int)advancedLockConfigAclPrefs[10] == 1), "chk_config_lock");
|
||||
printCheckBox(response, "CONFLCKALT", "Auto lock timeout", ((int)advancedLockConfigAclPrefs[11] == 1), "chk_config_lock");
|
||||
printCheckBox(response, "CONFLCKAUNLD", "Auto unlock disabled", ((int)advancedLockConfigAclPrefs[12] == 1), "chk_config_lock");
|
||||
printCheckBox(response, "CONFLCKNMENA", "Nightmode enabled", ((int)advancedLockConfigAclPrefs[13] == 1), "chk_config_lock");
|
||||
printCheckBox(response, "CONFLCKNMST", "Nightmode start time", ((int)advancedLockConfigAclPrefs[14] == 1), "chk_config_lock");
|
||||
printCheckBox(response, "CONFLCKNMET", "Nightmode end time", ((int)advancedLockConfigAclPrefs[15] == 1), "chk_config_lock");
|
||||
printCheckBox(response, "CONFLCKNMALENA", "Nightmode auto lock enabled", ((int)advancedLockConfigAclPrefs[16] == 1), "chk_config_lock");
|
||||
printCheckBox(response, "CONFLCKNMAULD", "Nightmode auto unlock disabled", ((int)advancedLockConfigAclPrefs[17] == 1), "chk_config_lock");
|
||||
printCheckBox(response, "CONFLCKNMLOS", "Nightmode immediate lock on start", ((int)advancedLockConfigAclPrefs[18] == 1), "chk_config_lock");
|
||||
printCheckBox(response, "CONFLCKALENA", "Auto lock enabled", ((int)advancedLockConfigAclPrefs[19] == 1), "chk_config_lock");
|
||||
printCheckBox(response, "CONFLCKIALENA", "Immediate auto lock enabled", ((int)advancedLockConfigAclPrefs[20] == 1), "chk_config_lock");
|
||||
printCheckBox(response, "CONFLCKAUENA", "Auto update enabled", ((int)advancedLockConfigAclPrefs[21] == 1), "chk_config_lock");
|
||||
response.concat("</table><br>");
|
||||
}
|
||||
if(_nukiOpener != nullptr)
|
||||
{
|
||||
uint32_t basicOpenerConfigAclPrefs[16];
|
||||
_preferences->getBytes(preference_conf_opener_basic_acl, &basicOpenerConfigAclPrefs, sizeof(basicOpenerConfigAclPrefs));
|
||||
uint32_t advancedOpenerConfigAclPrefs[22];
|
||||
_preferences->getBytes(preference_conf_opener_advanced_acl, &advancedOpenerConfigAclPrefs, sizeof(advancedOpenerConfigAclPrefs));
|
||||
|
||||
response.concat("<h3>Nuki Opener Access Control</h3>");
|
||||
response.concat("<input type=\"button\" value=\"Allow all\" style=\"margin-right: 10px;\" onclick=\"");
|
||||
response.concat("for(el of document.getElementsByClassName('chk_access_opener')){if(el.constructor.name==='HTMLInputElement'&&el.type==='checkbox')el.checked=true;}\">");
|
||||
response.concat("<input type=\"button\" value=\"Disallow all\" onclick=\"");
|
||||
response.concat("for(el of document.getElementsByClassName('chk_access_opener')){if(el.constructor.name==='HTMLInputElement'&&el.type==='checkbox')el.checked=false;}\">");
|
||||
response.concat("<table><tr><th>Action</th><th>Allowed</th></tr>");
|
||||
|
||||
printCheckBox(response, "ACLOPNUNLCK", "Activate Ring-to-Open", ((int)aclPrefs[9] == 1));
|
||||
printCheckBox(response, "ACLOPNLCK", "Deactivate Ring-to-Open", ((int)aclPrefs[10] == 1));
|
||||
printCheckBox(response, "ACLOPNUNLTCH", "Electric Strike Actuation", ((int)aclPrefs[11] == 1));
|
||||
printCheckBox(response, "ACLOPNUNLCKCM", "Activate Continuous Mode", ((int)aclPrefs[12] == 1));
|
||||
printCheckBox(response, "ACLOPNLCKCM", "Deactivate Continuous Mode", ((int)aclPrefs[13] == 1));
|
||||
printCheckBox(response, "ACLOPNFOB1", "Fob Action 1", ((int)aclPrefs[14] == 1));
|
||||
printCheckBox(response, "ACLOPNFOB2", "Fob Action 2", ((int)aclPrefs[15] == 1));
|
||||
printCheckBox(response, "ACLOPNFOB3", "Fob Action 3", ((int)aclPrefs[16] == 1));
|
||||
printCheckBox(response, "ACLOPNUNLCK", "Activate Ring-to-Open", ((int)aclPrefs[9] == 1), "chk_access_opener");
|
||||
printCheckBox(response, "ACLOPNLCK", "Deactivate Ring-to-Open", ((int)aclPrefs[10] == 1), "chk_access_opener");
|
||||
printCheckBox(response, "ACLOPNUNLTCH", "Electric Strike Actuation", ((int)aclPrefs[11] == 1), "chk_access_opener");
|
||||
printCheckBox(response, "ACLOPNUNLCKCM", "Activate Continuous Mode", ((int)aclPrefs[12] == 1), "chk_access_opener");
|
||||
printCheckBox(response, "ACLOPNLCKCM", "Deactivate Continuous Mode", ((int)aclPrefs[13] == 1), "chk_access_opener");
|
||||
printCheckBox(response, "ACLOPNFOB1", "Fob Action 1", ((int)aclPrefs[14] == 1), "chk_access_opener");
|
||||
printCheckBox(response, "ACLOPNFOB2", "Fob Action 2", ((int)aclPrefs[15] == 1), "chk_access_opener");
|
||||
printCheckBox(response, "ACLOPNFOB3", "Fob Action 3", ((int)aclPrefs[16] == 1), "chk_access_opener");
|
||||
response.concat("</table><br>");
|
||||
|
||||
response.concat("<h3>Nuki Opener Config Control (Requires PIN to be set)</h3>");
|
||||
response.concat("<input type=\"button\" value=\"Allow all\" style=\"margin-right: 10px;\" onclick=\"");
|
||||
response.concat("for(el of document.getElementsByClassName('chk_config_opener')){if(el.constructor.name==='HTMLInputElement'&&el.type==='checkbox')el.checked=true;}\">");
|
||||
response.concat("<input type=\"button\" value=\"Disallow all\" onclick=\"");
|
||||
response.concat("for(el of document.getElementsByClassName('chk_config_opener')){if(el.constructor.name==='HTMLInputElement'&&el.type==='checkbox')el.checked=false;}\">");
|
||||
response.concat("<table><tr><th>Change</th><th>Allowed</th></tr>");
|
||||
|
||||
printCheckBox(response, "CONFOPNNAME", "Name", ((int)basicOpenerConfigAclPrefs[0] == 1), "chk_config_opener");
|
||||
printCheckBox(response, "CONFOPNLAT", "Latitude", ((int)basicOpenerConfigAclPrefs[1] == 1), "chk_config_opener");
|
||||
printCheckBox(response, "CONFOPNLONG", "Longitude", ((int)basicOpenerConfigAclPrefs[2] == 1), "chk_config_opener");
|
||||
printCheckBox(response, "CONFOPNPRENA", "Pairing enabled", ((int)basicOpenerConfigAclPrefs[3] == 1), "chk_config_opener");
|
||||
printCheckBox(response, "CONFOPNBTENA", "Button enabled", ((int)basicOpenerConfigAclPrefs[4] == 1), "chk_config_opener");
|
||||
printCheckBox(response, "CONFOPNLEDENA", "LED flash enabled", ((int)basicOpenerConfigAclPrefs[5] == 1), "chk_config_opener");
|
||||
printCheckBox(response, "CONFOPNTZOFF", "Timezone offset", ((int)basicOpenerConfigAclPrefs[6] == 1), "chk_config_opener");
|
||||
printCheckBox(response, "CONFOPNDSTM", "DST mode", ((int)basicOpenerConfigAclPrefs[7] == 1), "chk_config_opener");
|
||||
printCheckBox(response, "CONFOPNFOB1", "Fob Action 1", ((int)basicOpenerConfigAclPrefs[8] == 1), "chk_config_opener");
|
||||
printCheckBox(response, "CONFOPNFOB2", "Fob Action 2", ((int)basicOpenerConfigAclPrefs[9] == 1), "chk_config_opener");
|
||||
printCheckBox(response, "CONFOPNFOB3", "Fob Action 3", ((int)basicOpenerConfigAclPrefs[10] == 1), "chk_config_opener");
|
||||
printCheckBox(response, "CONFOPNOPM", "Operating Mode", ((int)basicOpenerConfigAclPrefs[11] == 1), "chk_config_opener");
|
||||
printCheckBox(response, "CONFOPNADVM", "Advertising Mode", ((int)basicOpenerConfigAclPrefs[12] == 1), "chk_config_opener");
|
||||
printCheckBox(response, "CONFOPNTZID", "Timezone ID", ((int)basicOpenerConfigAclPrefs[13] == 1), "chk_config_opener");
|
||||
|
||||
printCheckBox(response, "CONFOPNICID", "Intercom ID", ((int)advancedOpenerConfigAclPrefs[0] == 1), "chk_config_opener");
|
||||
printCheckBox(response, "CONFOPNBUSMS", "BUS mode Switch", ((int)advancedOpenerConfigAclPrefs[1] == 1), "chk_config_opener");
|
||||
printCheckBox(response, "CONFOPNSCDUR", "Short Circuit Duration", ((int)advancedOpenerConfigAclPrefs[2] == 1), "chk_config_opener");
|
||||
printCheckBox(response, "CONFOPNESD", "Eletric Strike Delay", ((int)advancedOpenerConfigAclPrefs[3] == 1), "chk_config_opener");
|
||||
printCheckBox(response, "CONFOPNRESD", "Random Electric Strike Delay", ((int)advancedOpenerConfigAclPrefs[4] == 1), "chk_config_opener");
|
||||
printCheckBox(response, "CONFOPNESDUR", "Electric Strike Duration", ((int)advancedOpenerConfigAclPrefs[5] == 1), "chk_config_opener");
|
||||
printCheckBox(response, "CONFOPNDRTOAR", "Disable RTO after ring", ((int)advancedOpenerConfigAclPrefs[6] == 1), "chk_config_opener");
|
||||
printCheckBox(response, "CONFOPNRTOT", "RTO timeout", ((int)advancedOpenerConfigAclPrefs[7] == 1), "chk_config_opener");
|
||||
printCheckBox(response, "CONFOPNDRBSUP", "Doorbell suppression", ((int)advancedOpenerConfigAclPrefs[8] == 1), "chk_config_opener");
|
||||
printCheckBox(response, "CONFOPNDRBSUPDUR", "Doorbell suppression duration", ((int)advancedOpenerConfigAclPrefs[9] == 1), "chk_config_opener");
|
||||
printCheckBox(response, "CONFOPNSRING", "Sound Ring", ((int)advancedOpenerConfigAclPrefs[10] == 1), "chk_config_opener");
|
||||
printCheckBox(response, "CONFOPNSOPN", "Sound Open", ((int)advancedOpenerConfigAclPrefs[11] == 1), "chk_config_opener");
|
||||
printCheckBox(response, "CONFOPNSRTO", "Sound RTO", ((int)advancedOpenerConfigAclPrefs[12] == 1), "chk_config_opener");
|
||||
printCheckBox(response, "CONFOPNSCM", "Sound CM", ((int)advancedOpenerConfigAclPrefs[13] == 1), "chk_config_opener");
|
||||
printCheckBox(response, "CONFOPNSCFRM", "Sound confirmation", ((int)advancedOpenerConfigAclPrefs[14] == 1), "chk_config_opener");
|
||||
printCheckBox(response, "CONFOPNSLVL", "Sound level", ((int)advancedOpenerConfigAclPrefs[15] == 1), "chk_config_opener");
|
||||
printCheckBox(response, "CONFOPNSBPA", "Single button press action", ((int)advancedOpenerConfigAclPrefs[16] == 1), "chk_config_opener");
|
||||
printCheckBox(response, "CONFOPNDBPA", "Double button press action", ((int)advancedOpenerConfigAclPrefs[17] == 1), "chk_config_opener");
|
||||
printCheckBox(response, "CONFOPNBATT", "Battery type", ((int)advancedOpenerConfigAclPrefs[18] == 1), "chk_config_opener");
|
||||
printCheckBox(response, "CONFOPNABTD", "Automatic battery type detection", ((int)advancedOpenerConfigAclPrefs[19] == 1), "chk_config_opener");
|
||||
response.concat("</table><br>");
|
||||
}
|
||||
response.concat("<br><input type=\"submit\" name=\"submit\" value=\"Save\">");
|
||||
@@ -1041,12 +1435,12 @@ void WebCfgServer::buildNukiConfigHtml(String &response)
|
||||
response.concat("<form method=\"post\" action=\"savecfg\">");
|
||||
response.concat("<h3>Basic Nuki Configuration</h3>");
|
||||
response.concat("<table>");
|
||||
printCheckBox(response, "LOCKENA", "Nuki Smartlock enabled", _preferences->getBool(preference_lock_enabled));
|
||||
printCheckBox(response, "LOCKENA", "Nuki Smartlock enabled", _preferences->getBool(preference_lock_enabled), "");
|
||||
if(_preferences->getBool(preference_lock_enabled))
|
||||
{
|
||||
printInputField(response, "MQTTPATH", "MQTT Nuki Smartlock Path", _preferences->getString(preference_mqtt_lock_path).c_str(), 180);
|
||||
}
|
||||
printCheckBox(response, "OPENA", "Nuki Opener enabled", _preferences->getBool(preference_opener_enabled));
|
||||
printCheckBox(response, "OPENA", "Nuki Opener enabled", _preferences->getBool(preference_opener_enabled), "");
|
||||
if(_preferences->getBool(preference_opener_enabled))
|
||||
{
|
||||
printInputField(response, "MQTTOPPATH", "MQTT Nuki Opener Path", _preferences->getString(preference_mqtt_opener_path).c_str(), 180);
|
||||
@@ -1065,7 +1459,7 @@ void WebCfgServer::buildNukiConfigHtml(String &response)
|
||||
}
|
||||
printInputField(response, "NRTRY", "Number of retries if command failed", _preferences->getInt(preference_command_nr_of_retries), 10);
|
||||
printInputField(response, "TRYDLY", "Delay between retries (milliseconds)", _preferences->getInt(preference_command_retry_delay), 10);
|
||||
printCheckBox(response, "REGAPP", "Nuki Bridge is running alongside Nuki Hub (needs re-pairing if changed)", _preferences->getBool(preference_register_as_app));
|
||||
printCheckBox(response, "REGAPP", "Nuki Bridge is running alongside Nuki Hub (needs re-pairing if changed)", _preferences->getBool(preference_register_as_app), "");
|
||||
printInputField(response, "PRDTMO", "Presence detection timeout (seconds; -1 to disable)", _preferences->getInt(preference_presence_detection_timeout), 10);
|
||||
printInputField(response, "RSBC", "Restart if bluetooth beacons not received (seconds; -1 to disable)", _preferences->getInt(preference_restart_ble_beacon_lost), 10);
|
||||
response.concat("</table>");
|
||||
@@ -1146,6 +1540,11 @@ void WebCfgServer::buildInfoHtml(String &response)
|
||||
|
||||
if(_nuki != nullptr)
|
||||
{
|
||||
uint32_t basicLockConfigAclPrefs[16];
|
||||
_preferences->getBytes(preference_conf_lock_basic_acl, &basicLockConfigAclPrefs, sizeof(basicLockConfigAclPrefs));
|
||||
uint32_t advancedLockConfigAclPrefs[22];
|
||||
_preferences->getBytes(preference_conf_lock_advanced_acl, &advancedLockConfigAclPrefs, sizeof(advancedLockConfigAclPrefs));
|
||||
|
||||
response.concat("Lock firmware version: ");
|
||||
response.concat(_nuki->firmwareVersion().c_str());
|
||||
response.concat("\nLock hardware version: ");
|
||||
@@ -1176,10 +1575,91 @@ void WebCfgServer::buildInfoHtml(String &response)
|
||||
response.concat((int)aclPrefs[7] ? "Allowed\n" : "Disallowed\n");
|
||||
response.concat("Lock ACL (Fob Action 3): ");
|
||||
response.concat((int)aclPrefs[8] ? "Allowed\n" : "Disallowed\n");
|
||||
response.concat("Lock config ACL (Name): ");
|
||||
response.concat((int)basicLockConfigAclPrefs[0] ? "Allowed\n" : "Disallowed\n");
|
||||
response.concat("Lock config ACL (Latitude): ");
|
||||
response.concat((int)basicLockConfigAclPrefs[1] ? "Allowed\n" : "Disallowed\n");
|
||||
response.concat("Lock config ACL (Longitude): ");
|
||||
response.concat((int)basicLockConfigAclPrefs[2] ? "Allowed\n" : "Disallowed\n");
|
||||
response.concat("Lock config ACL (Auto Unlatch): ");
|
||||
response.concat((int)basicLockConfigAclPrefs[3] ? "Allowed\n" : "Disallowed\n");
|
||||
response.concat("Lock config ACL (Pairing enabled): ");
|
||||
response.concat((int)basicLockConfigAclPrefs[4] ? "Allowed\n" : "Disallowed\n");
|
||||
response.concat("Lock config ACL (Button enabled): ");
|
||||
response.concat((int)basicLockConfigAclPrefs[5] ? "Allowed\n" : "Disallowed\n");
|
||||
response.concat("Lock config ACL (LED flash enabled): ");
|
||||
response.concat((int)basicLockConfigAclPrefs[6] ? "Allowed\n" : "Disallowed\n");
|
||||
response.concat("Lock config ACL (LED brightness): ");
|
||||
response.concat((int)basicLockConfigAclPrefs[7] ? "Allowed\n" : "Disallowed\n");
|
||||
response.concat("Lock config ACL (Timezone offset): ");
|
||||
response.concat((int)basicLockConfigAclPrefs[8] ? "Allowed\n" : "Disallowed\n");
|
||||
response.concat("Lock config ACL (DST mode): ");
|
||||
response.concat((int)basicLockConfigAclPrefs[9] ? "Allowed\n" : "Disallowed\n");
|
||||
response.concat("Lock config ACL (Fob Action 1): ");
|
||||
response.concat((int)basicLockConfigAclPrefs[10] ? "Allowed\n" : "Disallowed\n");
|
||||
response.concat("Lock config ACL (Fob Action 2): ");
|
||||
response.concat((int)basicLockConfigAclPrefs[11] ? "Allowed\n" : "Disallowed\n");
|
||||
response.concat("Lock config ACL (Fob Action 3): ");
|
||||
response.concat((int)basicLockConfigAclPrefs[12] ? "Allowed\n" : "Disallowed\n");
|
||||
response.concat("Lock config ACL (Single Lock): ");
|
||||
response.concat((int)basicLockConfigAclPrefs[13] ? "Allowed\n" : "Disallowed\n");
|
||||
response.concat("Lock config ACL (Advertising Mode): ");
|
||||
response.concat((int)basicLockConfigAclPrefs[14] ? "Allowed\n" : "Disallowed\n");
|
||||
response.concat("Lock config ACL (Timezone ID): ");
|
||||
response.concat((int)basicLockConfigAclPrefs[15] ? "Allowed\n" : "Disallowed\n");
|
||||
response.concat("Lock config ACL (Unlocked Position Offset Degrees): ");
|
||||
response.concat((int)advancedLockConfigAclPrefs[0] ? "Allowed\n" : "Disallowed\n");
|
||||
response.concat("Lock config ACL (Locked Position Offset Degrees): ");
|
||||
response.concat((int)advancedLockConfigAclPrefs[1] ? "Allowed\n" : "Disallowed\n");
|
||||
response.concat("Lock config ACL (Single Locked Position Offset Degrees): ");
|
||||
response.concat((int)advancedLockConfigAclPrefs[2] ? "Allowed\n" : "Disallowed\n");
|
||||
response.concat("Lock config ACL (Unlocked To Locked Transition Offset Degrees): ");
|
||||
response.concat((int)advancedLockConfigAclPrefs[3] ? "Allowed\n" : "Disallowed\n");
|
||||
response.concat("Lock config ACL (Lock n Go timeout): ");
|
||||
response.concat((int)advancedLockConfigAclPrefs[4] ? "Allowed\n" : "Disallowed\n");
|
||||
response.concat("Lock config ACL (Single button press action): ");
|
||||
response.concat((int)advancedLockConfigAclPrefs[5] ? "Allowed\n" : "Disallowed\n");
|
||||
response.concat("Lock config ACL (Double button press action): ");
|
||||
response.concat((int)advancedLockConfigAclPrefs[6] ? "Allowed\n" : "Disallowed\n");
|
||||
response.concat("Lock config ACL (Detached cylinder): ");
|
||||
response.concat((int)advancedLockConfigAclPrefs[7] ? "Allowed\n" : "Disallowed\n");
|
||||
response.concat("Lock config ACL (Battery type): ");
|
||||
response.concat((int)advancedLockConfigAclPrefs[8] ? "Allowed\n" : "Disallowed\n");
|
||||
response.concat("Lock config ACL (Automatic battery type detection): ");
|
||||
response.concat((int)advancedLockConfigAclPrefs[9] ? "Allowed\n" : "Disallowed\n");
|
||||
response.concat("Lock config ACL (Unlatch duration): ");
|
||||
response.concat((int)advancedLockConfigAclPrefs[10] ? "Allowed\n" : "Disallowed\n");
|
||||
response.concat("Lock config ACL (Auto lock timeout): ");
|
||||
response.concat((int)advancedLockConfigAclPrefs[11] ? "Allowed\n" : "Disallowed\n");
|
||||
response.concat("Lock config ACL (Auto unlock disabled): ");
|
||||
response.concat((int)advancedLockConfigAclPrefs[12] ? "Allowed\n" : "Disallowed\n");
|
||||
response.concat("Lock config ACL (Nightmode enabled): ");
|
||||
response.concat((int)advancedLockConfigAclPrefs[13] ? "Allowed\n" : "Disallowed\n");
|
||||
response.concat("Lock config ACL (Nightmode start time): ");
|
||||
response.concat((int)advancedLockConfigAclPrefs[14] ? "Allowed\n" : "Disallowed\n");
|
||||
response.concat("Lock config ACL (Nightmode end time): ");
|
||||
response.concat((int)advancedLockConfigAclPrefs[15] ? "Allowed\n" : "Disallowed\n");
|
||||
response.concat("Lock config ACL (Nightmode auto lock enabled): ");
|
||||
response.concat((int)advancedLockConfigAclPrefs[16] ? "Allowed\n" : "Disallowed\n");
|
||||
response.concat("Lock config ACL (Nightmode auto unlock disabled): ");
|
||||
response.concat((int)advancedLockConfigAclPrefs[17] ? "Allowed\n" : "Disallowed\n");
|
||||
response.concat("Lock config ACL (Nightmode immediate lock on start): ");
|
||||
response.concat((int)advancedLockConfigAclPrefs[18] ? "Allowed\n" : "Disallowed\n");
|
||||
response.concat("Lock config ACL (Auto lock enabled): ");
|
||||
response.concat((int)advancedLockConfigAclPrefs[19] ? "Allowed\n" : "Disallowed\n");
|
||||
response.concat("Lock config ACL (Immediate auto lock enabled): ");
|
||||
response.concat((int)advancedLockConfigAclPrefs[20] ? "Allowed\n" : "Disallowed\n");
|
||||
response.concat("Lock config ACL (Auto update enabled): ");
|
||||
response.concat((int)advancedLockConfigAclPrefs[21] ? "Allowed\n" : "Disallowed\n");
|
||||
}
|
||||
|
||||
if(_nukiOpener != nullptr)
|
||||
{
|
||||
uint32_t basicOpenerConfigAclPrefs[16];
|
||||
_preferences->getBytes(preference_conf_opener_basic_acl, &basicOpenerConfigAclPrefs, sizeof(basicOpenerConfigAclPrefs));
|
||||
uint32_t advancedOpenerConfigAclPrefs[22];
|
||||
_preferences->getBytes(preference_conf_opener_advanced_acl, &advancedOpenerConfigAclPrefs, sizeof(advancedOpenerConfigAclPrefs));
|
||||
|
||||
response.concat("Opener firmware version: ");
|
||||
response.concat(_nukiOpener->firmwareVersion().c_str());
|
||||
response.concat("\nOpener hardware version: ");
|
||||
@@ -1205,6 +1685,74 @@ void WebCfgServer::buildInfoHtml(String &response)
|
||||
response.concat((int)aclPrefs[15] ? "Allowed\n" : "Disallowed\n");
|
||||
response.concat("Opener ACL (Fob Action 3): ");
|
||||
response.concat((int)aclPrefs[16] ? "Allowed\n" : "Disallowed\n");
|
||||
response.concat("Opener config ACL (Name): ");
|
||||
response.concat((int)basicOpenerConfigAclPrefs[0] ? "Allowed\n" : "Disallowed\n");
|
||||
response.concat("Opener config ACL (Latitude): ");
|
||||
response.concat((int)basicOpenerConfigAclPrefs[1] ? "Allowed\n" : "Disallowed\n");
|
||||
response.concat("Opener config ACL (Longitude): ");
|
||||
response.concat((int)basicOpenerConfigAclPrefs[2] ? "Allowed\n" : "Disallowed\n");
|
||||
response.concat("Opener config ACL (Pairing enabled): ");
|
||||
response.concat((int)basicOpenerConfigAclPrefs[3] ? "Allowed\n" : "Disallowed\n");
|
||||
response.concat("Opener config ACL (Button enabled): ");
|
||||
response.concat((int)basicOpenerConfigAclPrefs[4] ? "Allowed\n" : "Disallowed\n");
|
||||
response.concat("Opener config ACL (LED flash enabled): ");
|
||||
response.concat((int)basicOpenerConfigAclPrefs[5] ? "Allowed\n" : "Disallowed\n");
|
||||
response.concat("Opener config ACL (Timezone offset): ");
|
||||
response.concat((int)basicOpenerConfigAclPrefs[6] ? "Allowed\n" : "Disallowed\n");
|
||||
response.concat("Opener config ACL (DST mode): ");
|
||||
response.concat((int)basicOpenerConfigAclPrefs[7] ? "Allowed\n" : "Disallowed\n");
|
||||
response.concat("Opener config ACL (Fob Action 1): ");
|
||||
response.concat((int)basicOpenerConfigAclPrefs[8] ? "Allowed\n" : "Disallowed\n");
|
||||
response.concat("Opener config ACL (Fob Action 2): ");
|
||||
response.concat((int)basicOpenerConfigAclPrefs[9] ? "Allowed\n" : "Disallowed\n");
|
||||
response.concat("Opener config ACL (Fob Action 3): ");
|
||||
response.concat((int)basicOpenerConfigAclPrefs[10] ? "Allowed\n" : "Disallowed\n");
|
||||
response.concat("Opener config ACL (Operating Mode): ");
|
||||
response.concat((int)basicOpenerConfigAclPrefs[11] ? "Allowed\n" : "Disallowed\n");
|
||||
response.concat("Opener config ACL (Advertising Mode): ");
|
||||
response.concat((int)basicOpenerConfigAclPrefs[12] ? "Allowed\n" : "Disallowed\n");
|
||||
response.concat("Opener config ACL (Timezone ID): ");
|
||||
response.concat((int)basicOpenerConfigAclPrefs[13] ? "Allowed\n" : "Disallowed\n");
|
||||
response.concat("Opener config ACL (Intercom ID): ");
|
||||
response.concat((int)advancedOpenerConfigAclPrefs[0] ? "Allowed\n" : "Disallowed\n");
|
||||
response.concat("Opener config ACL (BUS mode Switch): ");
|
||||
response.concat((int)advancedOpenerConfigAclPrefs[1] ? "Allowed\n" : "Disallowed\n");
|
||||
response.concat("Opener config ACL (Short Circuit Duration): ");
|
||||
response.concat((int)advancedOpenerConfigAclPrefs[2] ? "Allowed\n" : "Disallowed\n");
|
||||
response.concat("Opener config ACL (Eletric Strike Delay): ");
|
||||
response.concat((int)advancedOpenerConfigAclPrefs[3] ? "Allowed\n" : "Disallowed\n");
|
||||
response.concat("Opener config ACL (Random Electric Strike Delay): ");
|
||||
response.concat((int)advancedOpenerConfigAclPrefs[4] ? "Allowed\n" : "Disallowed\n");
|
||||
response.concat("Opener config ACL (Electric Strike Duration): ");
|
||||
response.concat((int)advancedOpenerConfigAclPrefs[5] ? "Allowed\n" : "Disallowed\n");
|
||||
response.concat("Opener config ACL (Disable RTO after ring): ");
|
||||
response.concat((int)advancedOpenerConfigAclPrefs[6] ? "Allowed\n" : "Disallowed\n");
|
||||
response.concat("Opener config ACL (RTO timeout): ");
|
||||
response.concat((int)advancedOpenerConfigAclPrefs[7] ? "Allowed\n" : "Disallowed\n");
|
||||
response.concat("Opener config ACL (Doorbell suppression): ");
|
||||
response.concat((int)advancedOpenerConfigAclPrefs[8] ? "Allowed\n" : "Disallowed\n");
|
||||
response.concat("Opener config ACL (Doorbell suppression duration): ");
|
||||
response.concat((int)advancedOpenerConfigAclPrefs[9] ? "Allowed\n" : "Disallowed\n");
|
||||
response.concat("Opener config ACL (Sound Ring): ");
|
||||
response.concat((int)advancedOpenerConfigAclPrefs[10] ? "Allowed\n" : "Disallowed\n");
|
||||
response.concat("Opener config ACL (Sound Open): ");
|
||||
response.concat((int)advancedOpenerConfigAclPrefs[11] ? "Allowed\n" : "Disallowed\n");
|
||||
response.concat("Opener config ACL (Sound RTO): ");
|
||||
response.concat((int)advancedOpenerConfigAclPrefs[12] ? "Allowed\n" : "Disallowed\n");
|
||||
response.concat("Opener config ACL (Sound CM): ");
|
||||
response.concat((int)advancedOpenerConfigAclPrefs[13] ? "Allowed\n" : "Disallowed\n");
|
||||
response.concat("Opener config ACL (Sound confirmation): ");
|
||||
response.concat((int)advancedOpenerConfigAclPrefs[14] ? "Allowed\n" : "Disallowed\n");
|
||||
response.concat("Opener config ACL (Sound level): ");
|
||||
response.concat((int)advancedOpenerConfigAclPrefs[15] ? "Allowed\n" : "Disallowed\n");
|
||||
response.concat("Opener config ACL (Single button press action): ");
|
||||
response.concat((int)advancedOpenerConfigAclPrefs[16] ? "Allowed\n" : "Disallowed\n");
|
||||
response.concat("Opener config ACL (Double button press action): ");
|
||||
response.concat((int)advancedOpenerConfigAclPrefs[17] ? "Allowed\n" : "Disallowed\n");
|
||||
response.concat("Opener config ACL (Battery type): ");
|
||||
response.concat((int)advancedOpenerConfigAclPrefs[18] ? "Allowed\n" : "Disallowed\n");
|
||||
response.concat("Opener config ACL (Automatic battery type detection): ");
|
||||
response.concat((int)advancedOpenerConfigAclPrefs[19] ? "Allowed\n" : "Disallowed\n");
|
||||
}
|
||||
|
||||
response.concat("Network device: ");
|
||||
@@ -1337,7 +1885,7 @@ void WebCfgServer::printInputField(String& response,
|
||||
printInputField(response, token, description, valueStr, maxLength);
|
||||
}
|
||||
|
||||
void WebCfgServer::printCheckBox(String &response, const char *token, const char *description, const bool value)
|
||||
void WebCfgServer::printCheckBox(String &response, const char *token, const char *description, const bool value, const char *htmlClass)
|
||||
{
|
||||
response.concat("<tr><td>");
|
||||
response.concat(description);
|
||||
@@ -1350,6 +1898,8 @@ void WebCfgServer::printCheckBox(String &response, const char *token, const char
|
||||
|
||||
response.concat("<input type=checkbox name=\"");
|
||||
response.concat(token);
|
||||
response.concat("\" class=\"");
|
||||
response.concat(htmlClass);
|
||||
response.concat("\" value=\"1\"");
|
||||
response.concat(value ? " checked=\"checked\"" : "");
|
||||
response.concat("/></td></tr>");
|
||||
|
||||
@@ -54,7 +54,7 @@ private:
|
||||
void buildHtmlHeader(String& response);
|
||||
void printInputField(String& response, const char* token, const char* description, const char* value, const size_t& maxLength, const bool& isPassword = false, const bool& showLengthRestriction = false);
|
||||
void printInputField(String& response, const char* token, const char* description, const int value, size_t maxLength);
|
||||
void printCheckBox(String& response, const char* token, const char* description, const bool value);
|
||||
void printCheckBox(String& response, const char* token, const char* description, const bool value, const char* htmlClass);
|
||||
void printTextarea(String& response, const char *token, const char *description, const char *value, const size_t& maxLength, const bool& enabled = true, const bool& showLengthRestriction = false);
|
||||
void printDropDown(String &response, const char *token, const char *description, const String preselectedValue, std::vector<std::pair<String, String>> options);
|
||||
void buildNavigationButton(String& response, const char* caption, const char* targetPath, const char* labelText = "");
|
||||
|
||||
56
src/main.cpp
56
src/main.cpp
@@ -112,8 +112,8 @@ void setupTasks()
|
||||
{
|
||||
// configMAX_PRIORITIES is 25
|
||||
|
||||
xTaskCreatePinnedToCore(networkTask, "ntw", 8192, NULL, 3, &networkTaskHandle, 1);
|
||||
xTaskCreatePinnedToCore(nukiTask, "nuki", 3328, NULL, 2, &nukiTaskHandle, 1);
|
||||
xTaskCreatePinnedToCore(networkTask, "ntw", 10240, NULL, 3, &networkTaskHandle, 1);
|
||||
xTaskCreatePinnedToCore(nukiTask, "nuki", 5120, NULL, 2, &nukiTaskHandle, 1);
|
||||
xTaskCreatePinnedToCore(presenceDetectionTask, "prdet", 896, NULL, 5, &presenceDetectionTaskHandle, 1);
|
||||
}
|
||||
|
||||
@@ -146,10 +146,16 @@ bool initPreferences()
|
||||
{
|
||||
preferences->putBool(preference_started_before, true);
|
||||
preferences->putBool(preference_lock_enabled, true);
|
||||
preferences->putBool(preference_admin_enabled, true);
|
||||
|
||||
uint32_t aclPrefs[17] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
|
||||
preferences->putBytes(preference_acl, (byte*)(&aclPrefs), sizeof(aclPrefs));
|
||||
uint32_t basicLockConfigAclPrefs[16] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
|
||||
preferences->putBytes(preference_conf_lock_basic_acl, (byte*)(&basicLockConfigAclPrefs), sizeof(basicLockConfigAclPrefs));
|
||||
uint32_t basicOpenerConfigAclPrefs[14] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
|
||||
preferences->putBytes(preference_conf_opener_basic_acl, (byte*)(&basicOpenerConfigAclPrefs), sizeof(basicOpenerConfigAclPrefs));
|
||||
uint32_t advancedLockConfigAclPrefs[22] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
|
||||
preferences->putBytes(preference_conf_lock_advanced_acl, (byte*)(&advancedLockConfigAclPrefs), sizeof(advancedLockConfigAclPrefs));
|
||||
uint32_t advancedOpenerConfigAclPrefs[20] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
|
||||
preferences->putBytes(preference_conf_opener_advanced_acl, (byte*)(&advancedOpenerConfigAclPrefs), sizeof(advancedOpenerConfigAclPrefs));
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -173,40 +179,64 @@ bool initPreferences()
|
||||
case 0:
|
||||
{
|
||||
preferences->putBool(preference_keypad_control_enabled, true);
|
||||
preferences->putBool(preference_admin_enabled, true);
|
||||
|
||||
uint32_t aclPrefs[17] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1};
|
||||
preferences->putBytes(preference_acl, (byte*)(&aclPrefs), sizeof(aclPrefs));
|
||||
uint32_t basicLockConfigAclPrefs[16] = {0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0};
|
||||
preferences->putBytes(preference_conf_lock_basic_acl, (byte*)(&basicLockConfigAclPrefs), sizeof(basicLockConfigAclPrefs));
|
||||
uint32_t basicOpenerConfigAclPrefs[14] = {0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||
preferences->putBytes(preference_conf_opener_basic_acl, (byte*)(&basicOpenerConfigAclPrefs), sizeof(basicOpenerConfigAclPrefs));
|
||||
uint32_t advancedLockConfigAclPrefs[22] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0};
|
||||
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, 1, 0, 0, 0, 0};
|
||||
preferences->putBytes(preference_conf_opener_advanced_acl, (byte*)(&advancedOpenerConfigAclPrefs), sizeof(advancedOpenerConfigAclPrefs));
|
||||
break;
|
||||
}
|
||||
case 1:
|
||||
{
|
||||
preferences->putBool(preference_keypad_control_enabled, false);
|
||||
preferences->putBool(preference_admin_enabled, false);
|
||||
|
||||
uint32_t aclPrefs[17] = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 0};
|
||||
preferences->putBytes(preference_acl, (byte*)(&aclPrefs), sizeof(aclPrefs));
|
||||
uint32_t basicLockConfigAclPrefs[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||
preferences->putBytes(preference_conf_lock_basic_acl, (byte*)(&basicLockConfigAclPrefs), sizeof(basicLockConfigAclPrefs));
|
||||
uint32_t basicOpenerConfigAclPrefs[14] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||
preferences->putBytes(preference_conf_opener_basic_acl, (byte*)(&basicOpenerConfigAclPrefs), sizeof(basicOpenerConfigAclPrefs));
|
||||
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};
|
||||
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));
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
preferences->putBool(preference_keypad_control_enabled, false);
|
||||
preferences->putBool(preference_admin_enabled, false);
|
||||
|
||||
uint32_t aclPrefs[17] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||
preferences->putBytes(preference_acl, (byte*)(&aclPrefs), sizeof(aclPrefs));
|
||||
uint32_t basicLockConfigAclPrefs[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||
preferences->putBytes(preference_conf_lock_basic_acl, (byte*)(&basicLockConfigAclPrefs), sizeof(basicLockConfigAclPrefs));
|
||||
uint32_t basicOpenerConfigAclPrefs[14] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||
preferences->putBytes(preference_conf_opener_basic_acl, (byte*)(&basicOpenerConfigAclPrefs), sizeof(basicOpenerConfigAclPrefs));
|
||||
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};
|
||||
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));
|
||||
break;
|
||||
}
|
||||
case 3:
|
||||
{
|
||||
preferences->putBool(preference_keypad_control_enabled, false);
|
||||
preferences->putBool(preference_admin_enabled, false);
|
||||
|
||||
uint32_t aclPrefs[17] = {1, 1, 0, 1, 0, 1, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0, 0};
|
||||
preferences->putBytes(preference_acl, (byte*)(&aclPrefs), sizeof(aclPrefs));
|
||||
uint32_t basicLockConfigAclPrefs[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||
preferences->putBytes(preference_conf_lock_basic_acl, (byte*)(&basicLockConfigAclPrefs), sizeof(basicLockConfigAclPrefs));
|
||||
uint32_t basicOpenerConfigAclPrefs[14] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
|
||||
preferences->putBytes(preference_conf_opener_basic_acl, (byte*)(&basicOpenerConfigAclPrefs), sizeof(basicOpenerConfigAclPrefs));
|
||||
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};
|
||||
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));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
preferences->putInt(preference_config_version, atof(NUKI_HUB_VERSION) * 100);
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "../PreferencesKeys.h"
|
||||
#include "../Logger.h"
|
||||
#include "../MqttTopics.h"
|
||||
#include "sdkconfig.h"
|
||||
|
||||
W5500Device::W5500Device(const String &hostname, Preferences* preferences, const IPConfiguration* ipConfiguration, int variant)
|
||||
: NetworkDevice(hostname, ipConfiguration),
|
||||
@@ -48,7 +49,11 @@ void W5500Device::initialize()
|
||||
{
|
||||
case W5500Variant::M5StackAtomPoe:
|
||||
_resetPin = -1;
|
||||
#if defined(CONFIG_IDF_TARGET_ESP32S3)
|
||||
Ethernet.init(6, 5, 7, 8);
|
||||
#else
|
||||
Ethernet.init(19, 22, 23, 33);
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
_resetPin = -1;
|
||||
|
||||
@@ -14,13 +14,13 @@
|
||||
{
|
||||
"chipFamily": "ESP32-S3",
|
||||
"parts": [
|
||||
{ "path": "nuki_hub_esp32s3.bin", "offset": 0 }
|
||||
{ "path": "webflash_nuki_hub_esp32s3.bin", "offset": 0 }
|
||||
]
|
||||
},
|
||||
{
|
||||
"chipFamily": "ESP32-C3",
|
||||
"parts": [
|
||||
{ "path": "nuki_hub_esp32c3.bin", "offset": 0 }
|
||||
{ "path": "webflash_nuki_hub_esp32c3.bin", "offset": 0 }
|
||||
]
|
||||
}
|
||||
]
|
||||
|
||||
Binary file not shown.
Binary file not shown.
BIN
webflash/webflash_nuki_hub_esp32.bin
Normal file
BIN
webflash/webflash_nuki_hub_esp32.bin
Normal file
Binary file not shown.
Binary file not shown.
BIN
webflash/webflash_nuki_hub_esp32s3.bin
Normal file
BIN
webflash/webflash_nuki_hub_esp32s3.bin
Normal file
Binary file not shown.
Reference in New Issue
Block a user