Skip to content

Commit 9f5480a

Browse files
committed
feat(zigbee) Add humidity optional cluster + fixes
1 parent 11760b7 commit 9f5480a

12 files changed

+167
-63
lines changed

libraries/Zigbee/examples/Zigbee_Temperature_Sensor_Sleepy/README.md renamed to libraries/Zigbee/examples/Zigbee_Temp_Hum_Sensor_Sleepy/README.md

+8-12
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
# Arduino-ESP32 Zigbee Temperature Sensor Example
1+
# Arduino-ESP32 Zigbee Temperature and Humidity Sensor Sleepy Device Example
22

3-
This example shows how to configure the Zigbee end device and use it as a Home Automation (HA) temperature sensor.
3+
This example demonstrates how to use the Zigbee library to create an end device temperature/humidity sensor and use it as a Home Automation (HA) extended temperature sensor.
44

55
# Supported Targets
66

@@ -11,23 +11,19 @@ Currently, this example supports the following targets.
1111

1212
## Temperature Sensor Functions
1313

14-
Note:
15-
* This board means the board (e.g. ESP32-H2 / C6) loaded with `Zigbee_Temperature_Sensor` example.
16-
* The remote board means the board (e.g. ESP32-H2 / C6) loaded with `Zigbee_Thermostat` example.
17-
18-
Functions:
19-
* After this board first starts up, it would be configured locally to report the temperature on 1 degree change and no periodic reporting to the remote board.
20-
* By clicking the button (BOOT) on this board, this board will immediately send a report of the current measured temperature to the remote board.
14+
1. Initialize a Zigbee temperature and humidity sensor.
15+
2. Measure temperature and humidity values.
16+
3. Report the measured values to the Zigbee network.
17+
4. Put the device to sleep to save power.
2118

2219
## Hardware Required
2320

24-
* One development board (ESP32-H2 or ESP32-C6) acting as Zigbee coordinator (loaded with `Zigbee_Thermostat` example)
21+
* ESP32-H2 or ESP32-C6 development board
2522
* A USB cable for power supply and programming
26-
* Choose another board (ESP32-H2 or ESP32-C6) as Zigbee end device and upload the `Zigbee_Temperature_Sensor` example
2723

2824
### Configure the Project
2925

30-
In this example, the internal temperature sensor task is reading the chip temperature.
26+
In this example, to demonstrate the funcionality the chip temperature is used and reported as temperature and humidity.
3127
Set the Button GPIO by changing the `BUTTON_PIN` definition. By default, it's the pin `9` (BOOT button on ESP32-C6 and ESP32-H2).
3228

3329
#### Using Arduino IDE
+23-29
Original file line numberDiff line numberDiff line change
@@ -13,10 +13,10 @@
1313
// limitations under the License.
1414

1515
/**
16-
* @brief This example demonstrates Zigbee temperature sensor Sleepy device.
16+
* @brief This example demonstrates Zigbee temperature and humidity sensor Sleepy device.
1717
*
18-
* The example demonstrates how to use Zigbee library to create a end device temperature sensor.
19-
* The temperature sensor is a Zigbee end device, which is controlled by a Zigbee coordinator.
18+
* The example demonstrates how to use Zigbee library to create an end device temperature and humidity sensor.
19+
* The sensor is a Zigbee end device, which is reporting data to the Zigbee network.
2020
*
2121
* Proper Zigbee mode must be selected in Tools->Zigbee mode
2222
* and also the correct partition scheme must be selected in Tools->Partition Scheme.
@@ -32,42 +32,32 @@
3232

3333
#include "ZigbeeCore.h"
3434
#include "ep/ZigbeeTempSensor.h"
35-
#include <ctime>
3635

3736
#define BUTTON_PIN 9 //Boot button for C6/H2
3837
#define TEMP_SENSOR_ENDPOINT_NUMBER 10
3938

4039
#define uS_TO_S_FACTOR 1000000ULL /* Conversion factor for micro seconds to seconds */
41-
#define TIME_TO_SLEEP 30 /* Time ESP32 will go to sleep (in seconds) */
40+
#define TIME_TO_SLEEP 55 /* Sleep for 55s will + 5s delay for establishing connection => data reported every 1 minute */
4241

4342
ZigbeeTempSensor zbTempSensor = ZigbeeTempSensor(TEMP_SENSOR_ENDPOINT_NUMBER);
4443

4544
/************************ Temp sensor *****************************/
4645
void meausureAndSleep(){
4746
// Measure temperature sensor value
48-
float tsens_value = temperatureRead();
47+
float temperature = temperatureRead();
4948

50-
// Initialize random seed
51-
std::srand(static_cast<unsigned int>(std::time(0)));
49+
// Use temparture value as humidity value to demonstrate both temperature and humidity
50+
float humidity = temperature;
5251

53-
// Calculate the 1% fluctuation range
54-
float fluctuation = tsens_value * 0.01f;
52+
// Update temperature and humidity values in Temperature sensor EP
53+
zbTempSensor.setTemperature(temperature);
54+
zbTempSensor.setHumidity(humidity);
5555

56-
// Generate a random number between -1% and +1%
57-
float randomFactor = (static_cast<float>(std::rand()) / RAND_MAX) * 2.0f - 1.0f;
58-
59-
// Apply the fluctuation to the original temperature
60-
tsens_value = tsens_value + randomFactor * fluctuation;
61-
62-
// Update temperature value in Temperature sensor EP
63-
zbTempSensor.setTemperature(tsens_value);
64-
65-
// Report temperature value
56+
// Report temperature and humidity values
6657
zbTempSensor.reportTemperature();
58+
zbTempSensor.reportHumidity();
6759

68-
// Set battery percentage to 80% and report it
69-
zbTempSensor.setBatteryPercentage(80);
70-
zbTempSensor.reportBatteryPercentage();
60+
log_d("Temperature: %.2f°C, Humidity: %.2f%", temperature, humidity);
7161

7262
// Put device to deep sleep
7363
esp_deep_sleep_start();
@@ -78,25 +68,29 @@ void setup() {
7868
// Init button switch
7969
pinMode(BUTTON_PIN, INPUT_PULLUP);
8070

71+
// Configure the wake up source and set to wake up every 5 seconds
72+
esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);
73+
8174
// Optional: set Zigbee device name and model
82-
zbTempSensor.setManufacturerAndModel("Espressif", "SleepyZigbeeTempSensor");
75+
zbTempSensor.setManufacturerAndModel("Espressif", "SleepyZigbeeTempSensorTest");
8376

8477
// Set minimum and maximum temperature measurement value (10-50°C is default range for chip temperature measurement)
8578
zbTempSensor.setMinMaxValue(10, 50);
8679

8780
// Set tolerance for temperature measurement in °C (lowest possible value is 0.01°C)
8881
zbTempSensor.setTolerance(1);
8982

90-
// Set power source to battery and battery percentage to 100%
83+
// Set power source to battery and set battery percentage to measured value (now 100% for demonstration)
84+
// The value can be also updated by calling zbTempSensor.setBatteryPercentage(percentage) anytime
9185
zbTempSensor.setPowerSource(ZB_POWER_SOURCE_BATTERY, 100);
9286

87+
// Add humidity cluster to the temperature sensor device with min, max and tolerance values
88+
zbTempSensor.addHumiditySensor(0,100,1);
89+
9390
// Add endpoint to Zigbee Core
9491
Zigbee.addEndpoint(&zbTempSensor);
9592

96-
// Configure the wake up source and set to wake up every 5 seconds
97-
esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);
98-
99-
// Create a custom Zigbee configuration for End Device
93+
// Create a custom Zigbee configuration for End Device with keep alive 10s to avoid interference with reporting data
10094
esp_zb_cfg_t zigbeeConfig = ZIGBEE_DEFAULT_ED_CONFIG();
10195
zigbeeConfig.nwk_cfg.zed_cfg.keep_alive = 10000;
10296

libraries/Zigbee/src/ZigbeeCore.cpp

+12
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,9 @@
66
#include "ZigbeeHandlers.cpp"
77
#include "Arduino.h"
88

9+
extern "C" void zb_set_ed_node_descriptor(bool power_src, bool rx_on_when_idle, bool alloc_addr);
10+
static bool edBatteryPowered = false;
11+
912
ZigbeeCore::ZigbeeCore() {
1013
_radio_config.radio_mode = ZB_RADIO_MODE_NATIVE; // Use the native 15.4 radio
1114
_host_config.host_connection_mode = ZB_HOST_CONNECTION_MODE_NONE; // Disable host connection
@@ -73,6 +76,12 @@ void ZigbeeCore::addEndpoint(ZigbeeEP *ep) {
7376
static void esp_zb_task(void *pvParameters) {
7477
/* initialize Zigbee stack */
7578
ESP_ERROR_CHECK(esp_zb_start(false));
79+
80+
//NOTE: This is a workaround to make battery powered devices to be discovered as battery powered
81+
if(((zigbee_role_t)Zigbee.getRole() == ZIGBEE_END_DEVICE) && edBatteryPowered ) {
82+
zb_set_ed_node_descriptor(0,0,0);
83+
}
84+
7685
esp_zb_stack_main_loop();
7786
}
7887

@@ -109,6 +118,9 @@ bool ZigbeeCore::zigbeeInit(esp_zb_cfg_t *zb_cfg, bool erase_nvs) {
109118
log_i("List of registered Zigbee EPs:");
110119
for (std::list<ZigbeeEP *>::iterator it = ep_objects.begin(); it != ep_objects.end(); ++it) {
111120
log_i("Device type: %s, Endpoint: %d, Device ID: 0x%04x", getDeviceTypeString((*it)->_device_id), (*it)->_endpoint, (*it)->_device_id);
121+
if((*it)->_power_source == ZB_POWER_SOURCE_BATTERY) {
122+
edBatteryPowered = true;
123+
}
112124
}
113125
}
114126
// Register Zigbee action handler

libraries/Zigbee/src/ZigbeeEP.cpp

+24-8
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,27 @@
77
#include "esp_zigbee_cluster.h"
88
#include "zcl/esp_zigbee_zcl_power_config.h"
99

10-
uint8_t ZigbeeEP::_endpoint = 0;
10+
#ifdef __cplusplus
11+
extern "C"
12+
{
13+
#endif
14+
15+
extern void zb_set_ed_node_descriptor(bool power_src, bool rx_on_when_idle, bool alloc_addr);
16+
17+
#ifdef __cplusplus
18+
}
19+
#endif
20+
21+
// uint8_t ZigbeeEP::_endpoint = 0;
1122
bool ZigbeeEP::_is_bound = false;
1223
bool ZigbeeEP::_allow_multiple_binding = false;
1324

14-
extern void zb_set_ed_node_descriptor(bool power_src, bool rx_on_when_idle, bool alloc_addr);
25+
//TODO: is_bound and allow_multiple_binding to make not static
1526

1627
/* Zigbee End Device Class */
1728
ZigbeeEP::ZigbeeEP(uint8_t endpoint) {
1829
_endpoint = endpoint;
30+
log_v("Endpoint: %d", _endpoint);
1931
_ep_config.endpoint = 0;
2032
_cluster_list = nullptr;
2133
_on_identify = nullptr;
@@ -69,23 +81,27 @@ void ZigbeeEP::setManufacturerAndModel(const char *name, const char *model) {
6981
esp_zb_basic_cluster_add_attr(basic_cluster, ESP_ZB_ZCL_ATTR_BASIC_MODEL_IDENTIFIER_ID, (void *)zb_model);
7082
}
7183

72-
void ZigbeeEP::setPowerSource(zb_power_source_t power_source, uint8_t percentage) {
84+
void ZigbeeEP::setPowerSource(zb_power_source_t power_source, uint8_t battery_percentage) {
7385
esp_zb_attribute_list_t *basic_cluster = esp_zb_cluster_list_get_cluster(_cluster_list, ESP_ZB_ZCL_CLUSTER_ID_BASIC, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);
7486
esp_zb_cluster_update_attr(basic_cluster, ESP_ZB_ZCL_ATTR_BASIC_POWER_SOURCE_ID, (void *)&power_source);
7587

7688
if(power_source == ZB_POWER_SOURCE_BATTERY){
77-
//TODO:
78-
//UPDATE MAC CAPABILITIES TO SET POWER SOURCE TO BATTERY
79-
//currently its not possible to update mac capabilities
80-
zb_set_ed_node_descriptor(0,0,0);
8189
// Add power config cluster and battery percentage attribute
90+
battery_percentage = battery_percentage * 2;
8291
esp_zb_attribute_list_t *power_config_cluster = esp_zb_zcl_attr_list_create(ESP_ZB_ZCL_CLUSTER_ID_POWER_CONFIG);
83-
esp_zb_power_config_cluster_add_attr(power_config_cluster, ESP_ZB_ZCL_ATTR_POWER_CONFIG_BATTERY_PERCENTAGE_REMAINING_ID, (void *)&percentage);
92+
esp_zb_power_config_cluster_add_attr(power_config_cluster, ESP_ZB_ZCL_ATTR_POWER_CONFIG_BATTERY_PERCENTAGE_REMAINING_ID, (void *)&battery_percentage);
8493
esp_zb_cluster_list_add_power_config_cluster(_cluster_list, power_config_cluster, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);
8594
}
95+
_power_source = power_source;
8696
}
8797

8898
void ZigbeeEP::setBatteryPercentage(uint8_t percentage) {
99+
// 100% = 200 in decimal, 0% = 0
100+
// Convert percentage to 0-200 range
101+
if (percentage > 100) {
102+
percentage = 100;
103+
}
104+
percentage = percentage * 2;
89105
esp_zb_lock_acquire(portMAX_DELAY);
90106
esp_zb_zcl_set_attribute_val(
91107
_endpoint, ESP_ZB_ZCL_CLUSTER_ID_POWER_CONFIG, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_POWER_CONFIG_BATTERY_PERCENTAGE_REMAINING_ID, &percentage, false

libraries/Zigbee/src/ZigbeeEP.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -114,13 +114,14 @@ class ZigbeeEP {
114114
void (*_on_identify)(uint16_t time);
115115

116116
protected:
117-
static uint8_t _endpoint;
117+
uint8_t _endpoint;
118118
esp_zb_ha_standard_devices_t _device_id;
119119
esp_zb_endpoint_config_t _ep_config;
120120
esp_zb_cluster_list_t *_cluster_list;
121121
static bool _is_bound;
122122
std::list<zb_device_params_t *> _bound_devices;
123123
SemaphoreHandle_t lock;
124+
zb_power_source_t _power_source;
124125

125126
friend class ZigbeeCore;
126127
};

libraries/Zigbee/src/ep/ZigbeeColorDimmerSwitch.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ void ZigbeeColorDimmerSwitch::findCb(esp_zb_zdp_status_t zdo_status, uint16_t ad
5757
light->short_addr = addr;
5858
esp_zb_ieee_address_by_short(light->short_addr, light->ieee_addr);
5959
esp_zb_get_long_address(bind_req.src_address);
60-
bind_req.src_endp = _endpoint;
60+
bind_req.src_endp = *((uint8_t*)user_ctx); //_endpoint;
6161
bind_req.cluster_id = ESP_ZB_ZCL_CLUSTER_ID_ON_OFF;
6262
bind_req.dst_addr_mode = ESP_ZB_ZDO_BIND_DST_ADDR_MODE_64_BIT_EXTENDED;
6363
memcpy(bind_req.dst_address_u.addr_long, light->ieee_addr, sizeof(esp_zb_ieee_addr_t));
@@ -88,7 +88,7 @@ void ZigbeeColorDimmerSwitch::findEndpoint(esp_zb_zdo_match_desc_req_param_t *cm
8888
.num_out_clusters = 3,
8989
.cluster_list = cluster_list,
9090
};
91-
esp_zb_zdo_match_cluster(&color_dimmable_light_req, findCb, NULL);
91+
esp_zb_zdo_match_cluster(&color_dimmable_light_req, findCb, &_endpoint);
9292
}
9393

9494
// Methods to control the light

libraries/Zigbee/src/ep/ZigbeeLight.cpp

+2-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@ ZigbeeLight::ZigbeeLight(uint8_t endpoint) : ZigbeeEP(endpoint) {
66

77
esp_zb_on_off_light_cfg_t light_cfg = ESP_ZB_DEFAULT_ON_OFF_LIGHT_CONFIG();
88
_cluster_list = esp_zb_on_off_light_clusters_create(&light_cfg); // use esp_zb_zcl_cluster_list_create() instead of esp_zb_on_off_light_clusters_create()
9-
_ep_config = {.endpoint = _endpoint, .app_profile_id = ESP_ZB_AF_HA_PROFILE_ID, .app_device_id = ESP_ZB_HA_ON_OFF_LIGHT_DEVICE_ID, .app_device_version = 0};
9+
_ep_config = {.endpoint = endpoint, .app_profile_id = ESP_ZB_AF_HA_PROFILE_ID, .app_device_id = ESP_ZB_HA_ON_OFF_LIGHT_DEVICE_ID, .app_device_version = 0};
10+
log_v("Light endpoint created %d", _endpoint);
1011
}
1112

1213
//set attribute method -> method overridden in child class

libraries/Zigbee/src/ep/ZigbeeSwitch.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ void ZigbeeSwitch::findCb(esp_zb_zdp_status_t zdo_status, uint16_t addr, uint8_t
3535
light->short_addr = addr;
3636
esp_zb_ieee_address_by_short(light->short_addr, light->ieee_addr);
3737
esp_zb_get_long_address(bind_req.src_address);
38-
bind_req.src_endp = _endpoint; //_dev_endpoint;
38+
bind_req.src_endp = *((uint8_t*)user_ctx); //_endpoint;
3939
bind_req.cluster_id = ESP_ZB_ZCL_CLUSTER_ID_ON_OFF;
4040
bind_req.dst_addr_mode = ESP_ZB_ZDO_BIND_DST_ADDR_MODE_64_BIT_EXTENDED;
4141
memcpy(bind_req.dst_address_u.addr_long, light->ieee_addr, sizeof(esp_zb_ieee_addr_t));
@@ -60,7 +60,7 @@ void ZigbeeSwitch::findEndpoint(esp_zb_zdo_match_desc_req_param_t *cmd_req) {
6060
.cluster_list = cluster_list,
6161
};
6262

63-
esp_zb_zdo_match_cluster(&on_off_req, findCb, NULL);
63+
esp_zb_zdo_match_cluster(&on_off_req, findCb, &_endpoint);
6464
}
6565

6666
// Methods to control the light

0 commit comments

Comments
 (0)