Jc2k / aiohomekit

asyncio for homekit
Apache License 2.0
52 stars 19 forks source link

Examine Thread provisioning for Apple networks #81

Closed roysjosh closed 7 months ago

roysjosh commented 2 years ago

I've got a HomePod Mini on order. I'm going to see how the Home app provisions Nanoleaf Essentials bulbs onto Apple Thread networks.

roysjosh commented 2 years ago

Finally, some progress... I just needed a BLE "fake bulb" app, no biggie πŸ˜† With the HomePod Mini paired to the Home app, a newly-paired BLE bulb gets sent this tlv8:

HAPThreadControlPoint write: 000262770008000103010103090101
 PDU: control=0x0 opcode=0x2 tid=0x62 iid=119 datalen=8 data=0103010103090101
 hap_write new_val=0103010103090101
 _set_value format=0x1B value.bytes=0103010103090101
 Response PDU: 0262000000
HAPThreadControlPoint read

Now, to repeat that to a real bulb & we'll see what we get. Rinse & repeat.

roysjosh commented 2 years ago

Repeating those bytes to a bulb gave me identical tlv8 to the already-discovered Nanoleaf th/tc control, just wrapped in a HAP Param Value rather than the Nanoleaf command/response TLVs. Interesting.

[
  <1, [
    <2, [
      <1, b'NanoleafThread56'>,
      <2, b'... channel, 2 bytes ...']>,
      <3, b'... PAN ID, 2 bytes ...'>,
      <4, b'... ext PAN ID, 8 bytes ...'>,
    ]>,
  ]>,
]
Jc2k commented 2 years ago

Good stuff! As soon i saw the TLVs you found for th/tc I was sure they were going to rock up on this endpoint.

Jc2k commented 2 years ago

Even more hopeful that we can fully provision a thread mesh purely with aiohomekit. Will start thinking about how this should look in Home Assistant.

We might ultimately want some top level feature in HA for managing Thread networks so that e.g. people wanting to run an open source thread router as a HA add on can then drop their Nanoleaf accessories onto it.

But in the short term, i think it's either going to have to be on the CLI or via custom service calls. It's not like we can have a "move to thread" button or switch because we need to know the details of the mesh.

Jc2k commented 2 years ago

(https://twitter.com/falstaff_ch/status/1494755206566924289 for someone working on OTBR for HA)

roysjosh commented 2 years ago

Nice! I've still got to figure out what tags 1 and 3 are but it looks pretty straight-forward to send network credentials. A custom service call might make sense, I've seen that for other integrations. I know you were working on having pairings be multi-protocol, is there work left to do there?

Jc2k commented 2 years ago

Yes, unfortuantely.

The old code just routed the load operation to the right code based on the connect type string in the config entry.

The new idea was to instead give each backend the chance to provide a Pairing object for a given device id, and that Thread would have priority over BLE if it was available. I think that sort of happens now, but the backends will only consider the connection type string in the config entry. So it would need to look in the discovery data instead or we'd have to mark it as capable of Thread and BLE or something.

Right now its difficult to consider the thread enabled characteristic without layer violations. I'm hoping we can fix that and then respect the characteristic setting.

A more advanced version of that would be that a new multiprotocol class could be returned that would be able to switch protocol at runtime.

I'm doing some πŸ‡ΊπŸ‡¦ stuff thats eating all my time right now, so i've not been able to get any of the tests written I wanted to. Not even had chance to try and set up my Nanoleaf gear with my first thread network yet either.

roysjosh commented 2 years ago

Responding to the initial TLV

[
  <1, b'\x01\x01\x03'>,
  <9, b'\x01'>,
]

with an empty HAP Param Value TLV 0100 causes the Home app to attempt a provision of the HomePod Mini network creds:

HAPThreadControlPoint write: <redacted>
 PDU: control=0x0 opcode=0x2 tid=0x4D iid=119 datalen=69 data=<redacted>
 THREAD CONTROL hap_write new_val=<redacted>
[
  <1, b'... redacted tlv8 bytes in a HAP Param Value, decoded below ...'>,
  <9, b'\x01'>,
]
[
  <1, b'\x01'>,
  <2, [
    <1, ... str network name ...>,
    <2, ... int channel ...>,
    <3, ... int PAN ID ...>,
    <4, ... int extended PAN ID ...>,
    <5, b'... key bytes ...'>,
  ]>,
  <3, b'\x00'>,
]
roysjosh commented 2 years ago

TODO

Happy for suggestions on 2 and 3.

Anything else jump out at you @Jc2k from a high-level perspective or from my WIP HA/core branch?

Jc2k commented 2 years ago

I haven't looked yet but was originally thinking a proxy that implements the AbstractPairing and picks the best actual pairing.

If there was a exception like AccessoryNotFound or not connected it would try the next backend.

And then eventually with the refactoring that is in progress the idea is that each controller when started will track devices it can talk to, so the proxy will be able to get availability updates from that so it would try the ones it thought was available in priority order.

Although there are a lot of details here, I'd want to get @bdraco involved in the design as he has been doing a lot of heavy lifting recently while I'm distracted by a baby.

A simpler option could be we confirm that the device joined the thread network successfully and then switch it from BLE to CoAP and there's no magic failover - punt that to V2 and make sure everything is stable before we add that layer.

Jc2k commented 2 years ago

Just had a quick look at https://github.com/home-assistant/core/compare/dev...roysjosh:core:hap-thread-provision. It's not much code is it! So used to the handshakes in HAP i thought there would be a 6 step dance, but its barely different to setting a WiFi password!

Some thoughts:

roysjosh commented 2 years ago

Congrats on the distraction! Yes, the plan is to move it to aiohomekit's pairing classes. This was just quicker to test :) I'll see about the IP backend. I don't know if this code will provision a Border Router & start up a new network or not. Today, all of the values are grabbed from the Android Nanoleaf app (iOS hides a few of the values) so we aren't responsible for picking them.

Jc2k commented 2 years ago

Cheers :)

For Thread nubs like me :)

https://openthread.io/guides/thread-primer/network-discovery

Covers what a PAN ID etc is.

https://openthread.io/guides/pyspinel/wireshark

Talks about the master key, suggests its "AES-128 Encryption, 32-bit Integrity Protection"

So while we probably could generate the key, we can't safely generate our own network configuration without a thread radio i think.

That said, it would still be cool to be able to provision secondary border routers with this (if you have multiple shapes you get failover, which is pretty cool!).

MattWestb commented 1 year ago

With Silabs addon or paring one OTFD to the addon its possible paring devices with normal thread credentials and searing the complete OTBR / meh network with CLI or over IPV6.

The network parameters for doing the joinier PSKd is easy getting (Open thread papers) with CLI.

> dataset active
Active Timestamp: 1
Channel: 15
Channel Mask: 0x07fff800
Ext PAN ID: ff111111222222ee
Mesh Local Prefix: fd78:6b43:414a:a7a0::/64
Network Key: TeStNeTwOrKKeY
Network Name: BillyOpenThread
PAN ID: 0x1ef4
PSKc: NoTfOrYoUrEaYs
Security Policy: 672 onrc
Done

Its also possible getting it as one string with dataset active -x and its one function to importing the dataset to HA implanted in the addon.

Only 2 things i cant doing with EVE energy and Nanoleaf lights is getting them in thread paring mode and getting there pin for paring one thread network (is not the same as the HK code).

If both settings was possible putting in HA GUI they is in the thread network in 2 minutes with CLI :-)))

Jc2k commented 1 year ago

HA is working on a thread integration:

https://github.com/home-assistant/core/tree/dev/homeassistant/components/thread

The HA ecosystem will sync thread network connection settings into the store in this integration.

Right now you can see how you can list and get thread network details from this integration. There is a plan to add a get_preferred_dataset type API that we should use.

So we should be able to seamlessly pair a device over BLE and then upgrade it to Thread, without having to ask the user about network keys and pan ids etc.

Jc2k commented 7 months ago

Going to close this, as we did this ages ago and theres now a button in HA to move a device from bluetooth to thread.