I was playing with the IKEA DIRIGERA bridging some remotes, just for fun since I use them via Zigbee. Model doesn’t matter, happens with all remotes.
Only one of the buttons in the remotes is available since it uses the default button-battery profile instead of, let’s say, 2-button-battery, 5-button-battery, etc.
Looks like a recent bug that could affect any Matter button not in the list of manufacturer-specific fingerprints since the way the driver matches the profile is prone to this behaviour. Interestingly, if you switch to another driver and go back to the stock one, the profile is updated correctly, we’ll see why in a moment!
The problem is the battery profiling logic. The driver detects correctly the number of buttons (endpoints) but it doesn’t change the profile when it detects the number of buttons (maybe it should to prevent these issues). Instead, it sends a read request for some power attributes and only continues when it receives the response, that might never arrive…
If the response isn’t received the button is stuck with the defaut profile forever, like happens always to me when I add the device to the bridge. Forever or until you switch drivers, which calls driver_switched and match_profile and sends the read request again, but this time the response arrives and the profile is updated as expected.
local function build_button_profile(device, main_endpoint, num_button_eps)
local profile_name = string.gsub(num_button_eps .. "-button", "1%-", "") -- remove the "1-" in a device with 1 button ep
if device_type_supports_button_switch_combination(device, main_endpoint) then
profile_name = "light-level-" .. profile_name
end
device:try_update_metadata({profile = profile_name})
-- Why are we doing this here in the build_button_profile() function?
local battery_supported = #device:get_endpoints(clusters.PowerSource.ID, {feature_bitmap = clusters.PowerSource.types.PowerSourceFeature.BATTERY}) > 0
if battery_supported then -- battery profiles may be overridden later, in power_source_attribute_list_handler
device:send(clusters.PowerSource.attributes.AttributeList:read(device))
end
end
Fixing it for good is going to be tricky and probably requires a rethinking of the driver. With the incoming modular profiles it will hopefully be more manageable.
Changing the profile first and then immediately again after the read request/response could lead to other issues like the button having a wrong profile with no battery information if the response doesn’t arrive or in case a race condition is possible in try_update_metadataby calling it twice in a row.
Maybe the read request should be delayed one second or more like they do in other drivers to avoid race conditions when requesting features from a device. Delays are ugly though and the driver would still be betting everything to one response in just one try.
The actual root of the issue is capabilities that ultimately makes everything more complex than it should in SmartThings . Had to say it, they seem to be written in stone and can’t adapt when needed. I still don’t understand why there’s not a “long press release” event for buttons, or a “initial press”, maybe they cannot modify capabilities?
The driver needs to ask for the PowerSource reporting attributes because SmartThings has TWO capabilities to report battery state and needs to decide which one to use in the profile.
Why, oh why, is there abattery and a batteryLevel capability which are basically identical, with duplicated attributes, except one uses a numeric level and another a qualitative level?
It would have been so much easier to just have one with two attributes: a level and aqualitativeLevel. The app could display the information available, the percentage with a number and the normal/warning/critical with colours for instance. No profile change would be needed at all since the capability would always be the same and this post would not exist .
I just gave grok the init.lua and asked it if there are any issues with the code. It explained in detail (a dozen pages) what’s wrong with the profile matching and it even mentioned the timing. Try it yourself!
Adding a delay seems to work for the bridged buttons but, again, feels ugly and it’s not that I did extensive testing
if battery_supported then -- battery profiles are configured later, in power_source_attribute_list_handler
device.thread:call_with_delay(3, function(d)
device:send(clusters.PowerSource.attributes.AttributeList:read(device))
end)
else
Although the problem here was not receiving the response in the driver, that could as well be an issue with the Dirigera not sending the response, the beta firmware of the hub not sending the request, etc.
I’ve tried to replicate the issue now, but now the response is received correctly and the profile updated, at least the three times I tried.
Assuming there’s been no changes since the first post -ST hub fw is the same, driver is the same, Dirigera fw is the same- it makes the bug even more strange.
Caught it! Hub firmware is now 58.9, DIRIGERA fw is 2.815.2, and production Matter Switch driver 2025-09-10. I’ve been able to reproduce it. I sent the hub logs too @nayelyz.
But there’s no response so it ends up with the default profile for just 1 button when it was a TRADRFI 5-button.
Even if it’s DIRIGERA’s fault not replying (I only know the driver handler isn’t called, but hopefully you can get more insights in the hub logs), the driver could be modified to be more fail-proof as discussed in previous comments, maybe retrying or at least falling back to a profile with all the buttons even if the battery information is unknown.
I’d like to be wrong, but it seems a lot of the mucking around with profiles has keeping the mobile app happy as its goal.
Along with its belief that the online/offline status of a device is a complete absolute, an opinion seeming not shared elsewhere in the platform, the mobile app seems to place great import on attributes having been assigned a value when actually it doesn’t really matter.
So we get synthetic events being generated when a N/A would make it clear that the device hasn’t provided any data yet and something might be broken. We also get a desperate need to avoid unsupported capabilities in the profiles. Apart from making the UI look messy, should it really matter?
There really should be a fallback profile that results in a fully functioning device, even if there is extraneous stuff in it, rather than a minimal profile that results in a partially functioning device. However I get the feeling the mobile app prefers the latter.
I am sure the mobile app wasn’t always so fussy. It would let us know which attributes hadn’t been initialised but let us get on with using the device. That was far more sensible.