Skip to content

Commit 3b02007

Browse files
committed
integrate per/cum energyMeter handling, only emit powerConsumptionReport for single ep
1 parent 24f06a5 commit 3b02007

File tree

4 files changed

+31
-43
lines changed

4 files changed

+31
-43
lines changed

drivers/SmartThings/matter-switch/src/generic_handlers/attribute_handlers.lua

Lines changed: 24 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -277,7 +277,9 @@ end
277277

278278
-- [[ ELECTRICAL ENERGY MEASUREMENT CLUSTER ATTRIBUTES ]] --
279279

280-
local function report_power_consumption_to_st_energy(device, endpoint_id, latest_total_imported_energy_wh)
280+
local function report_power_consumption_to_st_energy(device, total_imported_energy_wh)
281+
device:set_field(fields.TOTAL_IMPORTED_ENERGY, total_imported_energy_wh, { persist = true })
282+
281283
local current_time = os.time()
282284
local last_time = device:get_field(fields.LAST_IMPORTED_REPORT_TIMESTAMP) or 0
283285

@@ -287,54 +289,45 @@ local function report_power_consumption_to_st_energy(device, endpoint_id, latest
287289
end
288290
device:set_field(fields.LAST_IMPORTED_REPORT_TIMESTAMP, current_time, { persist = true })
289291

290-
local state_device = switch_utils.find_child(device, endpoint_id) or device
292+
local state_device = switch_utils.find_child(device, device:get_field(fields.POWER_CONSUMPTION_REPORT_EP)) or device
291293
local previous_imported_report = state_device:get_latest_state("main", capabilities.powerConsumptionReport.ID,
292-
capabilities.powerConsumptionReport.powerConsumption.NAME, { energy = latest_total_imported_energy_wh })
293-
local energy_delta_wh = math.max(latest_total_imported_energy_wh - previous_imported_report.energy, 0.0) -- Calculate the energy delta between reports
294+
capabilities.powerConsumptionReport.powerConsumption.NAME, { energy = total_imported_energy_wh }) -- default value if nil
295+
local energy_delta_wh = total_imported_energy_wh - previous_imported_report.energy -- Calculate the energy delta between reports
294296

295297
-- Report the energy consumed during the time interval. The unit of these values should be 'Wh'
296298
local epoch_to_iso8601 = function(time) return os.date("!%Y-%m-%dT%H:%M:%SZ", time) end -- Return an ISO-8061 timestamp from UTC
297-
device:emit_event_for_endpoint(endpoint_id, capabilities.powerConsumptionReport.powerConsumption({
299+
device:emit_event_for_endpoint(device:get_field(fields.POWER_CONSUMPTION_REPORT_EP), capabilities.powerConsumptionReport.powerConsumption({
298300
start = epoch_to_iso8601(last_time),
299301
["end"] = epoch_to_iso8601(current_time - 1),
300302
deltaEnergy = energy_delta_wh,
301-
energy = latest_total_imported_energy_wh
303+
energy = total_imported_energy_wh
302304
}))
303305
end
304306

305-
function AttributeHandlers.cumul_energy_imported_handler(driver, device, ib, response)
306-
if ib.data.elements.energy then
307-
local watt_hour_value = ib.data.elements.energy.value / fields.CONVERSION_CONST_MILLIWATT_TO_WATT
308-
device:set_field(fields.TOTAL_IMPORTED_ENERGY, watt_hour_value, {persist = true})
309-
device:emit_event_for_endpoint(ib.endpoint_id, capabilities.energyMeter.energy({ value = watt_hour_value, unit = "Wh" }))
310-
report_power_consumption_to_st_energy(device, ib.endpoint_id, device:get_field(fields.TOTAL_IMPORTED_ENERGY))
311-
end
312-
end
313-
314-
function AttributeHandlers.per_energy_imported_handler(driver, device, ib, response)
315-
if ib.data.elements.energy then
316-
local watt_hour_value = ib.data.elements.energy.value / fields.CONVERSION_CONST_MILLIWATT_TO_WATT
317-
local latest_energy_report = device:get_field(fields.TOTAL_IMPORTED_ENERGY) or 0
318-
local summed_energy_report = latest_energy_report + watt_hour_value
319-
device:set_field(fields.TOTAL_IMPORTED_ENERGY, summed_energy_report, {persist = true})
320-
device:emit_event_for_endpoint(ib.endpoint_id, capabilities.energyMeter.energy({ value = summed_energy_report, unit = "Wh" }))
321-
report_power_consumption_to_st_energy(device, ib.endpoint_id, device:get_field(fields.TOTAL_IMPORTED_ENERGY))
322-
end
323-
end
324-
325-
function AttributeHandlers.energy_imported_factory(is_cumulative_report)
307+
function AttributeHandlers.energy_imported_factory(is_periodic_report)
326308
return function(driver, device, ib, response)
327309
-- workaround: ignore devices supporting Eve's private energy cluster AND the ElectricalEnergyMeasurement cluster
328310
local EVE_MANUFACTURER_ID, EVE_PRIVATE_CLUSTER_ID = 0x130A, 0x130AFC01
329311
local eve_private_energy_eps = device:get_endpoints(EVE_PRIVATE_CLUSTER_ID)
330312
if device.manufacturer_info.vendor_id == EVE_MANUFACTURER_ID and #eve_private_energy_eps > 0 then
331313
return
332314
end
315+
local state_device = switch_utils.find_child(device, ib.endpoint_id) or device
316+
local energy_meter_latest_state = state_device:get_latest_state(
317+
"main", capabilities.energyMeter.ID, capabilities.energyMeter.energy.NAME, 0 -- 0 as the default if state is nil
318+
)
319+
if ib.data.elements.energy then
320+
local energy_imported_wh = ib.data.elements.energy.value / fields.CONVERSION_CONST_MILLIWATT_TO_WATT
321+
if is_periodic_report then
322+
-- handle this report only if cumulative reports are not supported
323+
if device:get_field(fields.CUMULATIVE_REPORTS_SUPPORTED) then return end
324+
energy_imported_wh = energy_imported_wh + energy_meter_latest_state
325+
end
326+
device:emit_event_for_endpoint(ib.endpoint_id, capabilities.energyMeter.energy({ value = energy_imported_wh, unit = "Wh" }))
333327

334-
if is_cumulative_report then
335-
AttributeHandlers.cumul_energy_imported_handler(driver, device, ib, response)
336-
elseif device:get_field(fields.CUMULATIVE_REPORTS_NOT_SUPPORTED) then
337-
AttributeHandlers.per_energy_imported_handler(driver, device, ib, response)
328+
local energy_wh_delta = energy_imported_wh - energy_meter_latest_state
329+
local device_total_imported_energy_wh = (device:get_field(fields.TOTAL_IMPORTED_ENERGY) or 0) + energy_wh_delta
330+
report_power_consumption_to_st_energy(device, device_total_imported_energy_wh)
338331
end
339332
end
340333
end

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

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ function SwitchLifecycleHandlers.device_init(driver, device)
121121
clusters.ElectricalEnergyMeasurement.ID,
122122
{feature_bitmap = clusters.ElectricalEnergyMeasurement.types.Feature.CUMULATIVE_ENERGY}
123123
)
124-
if #cumulative_energy_eps == 0 then device:set_field(fields.CUMULATIVE_REPORTS_NOT_SUPPORTED, true, {persist = false}) end
124+
if #cumulative_energy_eps > 0 then device:set_field(fields.CUMULATIVE_REPORTS_SUPPORTED, true, {persist = false}) end
125125
end
126126
end
127127
end
@@ -149,8 +149,8 @@ local matter_driver_template = {
149149
[clusters.ColorControl.attributes.CurrentY.ID] = attribute_handlers.current_y_handler,
150150
},
151151
[clusters.ElectricalEnergyMeasurement.ID] = {
152-
[clusters.ElectricalEnergyMeasurement.attributes.CumulativeEnergyImported.ID] = attribute_handlers.energy_imported_factory(true),
153-
[clusters.ElectricalEnergyMeasurement.attributes.PeriodicEnergyImported.ID] = attribute_handlers.energy_imported_factory(false),
152+
[clusters.ElectricalEnergyMeasurement.attributes.CumulativeEnergyImported.ID] = attribute_handlers.energy_imported_factory(false),
153+
[clusters.ElectricalEnergyMeasurement.attributes.PeriodicEnergyImported.ID] = attribute_handlers.energy_imported_factory(true),
154154
},
155155
[clusters.ElectricalPowerMeasurement.ID] = {
156156
[clusters.ElectricalPowerMeasurement.attributes.ActivePower.ID] = attribute_handlers.active_power_handler,

drivers/SmartThings/matter-switch/src/utils/switch_fields.lua

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -76,10 +76,6 @@ SwitchFields.device_type_profile_map = {
7676
[SwitchFields.MOUNTED_DIMMABLE_LOAD_CONTROL_ID] = "switch-level",
7777
}
7878

79-
80-
SwitchFields.CONVERSION_CONST_MILLIWATT_TO_WATT = 1000 -- A milliwatt is 1/1000th of a watt
81-
82-
8379
-- COMPONENT_TO_ENDPOINT_MAP is here to preserve the endpoint mapping for
8480
-- devices that were joined to this driver as MCD devices before the transition
8581
-- to join switch devices as parent-child. This value will exist in the device
@@ -102,10 +98,6 @@ SwitchFields.updated_fields = {
10298
{ current_field_name = "__energy_management_endpoint", updated_field_name = nil }
10399
}
104100

105-
SwitchFields.HUE_SAT_COLOR_MODE = clusters.ColorControl.types.ColorMode.CURRENT_HUE_AND_CURRENT_SATURATION
106-
SwitchFields.X_Y_COLOR_MODE = clusters.ColorControl.types.ColorMode.CURRENTX_AND_CURRENTY
107-
108-
109101
SwitchFields.SONOFF_MANUFACTURER_ID = 0x1321
110102
SwitchFields.AQARA_MANUFACTURER_ID = 0x115F
111103
SwitchFields.AQARA_CLIMATE_SENSOR_W100_ID = 0x2004
@@ -121,14 +113,16 @@ SwitchFields.device_overrides_per_vendor = {
121113
}
122114
}
123115

116+
SwitchFields.CONVERSION_CONST_MILLIWATT_TO_WATT = 1000 -- A milliwatt is 1/1000th of a watt
117+
SwitchFields.POWER_CONSUMPTION_REPORT_EP = "__POWER_CONSUMPTION_REPORT_EP"
124118
SwitchFields.SET_TOPOLOGY_EPS = "__SET_TOPOLOGY_EPS"
125119
SwitchFields.PRIMARY_CHILD_EP = "__PRIMARY_CHILD_EP"
126120
SwitchFields.ELECTRICAL_TAGS = "__ELECTRICAL_TAGS"
127121
SwitchFields.profiling_data = {
128122
POWER_TOPOLOGY = "__POWER_TOPOLOGY",
129123
}
130124

131-
SwitchFields.CUMULATIVE_REPORTS_NOT_SUPPORTED = "__cumulative_reports_not_supported"
125+
SwitchFields.CUMULATIVE_REPORTS_SUPPORTED = "__cumulative_reports_supported"
132126
SwitchFields.TOTAL_IMPORTED_ENERGY = "__total_imported_energy"
133127
SwitchFields.LAST_IMPORTED_REPORT_TIMESTAMP = "__last_imported_report_timestamp"
134128
SwitchFields.MINIMUM_ST_ENERGY_REPORT_INTERVAL = (15 * 60) -- 15 minutes, reported in seconds

drivers/SmartThings/matter-switch/src/utils/switch_utils.lua

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,7 @@ function utils.collect_and_set_electrical_sensor_info(device)
221221
end
222222

223223
local electrical_ep = electrical_sensor_eps[1] or {}
224+
device:set_field(fields.POWER_CONSUMPTION_REPORT_EP, electrical_ep.endpoint_id, { persist = true })
224225
if electrical_ep[clusters.PowerTopology.ID] == clusters.PowerTopology.types.Feature.SET_TOPOLOGY then
225226
device:set_field(fields.SET_TOPOLOGY_EPS, electrical_sensor_eps) -- assume any other stored EPs also have a SET topology
226227
device:send(available_eps_req)

0 commit comments

Comments
 (0)