homekit_python
homekit_python copied to clipboard
Support events for BLE devices
There are 2 kinds of events in the BLE spec:
- Connected events - we have an established connection to the device. I'm not clear on whether this includes secure and insecure sessions, or just secure sessions.
- Disconnected events
Disconnected events
At least with my Eve Energy, if i do a secure read from the on characteristic then tear down the session I can see the GSN go up once when i press the physical button. Pressing the physical button a 2nd time does not increment the GSN and i don't see it increment again until i've done a secure read of the characteristic that changed. (I haven't tested to see if any secure read resets the state, or if you have to read the characteristic that changed).
I also haven't tested whether the GSN goes up whilst I am connected - even if it did with the Eve devices it would seem to be against spec to rely on this.
Right now it feels like supporting Disconnected events is outside the scope. In homeassistant I can run a DeviceManager with discovery turned on and monitor the ManufacturerData field for changes to GSN - maybe some helper code to detect changes to GSN and config number?
Connected events
In my current prototype I do a characteristic.enable_notifications() on the characterstics i'm interested in. This is not quite enough:
- Right now in my code there is a gatt
Managerfor discovery running in its own thread. This is always running discovery and registering devices as they appear. - Each homeassistant device has its own
ManagerandDevice, andManageris never permanently running for a device (can't remember whether I still run it briefly to resolve services or not). - If a device enables notifications on its own dbus connection then its main loop is not running to receive notifications, so you never get any values reported.
- In my prototype I hacked discovery to pass the
Deviceit creates during discovery through. This means there is a single dbus connection for all homekit bluetooth comms. This works, but makes for some messy code.
When this has happened characteristic_value_updated is called on the Device object. One annoying detail is that a secure read triggers characteristic_value_updated too. So you have to check the value to see if its a secure read or a genuine event:
def characteristic_value_updated(self, characteristic, value):
if value == b'':
print('Characterstic has changed - initiate a secure read')
This is pretty quick - the log message for the event being received is pretty much instantaneous.
To make this work with the existing API get_events for the BleSession has to run the mainloop. So each device has to have its own connection to dbus. This is more resource heavy, but simpler. This is awkward in homeassistant because with this model I can only do one get_events at once per phyiscal device - but if there are multiple services there could be multiple logical entities in hass. This will have to be an error condition on the homekit_python side.
I think there is an argument for factoring the API so that we only need one Manager (and hence one connection to bluez) but thats probably quite a big API change so i'm ignoring that right now.
@jlusiardi I can't tag this as BLE Transport by myself unfortunately - could you when you get a moment?
@Jc2k what about this one for the BLE merging milestone?
For me it’s a nice to have in the first release. I think it’s going to be a while before I can use HA with events.