15
15
-- Note: Currently only support for window shades with the PositionallyAware Feature
16
16
-- Note: No support for setting device into calibration mode, it must be done manually
17
17
local capabilities = require " st.capabilities"
18
+ local im = require " st.matter.interaction_model"
18
19
local log = require " log"
19
20
local clusters = require " st.matter.clusters"
20
21
local MatterDriver = require " st.matter.driver"
21
- local PROFILE_MATCHED = " __profile_matched"
22
+
23
+ local battery_support = {
24
+ NO_BATTERY = " NO_BATTERY" ,
25
+ BATTERY_LEVEL = " BATTERY_LEVEL" ,
26
+ BATTERY_PERCENTAGE = " BATTERY_PERCENTAGE"
27
+ }
22
28
23
29
local function find_default_endpoint (device , cluster )
24
30
local res = device .MATTER_DEFAULT_ENDPOINT
@@ -39,34 +45,47 @@ local function component_to_endpoint(device, component_name)
39
45
return find_default_endpoint (device , clusters .WindowCovering .ID )
40
46
end
41
47
42
- local function match_profile (device )
48
+ local function match_profile (device , battery_supported )
43
49
local profile_name = " window-covering"
44
- local battery_eps = device :get_endpoints (clusters .PowerSource .ID ,
45
- {feature_bitmap = clusters .PowerSource .types .PowerSourceFeature .BATTERY })
46
-
47
- if # battery_eps > 0 then
48
- profile_name = " window-covering-battery"
50
+ if battery_supported == battery_support .BATTERY_PERCENTAGE then
51
+ profile_name = profile_name .. " -battery"
52
+ elseif battery_supported == battery_support .BATTERY_LEVEL then
53
+ profile_name = profile_name .. " -batteryLevel"
49
54
end
50
55
device :try_update_metadata ({profile = profile_name })
51
- device :set_field (PROFILE_MATCHED , 1 )
52
56
end
53
57
54
58
local function device_init (driver , device )
55
- if not device :get_field (PROFILE_MATCHED ) then
56
- match_profile (device )
57
- end
58
59
device :set_component_to_endpoint_fn (component_to_endpoint )
59
60
device :subscribe ()
60
61
end
61
62
63
+ local function do_configure (driver , device )
64
+ local battery_feature_eps = device :get_endpoints (clusters .PowerSource .ID , {feature_bitmap = clusters .PowerSource .types .PowerSourceFeature .BATTERY })
65
+ if # battery_feature_eps > 0 then
66
+ local attribute_list_read = im .InteractionRequest (im .InteractionRequest .RequestType .READ , {})
67
+ attribute_list_read :merge (clusters .PowerSource .attributes .AttributeList :read ())
68
+ device :send (attribute_list_read )
69
+ else
70
+ match_profile (device , battery_support .NO_BATTERY )
71
+ end
72
+ end
73
+
62
74
local function info_changed (driver , device , event , args )
63
75
if device .profile .id ~= args .old_st_store .profile .id then
64
76
-- Profile has changed, resubscribe
65
77
device :subscribe ()
66
78
else
67
79
-- Something else has changed info (SW update, reinterview, etc.), so
68
80
-- try updating profile as needed
69
- match_profile (device )
81
+ local battery_feature_eps = device :get_endpoints (clusters .PowerSource .ID , {feature_bitmap = clusters .PowerSource .types .PowerSourceFeature .BATTERY })
82
+ if # battery_feature_eps > 0 then
83
+ local attribute_list_read = im .InteractionRequest (im .InteractionRequest .RequestType .READ , {})
84
+ attribute_list_read :merge (clusters .PowerSource .attributes .AttributeList :read ())
85
+ device :send (attribute_list_read )
86
+ else
87
+ match_profile (device , battery_support .NO_BATTERY )
88
+ end
70
89
end
71
90
end
72
91
@@ -169,8 +188,37 @@ local function battery_percent_remaining_attr_handler(driver, device, ib, respon
169
188
end
170
189
end
171
190
191
+ local function battery_charge_level_attr_handler (driver , device , ib , response )
192
+ if ib .data .value == clusters .PowerSource .types .BatChargeLevelEnum .OK then
193
+ device :emit_event (capabilities .batteryLevel .battery .normal ())
194
+ elseif ib .data .value == clusters .PowerSource .types .BatChargeLevelEnum .WARNING then
195
+ device :emit_event (capabilities .batteryLevel .battery .warning ())
196
+ elseif ib .data .value == clusters .PowerSource .types .BatChargeLevelEnum .CRITICAL then
197
+ device :emit_event (capabilities .batteryLevel .battery .critical ())
198
+ end
199
+ end
200
+
201
+ local function power_source_attribute_list_handler (driver , device , ib , response )
202
+ for _ , attr in ipairs (ib .data .elements ) do
203
+ -- Re-profile the device if BatPercentRemaining (Attribute ID 0x0C) is present.
204
+ if attr .value == 0x0C then
205
+ match_profile (device , battery_support .BATTERY_PERCENTAGE )
206
+ return
207
+ elseif attr .value == 0x0E then
208
+ match_profile (device , battery_support .BATTERY_LEVEL )
209
+ return
210
+ end
211
+ end
212
+ end
213
+
172
214
local matter_driver_template = {
173
- lifecycle_handlers = {init = device_init , removed = device_removed , added = device_added , infoChanged = info_changed },
215
+ lifecycle_handlers = {
216
+ init = device_init ,
217
+ removed = device_removed ,
218
+ added = device_added ,
219
+ infoChanged = info_changed ,
220
+ doConfigure = do_configure ,
221
+ },
174
222
matter_handlers = {
175
223
attr = {
176
224
-- TODO LevelControl may not be needed for certified devices since
@@ -184,6 +232,8 @@ local matter_driver_template = {
184
232
[clusters .WindowCovering .attributes .OperationalStatus .ID ] = current_status_handler ,
185
233
},
186
234
[clusters .PowerSource .ID ] = {
235
+ [clusters .PowerSource .attributes .AttributeList .ID ] = power_source_attribute_list_handler ,
236
+ [clusters .PowerSource .attributes .BatChargeLevel .ID ] = battery_charge_level_attr_handler ,
187
237
[clusters .PowerSource .attributes .BatPercentRemaining .ID ] = battery_percent_remaining_attr_handler ,
188
238
}
189
239
},
@@ -198,7 +248,10 @@ local matter_driver_template = {
198
248
},
199
249
[capabilities .battery .ID ] = {
200
250
clusters .PowerSource .attributes .BatPercentRemaining
201
- }
251
+ },
252
+ [capabilities .batteryLevel .ID ] = {
253
+ clusters .PowerSource .attributes .BatChargeLevel ,
254
+ },
202
255
},
203
256
capability_handlers = {
204
257
[capabilities .refresh .ID ] = {
@@ -221,6 +274,7 @@ local matter_driver_template = {
221
274
capabilities .windowShade ,
222
275
capabilities .windowShadePreset ,
223
276
capabilities .battery ,
277
+ capabilities .batteryLevel ,
224
278
},
225
279
sub_drivers = {
226
280
-- for devices sending a position update while device is in motion
0 commit comments