HomeKit Accessory Protocol (HAP) over CoAP/UDP (was: Nanoleaf Essentials bulb via Thread/CoAP)

Gotcha! I’d love to give it a shot and report back if I observe anything weird. I’m running HA OS on a Raspberry Pi.

I couldn’t figure out how to pass environment variables on my HA OS so I just hacked the code. If you’re familiar with vi/vim, give this a try.

Enter the homeassistant container from HA OS:

docker exec -it homeassistant sh

And then let’s edit some Python!

vi /usr/local/lib/python3.10/site-packages/aiohomekit/const.py

and edit line 36 (OLD)

    if "AIOHOMEKIT_TRANSPORT_COAP" in os.environ:

to read (NEW, spacing and capitalization are important):

    if True:

You’ll also have to edit aiocoap to fix an issue they haven’t merged a PR for yet:

vi /usr/local/lib/python3.10/site-packages/aiocoap/transports/ws.py

and edit line 187 (OLD):

            else:

to read (NEW):

            elif port != 0:

Finally, restart HA from the web interface. You should see Essentials as new devices!

1 Like

@lambdafunction Thanks. I applied the code hacks but somehow the bulbs still don’t show up in HA. I manually looked for them in HomeKit Controller integration too but only the Elements panel is there. Are there any logs that I can share to help diagnose the problem?

Have you already added them to a homekit system, google nest, or ios app? If so that’ll take up the one admin slot the essentials have and you’ll have to factory reset them.
Currently the best way to acquire them is to use the android app, which apparently also has a better thread network viewer.

Edit:
Updated HA finally and made the changes lambda outlined, seems to work fine for me though I already had my essentials acquired to HA previously.

I had them previously added to the Nanoleaf Android app only. Just to be sure, I did a factory reset on the bulbs, added them again to the Nanoleaf app, then looked for them in HA. Still no dice.

Here’s my HA setup:

  • HA OS on raspi
  • Nanoleaf Elements added to HA using the Nanoleaf integration (is this correct?)
  • Nanoleaf Essentials connected to Thread network created by the Elements border router (using Android app)

@spanky13 first, start with an mDNS service browser. On Android I use one called Service Browser by Andriy Druk on the Play Store. It’s OSS and seems to work fine. Look for _hap._udp. (HAP) services; there should be one for each bulb. Additionally, if you tap into a bulb you will see the mDNS properties; ensure that sf is 1 (pairable). On Mac I use dns-sd -Z _hap._udp to find the bulbs and on Linux I use avahi-browse -r _hap._udp.

You can also try to ping the bulbs.

ping6 Nanoleaf-A19-12FA.local
OR
ping -6 Nanoleaf-A19-12FA.local

If that looks good, go call the service “Logger: Set level” from the Developer Tools:

service: logger.set_level
data:
  aiohomekit: debug
  homeassistant.components.homekit_controller: debug
  zeroconf: debug

And let that sit for a bit to see if HA detects any HAP devices. Maybe turn a bulb off, wait a few seconds, then turn it back on with the logs at debug. Bulbs should trigger the BR to broadcast an mDNS service on startup.

1 Like

I need to call a freind who owns an android over to my house haha! All this development has me itching to try this.

You’re killing it lambda!

If sf is not set to 1, what are the next steps? Do I need to delete the bulbs from HomeKit in order for them to start showing up in Logger or at the very least having an sf value of 1?

@Leiesoldat sf=0 means that the accessory is paired to something. You need to either delete it from whatever “Home” it is paired to or factory reset it. Both should work.

@lambdafunction sf was indeed 0 in my bulbs. So I did a factory reset and did not add them to the Nanoleaf app anymore. HA was then able to find the bulb and I am now able to control it from there.

Some early feedback on the integration:

  1. There’s a bit of a delay (1-2 seconds) the first time you control the bulb (either turn it on or off). Subsequent commands after that gets instant response. Then it’ll be slow again after several minutes of not issuing commands.
  2. If I turn off the physical switch connected to the bulb, HA does not recognize that as an unreachable device.

At this point, I’m just glad that we now have the ability to control the bulbs in HA. The native Nanoleaf app is just too finicky to be considered useful :slight_smile: Hats off to everyone who contributed to this @Jc2k @lambdafunction @TheTofu

@spanky13 glad to hear you got it working! It sounds like you may be connected over BLE? You can check from the HA console:

jq '.data.entries[] | select(.domain == "homekit_controller") | select(.data.Connection == "BLE")' /mnt/data/supervisor/homeassistant/.storage/core.config_entries

Since you’ve got Android, you should be able to add the bulbs to the app again to get them on Thread. Or wait for the HA service, but that will be 2022.9 at the earliest.

Hmm, having various issues since I upgraded to HA 2022.8.3, some of which are homekit related.
Seems like occasionally the bulbs will lose connection and I’m not sure why, I may also just have some kind of network DNS issue, not sure if that would cause what I’m seeing:

Logger: homeassistant
Source: components/homekit_controller/config_flow.py:288
First occurred: 7:01:53 AM (148 occurrences)
Last logged: 10:55:12 PM

Error doing job: Task exception was never retrieved
Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/helpers/discovery_flow.py", line 74, in _async_process_pending_flows
    await gather_with_concurrency(
  File "/usr/src/homeassistant/homeassistant/util/async_.py", line 199, in gather_with_concurrency
    return await gather(
  File "/usr/src/homeassistant/homeassistant/util/async_.py", line 197, in sem_task
    return await task
  File "/usr/src/homeassistant/homeassistant/data_entry_flow.py", line 222, in async_init
    flow, result = await task
  File "/usr/src/homeassistant/homeassistant/data_entry_flow.py", line 249, in _async_init
    result = await self._async_handle_step(flow, flow.init_step, data, init_done)
  File "/usr/src/homeassistant/homeassistant/data_entry_flow.py", line 359, in _async_handle_step
    result: FlowResult = await getattr(flow, method)(user_input)
  File "/usr/src/homeassistant/homeassistant/components/homekit_controller/config_flow.py", line 288, in async_step_zeroconf
    await conn.pairing.reconnect_soon()
  File "/usr/local/lib/python3.10/site-packages/aiohomekit/controller/coap/pairing.py", line 228, in reconnect_soon
    address = self.pairing_data["AccessoryAddress"]
KeyError: 'AccessoryAddress'
Logger: aiohomekit.controller.coap.pdu
Source: components/homekit_controller/connection.py:629
First occurred: 9:43:42 AM (19 occurrences)
Last logged: 10:48:44 PM

Transaction 0 failed with error 6 (Invalid request)
Logger: aiohomekit.controller.coap.connection
Source: components/homekit_controller/connection.py:629
First occurred: 7:47:41 AM (91 occurrences)
Last logged: 10:55:42 PM

CoAP POST returned unexpected code <aiocoap.Message at 0x7fdf6f1ea350: Type.ACK 4.04 Not Found (MID 39198, token a8d5) remote <UDP6EndpointAddress [fdee:b12:3711:0:a015:26c6:b359:f13c] (locally 2603:8000:f101:2930:2459:9c09:ceb8:59cb%ens18)>>
CoAP POST returned unexpected code <aiocoap.Message at 0x7fdf6e732c50: Type.ACK 4.04 Not Found (MID 25189, token 4fda) remote <UDP6EndpointAddress [fdee:b12:3711:0:c65b:4519:b08e:d483] (locally 2603:8000:f101:2930:2459:9c09:ceb8:59cb%ens18)>>
Decryption failed, desynchronized? Counter=11/14
Decryption failed, desynchronized? Counter=12/14
Decryption failed, desynchronized? Counter=14/16

Slightly off-topic, but if you do have Nanoleaf gear connected via HomeKit BLE, there is a bunch of work in flight that will make things much faster over the coming months.

All of these changes together have a huge impact on HomeKit BLE performance.

1 Like

@TheTofu - at least the first one looks like my bad and probably caused by: https://github.com/Jc2k/aiohomekit/pull/133. Probably stick on .2 for now if you can.

I’m having trouble pairing the Essential bulb.

The environment:

  • RPI 4 running on DietPi
  • HA container: v2022.8.3
  • both code hacks in the python scripts are done
  • Essential bulb is paired to the BR (NL Shapes), working in NL android app, and available over Thread
  • Essential bulb can be seen in Service Browser (android app)
  • Essential bulb is auto-discovered (after turning it off and on after 5-10 secs) by HA which ask to integrate it through Homekit Controller

When trying to integrate it, I have some Timeout error every time (tried many times, turning off/on the bulb, reset etc).

Error log:

2022-08-11 09:34:02.634 WARNING (MainThread) [aiohomekit.controller.coap.connection] Pair setup 1/2 failed!
2022-08-11 09:34:02.642 ERROR (MainThread) [homeassistant.components.homekit_controller.config_flow] Pairing attempt failed with an unhandled exception
Traceback (most recent call last):
  File "/usr/local/lib/python3.10/asyncio/tasks.py", line 456, in wait_for
    return fut.result()
asyncio.exceptions.CancelledError
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
  File "/usr/src/homeassistant/homeassistant/components/homekit_controller/config_flow.py", line 502, in async_step_pair
    self.finish_pairing = await discovery.async_start_pairing(self.hkid)
  File "/usr/local/lib/python3.10/site-packages/aiohomekit/controller/coap/discovery.py", line 57, in async_start_pairing
    salt, srpB = await self.connection.do_pair_setup(
  File "/usr/local/lib/python3.10/site-packages/aiohomekit/controller/coap/connection.py", line 291, in do_pair_setup
    response = await asyncio.wait_for(
  File "/usr/local/lib/python3.10/asyncio/tasks.py", line 458, in wait_for
    raise exceptions.TimeoutError() from exc
asyncio.exceptions.TimeoutError

Any idea on this ?

I could try to make it work over BLE only to test, but I dont know how to force this, as it’s over CoAP right now.

@TheTofu the last one is the “normal” series of errors when comms get messed up. Either the bulb loses our session or some traffic is dropped/repeated causing the encryption context to get out of sync. I try to recover in the code but in general I’ve found that if you see the first error (CoAP POST returned … 4.04) that the bulb has lost the session. In the future I hope to make this more seamless to the frontend but for now the bulb toggles to “unavailable” for a minute.

@damru hmm can you please try to ping6 / ping -6 the bulb from the HA console? You can use the hostname format Nanoleaf-A19-XXXX.local where XXXX represents your bulb’s 4 character ID. If that doesn’t work, check if HA has an IPv6 address with ip -6 a. Finally, please restart HA and then don’t restart the BR (which causes it to advertise bulbs on a new IPv6 prefix).

If none of those work, please turn on the 3 debug logs per post 160 and DM them to me.

@lambdafunction I’m playing with your “hacktastic” code and was trying to see if I can get an Eve device to join the Nanoleaf router. I added it to a HomePod border router so that I could get the HK ID, unpaired it and reset it, and then tried to have it join the Nanoleaf border router using the service you created. I keep getting an Unknown HKID error when I try it though. Any ideas? Or am I missing a step

And thanks!

@psumatt the HomeKit ID changes with each pairing. If you are connected to the device over BLE, download the device diagnostics from HA & the HK ID will be in there.

@lambdafunction ahh genius, thank you. I’m no longer getting that error, although it doesn’t seem to be adding it to the thread network either.

Any tips on what I should be looking for in the logs? I’ve also tried it with an OpenThread router I have setup but still not seeing it join the network. Have tried the Android flag as well as the iOS flag.