@@ -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,7 +209,30 @@ 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
@@ -271,6 +293,81 @@ local function do_configure(driver, device)
271
293
device :try_update_metadata ({profile = profile_name })
272
294
end
273
295
296
+ local function supports_capability_by_id_modular (device , capability , component )
297
+ for _ , component_capabilities in ipairs (device :get_field (SUPPORTED_COMPONENT_CAPABILITIES )) do
298
+ local comp_id = component_capabilities [1 ]
299
+ local capability_ids = component_capabilities [2 ]
300
+ if (component == nil ) or (component == comp_id ) then
301
+ for _ , cap in ipairs (capability_ids ) do
302
+ if cap == capability then
303
+ return true
304
+ end
305
+ end
306
+ end
307
+ end
308
+ return false
309
+ end
310
+
311
+ local function match_modular_profile (driver , device )
312
+ local temp_eps = embedded_cluster_utils .get_endpoints (device , clusters .TemperatureMeasurement .ID )
313
+ local humidity_eps = embedded_cluster_utils .get_endpoints (device , clusters .RelativeHumidityMeasurement .ID )
314
+
315
+ -- we have to read the unit before reports of values will do anything
316
+ for _ , cluster in ipairs (units_required ) do
317
+ device :send (cluster .attributes .MeasurementUnit :read (device ))
318
+ end
319
+
320
+ local optional_supported_component_capabilities = {}
321
+ local main_component_capabilities = {}
322
+
323
+ if # temp_eps > 0 then
324
+ table.insert (main_component_capabilities , capabilities .temperatureMeasurement .ID )
325
+ end
326
+ if # humidity_eps > 0 then
327
+ table.insert (main_component_capabilities , capabilities .relativeHumidityMeasurement .ID )
328
+ end
329
+
330
+ local measurement_caps , level_caps = supported_level_measurements (device )
331
+
332
+ for _ , cap_id in ipairs (measurement_caps ) do
333
+ table.insert (main_component_capabilities , cap_id )
334
+ end
335
+
336
+ for _ , cap_id in ipairs (level_caps ) do
337
+ table.insert (main_component_capabilities , cap_id )
338
+ end
339
+
340
+ table.insert (optional_supported_component_capabilities , {" main" , main_component_capabilities })
341
+
342
+ device :set_field (SUPPORTED_COMPONENT_CAPABILITIES , optional_supported_component_capabilities )
343
+
344
+ device :try_update_metadata ({profile = " aqs-modular" , optional_component_capabilities = optional_supported_component_capabilities })
345
+
346
+ -- add mandatory capabilities for subscription
347
+ local total_supported_capabilities = optional_supported_component_capabilities
348
+ table.insert (total_supported_capabilities [1 ][2 ], capabilities .airQualityHealthConcern .ID )
349
+
350
+ device :set_field (SUPPORTED_COMPONENT_CAPABILITIES , total_supported_capabilities , { persist = true })
351
+
352
+ -- re-up subscription with new capabiltiies using the moudlar supports_capability override
353
+ device :extend_device (" supports_capability_by_id" , supports_capability_by_id_modular )
354
+ device :subscribe ()
355
+ end
356
+
357
+ local function do_configure (driver , device )
358
+ -- must use profile switching on older hubs
359
+ if version .api < 14 and version .rpc < 7 then
360
+ match_profile_switch (driver , device )
361
+ else
362
+ match_modular_profile (driver , device )
363
+ end
364
+ end
365
+
366
+ local function device_init (driver , device )
367
+ device :extend_device (" supports_capability_by_id" , supports_capability_by_id_modular )
368
+ device :subscribe ()
369
+ end
370
+
274
371
local function store_unit_factory (capability_name )
275
372
return function (driver , device , ib , response )
276
373
device :set_field (capability_name .. " _unit" , ib .data .value , {persist = true })
0 commit comments