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

You can use the IP or the HOSTNAME. If you use the hostname, make sure that DNS resolves it.

nuki_bridge_host: "nuki-bridge.axel.dom"
nuki_bridge_port: "8080"

Did you read the instructions and the example regarding the secrets.yaml content? I am showing my configuration there. I use a hostname, but you can use an IP.

it also supports the hostname. :slight_smile:

I think it’s too much to configure another automation for that problem.

The other thing I noticed is that it throws errors only on sensors with the [0]. I think it’s something syntax related. Maybe I could reinforce the code putting the value in a variable and then validate its content. How do I check if any kind of value (string, int, boolean) exists, I mean, it’s not NULL like in the startup phase? I don’t think checking against “” would work, is there a clean way?

Thanks.

Not 100% sure, but look at this:
https://jinja.palletsprojects.com/en/3.0.x/templates/#if
And here as well:
https://jinja.palletsprojects.com/en/3.0.x/templates/#list-of-builtin-tests
especially defined() or none()

It’s a catch-22 situation. If you do an IF to test if the sensor exists (is defined, etc.) and then in case it is, you extract the value, it throws the same error. It’s during the initial rendering, not during the evaluation of the statement.

I don’t want to spend all this time on it…

Ok, solved it. It wasn’t a catch-22. v5.0 released.

@Friedrieck the problem (and the solution) were the two REST sensors, that contain all the JSON data from the nuki, at startup they are not initialized so fast. If you check their code, I put value_state = “OK” to both of them, so I only needed to check if states() == “OK” to be sure they’re initialized.

- platform: rest
  scan_interval: 300
  resource_template: "http://{{ states('sensor.nuki_bridge_host') }}:{{ states('sensor.nuki_bridge_port') }}/list?&token={{ states('sensor.nuki_bridge_token') }}"
  name: "Nuki Endpoint List"
  value_template: "OK"
  json_attributes:
    - lastKnownState
    - firmwareVersion
    - nukiId
    - name
      {% if states('sensor.nuki_endpoint_info') == "OK" %}
        {{ state_attr('sensor.nuki_endpoint_info','scanResults')[0]['name'] }}
      {% endif %}

If states() is used with an uninitialized sensor, you can’t use none() to test it, because it returnes “unknown”.

So, this doesn’t work:

      {% if states('sensor.nuki_endpoint_info') is not none %}
        {{ state_attr('sensor.nuki_endpoint_info','scanResults')[0]['name'] }}
      {% endif %}

But this works:

      {% if states('sensor.nuki_endpoint_info') != "unknown" %}
        {{ state_attr('sensor.nuki_endpoint_info','scanResults')[0]['name'] }}
      {% endif %}

The alternative method, is to test if state_attr(), without the [0][‘name’], is none():

{% if state_attr('sensor.nuki_endpoint_info','scanResults') is not none %}
  {{ state_attr('sensor.nuki_endpoint_info','scanResults')[0]['name'] }}
{% endif %}

This for example doesn’t work:

{% if state_attr('sensor.nuki_endpoint_info','scanResults')[0]['name'] is not none %}
  {{ state_attr('sensor.nuki_endpoint_info','scanResults')[0]['name'] }}
{% endif %}

And while looking for some info, I found this. :sweat_smile:

Endless hours of frustration…literally!! But we made it, in the end. Perseverance is the key. :slight_smile:

Thanks for all the advices, going to get some sleep now.

2 Likes

:+1: :clap: :clap: :clap: :sweat_smile:

1 Like

Great work. I’ve followed your instructions and almost got it to work. The polling is ok and the sensor are populated. But the callback doesn’t arrive. I have not taken the time yet to read all the discussion above to debug, but I’ll report back here if I can get it running.

Two questions:

  • I noticed that there is a sensor for the token. I don’t feel well with that. Doesn’t that mean that the token is stored in the recorder? Is that necessary? For the interface, I don’t see a need for the token to be in a sensor. It is stored in the secrets.yaml anyhow and I could always look it up there.
  • The opener is not included. Is that planned as an extension?

Thanks for the effort!

Haha, I tricked myself. The bridge is on a different VLAN and the hostname of HA doesn’t resolve there. Putting in the correct IP of HA from that VLAN makes the callback work like a charm.

Unfortunately it was the only workaround I found to have a global parameter, in order to make it very easy for the user to configure this integration. I’ll show you what I mean, check these two REST sensors:

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

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

These two sensors are the ones responsible for polling data. The interesting thing here is that I didn’t want to use static URLs etc, because I just need those 3 parameters you put in secrets to dynamically construct the URL. While implementing it, I found out you can’t recall secret items in there, so I had to use a sensor’s state. If there’s a better way to pull in there secret items, I’m happy to adapt the code. :slight_smile:

Unfortunately not, because I don’t have it and so I can’t test it. And furthermore, the official integration in the future should have support for callbacks etc, so probably this integration, if that one does everything this does, won’t be needed anymore. We’ll see what happens…:slight_smile:

For me it’s been an excercise to force me to learn HA more. I’m happy that it’s working for you.

I see the problem. Maybe, it is slightly better to stick the values into an input_text and not a sensor as strictly speaking, they are not changing and thus the sensor is not sensing anything. That’s the logic discussed here: How to use !secret in sensor template - #4 by AhmadK

I have one so I might for the sake of following your learning curve experiment with it. If I get anything setup, I’ll share it here. But you’re right, ideally the native integration would pick this stuff up.

From a configuration perspective, it’s easier to just ask the user to configure all user-parameters in secrets (they are secrets) and then I pull them up as sensors when users pastes all the code in the sensor file. If I used input_texts there would be additional user steps to follow, that’s all. So, either I ask to put everything as input_text or as secrets, I didn’t like mixing things, the instructions are already too complex for my taste.

If you don’t like the sensors being recorded, you can filter it out.

Feel free to adapt it to your needs if you prefer input_text. The code is there to be changed/adapted by anybody. :slight_smile:

Sury, but that can also be done with input_text and not just with sensors :wink:

The beauty of HA is that you can solve the same problem in 100 ways, I chose one, and I explained why. I could argue that putting my sensitive information in input_text is not something that I like, but it’s subjective. :wink:

Like I said, input_text would require extra configuration steps, and I preferred to minimize those.

I’ll be more than glad, once it’s working, to add the opener bit to the integration. Let’s make sure that someone else with the opener can test it, obviously. :slight_smile:

Thanks a lot.

I went the easy way and simply used your callback idea to force an update of the Nuki integration itself. That includes the opener then, but it lacks all the wonderful attributes that you pull from the bridge.

Setup is fairly easy and I created a blueprint for that:

Open your Home Assistant instance and show the blueprint import dialog with a specific blueprint pre-filled.

Yeah, the easy way still requires the Nuki official integration. My goal was different. But it’s good to have choices. :slight_smile:

1 Like

It’s a nice feeling being able to click “ignore” while still having a fully working integration, that provides all info about the Nuki, and faster status feedback. :slight_smile:

image

1 Like

Great work! This method is so much faster then just using the rest api.
Is it possible to get the lock_state on callback? The current binary sensor only updates when a door status change is triggered.
I’m trying to create a binary sensor, which is on when the lock is unlatching or unlocking (7 or 2) but can’t get it working.