My application essentially
- goes through all accessories in a home (with some filtering to select just some of them)
- goes through all services of an accessory
- goes through all characteristics of a service (with some filtering, dtto)
If the acc is reachable, non-blocked, and if the characteristic has the SupportsEventNotification property, then (and only then)
- my controller is set as the accessory delegate
- the characteristic is sent the
enableNotification:completionHandler:message - my controller, of course, implements the
accessory:service:didUpdateValueForCharacteristic:method.
It works well most time, but I have bumped into two separate problems:
(i) occasionally, although a device does change its characteristic all right in reality (typically triggered by an automation and observed personally), I do not get the appropriate accessory:service:didUpdateValueForCharacteristic: message at all.
Is that normal? I sort of presume it would happen, if there's some communication glitch inside of the HomeKit ecosystem, right?
The best way to alleviate this problem would be to set up a timer and e.g., once a minute poll all observed characteristics using readValueWithCompletionHandler:, and if the current value differs from the previously seen one, assume it did change and simulate the update internally, right? Or is there a better approach?
(ii) what seems to me even more weird, occasionally I get the accessory:service:didUpdateValueForCharacteristic: message for a characteristic which I did not observe (it never was sent enableNotification:completionHandler:).
The solution is of course trivial, I simply ignore these superfluous updates, but I wonder: is it sort of normal, or does that mean my application must have a bug somewhere?
Thanks!
(i) Occasionally, although a device does change its characteristic all right in reality (typically triggered by an automation and observed personally), I do not get the appropriate accessory:service:didUpdateValueForCharacteristic: message at all. Is that normal? I sort of presume it would happen, if there's some communication glitch inside of the HomeKit ecosystem, right?
Basically, yes, that's not unusual. Determining EXACTLY what happens can be a bit painful, but, off the top of my head, it can happen because:
-
Communication issues mean you "missed" the notification.
-
The accessory itself is what actually generates the notification, and not all accessories ACTUALLY generate a notification for every change that occurs, even if the characteristic itself supports notifications.
The best way to alleviate this problem would be to set up a timer and, e.g., once a minute poll all observed characteristics using readValueWithCompletionHandler:, and if the current value differs from the previously seen one, assume it did change and simulate the update internally, right?
Yes, though I'd also recommend thinking about how the user actually interacts with your app and how important the "current" state is within that context. The issue here is that HomeKit app developers spend a lot of time staring at their app, which means they tend to be very annoyed/aware if/when its state doesn't match reality. The problem is that basically "no one" uses HomeKit like that— they open the app, perform one or more actions, then close it again. That doesn't mean getting the current state has no value*, but it does mean that focusing too much on the issue can be counterproductive.
*If you watch closely, you can see Home.app do it when it's opened
(ii) What seems to me even more weird, occasionally I get the accessory:service:didUpdateValueForCharacteristic: message for a characteristic which I did not observe (it never was sent enableNotification:completionHandler:). The solution is of course trivial; I simply ignore these superfluous updates, but I wonder: is it sort of normal, or does that mean my application must have a bug somewhere?
Normal as well. Again, determining the EXACT cause is tricky, but the common cause here is that when an accessory doesn't have an active connection, it notifies of "changes" but updates its GSN (Global State Number). That value change then triggers a reconnect and, as part of the reconnection process, they then read the entire state of the accessory. That can then trigger a "didUpdateValueForCharacteristic" message back to your app to let you know about the "change".
__
Kevin Elliott
DTS Engineer, CoreOS/Hardware