maximkulkin / esp-homekit

Apple HomeKit accessory server library for ESP-OPEN-RTOS
MIT License
1.1k stars 168 forks source link

Force update when internal variable changes #157

Closed pastre closed 4 years ago

pastre commented 4 years ago

I have a working led example running on an esp32, and I'm using another sensor to update the led_on bool, but HomeKit is not updating on my cell when I change this variable. I know the variable is changing because when I modify led_on and restart the Home app on my phone the LED state changes. Do you have any idea if I can force the update?

maximkulkin commented 4 years ago

To notify controllers that some characteristic value has changed, you need to call homekit_characteristic_notify(characteristic, value);.

E.g. check this example. First, it updates value of characteristic, so if controller connects to accessory and requests all accessory characteristics, it will get proper value. But controllers that are already connected have no idea that something has changed. And that's why homekit_characteristic_notify() is there.

maximkulkin commented 4 years ago

Setting characteristic value and sending notification is intentionally separate, so you can have finer control over those. E.g. with STATELESS_PROGRAMMABLE_SWITCH service, PROGRAMMABLE_SWITCH_EVENT characteristic has always null value, but you can send notifications with actual values, without changing stored value.

pastre commented 4 years ago

Thanks! That worked :)

ZweiEuro commented 3 years ago

@maximkulkin How does the server internally differentiate between the different accessories ? In your example they all use the same callback or event, with just their internal value changed. But where does it say which device is updated? Or is this handled with the callback ? And even then, how would it know with which context?

If it is via the characteristic, then that would mean i need to get the characteristik to my accessories, which I am not sure how it can be done (especially if they are allocated with NEW_...)

maximkulkin commented 3 years ago

Well, a) you can match accessory by characteristic (since characteristic can belong to only one service of one accessory); b) you can store pointer to arbitrary data in characteristic's context field and use it to quickly match which accessory it is.

ZweiEuro commented 3 years ago

I did it via a mix, the order in which the accessories doesn't really change so i just store the characteristic pointers and with the index i can instantly go to the one i need. But thanks ! So i just need the characteristic pointer

ZweiEuro commented 3 years ago

@maximkulkin something else that came up, does this cause the callback to be called from the homekit_characteristic_notify?

For me this causes a loop in the code, which i am not sure is intended or just my fault: button toggles LED -> notify homekit -> homekit toggles button -> notify homekit -> ...

maximkulkin commented 3 years ago

Yes, characteristic callbacks will be called if you call homekit_characteristic_notify(). To avoid loops you can check if the value is the same as current and skip doing anything. Or you can have a global flag that you can set before calling homekit_characteristic_notify() and check it inside notification callback. Or use setter instead - that one is not called when you do homekit_characteristic_notify() (but make sure you update characteristic value if you go that route).

ZweiEuro commented 3 years ago

My bad fix is settings is_null in the value and then the callback just ignores it and sets is_null back to false. it works but it's not really clean. just a manual circle break

maximkulkin commented 3 years ago

Setting is_null will send "null" value notification to all controllers. That's not what you want.