
Zigbee 온도 센서 장치 제작 코드를 이용해서 온습도센서 SHT20의 온습도 데이터를 전송할 수 있는 Zigbee ED 장치를 만들어 보자.
이번에는 상용품에서 사용될 수 있도록 평소에는 슬립모드로 전류소모를 줄이다 특정 시간마다 깨어나서 온습도 정보를 전송할 수 있도록 할 예정이다.
온습도 센서는 SHT20 이 실장되어 있는 I2C 온습도 모듈을 이용 하였다.
슬립모드 테스트 예제는 ESP32C6 Deep Sleep Mode Test 예제를 사용하였다.
#ifndef ZIGBEE_MODE_ED
#error "Zigbee end device mode is not selected in Tools->Zigbee mode"
#endif
#include "Zigbee.h" // ESP Zigbee 라이브러리
#include "uFire_SHT20.h" // SHT20 온습도 센서 라이브러리
uFire_SHT20 sht20; // SHT20 센서 객체 생성
#define LED_PIN1 14
#define Led1On() digitalWrite(LED_PIN1, 0)
#define Led1Off() digitalWrite(LED_PIN1, 1)
#define USE_GLOBAL_ON_RESPONSE_CALLBACK 1
// Zigbee 응답 처리 방식 선택 매크로
// 1: 글로벌 콜백(onGlobalResponse) 사용
// 0: 개별 엔드포인트에 onResponse 콜백 지정
/* Zigbee 온습도 센서 엔드포인트 설정 */
#define TEMP_SENSOR_ENDPOINT_NUMBER 10
// 이 기기(Zigbee End Device)가 사용할 엔드포인트 번호
// --- Deep Sleep 관련 매크로 ---
#define uS_TO_S_FACTOR 1000000ULL /* 초 → 마이크로초 변환 상수 */
#define TIME_TO_SLEEP 55 /* Deep Sleep 시간 (55초)
* → 기기 연결/리포트 준비 시간 약 5초 포함
* → 총 주기 = 60초 (1분마다 데이터 전송) */
#define REPORT_TIMEOUT 1000 /* Coordinator 응답 대기 타임아웃 (ms) */
uint8_t button = BOOT_PIN;
// Zigbee Factory Reset 용 버튼 핀 (보드 BOOT 버튼과 매핑됨)
ZigbeeTempSensor zbTempSensor = ZigbeeTempSensor(TEMP_SENSOR_ENDPOINT_NUMBER);
// Zigbee Temperature + Humidity Sensor 클러스터 객체 생성
// (엔드포인트 번호 10번에 등록됨)
uint8_t dataToSend = 2;
// 보고할 데이터 개수 (온도 1개 + 습도 1개 = 총 2개 값 보고)
// 이 값은 전송 완료 여부 확인에도 사용됨
bool resend = false;
// 데이터 전송 실패 시 재전송 플래그
void setup() {
Serial.begin(115200); // 시리얼 디버깅 시작
// --- 버튼 초기화 ---
// 내부 풀업저항을 활성화하여 버튼 입력 설정
pinMode(button, INPUT_PULLUP);
pinMode(LED_PIN1, INPUT_PULLUP);
// --- I2C 초기화 및 센서 시작 ---
Wire.begin();
sht20.begin(); // SHT20 온습도 센서 초기화
// --- Deep Sleep 타이머 설정 ---
// 매 55초마다 기기 깨우기 (TIME_TO_SLEEP 단위: 초, uS_TO_S_FACTOR: us 변환용)
esp_sleep_enable_timer_wakeup(TIME_TO_SLEEP * uS_TO_S_FACTOR);
// --- Zigbee Temperature Sensor Endpoint 설정 ---
zbTempSensor.setManufacturerAndModel("Espressif", "SleepyZigbeeTempSensor"); // 제조사/모델명
zbTempSensor.setMinMaxValue(10, 50); // 온도 측정 최소/최대값 (10~50°C)
zbTempSensor.setTolerance(1); // 온도 측정 오차 허용치 (±1°C)
// 전원 공급 방식, 배터리 잔량(%), 배터리 전압(×0.01V 단위)
// 여기서는 100% 잔량, 3.5V 로 표시 (데모 목적)
zbTempSensor.setPowerSource(ZB_POWER_SOURCE_BATTERY, 100, 35);
// 습도 클러스터 추가 (0~100%, 허용 오차 ±1%)
zbTempSensor.addHumiditySensor(0, 100, 1);
// --- Zigbee Default Response Callback 설정 ---
#if USE_GLOBAL_ON_RESPONSE_CALLBACK
// 글로벌 콜백: 엔드포인트/클러스터 정보까지 포함
Zigbee.onGlobalDefaultResponse(onGlobalResponse);
#else
// 특정 엔드포인트용 콜백
zbTempSensor.onDefaultResponse(onResponse);
#endif
// --- 엔드포인트 Zigbee Core에 등록 ---
Zigbee.addEndpoint(&zbTempSensor);
// --- Zigbee End Device 설정 ---
esp_zb_cfg_t zigbeeConfig = ZIGBEE_DEFAULT_ED_CONFIG();
zigbeeConfig.nwk_cfg.zed_cfg.keep_alive = 10000; // Keep-Alive 10초 (리포트 간섭 방지 목적)
// 배터리 절약을 위해 네트워크 Join 타임아웃을 10초로 줄임 (기본 30초)
Zigbee.setTimeout(10000);
// Zigbee End Device 모드 시작
if (!Zigbee.begin(&zigbeeConfig, false)) {
Serial.println("Zigbee failed to start!");
Serial.println("Rebooting...");
ESP.restart(); // Zigbee 시작 실패 시 재부팅
}
// --- 네트워크 연결 대기 ---
Serial.println("Connecting to network");
while (!Zigbee.connected()) {
Serial.print(".");
delay(100);
}
Serial.println();
Serial.println("Successfully connected to Zigbee network");
// --- 온습도 측정 및 Deep Sleep 태스크 시작 ---
xTaskCreate(meausureAndSleep, "temp_sensor_update", 2048, NULL, 10, NULL);
}
void loop() {
// --- 버튼을 이용한 Zigbee Factory Reset ---
if (digitalRead(button) == LOW) { // 버튼 눌림 감지
delay(100); // 디바운스 처리
int startTime = millis();
// 버튼이 계속 눌린 상태 감시
while (digitalRead(button) == LOW) {
delay(50);
if ((millis() - startTime) > 10000) { // 10초 이상 누름
Serial.println("Resetting Zigbee to factory and rebooting in 1s.");
delay(1000);
// Zigbee NVRAM(네트워크 정보) 삭제 → 재시작
// false 로 설정하면 재시작 대신 무한 Deep Sleep으로 들어감
Zigbee.factoryReset(false);
Serial.println("Going to endless sleep, press RESET button or power off/on the device to wake up");
// 타이머 기반 Wake-up 비활성화 후 Deep Sleep 진입
esp_sleep_disable_wakeup_source(ESP_SLEEP_WAKEUP_TIMER);
esp_deep_sleep_start();
}
}
}
delay(100); // loop 주기
}
온습도 데이터 측정은 RTOS로 새로운 타스크를 생성해서 슬립모드에서 께어나 전송 및 전송 상태 확인 하는 코드로 작성하였다.
// 온습도 측정 → Zigbee 전송 → 전송 확인 → Deep Sleep 으로 진입하는 함수
static void meausureAndSleep(void *arg) {
// --- 1. 센서 측정 ---
// SHT20 센서로부터 온도/습도 값 측정
sht20.measure_all();
float temperature = sht20.tempC; // 섭씨 온도 값
float humidity = sht20.RH; // 상대 습도 값
// --- 2. Zigbee 클러스터 업데이트 ---
// Zigbee Temperature/Humidity Cluster에 최신 측정값 반영
zbTempSensor.setTemperature(temperature);
zbTempSensor.setHumidity(humidity);
// --- 3. 데이터 리포트 전송 ---
// Zigbee Coordinator/Hub에 측정 데이터 전송
// (만약 습도 센서가 없는 경우, 온도 값만 전송됨)
zbTempSensor.report();
Serial.printf("Reported temperature: %.2f°C, Humidity: %.2f%%\r\n", temperature, humidity);
// --- 4. 전송 확인 대기 ---
unsigned long startTime = millis();
const unsigned long timeout = REPORT_TIMEOUT; // 리포트 응답 대기 시간
Serial.printf("Waiting for data report to be confirmed \r\n");
int tries = 0; // 재시도 횟수
const int maxTries = 3; // 최대 재시도 횟수
int led_flag = 0;
// Zigbee 스택에서 dataToSend 변수를 통해 전송 성공 여부 확인
while (dataToSend != 0 && tries < maxTries) {
// 전송 실패로 인한 재전송 플래그가 설정된 경우
if (resend) {
Serial.println("Resending data on failure!");
resend = false;
dataToSend = 2; // "데이터 전송 요청 상태"로 다시 설정
zbTempSensor.report(); // 다시 리포트 전송
}
// 타임아웃이 발생하면 재전송
if (millis() - startTime >= timeout) {
Serial.println("\nReport timeout! Report Again");
dataToSend = 2; // 전송 요청 상태로 변경
zbTempSensor.report(); // 다시 리포트 전송
startTime = millis(); // 타이머 리셋
tries++; // 재시도 횟수 증가
led_flag ^= 1;
if(led_flag)Led1On();
else Led1Off();
}
Serial.printf("."); // 진행 상황 출력
delay(50); // 50ms 대기 (busy-waiting 방지)
}
// --- 5. Deep Sleep 진입 ---
// 데이터가 성공적으로 전송되었거나, 재시도 횟수 초과 시 Deep Sleep으로 전환
Serial.println("Going to sleep now");
esp_deep_sleep_start(); // ESP32C6 Deep Sleep 모드 진입
}
프로그램 실행하면 55초마다 한번씩 깨어나서 온습도 데이터 값을 읽어 전송한다. 만약 전송에 실패하면 3번정도 재시도 하고 슬립모드로 들어가는 동작을 한다. 깨어 있는동안은 LED를 깜박이도록해서 디버깅 할 수 있도록 했다.
반응형