Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(zigbee): Add Time cluster support + fix of duplicate indentify cluster #10863

Open
wants to merge 4 commits into
base: master
Choose a base branch
from

Conversation

P-R-O-C-H-Y
Copy link
Member

@P-R-O-C-H-Y P-R-O-C-H-Y commented Jan 15, 2025

Description of Change

This PR adds support for Zigbee Time Cluster + fix of duplicate Identify clusters in multiple sensors.
New Time APIs for ZigbeeEP:

  // Set time
  void addTimeCluster(tm time = {0}, int32_t gmt_offset = 0); // gmt offset in seconds
  void setTime(tm time);
  void setTimezone(int32_t gmt_offset);

  // Get time from Coordinator or specific endpoint (blocking until response)
  struct tm getTime(uint8_t endpoint = 1, int32_t short_addr = 0x0000, esp_zb_ieee_addr_t ieee_addr = {0});
  int32_t getTimezone(uint8_t endpoint = 1, int32_t short_addr = 0x0000, esp_zb_ieee_addr_t ieee_addr = {0}); // gmt offset in seconds

Tests scenarios

Tested between 2 ESP32-C6s, both loaded with edited Thermostat/Temperature sensor example.

Edited Thermostat example:

// Copyright 2024 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/**
 * @brief This example demonstrates simple Zigbee thermostat.
 *
 * The example demonstrates how to use Zigbee library to get data from temperature
 * sensor end device and act as an thermostat.
 * The temperature sensor is a Zigbee end device, which is controlled by a Zigbee coordinator (thermostat).
 *
 * Proper Zigbee mode must be selected in Tools->Zigbee mode
 * and also the correct partition scheme must be selected in Tools->Partition Scheme.
 *
 * Please check the README.md for instructions and more detailed description.
 *
 * Created by Jan Procházka (https://github.com/P-R-O-C-H-Y/)
 */

#ifndef ZIGBEE_MODE_ZCZR
#error "Zigbee coordinator mode is not selected in Tools->Zigbee mode"
#endif

#include "Zigbee.h"

/* Zigbee thermostat configuration */
#define THERMOSTAT_ENDPOINT_NUMBER 1
uint8_t button = BOOT_PIN;

ZigbeeThermostat zbThermostat = ZigbeeThermostat(THERMOSTAT_ENDPOINT_NUMBER);

// Save temperature sensor data
float sensor_temp;
float sensor_max_temp;
float sensor_min_temp;
float sensor_tolerance;

struct tm timeinfo = {}; 

/****************** Temperature sensor handling *******************/
void recieveSensorTemp(float temperature) {
  Serial.printf("Temperature sensor value: %.2f°C\n", temperature);
  sensor_temp = temperature;
}

void recieveSensorConfig(float min_temp, float max_temp, float tolerance) {
  Serial.printf("Temperature sensor settings: min %.2f°C, max %.2f°C, tolerance %.2f°C\n", min_temp, max_temp, tolerance);
  sensor_min_temp = min_temp;
  sensor_max_temp = max_temp;
  sensor_tolerance = tolerance;
}
/********************* Arduino functions **************************/
void setup() {
  Serial.begin(115200);

  // Init button switch
  pinMode(button, INPUT_PULLUP);

  // Set callback functions for temperature and configuration receive
  zbThermostat.onTempRecieve(recieveSensorTemp);
  zbThermostat.onConfigRecieve(recieveSensorConfig);

  //Optional: set Zigbee device name and model
  zbThermostat.setManufacturerAndModel("Espressif", "ZigbeeThermostat");

  // example time January 13, 2025 13:30:30 CET
  timeinfo.tm_year = 2025 - 1900; // = 2025
  timeinfo.tm_mon = 0; // January
  timeinfo.tm_mday = 13; // 13th
  timeinfo.tm_hour = 12; // 12 hours - 1 hour (CET)
  timeinfo.tm_min = 30; // 30 minutes
  timeinfo.tm_sec = 30; // 30 seconds
  timeinfo.tm_isdst = -1;

  // Set time and gmt offset (timezone in seconds -> CET = +3600 seconds)
  zbThermostat.addTimeCluster(timeinfo, 3600); 

  //Add endpoint to Zigbee Core
  Zigbee.addEndpoint(&zbThermostat);

  //Open network for 180 seconds after boot
  Zigbee.setRebootOpenNetwork(180);

  // When all EPs are registered, start Zigbee with ZIGBEE_COORDINATOR mode
  if (!Zigbee.begin(ZIGBEE_COORDINATOR)) {
    Serial.println("Zigbee failed to start!");
    Serial.println("Rebooting...");
    ESP.restart();
  }

  Serial.println("Waiting for Temperature sensor to bound to the thermostat");
  while (!zbThermostat.bound()) {
    Serial.printf(".");
    delay(500);
  }

  Serial.println();

  // Get temperature sensor configuration
  zbThermostat.getSensorSettings();
}

void loop() {
  // Handle button switch in loop()
  if (digitalRead(button) == LOW) {  // Push button pressed

    // Key debounce handling
    while (digitalRead(button) == LOW) {
      delay(50);
    }

    // Set reporting interval for temperature sensor
    zbThermostat.setTemperatureReporting(0, 10, 2);
  }

  // Print temperature sensor data each 10 seconds
  static uint32_t last_print = 0;
  if (millis() - last_print > 10000) {
    last_print = millis();
    int temp_percent = (int)((sensor_temp - sensor_min_temp) / (sensor_max_temp - sensor_min_temp) * 100);
    Serial.printf("Loop temperature info: %.2f°C (%d %%)\n", sensor_temp, temp_percent);
  }
}

Edited Temperature Sensor example:

// Copyright 2024 Espressif Systems (Shanghai) PTE LTD
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/**
 * @brief This example demonstrates Zigbee temperature sensor.
 *
 * The example demonstrates how to use Zigbee library to create a end device temperature sensor.
 * The temperature sensor is a Zigbee end device, which is controlled by a Zigbee coordinator.
 *
 * Proper Zigbee mode must be selected in Tools->Zigbee mode
 * and also the correct partition scheme must be selected in Tools->Partition Scheme.
 *
 * Please check the README.md for instructions and more detailed description.
 *
 * Created by Jan Procházka (https://github.com/P-R-O-C-H-Y/)
 */

#ifndef ZIGBEE_MODE_ED
#error "Zigbee end device mode is not selected in Tools->Zigbee mode"
#endif

#include "Zigbee.h"

/* Zigbee temperature sensor configuration */
#define TEMP_SENSOR_ENDPOINT_NUMBER 10
uint8_t button = BOOT_PIN;

ZigbeeTempSensor zbTempSensor = ZigbeeTempSensor(TEMP_SENSOR_ENDPOINT_NUMBER);

struct tm timeinfo;
struct tm *localTime;
int32_t timezone;

/************************ Temp sensor *****************************/
static void temp_sensor_value_update(void *arg) {
  for (;;) {
    // Read temperature sensor value
    float tsens_value = temperatureRead();
    Serial.printf("Updated temperature sensor value to %.2f°C\r\n", tsens_value);
    // Update temperature value in Temperature sensor EP
    zbTempSensor.setTemperature(tsens_value);
    delay(1000);
  }
}

/********************* Arduino functions **************************/
void setup() {
  Serial.begin(115200);

  // Init button switch
  pinMode(button, INPUT_PULLUP);

  // Optional: set Zigbee device name and model
  zbTempSensor.setManufacturerAndModel("Espressif", "ZigbeeTempSensor");

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

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

  zbTempSensor.addTimeCluster();

  // Add endpoint to Zigbee Core
  Zigbee.addEndpoint(&zbTempSensor);

  Serial.println("Starting Zigbee...");
  // When all EPs are registered, start Zigbee in End Device mode
  if (!Zigbee.begin()) {
    Serial.println("Zigbee failed to start!");
    Serial.println("Rebooting...");
    ESP.restart();
  } else {
    Serial.println("Zigbee started successfully!");
  }
  Serial.println("Connecting to network");
  while (!Zigbee.connected()) {
    Serial.print(".");
    delay(100);
  }
  Serial.println();

  timeinfo = zbTempSensor.getTime();
  timezone = zbTempSensor.getTimezone();

  // print time
  Serial.println("UTC time:");
  Serial.println(&timeinfo, "%A, %B %d %Y %H:%M:%S");

  time_t local = mktime(&timeinfo) + timezone;
  localTime = localtime(&local);

  // print local time with timezone
  Serial.println("Local time:");
  Serial.println(localTime, "%A, %B %d %Y %H:%M:%S");

  
  // Start Temperature sensor reading task
  xTaskCreate(temp_sensor_value_update, "temp_sensor_update", 2048, NULL, 10, NULL);

  // Set reporting interval for temperature measurement in seconds, must be called after Zigbee.begin()
  // min_interval and max_interval in seconds, delta (temp change in 0,1 °C)
  // if min = 1 and max = 0, reporting is sent only when temperature changes by delta
  // if min = 0 and max = 10, reporting is sent every 10 seconds or temperature changes by delta
  // if min = 0, max = 10 and delta = 0, reporting is sent every 10 seconds regardless of temperature change
  zbTempSensor.setReporting(1, 0, 1);
}

void loop() {
  // Checking button for factory reset
  if (digitalRead(button) == LOW) {  // Push button pressed
    // Key debounce handling
    delay(100);
    int startTime = millis();
    while (digitalRead(button) == LOW) {
      delay(50);
      if ((millis() - startTime) > 3000) {
        // If key pressed for more than 3secs, factory reset Zigbee and reboot
        Serial.println("Resetting Zigbee to factory and rebooting in 1s.");
        delay(1000);
        Zigbee.factoryReset();
      }
    }
    zbTempSensor.reportTemperature();
  }
  delay(100);
}

Related links

Please provide links to related issue, PRs etc.

Closes #10431

@P-R-O-C-H-Y P-R-O-C-H-Y added Status: Review needed Issue or PR is awaiting review Area: Zigbee Issues and Feature Request about Zigbee labels Jan 15, 2025
@P-R-O-C-H-Y P-R-O-C-H-Y added this to the 3.2.0 milestone Jan 15, 2025
@P-R-O-C-H-Y P-R-O-C-H-Y self-assigned this Jan 15, 2025
Copy link
Contributor

github-actions bot commented Jan 15, 2025

Messages
📖 🎉 Good Job! All checks are passing!

👋 Hello P-R-O-C-H-Y, we appreciate your contribution to this project!


📘 Please review the project's Contributions Guide for key guidelines on code, documentation, testing, and more.

🖊️ Please also make sure you have read and signed the Contributor License Agreement for this project.

Click to see more instructions ...


This automated output is generated by the PR linter DangerJS, which checks if your Pull Request meets the project's requirements and helps you fix potential issues.

DangerJS is triggered with each push event to a Pull Request and modify the contents of this comment.

Please consider the following:
- Danger mainly focuses on the PR structure and formatting and can't understand the meaning behind your code or changes.
- Danger is not a substitute for human code reviews; it's still important to request a code review from your colleagues.
- To manually retry these Danger checks, please navigate to the Actions tab and re-run last Danger workflow.

Review and merge process you can expect ...


We do welcome contributions in the form of bug reports, feature requests and pull requests.

1. An internal issue has been created for the PR, we assign it to the relevant engineer.
2. They review the PR and either approve it or ask you for changes or clarifications.
3. Once the GitHub PR is approved we do the final review, collect approvals from core owners and make sure all the automated tests are passing.
- At this point we may do some adjustments to the proposed change, or extend it by adding tests or documentation.
4. If the change is approved and passes the tests it is merged into the default branch.

Generated by 🚫 dangerJS against 580084c

@P-R-O-C-H-Y P-R-O-C-H-Y changed the title Feat/zigbee time cluster feat(zigbee): Add Time cluster support + fix of duplicate indentify cluster Jan 15, 2025
Copy link
Contributor

Memory usage test (comparing PR against master branch)

The table below shows the summary of memory usage change (decrease - increase) in bytes and percentage for each target.

MemoryFLASH [bytes]FLASH [%]RAM [bytes]RAM [%]
TargetDECINCDECINCDECINCDECINC
ESP32C60⚠️ +1580.00⚠️ +0.030⚠️ +320.00⚠️ +0.11
ESP32H20⚠️ +1580.00⚠️ +0.030⚠️ +320.00⚠️ +0.11
Click to expand the detailed deltas report [usage change in BYTES]
TargetESP32C6ESP32H2
ExampleFLASHRAMFLASHRAM
Zigbee/examples/Zigbee_CarbonDioxide_Sensor⚠️ +140⚠️ +16⚠️ +140⚠️ +16
Zigbee/examples/Zigbee_Color_Dimmable_Light⚠️ +156⚠️ +16⚠️ +156⚠️ +16
Zigbee/examples/Zigbee_Color_Dimmer_Switch⚠️ +158⚠️ +16⚠️ +158⚠️ +16
Zigbee/examples/Zigbee_Dimmable_Light⚠️ +156⚠️ +16⚠️ +156⚠️ +16
Zigbee/examples/Zigbee_Occupancy_Sensor⚠️ +140⚠️ +16⚠️ +140⚠️ +16
Zigbee/examples/Zigbee_On_Off_Light⚠️ +156⚠️ +16⚠️ +156⚠️ +16
Zigbee/examples/Zigbee_On_Off_Switch⚠️ +156⚠️ +16⚠️ +156⚠️ +16
Zigbee/examples/Zigbee_Pressure_Flow_Sensor⚠️ +124⚠️ +32⚠️ +122⚠️ +32
Zigbee/examples/Zigbee_Scan_Networks⚠️ +200⚠️ +200
Zigbee/examples/Zigbee_Temp_Hum_Sensor_Sleepy⚠️ +156⚠️ +16⚠️ +156⚠️ +16
Zigbee/examples/Zigbee_Temperature_Sensor⚠️ +156⚠️ +16⚠️ +156⚠️ +16
Zigbee/examples/Zigbee_Thermostat⚠️ +156⚠️ +16⚠️ +156⚠️ +16

Copy link
Contributor

github-actions bot commented Jan 15, 2025

Test Results

 62 files   62 suites   5m 38s ⏱️
 21 tests  21 ✅ 0 💤 0 ❌
154 runs  154 ✅ 0 💤 0 ❌

Results for commit 580084c.

♻️ This comment has been updated with latest results.

@lucasssvaz
Copy link
Collaborator

Shouldn't we add or edit at least one example to highlight this functionality ?

@P-R-O-C-H-Y
Copy link
Member Author

Shouldn't we add or edit at least one example to highlight this functionality ?

Will do, probably just edit some, as it don't make much sense to be a standalone thing.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area: Zigbee Issues and Feature Request about Zigbee Status: Review needed Issue or PR is awaiting review
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Zigbee Implementation: ZCL Time Client (ZigBee Time Extension) support + Zigbee Time Client examples
2 participants