Nuki Smart Lock 2.0 - support all available API actions (i.e. add lock/unlock)


btw, you can’t ask in the same time two rest url, (example and because, template sensor can be unavailable (NUKI HW support one request). You must scan_interval example 120 seconds in info rest and 70 seconds in list rest.

I updated the code to add fw versions of the lock and bridge. In order to do it, I had to change all JSON parsing, the good thing is that adding other sensors will be way easier.

Check the post: Nuki Smart Lock 2.0 - support all available API actions (i.e. add lock/unlock) - #102 by alexdelprete

Here’s the updated card:

1 Like


I had zero issues with the same polling period. I don’t think HA does the two REST calls to the same host in parallel if the polling period is the same, there is an internal queue probably.

I restructured the JSON parsing code in order to add the fw version sensors, as requested by @Dueller and other people in private messages.

Works like a charm, thank you

Looks good!
Thanks for that.

Glad to hear you solved the connection problem, and now you also have the fw version as you requested. :slight_smile:

Thanks for the feedback.

Thanks Joerg.

So I enabled advanced API in Nuki WEB
Webhook calls are being correctly fired but on the HA end I receive no feedback.
Also in the nuki web interface I see a 404 code
I feel we are vey near to get this working.
Need some help on HA side.
Currently I just setup the webhook in an automation that toggles a light without parsing anyway the content.
But as you see on nuki side I receive a 404

Hey! I got the webhooks working, it works without problems and quite quick. Maybe you forgot to activate the webhook? But I still try to find out how to get the payload of the webhook, tried {{ }} or {{ trigger.json.body.feature }} without success:

Error executing script. Error for call_service at pos 1: Error rendering data template: UndefinedError: 'dict object' has no attribute 'body'

could anybody get that working?

What do you get when trying with {{ trigger.json }}? It should give you the full payload.

1 Like

yes! found the error, its without. body:

{{ trigger.json.smartlockLog.action }}

1 Like

Strangely enough, the official integration does not seem to use the local callback proposed by the NUKI bridge API. So, for those not satisfied with pooling:

  1. Create a long-term token on your profile page
  2. Register a callback on your bridge by running:
    curl -X GET -H "Content-Type: application/json" 'http://your_nuki_bridge_IP:8080/callback/add?token=your_NUKI_API_token&url=http://your_HA_IP:8123/api/webhook/your_long-term_webhook_id'.
    You should get a {"success": true} in response.
  3. Optionnally, you can check it is correctly registered by running:
    curl -X GET -H "Content-Type: application/json" 'http://your_nuki_bridge_IP:8080/callback/list?token=your_NUKI_API_token'
  4. Once the state of the door or of the lock changes, the bridge will now call your HA instance with a payload like this:
    {'deviceType': 0, 'nukiId': your_lock_id, 'mode': 2, 'state': 3, 'stateName': 'unlocked', 'batteryCritical': False, 'batteryCharging': False, 'batteryChargeState': 44, 'keypadBatteryCritical': False, 'doorsensorState': 2, 'doorsensorStateName': 'door closed'}
    Based on this, you can now create a new trigger-based template sensor. Here is mine (sorry for the French):

- trigger:
    - platform: webhook
      webhook_id: your_webhook_id
    - unique_id: porte_principale
      device_class: door
      state: >
        {{ trigger.json.doorsensorState == 3 }}
      availability: "{{ (trigger.json.doorsensorState == 3) or (trigger.json.doorsensorState == 2) }}"
      icon: >
        {% if trigger.json.doorsensorState == 3 %}
        {% elif (trigger.json.doorsensorState == 2) and (trigger.json.state == 1) %}
        {% elif trigger.json.doorsensorState == 2 %}
        {% else %}
        {% endif %}      
        friendly_name: "Porte principale"
        batteries: "{{ trigger.json.batteryChargeState }}%"
        Problème_keypad: "{{ trigger.json.keypadBatteryCritical == True  }}" # if you have a keypad, obviously.
        porte: >
          {% set my_state = {0: 'indisponible', 1: 'désactivée', 2: 'porte fermée', 3: 'porte ouverte', 4: 'inconnu', 5: 'calibration'} -%}
          {{ my_state[trigger.json.doorsensorState] }}
        serrure: >
          {% set my_state = {0: 'non calibrée', 1: 'verrouillée', 2:'déverrouillage', 3: 'déverrouillée', 4: 'verrouillage', 5: 'ouverte', 6: "déverrouillée (lock 'n' go)", 7: 'ouverture', 254: 'moteur bloqué', 255: 'indéfini'} -%}
          {{ my_state[trigger.json.state] }}        
        màj: "{{ strptime(as_timestamp(now()) | timestamp_local, '%Y-%m-%d %H:%M:00') }}"

I wanted to translate the lock and door states in French, you can just replace the FR terms with those in your language, but if you are happy with EN, then you can simply use the stateName and doorsensorStateName from the callback payload.
I am personnaly satisfied with the battery info in an attribute, but you can create sensors for this in the same template if you want (see the doc.)


Do tou mean the procedure described in the api docs requiring to call with clientid etc!

What kind of webhook have you setup? Central or decentral?

Great . I was missing the registration doh. Merci

1 Like

I might have missed it yesterday, I get a battery error:

Good catch, there was an error when batteries where in charging state. Are you using the new rechargable pack by Nuki?

I released v2.0 of the Nuki Card, with many changes that need to be tested (callback/webhook, and more sensors), let me know if it works for you. :slight_smile:


Hi Allessandro,

nope, I use Energizer Litium batteries.

Just configured it, it looks good and most does work, except for the door status.

Callback is defined and there is no entry in the log.
The door sensor (last entry) from the integration is working.

Sorry Joerge, I should have specified in the instructions that the first time you restart, the sensor is not initialized, so you have to trigger it opening/closing the door, so you have the first callback. I updated the instructions with a quick note about it. :slight_smile:

Regarding the recharging state of the batteries, I have code in place that changes the icon of the battery (strike symbol) if the batteryCharging flag reported by Nuki is true. I see your battery like this:


That means batteryCharging is true, and Nuki docs say this about it:


So when that flag is true, I use a battery icon with the strike symbol, otherwise, a plain battery icon with the charging level.

Let me know if the door sensor works when you open it the first time.

Guess its my fault. I assumed I had to open/close it at least once, but I had trouble in the beginning, because I registered two different callback and the second callback two times. :frowning:
So while testing I opened/closed door severall times, but after figuring out how to remove all callbacks and after starting from scratch, I forgot to do so.
It shows the door status now, thank you.

Regarding the batteries: yes, the api told they were charging, but as said, this are normal, but high capacity and long lasting, non-rechargeable batteries. I have no experience with them in the lock, but in a Blink cam they last one year.

I understand that the battery pack is only charged, when it falls under 75%.
Anyway, I changed the battery recognition settings in the app to Off and On again and now the charging state is false and the icon normal.

All good so far. Thanks again for your effort.

Thank you for the nice work (and all others who worked on it).

All is running fine, including Battery Level, except door status. It is because I created a callback with a wrong IP, something as when my HA server is reachable as https://ha.mydomain (redirected by my router to https// If I try to create (re-create ?) a callback with this last https address, I get a “HTTP 400 Bad Request”. May be I have to delete (how ?) the existing callback ?

I tried to configure as an internal URL in HA but I cannot reach my HA server this way.

1 Like