Nuki Card with Callback support (supports both Lock & Opener, it replaces the official integration)

A request to all users of the Nuki Card: here’s the refactored version in package format. I basically had to port everything to the automation platform with the legacy syntax (that I don’t like at all). The new Template trigger syntax is far more efficient and logical, but unfortunately can’t be packaged, so based on the input of @spokin, I completed a working packaged version. It works here, I tested it for 2hrs, but before officially releasing it, I need your help. At least 4-5 people should kindly test it and report if it’s working.

You need the same 4 secrets items in secrets.yaml (host, port, token and webhook), plus you need to create a folder called packages in the main CONFIG folder, and in that folder you create a file called nuki_card_callback.yaml, and you paste this code at the bottom of the post in it.

nuki_bridge_host: "nuki-bridge.axel.dom"
nuki_bridge_port: "8080"
nuki_bridge_token: "txxxxhl"
nuki_bridge_webhook: eyJ0eXAiOiJKVxyxyxyxyxyxyxyxy1NiJ9.eyJpc3MiOiI3OGQxMDJk

Then, in configuration.yaml, under the homeassistant: section you reference the directory containing all packages:

image

Here’s the code for nuki_card_callback.yaml:

########################
# Nuki Card v6.0-rc2   #
########################

#######################################################################################################################
###                                                                                                                 ###
### Automations                                                                                                     ###
###                                                                                                                 ###
#######################################################################################################################

automation:
  - id: "nuki_card_callback"
    alias: Nuki Card Callback
    description: Automation for the Nuki doorlock
    trigger:
      - platform: webhook
        webhook_id: !secret nuki_bridge_webhook
      - platform: event
        event_type:
          - automation_reloaded
          - event_template_reloaded
      - platform: state
        entity_id: sensor.nuki_door_sensor_state
        to:
          - "open"
          - "closed"
      - platform: state
        entity_id: sensor.nuki_lock_sensor_state
        to:
          - "locked"
          - "unlocked"
    condition: []
    action:
      - choose:
          - conditions: >
              {{ trigger.platform == 'webhook' }}
            sequence:
              - service: input_text.set_value
                target:
                  entity_id: input_text.nuki_bridge_door_sensor
                data:
                  value: >
                    {% set my_state = {1: 'deactivated', 2: 'closed', 3: 'open', 4: 'unknown', 5: 'calibrating'} %}
                    {{ my_state[trigger.json.doorsensorState] }}
              - service: input_text.set_value
                target:
                  entity_id: input_text.nuki_bridge_lock_sensor
                data:
                  value: >
                    {% set my_state = {0: 'uncalibrated', 1: 'locked', 2:'unlocking', 3: 'unlocked', 4: 'locking', 5: 'unlatched', 6: "unlocked (lock 'n' go)", 7: 'unlatching', 254: 'motor blocked', 255: 'undefined'} %}
                    {{ my_state[trigger.json.state] }}
              - service: input_text.set_value
                target:
                  entity_id: input_text.nuki_bridge_last_activity
                data:
                  value: >
                    {{ as_timestamp(now()) | timestamp_custom("%H:%M:%S (%b %d)") }}
              - service: input_text.set_value
                target:
                  entity_id: input_text.nuki_bridge_trigger_platform
                data:
                  value: >
                    {{ trigger.platform }}
          - conditions: >
              {{ trigger.platform == 'state' or trigger.platform == 'event' }}
            sequence:
              - service: input_text.set_value
                target:
                  entity_id: input_text.nuki_bridge_door_sensor
                data:
                  value: >
                    {{ states('sensor.nuki_door_sensor_state') }}
              - service: input_text.set_value
                target:
                  entity_id: input_text.nuki_bridge_lock_sensor
                data:
                  value: >
                    {{ states('sensor.nuki_lock_sensor_state') }}
              - service: input_text.set_value
                target:
                  entity_id: input_text.nuki_bridge_last_activity
                data:
                  value: >
                    {{ states('sensor.nuki_last_activity') }}
              - service: input_text.set_value
                target:
                  entity_id: input_text.nuki_bridge_trigger_platform
                data:
                  value: >
                    {{ trigger.platform }}
        default: []
    mode: single

#######################################################################################################################
###                                                                                                                 ###
### Binary sensors                                                                                                  ###
###                                                                                                                 ###
#######################################################################################################################

binary_sensor:
  - platform: template
    sensors:
      nuki_door_state:
        unique_id: nuki_door_state
        friendly_name: "Nuki Door State"
        device_class: door
        value_template: >
          {{ is_state('input_text.nuki_bridge_door_sensor', 'open') }}
        availability_template: >
          {{ (is_state('sensor.nuki_door_sensor_state', 'open') or is_state('sensor.nuki_door_sensor_state', 'closed')) }}
        icon_template: >
          {% set trigdoor = states('input_text.nuki_bridge_door_sensor') %}
          {% set triglock = states('input_text.nuki_bridge_lock_sensor') %}
          {% if (trigdoor == 'open') %}
            mdi:door-open
          {% elif trigdoor == 'closed' and triglock == 'locked' %}
            mdi:door-closed-lock
          {% elif trigdoor == 'closed' and triglock == 'unlocked' %}
            mdi:door-closed
          {% else %}
            mdi:alert-box-outline
          {% endif %}
        attribute_templates:
          trigger_platform: >
            {{ states('input_text.nuki_bridge_trigger_platform') }}
          nuki_id: >
            {{ states('sensor.nuki_id') }}
          door_state: >
            {{ states('input_text.nuki_bridge_door_sensor') }}
          lock_state: >
            {{ states('input_text.nuki_bridge_lock_sensor') }}
          lock_battery: >
            {{ states('sensor.nuki_lock_battery_level') }}
          lock_battery_critical: >
            {{ states('sensor.nuki_lock_battery_critical_state') }}
          keypad_battery_critical: >
            {% if states('sensor.nuki_keypad_battery_critical_state') != 'unknown' %}
              {{ states('sensor.nuki_keypad_battery_critical_state') }}
            {% else %}
              not installed 
            {% endif %}
          last_update: >
            {{ states('input_text.nuki_bridge_last_activity') }}
          last_update_polled: >
            {{ states('sensor.nuki_last_activity') }}
          door_sensor_polled: >
            {{ states('sensor.nuki_door_sensor_state') }}
          lock_sensor_polled: >
            {{ states('sensor.nuki_lock_sensor_state') }}

#######################################################################################################################
###                                                                                                                 ###
### Input Texts                                                                                                     ###
###                                                                                                                 ###
#######################################################################################################################
input_text:
  nuki_bridge_host:
    name: "Nuki Card (bridge host)"
    initial: !secret nuki_bridge_host
  nuki_bridge_port:
    name: "Nuki Card (bridge port)"
    initial: !secret nuki_bridge_port
  nuki_bridge_token:
    name: "Nuki Card (bridge token)"
    initial: !secret nuki_bridge_token
  nuki_bridge_door_sensor:
    name: "Nuki Card (door sensor)"
  nuki_bridge_lock_sensor:
    name: "Nuki Card (lock sensor)"
  nuki_bridge_last_activity:
    name: "Nuki Card (last activity)"
  nuki_bridge_trigger_platform:
    name: "Nuki Card (trigger platform)"

#######################################################################################################################
###                                                                                                                 ###
### Locks                                                                                                           ###
###                                                                                                                 ###
#######################################################################################################################

lock:
  - platform: template
    name: "Nuki Lock Action"
    unique_id: nuki_lock_action
    value_template: >
      {{ is_state_attr('binary_sensor.nuki_door_state', 'lock_state', 'locked') }}
    availability_template: >
      {{ is_state_attr('binary_sensor.nuki_door_state', 'lock_state', 'locked') or
        is_state_attr('binary_sensor.nuki_door_state', 'lock_state', 'unlocked')}}
    lock:
      service: rest_command.nuki_lock_action
      data:
        action: 2
    unlock:
      service: rest_command.nuki_lock_action
      data:
        action: 1

#######################################################################################################################
###                                                                                                                 ###
### rest commands                                                                                                   ###
###                                                                                                                 ###
#######################################################################################################################

rest_command:
  nuki_lock_action:
    url: "http://{{ states('input_text.nuki_bridge_host') }}:{{ states('input_text.nuki_bridge_port') }}/lockAction?nukiId={{ states('sensor.nuki_id') }}&token={{ states('input_text.nuki_bridge_token') | urlencode }}&action={{ action }}"

#######################################################################################################################
###                                                                                                                 ###
### sensors                                                                                                         ###
###                                                                                                                 ###
#######################################################################################################################

sensor:
  - platform: rest
    scan_interval: 150
    resource_template: "http://{{ states('input_text.nuki_bridge_host') }}:{{ states('input_text.nuki_bridge_port') }}/list?&token={{ states('input_text.nuki_bridge_token') | urlencode }}"
    name: "Nuki Endpoint List"
    value_template: "OK"
    json_attributes:
      - lastKnownState
      - firmwareVersion
      - nukiId
      - name

  - platform: rest
    scan_interval: 150
    resource_template: "http://{{ states('input_text.nuki_bridge_host') }}:{{ states('input_text.nuki_bridge_port') }}/info?&token={{ states('input_text.nuki_bridge_token') | urlencode }}"
    name: "Nuki Endpoint Info"
    value_template: "OK"
    json_attributes:
      - versions
      - scanResults
      - wlanConnected
      - serverConnected

  - platform: template
    sensors:
      nuki_device_name:
        unique_id: nuki_device_name
        friendly_name: "Nuki Device Name"
        icon_template: mdi:alphabetical-variant
        value_template: >
          {% if states('sensor.nuki_endpoint_info') == "OK" %}
            {{ state_attr('sensor.nuki_endpoint_info','scanResults')[0]['name'] }}
          {% endif %}

      nuki_bridge_fw_version:
        unique_id: nuki_bridge_fw_version
        friendly_name: "Nuki Bridge FW Version"
        icon_template: mdi:numeric
        value_template: >
          {% if states('sensor.nuki_endpoint_info') == "OK" %}
            {{ state_attr('sensor.nuki_endpoint_info','versions')['firmwareVersion'] }}
          {% endif %}

      nuki_bridge_lock_bt_rssi:
        unique_id: nuki_bridge_lock_bt_rssi
        friendly_name: "Nuki Bridge<->Lock BT RSSI"
        icon_template: mdi:signal-distance-variant
        value_template: >
          {% if states('sensor.nuki_endpoint_info') == "OK" %}
            {{ state_attr('sensor.nuki_endpoint_info','scanResults')[0]['rssi'] }}
          {% endif %}

      nuki_bridge_wifi_connected:
        unique_id: nuki_bridge_wifi_connected
        friendly_name: "Nuki Bridge WiFi Connected"
        icon_template: mdi:wifi-cog
        value_template: >
          {% if states('sensor.nuki_endpoint_info') == "OK" %}
            {{ state_attr('sensor.nuki_endpoint_info','wlanConnected') }}
          {% endif %}

      nuki_bridge_wifi_fw_version:
        unique_id: nuki_bridge_wifi_fw_version
        friendly_name: "Nuki Bridge WiFi FW Version"
        icon_template: mdi:numeric
        value_template: >
          {% if states('sensor.nuki_endpoint_info') == "OK" %}
            {{ state_attr('sensor.nuki_endpoint_info','versions')['wifiFirmwareVersion'] }}
          {% endif %}

      nuki_bridge_cloud_connected:
        unique_id: nuki_bridge_cloud_connected
        friendly_name: "Nuki Bridge Cloud Connected"
        icon_template: mdi:server-network
        value_template: >
          {% if states('sensor.nuki_endpoint_info') == "OK" %}
            {{ state_attr('sensor.nuki_endpoint_info','serverConnected') }}
          {% endif %}

      nuki_bridge_lock_bt_state:
        unique_id: nuki_bridge_lock_bt_state
        friendly_name: "Nuki Bridge<->Lock BT State"
        icon_template: >
          {% if states('sensor.nuki_endpoint_info') == "OK" %}
            {% if state_attr('sensor.nuki_endpoint_info','scanResults')[0]['paired'] %}
              mdi:bluetooth-connect
            {% elif not state_attr('sensor.nuki_endpoint_info','scanResults')[0]['paired'] %}
              mdi:bluetooth-off
            {% else %}
              mdi:bluetooth-audio
            {% endif %}
          {% endif %}
        value_template: >
          {% if states('sensor.nuki_endpoint_info') == "OK" %}
            {% if state_attr('sensor.nuki_endpoint_info','scanResults')[0]['paired'] %}
              connected
            {% elif not state_attr('sensor.nuki_endpoint_info','scanResults')[0]['paired'] %}
              disconnected
            {% else %}
              Unknown
            {% endif %}
          {% endif %}

      nuki_id:
        unique_id: nuki_id
        friendly_name: "Nuki ID"
        icon_template: mdi:numeric
        value_template: >
          {% if states('sensor.nuki_endpoint_list') == "OK" %}
            {{ state_attr('sensor.nuki_endpoint_list','nukiId') }}
          {% endif %}

      nuki_lock_fw_version:
        unique_id: nuki_lock_fw_version
        friendly_name: "Nuki Lock FW Version"
        icon_template: mdi:numeric
        value_template: >
          {% if states('sensor.nuki_endpoint_list') == "OK" %}
            {{ state_attr('sensor.nuki_endpoint_list','firmwareVersion') }}
          {% endif %}

      nuki_lock_battery_critical_state:
        unique_id: nuki_lock_battery_critical_state
        friendly_name: "Nuki Lock Battery Critical State"
        icon_template: mdi:battery-alert-variant-outline
        value_template: >
          {% if states('sensor.nuki_endpoint_list') == "OK" %}
            {{ state_attr('sensor.nuki_endpoint_list', 'lastKnownState')['batteryCritical'] }}
          {% endif %}

      nuki_friendly_name:
        unique_id: nuki_friendly_name
        friendly_name: "Nuki Friendly Name"
        icon_template: mdi:numeric
        value_template: >
          {% if states('sensor.nuki_endpoint_list') == "OK" %}
            {{ state_attr('sensor.nuki_endpoint_list','name') }}
          {% endif %}

      nuki_last_activity:
        unique_id: nuki_last_activity
        friendly_name: "Nuki Last Activity"
        icon_template: mdi:clock-check-outline
        value_template: >
          {% if states('sensor.nuki_endpoint_list') == "OK" %}
            {{ (as_timestamp(state_attr('sensor.nuki_endpoint_list', 'lastKnownState')['timestamp'])) | timestamp_custom("%H:%M:%S (%b %d)") }}
          {% endif %}

      nuki_lock_battery_level:
        unique_id: nuki_lock_battery_level
        friendly_name: "Nuki Lock Battery Level"
        device_class: "battery"
        unit_of_measurement: "%"
        icon_template: >
          {% if states('sensor.nuki_endpoint_list') == "OK" %}
            {% set battery_level = state_attr('sensor.nuki_endpoint_list', 'lastKnownState')['batteryChargeState'] | default(0) | int %}
            {% set battery_charging = state_attr('sensor.nuki_endpoint_list', 'lastKnownState')['batteryCharging'] %}
            {% set battery_round = (battery_level / 10) | int * 10 %}
            {% if battery_round >= 100 and not battery_charging %}
              mdi:battery
            {% elif battery_round >= 100 and battery_charging %}
              mdi:battery-charging
            {% elif battery_round > 0 and not battery_charging %}
              mdi:battery-{{ battery_round }}
            {% elif battery_round > 0 and battery_charging %}
              mdi:battery-charging-{{ battery_round }}
            {% else %}
              mdi:battery-alert-variant-outline
            {% endif %}
          {% endif %}
        value_template: >
          {% if states('sensor.nuki_endpoint_list') == "OK" %}
            {% set battery_level = state_attr('sensor.nuki_endpoint_list', 'lastKnownState')['batteryChargeState'] | default(0) | int %}
            {% if state_attr('sensor.nuki_endpoint_list', 'lastKnownState')['batteryCharging'] %}
              {{ battery_level }}
            {% else %}
              {{ battery_level }}
            {% endif %}
          {% endif %}

      nuki_door_sensor_state:
        unique_id: nuki_door_sensor_state
        friendly_name: "Nuki Door Sensor State"
        icon_template: >
          {% if states('sensor.nuki_endpoint_list') == "OK" %}
            {% set door_icon = state_attr('sensor.nuki_endpoint_list', 'lastKnownState')['doorsensorState'] %}
            {% set lock_icon = state_attr('sensor.nuki_endpoint_list', 'lastKnownState')['state'] %}
            {% if door_icon == 2 and lock_icon == 3 %}
              mdi:door-closed
            {% elif door_icon == 2 and lock_icon == 1 %}
              mdi:door-closed-lock
            {% elif door_icon == 3 %}
              mdi:door-open
            {% endif %}
          {% endif %}
        value_template: >
          {% if states('sensor.nuki_endpoint_list') == "OK" %}
            {% set my_state = {1: 'deactivated', 2: 'closed', 3: 'open', 4: 'unknown', 5: 'calibrating'} %}
            {{ my_state[state_attr('sensor.nuki_endpoint_list', 'lastKnownState')['doorsensorState']] }}
          {% endif %}

      nuki_lock_sensor_state:
        unique_id: nuki_lock_sensor_state
        friendly_name: "Nuki Lock Sensor State"
        icon_template: >
          {% if states('sensor.nuki_endpoint_list') == "OK" %}
            {% set lock_icon = state_attr('sensor.nuki_endpoint_list', 'lastKnownState')['state'] %}
            {% if lock_icon == 1 %}
              mdi:lock-outline
            {% elif lock_icon == 3 %}
              mdi:lock-open-outline
            {% endif %}
          {% endif %}
        value_template: >
          {% if states('sensor.nuki_endpoint_list') == "OK" %}
            {% set my_state = {0: 'uncalibrated', 1: 'locked', 2:'unlocking', 3: 'unlocked', 4: 'locking', 5: 'unlatched', 6: "unlocked (lock ‘n’ go)", 7: 'unlatching', 254: 'motor blocked', 255: 'undefined'} %}
            {{ my_state[state_attr('sensor.nuki_endpoint_list', 'lastKnownState')['state']] }}
          {% endif %}

      nuki_keypad_battery_critical_state:
        unique_id: nuki_keypad_battery_critical_state
        friendly_name: "Nuki Keypad Battery Critical State"
        icon_template: mdi:battery-alert-variant-outline
        value_template: >
          {% if states('sensor.nuki_endpoint_list') == "OK" %}
            {% if state_attr('sensor.nuki_endpoint_list', 'lastKnownState')['keypadBatteryCritical'] != null %}
              {{ state_attr('sensor.nuki_endpoint_list', 'lastKnownState')['keypadBatteryCritical'] }}
            {% else %}
              not installed 
            {% endif %}
          {% endif %}
2 Likes

@alexdelprete You came to the same solution as I did, going to make use of the input_text. I was half the way of implementing it and was starting to finish it when I read your post. Thnx.

I’ll try it later today, but not as package but as fully split configuration (every sensor in separate file) - that’s how my current configuration has been set now to work, and package is used to load everything.

Is there an open ticket for this issue ?

@alexdelprete intalled your package - everything works fine, the one problem I had is solved with door sensor reporting open state all time so let’s wait for further testing and see if anyone reports issues, I’ll test this over weekend I reply todays evening in between Euro games
Cheers for your work!

@mahikeulbody Yes there is an open ticket see https://community.home-assistant.io/t/allow-integration-template-in-packages/305865. Unfortunately Frenck closed it for this reason: https://github.com/home-assistant/core/issues/49212#issuecomment-834520809.

@cpu I see it too.

@alexdelprete I see that a lot of sensors retrieve their values from the sensor.nuki_endpoint_list and sensor.nuki_endpoint_info. Isn’t it better to retrieve them from the binary sensor where possible? As far as I have experienced it now the sensor.nuki_endpoint_list and sensor.nuki_endpoint_info are only updated while you lock or unlock the door from lock.nuki_lock_action within HA. However if you you lock or unlock the door from lock.nuki_lock_action within HA or any other way, a webhook will be sent to HA so the automation nuki_card_callback is triggered and the binary sensor is updated. This update of the binary sensor will then trigger the update of all depending sensors. What do you think?

Ok. So, is this approach :

Let’s approach it in steps: first a package with this legacy syntax, that still works, then when we can convert it into the new syntax we’ll do it.

a good one if we are not sure this issue will be solved someday when, at the same time, we are almost sure that the legacy syntax will be removed soon or late ?

I don’t know if the legacy syntax will be removed ever. When they will do that, I think a lot of users will end up with a non working HA system when they upgrade. I think this would kill HA. But this is my personal opinion, Maybe all references to the old syntax will be removed from the documentation so you can’t find any references to it any more in the official documentation.

The solution is simply the same thing I did with the split code, same logic. Check the use of the platform to update the input_texts, that’s the core difference in regards to the efficiency I mentioned in my previous comment regarding how you made it. If you look at the code, what I do is: if the trigger is the webhook, I use data from the callback that is immediately available, if the trigger is state/event, I take data from the polled sensors. Without doing unneeded REST calls. So you have the triggered data and the polled data, both refreshing the sensors.

Now we need to test it thouroughly before releasing it.

Well, you can split it as you want now, the core has been ported so the package works, you can manipulate it as you prefer. :slight_smile:

Let me know if it works though, so we can release it. Keep in mind that I don’t like this approach very much, in order to make it work I had to use “global variables” (input_text). The original solution is much more “elegant”. :slight_smile:

I have no issues locally. What did you find wrong? What did you fix?

It’s not only a matter of style, but functionality and efficiency. The fact that with the new Template Trigger sensor the sensors you create are part of the platform, and not separate is more efficient because from the binary_sensor and the sensors created, you can access to the trigger data, without using tricks like globals/input_texts.

BTW: did you test the !secret for webhook? Does it now work for you?

This is what I was talking about in my previous comment. I understood where the devs are going with the template platform/integration. I like where they’re going, but obviously there are consequences…

This is exactly what I tried to explain you in my previous comments.

If you check Nuki Bridge API, you’ll notice that the json payload info it sends with the callback is minimal, only the status of the door sensor and the lock (and battery). Why? Because the callback has to be focused on IMPORTANT sensors, not all the info sensors. And that’s how I designed the integration.

The long list of sensors is managed via polling by the two rest sensors. The important information, like door and lock status get immediate status updates through callbacks. This is the best approach, because it follows what Nuki is doing and we also keep the polling calls at minimum, because the information of the extra sensors is not mission-critical.

I think now you can understand fully how I approached it. :slight_smile:

I think they opted for a soft-landing scenario: they write in docs that they recommend modern-syntax, while keeping the old working, basically they don’t want to break all the existing old style configurations because it would upset many users. So for now they are keeping both, but it’s pretty clear they are heading towards a new template system, so new stuff should be implemented in that way, IMHO. We’re just speculating, obviously. Maybe they’ll find a way to go in the new path and also make the old things work…but I think if it could be done they would’ve already done it. :slight_smile:

@alexdelprete I have a new beta version of the package.

This is what I did:

  • Saved all available parameters from the webhook into an input_text
  • Referenced, where possible, all sensors to the according sensor.nuki_endpoint_list or the sensor.nuki or input_text. This way the sensors should react on both an update from the webhook or the rest api calls (Hope I did everything right…)

This should give a more accurate overview.

The code:

########################
# Nuki Card v6.0-beta2 #
########################

#######################################################################################################################
###                                                                                                                 ###
### Automations                                                                                                     ###
###                                                                                                                 ###
#######################################################################################################################

automation:
  - id: "nuki_card_callback"
    alias: Nuki Card Callback
    description: Automation for the Nuki doorlock
    trigger:
      - platform: webhook
        webhook_id: !secret nuki_bridge_webhook
      - platform: event
        event_type: event_template_reloaded
      - platform: state
        entity_id: sensor.nuki_door_sensor_state
        to:
          - "open"
          - "closed"
    condition: []
    action:
      - choose:
          - conditions: >
              {{ trigger.platform == 'webhook' }}
            sequence:
              - service: input_text.set_value
                target:
                  entity_id: input_text.nuki_bridge_door_sensor_state
                data:
                  value: >
                    {% set my_state = {1: 'deactivated', 2: 'closed', 3: 'open', 4: 'unknown', 5: 'calibrating'} %}
                    {{ my_state[trigger.json.doorsensorState] }}
              - service: input_text.set_value
                target:
                  entity_id: input_text.nuki_bridge_lock_sensor_state
                data:
                  value: >
                    {% set my_state = {0: 'uncalibrated', 1: 'locked', 2:'unlocking', 3: 'unlocked', 4: 'locking', 5: 'unlatched', 6: "unlocked (lock 'n' go)", 7: 'unlatching', 254: 'motor blocked', 255: 'undefined'} %}
                    {{ my_state[trigger.json.state] }}
              - service: input_text.set_value
                target:
                  entity_id: input_text.nuki_bridge_lock_sensor_state_name
                data:
                  value: >
                    {{ trigger.json.stateName }}
              - service: input_text.set_value
                target:
                  entity_id: input_text.nuki_bridge_door_sensor_mode
                data:
                  value: >
                    {{ trigger.json.mode }}
              - service: input_text.set_value
                target:
                  entity_id: input_text.nuki_bridge_nuki_id
                data:
                  value: >
                    {{ trigger.json.nukiId }}
              - service: input_text.set_value
                target:
                  entity_id: input_text.nuki_bridge_device_type
                data:
                  value: >
                    {{ trigger.json.deviceType }}
              - service: input_text.set_value
                target:
                  entity_id: input_text.nuki_bridge_battery_critical
                data:
                  value: >
                    {{ trigger.json.batteryCritical }}
              - service: input_text.set_value
                target:
                  entity_id: input_text.nuki_bridge_battery_charging
                data:
                  value: >
                    {{ trigger.json.batteryCharging }}
              - service: input_text.set_value
                target:
                  entity_id: input_text.nuki_bridge_battery_charge_state
                data:
                  value: >
                    {{ trigger.json.batteryChargeState }}
              - service: input_text.set_value
                target:
                  entity_id: input_text.nuki_bridge_lock_sensor_state_name
                data:
                  value: >
                    {{ trigger.json.doorsensorStateName }}
              - service: input_text.set_value
                target:
                  entity_id: input_text.nuki_bridge_last_activity
                data:
                  value: >
                    {{ as_timestamp(now()) | timestamp_custom("%H:%M:%S (%b %d)") }}
              - service: input_text.set_value
                target:
                  entity_id: input_text.nuki_bridge_trigger_platform
                data:
                  value: >
                    {{ trigger.platform }}
          - conditions: >
              {{ trigger.platform == 'state' or trigger.platform == 'event' }}
            sequence:
              - service: input_text.set_value
                target:
                  entity_id: input_text.nuki_bridge_door_sensor_state
                data:
                  value: >
                    {{ states('sensor.nuki_door_sensor_state') }}
              - service: input_text.set_value
                target:
                  entity_id: input_text.nuki_bridge_lock_sensor_state
                data:
                  value: >
                    {{ states('sensor.nuki_lock_sensor_state') }}
              - service: input_text.set_value
                target:
                  entity_id: input_text.nuki_bridge_last_activity
                data:
                  value: >
                    {{ states('sensor.nuki_last_activity') }}
              - service: input_text.set_value
                target:
                  entity_id: input_text.nuki_bridge_trigger_platform
                data:
                  value: >
                    {{ trigger.platform }}
        default: []
    mode: single

#######################################################################################################################
###                                                                                                                 ###
### Binary sensors                                                                                                  ###
###                                                                                                                 ###
#######################################################################################################################

binary_sensor:
  - platform: template
    sensors:
      nuki_door_state:
        unique_id: nuki_door_state
        friendly_name: "Nuki Door State"
        device_class: door
        value_template: >
          {{ is_state('input_text.nuki_bridge_door_sensor_state', 'open') }}
        availability_template: >
          {{ (is_state('sensor.nuki_door_sensor_state', 'open') or is_state('sensor.nuki_door_sensor_state', 'closed')) }}
        icon_template: >
          {% set trigdoor = states('input_text.nuki_bridge_door_sensor_state') %}
          {% set triglock = states('input_text.nuki_bridge_lock_sensor_state') %}
          {% if (trigdoor == 'open') %}
            mdi:door-open
          {% elif trigdoor == 'closed' and triglock == 'locked' %}
            mdi:door-closed-lock
          {% elif trigdoor == 'closed' and triglock == 'unlocked' %}
            mdi:door-closed
          {% else %}
            mdi:alert-box-outline
          {% endif %}
        attribute_templates:
          trigger_platform: >
            {{ states('input_text.nuki_bridge_trigger_platform') }}
          nuki_id: >
            {{ states('sensor.nuki_id') }}
          door_state: >
            {{ states('input_text.nuki_bridge_door_sensor_state') }}
          lock_state: >
            {{ states('input_text.nuki_bridge_lock_sensor_state') }}
          lock_battery: >
            {{ states('sensor.nuki_lock_battery_level') }}
          lock_battery_critical: >
            {{ states('sensor.nuki_lock_battery_critical_state') }}
          keypad_battery_critical: >
            {% if states('sensor.nuki_keypad_battery_critical_state') != 'unknown' %}
              {{ states('sensor.nuki_keypad_battery_critical_state') }}
            {% else %}
              not installed 
            {% endif %}
          last_update: >
            {{ states('input_text.nuki_bridge_last_activity') }}
          last_update_polled: >
            {{ states('sensor.nuki_last_activity') }}
          door_sensor_polled: >
            {{ states('sensor.nuki_door_sensor_state') }}
          lock_sensor_polled: >
            {{ states('sensor.nuki_lock_sensor_state') }}

#######################################################################################################################
###                                                                                                                 ###
### Input Texts                                                                                                           ###
###                                                                                                                 ###
#######################################################################################################################
input_text:
  nuki_bridge_host:
    initial: !secret nuki_bridge_host
  nuki_bridge_port:
    initial: !secret nuki_bridge_port
  nuki_bridge_token:
    initial: !secret nuki_bridge_token
  nuki_bridge_battery_critical:
  nuki_bridge_battery_charging:
  nuki_bridge_battery_charge_state:
  nuki_bridge_device_type:
  nuki_bridge_door_sensor_state:
  nuki_bridge_door_sensor_state_name:
  nuki_bridge_door_sensor_mode:
  nuki_bridge_lock_sensor_state:
  nuki_bridge_lock_sensor_state_name:
  nuki_bridge_last_activity:
  nuki_bridge_nuki_id:
  nuki_bridge_trigger_platform:

#######################################################################################################################
###                                                                                                                 ###
### Locks                                                                                                           ###
###                                                                                                                 ###
#######################################################################################################################

lock:
  - platform: template
    name: "Nuki Lock Action"
    unique_id: nuki_lock_action
    value_template: >
      {{ is_state_attr('binary_sensor.nuki_door_state', 'lock_state', 'locked') }}
    availability_template: >
      {{ is_state_attr('binary_sensor.nuki_door_state', 'lock_state', 'locked') or
        is_state_attr('binary_sensor.nuki_door_state', 'lock_state', 'unlocked')}}
    lock:
      service: rest_command.nuki_lock_action
      data:
        action: 2
    unlock:
      service: rest_command.nuki_lock_action
      data:
        action: 1

#######################################################################################################################
###                                                                                                                 ###
### sensors                                                                                                         ###
###                                                                                                                 ###
#######################################################################################################################

sensor:
  - platform: rest
    scan_interval: 150
    resource_template: "http://{{ states('input_text.nuki_bridge_host') }}:{{ states('input_text.nuki_bridge_port') }}/list?&token={{ states('input_text.nuki_bridge_token') }}"
    name: "Nuki Endpoint List"
    value_template: "OK"
    json_attributes:
      - lastKnownState
      - firmwareVersion
      - nukiId
      - name

  - platform: rest
    scan_interval: 150
    resource_template: "http://{{ states('input_text.nuki_bridge_host') }}:{{ states('input_text.nuki_bridge_port') }}/info?&token={{ states('input_text.nuki_bridge_token') }}"
    name: "Nuki Endpoint Info"
    value_template: "OK"
    json_attributes:
      - versions
      - scanResults
      - wlanConnected
      - serverConnected

  - platform: template
    sensors:
      nuki_device_name:
        unique_id: nuki_device_name
        friendly_name: "Nuki Device Name"
        icon_template: mdi:alphabetical-variant
        value_template: >
          {% if states('sensor.nuki_endpoint_info') == "OK" %}
            {{ state_attr('sensor.nuki_endpoint_info','scanResults')[0]['name'] }}
          {% endif %}

  - platform: template
    sensors:
      nuki_bridge_fw_version:
        unique_id: nuki_bridge_fw_version
        friendly_name: "Nuki Bridge FW Version"
        icon_template: mdi:numeric
        value_template: >
          {% if states('sensor.nuki_endpoint_info') == "OK" %}
            {{ state_attr('sensor.nuki_endpoint_info','versions')['firmwareVersion'] }}
          {% endif %}

      nuki_bridge_lock_bt_rssi:
        unique_id: nuki_bridge_lock_bt_rssi
        friendly_name: "Nuki Bridge<->Lock BT RSSI"
        icon_template: mdi:signal-distance-variant
        value_template: >
          {% if states('sensor.nuki_endpoint_info') == "OK" %}
            {{ state_attr('sensor.nuki_endpoint_info','scanResults')[0]['rssi'] }}
          {% endif %}

      nuki_bridge_wifi_connected:
        unique_id: nuki_bridge_wifi_connected
        friendly_name: "Nuki Bridge WiFi Connected"
        icon_template: mdi:wifi-cog
        value_template: >
          {% if states('sensor.nuki_endpoint_info') == "OK" %}
            {{ state_attr('sensor.nuki_endpoint_info','wlanConnected') }}
          {% endif %}

      nuki_bridge_wifi_fw_version:
        unique_id: nuki_bridge_wifi_fw_version
        friendly_name: "Nuki Bridge WiFi FW Version"
        icon_template: mdi:numeric
        value_template: >
          {% if states('sensor.nuki_endpoint_info') == "OK" %}
            {{ state_attr('sensor.nuki_endpoint_info','versions')['wifiFirmwareVersion'] }}
          {% endif %}

      nuki_bridge_cloud_connected:
        unique_id: nuki_bridge_cloud_connected
        friendly_name: "Nuki Bridge Cloud Connected"
        icon_template: mdi:server-network
        value_template: >
          {% if states('sensor.nuki_endpoint_info') == "OK" %}
            {{ state_attr('sensor.nuki_endpoint_info','serverConnected') }}
          {% endif %}

      nuki_bridge_lock_bt_state:
        unique_id: nuki_bridge_lock_bt_state
        friendly_name: "Nuki Bridge<->Lock BT State"
        icon_template: >
          {% if states('sensor.nuki_endpoint_info') == "OK" %}
            {% if state_attr('sensor.nuki_endpoint_info','scanResults')[0]['paired'] %}
              mdi:bluetooth-connect
            {% elif not state_attr('sensor.nuki_endpoint_info','scanResults')[0]['paired'] %}
              mdi:bluetooth-off
            {% else %}
              mdi:bluetooth-audio
            {% endif %}
          {% endif %}
        value_template: >
          {% if states('sensor.nuki_endpoint_info') == "OK" %}
            {% if state_attr('sensor.nuki_endpoint_info','scanResults')[0]['paired'] %}
              connected
            {% elif not state_attr('sensor.nuki_endpoint_info','scanResults')[0]['paired'] %}
              disconnected
            {% else %}
              Unknown
            {% endif %}
          {% endif %}

      nuki_id:
        unique_id: nuki_id
        friendly_name: "Nuki ID"
        icon_template: mdi:numeric
        value_template: >
          
          {% if states('sensor.nuki_endpoint_list') == "OK" %}
            {{ state_attr('sensor.nuki_endpoint_list','nukiId') }}
          {% elif states('input_text.nuki_bridge_nuki_id') != null %}
            {{ states('input_text.nuki_bridge_nuki_id') }}
          {% endif %}

      nuki_lock_fw_version:
        unique_id: nuki_lock_fw_version
        friendly_name: "Nuki Lock FW Version"
        icon_template: mdi:numeric
        value_template: >
          {% if states('sensor.nuki_endpoint_list') == "OK" %}
            {{ state_attr('sensor.nuki_endpoint_list','firmwareVersion') }}
          {% endif %}

      nuki_lock_battery_critical_state:
        unique_id: nuki_lock_battery_critical_state
        friendly_name: "Nuki Lock Battery Critical State"
        icon_template: mdi:battery-alert-variant-outline
        value_template: >
          {% if states('sensor.nuki_endpoint_list') == "OK" %}
            {{ state_attr('sensor.nuki_endpoint_list', 'lastKnownState')['batteryCritical'] }}
          {% elif states('input_text.nuki_bridge_battery_critical') != null%}
            {{ states('input_text.nuki_bridge_battery_critical') }}
          {% endif %}

      nuki_lock_battery_charging:
        unique_id: nuki_lock_battery_charging
        friendly_name: "Nuki Lock Battery Charging"
        icon_template: mdi:battery-charging
        value_template: >
          {% if states('sensor.nuki_endpoint_list') == "OK" %}
            {{ state_attr('sensor.nuki_endpoint_list', 'lastKnownState')['batteryCharging'] }}
          {% elif states('input_text.nuki_bridge_battery_charging') != null %}
            {{ states('input_text.nuki_bridge_battery_charging') }}
          {% endif %}

      nuki_lock_battery_level:
        unique_id: nuki_lock_battery_level
        friendly_name: "Nuki Lock Battery Level"
        device_class: "battery"
        unit_of_measurement: "%"
        icon_template: >
          {% if states('sensor.nuki_endpoint_list') == "OK" %}
            {% set battery_level = state_attr('sensor.nuki_endpoint_list', 'lastKnownState')['batteryChargeState'] | default(0) | int %}
            {% set battery_charging = state_attr('sensor.nuki_endpoint_list', 'lastKnownState')['batteryCharging'] %}
          {% elif states('input_text.nuki_bridge_battery_charge_state') != null %}
            {% set battery_level = states('input_text.nuki_bridge_battery_charge_state') | default(0) | int %}
            {% set battery_charging = states('input_text.nuki_bridge_battery_charging') %}
          {% endif %}
          {% set battery_round = (battery_level / 10) | int * 10 %}
          {% if battery_round >= 100 and not battery_charging %}
            mdi:battery
          {% elif battery_round >= 100 and battery_charging %}
            mdi:battery-charging
          {% elif battery_round > 0 and not battery_charging %}
            mdi:battery-{{ battery_round }}
          {% elif battery_round > 0 and battery_charging %}
            mdi:battery-charging-{{ battery_round }}
          {% else %}
            mdi:battery-alert-variant-outline
          {% endif %}
        value_template: >
          {% if states('sensor.nuki_endpoint_list') == "OK" %}
            {% set battery_level = state_attr('sensor.nuki_endpoint_list', 'lastKnownState')['batteryChargeState'] | default(0) | int %}
            {% set battery_charging = state_attr('sensor.nuki_endpoint_list', 'lastKnownState')['batteryCharging'] %}
          {% elif states('input_text.nuki_bridge_battery_charge_state') != null %}
            {% set battery_level = states('input_text.nuki_bridge_battery_charge_state') | default(0) | int %}
            {% set battery_charging = states('input_text.nuki_bridge_battery_charging') %}
          {% endif %}
          {% if battery_charging %}
            {{ battery_level }}
          {% else %}
            {{ battery_level }}
          {% endif %}

      nuki_friendly_name:
        unique_id: nuki_friendly_name
        friendly_name: "Nuki Friendly Name"
        icon_template: mdi:numeric
        value_template: >
          {% if states('sensor.nuki_endpoint_list') == "OK" %}
            {{ state_attr('sensor.nuki_endpoint_list','name') }}
          {% endif %}

      nuki_last_activity:
        unique_id: nuki_last_activity
        friendly_name: "Nuki Last Activity"
        icon_template: mdi:clock-check-outline
        value_template: >
          {% if states('sensor.nuki_endpoint_list') == "OK" %}
            {{ (as_timestamp(state_attr('sensor.nuki_endpoint_list', 'lastKnownState')['timestamp'])) | timestamp_custom("%H:%M:%S (%b %d)") }}
          {% endif %}

      nuki_door_sensor_state:
        unique_id: nuki_door_sensor_state
        friendly_name: "Nuki Door Sensor State"
        icon_template: >
          {% if states('sensor.nuki_endpoint_list') == "OK" %}
            {% set door_icon = state_attr('sensor.nuki_endpoint_list', 'lastKnownState')['doorsensorState'] %}
            {% set lock_icon = state_attr('sensor.nuki_endpoint_list', 'lastKnownState')['state'] %}
          {% elif states('input_text.nuki_bridge_door_sensor_state') != null %}
            {% set door_icon = states('input_text.nuki_bridge_door_sensor_state') %}
            {% set lock_icon = states('input_text.nuki_bridge_lock_sensor_state') %}
          {% endif %}
          {% if door_icon == 2 and lock_icon == 3 %}
            mdi:door-closed
          {% elif door_icon == 2 and lock_icon == 1 %}
            mdi:door-closed-lock
          {% elif door_icon == 3 %}
            mdi:door-open
          {% endif %}
        value_template: >
          {% set my_state = {1: 'deactivated', 2: 'closed', 3: 'open', 4: 'unknown', 5: 'calibrating'} %}
          {% if states('sensor.nuki_endpoint_list') == "OK" %}
            {{ my_state[state_attr('sensor.nuki_endpoint_list', 'lastKnownState')['doorsensorState']] }}
          {% elif states('input_text.nuki_bridge_door_sensor_state') != null %}
            {{ my_state[states('input_text.nuki_bridge_door_sensor_state')] }}
          {% endif %}

      nuki_lock_sensor_state:
        unique_id: nuki_lock_sensor_state
        friendly_name: "Nuki Lock Sensor State"
        icon_template: >
          {% if states('sensor.nuki_endpoint_list') == "OK" %}
            {% set lock_icon = state_attr('sensor.nuki_endpoint_list', 'lastKnownState')['state'] %}
          {% elif states('input_text.nuki_bridge_lock_sensor_state') != null %}
            {% set lock_icon = states('input_text.nuki_bridge_lock_sensor_state') %}
          {% endif %}
          {% if lock_icon == 1 %}
            mdi:lock-outline
          {% elif lock_icon == 3 %}
            mdi:lock-open-outline
          {% endif %}
        value_template: >
          {% set my_state = {0: 'uncalibrated', 1: 'locked', 2:'unlocking', 3: 'unlocked', 4: 'locking', 5: 'unlatched', 6: "unlocked (lock ‘n’ go)", 7: 'unlatching', 254: 'motor blocked', 255: 'undefined'} %}
          {% if states('sensor.nuki_endpoint_list') == "OK" %}
            {{ my_state[state_attr('sensor.nuki_endpoint_list', 'lastKnownState')['state']] }}
          {% elif states('input_text.nuki_bridge_lock_sensor_state') != null %}
            {{ mystate[states('input_text.nuki_bridge_lock_sensor_state')] }}
          {% endif %}

      nuki_keypad_battery_critical_state:
        unique_id: nuki_keypad_battery_critical_state
        friendly_name: "Nuki Keypad Battery Critical State"
        icon_template: mdi:battery-alert-variant-outline
        value_template: >
          {% if states('sensor.nuki_endpoint_list') == "OK" %}
            {% if state_attr('sensor.nuki_endpoint_list', 'lastKnownState')['keypadBatteryCritical'] != null %}
              {{ state_attr('sensor.nuki_endpoint_list', 'lastKnownState')['keypadBatteryCritical'] }}
            {% else %}
              not installed 
            {% endif %}
          {% endif %}

@alexdelprete I just took a quick look at the blueprint: https://www.home-assistant.io/docs/blueprint/tutorial/. It seems that this is compatible with the modern syntax, at least I see a trigger defined in the example. So probably with a blueprint, we can use the modern syntax…

The code I shared already does take info from trigger data AND rest sensors. I took a look at your version and it has several problems, you also forgot the rest_command from the code. The info sensors don’t need to take data from both, they are updated only by the rest commands, because in the trigger data you only have a minimum set of info that is already captured, apart from battery info that is not critical, so I decided not to take that info, I left it on purpose only to the rest sensors.

The code I shared last night is only to be tested, it does the same things as the modern-style split version, but it’s structured as an automation now, and I don’t want to add or change the structure because I know it works pretty good. :slight_smile:

I only did it to help new users, that are only beginners with HA, install it without too many issues. But I don’t really like it too much. But it works, and I see it as a bridge solution until the modern-style version can be packaged.

I’ll wait for some feedbacks on the tests of beta 1, then I’ll release it as 6.0 official.

Obviously without you I wouldn’t have the right “push” to do it, but I would have saved a night of sleep. :slight_smile:

I’m not sure that’s the new template trigger sensor, it’s just a way to configure in a user-friendly way an automation, so probably it will work with the new 6.0 version, with legacy style. But I’ll check it…

With the 6.0 automation, the only thing users have to do is define the 4 secret parameters, and configure the callback on the bridge, that’s it. So probably the blueprint is not necessary. I will think about it…