Matter subscriptions not working with MTRBaseDevice obtained from HomeKit

I am working on an app for a Home automation device built on Matter. There are both standard and custom features/services/clusters on this device. HomeKit seems to pick up the standard ones except for one (leak detector) that is part of the Matter 1.3 spec. Of course HomeKit doesn't know what to do with the custom ones so they aren't shown in the Home app. I am trying to access those directly via calls to the Matter APIs so I can present them in a custom app. To access Matter APIs I am using a process suggested by DTS in a forum post that can be found here.

The MTRBaseDevice I obtain in the suggested way responds appropriately to read and write commands, but subscribe doesn't work as expected. It returns an error code 48 which is described as "The operation couldn’t be completed." and the source that contains the error calls it "operationNotSupported". This is the subscribe call referenced in the DTS response to earlier post, however there are three more "subscribe" methods and I have tried them all. Two also return an error 48, and the last one never calls any of the callback handlers providing no data or errors.

Since a subscription is supposed to return data periodically even when there have been no changes it doesn't seem that different than polling so I have written code for that and it works. However I don't expect iOS will let me poll in the background for alarm conditions and I am hoping subscription updates will be sent to a background app so it can notify users of these conditions. Is that a reasonable assumption?

Here is the code I am using to test subscribe, perhaps I am doing something wrong? Originally I had shorter intervals but changing them made no difference. Do they need to be longer?

		let subscribeParams = MTRSubscribeParams(minInterval: 15, maxInterval: 900)
		if #available(iOS 17.6, *) {
			subscribeParams.shouldAssumeUnknownAttributesReportable = true
		}
		subscribeParams.shouldFilterByFabric = false
		subscribeParams.shouldReplaceExistingSubscriptions = true
		subscribeParams.shouldReportEventsUrgently = true
		subscribeParams.shouldResubscribeAutomatically = false
		
		print("Attempting subscribe:with")
		let localClusterStateCache = MTRClusterStateCacheContainer()
		matterBaseDevice.subscribe(with: OS_dispatch_queue_global.global(), params: subscribeParams, clusterStateCacheContainer: localClusterStateCache) { (attributes: [Any]) in
			print("subscribe:with attributeHandler: \(attributes)")
		} eventReportHandler: { (events: [Any]) in
			print("subscribe:with eventHandler: \(events)")
		} errorHandler: { (error: any Error) in
			let reportingError = error as NSError
			if reportingError.domain == "HMErrorDomain" {
				let hkError = HMError(HMError.Code(rawValue: reportingError.code)!)
				print("subscribe:with errorHandler: \(hkError.localizedDescription); UserInfo: \(hkError.userInfo); ErrorUserInfo: \(hkError.errorUserInfo)")
			} else {
				print("subscribe:with errorHandler: \(reportingError)")
			}
		} subscriptionEstablished: {
			print("subscribe:with Subscription established!!!")
		} resubscriptionScheduled: { (error: any Error, numericParam: NSNumber) in
			print("subscribe:with Resubscription scheduled; error: \(error); numericParam: \(numericParam)")
		}
Answered by DTS Engineer in 801256022

Hi,

First off, please file a bug about the issues you're having then post the bug back here. The underlying problem here is that because this was implemented directly "on" MTRBaseDevice, we don't have any good way to clearly explaining in the documentation exactly what will/will not work.

SO, starting with the code side, here is what I believe will work, based on my review of our code:

  1. "subscribeWithQueue..." is implemented, but ONLY the "subscriptionEstablishedHandler" actually works. If you've tried this already, try passing in "NULL" for everything except the "subscriptionEstablishedHandler".

  2. "subscribeToAttributesWithEndpointID..." appears to be fully supported, but I haven't drilled far enough into our implementation to be entirely confident that I haven't overlooked something.

In both cases, when you're testing this makes sure that you're only testing one at at time and experiment with the configuration options (particular the handlers you're registering) before you assume it simply doesn't work.

Since a subscription is supposed to return data periodically even when there have been no changes it doesn't seem that different than polling so I have written code for that and it works. However I don't expect iOS will let me poll in the background for alarm conditions and I am hoping subscription updates will be sent to a background app so it can notify users of these conditions. Is that a reasonable assumption?

No. HomeKit was intentionally designed* as a "foreground only" API. I don't actually know how these particular APIs will behave in a backgrounded app if you happened to be awake, but the system itself isn't going to wake you up for them and nothing in HomeKit will function.

Note that this is also true of the matter usage more broadly. While an ecosystem app can use matter in the background, the system doesn't provide any background category/service that directly supports matter. That second point is critical, because the primary way iOS limits background operation is by tightly controlling when apps are awake at ALL, not by constraining there API usage. The fact that an app could use matter in the background doesn't really matter when the system doesn't provide any way to for it to be awake.

*An Extended Sidebar on HomeKit Background Access:

I've been asked about background to HomeKit, so I think it's helpful to try and explain why we've blocked this. Architecturally, the HomeKit framework was designed around the idea that apps were manipulating a shared configuration that would then "execute somewhere", NOT directly controlling accessories. Users were expected to have lots of device, any one of which could issues commands through lots of possible "routes". Within that frameworks any change happens from one of two reasons:

  1. A user performed some kind of "direct" interaction that directly triggered the change.

  2. The shared "HomeKit Database" included some sort of automation which was executed "auto-magically".

The concern here is an issue I like to call "The Phantom Lightbulb™". That is, a light bulb keeps turning on, you don't know "why", and now you have to fix it. In the system above, either a "user" did it (which is not an Apple problem) or "something" was configured "wrong" in your HomeKit database so an automation didn't do what you wanted. In the second case, you can open any of your controllers and edit your HomeKit database to find the problem.

This all falls apart if you allow background access to HomeKit. Background access means that ANY controller that can run apps can issue commands, so fixing the issue could (potentially) mean interacting with EVERY iOS device you own or have shared your home configuration to. Preventing all background access might seem like an "extreme" solution but, in practice, I think it was the only option that was actually workable.

As another example of these kinds of issues that come up here, it's very common that the device that's most likely to configure/interact with an accessory is also the wrong device to be monitoring it. Speaking from my own experience:

  • Every accessory in my house was setup and configured with my iPhone.

  • My iPhone is the only device that has any manufacturer specific apps installed on it.

  • Of all my devices, my iPhone is the LEAST likely to be at home... since it's in my pocket at the office.

In other words, the only device I'm likely to install a manufacturer app on is also the device that's LEAST likely to be able to communicate with hat accessory.

Just to be clear here, I don't have any particular object about non-HomeKit or vendor specific commands. They're a critical part of many great accessories. My concern here is that any design needs to account for the practical differences between features that are available through the ecosystem and features that are not.

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

Accepted Answer

Hi,

First off, please file a bug about the issues you're having then post the bug back here. The underlying problem here is that because this was implemented directly "on" MTRBaseDevice, we don't have any good way to clearly explaining in the documentation exactly what will/will not work.

SO, starting with the code side, here is what I believe will work, based on my review of our code:

  1. "subscribeWithQueue..." is implemented, but ONLY the "subscriptionEstablishedHandler" actually works. If you've tried this already, try passing in "NULL" for everything except the "subscriptionEstablishedHandler".

  2. "subscribeToAttributesWithEndpointID..." appears to be fully supported, but I haven't drilled far enough into our implementation to be entirely confident that I haven't overlooked something.

In both cases, when you're testing this makes sure that you're only testing one at at time and experiment with the configuration options (particular the handlers you're registering) before you assume it simply doesn't work.

Since a subscription is supposed to return data periodically even when there have been no changes it doesn't seem that different than polling so I have written code for that and it works. However I don't expect iOS will let me poll in the background for alarm conditions and I am hoping subscription updates will be sent to a background app so it can notify users of these conditions. Is that a reasonable assumption?

No. HomeKit was intentionally designed* as a "foreground only" API. I don't actually know how these particular APIs will behave in a backgrounded app if you happened to be awake, but the system itself isn't going to wake you up for them and nothing in HomeKit will function.

Note that this is also true of the matter usage more broadly. While an ecosystem app can use matter in the background, the system doesn't provide any background category/service that directly supports matter. That second point is critical, because the primary way iOS limits background operation is by tightly controlling when apps are awake at ALL, not by constraining there API usage. The fact that an app could use matter in the background doesn't really matter when the system doesn't provide any way to for it to be awake.

*An Extended Sidebar on HomeKit Background Access:

I've been asked about background to HomeKit, so I think it's helpful to try and explain why we've blocked this. Architecturally, the HomeKit framework was designed around the idea that apps were manipulating a shared configuration that would then "execute somewhere", NOT directly controlling accessories. Users were expected to have lots of device, any one of which could issues commands through lots of possible "routes". Within that frameworks any change happens from one of two reasons:

  1. A user performed some kind of "direct" interaction that directly triggered the change.

  2. The shared "HomeKit Database" included some sort of automation which was executed "auto-magically".

The concern here is an issue I like to call "The Phantom Lightbulb™". That is, a light bulb keeps turning on, you don't know "why", and now you have to fix it. In the system above, either a "user" did it (which is not an Apple problem) or "something" was configured "wrong" in your HomeKit database so an automation didn't do what you wanted. In the second case, you can open any of your controllers and edit your HomeKit database to find the problem.

This all falls apart if you allow background access to HomeKit. Background access means that ANY controller that can run apps can issue commands, so fixing the issue could (potentially) mean interacting with EVERY iOS device you own or have shared your home configuration to. Preventing all background access might seem like an "extreme" solution but, in practice, I think it was the only option that was actually workable.

As another example of these kinds of issues that come up here, it's very common that the device that's most likely to configure/interact with an accessory is also the wrong device to be monitoring it. Speaking from my own experience:

  • Every accessory in my house was setup and configured with my iPhone.

  • My iPhone is the only device that has any manufacturer specific apps installed on it.

  • Of all my devices, my iPhone is the LEAST likely to be at home... since it's in my pocket at the office.

In other words, the only device I'm likely to install a manufacturer app on is also the device that's LEAST likely to be able to communicate with hat accessory.

Just to be clear here, I don't have any particular object about non-HomeKit or vendor specific commands. They're a critical part of many great accessories. My concern here is that any design needs to account for the practical differences between features that are available through the ecosystem and features that are not.

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

Thanks Kevin! - for another very helpful answer. I appreciate you giving such answers rather than avoiding topics I may not want to hear - I really do want to know all I can to make things work in the Apple ecosystem. I know Apple is VERY stingy with background operation of apps and this is why my iPhone battery life is both long and predictable - one of the reasons I stick with iPhone and probably many others as well. I will try your subscription suggestions and will file a bug as well. Thanks again.

Thanks Kevin! - for another very helpful answer.

Thank you and you're very welcome.

A few comments on all this:

I appreciate you giving such answers rather than avoiding topics I may not want to hear - I really do want to know all I can to make things work in the Apple ecosystem. I know Apple is VERY stingy with background operation of apps and this is why my iPhone battery life is both long and predictable - one of the reasons I stick with iPhone and probably many others as well. I will try your subscription suggestions and will file a bug as well.

On the background operation issues, one thing we want to avoid avoid here is accessory manufacturers creating "full" ecosystems implementations SIMPLY because of how their app needs to communicate with their accessory. The general expectation here is that actual "ecosystem vendors" don't really have any need for background operation because what they're actually pairing the matter accessory with isn't "their app", it's their ecosystem and it's underlying "off device" controller. To put that in HomeKit terms, if a home as a HomeKit Controller (AppleTV, HomePod, etc), you're not REALLY pairing a new accessory with "your device". The initial pairing process may involve the device your interacting with, but the "end state" of that process is that HomeKit Controller ends up "owning" the accessory and doing all of the actual communication and work*.

*Yes, there are whole HOST of edge cases and exceptions where that isn't what actually happens. This is about the "basic" process, not all of the exceptions and failure modes.

What I really want to avoid here is accessory manufacturer's implementing ecosystem apps SIMPLY because that's what's necessary for their app to do "basic" configuration and management. Because of that, please get bugs filed on anything you find, as it's really important that we document both the issues you're having and what your needs here actually are. The current state of the HomeKit-> Matter "bridge" process is basically a side effect the Matter framework's rapid evolution and the difficulties of adapting that implementation to work over XPC**. The current API state is obviously not ideal, so it's important to document any issues you're having AND the fact that this is an API you "want" to use.

**As background, the matter objects you're working with when you use this flow aren't the "real" matter objects, but are actually wrapper classes that are routing your commands over to homed (which does all of the actual communication). The error "operationNotSupported" basically means "sorry, that method isn't actually implemented in our bridge class".

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

Thanks for the further clarification, I will file bugs that include what I am trying to do as well as the APIs I want to use to implement those things. I did try the "subscriptionEstablishedHandler" and discovered it doesn't work for me if I only pass a "subscriptionEstablished" handler. That may be due to the fact that I am using Swift and the "errorHandler" is also required, though it appears that may not be the case in objectiveC? I've been away from objectiveC for a while. Consequently my error handler is called, not "subscriptionEstablished".

I have submitted this as a bug: FB14928319

Hi Kevin, I hope you are willing to reply to this thread one more time.

What you say about 3rd party apps is spot-on. In a perfect world they would be all about custom configuration. The problem for me is devices I am working on have custom sensors that result in custom alerts. HomeKit has a number of "standard" alerts it will handle in the ecosystem without the vendor app's involvement. An example of this is Leak Detection. Matter 1.3 specs have a standard for leak detection but as far as I know the Home and HomeKit implementation using Matter do not support these at this time. Matter 1.3 also has a freeze alarm which is something I don't believe HomeKit has done in the past, or currently does for Matter devices either.

What I really need is to be able to have a Matter device be able to raise an alarm similar to these as well as for other custom conditions - like temperature or humidity is outside a user-configured range. Does the current Matter implementation via HomeKit support notifications for alarm conditions of any kind from a Matter based device? If not would it be reasonable to expect this will be implemented at some point in the future?

I also need to be able to do custom configuration on the device such as set the ranges mentioned earlier and I currently have all the tools needed to do that, thanks in no small part to your kind assistance. Subscriptions will be nice so I can keep the settings shown in the UI up to date while the app is running without polling.

Detecting and notifying the user of alarm conditions is the only reason I would need to run in the background at all, and frankly I would rather the Home ecosystem take care of that for me as was done in many cases with HomeKit. As you point out attempting to do this with background processing on a device that isn't always in the home isn't a great solution. What is the alternative?

First off, sorry for the delayed response on this. I overlooked your last post and didn't see it until I was looking up this post to reference in another post.

What I really need is to be able to have a Matter device be able to raise an alarm similar to these as well as for other custom conditions - like temperature or humidity is outside a user-configured range. Does the current Matter implementation via HomeKit support notifications for alarm conditions of any kind from a Matter based device?

I'm not sure if it can do exactly what you need/want, but here's the broad state of how this works:

  • First off, if you're not already familiar with it, I would recommend reviewing the HomeKit Accessory Protocol ("HAP") specification directly. The spec is extremely readable, particularly if you don't care about more complex details like the pairing process, and I think having a basic understanding of the hardware protocol makes it easier to understand exactly how the framework actually works. Note that, for example, objects like "services" and "characteristics" actually come directly from the hardware specifications. If you're an MFI licensee you already have access to the most recent spec, but we also released a non-commercial version several years ago. I don't have a link I can share for that spec (please file a bug on that...) but you may be able to find a copy.

  • I would also suggest downloading and experimenting with the "HomeKit Accessory Simulator" (HAS), which you'll find inside "Additional Tools for Xcode <version>" download. HAS is an app that you run on your mac which publishes a hardware level simulation of whatever HomeKit accessories you've configured in it. You can then pair that simulated accessory with as you would any other accessory and then interact with that "accessory" as if it were a real accessory. You can use this tool to easily simulate basically any hardware configuration you can think of, then use that accessory in Home.app to see how the system handles it. This will let you test an experiment with most of Home.app's capabilities without bothering with physical hardware.

  • In the context of the broader, "notifying the user" isn't actually part of the spec. The hardware spec does have it's own "notification" system, but that is a very general system used to inform the controller about very broad variety of changes, most of which wouldn't be visible to the user at all. For example, the "On" characteristic used by lightbulbs notifies but we certainly don't post a notification when the user turns on a light.

  • In general, most of the "interface" you actually see is actually caused by the system itself, NOT the accessory. Looking at the "humidity is outside a user-configured range" example, the ONLY required characteristic of a HAP humidity sensor is "Current Relative Humidity", which returns a float value from 0-100 and which notifies on change. The range the user specifies isn't being pushed to the accessory but is just a threshold the system uses "on it's own". The system knowns every time the characteristic changes (through the HAP notify system) and the system tells the user (through a notification) when the threshold is crossed. It's certainly possible for an accessory to implement more complex behavior than that, but that's the "base" behavior.

  • In my experience, the behavior of matter accessories in HomeKit (see the supported accessory list here) generally matches HomeKit's support for the same accessory. For example, I happen to have a matter over thread temp/humidity sensor from one vendor and a HomeKit over Wifi temp/humidity sensor from a different vendor and the two sensors are handled exactly the same by Home.app. The only real difference I found was that the matter accessory had a "Turn On Pairing Mode" button.

If not would it be reasonable to expect this will be implemented at some point in the future?

I'm never going to discuss Apple's future plans. What I will say is:

  • I'm not aware of any technical issue that would prevent it from happening.

  • If you want Apple to do something, it's critical that you file bugs asking for us to do so. Note that the key point of that bug shouldn't be "please add this" but should actually be "this is the cool product I'm trying to make but can't". The goal of this sort of bug isn't to "tell us about a problem", it's to provide documentation showing interest in a particular change/feature and evidence that the result of that would (ultimately) be valuable to our users.

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

Matter subscriptions not working with MTRBaseDevice obtained from HomeKit
 
 
Q