@@ -44,19 +44,12 @@ local SWITCH_LEVEL_LIGHTING_MIN = 1
44
44
local CURRENT_HUESAT_ATTR_MIN = 0
45
45
local CURRENT_HUESAT_ATTR_MAX = 254
46
46
47
- local SWITCH_INITIALIZED = " __switch_intialized"
48
- -- COMPONENT_TO_ENDPOINT_MAP is here only to preserve the endpoint mapping for
47
+ -- COMPONENT_TO_ENDPOINT_MAP is here to preserve the endpoint mapping for
49
48
-- devices that were joined to this driver as MCD devices before the transition
50
- -- to join all matter- switch devices as parent-child. This value will only exist
51
- -- in the device table for devices that joined prior to this transition, and it
52
- -- will not be set for new devices .
49
+ -- to join switch devices as parent-child. This value will exist in the device
50
+ -- table for devices that joined prior to this transition, and is also used for
51
+ -- button devices that require component mapping .
53
52
local COMPONENT_TO_ENDPOINT_MAP = " __component_to_endpoint_map"
54
- -- COMPONENT_TO_ENDPOINT_MAP_BUTTON is for devices with button endpoints, to
55
- -- preserve the MCD functionality for button devices from the matter-button
56
- -- driver after it was merged into the matter-switch driver. Note that devices
57
- -- containing both button endpoints and switch endpoints will use this field
58
- -- rather than COMPONENT_TO_ENDPOINT_MAP.
59
- local COMPONENT_TO_ENDPOINT_MAP_BUTTON = " __component_to_endpoint_map_button"
60
53
local ENERGY_MANAGEMENT_ENDPOINT = " __energy_management_endpoint"
61
54
local IS_PARENT_CHILD_DEVICE = " __is_parent_child_device"
62
55
local COLOR_TEMP_BOUND_RECEIVED_KELVIN = " __colorTemp_bound_received_kelvin"
@@ -67,6 +60,12 @@ local LEVEL_BOUND_RECEIVED = "__level_bound_received"
67
60
local LEVEL_MIN = " __level_min"
68
61
local LEVEL_MAX = " __level_max"
69
62
local COLOR_MODE = " __color_mode"
63
+
64
+ local updated_fields = {
65
+ { field_name = " __component_to_endpoint_map_button" , updated_field_name = COMPONENT_TO_ENDPOINT_MAP },
66
+ { field_name = " __switch_intialized" , updated_field_name = nil }
67
+ }
68
+
70
69
local HUE_SAT_COLOR_MODE = clusters .ColorControl .types .ColorMode .CURRENT_HUE_AND_CURRENT_SATURATION
71
70
local X_Y_COLOR_MODE = clusters .ColorControl .types .ColorMode .CURRENTX_AND_CURRENTY
72
71
@@ -292,8 +291,6 @@ local HELD_THRESHOLD = 1
292
291
-- this is the number of buttons for which we have a static profile already made
293
292
local STATIC_BUTTON_PROFILE_SUPPORTED = {1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 }
294
293
295
- local BUTTON_DEVICE_PROFILED = " __button_device_profiled"
296
-
297
294
-- Some switches will send a MultiPressComplete event as part of a long press sequence. Normally the driver will create a
298
295
-- button capability event on receipt of MultiPressComplete, but in this case that would result in an extra event because
299
296
-- the "held" capability event is generated when the LongPress event is received. The IGNORE_NEXT_MPC flag is used
@@ -406,6 +403,7 @@ local function device_type_supports_button_switch_combination(device, endpoint_i
406
403
end
407
404
408
405
local function get_first_non_zero_endpoint (endpoints )
406
+ table.sort (endpoints )
409
407
for _ ,ep in ipairs (endpoints ) do
410
408
if ep ~= 0 then -- 0 is the matter RootNode endpoint
411
409
return ep
@@ -425,8 +423,6 @@ local function find_default_endpoint(device)
425
423
426
424
local switch_eps = device :get_endpoints (clusters .OnOff .ID )
427
425
local button_eps = device :get_endpoints (clusters .Switch .ID , {feature_bitmap = clusters .Switch .types .SwitchFeature .MOMENTARY_SWITCH })
428
- table.sort (switch_eps )
429
- table.sort (button_eps )
430
426
431
427
-- Return the first switch endpoint as the default endpoint if no button endpoints are present
432
428
if # button_eps == 0 and # switch_eps > 0 then
@@ -456,15 +452,15 @@ local function find_default_endpoint(device)
456
452
end
457
453
458
454
local function component_to_endpoint (device , component )
459
- local map = device :get_field (COMPONENT_TO_ENDPOINT_MAP_BUTTON ) or device : get_field ( COMPONENT_TO_ENDPOINT_MAP ) or {}
455
+ local map = device :get_field (COMPONENT_TO_ENDPOINT_MAP ) or {}
460
456
if map [component ] then
461
457
return map [component ]
462
458
end
463
459
return find_default_endpoint (device )
464
460
end
465
461
466
462
local function endpoint_to_component (device , ep )
467
- local map = device :get_field (COMPONENT_TO_ENDPOINT_MAP_BUTTON ) or device : get_field ( COMPONENT_TO_ENDPOINT_MAP ) or {}
463
+ local map = device :get_field (COMPONENT_TO_ENDPOINT_MAP ) or {}
468
464
for component , endpoint in pairs (map ) do
469
465
if endpoint == ep then
470
466
return component
@@ -473,6 +469,17 @@ local function endpoint_to_component(device, ep)
473
469
return " main"
474
470
end
475
471
472
+ local function check_field_name_updates (device )
473
+ for _ , field in ipairs (updated_fields ) do
474
+ if device :get_field (field .field_name ) then
475
+ if field .updated_field_name ~= nil then
476
+ device :set_field (field .updated_field_name , device :get_field (field .field_name ), {persist = true })
477
+ end
478
+ device :set_field (field .field_name , nil )
479
+ end
480
+ end
481
+ end
482
+
476
483
local function assign_child_profile (device , child_ep )
477
484
local profile
478
485
@@ -512,41 +519,6 @@ local function assign_child_profile(device, child_ep)
512
519
return profile or " switch-binary"
513
520
end
514
521
515
- local function do_configure (driver , device )
516
- if device :get_field (BUTTON_DEVICE_PROFILED ) then
517
- return
518
- end
519
- local fan_eps = device :get_endpoints (clusters .FanControl .ID )
520
- local level_eps = device :get_endpoints (clusters .LevelControl .ID )
521
- local energy_eps = embedded_cluster_utils .get_endpoints (device , clusters .ElectricalEnergyMeasurement .ID )
522
- local power_eps = embedded_cluster_utils .get_endpoints (device , clusters .ElectricalPowerMeasurement .ID )
523
- local valve_eps = embedded_cluster_utils .get_endpoints (device , clusters .ValveConfigurationAndControl .ID )
524
- local profile_name = nil
525
- local level_support = " "
526
- if # level_eps > 0 then
527
- level_support = " -level"
528
- end
529
- if # energy_eps > 0 and # power_eps > 0 then
530
- profile_name = " plug" .. level_support .. " -power-energy-powerConsumption"
531
- elseif # energy_eps > 0 then
532
- profile_name = " plug" .. level_support .. " -energy-powerConsumption"
533
- elseif # power_eps > 0 then
534
- profile_name = " plug" .. level_support .. " -power"
535
- elseif # valve_eps > 0 then
536
- profile_name = " water-valve"
537
- if # embedded_cluster_utils .get_endpoints (device , clusters .ValveConfigurationAndControl .ID ,
538
- {feature_bitmap = clusters .ValveConfigurationAndControl .types .Feature .LEVEL }) > 0 then
539
- profile_name = profile_name .. " -level"
540
- end
541
- elseif # fan_eps > 0 then
542
- profile_name = " light-color-level-fan"
543
- end
544
-
545
- if profile_name then
546
- device :try_update_metadata ({ profile = profile_name })
547
- end
548
- end
549
-
550
522
local function configure_buttons (device )
551
523
if device .network_type == device_lib .NETWORK_TYPE_CHILD then
552
524
return
@@ -603,7 +575,7 @@ local function build_button_component_map(device, main_endpoint, button_eps)
603
575
component_map [button_component ] = ep
604
576
end
605
577
end
606
- device :set_field (COMPONENT_TO_ENDPOINT_MAP_BUTTON , component_map , {persist = true })
578
+ device :set_field (COMPONENT_TO_ENDPOINT_MAP , component_map , {persist = true })
607
579
end
608
580
609
581
local function build_button_profile (device , main_endpoint , num_button_eps )
@@ -613,13 +585,10 @@ local function build_button_profile(device, main_endpoint, num_button_eps)
613
585
end
614
586
local battery_supported = # device :get_endpoints (clusters .PowerSource .ID , {feature_bitmap = clusters .PowerSource .types .PowerSourceFeature .BATTERY }) > 0
615
587
if battery_supported then -- battery profiles are configured later, in power_source_attribute_list_handler
616
- local attribute_list_read = im .InteractionRequest (im .InteractionRequest .RequestType .READ , {})
617
- attribute_list_read :merge (clusters .PowerSource .attributes .AttributeList :read ())
618
- device :send (attribute_list_read )
588
+ device :send (clusters .PowerSource .attributes .AttributeList :read (device ))
619
589
else
620
590
device :try_update_metadata ({profile = profile_name })
621
591
end
622
- device :set_field (BUTTON_DEVICE_PROFILED , true )
623
592
end
624
593
625
594
local function build_child_switch_profiles (driver , device , main_endpoint )
@@ -683,13 +652,15 @@ local function handle_light_switch_with_onOff_server_clusters(device, main_endpo
683
652
end
684
653
685
654
local function initialize_buttons_and_switches (driver , device , main_endpoint )
655
+ local profile_found = false
686
656
local button_eps = device :get_endpoints (clusters .Switch .ID , {feature_bitmap = clusters .Switch .types .SwitchFeature .MOMENTARY_SWITCH })
687
657
if tbl_contains (STATIC_BUTTON_PROFILE_SUPPORTED , # button_eps ) then
688
658
build_button_profile (device , main_endpoint , # button_eps )
689
659
-- All button endpoints found will be added as additional components in the profile containing the main_endpoint.
690
- -- The resulting endpoint to component map is saved in the COMPONENT_TO_ENDPOINT_MAP_BUTTON field
660
+ -- The resulting endpoint to component map is saved in the COMPONENT_TO_ENDPOINT_MAP field
691
661
build_button_component_map (device , main_endpoint , button_eps )
692
662
configure_buttons (device )
663
+ profile_found = true
693
664
end
694
665
695
666
-- Without support for bindings, only clusters that are implemented as server are counted. This count is handled
@@ -701,9 +672,9 @@ local function initialize_buttons_and_switches(driver, device, main_endpoint)
701
672
-- Note: since their device type isn't supported, these devices join as a matter-thing.
702
673
if num_switch_server_eps > 0 and detect_matter_thing (device ) then
703
674
handle_light_switch_with_onOff_server_clusters (device , main_endpoint )
675
+ profile_found = true
704
676
end
705
-
706
- device :set_field (SWITCH_INITIALIZED , true , {persist = true })
677
+ return profile_found
707
678
end
708
679
709
680
local function detect_bridge (device )
@@ -721,20 +692,13 @@ local function device_init(driver, device)
721
692
if device .network_type ~= device_lib .NETWORK_TYPE_MATTER then
722
693
return
723
694
end
724
-
695
+ check_field_name_updates ( device )
725
696
device :set_component_to_endpoint_fn (component_to_endpoint )
726
697
device :set_endpoint_to_component_fn (endpoint_to_component )
727
-
728
- local main_endpoint = find_default_endpoint (device )
729
- if not device :get_field (COMPONENT_TO_ENDPOINT_MAP ) and -- this field is only set for old MCD devices. See comments in the field def.
730
- not device :get_field (SWITCH_INITIALIZED ) and
731
- not detect_bridge (device ) then
732
- -- initialize the main device card with buttons if applicable, and create child devices as needed for multi-switch devices.
733
- initialize_buttons_and_switches (driver , device , main_endpoint )
734
- end
735
698
if device :get_field (IS_PARENT_CHILD_DEVICE ) then
736
699
device :set_find_child (find_child )
737
700
end
701
+ local main_endpoint = find_default_endpoint (device )
738
702
-- ensure subscription to all endpoint attributes- including those mapped to child devices
739
703
for _ , ep in ipairs (device .endpoints ) do
740
704
if ep .endpoint_id ~= main_endpoint then
@@ -756,6 +720,50 @@ local function device_init(driver, device)
756
720
device :subscribe ()
757
721
end
758
722
723
+ local function do_configure (driver , device )
724
+ if detect_bridge (device ) then
725
+ return
726
+ end
727
+ local main_endpoint = find_default_endpoint (device )
728
+ -- initialize the main device card with buttons if applicable, and create child devices as needed for multi-switch devices.
729
+ local profile_found = initialize_buttons_and_switches (driver , device , main_endpoint )
730
+ if device :get_field (IS_PARENT_CHILD_DEVICE ) then
731
+ device :set_find_child (find_child )
732
+ end
733
+ if profile_found then
734
+ return
735
+ end
736
+
737
+ local fan_eps = device :get_endpoints (clusters .FanControl .ID )
738
+ local level_eps = device :get_endpoints (clusters .LevelControl .ID )
739
+ local energy_eps = embedded_cluster_utils .get_endpoints (device , clusters .ElectricalEnergyMeasurement .ID )
740
+ local power_eps = embedded_cluster_utils .get_endpoints (device , clusters .ElectricalPowerMeasurement .ID )
741
+ local valve_eps = embedded_cluster_utils .get_endpoints (device , clusters .ValveConfigurationAndControl .ID )
742
+ local profile_name = nil
743
+ local level_support = " "
744
+ if # level_eps > 0 then
745
+ level_support = " -level"
746
+ end
747
+ if # energy_eps > 0 and # power_eps > 0 then
748
+ profile_name = " plug" .. level_support .. " -power-energy-powerConsumption"
749
+ elseif # energy_eps > 0 then
750
+ profile_name = " plug" .. level_support .. " -energy-powerConsumption"
751
+ elseif # power_eps > 0 then
752
+ profile_name = " plug" .. level_support .. " -power"
753
+ elseif # valve_eps > 0 then
754
+ profile_name = " water-valve"
755
+ if # embedded_cluster_utils .get_endpoints (device , clusters .ValveConfigurationAndControl .ID ,
756
+ {feature_bitmap = clusters .ValveConfigurationAndControl .types .Feature .LEVEL }) > 0 then
757
+ profile_name = profile_name .. " -level"
758
+ end
759
+ elseif # fan_eps > 0 then
760
+ profile_name = " light-color-level-fan"
761
+ end
762
+ if profile_name then
763
+ device :try_update_metadata ({ profile = profile_name })
764
+ end
765
+ end
766
+
759
767
local function device_removed (driver , device )
760
768
log .info (" device removed" )
761
769
delete_import_poll_schedule (device )
0 commit comments