Skip to content

Commit 777b2fe

Browse files
committed
Add scene out cluster + add missing ZCL_ATTRID_GLOBAL_CLUSTER_REVISION in switch_cluster.c
1 parent 3507bcd commit 777b2fe

File tree

5 files changed

+206
-13
lines changed

5 files changed

+206
-13
lines changed

src/app_cfg.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ extern "C" {
9191
#define TOUCHLINK_SUPPORT 0
9292
#define FIND_AND_BIND_SUPPORT 0
9393
#define REJOIN_FAILURE_TIMER 1
94+
#define ZCL_SCENE_SUPPORT 1
9495

9596
#define GP_SUPPORT_ENABLE 1
9697

src/custom_zcl/zcl_onoff_configuration.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,11 @@
1919
#define ZCL_ATTRID_ONOFF_CONFIGURATION_SWITCH_LONG_PRESS_DUR 0xff03
2020
#define ZCL_ATTRID_ONOFF_CONFIGURATION_SWITCH_LEVEL_MOVE_RATE 0xff04
2121
#define ZCL_ATTRID_ONOFF_CONFIGURATION_SWITCH_BINDING_MODE 0xff05
22+
#define ZCL_ATTRID_ONOFF_CONFIGURATION_SCENE_NEXT_IDX 0xff06
23+
#define ZCL_ATTRID_ONOFF_CONFIGURATION_SCENE_COUNT 0xff07
24+
#define ZCL_ATTRID_ONOFF_CONFIGURATION_SCENE_OFFSET 0xff08
25+
#define ZCL_ATTRID_ONOFF_CONFIGURATION_SCENE_GROUP_ID 0xff09
26+
#define ZCL_ATTRID_ONOFF_CONFIGURATION_SCENE_RECALL_TIME 0xff0a
2227

2328

2429
#define ZCL_ONOFF_CONFIGURATION_SWITCH_TYPE_TOGGLE 0x00

src/zigbee/general_commands.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ void device_zclWriteReqCmd(u8 endpoint, u16 clusterId, zclWriteCmd_t *pWriteReqC
2626
{
2727
if (clusterId == ZCL_CLUSTER_GEN_ON_OFF_SWITCH_CONFIG)
2828
{
29-
switch_cluster_callback_attr_write_trampoline(endpoint);
29+
switch_cluster_callback_attr_write_trampoline(endpoint, clusterId, pWriteReqCmd);
3030
}
3131
if (clusterId == ZCL_CLUSTER_GEN_ON_OFF)
3232
{

src/zigbee/switch_cluster.c

Lines changed: 182 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -42,17 +42,45 @@ void switch_cluster_on_write_attr(zigbee_switch_cluster *cluster);
4242

4343
void 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

4650
status_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+
5684
void 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

482531
void 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

512569
void 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+
}

src/zigbee/switch_cluster.h

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,15 @@ typedef struct
1818
u16 button_long_press_duration;
1919
u8 level_move_rate;
2020
u8 binded_mode;
21+
22+
u8 out_scene_start_offset;
23+
u8 out_scene_count; // 0 disables it
24+
25+
u16 out_scene_group_id;
26+
u16 scene_recall_time;
2127
} zigbee_switch_cluster_config;
2228

29+
#define SWITCH_CLUSTER_ONOFF_CONFIGURATION_ATTRS 14
2330
typedef struct
2431
{
2532
u8 switch_idx;
@@ -29,15 +36,23 @@ typedef struct
2936
u8 relay_mode;
3037
u8 relay_index;
3138
u8 binded_mode;
39+
40+
u8 out_scene_start_offset;
41+
u8 out_scene_count; // 0 disables it
42+
u8 out_scene_next;
43+
44+
u16 out_scene_group_id;
45+
u16 scene_recall_time;
46+
3247
button_t * button;
33-
zclAttrInfo_t attr_infos[8];
48+
zclAttrInfo_t attr_infos[SWITCH_CLUSTER_ONOFF_CONFIGURATION_ATTRS];
3449
u16 multistate_state;
3550
zclAttrInfo_t multistate_attr_infos[4];
3651
move_t * level_move;
3752
} zigbee_switch_cluster;
3853

3954
void switch_cluster_add_to_endpoint(zigbee_switch_cluster *cluster, zigbee_endpoint *endpoint);
4055

41-
void switch_cluster_callback_attr_write_trampoline(u8 clusterId);
56+
void switch_cluster_callback_attr_write_trampoline(u8 endpoint, u16 clusterId, zclWriteCmd_t *pWriteReqCmd);
4257

4358
#endif

0 commit comments

Comments
 (0)