@@ -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,85 @@ 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
+ local MAIN_COMPONENT_IDX = 1
313
+ local CAPABILITIES_LIST_IDX = 2
314
+
315
+
316
+ if # temp_eps > 0 then
317
+ table.insert (main_component_capabilities , capabilities .temperatureMeasurement .ID )
318
+ end
319
+ if # humidity_eps > 0 then
320
+ table.insert (main_component_capabilities , capabilities .relativeHumidityMeasurement .ID )
321
+ end
322
+
323
+ local measurement_caps , level_caps = supported_level_measurements (device )
324
+
325
+ for _ , cap_id in ipairs (measurement_caps ) do
326
+ table.insert (main_component_capabilities , cap_id )
327
+ end
328
+
329
+ for _ , cap_id in ipairs (level_caps ) do
330
+ table.insert (main_component_capabilities , cap_id )
331
+ end
332
+
333
+ table.insert (optional_supported_component_capabilities , {" main" , main_component_capabilities })
334
+
335
+ device :try_update_metadata ({profile = " aqs-modular" , optional_component_capabilities = optional_supported_component_capabilities })
336
+
337
+ -- add mandatory capabilities for subscription
338
+ local total_supported_capabilities = optional_supported_component_capabilities
339
+ table.insert (total_supported_capabilities [MAIN_COMPONENT_IDX ][CAPABILITIES_LIST_IDX ], capabilities .airQualityHealthConcern .ID )
340
+
341
+ device :set_field (SUPPORTED_COMPONENT_CAPABILITIES , total_supported_capabilities , { persist = true })
342
+
343
+ -- re-up subscription with new capabilities using the modular supports_capability override
344
+ device :extend_device (" supports_capability_by_id" , supports_capability_by_id_modular )
345
+ device :subscribe ()
346
+ end
347
+
348
+ local function do_configure (driver , device )
349
+ -- we have to read the unit before reports of values will do anything
350
+ for _ , cluster in ipairs (units_required ) do
351
+ device :send (cluster .attributes .MeasurementUnit :read (device ))
352
+ end
353
+ if version .api >= 14 and version .rpc >= 8 then
354
+ match_modular_profile (driver , device )
355
+ else
356
+ match_profile_switch (driver , device )
357
+
358
+ end
359
+ end
360
+
361
+ local function device_init (driver , device )
362
+ if device :get_field (SUPPORTED_COMPONENT_CAPABILITIES ) then
363
+ -- assume that device is using a modular profile, override supports_capability_by_id
364
+ -- library function to utilize optional capabilities
365
+ device :extend_device (" supports_capability_by_id" , supports_capability_by_id_modular )
366
+ end
367
+ device :subscribe ()
368
+ end
369
+
274
370
local function store_unit_factory (capability_name )
275
371
return function (driver , device , ib , response )
276
372
device :set_field (capability_name .. " _unit" , ib .data .value , {persist = true })
0 commit comments