@@ -20,6 +20,9 @@ local embedded_cluster_utils = require "embedded-cluster-utils"
20
20
local log = require " log"
21
21
local AIR_QUALITY_SENSOR_DEVICE_TYPE_ID = 0x002C
22
22
23
+ local SUPPORTED_COMPONENT_CAPABILITIES = " __supported_component_capabilities"
24
+
25
+
23
26
-- Include driver-side definitions when lua libs api version is < 10
24
27
local version = require " version"
25
28
if version .api < 10 then
@@ -141,10 +144,6 @@ local units_required = {
141
144
clusters .TotalVolatileOrganicCompoundsConcentrationMeasurement
142
145
}
143
146
144
- local function device_init (driver , device )
145
- device :subscribe ()
146
- end
147
-
148
147
local tbl_contains = function (t , val )
149
148
for _ , v in pairs (t ) do
150
149
if v == val then
@@ -210,15 +209,33 @@ local function create_level_measurement_profile(device)
210
209
return meas_name , level_name
211
210
end
212
211
213
- local function do_configure (driver , device )
212
+ local function supported_level_measurements (device )
213
+ local measurement_caps , level_caps = {}, {}
214
+ for _ , details in ipairs (AIR_QUALITY_MAP ) do
215
+ local cap_id = details [1 ]
216
+ local cluster = details [3 ]
217
+ -- capability describes either a HealthConcern or Measurement/Sensor
218
+ if (cap_id :match (" HealthConcern$" )) then
219
+ local attr_eps = embedded_cluster_utils .get_endpoints (device , cluster .ID , { feature_bitmap = cluster .types .Feature .LEVEL_INDICATION })
220
+ if # attr_eps > 0 then
221
+ device .log .info (string.format (" Adding %s cap to table" , cap_id ))
222
+ table.insert (level_caps , cap_id )
223
+ end
224
+ elseif (cap_id :match (" Measurement$" ) or cap_id :match (" Sensor$" )) then
225
+ local attr_eps = embedded_cluster_utils .get_endpoints (device , cluster .ID , { feature_bitmap = cluster .types .Feature .NUMERIC_MEASUREMENT })
226
+ if # attr_eps > 0 then
227
+ device .log .info (string.format (" Adding %s cap to table" , cap_id ))
228
+ table.insert (measurement_caps , cap_id )
229
+ end
230
+ end
231
+ end
232
+ return measurement_caps , level_caps
233
+ end
234
+
235
+ local function match_profile_switch (driver , device )
214
236
local temp_eps = embedded_cluster_utils .get_endpoints (device , clusters .TemperatureMeasurement .ID )
215
237
local humidity_eps = embedded_cluster_utils .get_endpoints (device , clusters .RelativeHumidityMeasurement .ID )
216
238
217
- -- we have to read the unit before reports of values will do anything
218
- for _ , cluster in ipairs (units_required ) do
219
- device :send (cluster .attributes .MeasurementUnit :read (device ))
220
- end
221
-
222
239
local profile_name = " aqs"
223
240
224
241
if # temp_eps > 0 then
@@ -271,6 +288,80 @@ local function do_configure(driver, device)
271
288
device :try_update_metadata ({profile = profile_name })
272
289
end
273
290
291
+ local function supports_capability_by_id_modular (device , capability , component )
292
+ for _ , component_capabilities in ipairs (device :get_field (SUPPORTED_COMPONENT_CAPABILITIES )) do
293
+ local comp_id = component_capabilities [1 ]
294
+ local capability_ids = component_capabilities [2 ]
295
+ if (component == nil ) or (component == comp_id ) then
296
+ for _ , cap in ipairs (capability_ids ) do
297
+ if cap == capability then
298
+ return true
299
+ end
300
+ end
301
+ end
302
+ end
303
+ return false
304
+ end
305
+
306
+ local function match_modular_profile (driver , device )
307
+ local temp_eps = embedded_cluster_utils .get_endpoints (device , clusters .TemperatureMeasurement .ID )
308
+ local humidity_eps = embedded_cluster_utils .get_endpoints (device , clusters .RelativeHumidityMeasurement .ID )
309
+
310
+ local optional_supported_component_capabilities = {}
311
+ local main_component_capabilities = {}
312
+
313
+ if # temp_eps > 0 then
314
+ table.insert (main_component_capabilities , capabilities .temperatureMeasurement .ID )
315
+ end
316
+ if # humidity_eps > 0 then
317
+ table.insert (main_component_capabilities , capabilities .relativeHumidityMeasurement .ID )
318
+ end
319
+
320
+ local measurement_caps , level_caps = supported_level_measurements (device )
321
+
322
+ for _ , cap_id in ipairs (measurement_caps ) do
323
+ table.insert (main_component_capabilities , cap_id )
324
+ end
325
+
326
+ for _ , cap_id in ipairs (level_caps ) do
327
+ table.insert (main_component_capabilities , cap_id )
328
+ end
329
+
330
+ table.insert (optional_supported_component_capabilities , {" main" , main_component_capabilities })
331
+
332
+ device :set_field (SUPPORTED_COMPONENT_CAPABILITIES , optional_supported_component_capabilities )
333
+
334
+ device :try_update_metadata ({profile = " aqs-modular" , optional_component_capabilities = optional_supported_component_capabilities })
335
+
336
+ -- add mandatory capabilities for subscription
337
+ local total_supported_capabilities = optional_supported_component_capabilities
338
+ table.insert (total_supported_capabilities [1 ][2 ], capabilities .airQualityHealthConcern .ID )
339
+
340
+ device :set_field (SUPPORTED_COMPONENT_CAPABILITIES , total_supported_capabilities , { persist = true })
341
+
342
+ -- re-up subscription with new capabiltiies using the moudlar supports_capability override
343
+ device :extend_device (" supports_capability_by_id" , supports_capability_by_id_modular )
344
+ device :subscribe ()
345
+ end
346
+
347
+ local function do_configure (driver , device )
348
+ -- must use profile switching on older hubs
349
+ if version .api < 14 and version .rpc < 7 then
350
+ match_profile_switch (driver , device )
351
+ else
352
+ match_modular_profile (driver , device )
353
+ end
354
+ end
355
+
356
+ local function device_init (driver , device )
357
+ if device :get_field (SUPPORTED_COMPONENT_CAPABILITIES ) then
358
+ -- assume that device is using a modular profile, override supports_capability_by_id
359
+ -- library function to utilize optional capabilities
360
+ device :extend_device (" supports_capability_by_id" , supports_capability_by_id_modular )
361
+ end
362
+ device :subscribe ()
363
+ end
364
+
274
365
local function store_unit_factory (capability_name )
275
366
return function (driver , device , ib , response )
276
367
device :set_field (capability_name .. " _unit" , ib .data .value , {persist = true })
0 commit comments