ZigbeeThermostat

About

The ZigbeeThermostat class provides a thermostat endpoint for Zigbee networks. This endpoint implements the Zigbee Home Automation (HA) standard for thermostats that can bind to temperature and humidity sensors and receive temperature and humidity readings.

Features: * Automatic discovery and binding to temperature sensors * Temperature and humidity data reception from bound sensors * Configurable temperature and humidity reporting intervals * Sensor settings retrieval (min/max/tolerance for temperature and humidity) * Multiple addressing modes (group, specific endpoint, IEEE address)

API Reference

Constructor

ZigbeeThermostat

Creates a new Zigbee thermostat endpoint.

ZigbeeThermostat(uint8_t endpoint);
  • endpoint - Endpoint number (1-254)

Event Handling

onTempReceive

Sets a callback function for receiving temperature data.

void onTempReceive(void (*callback)(float temperature));
  • callback - Function to call when temperature data is received

  • temperature - Temperature value in degrees Celsius

onTempReceiveWithSource

Sets a callback function for receiving temperature data with source information.

void onTempReceiveWithSource(void (*callback)(float temperature, uint8_t src_endpoint, esp_zb_zcl_addr_t src_address));
  • callback - Function to call when temperature data is received

  • temperature - Temperature value in degrees Celsius

  • src_endpoint - Source endpoint that sent the temperature data

  • src_address - Source address information

onTempConfigReceive

Sets a callback function for receiving sensor configuration data.

void onTempConfigReceive(void (*callback)(float min_temp, float max_temp, float tolerance));
  • callback - Function to call when sensor configuration is received

  • min_temp - Minimum temperature supported by the sensor

  • max_temp - Maximum temperature supported by the sensor

  • tolerance - Temperature tolerance of the sensor

onHumidityReceive

Sets a callback function for receiving humidity data.

void onHumidityReceive(void (*callback)(float humidity));
  • callback - Function to call when humidity data is received

  • humidity - Humidity value in percentage

onHumidityReceiveWithSource

Sets a callback function for receiving humidity data with source information.

void onHumidityReceiveWithSource(void (*callback)(float humidity, uint8_t src_endpoint, esp_zb_zcl_addr_t src_address));
  • callback - Function to call when humidity data is received

  • humidity - Humidity value in percentage

  • src_endpoint - Source endpoint that sent the humidity data

  • src_address - Source address information

onHumidityConfigReceive

Sets a callback function for receiving humidity sensor configuration data.

void onHumidityConfigReceive(void (*callback)(float min_humidity, float max_humidity, float tolerance));
  • callback - Function to call when humidity sensor configuration is received

  • min_humidity - Minimum humidity supported by the sensor

  • max_humidity - Maximum humidity supported by the sensor

  • tolerance - Humidity tolerance of the sensor

Temperature Data Retrieval

getTemperature

Requests temperature data from all bound sensors.

void getTemperature();

getTemperature (Group)

Requests temperature data from a specific group.

void getTemperature(uint16_t group_addr);
  • group_addr - Group address to send the request to

getTemperature (Endpoint + Short Address)

Requests temperature data from a specific endpoint using short address.

void getTemperature(uint8_t endpoint, uint16_t short_addr);
  • endpoint - Target endpoint number

  • short_addr - Short address of the target device

getTemperature (Endpoint + IEEE Address)

Requests temperature data from a specific endpoint using IEEE address.

void getTemperature(uint8_t endpoint, esp_zb_ieee_addr_t ieee_addr);
  • endpoint - Target endpoint number

  • ieee_addr - IEEE address of the target device

Humidity Data Retrieval

getHumidity

Requests humidity data from all bound sensors.

void getHumidity();

getHumidity (Group)

Requests humidity data from a specific group.

void getHumidity(uint16_t group_addr);
  • group_addr - Group address to send the request to

getHumidity (Endpoint + Short Address)

Requests humidity data from a specific endpoint using short address.

void getHumidity(uint8_t endpoint, uint16_t short_addr);
  • endpoint - Target endpoint number

  • short_addr - Short address of the target device

getHumidity (Endpoint + IEEE Address)

Requests humidity data from a specific endpoint using IEEE address.

void getHumidity(uint8_t endpoint, esp_zb_ieee_addr_t ieee_addr);
  • endpoint - Target endpoint number

  • ieee_addr - IEEE address of the target device

Temperature Settings Retrieval

getTemperatureSettings

Requests temperature sensor settings from all bound sensors.

void getTemperatureSettings();

getTemperatureSettings (Group)

Requests temperature sensor settings from a specific group.

void getTemperatureSettings(uint16_t group_addr);
  • group_addr - Group address to send the request to

getTemperatureSettings (Endpoint + Short Address)

Requests temperature sensor settings from a specific endpoint using short address.

void getTemperatureSettings(uint8_t endpoint, uint16_t short_addr);
  • endpoint - Target endpoint number

  • short_addr - Short address of the target device

getTemperatureSettings (Endpoint + IEEE Address)

Requests temperature sensor settings from a specific endpoint using IEEE address.

void getTemperatureSettings(uint8_t endpoint, esp_zb_ieee_addr_t ieee_addr);
  • endpoint - Target endpoint number

  • ieee_addr - IEEE address of the target device

Humidity Settings Retrieval

getHumiditySettings

Requests humidity sensor settings from all bound sensors.

void getHumiditySettings();

getHumiditySettings (Group)

Requests humidity sensor settings from a specific group.

void getHumiditySettings(uint16_t group_addr);
  • group_addr - Group address to send the request to

getHumiditySettings (Endpoint + Short Address)

Requests humidity sensor settings from a specific endpoint using short address.

void getHumiditySettings(uint8_t endpoint, uint16_t short_addr);
  • endpoint - Target endpoint number

  • short_addr - Short address of the target device

getHumiditySettings (Endpoint + IEEE Address)

Requests humidity sensor settings from a specific endpoint using IEEE address.

void getHumiditySettings(uint8_t endpoint, esp_zb_ieee_addr_t ieee_addr);
  • endpoint - Target endpoint number

  • ieee_addr - IEEE address of the target device

Temperature Reporting Configuration

setTemperatureReporting

Configures temperature reporting for all bound sensors.

void setTemperatureReporting(uint16_t min_interval, uint16_t max_interval, float delta);
  • min_interval - Minimum reporting interval in seconds

  • max_interval - Maximum reporting interval in seconds

  • delta - Minimum change in temperature to trigger a report

setTemperatureReporting (Group)

Configures temperature reporting for a specific group.

void setTemperatureReporting(uint16_t group_addr, uint16_t min_interval, uint16_t max_interval, float delta);
  • group_addr - Group address to configure

  • min_interval - Minimum reporting interval in seconds

  • max_interval - Maximum reporting interval in seconds

  • delta - Minimum change in temperature to trigger a report

setTemperatureReporting (Endpoint + Short Address)

Configures temperature reporting for a specific endpoint using short address.

void setTemperatureReporting(uint8_t endpoint, uint16_t short_addr, uint16_t min_interval, uint16_t max_interval, float delta);
  • endpoint - Target endpoint number

  • short_addr - Short address of the target device

  • min_interval - Minimum reporting interval in seconds

  • max_interval - Maximum reporting interval in seconds

  • delta - Minimum change in temperature to trigger a report

setTemperatureReporting (Endpoint + IEEE Address)

Configures temperature reporting for a specific endpoint using IEEE address.

void setTemperatureReporting(uint8_t endpoint, esp_zb_ieee_addr_t ieee_addr, uint16_t min_interval, uint16_t max_interval, float delta);
  • endpoint - Target endpoint number

  • ieee_addr - IEEE address of the target device

  • min_interval - Minimum reporting interval in seconds

  • max_interval - Maximum reporting interval in seconds

  • delta - Minimum change in temperature to trigger a report

Humidity Reporting Configuration

setHumidityReporting

Configures humidity reporting for all bound sensors.

void setHumidityReporting(uint16_t min_interval, uint16_t max_interval, float delta);
  • min_interval - Minimum reporting interval in seconds

  • max_interval - Maximum reporting interval in seconds

  • delta - Minimum change in humidity to trigger a report

setHumidityReporting (Group)

Configures humidity reporting for a specific group.

void setHumidityReporting(uint16_t group_addr, uint16_t min_interval, uint16_t max_interval, float delta);
  • group_addr - Group address to configure

  • min_interval - Minimum reporting interval in seconds

  • max_interval - Maximum reporting interval in seconds

  • delta - Minimum change in humidity to trigger a report

setHumidityReporting (Endpoint + Short Address)

Configures humidity reporting for a specific endpoint using short address.

void setHumidityReporting(uint8_t endpoint, uint16_t short_addr, uint16_t min_interval, uint16_t max_interval, float delta);
  • endpoint - Target endpoint number

  • short_addr - Short address of the target device

  • min_interval - Minimum reporting interval in seconds

  • max_interval - Maximum reporting interval in seconds

  • delta - Minimum change in humidity to trigger a report

setHumidityReporting (Endpoint + IEEE Address)

Configures humidity reporting for a specific endpoint using IEEE address.

void setHumidityReporting(uint8_t endpoint, esp_zb_ieee_addr_t ieee_addr, uint16_t min_interval, uint16_t max_interval, float delta);
  • endpoint - Target endpoint number

  • ieee_addr - IEEE address of the target device

  • min_interval - Minimum reporting interval in seconds

  • max_interval - Maximum reporting interval in seconds

  • delta - Minimum change in humidity to trigger a report

Example

Thermostat Implementation

// 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
#define USE_RECEIVE_TEMP_WITH_SOURCE 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 = {};  // Time structure for Time cluster

/****************** Temperature sensor handling *******************/
#if USE_RECEIVE_TEMP_WITH_SOURCE == 0
void receiveSensorTemp(float temperature) {
  Serial.printf("Temperature sensor value: %.2f°C\n", temperature);
  sensor_temp = temperature;
}
#else
void receiveSensorTempWithSource(float temperature, uint8_t src_endpoint, esp_zb_zcl_addr_t src_address) {
  if (src_address.addr_type == ESP_ZB_ZCL_ADDR_TYPE_SHORT) {
    Serial.printf("Temperature sensor value: %.2f°C from endpoint %d, address 0x%04x\n", temperature, src_endpoint, src_address.u.short_addr);
  } else {
    Serial.printf(
      "Temperature sensor value: %.2f°C from endpoint %d, address %02x:%02x:%02x:%02x:%02x:%02x:%02x:%02x\n", temperature, src_endpoint,
      src_address.u.ieee_addr[7], src_address.u.ieee_addr[6], src_address.u.ieee_addr[5], src_address.u.ieee_addr[4], src_address.u.ieee_addr[3],
      src_address.u.ieee_addr[2], src_address.u.ieee_addr[1], src_address.u.ieee_addr[0]
    );
  }
  sensor_temp = temperature;
}
#endif

void receiveSensorConfig(float min_temp, float max_temp, float tolerance) {
  Serial.printf("Temperature sensor config: 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 function for receiving temperature from sensor - Use only one option
#if USE_RECEIVE_TEMP_WITH_SOURCE == 0
  zbThermostat.onTempReceive(receiveSensorTemp);  // If you bound only one sensor or you don't need to know the source of the temperature
#else
  zbThermostat.onTempReceiveWithSource(receiveSensorTempWithSource);
#endif

  // Set callback function for receiving sensor configuration
  zbThermostat.onTempConfigReceive(receiveSensorConfig);

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

  //Optional Time cluster configuration
  //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 for all bound sensors by endpoint number and address
  std::list<zb_device_params_t *> boundSensors = zbThermostat.getBoundDevices();
  for (const auto &device : boundSensors) {
    Serial.println("--------------------------------");
    if (device->short_addr == 0x0000 || device->short_addr == 0xFFFF) {  //End devices never have 0x0000 short address or 0xFFFF group address
      Serial.printf(
        "Device on endpoint %d, IEEE Address: %02X:%02X:%02X:%02X:%02X:%02X:%02X:%02X\r\n", device->endpoint, device->ieee_addr[7], device->ieee_addr[6],
        device->ieee_addr[5], device->ieee_addr[4], device->ieee_addr[3], device->ieee_addr[2], device->ieee_addr[1], device->ieee_addr[0]
      );
      zbThermostat.getTemperatureSettings(device->endpoint, device->ieee_addr);
    } else {
      Serial.printf("Device on endpoint %d, short address: 0x%x\r\n", device->endpoint, device->short_addr);
      zbThermostat.getTemperatureSettings(device->endpoint, device->short_addr);
    }
  }
}

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);
    zbThermostat.printBoundDevices(Serial);
  }
}