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

I have the same error and also suspect that it is due to my internet connection.
I got a new router (Orbi behind FritzBox)

No need to be sorry, it’s reality, not your fault. :slight_smile:

The problem is that the bridge often can’t process the requests, so we need to make sure only 1 request every 5-10 secs is done. With last version we greatly improved this, requests are much more spread in time, but it could happen every once in a while that it’s not processed.

Apart from the log, did you have problems on the card? Something not working?

This is a great feedback. I have the same situation: in my installation, in 24 hours I have only 2 errors logged. Great improvement. Thanks a lot for the feedback.

Yes, that’s what I understood in last 3 days of testing. The queue mode of the automation and the change of polling times on rest sensors helped a lot in serializing, but it still happens, and I know why: in some parts of the code I use update_entity to force a refresh of the rest sensors, and those are out of the control of the Automation queue serialization. I will optimize the code so that ALL http requeste are in a queue, that should help a lot.

The problem, as always, is that we’re doing all this with yaml, and standard featured of HA. If we had a good python developer we would solve all this in 1 hour. :slight_smile:

I hope one day we find a python dev willing to work with us to port this automation to python so we can release a good custom component. I know exactly what to do, we just need a good and willing python dev.

Nuki Card v8.6 released: further optimized the code to avoid concurrent http requests to the bridge, that is poorly designed, supporting only 1 request at a time

1 Like

Jeroem, I wanted to integrate your translation code in v8.6, but I noticed that you not only changed the states to numbers, but, for example, in the binary_sensor you changed the value and availability templates to the polling sensors, instead of using input_text variables like my code. This is a problem, because the binary sensor would not be updated quickly by the callback.

I agree that numeric states are better, but I don’t want to change the logic of the automation, since it’s working fine. So now I released v8.6, without the translation code. if you want to integrate your code, please be sure not to modify the logic, if I chose to use input_text instead of a sensor, there’s a valid reason behind that decision.

I also noticed this bit of code:

      nuki_languages_string: >
        {% for x in nuki_languages %}
          {%- if loop.last %}
            "{{ x }}"]
          {% elif loop.first %}
            ["{{ x }}", 
          {% else %}
            "{{ x }}",
          {% endif -%}
        {%- endfor %}

Instead of literally building the list, you could do this:

{% set ns = namespace(lang_list = []) %}
{% for x in nuki_languages %}
  {% set ns.lang_list = ns.lang_list + [x] %}
{% endfor %}
{{ ns.lang_list }}

Also, for the json file, I would use numeric codes, not numbers as strings, like this:

  "English": {
    "trl_lock_bt_state": {
      1: "connected",
      2: "disconnected",
      3: "unknown"
    },
    "trl_door_sensor_state": {
      1: "deactivated",
      2: "closed",
      3: "open",
      4: "unknown",
      5: "calibrating"
    },

For the reference to the values, you are doing this:

{{ nuki_languages["English"]["trl_door_sensor_state"][1] }}

But recently I found out you could also do this:

{{ nuki_languages.English.trl_door_sensor_state.1 }}

In next release I will use this new syntax for all the polled sensors. :slight_smile:

Thanks for your help,

Alessandro

Hi Alessandro,

Thank you for your feedback. The reason I changed the logic of the binary sensor is that for the translation I can’t rely on string states, because the states are also translated. Therefore I changed it to the numeric states of the callback. As you said that the consequence is that the sensor isn’t updated quickly. A solution could be to use also input_numbers, or extra input_texts to store the numerical states.

About the new syntax, this is ok if you don’t use calculations or references to other fields to get the value, when using references to another for getting a reference, i.e.:

{{ nuki_languages[states('input_select.nuki_language')]['trl_lock_sensor_state'] | to_json }}

I don’t see a possibility to use this new syntax and therefore I would advise to use the same style everywhere in your code. This makes it more readable.

Hi Alessandro,

About the json file, I need to enclose the fields in double quotes otherwise the function “from_json” will give an error.

There’s no need of extra input_texts, look at the sequence of the trigger for the callback:

            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] }}

I get the state number, and I translate it to text. :slight_smile:

So we can translate with your system, instead of the fixed one I’m using, ok?

Look at these examples:

These are equivalent:

{{ nuki_languages["English"]["trl_door_sensor_state"][1] }}
{{ nuki_languages.English.trl_door_sensor_state.1 }}

And these too:

{{ state_attr('sensor.nuki_bridge_endpoint_list', 'lastKnownState')['batteryChargeState'] }}
{{ state_attr('sensor.nuki_bridge_endpoint_list', 'lastKnownState').batteryChargeState }}

Put this code in Dev Tools → Template, and play with the syntax, you’ll find the proper way to do it without doing complex stuff or converting from_json / to_json when not needed.

{% set nuki_languages =
{
  "English": {
    "trl_lock_bt_state": {
      1: "connected",
      2: "disconnected",
      3: "unknown"
    },
    "trl_door_sensor_state": {
      1: "deactivated",
      2: "closed",
      3: "open",
      4: "unknown",
      5: "calibrating"
    },
    "trl_lock_sensor_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"
    },
    "trl_keypad_battery_critical_state": "not installed"
  },
  "Deutsch": {
    "trl_lock_bt_state": {
      "1": "angebunden",
      "2": "getrennt",
      "3": "unbekannt"
    },
    "trl_door_sensor_state": {
      "1": "deactiviert",
      "2": "gesperrt",
      "3": "geöffnet",
      "4": "unbekannt",
      "5": "kalibrierend"
    },
    "trl_lock_sensor_state": {
      "0": "nicht kalibriert",
      "1": "gesperrt",
      "2": "aufmachen",
      "3": "geöffnet",
      "4": "sperren",
      "5": "aufgeklinkt",
      "6": "geöffnet (lock ‘n’ go)",
      "7": "aufklinkend",
      "254": "Antrieb blockiert",
      "255": "unbekannt"
    },
    "trl_keypad_battery_critical_state": "nicht installiert"
  },
  "Nederlands": {
    "trl_lock_bt_state": {
      "1": "verbonden",
      "2": "verbroken",
      "3": "onbekend"
    },
    "trl_door_sensor_state": {
      "1": "gedeactiveerd",
      "2": "gesloten",
      "3": "open",
      "4": "onbekend",
      "5": "aan het calibreren"
    },
    "trl_lock_sensor_state": {
      "0": "niet gecalibreerd",
      "1": "gesloten",
      "2": "openen",
      "3": "open",
      "4": "ontsluiten",
      "5": "ontgrendeld",
      "6": "open (lock ‘n’ go)",
      "7": "ontgrendelen",
      "254": "moter geblokkeerd",
      "255": "onbekend"
    },
    "trl_keypad_battery_critical_state": "niet geïnstalleerd"
  }
}
%}


{% set ns = namespace(lang_list = []) %}
{% for x in nuki_languages %}
  {% set ns.lang_list = ns.lang_list + [x] %}
{% endfor %}
{{ ns.lang_list }}

{{ nuki_languages["English"]["trl_door_sensor_state"][1] }}
{{ nuki_languages.English.trl_door_sensor_state.1 }}
{{ state_attr('sensor.nuki_bridge_endpoint_list', 'lastKnownState')['batteryChargeState'] }}
{{ state_attr('sensor.nuki_bridge_endpoint_list', 'lastKnownState').batteryChargeState }}

Basically you’re saying that a json structure can’t have that field as numeric, but that’s not true. :slight_smile:

You need to adjust the code so to avoid doing to_json/from_json if not needed, if the structure is already a json string structure, why do you need from_json? That’s the question…

{{ nuki_languages["English"]["trl_door_sensor_state"][1] }}
{{ nuki_languages.English.trl_door_sensor_state.1 }}

These are equivalent, you’re right, but English is hard coded. Try to make it flexible, with this example:

{{ nuki_languages[states('input_select.nuki_language')]['trl_lock_sensor_state'] | to_json }}

this is possible because it is depending on the state of the entity “input_select.nuki_language” and the value of the entity “trl_lock_sensor_state”. I don’t know how to do that with the new syntaxis…

Hi Alessandro,

I’ve looked at your code again, changed a lot and published it on my gist as version v8.6.1. The things I changed:

  • Put the possible states of the lock and door in an input_text, so that this needs to be defined only once.
  • Setting everything to numerical states where possible leaving your logic as is.
  • changed the automation, deleted the “trigger_nuki_lock_sensor_polled” and “trigger_nuki_door_sensor_polled” and according actions and replaced them by “trigger_nuki_bridge_endpoint_list” to set the according input_text entities.
  • Changed the sensor entities “nuki_door_sensor_state” and “nuki_lock_sensor_state” to depend on the according input_text entities. This will cause these entities to update immediately when an action on the lock has been performed.

It would be nice if you would review this version and give your comments. I know that regarding the used json, you’ve got another insight, but for now this does work so I left it this way.

1 Like

Alessandro, nuki card works fine so far. Today in the morning I found the following errors:
Error while executing automation automation.nuki_card_callback: Error rendering data template: JSONDecodeError: Expecting value: line 1 column 1 (char 0)

8:51:11 AM – (ERROR) Automation

Nuki Card Callback: Choose at step 1: choice 3: Error executing script. Error for call_service at pos 1: Error rendering data template: JSONDecodeError: Expecting value: line 1 column 1 (char 0)

8:51:11 AM – (ERROR) Automation - message first occurred at 8:51:11 AM and shows up 2 times

Empty reply found when expecting JSON data

8:51:11 AM – (WARNING) RESTful - message first occurred at July 27, 2021, 8:44:18 AM and shows up 3 times

Error fetching data: http://192.168.1.47:8080/info?&token=ucqbkj failed with

8:51:11 AM – (ERROR) RESTful - message first occurred at July 27, 2021, 8:44:18 AM and shows up 3 times

We know them already (except for the callback automation error) I just want to show them because I have the corresponding Nuki log entries as well:
{“timestamp”: “2021-07-28T06:56:56+00:00”, “type”: “HTTP-Info”},
{“timestamp”: “2021-07-28T06:55:55+00:00”, “type”: “HTTP-List”},
{“timestamp”: “2021-07-28T06:54:25+00:00”, “type”: “HTTP-Info”},
{“timestamp”: “2021-07-28T06:53:54+00:00”, “type”: “HTTP-List”},
{“timestamp”: “2021-07-28T06:53:25+00:00”, “type”: “SSE-PushNukisResponse”},
{“timestamp”: “2021-07-28T06:53:25+00:00”, “type”: “SSE-PushNukisRequest”, “count”: 1},
{“timestamp”: “2021-07-28T06:51:54+00:00”, “type”: “HTTP-Info”},
{“timestamp”: “2021-07-28T06:51:54+00:00”, “type”: “HTTP-List”},
{“timestamp”: “2021-07-28T06:51:31+00:00”, “type”: “SSE-Connected”, “serverNum”: 3},
{“timestamp”: “2021-07-28T06:51:26+00:00”, “type”: “WLAN-Connected”, “ipAddr”: “192.168.1.47”},
{“timestamp”: “2021-07-28T06:51:22+00:00”, “type”: “WLAN-Connect”},
{“timestamp”: “2021-07-28T06:51:22+00:00”, “type”: “WLAN-Init”},
{“timestamp”: “2021-07-28T06:50:20+00:00”, “type”: “WLAN-Disconnected”},
{“timestamp”: “2021-07-28T06:50:20+00:00”, “type”: “SSE-Disconnected”, “serverNum”: 5},
{“timestamp”: “2021-07-28T06:49:53+00:00”, “type”: “HTTP-List”},
{“timestamp”: “2021-07-28T06:49:24+00:00”, “type”: “HTTP-Info”},
{“timestamp”: “2021-07-28T06:47:52+00:00”, “type”: “HTTP-List”},
{“timestamp”: “2021-07-28T06:46:53+00:00”, “type”: “HTTP-Info”},
{“timestamp”: “2021-07-28T06:45:51+00:00”, “type”: “HTTP-List”},
{“timestamp”: “2021-07-28T06:44:22+00:00”, “type”: “HTTP-Info”}]

The time in Nuki is 2 hours off our local time (GMT I guess). The log shows a loss of Wifi connection which cause the error in Nuki automation. My question is if there is a better way of error handling. Unfortunately I have no glue about yaml and the way it handles failing http requests. Thanks again for your work.

Hi Alessandro,

I’ve published version v8.6.2 on my gist with the build in translation.

1 Like

Ciao Joachim,

unfortunately the REST sensor, believe it or not, does not return a status for the http request. I was astonished too about this. At least I didn’t find any mention about it in documentation.

I searched on the forum, but didn’t find any relevant information. If we could have the result of the http call we could implement much better error management.

Sorry about this.

Alessandro

Ciao Jeroen,

thanks a lot for your contribution, I actually liked what you did. I spent 1 hour looking at the code, and I simply renamed some input_text for harmonization, and merged the 2nd automation 2 you created in the existing automation, so to have a single automation.

I also modified this code:

      nuki_languages_string: >
        {% for x in nuki_languages %}
          {%- if loop.last %}
            "{{ x }}"]
          {% elif loop.first %}
            ["{{ x }}", 
          {% else %}
            "{{ x }}",
          {% endif -%}
        {%- endfor %}

With this:

      nuki_languages_string: >
        {% set ns = namespace(lang_list = []) %}
        {% for x in nuki_languages %}
          {% set ns.lang_list = ns.lang_list + [x] %}
        {% endfor %}
        {{ ns.lang_list | to_json }}

I’m going to test it for a while, and if it’s working, I’ll release it as v8.7. :slight_smile:

Thank you so much, we made a good team of two guys with a lot of hair. :rofl:

2 Likes

Ciao Jeroen,

I almost completed the review and the tests.

Question: why do you need the input_text.nuki_preserve_language entity? the input_select preserves its state after restarts.

HI Alessandro,

You’re right about the fact that HA preserves the state of an input_select on a restart. However, if you look closely at the input select you’ll see that I have defined only one value and therefore HA will always revert to this value. The reason I only defined one value is simple, I wanted to fill the values based on the content of the nuki_languages.json file to have the input_select options variable. This is done in the script I added. So if I don’t want to loose the selected language I needed a solution to save the selected language and that is why I created the input_text.nuki_preserve_language entity…

1 Like

Back to this topic since a while. Question: what is the latency to feed back door status?

Pleease do not ask to search the entire threaaaad :slight_smile:

What I have experienced, it is as quick as receiving the notifications on your telephone and sometimes a bit faster…