Skip to content

Commit cb3da21

Browse files
committed
Add reconfiguration for zigbee power meter to reduce reporting
This will check devices on init to see if they support the clusters for power reporting and if so schedules a 5 minute timer to check all devices in the driver, and attempt to configure them to a lower reporting frequency. It will then mark the configuration version on the device to avoid it happening again.
1 parent 634161b commit cb3da21

26 files changed

Lines changed: 360 additions & 14 deletions

File tree

drivers/SmartThings/zigbee-switch/src/aqara/multi-switch/init.lua

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ local device_lib = require "st.device"
22
local capabilities = require "st.capabilities"
33
local cluster_base = require "st.zigbee.cluster_base"
44
local data_types = require "st.zigbee.data_types"
5+
local configurations = require "configurations"
56

67
local PRIVATE_CLUSTER_ID = 0xFCC0
78
local PRIVATE_ATTRIBUTE_ID = 0x0009
@@ -100,7 +101,7 @@ end
100101
local aqara_multi_switch_handler = {
101102
NAME = "Aqara Multi Switch Handler",
102103
lifecycle_handlers = {
103-
init = device_init,
104+
init = configurations.power_reconfig_wrapper(device_init),
104105
added = device_added
105106
},
106107
can_handle = is_aqara_products

drivers/SmartThings/zigbee-switch/src/configurations.lua

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,15 @@
1414

1515
local clusters = require "st.zigbee.zcl.clusters"
1616
local constants = require "st.zigbee.constants"
17+
local capabilities = require "st.capabilities"
18+
local device_def = require "st.device"
1719

1820
local ColorControl = clusters.ColorControl
1921
local IASZone = clusters.IASZone
22+
local Status = require "st.zigbee.generated.types.ZclStatus"
23+
24+
local CONFIGURATION_VERSION_KEY = "_configuration_version"
25+
local CONFIGURATION_ATTEMPTED = "_reconfiguration_attempted"
2026

2127
local devices = {
2228
IKEA_RGB_BULB = {
@@ -60,8 +66,94 @@ local devices = {
6066
}
6167
}
6268

69+
6370
local configurations = {}
6471

72+
local active_power_configuration = {
73+
cluster = clusters.ElectricalMeasurement.ID,
74+
attribute = clusters.ElectricalMeasurement.attributes.ActivePower.ID,
75+
minimum_interval = 5,
76+
maximum_interval = 3600,
77+
data_type = clusters.ElectricalMeasurement.attributes.ActivePower.base_type,
78+
reportable_change = 5
79+
}
80+
81+
local instantaneous_demand_configuration = {
82+
cluster = clusters.SimpleMetering.ID,
83+
attribute = clusters.SimpleMetering.attributes.InstantaneousDemand.ID,
84+
minimum_interval = 5,
85+
maximum_interval = 3600,
86+
data_type = clusters.SimpleMetering.attributes.InstantaneousDemand.base_type,
87+
reportable_change = 5
88+
}
89+
90+
configurations.check_and_reconfig_devices = function(driver)
91+
for device_id, device in pairs(driver.device_cache) do
92+
local config_version = device:get_field(CONFIGURATION_VERSION_KEY)
93+
if config_version == nil or config_version < driver.current_config_version then
94+
if device:supports_capability(capabilities.powerMeter) then
95+
if device:supports_server_cluster(clusters.ElectricalMeasurement.ID) then
96+
-- Increase minimum reporting interval to 5 seconds
97+
device:send(clusters.ElectricalMeasurement.attributes.ActivePower:configure_reporting(device, 5, 600, 5))
98+
device:add_configured_attribute(active_power_configuration)
99+
end
100+
if device:supports_server_cluster(clusters.SimpleMetering.ID) then
101+
-- Increase minimum reporting interval to 5 seconds
102+
device:send(clusters.SimpleMetering.attributes.InstantaneousDemand:configure_reporting(device, 5, 600, 5))
103+
device:add_configured_attribute(instantaneous_demand_configuration)
104+
end
105+
end
106+
device:set_field(CONFIGURATION_ATTEMPTED, true, {persist = true})
107+
end
108+
end
109+
driver._reconfig_timer = nil
110+
end
111+
112+
configurations.handle_reporting_config_response = function(driver, device, zb_mess)
113+
local dev = device
114+
local find_child_fn = device:get_field(device_def.FIND_CHILD_KEY)
115+
if find_child_fn ~= nil then
116+
local child = find_child_fn(device, zb_mess.address_header.src_endpoint.value)
117+
if child ~= nil then
118+
dev = child
119+
end
120+
end
121+
if dev:get_field(CONFIGURATION_ATTEMPTED) == true then
122+
if zb_mess.body.zcl_body.global_status ~= nil and zb_mess.body.zcl_body.global_status.value == Status.SUCCESS then
123+
dev:set_field(CONFIGURATION_VERSION_KEY, driver.current_config_version, {persist = true})
124+
elseif zb_mess.body.zcl_body.config_records ~= nil then
125+
local config_records = zb_mess.body.zcl_body.config_records
126+
for _, record in ipairs(config_records) do
127+
if zb_mess.address_header.cluster.value == clusters.SimpleMetering.ID then
128+
if record.attr_id.value == clusters.SimpleMetering.attributes.InstantaneousDemand.ID
129+
and record.status.value == Status.SUCCESS then
130+
dev:set_field(CONFIGURATION_VERSION_KEY, driver.current_config_version, {persist = true})
131+
end
132+
elseif zb_mess.address_header.cluster.value == clusters.ElectricalMeasurement.ID then
133+
if record.attr_id.value == clusters.ElectricalMeasurement.attributes.ActivePower.ID
134+
and record.status.value == Status.SUCCESS then
135+
dev:set_field(CONFIGURATION_VERSION_KEY, driver.current_config_version, {persist = true})
136+
end
137+
end
138+
139+
end
140+
end
141+
end
142+
end
143+
144+
configurations.power_reconfig_wrapper = function(orig_function)
145+
local new_init = function(driver, device)
146+
local config_version = device:get_field(CONFIGURATION_VERSION_KEY)
147+
if config_version == nil or config_version < driver.current_config_version then
148+
if driver._reconfig_timer == nil then
149+
driver._reconfig_timer = driver:call_with_delay(5*60, configurations.check_and_reconfig_devices, "reconfig_power_devices")
150+
end
151+
end
152+
orig_function(driver, device)
153+
end
154+
return new_init
155+
end
156+
65157
configurations.get_device_configuration = function(zigbee_device)
66158
for _, device in pairs(devices) do
67159
for _, fingerprint in pairs(device.FINGERPRINTS) do

drivers/SmartThings/zigbee-switch/src/ezex/init.lua

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
-- limitations under the License.
1414

1515
local zigbee_constants = require "st.zigbee.constants"
16+
local configurations = require "configurations"
1617

1718
local ZIGBEE_METERING_SWITCH_FINGERPRINTS = {
1819
{ model = "E240-KR116Z-HA" }
@@ -37,7 +38,7 @@ end
3738
local ezex_switch_handler = {
3839
NAME = "ezex switch handler",
3940
lifecycle_handlers = {
40-
init = do_init
41+
init = configurations.power_reconfig_wrapper(do_init)
4142
},
4243
can_handle = is_zigbee_ezex_switch
4344
}

drivers/SmartThings/zigbee-switch/src/hanssem/init.lua

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
-- limitations under the License.
1414

1515
local stDevice = require "st.device"
16+
local configurations = require "configurations"
1617

1718
local FINGERPRINTS = {
1819
{ mfr = "Winners", model = "LSS1-101", children = 0 },
@@ -78,7 +79,7 @@ local HanssemSwitch = {
7879
NAME = "Zigbee Hanssem Switch",
7980
lifecycle_handlers = {
8081
added = device_added,
81-
init = device_init
82+
init = configurations.power_reconfig_wrapper(device_init)
8283
},
8384
can_handle = can_handle_hanssem_switch
8485
}

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

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@ local ZigbeeDriver = require "st.zigbee"
1717
local defaults = require "st.zigbee.defaults"
1818
local clusters = require "st.zigbee.zcl.clusters"
1919
local configurationMap = require "configurations"
20+
local zcl_global_commands = require "st.zigbee.zcl.global_commands"
2021
local SimpleMetering = clusters.SimpleMetering
22+
local ElectricalMeasurement = clusters.ElectricalMeasurement
2123
local preferences = require "preferences"
2224
local device_lib = require "st.device"
2325

@@ -127,6 +129,7 @@ local function device_added(driver, device, event)
127129
end
128130
end
129131

132+
130133
local zigbee_switch_driver_template = {
131134
supported_capabilities = {
132135
capabilities.switch,
@@ -164,8 +167,19 @@ local zigbee_switch_driver_template = {
164167
lazy_load_if_possible("laisiao"),
165168
lazy_load_if_possible("tuya-multi")
166169
},
170+
zigbee_handlers = {
171+
global = {
172+
[SimpleMetering.ID] = {
173+
[zcl_global_commands.CONFIGURE_REPORTING_RESPONSE_ID] = configurationMap.handle_reporting_config_response
174+
},
175+
[ElectricalMeasurement.ID] = {
176+
[zcl_global_commands.CONFIGURE_REPORTING_RESPONSE_ID] = configurationMap.handle_reporting_config_response
177+
}
178+
}
179+
},
180+
current_config_version = 1,
167181
lifecycle_handlers = {
168-
init = device_init,
182+
init = configurationMap.power_reconfig_wrapper(device_init),
169183
added = device_added,
170184
infoChanged = info_changed,
171185
doConfigure = do_configure

drivers/SmartThings/zigbee-switch/src/inovelli-vzm31-sn/init.lua

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ local st_device = require "st.device"
1919
local data_types = require "st.zigbee.data_types"
2020
local capabilities = require "st.capabilities"
2121
local device_management = require "st.zigbee.device_management"
22+
local configurations = require "configurations"
2223

2324
local LATEST_CLOCK_SET_TIMESTAMP = "latest_clock_set_timestamp"
2425

@@ -358,7 +359,7 @@ local inovelli_vzm31_sn = {
358359
NAME = "inovelli vzm31-sn handler",
359360
lifecycle_handlers = {
360361
doConfigure = do_configure,
361-
init = device_init,
362+
init = configurations.power_reconfig_wrapper(device_init),
362363
infoChanged = info_changed
363364
},
364365
zigbee_handlers = {

drivers/SmartThings/zigbee-switch/src/laisiao/init.lua

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
local capabilities = require "st.capabilities"
1616
local zcl_clusters = require "st.zigbee.zcl.clusters"
17+
local configurations = require "configurations"
1718

1819
local FINGERPRINTS = {
1920
{ mfr = "LAISIAO", model = "yuba" },
@@ -70,7 +71,7 @@ local laisiao_bath_heater = {
7071
capabilities.switch,
7172
},
7273
lifecycle_handlers = {
73-
init = device_init,
74+
init = configurations.power_reconfig_wrapper(device_init),
7475
},
7576
capability_handlers = {
7677
[capabilities.switch.ID] = {

drivers/SmartThings/zigbee-switch/src/multi-switch-no-master/init.lua

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
-- limitations under the License.
1414
local st_device = require "st.device"
1515
local utils = require "st.utils"
16+
local configurations = require "configurations"
1617

1718
local MULTI_SWITCH_NO_MASTER_FINGERPRINTS = {
1819
{ mfr = "DAWON_DNS", model = "PM-S240-ZB", children = 1 },
@@ -113,7 +114,7 @@ end
113114
local multi_switch_no_master = {
114115
NAME = "multi switch no master",
115116
lifecycle_handlers = {
116-
init = device_init,
117+
init = configurations.power_reconfig_wrapper(device_init),
117118
added = device_added
118119
},
119120
can_handle = is_multi_switch_no_master

drivers/SmartThings/zigbee-switch/src/robb/init.lua

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
local constants = require "st.zigbee.constants"
1616
local zcl_clusters = require "st.zigbee.zcl.clusters"
1717
local capabilities = require "st.capabilities"
18+
local configurations = require "configurations"
1819
local SimpleMetering = zcl_clusters.SimpleMetering
1920

2021
local ROBB_DIMMER_FINGERPRINTS = {
@@ -57,7 +58,7 @@ local robb_dimmer_handler = {
5758
}
5859
},
5960
lifecycle_handlers = {
60-
init = do_init
61+
init = configurations.power_reconfig_wrapper(do_init)
6162
},
6263
can_handle = is_robb_dimmer
6364
}

0 commit comments

Comments
 (0)