-
Notifications
You must be signed in to change notification settings - Fork 510
Matter Switch: remove ENERGY_MANAGEMENT_ENDPOINT field #2436
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -16,6 +16,7 @@ local capabilities = require "st.capabilities" | |
local clusters = require "st.matter.clusters" | ||
local version = require "version" | ||
local im = require "st.matter.interaction_model" | ||
local device_lib = require "st.device" | ||
|
||
local st_utils = require "st.utils" | ||
local fields = require "utils.switch_fields" | ||
|
@@ -245,17 +246,13 @@ end | |
-- [[ ELECTRICAL POWER MEASUREMENT CLUSTER ATTRIBUTES ]] -- | ||
|
||
function AttributeHandlers.active_power_handler(driver, device, ib, response) | ||
local component = device.profile.components["main"] | ||
if ib.data.value then | ||
local watt_value = ib.data.value / fields.CONVERSION_CONST_MILLIWATT_TO_WATT | ||
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(fields.ENERGY_MANAGEMENT_ENDPOINT), capabilities.powerMeter.power({ value = watt_value, unit = "W"})) | ||
end | ||
if type(device.register_native_capability_attr_handler) == "function" then | ||
device:register_native_capability_attr_handler("powerMeter","power") | ||
end | ||
device:emit_component_event(component, capabilities.powerMeter.power({ value = watt_value, unit = "W"})) | ||
end | ||
if type(device.register_native_capability_attr_handler) == "function" then | ||
device:register_native_capability_attr_handler("powerMeter","power") | ||
end | ||
end | ||
|
||
|
@@ -281,25 +278,22 @@ end | |
|
||
function AttributeHandlers.cumul_energy_imported_handler(driver, device, ib, response) | ||
if ib.data.elements.energy then | ||
local energy_component = device.profile.components["main"] | ||
local watt_hour_value = ib.data.elements.energy.value / fields.CONVERSION_CONST_MILLIWATT_TO_WATT | ||
device:set_field(fields.TOTAL_IMPORTED_ENERGY, watt_hour_value, {persist = true}) | ||
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(fields.ENERGY_MANAGEMENT_ENDPOINT), capabilities.energyMeter.energy({ value = watt_hour_value, unit = "Wh" })) | ||
end | ||
device:emit_component_event(energy_component, capabilities.energyMeter.energy({ value = watt_hour_value, unit = "Wh" })) | ||
switch_utils.report_power_consumption_to_st_energy(device, device:get_field(fields.TOTAL_IMPORTED_ENERGY)) | ||
end | ||
end | ||
|
||
function AttributeHandlers.per_energy_imported_handler(driver, device, ib, response) | ||
if ib.data.elements.energy then | ||
local energy_component = device.profile.components["main"] | ||
local watt_hour_value = ib.data.elements.energy.value / fields.CONVERSION_CONST_MILLIWATT_TO_WATT | ||
local latest_energy_report = device:get_field(fields.TOTAL_IMPORTED_ENERGY) or 0 | ||
local summed_energy_report = latest_energy_report + watt_hour_value | ||
device:set_field(fields.TOTAL_IMPORTED_ENERGY, summed_energy_report, {persist = true}) | ||
device:emit_event(capabilities.energyMeter.energy({ value = summed_energy_report, unit = "Wh" })) | ||
device:emit_component_event(energy_component, capabilities.energyMeter.energy({ value = summed_energy_report, unit = "Wh" })) | ||
switch_utils.report_power_consumption_to_st_energy(device, device:get_field(fields.TOTAL_IMPORTED_ENERGY)) | ||
end | ||
end | ||
|
@@ -309,7 +303,7 @@ function AttributeHandlers.energy_imported_factory(is_cumulative_report) | |
-- workaround: ignore devices supporting Eve's private energy cluster AND the ElectricalEnergyMeasurement cluster | ||
local EVE_MANUFACTURER_ID, EVE_PRIVATE_CLUSTER_ID = 0x130A, 0x130AFC01 | ||
local eve_private_energy_eps = device:get_endpoints(EVE_PRIVATE_CLUSTER_ID) | ||
if device.manufacturer_info.vendor_id == EVE_MANUFACTURER_ID and #eve_private_energy_eps > 0 then | ||
if device.network_type == device_lib.NETWORK_TYPE_MATTER and device.manufacturer_info.vendor_id == EVE_MANUFACTURER_ID and #eve_private_energy_eps > 0 then | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This check may be required if a child device attempts to call this function for two reasons:
Both of these are kinda theoretical, but a unit test caught the issue and rather than updating the unit test, I figured the above reasons justified the inclusion anyway. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is this directly related to removing the There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's semi-related. A child device may not have manufacturer info set, which would cause an issue. So in a unit test, that wasn't set. We also don't set the manufacturer info for child devices in our current logic. |
||
return | ||
end | ||
|
||
|
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we should be hard coding in use of the
main
endpoint, because then this will break on a multi-component device. Do we have any multi-component power devices as far as we know?Why doesnevermind, I see we need to emit on the first switch endpointENERGY_MANAGEMENT_ENDPOINT
need to be saved in the first place when we already know it is on endpoint 0 given theif ib.endpoint_id ~= 0 then
statement?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we are going to hard code a component, why not just hardcode the endpoint for certain device types? If this is limited to a couple Aqara devices (or only 1?) I might perfer just adding special handling for them.
Is having the energy measurement cluster on the root endpoint typical, or is this the only device?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We don't have any profiles where energy isn't on the main component. As I noted in the description, even if that comes up, I still think this is a better handling than the current.
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
At the moment, this only shows up for Aqara because it is the only device that has energy on a child device. However, this will change, and we know these devices will often have the Electrical Sensor device type on multiple EPs. This would normally be where endpoint_to_component would come in. In this case, I've just circumvented that function and defined the relationship explicitly (since we already know it will be like this in all cases for the foreseeable future since plugs and switches are locked into single component profiles).
Perhaps endpoint_to_component could be a better option though, but tbh that is just punting this same logic to a helper function.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is all a matter of opinion, but to me we should avoid hard coding components in our function as a rule since we created the
component_to_endpoint
andendpoint_to_component
apis explicitly for this purpose. I believe the cleanest solution is to handle this mapping in our available APIs, and leave component and endpoint mapping outside of attribute handlers as much as we can. If I am not mistaken, can we not just add the root node to the component to endpoint map and have it map to themain
component, and then continue to leverage that function as expected?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I might prefer specific handling for this device, because according to the spec it isn't supported to have clusters with the Application role implemented on the root node, which would include the Electrical Energy+Power Measurement clusters. So it's unlikely we would see this on another device
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But then again, it's already been implemented generically for a while, so I don't necessarily think we need to change it back to the original handling
Uh oh!
There was an error while loading. Please reload this page.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The issue is more generic than the fact that it's happening on the root node. It will occur for other devices if
From initial testing, I have seen this case show up twice (not counting aqara). It generically can and will occur for generic endpoints, not just root.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For that
find_child
problem you mentioned where child device only use one endpoint, we can also update thefind_child
function specifically for our purposes here so that is could allow for multiple endpoints to map to the child device using a new device key that can have multiple endpoints. You could even update it so that we have a specific override of this function that is only set for devices like this where we need multiple endpoints mapped to a child, and other devices can continue to use the generic one.The find child function is device-scoped and not driver-scoped, so you can make a custom one specifically for devices like this and not affect others in the driverThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
per this discussion, I have updated the logic to leave a single
emit_event_for_endpoint
call in each of these handlers in this PR: #2444It cannot be easily broken out of the above PR anymore, since the new logic is inherently tied to the new PowerTopology handling.