Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Aqara Light Switch H2 #1822

Merged
merged 6 commits into from
Jan 22, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
name: light-power-energy-powerConsumption
components:
- id: main
capabilities:
- id: switch
version: 1
- id: powerMeter
version: 1
- id: energyMeter
version: 1
- id: powerConsumptionReport
version: 1
- id: firmwareUpdate
version: 1
- id: refresh
version: 1
categories:
- name: Light
43 changes: 40 additions & 3 deletions drivers/SmartThings/matter-switch/src/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ local COMPONENT_TO_ENDPOINT_MAP = "__component_to_endpoint_map"
-- containing both button endpoints and switch endpoints will use this field
-- rather than COMPONENT_TO_ENDPOINT_MAP.
local COMPONENT_TO_ENDPOINT_MAP_BUTTON = "__component_to_endpoint_map_button"
local ENERGY_MANAGEMENT_ENDPOINT = "__energy_management_endpoint"
local IS_PARENT_CHILD_DEVICE = "__is_parent_child_device"
local COLOR_TEMP_BOUND_RECEIVED = "__colorTemp_bound_received"
local COLOR_TEMP_MIN = "__color_temp_min"
Expand All @@ -65,6 +66,7 @@ local ON_OFF_SWITCH_ID = 0x0103
local ON_OFF_DIMMER_SWITCH_ID = 0x0104
local ON_OFF_COLOR_DIMMER_SWITCH_ID = 0x0105
local GENERIC_SWITCH_ID = 0x000F
local ELECTRICAL_SENSOR_ID = 0x0510
local device_type_profile_map = {
[ON_OFF_LIGHT_DEVICE_TYPE_ID] = "light-binary",
[DIMMABLE_LIGHT_DEVICE_TYPE_ID] = "light-level",
Expand Down Expand Up @@ -147,12 +149,19 @@ local device_type_attribute_map = {
clusters.Switch.events.LongPress,
clusters.Switch.events.ShortRelease,
clusters.Switch.events.MultiPressComplete
},
[ELECTRICAL_SENSOR_ID] = {
clusters.ElectricalPowerMeasurement.attributes.ActivePower,
clusters.ElectricalEnergyMeasurement.attributes.CumulativeEnergyImported,
clusters.ElectricalEnergyMeasurement.attributes.PeriodicEnergyImported
}
}

local child_device_profile_overrides = {
{ vendor_id = 0x1321, product_id = 0x000C, child_profile = "switch-binary" },
{ vendor_id = 0x1321, product_id = 0x000D, child_profile = "switch-binary" },
{ vendor_id = 0x115F, product_id = 0x1008, child_profile = "light-power-energy-powerConsumption" }, -- 2 switch
{ vendor_id = 0x115F, product_id = 0x1009, child_profile = "light-power-energy-powerConsumption" }, -- 4 switch
}

local detect_matter_thing
Expand Down Expand Up @@ -256,6 +265,7 @@ local HELD_THRESHOLD = 1
local STATIC_BUTTON_PROFILE_SUPPORTED = {1, 2, 3, 4, 5, 6, 7, 8}

local DEFERRED_CONFIGURE = "__DEFERRED_CONFIGURE"
local BUTTON_DEVICE_PROFILED = "__button_device_profiled"

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

local HUE_MANUFACTURER_ID = 0x100B
local AQARA_MANUFACTURER_ID = 0x115F

--helper function to create list of multi press values
local function create_multi_press_values_list(size, supportsHeld)
Expand Down Expand Up @@ -413,6 +424,13 @@ local function assign_child_profile(device, child_ep)
for _, fingerprint in ipairs(child_device_profile_overrides) do
if device.manufacturer_info.vendor_id == fingerprint.vendor_id and
device.manufacturer_info.product_id == fingerprint.product_id then
if device.manufacturer_info.vendor_id == AQARA_MANUFACTURER_ID then
if child_ep ~= 1 then
-- To add Electrical Sensor only to the first EDGE_CHILD(light-power-energy-powerConsumption)
-- The profile of the second EDGE_CHILD is determined in the "for" loop below (e.g., light-binary)
break
end
end
return fingerprint.child_profile
end
end
Expand All @@ -436,6 +454,9 @@ local function assign_child_profile(device, child_ep)
end

local function do_configure(driver, device)
if device:get_field(BUTTON_DEVICE_PROFILED) then
return
end
local energy_eps = embedded_cluster_utils.get_endpoints(device, clusters.ElectricalEnergyMeasurement.ID)
local power_eps = embedded_cluster_utils.get_endpoints(device, clusters.ElectricalPowerMeasurement.ID)
local valve_eps = embedded_cluster_utils.get_endpoints(device, clusters.ValveConfigurationAndControl.ID)
Expand Down Expand Up @@ -538,6 +559,10 @@ local function initialize_switch(driver, device)
end

for _, ep in ipairs(switch_eps) do
if _ == 1 then
-- when energy management is defined in the root endpoint(0), replace it with the first switch endpoint and process it.
device:set_field(ENERGY_MANAGEMENT_ENDPOINT, ep)
end
if device:supports_server_cluster(clusters.OnOff.ID, ep) then
num_switch_server_eps = num_switch_server_eps + 1
if ep ~= main_endpoint then -- don't create a child device that maps to the main endpoint
Expand Down Expand Up @@ -579,6 +604,7 @@ local function initialize_switch(driver, device)
end
device:try_update_metadata({profile = profile_name})
device:set_field(DEFERRED_CONFIGURE, true)
device:set_field(BUTTON_DEVICE_PROFILED, true)
elseif #button_eps > 0 then
local battery_support = false
if device.manufacturer_info.vendor_id ~= HUE_MANUFACTURER_ID and
Expand All @@ -599,6 +625,7 @@ local function initialize_switch(driver, device)
if profile_name then
device:try_update_metadata({profile = profile_name})
device:set_field(DEFERRED_CONFIGURE, true)
device:set_field(BUTTON_DEVICE_PROFILED, true)
else
configure_buttons(device)
end
Expand Down Expand Up @@ -680,7 +707,7 @@ local function device_init(driver, device)
end
local main_endpoint = find_default_endpoint(device)
for _, ep in ipairs(device.endpoints) do
if ep.endpoint_id ~= main_endpoint and ep.endpoint_id ~= 0 then
if ep.endpoint_id ~= main_endpoint then
local id = 0
for _, dt in ipairs(ep.device_types) do
id = math.max(id, dt.device_type_id)
Expand Down Expand Up @@ -983,7 +1010,12 @@ local function cumul_energy_imported_handler(driver, device, ib, response)
if ib.data.elements.energy then
local watt_hour_value = ib.data.elements.energy.value / CONVERSION_CONST_MILLIWATT_TO_WATT
device:set_field(TOTAL_IMPORTED_ENERGY, watt_hour_value)
device:emit_event(capabilities.energyMeter.energy({ value = watt_hour_value, unit = "Wh" }))
if ib.endpoint_id ~= 0 then
device:emit_event_for_endpoint(ib.endpoint_id, capabilities.energyMeter.energy({ value = watt_hour_value, unit = "Wh" }))
else
-- when energy management is defined in the root endpoint(0), replace it with the first switch endpoint and process it.
device:emit_event_for_endpoint(device:get_field(ENERGY_MANAGEMENT_ENDPOINT), capabilities.energyMeter.energy({ value = watt_hour_value, unit = "Wh" }))
end
end
end

Expand Down Expand Up @@ -1046,7 +1078,12 @@ end
local function active_power_handler(driver, device, ib, response)
if ib.data.value then
local watt_value = ib.data.value / CONVERSION_CONST_MILLIWATT_TO_WATT
device:emit_event(capabilities.powerMeter.power({ value = watt_value, unit = "W"}))
if ib.endpoint_id ~= 0 then
device:emit_event_for_endpoint(ib.endpoint_id, capabilities.powerMeter.power({ value = watt_value, unit = "W"}))
else
-- when energy management is defined in the root endpoint(0), replace it with the first switch endpoint and process it.
device:emit_event_for_endpoint(device:get_field(ENERGY_MANAGEMENT_ENDPOINT), capabilities.powerMeter.power({ value = watt_value, unit = "W"}))
end
end
end

Expand Down
Loading
Loading