From 093122949dad2a57b4cf6157d6c36cb0f655d745 Mon Sep 17 00:00:00 2001 From: Harrison Carter Date: Tue, 27 May 2025 11:15:20 -0500 Subject: [PATCH 1/4] add new subscribed attribute to smoke co alarm --- drivers/SmartThings/matter-sensor/src/smoke-co-alarm/init.lua | 3 +++ 1 file changed, 3 insertions(+) diff --git a/drivers/SmartThings/matter-sensor/src/smoke-co-alarm/init.lua b/drivers/SmartThings/matter-sensor/src/smoke-co-alarm/init.lua index c5fe00a4be..c78d051cc3 100644 --- a/drivers/SmartThings/matter-sensor/src/smoke-co-alarm/init.lua +++ b/drivers/SmartThings/matter-sensor/src/smoke-co-alarm/init.lua @@ -307,6 +307,9 @@ local matter_smoke_co_alarm_handler = { clusters.CarbonMonoxideConcentrationMeasurement.attributes.MeasuredValue, clusters.CarbonMonoxideConcentrationMeasurement.attributes.MeasurementUnit, }, + [capabilities.carbonMonoxideHealthConcern.ID] = { + clusters.CarbonMonoxideConcentrationMeasurement.attributes.LevelValue, + }, [capabilities.batteryLevel.ID] = { clusters.PowerSource.attributes.BatChargeLevel, }, From 17d43b4bd0f080a4d0023836c7a3b3ec003500f9 Mon Sep 17 00:00:00 2001 From: Harrison Carter Date: Tue, 27 May 2025 11:27:10 -0500 Subject: [PATCH 2/4] add handler for co health concern --- .../matter-sensor/src/smoke-co-alarm/init.lua | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/drivers/SmartThings/matter-sensor/src/smoke-co-alarm/init.lua b/drivers/SmartThings/matter-sensor/src/smoke-co-alarm/init.lua index c78d051cc3..395b1f5716 100644 --- a/drivers/SmartThings/matter-sensor/src/smoke-co-alarm/init.lua +++ b/drivers/SmartThings/matter-sensor/src/smoke-co-alarm/init.lua @@ -247,6 +247,18 @@ local function handle_battery_percent_remaining(driver, device, ib, response) end end +local level_strings = { + [clusters.CarbonMonoxideConcentrationMeasurement.types.LevelValueEnum.UNKNOWN] = "unknown", + [clusters.CarbonMonoxideConcentrationMeasurement.types.LevelValueEnum.LOW] = "good", + [clusters.CarbonMonoxideConcentrationMeasurement.types.LevelValueEnum.MEDIUM] = "moderate", + [clusters.CarbonMonoxideConcentrationMeasurement.types.LevelValueEnum.HIGH] = "unhealthy", + [clusters.CarbonMonoxideConcentrationMeasurement.types.LevelValueEnum.CRITICAL] = "hazardous", +} + +local function carbon_monoxide_level_handler(driver, device, ib, response) + device:emit_event_for_endpoint(ib.endpoint_id, level_strings[ib.data.value]) +end + local function do_configure(driver, device) local battery_feature_eps = device:get_endpoints(clusters.PowerSource.ID, {feature_bitmap = clusters.PowerSource.types.PowerSourceFeature.BATTERY}) if #battery_feature_eps > 0 then @@ -275,6 +287,7 @@ local matter_smoke_co_alarm_handler = { [clusters.CarbonMonoxideConcentrationMeasurement.ID] = { [clusters.CarbonMonoxideConcentrationMeasurement.attributes.MeasuredValue.ID] = carbon_monoxide_attr_handler, [clusters.CarbonMonoxideConcentrationMeasurement.attributes.MeasurementUnit.ID] = carbon_monoxide_unit_attr_handler, + [clusters.CarbonMonoxideConcentrationMeasurement.attributes.LevelValue.ID] = carbon_monoxide_level_handler, }, [clusters.PowerSource.ID] = { [clusters.PowerSource.attributes.AttributeList.ID] = power_source_attribute_list_handler, From 849ee0671a727cfa402c577e2cc03a6a568243d2 Mon Sep 17 00:00:00 2001 From: Harrison Carter Date: Tue, 27 May 2025 11:37:29 -0500 Subject: [PATCH 3/4] add new smoke alarm profile --- .../smoke-co-comeas-colevel-battery.yml | 22 +++++++++++++++++++ .../matter-sensor/src/smoke-co-alarm/init.lua | 1 + 2 files changed, 23 insertions(+) create mode 100644 drivers/SmartThings/matter-sensor/profiles/smoke-co-comeas-colevel-battery.yml diff --git a/drivers/SmartThings/matter-sensor/profiles/smoke-co-comeas-colevel-battery.yml b/drivers/SmartThings/matter-sensor/profiles/smoke-co-comeas-colevel-battery.yml new file mode 100644 index 0000000000..f4d42a008a --- /dev/null +++ b/drivers/SmartThings/matter-sensor/profiles/smoke-co-comeas-colevel-battery.yml @@ -0,0 +1,22 @@ +name: smoke-co-comeas-colevel-battery +components: +- id: main + capabilities: + - id: smokeDetector + version: 1 + - id: carbonMonoxideDetector + version: 1 + - id: carbonMonoxideMeasurement + version: 1 + - id: carbonMonoxideHealthConcern + version: 1 + - id: battery + version: 1 + - id: hardwareFault + version: 1 + - id: firmwareUpdate + version: 1 + - id: refresh + version: 1 + categories: + - name: SmokeDetector \ No newline at end of file diff --git a/drivers/SmartThings/matter-sensor/src/smoke-co-alarm/init.lua b/drivers/SmartThings/matter-sensor/src/smoke-co-alarm/init.lua index 395b1f5716..07074c5ebf 100644 --- a/drivers/SmartThings/matter-sensor/src/smoke-co-alarm/init.lua +++ b/drivers/SmartThings/matter-sensor/src/smoke-co-alarm/init.lua @@ -66,6 +66,7 @@ local supported_profiles = "smoke-battery", "smoke-co-comeas", "smoke-co-comeas-battery", + "smoke-co-comeas-colevel-battery", "smoke-co-temp-humidity-comeas", "smoke-co-temp-humidity-comeas-battery" } From dae63f10aa1a70c0d3880b724aad8e5d9a2f5d22 Mon Sep 17 00:00:00 2001 From: Harrison Carter Date: Wed, 28 May 2025 11:04:49 -0500 Subject: [PATCH 4/4] fix level handler, include test --- .../matter-sensor/src/smoke-co-alarm/init.lua | 2 +- .../src/test/test_matter_smoke_co_alarm.lua | 103 ++++++++++++++++++ 2 files changed, 104 insertions(+), 1 deletion(-) diff --git a/drivers/SmartThings/matter-sensor/src/smoke-co-alarm/init.lua b/drivers/SmartThings/matter-sensor/src/smoke-co-alarm/init.lua index 07074c5ebf..7c40fd282c 100644 --- a/drivers/SmartThings/matter-sensor/src/smoke-co-alarm/init.lua +++ b/drivers/SmartThings/matter-sensor/src/smoke-co-alarm/init.lua @@ -257,7 +257,7 @@ local level_strings = { } local function carbon_monoxide_level_handler(driver, device, ib, response) - device:emit_event_for_endpoint(ib.endpoint_id, level_strings[ib.data.value]) + device:emit_event_for_endpoint(ib.endpoint_id, capabilities.carbonMonoxideHealthConcern.carbonMonoxideHealthConcern(level_strings[ib.data.value])) end local function do_configure(driver, device) diff --git a/drivers/SmartThings/matter-sensor/src/test/test_matter_smoke_co_alarm.lua b/drivers/SmartThings/matter-sensor/src/test/test_matter_smoke_co_alarm.lua index f5029147d7..03ce8068e9 100644 --- a/drivers/SmartThings/matter-sensor/src/test/test_matter_smoke_co_alarm.lua +++ b/drivers/SmartThings/matter-sensor/src/test/test_matter_smoke_co_alarm.lua @@ -57,6 +57,36 @@ local mock_device = test.mock_device.build_test_matter_device({ } }) +local mock_device_colevel = test.mock_device.build_test_matter_device({ + profile = t_utils.get_profile_definition("co-comeas-colevel-battery.yml"), + manufacturer_info = { + vendor_id = 0x0000, + product_id = 0x0000, + }, + endpoints = { + { + endpoint_id = 0, + clusters = { + {cluster_id = clusters.Basic.ID, cluster_type = "SERVER"}, + }, + device_types = { + {device_type_id = 0x0016, device_type_revision = 1} -- RootNode + } + }, + { + endpoint_id = 1, + clusters = { + {cluster_id = clusters.SmokeCoAlarm.ID, cluster_type = "SERVER", feature_map = clusters.SmokeCoAlarm.types.Feature.CO_ALARM}, + {cluster_id = clusters.CarbonMonoxideConcentrationMeasurement.ID, cluster_type = "SERVER", feature_map = clusters.CarbonMonoxideConcentrationMeasurement.types.Feature.NUMERIC_MEASUREMENT | clusters.CarbonMonoxideConcentrationMeasurement.types.Feature.LEVEL_INDICATION}, + {cluster_id = clusters.PowerSource.ID, cluster_type = "SERVER", feature_map = clusters.PowerSource.types.PowerSourceFeature.BATTERY}, + }, + device_types = { + {device_type_id = 0x0076, device_type_revision = 1} -- Smoke CO Alarm + } + } + } +}) + local cluster_subscribe_list = { clusters.SmokeCoAlarm.attributes.SmokeState, clusters.SmokeCoAlarm.attributes.TestInProgress, @@ -87,6 +117,27 @@ local function test_init() test.mock_device.add_test_device(mock_device) end +local cluster_subscribe_list_colevel = { + clusters.SmokeCoAlarm.attributes.TestInProgress, + clusters.SmokeCoAlarm.attributes.COState, + clusters.SmokeCoAlarm.attributes.HardwareFaultAlert, + clusters.CarbonMonoxideConcentrationMeasurement.attributes.MeasurementUnit, + clusters.CarbonMonoxideConcentrationMeasurement.attributes.LevelValue, + clusters.CarbonMonoxideConcentrationMeasurement.attributes.MeasuredValue, + clusters.PowerSource.attributes.BatPercentRemaining, +} + +local function test_init_colevel() + local subscribe_request = cluster_subscribe_list_colevel[1]:subscribe(mock_device_colevel) + for i, cluster in ipairs(cluster_subscribe_list_colevel) do + if i > 1 then + subscribe_request:merge(cluster:subscribe(mock_device_colevel)) + end + end + test.socket.matter:__expect_send({mock_device_colevel.id, subscribe_request}) + test.mock_device.add_test_device(mock_device_colevel) +end + test.set_test_init_function(test_init) test.register_message_test( @@ -134,6 +185,58 @@ test.register_message_test( } ) +test.register_coroutine_test( + "Level value reports should generate events", + function() + test.socket.matter:__queue_receive({ + mock_device_colevel.id, + clusters.CarbonMonoxideConcentrationMeasurement.attributes.LevelValue:build_test_report_data( + mock_device_colevel, 1, clusters.CarbonMonoxideConcentrationMeasurement.types.LevelValueEnum.UNKNOWN + ) + }) + test.socket.capability:__expect_send( + mock_device_colevel:generate_test_message("main", capabilities.carbonMonoxideHealthConcern.carbonMonoxideHealthConcern.unknown()) + ) + test.socket.matter:__queue_receive({ + mock_device_colevel.id, + clusters.CarbonMonoxideConcentrationMeasurement.attributes.LevelValue:build_test_report_data( + mock_device_colevel, 1, clusters.CarbonMonoxideConcentrationMeasurement.types.LevelValueEnum.LOW + ) + }) + test.socket.capability:__expect_send( + mock_device_colevel:generate_test_message("main", capabilities.carbonMonoxideHealthConcern.carbonMonoxideHealthConcern.good()) + ) + test.socket.matter:__queue_receive({ + mock_device_colevel.id, + clusters.CarbonMonoxideConcentrationMeasurement.attributes.LevelValue:build_test_report_data( + mock_device_colevel, 1, clusters.CarbonMonoxideConcentrationMeasurement.types.LevelValueEnum.MEDIUM + ) + }) + test.socket.capability:__expect_send( + mock_device_colevel:generate_test_message("main", capabilities.carbonMonoxideHealthConcern.carbonMonoxideHealthConcern.moderate()) + ) + test.socket.matter:__queue_receive({ + mock_device_colevel.id, + clusters.CarbonMonoxideConcentrationMeasurement.attributes.LevelValue:build_test_report_data( + mock_device_colevel, 1, clusters.CarbonMonoxideConcentrationMeasurement.types.LevelValueEnum.HIGH + ) + }) + test.socket.capability:__expect_send( + mock_device_colevel:generate_test_message("main", capabilities.carbonMonoxideHealthConcern.carbonMonoxideHealthConcern.unhealthy()) + ) + test.socket.matter:__queue_receive({ + mock_device_colevel.id, + clusters.CarbonMonoxideConcentrationMeasurement.attributes.LevelValue:build_test_report_data( + mock_device_colevel, 1, clusters.CarbonMonoxideConcentrationMeasurement.types.LevelValueEnum.CRITICAL + ) + }) + test.socket.capability:__expect_send( + mock_device_colevel:generate_test_message("main", capabilities.carbonMonoxideHealthConcern.carbonMonoxideHealthConcern.hazardous()) + ) + end, + { test_init = test_init_colevel } +) + test.register_message_test( "Test CO state handler", {