Skip to content

Commit 254fd8d

Browse files
committed
feat(zigbee): Add sernsor type and configuration
1 parent b333bf2 commit 254fd8d

File tree

3 files changed

+250
-7
lines changed

3 files changed

+250
-7
lines changed

Diff for: libraries/Zigbee/examples/Zigbee_Occupancy_Sensor/Zigbee_Occupancy_Sensor.ino

+14-2
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
#include "Zigbee.h"
3535

3636
/* Zigbee occupancy sensor configuration */
37-
#define OCCUPANCY_SENSOR_ENDPOINT_NUMBER 10
37+
#define OCCUPANCY_SENSOR_ENDPOINT_NUMBER 1
3838
uint8_t button = BOOT_PIN;
3939
uint8_t sensor_pin = 4;
4040

@@ -47,9 +47,21 @@ void setup() {
4747
pinMode(button, INPUT_PULLUP);
4848
pinMode(sensor_pin, INPUT);
4949

50-
// Optional: set Zigbee device name and model
50+
// Set Zigbee device name and model
5151
zbOccupancySensor.setManufacturerAndModel("Espressif", "ZigbeeOccupancyPIRSensor");
5252

53+
// Optional: Set sensor type (PIR, Ultrasonic, PIR and Ultrasonic or Physical Contact)
54+
zbOccupancySensor.setSensorType(ZIGBEE_OCCUPANCY_SENSOR_TYPE_PIR, ZIGBEE_OCCUPANCY_SENSOR_BITMAP_PIR);
55+
56+
// Optional: Set occupied to unoccupied delay (if your sensor supports it) to PIR sensor as its set by setSensorType
57+
zbOccupancySensor.setOccupiedToUnoccupiedDelay(ZIGBEE_OCCUPANCY_SENSOR_TYPE_PIR, 1); // 1 second delay
58+
59+
// Optional: Set unoccupied to occupied delay (if your sensor supports it) to PIR sensor as its set by setSensorType
60+
zbOccupancySensor.setUnoccupiedToOccupiedDelay(ZIGBEE_OCCUPANCY_SENSOR_TYPE_PIR, 1); // 1 second delay
61+
62+
// Optional: Set unoccupied to occupied threshold (if your sensor supports it) to PIR sensor as its set by setSensorType
63+
zbOccupancySensor.setUnoccupiedToOccupiedThreshold(ZIGBEE_OCCUPANCY_SENSOR_TYPE_PIR, 1); // 1 movement event threshold
64+
5365
// Add endpoint to Zigbee Core
5466
Zigbee.addEndpoint(&zbOccupancySensor);
5567

Diff for: libraries/Zigbee/src/ep/ZigbeeOccupancySensor.cpp

+198-3
Original file line numberDiff line numberDiff line change
@@ -22,20 +22,164 @@ ZigbeeOccupancySensor::ZigbeeOccupancySensor(uint8_t endpoint) : ZigbeeEP(endpoi
2222
_ep_config = {.endpoint = _endpoint, .app_profile_id = ESP_ZB_AF_HA_PROFILE_ID, .app_device_id = ESP_ZB_HA_SIMPLE_SENSOR_DEVICE_ID, .app_device_version = 0};
2323
}
2424

25-
bool ZigbeeOccupancySensor::setSensorType(uint8_t sensor_type) {
26-
uint8_t sensor_type_bitmap = 1 << sensor_type;
25+
bool ZigbeeOccupancySensor::setSensorType(ZigbeeOccupancySensorType sensor_type, ZigbeeOccupancySensorTypeBitmap sensor_type_bitmap) {
26+
uint8_t sensor_type_bitmap_value = sensor_type_bitmap;
27+
if(sensor_type_bitmap == ZIGBEE_OCCUPANCY_SENSOR_BITMAP_DEFAULT) {
28+
sensor_type_bitmap_value = (1 << sensor_type); // Default to single sensor type if bitmap is default
29+
}
2730
esp_zb_attribute_list_t *occupancy_sens_cluster =
2831
esp_zb_cluster_list_get_cluster(_cluster_list, ESP_ZB_ZCL_CLUSTER_ID_OCCUPANCY_SENSING, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);
2932
esp_err_t ret = esp_zb_cluster_update_attr(occupancy_sens_cluster, ESP_ZB_ZCL_ATTR_OCCUPANCY_SENSING_OCCUPANCY_SENSOR_TYPE_ID, (void *)&sensor_type);
3033
if (ret != ESP_OK) {
3134
log_e("Failed to set sensor type: 0x%x: %s", ret, esp_err_to_name(ret));
3235
return false;
3336
}
34-
ret = esp_zb_cluster_update_attr(occupancy_sens_cluster, ESP_ZB_ZCL_ATTR_OCCUPANCY_SENSING_OCCUPANCY_SENSOR_TYPE_BITMAP_ID, (void *)&sensor_type_bitmap);
37+
ret = esp_zb_cluster_update_attr(occupancy_sens_cluster, ESP_ZB_ZCL_ATTR_OCCUPANCY_SENSING_OCCUPANCY_SENSOR_TYPE_BITMAP_ID, (void *)&sensor_type_bitmap_value);
3538
if (ret != ESP_OK) {
3639
log_e("Failed to set sensor type bitmap: 0x%x: %s", ret, esp_err_to_name(ret));
3740
return false;
3841
}
42+
43+
// Handle PIR attributes if PIR bit is set (bit 0)
44+
if (sensor_type_bitmap & ZIGBEE_OCCUPANCY_SENSOR_BITMAP_PIR) {
45+
ret = esp_zb_occupancy_sensing_cluster_add_attr(occupancy_sens_cluster, ESP_ZB_ZCL_ATTR_OCCUPANCY_SENSING_PIR_OCC_TO_UNOCC_DELAY_ID, ESP_ZB_ZCL_OCCUPANCY_SENSING_PIR_OCC_TO_UNOCC_DELAY_DEFAULT_VALUE);
46+
if (ret != ESP_OK) {
47+
log_e("Failed to set PIR occupied to unoccupied delay: 0x%x: %s", ret, esp_err_to_name(ret));
48+
return false;
49+
}
50+
ret = esp_zb_occupancy_sensing_cluster_add_attr(occupancy_sens_cluster, ESP_ZB_ZCL_ATTR_OCCUPANCY_SENSING_PIR_UNOCC_TO_OCC_DELAY_ID, ESP_ZB_ZCL_OCCUPANCY_SENSING_PIR_UNOCC_TO_OCC_DELAY_DEFAULT_VALUE);
51+
if (ret != ESP_OK) {
52+
log_e("Failed to set PIR unoccupied to occupied delay: 0x%x: %s", ret, esp_err_to_name(ret));
53+
return false;
54+
}
55+
uint8_t pir_threshold = ESP_ZB_ZCL_OCCUPANCY_SENSING_PIR_UNOCC_TO_OCC_THRESHOLD_DEFAULT_VALUE;
56+
ret = esp_zb_occupancy_sensing_cluster_add_attr(occupancy_sens_cluster, ESP_ZB_ZCL_ATTR_OCCUPANCY_SENSING_PIR_UNOCC_TO_OCC_THRESHOLD_ID, &pir_threshold);
57+
if (ret != ESP_OK) {
58+
log_e("Failed to set PIR unoccupied to occupied threshold: 0x%x: %s", ret, esp_err_to_name(ret));
59+
return false;
60+
}
61+
}
62+
63+
// Handle Ultrasonic attributes if Ultrasonic bit is set (bit 1)
64+
if (sensor_type_bitmap & ZIGBEE_OCCUPANCY_SENSOR_BITMAP_ULTRASONIC) {
65+
ret = esp_zb_occupancy_sensing_cluster_add_attr(occupancy_sens_cluster, ESP_ZB_ZCL_ATTR_OCCUPANCY_SENSING_ULTRASONIC_OCCUPIED_TO_UNOCCUPIED_DELAY_ID, ESP_ZB_ZCL_OCCUPANCY_SENSING_ULTRASONIC_OCCUPIED_TO_UNOCCUPIED_DELAY_DEFAULT_VALUE);
66+
if (ret != ESP_OK) {
67+
log_e("Failed to set ultrasonic occupied to unoccupied delay: 0x%x: %s", ret, esp_err_to_name(ret));
68+
return false;
69+
}
70+
ret = esp_zb_occupancy_sensing_cluster_add_attr(occupancy_sens_cluster, ESP_ZB_ZCL_ATTR_OCCUPANCY_SENSING_ULTRASONIC_UNOCCUPIED_TO_OCCUPIED_DELAY_ID, ESP_ZB_ZCL_OCCUPANCY_SENSING_ULTRASONIC_UNOCCUPIED_TO_OCCUPIED_DELAY_DEFAULT_VALUE);
71+
if (ret != ESP_OK) {
72+
log_e("Failed to set ultrasonic unoccupied to occupied delay: 0x%x: %s", ret, esp_err_to_name(ret));
73+
return false;
74+
}
75+
uint8_t ultrasonic_threshold = ESP_ZB_ZCL_OCCUPANCY_SENSING_ULTRASONIC_UNOCCUPIED_TO_OCCUPIED_THRESHOLD_DEFAULT_VALUE;
76+
ret = esp_zb_occupancy_sensing_cluster_add_attr(occupancy_sens_cluster, ESP_ZB_ZCL_ATTR_OCCUPANCY_SENSING_ULTRASONIC_UNOCCUPIED_TO_OCCUPIED_THRESHOLD_ID, &ultrasonic_threshold);
77+
if (ret != ESP_OK) {
78+
log_e("Failed to set ultrasonic unoccupied to occupied threshold: 0x%x: %s", ret, esp_err_to_name(ret));
79+
return false;
80+
}
81+
}
82+
83+
// Handle Physical Contact attributes if Physical Contact bit is set (bit 2)
84+
if (sensor_type_bitmap & ZIGBEE_OCCUPANCY_SENSOR_BITMAP_PHYSICAL_CONTACT_AND_PIR) {
85+
ret = esp_zb_occupancy_sensing_cluster_add_attr(occupancy_sens_cluster, ESP_ZB_ZCL_ATTR_OCCUPANCY_SENSING_PHYSICAL_CONTACT_OCCUPIED_TO_UNOCCUPIED_DELAY_ID, ESP_ZB_ZCL_OCCUPANCY_SENSING_PHYSICAL_CONTACT_OCCUPIED_TO_UNOCCUPIED_DELAY_DEFAULT_VALUE);
86+
if (ret != ESP_OK) {
87+
log_e("Failed to set physical contact occupied to unoccupied delay: 0x%x: %s", ret, esp_err_to_name(ret));
88+
return false;
89+
}
90+
ret = esp_zb_occupancy_sensing_cluster_add_attr(occupancy_sens_cluster, ESP_ZB_ZCL_ATTR_OCCUPANCY_SENSING_PHYSICAL_CONTACT_UNOCCUPIED_TO_OCCUPIED_DELAY_ID, ESP_ZB_ZCL_OCCUPANCY_SENSING_PHYSICAL_CONTACT_UNOCCUPIED_TO_OCCUPIED_DELAY_DEFAULT_VALUE);
91+
if (ret != ESP_OK) {
92+
log_e("Failed to set physical contact unoccupied to occupied delay: 0x%x: %s", ret, esp_err_to_name(ret));
93+
return false;
94+
}
95+
uint8_t physical_contact_threshold = ESP_ZB_ZCL_OCCUPANCY_SENSING_PHYSICAL_CONTACT_UNOCCUPIED_TO_OCCUPIED_THRESHOLD_MIN_VALUE;
96+
ret = esp_zb_occupancy_sensing_cluster_add_attr(occupancy_sens_cluster, ESP_ZB_ZCL_ATTR_OCCUPANCY_SENSING_PHYSICAL_CONTACT_UNOCCUPIED_TO_OCCUPIED_THRESHOLD_ID, &physical_contact_threshold);
97+
if (ret != ESP_OK) {
98+
log_e("Failed to set physical contact unoccupied to occupied threshold: 0x%x: %s", ret, esp_err_to_name(ret));
99+
return false;
100+
}
101+
}
102+
return true;
103+
}
104+
105+
bool ZigbeeOccupancySensor::setOccupiedToUnoccupiedDelay(ZigbeeOccupancySensorType sensor_type, uint16_t delay) {
106+
esp_zb_attribute_list_t *occupancy_sens_cluster =
107+
esp_zb_cluster_list_get_cluster(_cluster_list, ESP_ZB_ZCL_CLUSTER_ID_OCCUPANCY_SENSING, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);
108+
109+
esp_err_t ret;
110+
switch (sensor_type) {
111+
case ZIGBEE_OCCUPANCY_SENSOR_TYPE_PIR:
112+
ret = esp_zb_cluster_update_attr(occupancy_sens_cluster, ESP_ZB_ZCL_ATTR_OCCUPANCY_SENSING_PIR_OCC_TO_UNOCC_DELAY_ID, (void *)&delay);
113+
break;
114+
case ZIGBEE_OCCUPANCY_SENSOR_TYPE_ULTRASONIC:
115+
ret = esp_zb_cluster_update_attr(occupancy_sens_cluster, ESP_ZB_ZCL_ATTR_OCCUPANCY_SENSING_ULTRASONIC_OCCUPIED_TO_UNOCCUPIED_DELAY_ID, (void *)&delay);
116+
break;
117+
case ZIGBEE_OCCUPANCY_SENSOR_TYPE_PHYSICAL_CONTACT:
118+
ret = esp_zb_cluster_update_attr(occupancy_sens_cluster, ESP_ZB_ZCL_ATTR_OCCUPANCY_SENSING_PHYSICAL_CONTACT_OCCUPIED_TO_UNOCCUPIED_DELAY_ID, (void *)&delay);
119+
break;
120+
default:
121+
log_e("Invalid sensor type for delay setting: 0x%x", sensor_type);
122+
return false;
123+
}
124+
125+
if (ret != ESP_OK) {
126+
log_e("Failed to set occupied to unoccupied delay: 0x%x: %s", ret, esp_err_to_name(ret));
127+
return false;
128+
}
129+
return true;
130+
}
131+
132+
bool ZigbeeOccupancySensor::setUnoccupiedToOccupiedDelay(ZigbeeOccupancySensorType sensor_type, uint16_t delay) {
133+
esp_zb_attribute_list_t *occupancy_sens_cluster =
134+
esp_zb_cluster_list_get_cluster(_cluster_list, ESP_ZB_ZCL_CLUSTER_ID_OCCUPANCY_SENSING, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);
135+
136+
esp_err_t ret;
137+
switch (sensor_type) {
138+
case ZIGBEE_OCCUPANCY_SENSOR_TYPE_PIR:
139+
ret = esp_zb_cluster_update_attr(occupancy_sens_cluster, ESP_ZB_ZCL_ATTR_OCCUPANCY_SENSING_PIR_UNOCC_TO_OCC_DELAY_ID, (void *)&delay);
140+
break;
141+
case ZIGBEE_OCCUPANCY_SENSOR_TYPE_ULTRASONIC:
142+
ret = esp_zb_cluster_update_attr(occupancy_sens_cluster, ESP_ZB_ZCL_ATTR_OCCUPANCY_SENSING_ULTRASONIC_UNOCCUPIED_TO_OCCUPIED_DELAY_ID, (void *)&delay);
143+
break;
144+
case ZIGBEE_OCCUPANCY_SENSOR_TYPE_PHYSICAL_CONTACT:
145+
ret = esp_zb_cluster_update_attr(occupancy_sens_cluster, ESP_ZB_ZCL_ATTR_OCCUPANCY_SENSING_PHYSICAL_CONTACT_UNOCCUPIED_TO_OCCUPIED_DELAY_ID, (void *)&delay);
146+
break;
147+
default:
148+
log_e("Invalid sensor type for delay setting: 0x%x", sensor_type);
149+
return false;
150+
}
151+
152+
if (ret != ESP_OK) {
153+
log_e("Failed to set unoccupied to occupied delay: 0x%x: %s", ret, esp_err_to_name(ret));
154+
return false;
155+
}
156+
return true;
157+
}
158+
159+
bool ZigbeeOccupancySensor::setUnoccupiedToOccupiedThreshold(ZigbeeOccupancySensorType sensor_type, uint8_t threshold) {
160+
esp_zb_attribute_list_t *occupancy_sens_cluster =
161+
esp_zb_cluster_list_get_cluster(_cluster_list, ESP_ZB_ZCL_CLUSTER_ID_OCCUPANCY_SENSING, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);
162+
163+
esp_err_t ret;
164+
switch (sensor_type) {
165+
case ZIGBEE_OCCUPANCY_SENSOR_TYPE_PIR:
166+
ret = esp_zb_cluster_update_attr(occupancy_sens_cluster, ESP_ZB_ZCL_ATTR_OCCUPANCY_SENSING_PIR_UNOCC_TO_OCC_THRESHOLD_ID, (void *)&threshold);
167+
break;
168+
case ZIGBEE_OCCUPANCY_SENSOR_TYPE_ULTRASONIC:
169+
ret = esp_zb_cluster_update_attr(occupancy_sens_cluster, ESP_ZB_ZCL_ATTR_OCCUPANCY_SENSING_ULTRASONIC_UNOCCUPIED_TO_OCCUPIED_THRESHOLD_ID, (void *)&threshold);
170+
break;
171+
case ZIGBEE_OCCUPANCY_SENSOR_TYPE_PHYSICAL_CONTACT:
172+
ret = esp_zb_cluster_update_attr(occupancy_sens_cluster, ESP_ZB_ZCL_ATTR_OCCUPANCY_SENSING_PHYSICAL_CONTACT_UNOCCUPIED_TO_OCCUPIED_THRESHOLD_ID, (void *)&threshold);
173+
break;
174+
default:
175+
log_e("Invalid sensor type for threshold setting: 0x%x", sensor_type);
176+
return false;
177+
}
178+
179+
if (ret != ESP_OK) {
180+
log_e("Failed to set unoccupied to occupied threshold: 0x%x: %s", ret, esp_err_to_name(ret));
181+
return false;
182+
}
39183
return true;
40184
}
41185

@@ -77,4 +221,55 @@ bool ZigbeeOccupancySensor::report() {
77221
return true;
78222
}
79223

224+
//set attribute method -> method overridden in child class
225+
void ZigbeeOccupancySensor::zbAttributeSet(const esp_zb_zcl_set_attr_value_message_t *message) {
226+
if (message->info.cluster == ESP_ZB_ZCL_CLUSTER_ID_OCCUPANCY_SENSING) {
227+
//PIR
228+
if (message->attribute.id == ESP_ZB_ZCL_ATTR_OCCUPANCY_SENSING_PIR_OCC_TO_UNOCC_DELAY_ID && message->attribute.data.type == ESP_ZB_ZCL_ATTR_TYPE_U16) {
229+
uint16_t pir_occ_to_unocc_delay = *(uint16_t *)message->attribute.data.value;
230+
occupancyConfigChanged(ZIGBEE_OCCUPANCY_SENSOR_TYPE_PIR);
231+
} else if (message->attribute.id == ESP_ZB_ZCL_ATTR_OCCUPANCY_SENSING_PIR_UNOCC_TO_OCC_DELAY_ID && message->attribute.data.type == ESP_ZB_ZCL_ATTR_TYPE_U16) {
232+
uint16_t pir_unocc_to_occ_delay = *(uint16_t *)message->attribute.data.value;
233+
occupancyConfigChanged(ZIGBEE_OCCUPANCY_SENSOR_TYPE_PIR);
234+
} else if (message->attribute.id == ESP_ZB_ZCL_ATTR_OCCUPANCY_SENSING_PIR_UNOCC_TO_OCC_THRESHOLD_ID && message->attribute.data.type == ESP_ZB_ZCL_ATTR_TYPE_U8) {
235+
uint8_t pir_unocc_to_occ_threshold = *(uint8_t *)message->attribute.data.value;
236+
occupancyConfigChanged(ZIGBEE_OCCUPANCY_SENSOR_TYPE_PIR);
237+
}
238+
//Ultrasonic
239+
else if (message->attribute.id == ESP_ZB_ZCL_ATTR_OCCUPANCY_SENSING_ULTRASONIC_OCCUPIED_TO_UNOCCUPIED_DELAY_ID && message->attribute.data.type == ESP_ZB_ZCL_ATTR_TYPE_U16) {
240+
uint16_t ultrasonic_occ_to_unocc_delay = *(uint16_t *)message->attribute.data.value;
241+
occupancyConfigChanged(ZIGBEE_OCCUPANCY_SENSOR_TYPE_ULTRASONIC);
242+
} else if (message->attribute.id == ESP_ZB_ZCL_ATTR_OCCUPANCY_SENSING_ULTRASONIC_UNOCCUPIED_TO_OCCUPIED_DELAY_ID && message->attribute.data.type == ESP_ZB_ZCL_ATTR_TYPE_U16) {
243+
uint16_t ultrasonic_unocc_to_occ_delay = *(uint16_t *)message->attribute.data.value;
244+
occupancyConfigChanged(ZIGBEE_OCCUPANCY_SENSOR_TYPE_ULTRASONIC);
245+
} else if (message->attribute.id == ESP_ZB_ZCL_ATTR_OCCUPANCY_SENSING_ULTRASONIC_UNOCCUPIED_TO_OCCUPIED_THRESHOLD_ID && message->attribute.data.type == ESP_ZB_ZCL_ATTR_TYPE_U8) {
246+
uint8_t ultrasonic_unocc_to_occ_threshold = *(uint8_t *)message->attribute.data.value;
247+
occupancyConfigChanged(ZIGBEE_OCCUPANCY_SENSOR_TYPE_ULTRASONIC);
248+
}
249+
//Physical Contact
250+
else if (message->attribute.id == ESP_ZB_ZCL_ATTR_OCCUPANCY_SENSING_PHYSICAL_CONTACT_OCCUPIED_TO_UNOCCUPIED_DELAY_ID && message->attribute.data.type == ESP_ZB_ZCL_ATTR_TYPE_U16) {
251+
uint16_t physical_contact_occ_to_unocc_delay = *(uint16_t *)message->attribute.data.value;
252+
occupancyConfigChanged(ZIGBEE_OCCUPANCY_SENSOR_TYPE_PHYSICAL_CONTACT);
253+
} else if (message->attribute.id == ESP_ZB_ZCL_ATTR_OCCUPANCY_SENSING_PHYSICAL_CONTACT_UNOCCUPIED_TO_OCCUPIED_DELAY_ID && message->attribute.data.type == ESP_ZB_ZCL_ATTR_TYPE_U16) {
254+
uint16_t physical_contact_unocc_to_occ_delay = *(uint16_t *)message->attribute.data.value;
255+
occupancyConfigChanged(ZIGBEE_OCCUPANCY_SENSOR_TYPE_PHYSICAL_CONTACT);
256+
} else if (message->attribute.id == ESP_ZB_ZCL_ATTR_OCCUPANCY_SENSING_PHYSICAL_CONTACT_UNOCCUPIED_TO_OCCUPIED_THRESHOLD_ID && message->attribute.data.type == ESP_ZB_ZCL_ATTR_TYPE_U8) {
257+
uint8_t physical_contact_unocc_to_occ_threshold = *(uint8_t *)message->attribute.data.value;
258+
occupancyConfigChanged(ZIGBEE_OCCUPANCY_SENSOR_TYPE_PHYSICAL_CONTACT);
259+
} else {
260+
log_w("Received message ignored. Attribute ID: %d not supported for Occupancy Sensor endpoint", message->attribute.id);
261+
}
262+
} else {
263+
log_w("Received message ignored. Cluster ID: %d not supported for Occupancy Sensor endpoint", message->info.cluster);
264+
}
265+
}
266+
267+
void ZigbeeOccupancySensor::occupancyConfigChanged(ZigbeeOccupancySensorType sensor_type) {
268+
if (_on_occupancy_config_change) {
269+
_on_occupancy_config_change(sensor_type); //sensor type, delay, delay, threshold
270+
} else {
271+
log_w("No callback function set for occupancy config change");
272+
}
273+
}
274+
80275
#endif // CONFIG_ZB_ENABLED

Diff for: libraries/Zigbee/src/ep/ZigbeeOccupancySensor.h

+38-2
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,24 @@
3030
}
3131
// clang-format on
3232

33+
enum ZigbeeOccupancySensorType{
34+
ZIGBEE_OCCUPANCY_SENSOR_TYPE_PIR = 0,
35+
ZIGBEE_OCCUPANCY_SENSOR_TYPE_ULTRASONIC = 1,
36+
ZIGBEE_OCCUPANCY_SENSOR_TYPE_PIR_AND_ULTRASONIC = 2,
37+
ZIGBEE_OCCUPANCY_SENSOR_TYPE_PHYSICAL_CONTACT = 3
38+
};
39+
40+
enum ZigbeeOccupancySensorTypeBitmap{
41+
ZIGBEE_OCCUPANCY_SENSOR_BITMAP_PIR = 0x01,
42+
ZIGBEE_OCCUPANCY_SENSOR_BITMAP_ULTRASONIC = 0x02,
43+
ZIGBEE_OCCUPANCY_SENSOR_BITMAP_PIR_AND_ULTRASONIC = 0x03,
44+
// ZIGBEE_OCCUPANCY_SENSOR_BITMAP_PHYSICAL_CONTACT = 0x04, // No info in cluster specification R8
45+
ZIGBEE_OCCUPANCY_SENSOR_BITMAP_PHYSICAL_CONTACT_AND_PIR = 0x05,
46+
ZIGBEE_OCCUPANCY_SENSOR_BITMAP_PHYSICAL_CONTACT_AND_ULTRASONIC = 0x06,
47+
ZIGBEE_OCCUPANCY_SENSOR_BITMAP_PHYSICAL_CONTACT_AND_PIR_AND_ULTRASONIC = 0x07,
48+
ZIGBEE_OCCUPANCY_SENSOR_BITMAP_DEFAULT = 0xff
49+
};
50+
3351
typedef struct zigbee_occupancy_sensor_cfg_s {
3452
esp_zb_basic_cluster_cfg_t basic_cfg;
3553
esp_zb_identify_cluster_cfg_t identify_cfg;
@@ -44,11 +62,29 @@ class ZigbeeOccupancySensor : public ZigbeeEP {
4462
// Set the occupancy value. True for occupied, false for unoccupied
4563
bool setOccupancy(bool occupied);
4664

47-
// Set the sensor type, see esp_zb_zcl_occupancy_sensing_occupancy_sensor_type_t
48-
bool setSensorType(uint8_t sensor_type);
65+
// Set the sensor type, see ZigbeeOccupancySensorType
66+
bool setSensorType(ZigbeeOccupancySensorType sensor_type, ZigbeeOccupancySensorTypeBitmap sensor_type_bitmap = ZIGBEE_OCCUPANCY_SENSOR_BITMAP_DEFAULT);
67+
68+
// Set the occupied to unoccupied delay
69+
// Specifies the time delay, in seconds, before the sensor changes to its unoccupied state after the last detection of movement in the sensed area.
70+
bool setOccupiedToUnoccupiedDelay(ZigbeeOccupancySensorType sensor_type, uint16_t delay);
71+
72+
// Set the unoccupied to occupied delay
73+
// Specifies the time delay, in seconds, before the sensor changes to its occupied state after the detection of movement in the sensed area.
74+
bool setUnoccupiedToOccupiedDelay(ZigbeeOccupancySensorType sensor_type, uint16_t delay);
75+
76+
// Set the unoccupied to occupied threshold
77+
// Specifies the number of movement detection events that must occur in the period unoccupied to occupied delay, before the sensor changes to its occupied state.
78+
bool setUnoccupiedToOccupiedThreshold(ZigbeeOccupancySensorType sensor_type, uint8_t threshold);
4979

5080
// Report the occupancy value
5181
bool report();
82+
83+
private:
84+
void zbAttributeSet(const esp_zb_zcl_set_attr_value_message_t *message) override;
85+
86+
void (*_on_occupancy_config_change)(bool);
87+
void occupancyConfigChanged(ZigbeeOccupancySensorType sensor_type);
5288
};
5389

5490
#endif // CONFIG_ZB_ENABLED

0 commit comments

Comments
 (0)