@@ -42,17 +42,45 @@ void switch_cluster_on_write_attr(zigbee_switch_cluster *cluster);
4242
4343void switch_cluster_report_action (zigbee_switch_cluster * cluster );
4444
45+ static void switch_cluster_fixup_scene_attrs (zigbee_switch_cluster * cluster );
46+ static void switch_cluster_report_next_scene (zigbee_switch_cluster * cluster );
47+
48+ bool switch_cluster_scenes_is_enabled (zigbee_switch_cluster * cluster );
4549
4650status_t switch_cluster_callback_trampoline (zclIncomingAddrInfo_t * pAddrInfo , u8 cmdId , void * cmdPayload )
4751{
4852 return (ZCL_STA_SUCCESS );
4953}
5054
51- void switch_cluster_callback_attr_write_trampoline (u8 clusterId )
55+ void switch_cluster_callback_attr_write_trampoline (u8 endpoint , u16 clusterId , zclWriteCmd_t * pWriteReqCmd )
5256{
53- switch_cluster_on_write_attr (switch_cluster_by_endpoint [clusterId ]);
57+ (void )pWriteReqCmd ;
58+ zigbee_switch_cluster * cluster = switch_cluster_by_endpoint [endpoint ];
59+
60+ switch_cluster_on_write_attr (cluster );
61+
62+ if (clusterId == 8 || clusterId == 9 || clusterId == 10 )
63+ {
64+ switch_cluster_fixup_scene_attrs (cluster );
65+ }
5466}
5567
68+ // (mandatory) Cluster revisions
69+ static u16 onoff_cluster_revision = 0x0002 ;
70+ static const zclAttrInfo_t onOff_client_attrs [] = {
71+ {.id = 0 , .type = ZCL_DATA_TYPE_UINT16 , .access = ACCESS_CONTROL_READ , .data = (u8 * )& onoff_cluster_revision },
72+ };
73+
74+ static u16 scenes_cluster_revision = 0x0003 ;
75+ static const zclAttrInfo_t scenes_client_attrs [] = {
76+ {.id = 0 , .type = ZCL_DATA_TYPE_UINT16 , .access = ACCESS_CONTROL_READ , .data = (u8 * )& scenes_cluster_revision },
77+ };
78+
79+ // Level has the same revision as Scene cluster
80+ #define level_client_attrs scenes_client_attrs
81+
82+ static u16 multistate_input_cluster_revision = 0x0001 ;
83+
5684void switch_cluster_add_to_endpoint (zigbee_switch_cluster * cluster , zigbee_endpoint * endpoint )
5785{
5886 switch_cluster_by_endpoint [endpoint -> index ] = cluster ;
@@ -74,13 +102,21 @@ void switch_cluster_add_to_endpoint(zigbee_switch_cluster *cluster, zigbee_endpo
74102 SETUP_ATTR (5 , ZCL_ATTRID_ONOFF_CONFIGURATION_SWITCH_LONG_PRESS_DUR , ZCL_DATA_TYPE_UINT16 , ACCESS_CONTROL_READ | ACCESS_CONTROL_WRITE , cluster -> button -> long_press_duration_ms );
75103 SETUP_ATTR (6 , ZCL_ATTRID_ONOFF_CONFIGURATION_SWITCH_LEVEL_MOVE_RATE , ZCL_DATA_TYPE_UINT8 , ACCESS_CONTROL_READ | ACCESS_CONTROL_WRITE , cluster -> level_move -> rate );
76104 SETUP_ATTR (7 , ZCL_ATTRID_ONOFF_CONFIGURATION_SWITCH_BINDING_MODE , ZCL_DATA_TYPE_ENUM8 , ACCESS_CONTROL_READ | ACCESS_CONTROL_WRITE , cluster -> binded_mode );
105+ SETUP_ATTR (8 , ZCL_ATTRID_ONOFF_CONFIGURATION_SCENE_NEXT_IDX , ZCL_DATA_TYPE_UINT8 , ACCESS_CONTROL_READ | ACCESS_CONTROL_AUTH_WRITE | ACCESS_CONTROL_REPORTABLE , cluster -> out_scene_next );
106+ SETUP_ATTR (9 , ZCL_ATTRID_ONOFF_CONFIGURATION_SCENE_COUNT , ZCL_DATA_TYPE_UINT8 , ACCESS_CONTROL_READ | ACCESS_CONTROL_WRITE , cluster -> out_scene_count );
107+ SETUP_ATTR (10 , ZCL_ATTRID_ONOFF_CONFIGURATION_SCENE_OFFSET , ZCL_DATA_TYPE_UINT8 , ACCESS_CONTROL_READ | ACCESS_CONTROL_WRITE , cluster -> out_scene_start_offset );
108+ SETUP_ATTR (11 , ZCL_ATTRID_ONOFF_CONFIGURATION_SCENE_GROUP_ID , ZCL_DATA_TYPE_UINT16 , ACCESS_CONTROL_READ | ACCESS_CONTROL_WRITE , cluster -> out_scene_group_id );
109+ SETUP_ATTR (12 , ZCL_ATTRID_ONOFF_CONFIGURATION_SCENE_RECALL_TIME , ZCL_DATA_TYPE_UINT16 , ACCESS_CONTROL_READ | ACCESS_CONTROL_WRITE , cluster -> scene_recall_time );
110+ // This is mandatory on everything
111+ SETUP_ATTR (12 , ZCL_ATTRID_GLOBAL_CLUSTER_REVISION , ZCL_DATA_TYPE_UINT16 , ACCESS_CONTROL_READ , zcl_attr_global_clusterRevision );
112+
77113
78114 // Configuration
79115 zigbee_endpoint_add_cluster (endpoint , 1 , ZCL_CLUSTER_GEN_ON_OFF_SWITCH_CONFIG );
80116 zcl_specClusterInfo_t * info_conf = zigbee_endpoint_reserve_info (endpoint );
81117 info_conf -> clusterId = ZCL_CLUSTER_GEN_ON_OFF_SWITCH_CONFIG ;
82118 info_conf -> manuCode = MANUFACTURER_CODE_NONE ;
83- info_conf -> attrNum = 8 ;
119+ info_conf -> attrNum = SWITCH_CLUSTER_ONOFF_CONFIGURATION_ATTRS ;
84120 info_conf -> attrTbl = cluster -> attr_infos ;
85121 info_conf -> clusterRegisterFunc = zcl_onoff_configuration_register ;
86122 info_conf -> clusterAppCb = switch_cluster_callback_trampoline ;
@@ -90,22 +126,23 @@ void switch_cluster_add_to_endpoint(zigbee_switch_cluster *cluster, zigbee_endpo
90126 zcl_specClusterInfo_t * info = zigbee_endpoint_reserve_info (endpoint );
91127 info -> clusterId = ZCL_CLUSTER_GEN_ON_OFF ;
92128 info -> manuCode = MANUFACTURER_CODE_NONE ;
93- info -> attrNum = 0 ;
94- info -> attrTbl = NULL ;
129+ info -> attrNum = 1 ;
130+ info -> attrTbl = onOff_client_attrs ;
95131 info -> clusterRegisterFunc = zcl_onOff_register ;
96132 info -> clusterAppCb = switch_cluster_callback_trampoline ;
97133
98134 SETUP_ATTR_FOR_TABLE (cluster -> multistate_attr_infos , 0 , ZCL_ATTRID_MULTISTATE_INPUT_NUMBER_OF_STATES , ZCL_DATA_TYPE_UINT16 , ACCESS_CONTROL_READ , multistate_num_of_states );
99135 SETUP_ATTR_FOR_TABLE (cluster -> multistate_attr_infos , 1 , ZCL_ATTRID_MULTISTATE_INPUT_OUT_OF_SERVICE , ZCL_DATA_TYPE_BOOLEAN , ACCESS_CONTROL_READ , multistate_out_of_service );
100136 SETUP_ATTR_FOR_TABLE (cluster -> multistate_attr_infos , 2 , ZCL_ATTRID_MULTISTATE_INPUT_PRESENT_VALUE , ZCL_DATA_TYPE_UINT16 , ACCESS_CONTROL_READ | ACCESS_CONTROL_REPORTABLE , cluster -> multistate_state );
101137 SETUP_ATTR_FOR_TABLE (cluster -> multistate_attr_infos , 3 , ZCL_ATTRID_MULTISTATE_INPUT_STATUS_FLAGS , ZCL_DATA_TYPE_BITMAP8 , ACCESS_CONTROL_READ , multistate_flags );
138+ SETUP_ATTR_FOR_TABLE (cluster -> multistate_attr_infos , 4 , ZCL_ATTRID_GLOBAL_CLUSTER_REVISION , ZCL_DATA_TYPE_UINT16 , ACCESS_CONTROL_READ , multistate_input_cluster_revision );
102139
103140 // Output
104141 zigbee_endpoint_add_cluster (endpoint , 1 , ZCL_CLUSTER_GEN_MULTISTATE_INPUT_BASIC );
105142 zcl_specClusterInfo_t * info_multistate = zigbee_endpoint_reserve_info (endpoint );
106143 info_multistate -> clusterId = ZCL_CLUSTER_GEN_MULTISTATE_INPUT_BASIC ;
107144 info_multistate -> manuCode = MANUFACTURER_CODE_NONE ;
108- info_multistate -> attrNum = 4 ;
145+ info_multistate -> attrNum = 5 ;
109146 info_multistate -> attrTbl = cluster -> multistate_attr_infos ;
110147 info_multistate -> clusterRegisterFunc = zcl_multistate_input_register ;
111148 info_multistate -> clusterAppCb = NULL ;
@@ -115,10 +152,20 @@ void switch_cluster_add_to_endpoint(zigbee_switch_cluster *cluster, zigbee_endpo
115152 zcl_specClusterInfo_t * info_level = zigbee_endpoint_reserve_info (endpoint );
116153 info_level -> clusterId = ZCL_CLUSTER_GEN_LEVEL_CONTROL ;
117154 info_level -> manuCode = MANUFACTURER_CODE_NONE ;
118- info_level -> attrNum = 0 ;
119- info_level -> attrTbl = NULL ;
155+ info_level -> attrNum = 1 ;
156+ info_level -> attrTbl = level_client_attrs ;
120157 info_level -> clusterRegisterFunc = zcl_level_register ;
121158 info_level -> clusterAppCb = switch_cluster_callback_trampoline ;
159+
160+ // Scenes output for other devices
161+ zigbee_endpoint_add_cluster (endpoint , 0 , ZCL_CLUSTER_GEN_SCENES );
162+ zcl_specClusterInfo_t * info_scenes = zigbee_endpoint_reserve_info (endpoint );
163+ info_scenes -> clusterId = ZCL_CLUSTER_GEN_SCENES ;
164+ info_level -> manuCode = MANUFACTURER_CODE_NONE ;
165+ info_level -> attrNum = 1 ;
166+ info_level -> attrTbl = scenes_client_attrs ;
167+ info_level -> clusterRegisterFunc = zcl_scene_register ;
168+ info_level -> clusterAppCb = switch_cluster_callback_trampoline ;
122169}
123170
124171
@@ -476,8 +523,10 @@ void switch_cluster_on_write_attr(zigbee_switch_cluster *cluster)
476523 switch_cluster_store_attrs_to_nv (cluster );
477524}
478525
479- zigbee_switch_cluster_config nv_config_buffer ;
480-
526+ zigbee_switch_cluster_config nv_config_buffer = {
527+ .out_scene_group_id = 0xffff ,
528+ .scene_recall_time = 0xffff ,
529+ };
481530
482531void switch_cluster_store_attrs_to_nv (zigbee_switch_cluster * cluster )
483532{
@@ -488,6 +537,10 @@ void switch_cluster_store_attrs_to_nv(zigbee_switch_cluster *cluster)
488537 nv_config_buffer .button_long_press_duration = cluster -> button -> long_press_duration_ms ;
489538 nv_config_buffer .level_move_rate = cluster -> level_move -> rate ;
490539 nv_config_buffer .binded_mode = cluster -> binded_mode ;
540+ nv_config_buffer .out_scene_count = cluster -> out_scene_count ;
541+ nv_config_buffer .out_scene_start_offset = cluster -> out_scene_start_offset ;
542+ nv_config_buffer .out_scene_group_id = cluster -> out_scene_group_id ;
543+ nv_config_buffer .scene_recall_time = cluster -> scene_recall_time ;
491544
492545 nv_flashWriteNew (1 , NV_MODULE_APP , NV_ITEM_SWITCH_CLUSTER_DATA (cluster -> switch_idx ), sizeof (zigbee_switch_cluster_config ), (u8 * )& nv_config_buffer );
493546}
@@ -507,6 +560,10 @@ void switch_cluster_load_attrs_from_nv(zigbee_switch_cluster *cluster)
507560 cluster -> button -> long_press_duration_ms = nv_config_buffer .button_long_press_duration ;
508561 cluster -> level_move -> rate = nv_config_buffer .level_move_rate ;
509562 cluster -> binded_mode = nv_config_buffer .binded_mode ;
563+ cluster -> out_scene_count = nv_config_buffer .out_scene_count ;
564+ cluster -> out_scene_start_offset = nv_config_buffer .out_scene_start_offset ;
565+ cluster -> out_scene_group_id = nv_config_buffer .out_scene_group_id ;
566+ cluster -> scene_recall_time = nv_config_buffer .scene_recall_time ;
510567}
511568
512569void switch_cluster_report_action (zigbee_switch_cluster * cluster )
@@ -525,3 +582,118 @@ void switch_cluster_report_action(zigbee_switch_cluster *cluster)
525582 ZCL_CLUSTER_GEN_MULTISTATE_INPUT_BASIC , pAttrEntry -> id , pAttrEntry -> type , pAttrEntry -> data );
526583 }
527584}
585+
586+ static void switch_cluster_report_next_scene (zigbee_switch_cluster * cluster )
587+ {
588+ if (zb_isDeviceJoinedNwk ())
589+ {
590+ epInfo_t dstEpInfo ;
591+ TL_SETSTRUCTCONTENT (dstEpInfo , 0 );
592+
593+ dstEpInfo .profileId = HA_PROFILE_ID ;
594+ dstEpInfo .dstAddrMode = APS_DSTADDR_EP_NOTPRESETNT ;
595+
596+ zclAttrInfo_t * pAttrEntry = & cluster -> attr_infos [8 ];
597+ zcl_sendReportCmd (cluster -> endpoint , & dstEpInfo , TRUE, ZCL_FRAME_SERVER_CLIENT_DIR ,
598+ ZCL_CLUSTER_GEN_ON_OFF_SWITCH_CONFIG , pAttrEntry -> id , pAttrEntry -> type , pAttrEntry -> data );
599+ }
600+ }
601+
602+ static void switch_cluster_fixup_scene_attrs (zigbee_switch_cluster * cluster )
603+ {
604+ u8 next_normal = cluster -> out_scene_next - cluster -> out_scene_start_offset ;
605+ if (next_normal < cluster -> out_scene_count || next_normal == 0 )
606+ {
607+ return ;
608+ }
609+
610+ // Basically reset to 0
611+ cluster -> out_scene_next = cluster -> out_scene_start_offset ;
612+ switch_cluster_report_next_scene (cluster );
613+ }
614+
615+ static void switch_cluster_binding_recall_scene (zigbee_switch_cluster * cluster )
616+ {
617+ if (!switch_cluster_scenes_is_enabled (cluster ) || !zb_isDeviceJoinedNwk ())
618+ {
619+ return ;
620+ }
621+
622+ u8 next_scene = cluster -> out_scene_next ++ ;
623+ if (cluster -> out_scene_next - cluster -> out_scene_start_offset > cluster -> out_scene_count )
624+ cluster -> out_scene_next = cluster -> out_scene_start_offset ;
625+
626+ if (cluster -> out_scene_group_id != 0xffff )
627+ {
628+ epInfo_t dstEpInfo ;
629+ TL_SETSTRUCTCONTENT (dstEpInfo , 0 );
630+
631+ dstEpInfo .profileId = HA_PROFILE_ID ;
632+ dstEpInfo .dstAddrMode = APS_DSTADDR_EP_NOTPRESETNT ;
633+
634+ recallScene_t recallScene = {
635+ .groupId = cluster -> out_scene_group_id ,
636+ .sceneId = next_scene ,
637+ .transTime = 0xffff ,
638+ };
639+
640+ zcl_scene_recallScene (cluster -> endpoint , & dstEpInfo , true, ZCL_SEQ_NUM , & recallScene );
641+ }
642+ else
643+ {
644+ aps_data_req_t scenesInfo ;
645+ TL_SETSTRUCTCONTENT (scenesInfo , 0 );
646+
647+ scenesInfo .profile_id = HA_PROFILE_ID ;
648+ scenesInfo .cluster_id = ZCL_CLUSTER_GEN_SCENES ;
649+ scenesInfo .src_endpoint = cluster -> endpoint ;
650+ scenesInfo .dst_addr_mode = 0x00 ;
651+
652+ bind_dst_list_tbl bindTbl ;
653+
654+ if (aps_search_dst_from_bind_tbl (& scenesInfo , & bindTbl ) != APS_STATUS_SUCCESS )
655+ {
656+ goto out ;
657+ }
658+
659+ for (u8 i = 0 ; i < bindTbl .txCnt ; ++ i )
660+ {
661+ bind_dst_list * l = bindTbl .list + i ;
662+
663+ u16 group_id = 0xffff ;
664+
665+ epInfo_t dstEpInfo ;
666+ TL_SETSTRUCTCONTENT (dstEpInfo , 0 );
667+
668+ if (l -> dst_addr_mode == APS_BIND_DST_ADDR_GROUP )
669+ {
670+ group_id = l -> aps_addr .dst_group_addr ;
671+
672+ dstEpInfo .profileId = HA_PROFILE_ID ;
673+ dstEpInfo .dstAddrMode = APS_SHORT_GROUPADDR_NOEP ;
674+ dstEpInfo .dstAddr .shortAddr = l -> aps_addr .dst_group_addr ;
675+ }
676+ else
677+ {
678+ group_id = 0 ;
679+
680+ dstEpInfo .profileId = HA_PROFILE_ID ;
681+ dstEpInfo .dstAddrMode = APS_LONG_DSTADDR_WITHEP ;
682+ dstEpInfo .dstEp = l -> aps_addr .dst_endpoint ;
683+
684+ ZB_IEEE_ADDR_COPY (dstEpInfo .dstAddr .extAddr , l -> aps_addr .dst_ext_addr );
685+ }
686+
687+ recallScene_t recallScene = {
688+ .groupId = cluster -> out_scene_group_id ,
689+ .sceneId = next_scene ,
690+ .transTime = 0xffff ,
691+ };
692+
693+ zcl_scene_recallScene (cluster -> endpoint , & dstEpInfo , true, ZCL_SEQ_NUM , & recallScene );
694+ }
695+ }
696+
697+ out :
698+ switch_cluster_report_next_scene (cluster );
699+ }
0 commit comments