Skip to content

Adding support for Hager WAASYS devices#2858

Merged
hcarter-775 merged 1 commit into
SmartThingsCommunity:mainfrom
JanJakubiszyn:Hager_WAASYS_device_support
Jul 1, 2026
Merged

Adding support for Hager WAASYS devices#2858
hcarter-775 merged 1 commit into
SmartThingsCommunity:mainfrom
JanJakubiszyn:Hager_WAASYS_device_support

Conversation

@JanJakubiszyn

Copy link
Copy Markdown
Contributor

Check all that apply

Type of Change

  • WWST Certification Request
    • If this is your first time contributing code:
      • I have reviewed the README.md file
      • I have reviewed the CODE_OF_CONDUCT.md file
      • I have signed the CLA
    • I plan on entering a WWST Certification Request or have entered a request through the WWST Certification console at developer.smartthings.com
  • Bug fix
  • New feature
  • Refactor

Checklist

  • I have performed a self-review of my code
  • I have commented my code in hard-to-understand areas
  • I have verified my changes by testing with a device or have communicated a plan for testing
  • I am adding new behavior, such as adding a sub-driver, and have added and run new unit tests to cover the new behavior

Description of Change

Summary of Completed Tests

Tests performed on the physical device.

@github-actions

github-actions Bot commented Mar 30, 2026

Copy link
Copy Markdown

Duplicate profile check: Passed - no duplicate profiles detected.

@github-actions

github-actions Bot commented Mar 30, 2026

Copy link
Copy Markdown

Channel deleted.

@github-actions

github-actions Bot commented Mar 30, 2026

Copy link
Copy Markdown

Test Results

   73 files    518 suites   0s ⏱️
2 963 tests 2 963 ✅ 0 💤 0 ❌
4 860 runs  4 860 ✅ 0 💤 0 ❌

Results for commit 4252039.

♻️ This comment has been updated with latest results.

@github-actions

github-actions Bot commented Mar 30, 2026

Copy link
Copy Markdown

File Coverage
All files 92%
/home/runner/work/SmartThingsEdgeDrivers/SmartThingsEdgeDrivers/drivers/SmartThings/matter-switch/src/sub_drivers/ikea_scroll/scroll_utils/event_utils.lua 41%
/home/runner/work/SmartThingsEdgeDrivers/SmartThingsEdgeDrivers/drivers/SmartThings/matter-switch/src/sub_drivers/ikea_scroll/init.lua 87%
/home/runner/work/SmartThingsEdgeDrivers/SmartThingsEdgeDrivers/drivers/SmartThings/matter-switch/src/switch_handlers/capability_handlers.lua 92%
/home/runner/work/SmartThingsEdgeDrivers/SmartThingsEdgeDrivers/drivers/SmartThings/matter-switch/src/switch_handlers/attribute_handlers.lua 80%
/home/runner/work/SmartThingsEdgeDrivers/SmartThingsEdgeDrivers/drivers/SmartThings/matter-switch/src/switch_handlers/event_handlers.lua 97%
/home/runner/work/SmartThingsEdgeDrivers/SmartThingsEdgeDrivers/drivers/SmartThings/matter-switch/src/switch_utils/device_configuration.lua 97%
/home/runner/work/SmartThingsEdgeDrivers/SmartThingsEdgeDrivers/drivers/SmartThings/matter-switch/src/switch_utils/embedded_cluster_utils.lua 38%
/home/runner/work/SmartThingsEdgeDrivers/SmartThingsEdgeDrivers/drivers/SmartThings/matter-switch/src/switch_utils/utils.lua 92%
/home/runner/work/SmartThingsEdgeDrivers/SmartThingsEdgeDrivers/drivers/SmartThings/matter-switch/src/sub_drivers/camera/camera_handlers/attribute_handlers.lua 96%
/home/runner/work/SmartThingsEdgeDrivers/SmartThingsEdgeDrivers/drivers/SmartThings/matter-switch/src/sub_drivers/camera/camera_handlers/capability_handlers.lua 84%
/home/runner/work/SmartThingsEdgeDrivers/SmartThingsEdgeDrivers/drivers/SmartThings/matter-switch/src/sub_drivers/aqara_cube/init.lua 95%
/home/runner/work/SmartThingsEdgeDrivers/SmartThingsEdgeDrivers/drivers/SmartThings/matter-switch/src/init.lua 97%
/home/runner/work/SmartThingsEdgeDrivers/SmartThingsEdgeDrivers/drivers/SmartThings/matter-switch/src/sub_drivers/hager/init.lua 93%
/home/runner/work/SmartThingsEdgeDrivers/SmartThingsEdgeDrivers/drivers/SmartThings/matter-switch/src/sub_drivers/eve_energy/init.lua 91%
/home/runner/work/SmartThingsEdgeDrivers/SmartThingsEdgeDrivers/drivers/SmartThings/matter-switch/src/sub_drivers/camera/camera_utils/utils.lua 98%
/home/runner/work/SmartThingsEdgeDrivers/SmartThingsEdgeDrivers/drivers/SmartThings/matter-switch/src/sub_drivers/camera/camera_utils/device_configuration.lua 94%
/home/runner/work/SmartThingsEdgeDrivers/SmartThingsEdgeDrivers/drivers/SmartThings/matter-switch/src/sub_drivers/camera/init.lua 96%
/home/runner/work/SmartThingsEdgeDrivers/SmartThingsEdgeDrivers/drivers/SmartThings/matter-switch/src/sub_drivers/ikea_scroll/scroll_handlers/event_handlers.lua 73%
/home/runner/work/SmartThingsEdgeDrivers/SmartThingsEdgeDrivers/drivers/SmartThings/matter-switch/src/sub_drivers/third_reality_mk1/init.lua 95%

Minimum allowed coverage is 90%

Generated by 🐒 cobertura-action against 4252039

@hcarter-775

Copy link
Copy Markdown
Contributor

One way in which I think we could quickly simplify some of the Hager subdriver would be by require-ing some fields and functions from the main driver, and changing their inputs as necessary in the overriden driver, rather than rewriting everything completely from scratch.

@JanJakubiszyn JanJakubiszyn force-pushed the Hager_WAASYS_device_support branch from 46b4bc2 to 1373485 Compare May 13, 2026 18:44

@hcarter-775 hcarter-775 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for implementing more of the pre-existing functionality. At this point, my main concern is with the way this device intersects with the main driver, all of which I've commented on at this point. As far as I can tell, we may not really have to interact with the main driver at all, and if so that would be my preference, to not include as many vendor checks in otherwise generic-ish code.

Comment thread drivers/SmartThings/matter-switch/src/init.lua Outdated
Comment thread drivers/SmartThings/matter-switch/src/switch_utils/fields.lua
Comment thread drivers/SmartThings/matter-switch/src/switch_utils/utils.lua Outdated
Comment thread drivers/SmartThings/matter-switch/src/sub_drivers/Hager/init.lua Outdated
Comment thread drivers/SmartThings/matter-switch/src/sub_drivers/Hager/init.lua Outdated
Comment thread drivers/SmartThings/matter-switch/src/switch_utils/device_configuration.lua Outdated
Comment thread drivers/SmartThings/matter-switch/src/sub_drivers/Hager/init.lua Outdated
Comment thread drivers/SmartThings/matter-switch/src/sub_drivers/Hager/init.lua Outdated
Comment thread drivers/SmartThings/matter-switch/src/sub_drivers/Hager/init.lua Outdated
Comment thread drivers/SmartThings/matter-switch/src/sub_drivers/Hager/init.lua Outdated
Comment thread drivers/SmartThings/matter-switch/src/switch_utils/device_configuration.lua Outdated
@JanJakubiszyn JanJakubiszyn force-pushed the Hager_WAASYS_device_support branch 2 times, most recently from eae58ac to ea664a3 Compare May 22, 2026 16:25
Comment thread drivers/SmartThings/matter-switch/profiles/motion-illuminance.yml Outdated
Comment thread drivers/SmartThings/matter-switch/src/sub_drivers/hager/can_handle.lua Outdated
Comment thread drivers/SmartThings/matter-switch/src/sub_drivers/hager/can_handle.lua Outdated
Comment thread drivers/SmartThings/matter-switch/src/switch_utils/fields.lua
Comment thread drivers/SmartThings/matter-switch/src/switch_utils/device_configuration.lua Outdated
Comment thread drivers/SmartThings/matter-switch/src/switch_utils/device_configuration.lua Outdated
Comment thread drivers/SmartThings/matter-switch/src/switch_utils/utils.lua
@JanJakubiszyn JanJakubiszyn force-pushed the Hager_WAASYS_device_support branch 3 times, most recently from 4fa8d9f to d11f453 Compare May 27, 2026 13:56
@JanJakubiszyn JanJakubiszyn requested a review from hcarter-775 May 27, 2026 14:04
@JanJakubiszyn JanJakubiszyn force-pushed the Hager_WAASYS_device_support branch from ef0035d to 139d305 Compare May 28, 2026 09:03

@hcarter-775 hcarter-775 left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are two more minor comments that should be addressed imo, otherwise LGTM!

@hcarter-775

Copy link
Copy Markdown
Contributor

And reminder, make sure to squash your commits before merging. Thanks!

@JanJakubiszyn JanJakubiszyn force-pushed the Hager_WAASYS_device_support branch from 2a5117d to 7a6bee8 Compare June 2, 2026 09:58
@JanJakubiszyn JanJakubiszyn requested a review from hcarter-775 June 2, 2026 10:08
@JanJakubiszyn JanJakubiszyn force-pushed the Hager_WAASYS_device_support branch 6 times, most recently from 912c0c8 to d08ddc4 Compare June 3, 2026 12:38
Comment thread drivers/SmartThings/matter-switch/src/switch_utils/fields.lua Outdated
Comment thread drivers/SmartThings/matter-switch/src/switch_utils/fields.lua Outdated
Comment thread drivers/SmartThings/matter-switch/src/sub_drivers/hager/init.lua Outdated
Comment thread drivers/SmartThings/matter-switch/src/sub_drivers/hager/init.lua Outdated
Comment thread drivers/SmartThings/matter-switch/src/sub_drivers/hager/init.lua Outdated
Comment thread drivers/SmartThings/matter-switch/src/sub_drivers/hager/init.lua Outdated
Comment thread drivers/SmartThings/matter-switch/src/sub_drivers/hager/init.lua Outdated
Comment on lines +336 to +342
local function occupancy_measured_value_handler(driver, device, ib, response)
if ib.data.value ~= nil then
device:emit_event_for_endpoint(ib.endpoint_id, ib.data.value == 0x01 and
capabilities.motionSensor.motion.active() or
capabilities.motionSensor.motion.inactive())
end
end

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we shouldn't need this unique handler, since it is already handled in the main driver?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Its due to the reason that the main driver utilizes ":emit_event" instead of "emit_event_for_endpoint" in the occupancy attr handler so it would emit on the "Parent" device instead of the matter type device which is bridged to it.

I need to evaluate if implementing an emit_event override on the matter device would introduce additional complexity. Will take a look tomorrow.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh sure, in that case then I'd say just change the main driver to use emit_event_on_endpoint. There's no real reason why it can't be that. Then we can remove this override

Comment thread drivers/SmartThings/matter-switch/src/sub_drivers/hager/init.lua Outdated
Comment thread drivers/SmartThings/matter-switch/src/sub_drivers/hager/init.lua Outdated
Comment on lines +131 to +134
local parent = device:get_parent_device()
device:extend_device("send", function(self, message)
return parent:send(message)
end)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if a device is a child, send is already handled by the parent?

@JanJakubiszyn JanJakubiszyn Jun 15, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that's correct, but there is also a matter device which requires this override.

There are following devices handled by my driver:

  • Parent (matter hub).
  • Matter type device (this one is the reason for such override as I keep the communication through the parent device due to the limitation related to the endpoint activation and deactivation).
  • Child devices.

Comment thread drivers/SmartThings/matter-switch/src/sub_drivers/hager/init.lua Outdated
Comment thread drivers/SmartThings/matter-switch/src/sub_drivers/hager/init.lua Outdated
Comment on lines +139 to +143
device.thread:call_with_delay(6, function()
if device:supports_capability(capabilities.switchLevel) then
device:set_field(MAIN_ONOFF_EP, 4, { persist = true })
end
end)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are you hoping to check this after the profile has been altered or something? Wondering due to the delay call.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure if I can recall the reason right now. Tomorrow I will be able to confirm it with the device.

@JanJakubiszyn JanJakubiszyn force-pushed the Hager_WAASYS_device_support branch from d08ddc4 to 3b0e21e Compare June 16, 2026 15:31
@JanJakubiszyn JanJakubiszyn force-pushed the Hager_WAASYS_device_support branch from 3b0e21e to ca6a3d2 Compare June 17, 2026 16:38
Comment thread drivers/SmartThings/matter-switch/src/sub_drivers/hager/init.lua Outdated
Comment on lines +189 to +191
local removed_eps, added_eps = detect_endpoint_changes(device, new_eps)

device:set_field(ACTIVE_EPS, new_eps, { persist = true })

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm wondering, should the endpoint change detection be comparing the device and the new endpoints every time? Because we store the new eps into ACTIVE_EPS, wouldn't this mean the ACTIVE_EPS should be compared against in the future, not the device itself?

@JanJakubiszyn JanJakubiszyn force-pushed the Hager_WAASYS_device_support branch from ca6a3d2 to 316082b Compare June 18, 2026 16:25
Comment on lines +116 to +171
local wc_eps = device:get_endpoints(clusters.WindowCovering.ID)
local oc_eps = device:get_endpoints(clusters.OccupancySensing.ID)
local bt_eps = device:get_endpoints(clusters.Switch.ID)
local lvl_eps = device:get_endpoints(clusters.LevelControl.ID)
local product_id = device.manufacturer_info.product_id
local profile_configured = device:get_field(HAS_PROFILE) or {}

table.sort(wc_eps)
table.sort(oc_eps)
table.sort(lvl_eps)

if device:get_parent_device() ~= nil then
link_matter_device_and_parent(device)
local parent = device:get_parent_device()
device:extend_device("send", function(self, message)
return parent:send(message)
end)

local main_onOff_at_join = device:get_field(MAIN_ONOFF_EP)
if main_onOff_at_join and (product_id == PRODUCT_ID.SWITCH_1G or product_id == PRODUCT_ID.SWITCH_2G) then
device:set_field(MAIN_ONOFF_EP, 3, { persist = true })
if device:supports_capability(capabilities.switchLevel) then
device:set_field(MAIN_ONOFF_EP, 4, { persist = true })
end
end

if profile_configured ~= true then
if #oc_eps > 0 then
device:try_update_metadata({ profile = "motion-illuminance" })
elseif #wc_eps > 0 and product_id == PRODUCT_ID.SWITCH_1G then
device:try_update_metadata({ profile = "window-covering" })
device:set_field(MAIN_WC_EP, wc_eps[1])
elseif #bt_eps == 4 then
device:try_update_metadata({ profile = "4-button" })
elseif #bt_eps == 2 then
device:try_update_metadata({ profile = "2-button" })
elseif #lvl_eps > 0 and product_id == PRODUCT_ID.SWITCH_1G then
device:try_update_metadata({ profile = "light-level" })
end
device:set_field(HAS_PROFILE, true, { persist = true })
end
else
subscribe(device, 2, clusters.Descriptor.ID, clusters.Descriptor.attributes.PartsList.ID)
local matter_device = get_matter_device(device)
device:extend_device("emit_event_for_endpoint", function(self, ep_info, event)
local endpoint_id = type(ep_info) == "number" and ep_info or ep_info.endpoint_id
local child = self:get_child_by_parent_assigned_key(string.format("%d", endpoint_id))

if child then
return child:emit_event(event)
end
if matter_device then
return matter_device:emit_event_for_endpoint(ep_info, event)
end
end)
end

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is this happening in init? Seems like it should be happening in doConfigure (which would automatically have this happen only once), and then subsequent updates would occur in the descriptor cluster handlers

Comment thread drivers/SmartThings/matter-switch/src/sub_drivers/hager/init.lua Outdated
local parent = get_parent(driver, device)
local map = {}
if device.network_type == device_lib.NETWORK_TYPE_MATTER and device.profile.id ~= args.old_st_store.profile.id then
device.thread:call_with_delay(5, function()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why is this a delayed call? Does not appear like that would be necessary

local function info_changed(driver, device, event, args)
local parent = get_parent(driver, device)
local map = {}
if device.network_type == device_lib.NETWORK_TYPE_MATTER and device.profile.id ~= args.old_st_store.profile.id then

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm confused, why would we only update these things for the main device and not any children (EDGE_CHILD)? This appears to just be basic configuration logic, no? Is the idea that these would have been configured elsewhere?

parent:send(clusters.IlluminanceMeasurement.attributes.MeasuredValue:read(parent))
elseif device:supports_capability(capabilities.windowShadeLevel) then
map = { main = 5 }
parent:send(clusters.WindowCovering.attributes.CurrentPositionLiftPercent100ths:read(parent))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I see all these reads, I do not think that is necessary. We should just set up a subscription and the same thing will basically happen. Looking at it more, I also strongly suggest simply using the subscribe logic from the main driver here (where we extend subscribe to use the custom logic in Matter Switch). It is specifically built to ensure subscriptions are created as expected for parent/child devices of varying types, like this.

@JanJakubiszyn JanJakubiszyn Jun 29, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The reason for custom subscription handling in my driver is that after an endpoint is deactivated and/or activated, the device's JSON might not update accurately. It won't show all the available endpoints, making the device.endpoints call miss some of them. The subscription through cluster_base eliminates the possibility of such behaviour by ensuring that all of the dynamic endpoints receive the subscription regardless of the cached device JSON.

I will change those reads to subscriptions.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, that makes sense. I am still wondering though if we even need these at all? Don't you already subscribe to these attributes elsewhere?

@JanJakubiszyn JanJakubiszyn Jun 29, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, these reads were likely added to get initial state faster before subscriptions arrive. Since I'm already subscribing to these clusters elsewhere, they're redundant. I'll verify with the devices and remove them.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ahh, sure that also makes sense. In the main driver we also update the subscription upon an infoChanged event. In that case, I might say we should make these subscribes, and then remove the other place where the subscription is happening then (in the descriptor cluster handlers)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@JanJakubiszyn In your current subscription implementation, one concern I have is whether the subscription will be re-initialized correctly when the hub is restart. This will delete the current subscription cache, and so this will need to be re-populated somehow. For this reason, I think you may want to include the main driver's subscription method. The primary issue with this at the moment is related to the fact that this is a subdriver. For that reason, I might suggest you look at the work I did in this PR and implement that subscription method here in utils.lua. Then, you can add a subscriptions.lua file like in this PR. Then you can just call "device:subscribe()" the same way that it's done in the main driver. You can also use the example in the current Matter Camera driver as an example of what to do instead, though I'm partial to this method in PR.

But basically, the issue now is that when the hub restarts, your subscription will be removed and you currently have no way of re-creating it.

Comment thread drivers/SmartThings/matter-switch/src/sub_drivers/hager/init.lua Outdated
Comment thread drivers/SmartThings/matter-switch/src/sub_drivers/hager/init.lua Outdated
Comment thread drivers/SmartThings/matter-switch/src/sub_drivers/hager/init.lua Outdated
Comment thread drivers/SmartThings/matter-switch/src/sub_drivers/hager/init.lua Outdated
@JanJakubiszyn JanJakubiszyn force-pushed the Hager_WAASYS_device_support branch from 316082b to c56c96c Compare June 29, 2026 20:19
@JanJakubiszyn

JanJakubiszyn commented Jun 29, 2026

Copy link
Copy Markdown
Contributor Author

Hello @hcarter-775 , I've implemented the changes to the code and tested it with the physical devices. Please let me know if this state is acceptable. After that, I will adjust the unit tests.

Comment on lines +109 to +110
device:set_field(fields.profiling_data.POWER_TOPOLOGY, false, { persist = true })
device:set_field(fields.profiling_data.BATTERY_SUPPORT, fields.battery_support.NO_BATTERY, { persist = true })

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since you're no longer using the main driver's logic, you shouldn't need these field sets.

device:set_field(fields.profiling_data.POWER_TOPOLOGY, false, { persist = true })
device:set_field(fields.profiling_data.BATTERY_SUPPORT, fields.battery_support.NO_BATTERY, { persist = true })

if device:get_parent_device() ~= nil then

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since you have:

  if device.network_type ~= device_lib.NETWORK_TYPE_MATTER then
    return
  end

there will never be a parent device at this point. If you're trying to focus in on child devices with this, I might suggest you add an "if device.network_type == device_lib.EDGE_CHILD" check at the top or bottom of init and do this logic.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

then you don't need the "else" either, as you will know you're interacting with the primary matter device.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This guard handles the Matter child device in a parent-child architecture. There is always one parent device (MATTER type, no parent) and one Matter child device (MATTER type, with parent reference). which require a different initialization.

Additional EDGE_CHILD devices are filtered out by the NETWORK_TYPE_MATTER check.

end

local function info_changed(driver, device, event, args)
if device.profile.id ~= args.old_st_store.profile.id or device.network_type == device_lib.NETWORK_TYPE_CHILD then

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
if device.profile.id ~= args.old_st_store.profile.id or device.network_type == device_lib.NETWORK_TYPE_CHILD then
if device.profile.id ~= args.old_st_store.profile.id then

I don't think you should just blanket allow all this to happen if it's a child device. The initial "device.profile.id" should be good enough, since the old profile would be non-existent if this is a new device.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've noticed that child devices don't pass the profile change condition on creation. The component-endpoint mapping is primarily for the matter_device's command routing. Child devices route commands through the parent by default, so the mapping field has no impact on their behavior. Testing confirms this works correctly.

if device.profile.id ~= args.old_st_store.profile.id or device.network_type == device_lib.NETWORK_TYPE_CHILD then
local parent = device:get_parent_device()
local map = {}
device.thread:call_with_delay(2, function()

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you don't need this delay

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

During testing, I observed that removing this delay causes subscriptions to be sent before component mapping completes for 1G and PIR devices. This results in devices remaining in 'connected' state with no initial state reported until the first attribute change occurs.


if ep_id == 3 then
if device.manufacturer_info.product_id == PRODUCT_ID.SWITCH_1G then
matter_device:try_update_metadata({ profile = "2-button" })

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One thing I find strange about this logic is that you are able to call try_update_metadata more than once for the same device. I might try and re-work this logic to ensure that "try_update_metadata" is only ever called once in this handler, to limit calls.

Also, we don't necessarily want to try this call every time we get a descriptor cluster response (like if the device or hub ever go offline, for example).

elseif #lvl_eps > 0 and product_id == PRODUCT_ID.SWITCH_1G then
device:try_update_metadata({ profile = "light-level" })
end
device:set_field(BUTTON_EPS, bt_eps)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
device:set_field(BUTTON_EPS, bt_eps)
device:set_field(BUTTON_EPS, bt_eps, { persist = true })

I think you want this

@JanJakubiszyn JanJakubiszyn force-pushed the Hager_WAASYS_device_support branch from c56c96c to 4252039 Compare July 1, 2026 12:36
@JanJakubiszyn JanJakubiszyn requested a review from hcarter-775 July 1, 2026 12:41
@hcarter-775 hcarter-775 merged commit 4e1ca8b into SmartThingsCommunity:main Jul 1, 2026
15 of 19 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants