Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 1d2c6c1

Browse files
committedJan 28, 2025·
feat(zigbee): Added Endpoint for Window Covering (#10913)
1 parent 2f423af commit 1d2c6c1

File tree

5 files changed

+353
-6
lines changed

5 files changed

+353
-6
lines changed
 

‎libraries/Zigbee/src/Zigbee.h

+1
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,4 @@
1818
#include "ep/ZigbeeFlowSensor.h"
1919
#include "ep/ZigbeeOccupancySensor.h"
2020
#include "ep/ZigbeeCarbonDioxideSensor.h"
21+
#include "ep/ZigbeeWindowCovering.h"

‎libraries/Zigbee/src/ZigbeeEP.h

+1
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@ class ZigbeeEP {
104104
virtual void zbAttributeRead(uint16_t cluster_id, const esp_zb_zcl_attribute_t *attribute) {};
105105
virtual void zbReadBasicCluster(const esp_zb_zcl_attribute_t *attribute); //already implemented
106106
virtual void zbIdentify(const esp_zb_zcl_set_attr_value_message_t *message);
107+
virtual void zbWindowCoveringMovementCmd(const esp_zb_zcl_window_covering_movement_message_t *message) {};
107108

108109
void onIdentify(void (*callback)(uint16_t)) {
109110
_on_identify = callback;

‎libraries/Zigbee/src/ZigbeeHandlers.cpp

+30-6
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,20 @@ static esp_err_t zb_attribute_reporting_handler(const esp_zb_zcl_report_attr_mes
1010
static esp_err_t zb_cmd_read_attr_resp_handler(const esp_zb_zcl_cmd_read_attr_resp_message_t *message);
1111
static esp_err_t zb_configure_report_resp_handler(const esp_zb_zcl_cmd_config_report_resp_message_t *message);
1212
static esp_err_t zb_cmd_default_resp_handler(const esp_zb_zcl_cmd_default_resp_message_t *message);
13+
static esp_err_t zb_window_covering_movement_resp_handler(const esp_zb_zcl_window_covering_movement_message_t *message);
1314

1415
// Zigbee action handlers
1516
[[maybe_unused]]
1617
static esp_err_t zb_action_handler(esp_zb_core_action_callback_id_t callback_id, const void *message) {
1718
esp_err_t ret = ESP_OK;
1819
switch (callback_id) {
19-
case ESP_ZB_CORE_SET_ATTR_VALUE_CB_ID: ret = zb_attribute_set_handler((esp_zb_zcl_set_attr_value_message_t *)message); break;
20-
case ESP_ZB_CORE_REPORT_ATTR_CB_ID: ret = zb_attribute_reporting_handler((esp_zb_zcl_report_attr_message_t *)message); break;
21-
case ESP_ZB_CORE_CMD_READ_ATTR_RESP_CB_ID: ret = zb_cmd_read_attr_resp_handler((esp_zb_zcl_cmd_read_attr_resp_message_t *)message); break;
22-
case ESP_ZB_CORE_CMD_REPORT_CONFIG_RESP_CB_ID: ret = zb_configure_report_resp_handler((esp_zb_zcl_cmd_config_report_resp_message_t *)message); break;
23-
case ESP_ZB_CORE_CMD_DEFAULT_RESP_CB_ID: ret = zb_cmd_default_resp_handler((esp_zb_zcl_cmd_default_resp_message_t *)message); break;
24-
default: log_w("Receive unhandled Zigbee action(0x%x) callback", callback_id); break;
20+
case ESP_ZB_CORE_SET_ATTR_VALUE_CB_ID: ret = zb_attribute_set_handler((esp_zb_zcl_set_attr_value_message_t *)message); break;
21+
case ESP_ZB_CORE_REPORT_ATTR_CB_ID: ret = zb_attribute_reporting_handler((esp_zb_zcl_report_attr_message_t *)message); break;
22+
case ESP_ZB_CORE_CMD_READ_ATTR_RESP_CB_ID: ret = zb_cmd_read_attr_resp_handler((esp_zb_zcl_cmd_read_attr_resp_message_t *)message); break;
23+
case ESP_ZB_CORE_CMD_REPORT_CONFIG_RESP_CB_ID: ret = zb_configure_report_resp_handler((esp_zb_zcl_cmd_config_report_resp_message_t *)message); break;
24+
case ESP_ZB_CORE_CMD_DEFAULT_RESP_CB_ID: ret = zb_cmd_default_resp_handler((esp_zb_zcl_cmd_default_resp_message_t *)message); break;
25+
case ESP_ZB_CORE_WINDOW_COVERING_MOVEMENT_CB_ID: ret = zb_window_covering_movement_resp_handler((esp_zb_zcl_window_covering_movement_message_t *)message); break;
26+
default: log_w("Receive unhandled Zigbee action(0x%x) callback", callback_id); break;
2527
}
2628
return ret;
2729
}
@@ -138,4 +140,26 @@ static esp_err_t zb_cmd_default_resp_handler(const esp_zb_zcl_cmd_default_resp_m
138140
return ESP_OK;
139141
}
140142

143+
static esp_err_t zb_window_covering_movement_resp_handler(const esp_zb_zcl_window_covering_movement_message_t *message) {
144+
if (!message) {
145+
log_e("Empty message");
146+
}
147+
if (message->info.status != ESP_ZB_ZCL_STATUS_SUCCESS) {
148+
log_e("Received message: error status(%d)", message->info.status);
149+
}
150+
151+
log_v(
152+
"Received message: endpoint(%d), cluster(0x%x), command(0x%x), payload(%d)", message->info.dst_endpoint, message->info.cluster, message->command,
153+
message->payload
154+
);
155+
156+
// List through all Zigbee EPs and call the callback function, with the message
157+
for (std::list<ZigbeeEP *>::iterator it = Zigbee.ep_objects.begin(); it != Zigbee.ep_objects.end(); ++it) {
158+
if (message->info.dst_endpoint == (*it)->getEndpoint()) {
159+
(*it)->zbWindowCoveringMovementCmd(message); //method zbWindowCoveringMovementCmd must be implemented in specific EP class
160+
}
161+
}
162+
return ESP_OK;
163+
}
164+
141165
#endif //SOC_IEEE802154_SUPPORTED && CONFIG_ZB_ENABLED
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
2+
#include "ZigbeeWindowCovering.h"
3+
#if SOC_IEEE802154_SUPPORTED && CONFIG_ZB_ENABLED
4+
5+
#include "esp_zigbee_cluster.h"
6+
7+
ZigbeeWindowCovering::ZigbeeWindowCovering(uint8_t endpoint) : ZigbeeEP(endpoint) {
8+
_device_id = ESP_ZB_HA_WINDOW_COVERING_DEVICE_ID;
9+
10+
zigbee_window_covering_cfg_t window_covering_cfg = ZIGBEE_DEFAULT_WINDOW_COVERING_CONFIG();
11+
_cluster_list = zigbee_window_covering_clusters_create(&window_covering_cfg);
12+
13+
_ep_config = {.endpoint = _endpoint, .app_profile_id = ESP_ZB_AF_HA_PROFILE_ID, .app_device_id = ESP_ZB_HA_WINDOW_COVERING_DEVICE_ID, .app_device_version = 0};
14+
15+
// set default values
16+
_current_lift_percentage = ESP_ZB_ZCL_WINDOW_COVERING_CURRENT_POSITION_LIFT_PERCENTAGE_DEFAULT_VALUE;
17+
_current_tilt_percentage = ESP_ZB_ZCL_WINDOW_COVERING_CURRENT_POSITION_TILT_PERCENTAGE_DEFAULT_VALUE;
18+
_installed_open_limit_lift = ESP_ZB_ZCL_WINDOW_COVERING_INSTALLED_OPEN_LIMIT_LIFT_DEFAULT_VALUE;
19+
_installed_closed_limit_lift = ESP_ZB_ZCL_WINDOW_COVERING_INSTALLED_CLOSED_LIMIT_LIFT_DEFAULT_VALUE;
20+
_installed_open_limit_tilt = ESP_ZB_ZCL_WINDOW_COVERING_INSTALLED_OPEN_LIMIT_TILT_DEFAULT_VALUE;
21+
_installed_closed_limit_tilt = ESP_ZB_ZCL_WINDOW_COVERING_INSTALLED_CLOSED_LIMIT_TILT_DEFAULT_VALUE;
22+
_current_position_lift = ESP_ZB_ZCL_WINDOW_COVERING_CURRENT_POSITION_LIFT_DEFAULT_VALUE;
23+
_physical_closed_limit_lift = ESP_ZB_ZCL_WINDOW_COVERING_PHYSICAL_CLOSED_LIMIT_LIFT_DEFAULT_VALUE;
24+
_physical_closed_limit_tilt = ESP_ZB_ZCL_WINDOW_COVERING_PHY_CLOSED_LIMIT_TILT_DEFAULT_VALUE;
25+
}
26+
27+
// set attribute method -> method overridden in child class
28+
void ZigbeeWindowCovering::zbAttributeSet(const esp_zb_zcl_set_attr_value_message_t *message) {
29+
//check the data and call right method
30+
log_w("Received message ignored. Cluster ID: %d not supported for Window Covering", message->info.cluster);
31+
}
32+
33+
void ZigbeeWindowCovering::zbWindowCoveringMovementCmd(const esp_zb_zcl_window_covering_movement_message_t *message) {
34+
// check the data and call right method
35+
if (message->info.cluster == ESP_ZB_ZCL_CLUSTER_ID_WINDOW_COVERING) {
36+
if (message->command == ESP_ZB_ZCL_CMD_WINDOW_COVERING_UP_OPEN) {
37+
goToLiftPercentage(0);
38+
return;
39+
} else if (message->command == ESP_ZB_ZCL_CMD_WINDOW_COVERING_DOWN_CLOSE) {
40+
goToLiftPercentage(100);
41+
return;
42+
} else if (message->command == ESP_ZB_ZCL_CMD_WINDOW_COVERING_STOP) {
43+
stop();
44+
return;
45+
} else if (message->command == ESP_ZB_ZCL_CMD_WINDOW_COVERING_GO_TO_LIFT_PERCENTAGE) {
46+
if (_current_lift_percentage != message->payload.percentage_lift_value) {
47+
_current_lift_percentage = message->payload.percentage_lift_value;
48+
goToLiftPercentage(_current_lift_percentage);
49+
}
50+
return;
51+
} else {
52+
log_w("Received message ignored. Command: %d not supported for Window Covering", message->command);
53+
}
54+
} else {
55+
log_w("Received message ignored. Cluster ID: %d not supported for Window Covering", message->info.cluster);
56+
}
57+
}
58+
59+
void ZigbeeWindowCovering::goToLiftPercentage(uint8_t lift_percentage) {
60+
if (_on_go_to_lift_percentage) {
61+
_on_go_to_lift_percentage(lift_percentage);
62+
}
63+
}
64+
65+
void ZigbeeWindowCovering::stop() {
66+
if (_on_stop) {
67+
_on_stop();
68+
}
69+
}
70+
71+
void ZigbeeWindowCovering::setLiftPosition(uint16_t lift_position) {
72+
// Update all attributes
73+
_current_position_lift = lift_position;
74+
_current_lift_percentage = ((lift_position - _installed_open_limit_lift) * 100) / (_installed_closed_limit_lift - _installed_open_limit_lift);
75+
76+
log_v("Updating window covering lift position to %d (%d%)", _current_position_lift, _current_lift_percentage);
77+
// set lift state
78+
esp_zb_lock_acquire(portMAX_DELAY);
79+
esp_zb_zcl_set_attribute_val(
80+
_endpoint, ESP_ZB_ZCL_CLUSTER_ID_WINDOW_COVERING, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_WINDOW_COVERING_CURRENT_POSITION_LIFT_ID, &_current_position_lift, false
81+
);
82+
esp_zb_zcl_set_attribute_val(
83+
_endpoint, ESP_ZB_ZCL_CLUSTER_ID_WINDOW_COVERING, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_WINDOW_COVERING_CURRENT_POSITION_LIFT_PERCENTAGE_ID, &_current_lift_percentage, false
84+
);
85+
86+
esp_zb_zcl_report_attr_cmd_t report_attr_cmd;
87+
report_attr_cmd.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT;
88+
report_attr_cmd.direction = ESP_ZB_ZCL_CMD_DIRECTION_TO_CLI;
89+
report_attr_cmd.clusterID = ESP_ZB_ZCL_CLUSTER_ID_WINDOW_COVERING;
90+
report_attr_cmd.zcl_basic_cmd.src_endpoint = _endpoint;
91+
92+
report_attr_cmd.attributeID = ESP_ZB_ZCL_ATTR_WINDOW_COVERING_CURRENT_POSITION_LIFT_ID;
93+
esp_zb_zcl_report_attr_cmd_req(&report_attr_cmd);
94+
report_attr_cmd.attributeID = ESP_ZB_ZCL_ATTR_WINDOW_COVERING_CURRENT_POSITION_LIFT_PERCENTAGE_ID;
95+
esp_zb_zcl_report_attr_cmd_req(&report_attr_cmd);
96+
97+
esp_zb_lock_release();
98+
}
99+
100+
void ZigbeeWindowCovering::setCoveringType(WindowCoveringType covering_type) {
101+
esp_zb_attribute_list_t *window_covering_cluster =
102+
esp_zb_cluster_list_get_cluster(_cluster_list, ESP_ZB_ZCL_CLUSTER_ID_WINDOW_COVERING, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);
103+
esp_zb_cluster_update_attr(window_covering_cluster, ESP_ZB_ZCL_ATTR_WINDOW_COVERING_WINDOW_COVERING_TYPE_ID, (void *)&covering_type);
104+
}
105+
106+
void ZigbeeWindowCovering::setConfigStatus(bool operational, bool online, bool commands_reversed,
107+
bool lift_closed_loop, bool tilt_closed_loop,
108+
bool lift_encoder_controlled, bool tilt_encoder_controlled) {
109+
uint8_t config_status = (operational ? ESP_ZB_ZCL_ATTR_WINDOW_COVERING_CONFIG_OPERATIONAL : 0)
110+
| (online ? ESP_ZB_ZCL_ATTR_WINDOW_COVERING_CONFIG_ONLINE : 0)
111+
| (commands_reversed ? ESP_ZB_ZCL_ATTR_WINDOW_COVERING_CONFIG_REVERSE_COMMANDS : 0)
112+
| (lift_closed_loop ? ESP_ZB_ZCL_ATTR_WINDOW_COVERING_CONFIG_LIFT_CONTROL_IS_CLOSED_LOOP : 0)
113+
| (tilt_closed_loop ? ESP_ZB_ZCL_ATTR_WINDOW_COVERING_CONFIG_TILT_CONTROL_IS_CLOSED_LOOP : 0)
114+
| (lift_encoder_controlled ? ESP_ZB_ZCL_ATTR_WINDOW_COVERING_CONFIG_LIFT_ENCODER_CONTROLLED : 0)
115+
| (tilt_encoder_controlled ? ESP_ZB_ZCL_ATTR_WINDOW_COVERING_CONFIG_TILT_ENCODER_CONTROLLED : 0);
116+
117+
log_v("Updating window covering config status to %d", config_status);
118+
119+
esp_zb_attribute_list_t *window_covering_cluster =
120+
esp_zb_cluster_list_get_cluster(_cluster_list, ESP_ZB_ZCL_CLUSTER_ID_WINDOW_COVERING, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);
121+
esp_zb_cluster_update_attr(window_covering_cluster, ESP_ZB_ZCL_ATTR_WINDOW_COVERING_CONFIG_STATUS_ID, (void *)&config_status);
122+
}
123+
124+
void ZigbeeWindowCovering::setMode(bool motor_reversed, bool calibration_mode, bool maintenance_mode, bool leds_on) {
125+
uint8_t mode = (motor_reversed ? ESP_ZB_ZCL_ATTR_WINDOW_COVERING_TYPE_REVERSED_MOTOR_DIRECTION : 0)
126+
| (calibration_mode ? ESP_ZB_ZCL_ATTR_WINDOW_COVERING_TYPE_RUN_IN_CALIBRATION_MODE : 0)
127+
| (maintenance_mode ? ESP_ZB_ZCL_ATTR_WINDOW_COVERING_TYPE_MOTOR_IS_RUNNING_IN_MAINTENANCE_MODE : 0)
128+
| (leds_on ? ESP_ZB_ZCL_ATTR_WINDOW_COVERING_TYPE_LEDS_WILL_DISPLAY_FEEDBACK : 0);
129+
130+
log_v("Updating window covering mode to %d", mode);
131+
132+
esp_zb_attribute_list_t *window_covering_cluster =
133+
esp_zb_cluster_list_get_cluster(_cluster_list, ESP_ZB_ZCL_CLUSTER_ID_WINDOW_COVERING, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);
134+
esp_zb_cluster_update_attr(window_covering_cluster, ESP_ZB_ZCL_ATTR_WINDOW_COVERING_MODE_ID, (void *)&mode);
135+
}
136+
137+
void ZigbeeWindowCovering::setLimits(uint16_t installed_open_limit_lift, uint16_t installed_closed_limit_lift,
138+
uint16_t installed_open_limit_tilt, uint16_t installed_closed_limit_tilt) {
139+
_installed_open_limit_lift = installed_open_limit_lift;
140+
_installed_closed_limit_lift = installed_closed_limit_lift;
141+
_physical_closed_limit_lift = installed_closed_limit_lift;
142+
_installed_open_limit_tilt = installed_open_limit_tilt;
143+
_installed_closed_limit_tilt = installed_closed_limit_tilt;
144+
_physical_closed_limit_tilt = installed_closed_limit_tilt;
145+
146+
esp_zb_attribute_list_t *window_covering_cluster =
147+
esp_zb_cluster_list_get_cluster(_cluster_list, ESP_ZB_ZCL_CLUSTER_ID_WINDOW_COVERING, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);
148+
esp_zb_cluster_update_attr(window_covering_cluster, ESP_ZB_ZCL_ATTR_WINDOW_COVERING_INSTALLED_OPEN_LIMIT_LIFT_ID, (void *)&_installed_open_limit_lift);
149+
esp_zb_cluster_update_attr(window_covering_cluster, ESP_ZB_ZCL_ATTR_WINDOW_COVERING_INSTALLED_CLOSED_LIMIT_LIFT_ID, (void *)&_installed_closed_limit_lift);
150+
esp_zb_cluster_update_attr(window_covering_cluster, ESP_ZB_ZCL_ATTR_WINDOW_COVERING_INSTALLED_OPEN_LIMIT_TILT_ID, (void *)&_installed_open_limit_tilt);
151+
esp_zb_cluster_update_attr(window_covering_cluster, ESP_ZB_ZCL_ATTR_WINDOW_COVERING_INSTALLED_CLOSED_LIMIT_TILT_ID, (void *)&_installed_closed_limit_tilt);
152+
esp_zb_cluster_update_attr(window_covering_cluster, ESP_ZB_ZCL_ATTR_WINDOW_COVERING_PHYSICAL_CLOSED_LIMIT_LIFT_ID, (void *)&_physical_closed_limit_lift);
153+
esp_zb_cluster_update_attr(window_covering_cluster, ESP_ZB_ZCL_ATTR_WINDOW_COVERING_PHY_CLOSED_LIMIT_TILT_ID, (void *)&_physical_closed_limit_tilt);
154+
}
155+
156+
esp_zb_cluster_list_t *ZigbeeWindowCovering::zigbee_window_covering_clusters_create(zigbee_window_covering_cfg_t *window_covering_cfg) {
157+
esp_zb_attribute_list_t *esp_zb_basic_cluster = esp_zb_basic_cluster_create(&window_covering_cfg->basic_cfg);
158+
esp_zb_attribute_list_t *esp_zb_identify_cluster = esp_zb_identify_cluster_create(&window_covering_cfg->identify_cfg);
159+
esp_zb_attribute_list_t *esp_zb_groups_cluster = esp_zb_groups_cluster_create(&window_covering_cfg->groups_cfg);
160+
esp_zb_attribute_list_t *esp_zb_scenes_cluster = esp_zb_scenes_cluster_create(&window_covering_cfg->scenes_cfg);
161+
esp_zb_attribute_list_t *esp_zb_window_covering_cluster = esp_zb_window_covering_cluster_create(&window_covering_cfg->window_covering_cfg);
162+
163+
// ------------------------------ Create cluster list ------------------------------
164+
esp_zb_cluster_list_t *esp_zb_cluster_list = esp_zb_zcl_cluster_list_create();
165+
esp_zb_cluster_list_add_basic_cluster(esp_zb_cluster_list, esp_zb_basic_cluster, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);
166+
esp_zb_cluster_list_add_identify_cluster(esp_zb_cluster_list, esp_zb_identify_cluster, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);
167+
esp_zb_cluster_list_add_groups_cluster(esp_zb_cluster_list, esp_zb_groups_cluster, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);
168+
esp_zb_cluster_list_add_scenes_cluster(esp_zb_cluster_list, esp_zb_scenes_cluster, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);
169+
esp_zb_cluster_list_add_window_covering_cluster(esp_zb_cluster_list, esp_zb_window_covering_cluster, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);
170+
171+
esp_zb_window_covering_cluster_add_attr(esp_zb_window_covering_cluster, ESP_ZB_ZCL_ATTR_WINDOW_COVERING_CURRENT_POSITION_LIFT_PERCENTAGE_ID, &_current_lift_percentage);
172+
esp_zb_window_covering_cluster_add_attr(esp_zb_window_covering_cluster, ESP_ZB_ZCL_ATTR_WINDOW_COVERING_INSTALLED_OPEN_LIMIT_LIFT_ID, &_installed_open_limit_lift);
173+
esp_zb_window_covering_cluster_add_attr(esp_zb_window_covering_cluster, ESP_ZB_ZCL_ATTR_WINDOW_COVERING_INSTALLED_CLOSED_LIMIT_LIFT_ID, &_installed_closed_limit_lift);
174+
esp_zb_window_covering_cluster_add_attr(esp_zb_window_covering_cluster, ESP_ZB_ZCL_ATTR_WINDOW_COVERING_INSTALLED_OPEN_LIMIT_TILT_ID, &_installed_open_limit_tilt);
175+
esp_zb_window_covering_cluster_add_attr(esp_zb_window_covering_cluster, ESP_ZB_ZCL_ATTR_WINDOW_COVERING_INSTALLED_CLOSED_LIMIT_TILT_ID, &_installed_closed_limit_tilt);
176+
esp_zb_window_covering_cluster_add_attr(esp_zb_window_covering_cluster, ESP_ZB_ZCL_ATTR_WINDOW_COVERING_CURRENT_POSITION_LIFT_ID, &_current_position_lift);
177+
esp_zb_window_covering_cluster_add_attr(esp_zb_window_covering_cluster, ESP_ZB_ZCL_ATTR_WINDOW_COVERING_PHYSICAL_CLOSED_LIMIT_LIFT_ID, &_physical_closed_limit_lift);
178+
return esp_zb_cluster_list;
179+
}
180+
181+
#endif // SOC_IEEE802154_SUPPORTED
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
/* Class of Zigbee Window Covering endpoint inherited from common EP class */
2+
3+
#pragma once
4+
5+
#include "soc/soc_caps.h"
6+
#include "sdkconfig.h"
7+
#if SOC_IEEE802154_SUPPORTED && CONFIG_ZB_ENABLED
8+
9+
#include "ZigbeeEP.h"
10+
#include "ha/esp_zigbee_ha_standard.h"
11+
12+
/**
13+
* @brief Zigbee HA standard window covering device clusters.
14+
* Added here as not supported by ESP Zigbee library.
15+
*
16+
*
17+
*/
18+
typedef struct zigbee_window_covering_cfg_s {
19+
esp_zb_basic_cluster_cfg_t basic_cfg; /*!< Basic cluster configuration, @ref esp_zb_basic_cluster_cfg_s */
20+
esp_zb_identify_cluster_cfg_t identify_cfg; /*!< Identify cluster configuration, @ref esp_zb_identify_cluster_cfg_s */
21+
esp_zb_groups_cluster_cfg_t groups_cfg; /*!< Groups cluster configuration, @ref esp_zb_groups_cluster_cfg_s */
22+
esp_zb_scenes_cluster_cfg_t scenes_cfg; /*!< Scenes cluster configuration, @ref esp_zb_scenes_cluster_cfg_s */
23+
esp_zb_window_covering_cluster_cfg_t window_covering_cfg; /*!< Window covering cluster configuration, @ref esp_zb_window_covering_cluster_cfg_s */
24+
} zigbee_window_covering_cfg_t;
25+
26+
enum WindowCoveringType {
27+
ROLLERSHADE = ESP_ZB_ZCL_ATTR_WINDOW_COVERING_TYPE_ROLLERSHADE,
28+
ROLLERSHADE_2_MOTOR = ESP_ZB_ZCL_ATTR_WINDOW_COVERING_TYPE_ROLLERSHADE_2_MOTOR,
29+
ROLLERSHADE_EXTERIOR = ESP_ZB_ZCL_ATTR_WINDOW_COVERING_TYPE_ROLLERSHADE_EXTERIOR,
30+
ROLLERSHADE_EXTERIOR_2_MOTOR = ESP_ZB_ZCL_ATTR_WINDOW_COVERING_TYPE_ROLLERSHADE_EXTERIOR_2_MOTOR,
31+
DRAPERY = ESP_ZB_ZCL_ATTR_WINDOW_COVERING_TYPE_DRAPERY,
32+
AWNING = ESP_ZB_ZCL_ATTR_WINDOW_COVERING_TYPE_AWNING,
33+
SHUTTER = ESP_ZB_ZCL_ATTR_WINDOW_COVERING_TYPE_SHUTTER,
34+
BLIND_TILT_ONLY = ESP_ZB_ZCL_ATTR_WINDOW_COVERING_TYPE_TILT_BLIND_TILT_ONLY,
35+
BLIND_LIFT_AND_TILT = ESP_ZB_ZCL_ATTR_WINDOW_COVERING_TYPE_TILT_BLIND_LIFT_AND_TILT,
36+
PROJECTOR_SCREEN = ESP_ZB_ZCL_ATTR_WINDOW_COVERING_TYPE_PROJECTOR_SCREEN,
37+
};
38+
39+
/**
40+
* @brief Zigbee HA standard window covering device default config value.
41+
* Added here as not supported by ESP Zigbee library.
42+
*
43+
*/
44+
// clang-format off
45+
#define ZIGBEE_DEFAULT_WINDOW_COVERING_CONFIG() \
46+
{ \
47+
.basic_cfg = \
48+
{ \
49+
.zcl_version = ESP_ZB_ZCL_BASIC_ZCL_VERSION_DEFAULT_VALUE, \
50+
.power_source = ESP_ZB_ZCL_BASIC_POWER_SOURCE_DEFAULT_VALUE, \
51+
}, \
52+
.identify_cfg = \
53+
{ \
54+
.identify_time = ESP_ZB_ZCL_IDENTIFY_IDENTIFY_TIME_DEFAULT_VALUE, \
55+
}, \
56+
.groups_cfg = \
57+
{ \
58+
.groups_name_support_id = ESP_ZB_ZCL_GROUPS_NAME_SUPPORT_DEFAULT_VALUE, \
59+
}, \
60+
.scenes_cfg = \
61+
{ \
62+
.scenes_count = ESP_ZB_ZCL_SCENES_SCENE_COUNT_DEFAULT_VALUE, \
63+
.current_scene = ESP_ZB_ZCL_SCENES_CURRENT_SCENE_DEFAULT_VALUE, \
64+
.current_group = ESP_ZB_ZCL_SCENES_CURRENT_GROUP_DEFAULT_VALUE, \
65+
.scene_valid = ESP_ZB_ZCL_SCENES_SCENE_VALID_DEFAULT_VALUE, \
66+
.name_support = ESP_ZB_ZCL_SCENES_NAME_SUPPORT_DEFAULT_VALUE, \
67+
}, \
68+
.window_covering_cfg = \
69+
{ \
70+
.covering_type = ESP_ZB_ZCL_WINDOW_COVERING_WINDOW_COVERING_TYPE_DEFAULT_VALUE, \
71+
.covering_status = ESP_ZB_ZCL_WINDOW_COVERING_CONFIG_STATUS_DEFAULT_VALUE, \
72+
.covering_mode = ESP_ZB_ZCL_WINDOW_COVERING_MODE_DEFAULT_VALUE, \
73+
}, \
74+
}
75+
// clang-format on
76+
77+
class ZigbeeWindowCovering : public ZigbeeEP {
78+
public:
79+
ZigbeeWindowCovering(uint8_t endpoint);
80+
~ZigbeeWindowCovering();
81+
82+
void onGoToLiftPercentage(void (*callback)(uint8_t)) {
83+
_on_go_to_lift_percentage = callback;
84+
}
85+
86+
void onStop(void (*callback)()) {
87+
_on_stop = callback;
88+
}
89+
90+
void setLiftPosition(uint16_t lift_position);
91+
92+
// Set the window covering type, see esp_zb_zcl_window_covering_window_covering_type_t
93+
void setCoveringType(WindowCoveringType covering_type);
94+
95+
// Set window covering config/status, see esp_zb_zcl_window_covering_config_status_t
96+
void setConfigStatus(bool operational, bool online, bool commands_reversed,
97+
bool lift_closed_loop, bool tilt_closed_loop,
98+
bool lift_encoder_controlled, bool tilt_encoder_controlled);
99+
100+
// Set configuration mode of window covering, see esp_zb_zcl_window_covering_mode_t
101+
void setMode(bool motor_reversed, bool calibration_mode, bool maintenance_mode, bool leds_on);
102+
103+
// Set limits of motion, see esp_zb_zcl_window_covering_info_attr_t
104+
void setLimits(uint16_t installed_open_limit_lift, uint16_t installed_closed_limit_lift,
105+
uint16_t installed_open_limit_tilt, uint16_t installed_closed_limit_tilt);
106+
private:
107+
void zbAttributeSet(const esp_zb_zcl_set_attr_value_message_t *message) override;
108+
void zbWindowCoveringMovementCmd(const esp_zb_zcl_window_covering_movement_message_t *message) override;
109+
110+
void goToLiftPercentage(uint8_t);
111+
void stop();
112+
113+
// callback function to be called on lift percentage change (lift percentage)
114+
void (*_on_go_to_lift_percentage)(uint8_t);
115+
void (*_on_stop)();
116+
117+
/**
118+
* @brief Create a standard HA window covering cluster list.
119+
* Added here as not supported by ESP Zigbee library.
120+
*
121+
* @note This contains basic, identify, groups, scenes, window_covering, as server side.
122+
* @param[in] window_covering_cfg Configuration parameters for this cluster lists defined by @ref zigbee_window_covering_cfg_t
123+
*
124+
* @return Pointer to cluster list @ref esp_zb_cluster_list_s
125+
*
126+
*/
127+
esp_zb_cluster_list_t *zigbee_window_covering_clusters_create(zigbee_window_covering_cfg_t *window_covering_cfg);
128+
129+
uint8_t _current_lift_percentage;
130+
uint8_t _current_tilt_percentage;
131+
uint16_t _current_position_lift;
132+
uint16_t _installed_open_limit_lift;
133+
uint16_t _installed_closed_limit_lift;
134+
uint16_t _installed_open_limit_tilt;
135+
uint16_t _installed_closed_limit_tilt;
136+
uint16_t _physical_closed_limit_lift;
137+
uint16_t _physical_closed_limit_tilt;
138+
};
139+
140+
#endif // SOC_IEEE802154_SUPPORTED

0 commit comments

Comments
 (0)
Please sign in to comment.