Skip to content

Commit a8aa597

Browse files
authored
Add Aqara Light Switch H2 (#1822)
This is a new Matter Device with four physical switches. - Two of each of the four switchs have On/Off Light(0x0100) and Generic Switch(0x000F) device types. - The other two switches have a Generic Switch(0x000F) device type. - The root node has Electrical Sensor(0x0510) utility device type.
1 parent 78ed039 commit a8aa597

File tree

3 files changed

+391
-3
lines changed

3 files changed

+391
-3
lines changed
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
name: light-power-energy-powerConsumption
2+
components:
3+
- id: main
4+
capabilities:
5+
- id: switch
6+
version: 1
7+
- id: powerMeter
8+
version: 1
9+
- id: energyMeter
10+
version: 1
11+
- id: powerConsumptionReport
12+
version: 1
13+
- id: firmwareUpdate
14+
version: 1
15+
- id: refresh
16+
version: 1
17+
categories:
18+
- name: Light

drivers/SmartThings/matter-switch/src/init.lua

Lines changed: 40 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ local COMPONENT_TO_ENDPOINT_MAP = "__component_to_endpoint_map"
4747
-- containing both button endpoints and switch endpoints will use this field
4848
-- rather than COMPONENT_TO_ENDPOINT_MAP.
4949
local COMPONENT_TO_ENDPOINT_MAP_BUTTON = "__component_to_endpoint_map_button"
50+
local ENERGY_MANAGEMENT_ENDPOINT = "__energy_management_endpoint"
5051
local IS_PARENT_CHILD_DEVICE = "__is_parent_child_device"
5152
local COLOR_TEMP_BOUND_RECEIVED_KELVIN = "__colorTemp_bound_received_kelvin"
5253
local COLOR_TEMP_BOUND_RECEIVED_MIRED = "__colorTemp_bound_received_mired"
@@ -66,6 +67,7 @@ local ON_OFF_SWITCH_ID = 0x0103
6667
local ON_OFF_DIMMER_SWITCH_ID = 0x0104
6768
local ON_OFF_COLOR_DIMMER_SWITCH_ID = 0x0105
6869
local GENERIC_SWITCH_ID = 0x000F
70+
local ELECTRICAL_SENSOR_ID = 0x0510
6971
local device_type_profile_map = {
7072
[ON_OFF_LIGHT_DEVICE_TYPE_ID] = "light-binary",
7173
[DIMMABLE_LIGHT_DEVICE_TYPE_ID] = "light-level",
@@ -148,12 +150,19 @@ local device_type_attribute_map = {
148150
clusters.Switch.events.LongPress,
149151
clusters.Switch.events.ShortRelease,
150152
clusters.Switch.events.MultiPressComplete
153+
},
154+
[ELECTRICAL_SENSOR_ID] = {
155+
clusters.ElectricalPowerMeasurement.attributes.ActivePower,
156+
clusters.ElectricalEnergyMeasurement.attributes.CumulativeEnergyImported,
157+
clusters.ElectricalEnergyMeasurement.attributes.PeriodicEnergyImported
151158
}
152159
}
153160

154161
local child_device_profile_overrides = {
155162
{ vendor_id = 0x1321, product_id = 0x000C, child_profile = "switch-binary" },
156163
{ vendor_id = 0x1321, product_id = 0x000D, child_profile = "switch-binary" },
164+
{ vendor_id = 0x115F, product_id = 0x1008, child_profile = "light-power-energy-powerConsumption" }, -- 2 switch
165+
{ vendor_id = 0x115F, product_id = 0x1009, child_profile = "light-power-energy-powerConsumption" }, -- 4 switch
157166
}
158167

159168
local detect_matter_thing
@@ -257,6 +266,7 @@ local HELD_THRESHOLD = 1
257266
local STATIC_BUTTON_PROFILE_SUPPORTED = {1, 2, 3, 4, 5, 6, 7, 8}
258267

259268
local DEFERRED_CONFIGURE = "__DEFERRED_CONFIGURE"
269+
local BUTTON_DEVICE_PROFILED = "__button_device_profiled"
260270

261271
-- Some switches will send a MultiPressComplete event as part of a long press sequence. Normally the driver will create a
262272
-- button capability event on receipt of MultiPressComplete, but in this case that would result in an extra event because
@@ -271,6 +281,7 @@ local SUPPORTS_MULTI_PRESS = "__multi_button" -- for MSM devices (MomentarySwitc
271281
local INITIAL_PRESS_ONLY = "__initial_press_only" -- for devices that support MS (MomentarySwitch), but not MSR (MomentarySwitchRelease)
272282

273283
local HUE_MANUFACTURER_ID = 0x100B
284+
local AQARA_MANUFACTURER_ID = 0x115F
274285

275286
--helper function to create list of multi press values
276287
local function create_multi_press_values_list(size, supportsHeld)
@@ -414,6 +425,13 @@ local function assign_child_profile(device, child_ep)
414425
for _, fingerprint in ipairs(child_device_profile_overrides) do
415426
if device.manufacturer_info.vendor_id == fingerprint.vendor_id and
416427
device.manufacturer_info.product_id == fingerprint.product_id then
428+
if device.manufacturer_info.vendor_id == AQARA_MANUFACTURER_ID then
429+
if child_ep ~= 1 then
430+
-- To add Electrical Sensor only to the first EDGE_CHILD(light-power-energy-powerConsumption)
431+
-- The profile of the second EDGE_CHILD is determined in the "for" loop below (e.g., light-binary)
432+
break
433+
end
434+
end
417435
return fingerprint.child_profile
418436
end
419437
end
@@ -437,6 +455,9 @@ local function assign_child_profile(device, child_ep)
437455
end
438456

439457
local function do_configure(driver, device)
458+
if device:get_field(BUTTON_DEVICE_PROFILED) then
459+
return
460+
end
440461
local energy_eps = embedded_cluster_utils.get_endpoints(device, clusters.ElectricalEnergyMeasurement.ID)
441462
local power_eps = embedded_cluster_utils.get_endpoints(device, clusters.ElectricalPowerMeasurement.ID)
442463
local valve_eps = embedded_cluster_utils.get_endpoints(device, clusters.ValveConfigurationAndControl.ID)
@@ -539,6 +560,10 @@ local function initialize_switch(driver, device)
539560
end
540561

541562
for _, ep in ipairs(switch_eps) do
563+
if _ == 1 then
564+
-- when energy management is defined in the root endpoint(0), replace it with the first switch endpoint and process it.
565+
device:set_field(ENERGY_MANAGEMENT_ENDPOINT, ep)
566+
end
542567
if device:supports_server_cluster(clusters.OnOff.ID, ep) then
543568
num_switch_server_eps = num_switch_server_eps + 1
544569
if ep ~= main_endpoint then -- don't create a child device that maps to the main endpoint
@@ -580,6 +605,7 @@ local function initialize_switch(driver, device)
580605
end
581606
device:try_update_metadata({profile = profile_name})
582607
device:set_field(DEFERRED_CONFIGURE, true)
608+
device:set_field(BUTTON_DEVICE_PROFILED, true)
583609
elseif #button_eps > 0 then
584610
local battery_support = false
585611
if device.manufacturer_info.vendor_id ~= HUE_MANUFACTURER_ID and
@@ -600,6 +626,7 @@ local function initialize_switch(driver, device)
600626
if profile_name then
601627
device:try_update_metadata({profile = profile_name})
602628
device:set_field(DEFERRED_CONFIGURE, true)
629+
device:set_field(BUTTON_DEVICE_PROFILED, true)
603630
else
604631
configure_buttons(device)
605632
end
@@ -681,7 +708,7 @@ local function device_init(driver, device)
681708
end
682709
local main_endpoint = find_default_endpoint(device)
683710
for _, ep in ipairs(device.endpoints) do
684-
if ep.endpoint_id ~= main_endpoint and ep.endpoint_id ~= 0 then
711+
if ep.endpoint_id ~= main_endpoint then
685712
local id = 0
686713
for _, dt in ipairs(ep.device_types) do
687714
id = math.max(id, dt.device_type_id)
@@ -1009,7 +1036,12 @@ local function cumul_energy_imported_handler(driver, device, ib, response)
10091036
if ib.data.elements.energy then
10101037
local watt_hour_value = ib.data.elements.energy.value / CONVERSION_CONST_MILLIWATT_TO_WATT
10111038
device:set_field(TOTAL_IMPORTED_ENERGY, watt_hour_value)
1012-
device:emit_event(capabilities.energyMeter.energy({ value = watt_hour_value, unit = "Wh" }))
1039+
if ib.endpoint_id ~= 0 then
1040+
device:emit_event_for_endpoint(ib.endpoint_id, capabilities.energyMeter.energy({ value = watt_hour_value, unit = "Wh" }))
1041+
else
1042+
-- when energy management is defined in the root endpoint(0), replace it with the first switch endpoint and process it.
1043+
device:emit_event_for_endpoint(device:get_field(ENERGY_MANAGEMENT_ENDPOINT), capabilities.energyMeter.energy({ value = watt_hour_value, unit = "Wh" }))
1044+
end
10131045
end
10141046
end
10151047

@@ -1072,7 +1104,12 @@ end
10721104
local function active_power_handler(driver, device, ib, response)
10731105
if ib.data.value then
10741106
local watt_value = ib.data.value / CONVERSION_CONST_MILLIWATT_TO_WATT
1075-
device:emit_event(capabilities.powerMeter.power({ value = watt_value, unit = "W"}))
1107+
if ib.endpoint_id ~= 0 then
1108+
device:emit_event_for_endpoint(ib.endpoint_id, capabilities.powerMeter.power({ value = watt_value, unit = "W"}))
1109+
else
1110+
-- when energy management is defined in the root endpoint(0), replace it with the first switch endpoint and process it.
1111+
device:emit_event_for_endpoint(device:get_field(ENERGY_MANAGEMENT_ENDPOINT), capabilities.powerMeter.power({ value = watt_value, unit = "W"}))
1112+
end
10761113
end
10771114
end
10781115

0 commit comments

Comments
 (0)