Community project

Zigbee Temperature Humidity Sensor

ESP32
Photo of Zigbee Temperature Humidity Sensor
Generated with AI

Giuseppe Faccilongo

Last updated October 13, 2026

This project builds a battery-powered Zigbee temperature and humidity sensor using an ESP32-C6 microcontroller and a Sensirion SHTC3 sensor. The device wakes periodically to measure environmental conditions, reports them over Zigbee, then returns to deep sleep to maximize battery life from a single CR2450 coin cell.

The guide provides a complete wiring diagram, parts list, and step-by-step assembly instructions for integrating the power regulation circuit, supercapacitor burst-energy buffer, and sensor connections. Firmware code handles Zigbee network joining, sensor reading, and sleep scheduling to deliver updates every 15 minutes while consuming minimal power.

Wiring diagram

Wiring diagram for Zigbee Temperature Humidity Sensor

Gather all the parts

QtyComponent
1

Sensirion SHTC3 Humidity & Temperature Sensor

Sensirion SHTC3 ultra-low-power I2C humidity and temperature sensor.

1

CR2450 3 V lithium coin cell

The replaceable coin cell that stores energy for the remote sensor.

1

CR2450 coin-cell holder

The clip that holds the CR2450 cell and brings its positive and negative terminals out to wires.

1

TPS63900 3.3 V low-quiescent-current buck-boost regulator module

A regulator module that holds the sensor supply at 3.3 V as the coin-cell voltage falls.

1

0.1 F 5.5 V low-leakage supercapacitor

0.1 F, 5.5 V

A small energy store that supplies the short high-current radio bursts the coin cell cannot provide alone.

Assemble it in 5 steps

1. Prepare the coin-cell power section

Place the CR2450 holder and TPS63900 regulator module where their labels are visible. Solder the holder's BAT+ contact to the regulator VIN pin, and solder the holder's BAT- contact to a shared ground point. Leave the CR2450 cell out until the final step.

  • Use short, thick wires for the two battery wires so the radio burst has the easiest path to the regulator.
  • Do not connect the coin cell to the ESP32-C6-Zero 5V pin; that pin expects 5 V and the sensor must receive the regulator's 3.3 V output.

2. Add the burst-energy capacitor

Connect the supercapacitor's + lead to the same VIN point as the holder BAT+ wire, and connect its - lead to the same shared ground point as holder BAT-.

  • On a polarized supercapacitor, the marked minus stripe is the - lead.
  • Do not swap the capacitor leads — reversed polarity can overheat or permanently damage it.

3. Power the ESP32-C6-Zero safely

Connect TPS63900 VOUT to the ESP32-C6-Zero 3V3 pin (power), and connect TPS63900 GND to an ESP32-C6-Zero GND pin (ground). This bypasses the board's 5 V input path and gives the board the regulated 3.3 V it needs.

  • For first programming, disconnect the battery supply and power the board only from USB. Do not use USB and the coin-cell supply together.
  • Make sure the regulator output is 3.3 V before connecting it to the board — a higher voltage can damage the ESP32-C6-Zero.

4. Wire the temperature and humidity sensor

Connect SHTC3 VCC to the 3V3 point (power), SHTC3 GND to GND (ground), SHTC3 SDA to GPIO16 / TX header pin (data), and SHTC3 SCL to GPIO15 / SCL header pin (clock).

  • Keep the sensor away from the ESP32-C6-Zero antenna and regulator so their warmth does not make the temperature reading look too high.
  • Make sure VCC and GND are not swapped — swapped power can damage the sensor.
  • Do not use the built-in RGB LED pin GPIO8 or the BOOT button pin GPIO9 for the sensor.

5. Program, join, and install the battery

With the coin cell still removed, plug the ESP32-C6-Zero into USB and use Deploy. Allow Zigbee joining on your coordinator, then reset the board so its first 10-second wake period can join. Once it appears as a temperature/humidity device, unplug USB and insert the CR2450 with its + face against the holder's + contact.

  • The device wakes and sends a new reading about every 15 minutes; reset it while USB-powered if you need an immediate attempt to join.
  • Never place a loose coin cell where a child or pet can reach it; swallowed coin cells are an emergency.

Review all connections

1. Connections between "cr2450_1" and "ESP32"

Functioncr2450_1ESP32
power+ → CR2450 coin-cell holder BAT+EXT
ground- → CR2450 coin-cell holder BAT-EXT

2. Connections between "cr2450_holder_1" and "ESP32"

Functioncr2450_holder_1ESP32
powerBAT+ → TPS63900 3.3 V low-quiescent-current buck-boost regulator module VINEXT
groundBAT-GND

3. Connections between "reservoir_cap_1" and "ESP32"

Functionreservoir_cap_1ESP32
power+ → TPS63900 3.3 V low-quiescent-current buck-boost regulator module VINEXT
ground-GND

4. Connections between "tps63900_1" and "ESP32"

Functiontps63900_1ESP32
groundGNDGND
powerVOUT3V3

5. Connections between "shtc3_1" and "ESP32"

Functionshtc3_1ESP32
powerVCC3V3
groundGNDGND
i2cSDAGPIO 16
i2cSCLGPIO 15

Deploy the firmware

#include <Arduino.h>
#include <Wire.h>
#include <Adafruit_SHTC3.h>
#include <Zigbee.h>
#include <esp_sleep.h>

constexpr int SHTC3_SDA_PIN = 16;
constexpr int SHTC3_SCL_PIN = 15;
constexpr uint8_t SENSOR_ENDPOINT = 10;
constexpr uint32_t SLEEP_SECONDS = 900;       // Send one update every 15 minutes.
constexpr uint32_t JOIN_TIMEOUT_MS = 10000;   // Avoid draining the cell if no Zigbee network is open.

Adafruit_SHTC3 shtc3;
ZigbeeTempSensor zigbeeSensor(SENSOR_ENDPOINT);

void sleepForNextReport() {
  Serial.println("Sleeping until the next report.");
  Serial.flush();
  esp_sleep_enable_timer_wakeup(static_cast<uint64_t>(SLEEP_SECONDS) * 1000000ULL);
  esp_deep_sleep_start();
}

bool joinZigbeeNetwork() {
  Zigbee.setTimeout(JOIN_TIMEOUT_MS);
  zigbeeSensor.addHumiditySensor(0.0f, 100.0f, 1.0f, 0.0f);
  Zigbee.addEndpoint(&zigbeeSensor);

  if (!Zigbee.begin()) {
    Serial.println("Zigbee could not start.");
    return false;
  }

  const uint32_t startedAt = millis();
  while (!Zigbee.connected() && millis() - startedAt < JOIN_TIMEOUT_MS) {
    delay(100);
  }
  return Zigbee.connected();
}

bool readAndReport() {
  sensors_event_t humidityEvent;
  sensors_event_t temperatureEvent;
  if (!shtc3.getEvent(&humidityEvent, &temperatureEvent)) {
    Serial.println("SHTC3 measurement failed.");
    return false;
  }

  const float temperatureC = temperatureEvent.temperature;
  const float humidityPercent = humidityEvent.relative_humidity;
  if (isnan(temperatureC) || isnan(humidityPercent)) {
    Serial.println("SHTC3 returned an invalid measurement.");
    return false;
  }

  zigbeeSensor.setTemperature(temperatureC);
  zigbeeSensor.setHumidity(humidityPercent);
  zigbeeSensor.reportTemperature();
  zigbeeSensor.reportHumidity();
  Serial.printf("Reported %.2f C and %.1f %%RH\n", temperatureC, humidityPercent);

  // Keep the radio awake briefly so both Zigbee reports can leave the device.
  delay(750);
  return true;
}

void setup() {
  Serial.begin(115200);
  delay(50);

  Wire.begin(SHTC3_SDA_PIN, SHTC3_SCL_PIN);
  if (!shtc3.begin()) {
    Serial.println("SHTC3 was not found; check its four wires.");
    sleepForNextReport();
  }

  if (!joinZigbeeNetwork()) {
    Serial.println("No Zigbee coordinator joined during this wake period.");
    sleepForNextReport();
  }

  readAndReport();
  sleepForNextReport();
}

void loop() {
  // The device always enters deep sleep from setup().
}

Remix this project

Make it yours in one click

Open a full copy of this project in your own Schematik workspace — diagram, code, parts, and assembly steps included. Swap the sensor, add features, or redesign the whole thing with AI. The author's original stays untouched.

Open in Schematik