Merge branch 'master' into release/v3.3.x
This commit is contained in:
commit
ae2ae8dfa0
25 changed files with 698 additions and 127 deletions
|
|
@ -300,6 +300,7 @@ set(ARDUINO_LIBRARY_Zigbee_SRCS
|
|||
libraries/Zigbee/src/ep/ZigbeeGateway.cpp
|
||||
libraries/Zigbee/src/ep/ZigbeeWindSpeedSensor.cpp
|
||||
libraries/Zigbee/src/ep/ZigbeeIlluminanceSensor.cpp
|
||||
libraries/Zigbee/src/ep/ZigbeePM25Sensor.cpp
|
||||
)
|
||||
|
||||
set(ARDUINO_LIBRARY_BLE_SRCS
|
||||
|
|
|
|||
|
|
@ -603,6 +603,7 @@ void HWCDC::setDebugOutput(bool en) {
|
|||
} else {
|
||||
ets_install_putc2(NULL);
|
||||
}
|
||||
ets_install_putc1(NULL); // closes UART log output
|
||||
}
|
||||
|
||||
#if ARDUINO_USB_MODE && ARDUINO_USB_CDC_ON_BOOT // Hardware JTAG CDC selected
|
||||
|
|
|
|||
|
|
@ -607,6 +607,24 @@ bool HardwareSerial::setMode(SerialMode mode) {
|
|||
return uartSetMode(_uart, mode);
|
||||
}
|
||||
|
||||
// Sets the UART Clock Source based on the compatible SoC options
|
||||
// This method must be called before starting UART using begin(), otherwise it won't have any effect.
|
||||
// Clock Source Options are:
|
||||
// UART_CLK_SRC_DEFAULT :: any SoC - it will set whatever IDF defines as the default UART Clock Source
|
||||
// UART_CLK_SRC_APB :: ESP32, ESP32-S2, ESP32-C3 and ESP32-S3
|
||||
// UART_CLK_SRC_PLL :: ESP32-C2, ESP32-C5, ESP32-C6, ESP32-C61, ESP32-H2 and ESP32-P4
|
||||
// UART_CLK_SRC_XTAL :: ESP32-C2, ESP32-C3, ESP32-C5, ESP32-C6, ESP32-C61, ESP32-H2, ESP32-S3 and ESP32-P4
|
||||
// UART_CLK_SRC_RTC :: ESP32-C2, ESP32-C3, ESP32-C5, ESP32-C6, ESP32-C61, ESP32-H2, ESP32-S3 and ESP32-P4
|
||||
// UART_CLK_SRC_REF_TICK :: ESP32 and ESP32-S2
|
||||
// Note: CLK_SRC_PLL Freq depends on the SoC - ESP32-C2 has 40MHz, ESP32-H2 has 48MHz and ESP32-C5, C6, C61 and P4 has 80MHz
|
||||
// Note: ESP32-C6, C61, ESP32-P4 and ESP32-C5 have LP UART that will use only RTC_FAST or XTAL/2 as Clock Source
|
||||
bool HardwareSerial::setClockSource(SerialClkSrc clkSrc) {
|
||||
if (_uart) {
|
||||
log_e("No Clock Source change was done. This function must be called before beginning UART%d.", _uart_nr);
|
||||
return false;
|
||||
}
|
||||
return uartSetClockSource(_uart_nr, (uart_sclk_t)clkSrc);
|
||||
}
|
||||
// minimum total RX Buffer size is the UART FIFO space (128 bytes for most SoC) + 1. IDF imposition.
|
||||
// LP UART has FIFO of 16 bytes
|
||||
size_t HardwareSerial::setRxBufferSize(size_t new_size) {
|
||||
|
|
|
|||
|
|
@ -96,6 +96,29 @@ typedef enum {
|
|||
UART_PARITY_ERROR
|
||||
} hardwareSerial_error_t;
|
||||
|
||||
typedef enum {
|
||||
UART_CLK_SRC_DEFAULT = UART_SCLK_DEFAULT,
|
||||
#if SOC_UART_SUPPORT_APB_CLK
|
||||
UART_CLK_SRC_APB = UART_SCLK_APB,
|
||||
#endif
|
||||
#if SOC_UART_SUPPORT_PLL_F40M_CLK
|
||||
UART_CLK_SRC_PLL = UART_SCLK_PLL_F40M,
|
||||
#elif SOC_UART_SUPPORT_PLL_F80M_CLK
|
||||
UART_CLK_SRC_PLL = UART_SCLK_PLL_F80M,
|
||||
#elif CONFIG_IDF_TARGET_ESP32H2
|
||||
UART_CLK_SRC_PLL = UART_SCLK_PLL_F48M,
|
||||
#endif
|
||||
#if SOC_UART_SUPPORT_XTAL_CLK
|
||||
UART_CLK_SRC_XTAL = UART_SCLK_XTAL,
|
||||
#endif
|
||||
#if SOC_UART_SUPPORT_RTC_CLK
|
||||
UART_CLK_SRC_RTC = UART_SCLK_RTC,
|
||||
#endif
|
||||
#if SOC_UART_SUPPORT_REF_TICK
|
||||
UART_CLK_SRC_REF_TICK = UART_SCLK_REF_TICK,
|
||||
#endif
|
||||
} SerialClkSrc;
|
||||
|
||||
#ifndef ARDUINO_SERIAL_EVENT_TASK_STACK_SIZE
|
||||
#ifndef CONFIG_ARDUINO_SERIAL_EVENT_TASK_STACK_SIZE
|
||||
#define ARDUINO_SERIAL_EVENT_TASK_STACK_SIZE 2048
|
||||
|
|
@ -352,6 +375,17 @@ public:
|
|||
// UART_MODE_RS485_COLLISION_DETECT = 0x03 mode: RS485 collision detection UART mode (used for test purposes)
|
||||
// UART_MODE_RS485_APP_CTRL = 0x04 mode: application control RS485 UART mode (used for test purposes)
|
||||
bool setMode(SerialMode mode);
|
||||
// Used to set the UART clock source mode. It must be set before calling begin(), otherwise it won't have any effect.
|
||||
// Not all clock source are available to every SoC. The compatible option are listed here:
|
||||
// UART_CLK_SRC_DEFAULT :: any SoC - it will set whatever IDF defines as the default UART Clock Source
|
||||
// UART_CLK_SRC_APB :: ESP32, ESP32-S2, ESP32-C3 and ESP32-S3
|
||||
// UART_CLK_SRC_PLL :: ESP32-C2, ESP32-C5, ESP32-C6, ESP32-C61, ESP32-H2 and ESP32-P4
|
||||
// UART_CLK_SRC_XTAL :: ESP32-C2, ESP32-C3, ESP32-C5, ESP32-C6, ESP32-C61, ESP32-H2, ESP32-S3 and ESP32-P4
|
||||
// UART_CLK_SRC_RTC :: ESP32-C2, ESP32-C3, ESP32-C5, ESP32-C6, ESP32-C61, ESP32-H2, ESP32-S3 and ESP32-P4
|
||||
// UART_CLK_SRC_REF_TICK :: ESP32 and ESP32-S2
|
||||
// Note: CLK_SRC_PLL Freq depends on the SoC - ESP32-C2 has 40MHz, ESP32-H2 has 48MHz and ESP32-C5, C6, C61 and P4 has 80MHz
|
||||
// Note: ESP32-C6, C61, ESP32-P4 and ESP32-C5 have LP UART that will use only RTC_FAST or XTAL/2 as Clock Source
|
||||
bool setClockSource(SerialClkSrc clkSrc);
|
||||
size_t setRxBufferSize(size_t new_size);
|
||||
size_t setTxBufferSize(size_t new_size);
|
||||
|
||||
|
|
|
|||
|
|
@ -100,6 +100,7 @@ static bool tinyusb_device_suspended = false;
|
|||
void tud_mount_cb(void) {
|
||||
tinyusb_device_mounted = true;
|
||||
arduino_usb_event_data_t p;
|
||||
p.suspend.remote_wakeup_en = 0;
|
||||
arduino_usb_event_post(ARDUINO_USB_EVENTS, ARDUINO_USB_STARTED_EVENT, &p, sizeof(arduino_usb_event_data_t), portMAX_DELAY);
|
||||
}
|
||||
|
||||
|
|
@ -107,6 +108,7 @@ void tud_mount_cb(void) {
|
|||
void tud_umount_cb(void) {
|
||||
tinyusb_device_mounted = false;
|
||||
arduino_usb_event_data_t p;
|
||||
p.suspend.remote_wakeup_en = 0;
|
||||
arduino_usb_event_post(ARDUINO_USB_EVENTS, ARDUINO_USB_STOPPED_EVENT, &p, sizeof(arduino_usb_event_data_t), portMAX_DELAY);
|
||||
}
|
||||
|
||||
|
|
@ -123,6 +125,7 @@ void tud_suspend_cb(bool remote_wakeup_en) {
|
|||
void tud_resume_cb(void) {
|
||||
tinyusb_device_suspended = false;
|
||||
arduino_usb_event_data_t p;
|
||||
p.suspend.remote_wakeup_en = 0;
|
||||
arduino_usb_event_post(ARDUINO_USB_EVENTS, ARDUINO_USB_RESUME_EVENT, &p, sizeof(arduino_usb_event_data_t), portMAX_DELAY);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -455,6 +455,7 @@ void USBCDC::setDebugOutput(bool en) {
|
|||
} else {
|
||||
ets_install_putc2(NULL);
|
||||
}
|
||||
ets_install_putc1(NULL); // closes UART log output
|
||||
}
|
||||
|
||||
USBCDC::operator bool() const {
|
||||
|
|
|
|||
|
|
@ -15,7 +15,7 @@
|
|||
#include "esp32-hal-bt.h"
|
||||
|
||||
#if SOC_BT_SUPPORTED
|
||||
#ifdef CONFIG_BT_ENABLED
|
||||
#ifdef CONFIG_BT_BLUEDROID_ENABLED
|
||||
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
bool btInUse() {
|
||||
|
|
|
|||
|
|
@ -25,9 +25,9 @@
|
|||
#include "esp_ota_ops.h"
|
||||
#endif //CONFIG_APP_ROLLBACK_ENABLE
|
||||
#include "esp_private/startup_internal.h"
|
||||
#if defined(CONFIG_BT_ENABLED) && SOC_BT_SUPPORTED
|
||||
#if defined(CONFIG_BT_BLUEDROID_ENABLED) && SOC_BT_SUPPORTED
|
||||
#include "esp_bt.h"
|
||||
#endif //CONFIG_BT_ENABLED
|
||||
#endif //CONFIG_BT_BLUEDROID_ENABLED
|
||||
#include <sys/time.h>
|
||||
#include "soc/rtc.h"
|
||||
#if !defined(CONFIG_IDF_TARGET_ESP32C2) && !defined(CONFIG_IDF_TARGET_ESP32C6) && !defined(CONFIG_IDF_TARGET_ESP32H2) && !defined(CONFIG_IDF_TARGET_ESP32P4) && !defined(CONFIG_IDF_TARGET_ESP32C5)
|
||||
|
|
@ -245,7 +245,7 @@ bool verifyRollbackLater() {
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_BT_ENABLED
|
||||
#ifdef CONFIG_BT_BLUEDROID_ENABLED
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
//overwritten in esp32-hal-bt.c
|
||||
bool btInUse() __attribute__((weak));
|
||||
|
|
@ -307,7 +307,7 @@ void initArduino() {
|
|||
if (err) {
|
||||
log_e("Failed to initialize NVS! Error: %u", err);
|
||||
}
|
||||
#if defined(CONFIG_BT_ENABLED) && SOC_BT_SUPPORTED
|
||||
#if defined(CONFIG_BT_BLUEDROID_ENABLED) && SOC_BT_SUPPORTED
|
||||
if (!btInUse()) {
|
||||
esp_bt_controller_mem_release(ESP_BT_MODE_BTDM);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -206,7 +206,8 @@ bool rmtSetCarrier(int pin, bool carrier_en, bool carrier_level, uint32_t freque
|
|||
log_w("GPIO %d - RMT Carrier must be a float percentage from 0 to 1. Setting to 50%.", pin);
|
||||
duty_percent = 0.5;
|
||||
}
|
||||
rmt_carrier_config_t carrier_cfg = {0};
|
||||
rmt_carrier_config_t carrier_cfg;
|
||||
memset((void *)&carrier_cfg, 0, sizeof(rmt_carrier_config_t));
|
||||
carrier_cfg.duty_cycle = duty_percent; // duty cycle
|
||||
carrier_cfg.frequency_hz = carrier_en ? frequency_Hz : 0; // carrier frequency in Hz
|
||||
carrier_cfg.flags.polarity_active_low = carrier_level; // carrier modulation polarity level
|
||||
|
|
@ -313,7 +314,8 @@ static bool _rmtWrite(int pin, rmt_data_t *data, size_t num_rmt_symbols, bool bl
|
|||
return false;
|
||||
}
|
||||
|
||||
rmt_transmit_config_t transmit_cfg = {0}; // loop mode disabled
|
||||
rmt_transmit_config_t transmit_cfg; // loop mode disabled
|
||||
memset((void *)&transmit_cfg, 0, sizeof(rmt_transmit_config_t));
|
||||
bool retCode = true;
|
||||
|
||||
RMT_MUTEX_LOCK(bus);
|
||||
|
|
@ -380,6 +382,7 @@ static bool _rmtRead(int pin, rmt_data_t *data, size_t *num_rmt_symbols, bool wa
|
|||
|
||||
// request reading RMT Channel Data
|
||||
rmt_receive_config_t receive_config;
|
||||
memset((void *)&receive_config, 0, sizeof(rmt_receive_config_t));
|
||||
receive_config.signal_range_min_ns = bus->signal_range_min_ns;
|
||||
receive_config.signal_range_max_ns = bus->signal_range_max_ns;
|
||||
|
||||
|
|
@ -530,6 +533,7 @@ bool rmtInit(int pin, rmt_ch_dir_t channel_direction, rmt_reserve_memsize_t mem_
|
|||
if (channel_direction == RMT_TX_MODE) {
|
||||
// TX Channel
|
||||
rmt_tx_channel_config_t tx_cfg;
|
||||
memset((void *)&tx_cfg, 0, sizeof(rmt_tx_channel_config_t));
|
||||
tx_cfg.gpio_num = pin;
|
||||
// CLK_APB for ESP32|S2|S3|C3 -- CLK_PLL_F80M for C6 -- CLK_XTAL for H2
|
||||
tx_cfg.clk_src = RMT_CLK_SRC_DEFAULT;
|
||||
|
|
@ -559,6 +563,7 @@ bool rmtInit(int pin, rmt_ch_dir_t channel_direction, rmt_reserve_memsize_t mem_
|
|||
} else {
|
||||
// RX Channel
|
||||
rmt_rx_channel_config_t rx_cfg;
|
||||
memset((void *)&rx_cfg, 0, sizeof(rmt_rx_channel_config_t));
|
||||
rx_cfg.gpio_num = pin;
|
||||
// CLK_APB for ESP32|S2|S3|C3 -- CLK_PLL_F80M for C6 -- CLK_XTAL for H2
|
||||
rx_cfg.clk_src = RMT_CLK_SRC_DEFAULT;
|
||||
|
|
@ -585,7 +590,8 @@ bool rmtInit(int pin, rmt_ch_dir_t channel_direction, rmt_reserve_memsize_t mem_
|
|||
}
|
||||
|
||||
// allocate memory for the RMT Copy encoder
|
||||
rmt_copy_encoder_config_t copy_encoder_config = {};
|
||||
rmt_copy_encoder_config_t copy_encoder_config;
|
||||
memset((void *)©_encoder_config, 0, sizeof(rmt_copy_encoder_config_t));
|
||||
if (rmt_new_copy_encoder(©_encoder_config, &bus->rmt_copy_encoder_h) != ESP_OK) {
|
||||
log_e("GPIO %d - RMT Encoder Memory Allocation error.", pin);
|
||||
goto Err;
|
||||
|
|
|
|||
|
|
@ -58,6 +58,7 @@ struct uart_struct_t {
|
|||
uint16_t _rx_buffer_size, _tx_buffer_size; // UART RX and TX buffer sizes
|
||||
bool _inverted; // UART inverted signal
|
||||
uint8_t _rxfifo_full_thrhd; // UART RX FIFO full threshold
|
||||
int8_t _uart_clock_source; // UART Clock Source used when it is started using uartBegin()
|
||||
};
|
||||
|
||||
#if CONFIG_DISABLE_HAL_LOCKS
|
||||
|
|
@ -66,21 +67,21 @@ struct uart_struct_t {
|
|||
#define UART_MUTEX_UNLOCK()
|
||||
|
||||
static uart_t _uart_bus_array[] = {
|
||||
{0, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0},
|
||||
{0, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0, -1},
|
||||
#if SOC_UART_NUM > 1
|
||||
{1, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0},
|
||||
{1, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0, -1},
|
||||
#endif
|
||||
#if SOC_UART_NUM > 2
|
||||
{2, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0},
|
||||
{2, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0, -1},
|
||||
#endif
|
||||
#if SOC_UART_NUM > 3
|
||||
{3, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0},
|
||||
{3, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0, -1},
|
||||
#endif
|
||||
#if SOC_UART_NUM > 4
|
||||
{4, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0},
|
||||
{4, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0, -1},
|
||||
#endif
|
||||
#if SOC_UART_NUM > 5
|
||||
{5, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0},
|
||||
{5, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0, -1},
|
||||
#endif
|
||||
};
|
||||
|
||||
|
|
@ -95,21 +96,21 @@ static uart_t _uart_bus_array[] = {
|
|||
xSemaphoreGive(uart->lock)
|
||||
|
||||
static uart_t _uart_bus_array[] = {
|
||||
{NULL, 0, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0},
|
||||
{NULL, 0, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0, -1},
|
||||
#if SOC_UART_NUM > 1
|
||||
{NULL, 1, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0},
|
||||
{NULL, 1, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0, -1},
|
||||
#endif
|
||||
#if SOC_UART_NUM > 2
|
||||
{NULL, 2, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0},
|
||||
{NULL, 2, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0, -1},
|
||||
#endif
|
||||
#if SOC_UART_NUM > 3
|
||||
{NULL, 3, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0},
|
||||
{NULL, 3, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0, -1},
|
||||
#endif
|
||||
#if SOC_UART_NUM > 4
|
||||
{NULL, 4, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0},
|
||||
{NULL, 4, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0, -1},
|
||||
#endif
|
||||
#if SOC_UART_NUM > 5
|
||||
{NULL, 5, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0},
|
||||
{NULL, 5, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0, -1},
|
||||
#endif
|
||||
};
|
||||
|
||||
|
|
@ -676,30 +677,40 @@ uart_t *uartBegin(
|
|||
rxfifo_full_thrhd = uart_config.rx_flow_ctrl_thresh; // makes sure that it will be set correctly in the struct
|
||||
uart_config.baud_rate = baudrate;
|
||||
#if SOC_UART_LP_NUM >= 1
|
||||
if (uart_nr >= SOC_UART_HP_NUM) { // it is a LP UART NUM
|
||||
uart_config.lp_source_clk = LP_UART_SCLK_DEFAULT; // use default LP clock
|
||||
log_v("Setting UART%d to use LP clock", uart_nr);
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
// there is an issue when returning from light sleep with the C6 and H2: the uart baud rate is not restored
|
||||
// therefore, uart clock source will set to XTAL for all SoC that support it. This fix solves the C6|H2 issue.
|
||||
#if SOC_UART_SUPPORT_XTAL_CLK
|
||||
uart_config.source_clk = UART_SCLK_XTAL; // valid for C2, S3, C3, C6, H2 and P4
|
||||
log_v("Setting UART%d to use XTAL clock", uart_nr);
|
||||
#elif SOC_UART_SUPPORT_REF_TICK
|
||||
if (baudrate <= REF_TICK_BAUDRATE_LIMIT) {
|
||||
uart_config.source_clk = UART_SCLK_REF_TICK; // valid for ESP32, S2 - MAX supported baud rate is 250 Kbps
|
||||
log_v("Setting UART%d to use REF_TICK clock", uart_nr);
|
||||
if (uart_nr >= SOC_UART_HP_NUM) { // it is a LP UART NUM
|
||||
if (uart->_uart_clock_source > 0) {
|
||||
uart_config.lp_source_clk = (soc_periph_lp_uart_clk_src_t)uart->_uart_clock_source; // use user defined LP UART clock
|
||||
log_v("Setting UART%d to user defined LP clock source (%d) ", uart_nr, uart->_uart_clock_source);
|
||||
} else {
|
||||
uart_config.source_clk = UART_SCLK_APB; // baudrate may change with the APB Frequency!
|
||||
log_v("Setting UART%d to use APB clock", uart_nr);
|
||||
uart_config.lp_source_clk = LP_UART_SCLK_DEFAULT; // use default LP clock
|
||||
log_v("Setting UART%d to Default LP clock source", uart_nr);
|
||||
}
|
||||
} else
|
||||
#endif // SOC_UART_LP_NUM >= 1
|
||||
{
|
||||
if (uart->_uart_clock_source >= 0) {
|
||||
uart_config.source_clk = (soc_module_clk_t)uart->_uart_clock_source; // use user defined HP UART clock
|
||||
log_v("Setting UART%d to user defined HP clock source (%d) ", uart_nr, uart->_uart_clock_source);
|
||||
} else {
|
||||
// there is an issue when returning from light sleep with the C6 and H2: the uart baud rate is not restored
|
||||
// therefore, uart clock source will set to XTAL for all SoC that support it. This fix solves the C6|H2 issue.
|
||||
#if SOC_UART_SUPPORT_XTAL_CLK
|
||||
uart_config.source_clk = UART_SCLK_XTAL; // valid for C2, S3, C3, C6, H2 and P4
|
||||
log_v("Setting UART%d to use XTAL clock", uart_nr);
|
||||
#elif SOC_UART_SUPPORT_REF_TICK
|
||||
if (baudrate <= REF_TICK_BAUDRATE_LIMIT) {
|
||||
uart_config.source_clk = UART_SCLK_REF_TICK; // valid for ESP32, S2 - MAX supported baud rate is 250 Kbps
|
||||
log_v("Setting UART%d to use REF_TICK clock", uart_nr);
|
||||
} else {
|
||||
uart_config.source_clk = UART_SCLK_APB; // baudrate may change with the APB Frequency!
|
||||
log_v("Setting UART%d to use APB clock", uart_nr);
|
||||
}
|
||||
#else
|
||||
// Default CLK Source: CLK_APB for ESP32|S2|S3|C3 -- CLK_PLL_F40M for C2 -- CLK_PLL_F48M for H2 -- CLK_PLL_F80M for C6
|
||||
uart_config.source_clk = UART_SCLK_DEFAULT; // baudrate may change with the APB Frequency!
|
||||
log_v("Setting UART%d to use DEFAULT clock", uart_nr);
|
||||
#endif
|
||||
// Default CLK Source: CLK_APB for ESP32|S2|S3|C3 -- CLK_PLL_F40M for C2 -- CLK_PLL_F48M for H2 -- CLK_PLL_F80M for C6|P4
|
||||
uart_config.source_clk = UART_SCLK_DEFAULT; // baudrate may change with the APB Frequency!
|
||||
log_v("Setting UART%d to use DEFAULT clock", uart_nr);
|
||||
#endif // SOC_UART_SUPPORT_XTAL_CLK
|
||||
}
|
||||
}
|
||||
|
||||
UART_MUTEX_LOCK();
|
||||
|
|
@ -728,6 +739,14 @@ uart_t *uartBegin(
|
|||
uart->_tx_buffer_size = tx_buffer_size;
|
||||
uart->has_peek = false;
|
||||
uart->peek_byte = 0;
|
||||
#if SOC_UART_LP_NUM >= 1
|
||||
if (uart_nr >= SOC_UART_HP_NUM) {
|
||||
uart->_uart_clock_source = uart_config.lp_source_clk;
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
uart->_uart_clock_source = uart_config.source_clk;
|
||||
}
|
||||
}
|
||||
UART_MUTEX_UNLOCK();
|
||||
|
||||
|
|
@ -987,22 +1006,52 @@ bool uartSetBaudRate(uart_t *uart, uint32_t baud_rate) {
|
|||
return false;
|
||||
}
|
||||
bool retCode = true;
|
||||
UART_MUTEX_LOCK();
|
||||
#if SOC_UART_SUPPORT_XTAL_CLK // ESP32-S3, ESP32-C3, ESP32-C5, ESP32-C6, ESP32-H2 and ESP32-P4
|
||||
soc_module_clk_t newClkSrc = UART_SCLK_XTAL;
|
||||
soc_module_clk_t newClkSrc = UART_SCLK_DEFAULT;
|
||||
int8_t previousClkSrc = uart->_uart_clock_source;
|
||||
#if SOC_UART_LP_NUM >= 1
|
||||
if (uart->num >= SOC_UART_HP_NUM) { // it is a LP UART NUM
|
||||
newClkSrc = LP_UART_SCLK_DEFAULT; // use default LP clock
|
||||
if (uart->_uart_clock_source > 0) {
|
||||
newClkSrc = (soc_periph_lp_uart_clk_src_t)uart->_uart_clock_source; // use user defined LP UART clock
|
||||
log_v("Setting UART%d to user defined LP clock source (%d) ", uart->num, newClkSrc);
|
||||
} else {
|
||||
newClkSrc = LP_UART_SCLK_DEFAULT; // use default LP clock
|
||||
log_v("Setting UART%d to Default LP clock source", uart->num);
|
||||
}
|
||||
} else
|
||||
#endif // SOC_UART_LP_NUM >= 1
|
||||
{
|
||||
if (uart->_uart_clock_source >= 0) {
|
||||
newClkSrc = (soc_module_clk_t)uart->_uart_clock_source; // use user defined HP UART clock
|
||||
log_v("Setting UART%d to use HP clock source (%d) ", uart->num, newClkSrc);
|
||||
} else {
|
||||
// there is an issue when returning from light sleep with the C6 and H2: the uart baud rate is not restored
|
||||
// therefore, uart clock source will set to XTAL for all SoC that support it. This fix solves the C6|H2 issue.
|
||||
#if SOC_UART_SUPPORT_XTAL_CLK
|
||||
newClkSrc = UART_SCLK_XTAL; // valid for C2, S3, C3, C6, H2 and P4
|
||||
log_v("Setting UART%d to use XTAL clock", uart->num);
|
||||
#elif SOC_UART_SUPPORT_REF_TICK
|
||||
if (baud_rate <= REF_TICK_BAUDRATE_LIMIT) {
|
||||
newClkSrc = UART_SCLK_REF_TICK; // valid for ESP32, S2 - MAX supported baud rate is 250 Kbps
|
||||
log_v("Setting UART%d to use REF_TICK clock", uart->num);
|
||||
} else {
|
||||
newClkSrc = UART_SCLK_APB; // baudrate may change with the APB Frequency!
|
||||
log_v("Setting UART%d to use APB clock", uart->num);
|
||||
}
|
||||
#else
|
||||
// Default CLK Source: CLK_APB for ESP32|S2|S3|C3 -- CLK_PLL_F40M for C2 -- CLK_PLL_F48M for H2 -- CLK_PLL_F80M for C6|P4
|
||||
// using newClkSrc = UART_SCLK_DEFAULT as defined in the variable declaration
|
||||
log_v("Setting UART%d to use DEFAULT clock", uart->num);
|
||||
#endif // SOC_UART_SUPPORT_XTAL_CLK
|
||||
}
|
||||
}
|
||||
#endif
|
||||
// ESP32-P4 demands an atomic operation for setting the clock source
|
||||
HP_UART_SRC_CLK_ATOMIC() {
|
||||
uart_ll_set_sclk(UART_LL_GET_HW(uart->num), newClkSrc);
|
||||
UART_MUTEX_LOCK();
|
||||
// if necessary, set the correct UART Clock Source before changing the baudrate
|
||||
if (previousClkSrc < 0 || previousClkSrc != newClkSrc) {
|
||||
HP_UART_SRC_CLK_ATOMIC() {
|
||||
uart_ll_set_sclk(UART_LL_GET_HW(uart->num), newClkSrc);
|
||||
}
|
||||
uart->_uart_clock_source = newClkSrc;
|
||||
}
|
||||
#else // ESP32, ESP32-S2
|
||||
soc_module_clk_t newClkSrc = baud_rate <= REF_TICK_BAUDRATE_LIMIT ? SOC_MOD_CLK_REF_TICK : SOC_MOD_CLK_APB;
|
||||
uart_ll_set_sclk(UART_LL_GET_HW(uart->num), newClkSrc);
|
||||
#endif
|
||||
if (uart_set_baudrate(uart->num, baud_rate) == ESP_OK) {
|
||||
log_v("Setting UART%d baud rate to %ld.", uart->num, baud_rate);
|
||||
uart->_baudrate = baud_rate;
|
||||
|
|
@ -1096,6 +1145,31 @@ bool uartSetMode(uart_t *uart, uart_mode_t mode) {
|
|||
return retCode;
|
||||
}
|
||||
|
||||
// this function will set the uart clock source
|
||||
// it must be called before uartBegin(), otherwise it won't change any thing.
|
||||
bool uartSetClockSource(uint8_t uartNum, uart_sclk_t clkSrc) {
|
||||
if (uartNum >= SOC_UART_NUM) {
|
||||
log_e("UART%d is invalid. This device has %d UARTs, from 0 to %d.", uartNum, SOC_UART_NUM, SOC_UART_NUM - 1);
|
||||
return false;
|
||||
}
|
||||
uart_t *uart = &_uart_bus_array[uartNum];
|
||||
#if SOC_UART_LP_NUM >= 1
|
||||
if (uart->num >= SOC_UART_HP_NUM) {
|
||||
switch (clkSrc) {
|
||||
case UART_SCLK_XTAL: uart->_uart_clock_source = LP_UART_SCLK_XTAL_D2; break;
|
||||
case UART_SCLK_RTC: uart->_uart_clock_source = LP_UART_SCLK_LP_FAST; break;
|
||||
case UART_SCLK_DEFAULT:
|
||||
default: uart->_uart_clock_source = LP_UART_SCLK_DEFAULT;
|
||||
}
|
||||
} else
|
||||
#endif
|
||||
{
|
||||
uart->_uart_clock_source = clkSrc;
|
||||
}
|
||||
//log_i("UART%d set clock source to %d", uart->num, uart->_uart_clock_source);
|
||||
return true;
|
||||
}
|
||||
|
||||
void uartSetDebug(uart_t *uart) {
|
||||
// LP UART is not supported for debug
|
||||
if (uart == NULL || uart->num >= SOC_UART_HP_NUM) {
|
||||
|
|
@ -1124,7 +1198,7 @@ int log_printfv(const char *format, va_list arg) {
|
|||
return 0;
|
||||
}
|
||||
}
|
||||
/*
|
||||
/*
|
||||
// This causes dead locks with logging in specific cases and also with C++ constructors that may send logs
|
||||
#if !CONFIG_DISABLE_HAL_LOCKS
|
||||
if(s_uart_debug_nr != -1 && _uart_bus_array[s_uart_debug_nr].lock){
|
||||
|
|
@ -1132,16 +1206,8 @@ int log_printfv(const char *format, va_list arg) {
|
|||
}
|
||||
#endif
|
||||
*/
|
||||
#if (ARDUINO_USB_CDC_ON_BOOT == 1 && ARDUINO_USB_MODE == 0) || CONFIG_IDF_TARGET_ESP32C3 \
|
||||
|| ((CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32P4) && ARDUINO_USB_CDC_ON_BOOT == 1)
|
||||
vsnprintf(temp, len + 1, format, arg);
|
||||
ets_printf("%s", temp);
|
||||
#else
|
||||
int wlen = vsnprintf(temp, len + 1, format, arg);
|
||||
for (int i = 0; i < wlen; i++) {
|
||||
ets_write_char_uart(temp[i]);
|
||||
}
|
||||
#endif
|
||||
/*
|
||||
// This causes dead locks with logging and also with constructors that may send logs
|
||||
#if !CONFIG_DISABLE_HAL_LOCKS
|
||||
|
|
|
|||
|
|
@ -97,6 +97,19 @@ bool uartSetHwFlowCtrlMode(uart_t *uart, uart_hw_flowcontrol_t mode, uint8_t thr
|
|||
// UART_MODE_RS485_APP_CTRL = 0x04 mode: application control RS485 UART mode (used for test purposes)
|
||||
bool uartSetMode(uart_t *uart, uart_mode_t mode);
|
||||
|
||||
// Used to set the UART clock source mode. It must be set before calling uartBegin(), otherwise it won't have any effect.
|
||||
// Not all clock source are available to every SoC. The compatible option are listed here:
|
||||
// UART_SCLK_DEFAULT :: any SoC - it will set whatever IDF defines as the default UART Clock Source
|
||||
// UART_SCLK_APB :: ESP32, ESP32-S2, ESP32-C3 and ESP32-S3
|
||||
// UART_SCLK_PLL_F80M :: ESP32-C5, ESP32-C6, ESP32-C61 and ESP32-P4
|
||||
// UART_SCLK_PLL_F40M :: ESP32-C2
|
||||
// UART_SCLK_PLL_F48M :: ESP32-H2
|
||||
// UART_SCLK_XTAL :: ESP32-C2, ESP32-C3, ESP32-C5, ESP32-C6, ESP32-C61, ESP32-H2, ESP32-S3 and ESP32-P4
|
||||
// UART_SCLK_RTC :: ESP32-C2, ESP32-C3, ESP32-C5, ESP32-C6, ESP32-C61, ESP32-H2, ESP32-S3 and ESP32-P4
|
||||
// UART_SCLK_REF_TICK :: ESP32 and ESP32-S2
|
||||
// Note: ESP32-C6, C61, ESP32-P4 and ESP32-C5 have LP UART that will use only LP_UART_SCLK_LP_FAST (RTC_FAST) or LP_UART_SCLK_XTAL_D2 (XTAL/2) as Clock Source
|
||||
bool uartSetClockSource(uint8_t uartNum, uart_sclk_t clkSrc);
|
||||
|
||||
void uartStartDetectBaudrate(uart_t *uart);
|
||||
unsigned long uartDetectBaudrate(uart_t *uart);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
// Copyright 2023 Espressif Systems (Shanghai) PTE LTD
|
||||
// Copyright 2025 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.
|
||||
|
|
@ -35,14 +35,11 @@
|
|||
rmt_data_t my_data[256];
|
||||
rmt_data_t data[256];
|
||||
|
||||
static EventGroupHandle_t events;
|
||||
|
||||
#define RMT_FREQ 10000000 // tick time is 100ns
|
||||
#define RMT_NUM_EXCHANGED_DATA 30
|
||||
#define RMT_NUM_EXCHANGED_DATA 32
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
events = xEventGroupCreate();
|
||||
|
||||
if (!rmtInit(RMT_TX_PIN, RMT_TX_MODE, RMT_MEM_NUM_BLOCKS_1, RMT_FREQ)) {
|
||||
Serial.println("init sender failed\n");
|
||||
|
|
@ -50,25 +47,41 @@ void setup() {
|
|||
if (!rmtInit(RMT_RX_PIN, RMT_RX_MODE, RMT_MEM_RX, RMT_FREQ)) {
|
||||
Serial.println("init receiver failed\n");
|
||||
}
|
||||
Serial.println();
|
||||
Serial.println("RMT tick set to: 100ns");
|
||||
|
||||
// End of transmission shall be detected when line is idle for 2us = 20*100ns
|
||||
rmtSetRxMaxThreshold(RMT_RX_PIN, 20);
|
||||
// Disable Glitch filter
|
||||
rmtSetRxMinThreshold(RMT_RX_PIN, 0);
|
||||
|
||||
Serial.println("real tick set to: 100ns");
|
||||
Serial.printf("\nPlease connect GPIO %d to GPIO %d, now.\n", RMT_TX_PIN, RMT_RX_PIN);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// Init data
|
||||
int i;
|
||||
for (i = 0; i < 255; i++) {
|
||||
data[i].val = 0x80010001 + ((i % 13) << 16) + 13 - (i % 13);
|
||||
// create multiple pulses with different width to be sent
|
||||
for (int i = 0; i < 255; i++) {
|
||||
data[i].level0 = 1; // HIGH
|
||||
data[i].duration0 = 1 + 13 - (i % 13); // number of Tick on High
|
||||
data[i].level1 = 0; // LOW
|
||||
data[i].duration1 = 1 + (i % 13); // number of Ticks on Low
|
||||
my_data[i].val = 0;
|
||||
}
|
||||
data[255].val = 0;
|
||||
Serial.println();
|
||||
Serial.println("====================================================================================================");
|
||||
Serial.println("Preloaded Data that will sent (time in 0.1us):");
|
||||
// Printout the received data plus the original values
|
||||
for (int i = 0; i < RMT_NUM_EXCHANGED_DATA; i++) {
|
||||
Serial.printf("%08lx=[%c 0x%02x|%c 0x%02x] ", data[i].val, data[i].level0 ? 'H' : 'L', data[i].duration0, data[i].level1 ? 'H' : 'L', data[i].duration1);
|
||||
|
||||
if (!((i + 1) % 4)) {
|
||||
Serial.println();
|
||||
}
|
||||
}
|
||||
Serial.println("====================================================================================================");
|
||||
Serial.printf("Please connect GPIO %d to GPIO %d, now.", RMT_TX_PIN, RMT_RX_PIN);
|
||||
Serial.println();
|
||||
Serial.println();
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// Start an async data read
|
||||
size_t rx_num_symbols = RMT_NUM_EXCHANGED_DATA;
|
||||
rmtReadAsync(RMT_RX_PIN, my_data, &rx_num_symbols);
|
||||
|
|
@ -84,13 +97,13 @@ void loop() {
|
|||
Serial.printf("Got %d RMT symbols\n", rx_num_symbols);
|
||||
|
||||
// Printout the received data plus the original values
|
||||
for (i = 0; i < 60; i++) {
|
||||
for (int i = 0; i < RMT_NUM_EXCHANGED_DATA; i++) {
|
||||
Serial.printf("%08lx=%08lx ", my_data[i].val, data[i].val);
|
||||
if (!((i + 1) % 4)) {
|
||||
Serial.println("");
|
||||
Serial.println();
|
||||
}
|
||||
}
|
||||
Serial.println("\n");
|
||||
Serial.println();
|
||||
|
||||
delay(500);
|
||||
delay(2000);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -37,10 +37,14 @@
|
|||
#define CONSUMER_CONTROL_WIRELESS_RADIO_SLIDER_SWITCH 0x00C8
|
||||
|
||||
// Media Control
|
||||
#define CONSUMER_CONTROL_PLAY_PAUSE 0x00CD
|
||||
#define CONSUMER_CONTROL_RECORD 0x00B2
|
||||
#define CONSUMER_CONTROL_FAST_FORWARD 0x00B3
|
||||
#define CONSUMER_CONTROL_REWIND 0x00B4
|
||||
#define CONSUMER_CONTROL_SCAN_NEXT 0x00B5
|
||||
#define CONSUMER_CONTROL_SCAN_PREVIOUS 0x00B6
|
||||
#define CONSUMER_CONTROL_STOP 0x00B7
|
||||
#define CONSUMER_CONTROL_EJECT 0x00B8
|
||||
#define CONSUMER_CONTROL_PLAY_PAUSE 0x00CD
|
||||
#define CONSUMER_CONTROL_VOLUME 0x00E0
|
||||
#define CONSUMER_CONTROL_MUTE 0x00E2
|
||||
#define CONSUMER_CONTROL_BASS 0x00E3
|
||||
|
|
|
|||
|
|
@ -606,9 +606,9 @@ bool WiFiGenericClass::mode(wifi_mode_t m) {
|
|||
#else
|
||||
#define WIFI_PROTOCOL_DEFAULT (WIFI_PROTOCOL_11B | WIFI_PROTOCOL_11G | WIFI_PROTOCOL_11N)
|
||||
#endif
|
||||
uint8_t current_protocol = 0;
|
||||
uint32_t current_protocol = 0;
|
||||
if (m & WIFI_MODE_STA) {
|
||||
err = esp_wifi_get_protocol(WIFI_IF_STA, ¤t_protocol);
|
||||
err = esp_wifi_get_protocol(WIFI_IF_STA, (uint8_t *)¤t_protocol);
|
||||
if (err == ESP_OK && current_protocol == WIFI_PROTOCOL_LR) {
|
||||
log_v("Disabling long range on STA");
|
||||
err = esp_wifi_set_protocol(WIFI_IF_STA, WIFI_PROTOCOL_DEFAULT);
|
||||
|
|
@ -618,7 +618,7 @@ bool WiFiGenericClass::mode(wifi_mode_t m) {
|
|||
}
|
||||
}
|
||||
if (m & WIFI_MODE_AP) {
|
||||
err = esp_wifi_get_protocol(WIFI_IF_AP, ¤t_protocol);
|
||||
err = esp_wifi_get_protocol(WIFI_IF_AP, (uint8_t *)¤t_protocol);
|
||||
if (err == ESP_OK && current_protocol == WIFI_PROTOCOL_LR) {
|
||||
log_v("Disabling long range on AP");
|
||||
err = esp_wifi_set_protocol(WIFI_IF_AP, WIFI_PROTOCOL_DEFAULT);
|
||||
|
|
|
|||
72
libraries/Zigbee/examples/Zigbee_PM25_Sensor/README.md
Normal file
72
libraries/Zigbee/examples/Zigbee_PM25_Sensor/README.md
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
# Arduino-ESP32 PM2.5 Sensor
|
||||
|
||||
This example shows how to configure the Zigbee end device and use it as a Home Automation (HA) simple sensor device type with particulate matter (PM2.5) measuring
|
||||
|
||||
# Supported Targets
|
||||
|
||||
Currently, this example supports the following targets.
|
||||
|
||||
| Supported Targets | ESP32-C6 | ESP32-H2 |
|
||||
| ----------------- | -------- | -------- |
|
||||
|
||||
## Pressure + Flow Sensor Functions
|
||||
|
||||
* After this board first starts up, it would be configured locally to report the PM2.5 on every 30 seconds.
|
||||
* By clicking the button (BOOT) on this board, this board will immediately send a report of the current PM2.5 to the network.
|
||||
|
||||
## Hardware Required
|
||||
|
||||
* A USB cable for power supply and programming
|
||||
|
||||
### Configure the Project
|
||||
|
||||
In this example, the internal temperature sensor is used to demonstrate reading of the PM2.5 sensors.
|
||||
Set the Button GPIO by changing the `button` variable. By default, it's the pin `BOOT_PIN` (BOOT button on ESP32-C6 and ESP32-H2).
|
||||
|
||||
#### Using Arduino IDE
|
||||
|
||||
To get more information about the Espressif boards see [Espressif Development Kits](https://www.espressif.com/en/products/devkits).
|
||||
|
||||
* Before Compile/Verify, select the correct board: `Tools -> Board`.
|
||||
* Select the End device Zigbee mode: `Tools -> Zigbee mode: Zigbee ED (end device)`
|
||||
* Select Partition Scheme for Zigbee: `Tools -> Partition Scheme: Zigbee 4MB with spiffs`
|
||||
* Select the COM port: `Tools -> Port: xxx` where the `xxx` is the detected COM port.
|
||||
* Optional: Set debug level to verbose to see all logs from Zigbee stack: `Tools -> Core Debug Level: Verbose`.
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
If the End device flashed with this example is not connecting to the coordinator, erase the flash of the End device before flashing the example to the board. It is recommended to do this if you re-flash the coordinator.
|
||||
You can do the following:
|
||||
|
||||
* In the Arduino IDE go to the Tools menu and set `Erase All Flash Before Sketch Upload` to `Enabled`.
|
||||
* Add to the sketch `Zigbee.factoryReset();` to reset the device and Zigbee stack.
|
||||
|
||||
By default, the coordinator network is closed after rebooting or flashing new firmware.
|
||||
To open the network you have 2 options:
|
||||
|
||||
* Open network after reboot by setting `Zigbee.setRebootOpenNetwork(time);` before calling `Zigbee.begin();`.
|
||||
* In application you can anytime call `Zigbee.openNetwork(time);` to open the network for devices to join.
|
||||
|
||||
***Important: Make sure you are using a good quality USB cable and that you have a reliable power source***
|
||||
|
||||
* **LED not blinking:** Check the wiring connection and the IO selection.
|
||||
* **Programming Fail:** If the programming/flash procedure fails, try reducing the serial connection speed.
|
||||
* **COM port not detected:** Check the USB cable and the USB to Serial driver installation.
|
||||
|
||||
If the error persists, you can ask for help at the official [ESP32 forum](https://esp32.com) or see [Contribute](#contribute).
|
||||
|
||||
## Contribute
|
||||
|
||||
To know how to contribute to this project, see [How to contribute.](https://github.com/espressif/arduino-esp32/blob/master/CONTRIBUTING.rst)
|
||||
|
||||
If you have any **feedback** or **issue** to report on this example/library, please open an issue or fix it by creating a new PR. Contributions are more than welcome!
|
||||
|
||||
Before creating a new issue, be sure to try Troubleshooting and check if the same issue was already created by someone else.
|
||||
|
||||
## Resources
|
||||
|
||||
* Official ESP32 Forum: [Link](https://esp32.com)
|
||||
* Arduino-ESP32 Official Repository: [espressif/arduino-esp32](https://github.com/espressif/arduino-esp32)
|
||||
* ESP32-C6 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-c6_datasheet_en.pdf)
|
||||
* ESP32-H2 Datasheet: [Link to datasheet](https://www.espressif.com/sites/default/files/documentation/esp32-h2_datasheet_en.pdf)
|
||||
* Official ESP-IDF documentation: [ESP-IDF](https://idf.espressif.com)
|
||||
|
|
@ -0,0 +1,109 @@
|
|||
// 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 PM2.5 sensor.
|
||||
*
|
||||
* The example demonstrates how to use Zigbee library to create a end device PM2.5 sensor.
|
||||
*
|
||||
* 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 PM2.5 sensor configuration */
|
||||
#define PM2_5_SENSOR_ENDPOINT_NUMBER 1
|
||||
uint8_t button = BOOT_PIN;
|
||||
|
||||
ZigbeePM25Sensor zbPM25Sensor = ZigbeePM25Sensor(PM2_5_SENSOR_ENDPOINT_NUMBER);
|
||||
|
||||
void setup() {
|
||||
Serial.begin(115200);
|
||||
|
||||
// Init button switch
|
||||
pinMode(button, INPUT_PULLUP);
|
||||
|
||||
// Optional: set Zigbee device name and model
|
||||
zbPM25Sensor.setManufacturerAndModel("Espressif", "ZigbeePM25Sensor");
|
||||
|
||||
// Set minimum and maximum PM2.5 measurement value in µg/m³
|
||||
zbPM25Sensor.setMinMaxValue(0, 350);
|
||||
|
||||
// Set tolerance for PM2.5 measurement in µg/m³
|
||||
zbPM25Sensor.setTolerance(0.1);
|
||||
|
||||
// Add endpoints to Zigbee Core
|
||||
Zigbee.addEndpoint(&zbPM25Sensor);
|
||||
|
||||
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();
|
||||
|
||||
// Set reporting interval for PM2.5 measurement to be done every 30 seconds, must be called after Zigbee.begin()
|
||||
// min_interval and max_interval in seconds, delta (PM2.5 change in µg/m³)
|
||||
// if min = 1 and max = 0, reporting is sent only when PM2.5 changes by delta
|
||||
// if min = 0 and max = 10, reporting is sent every 10 seconds or when PM2.5 changes by delta
|
||||
// if min = 0, max = 10 and delta = 0, reporting is sent every 10 seconds regardless of delta change
|
||||
zbPM25Sensor.setReporting(0, 30, 0);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
static uint32_t timeCounter = 0;
|
||||
// Read PM2.5 sensor every 2s
|
||||
if (!(timeCounter++ % 20)) { // delaying for 100ms x 20 = 2s
|
||||
// Read sensor value - here is chip temperature used + 50 as a dummy value for demonstration
|
||||
float pm25_value = 50.5 + temperatureRead();
|
||||
Serial.printf("Updating PM2.5 sensor value to %0.1f µg/m³\r\n", pm25_value);
|
||||
zbPM25Sensor.setPM25(pm25_value);
|
||||
}
|
||||
|
||||
// Checking button for factory reset and reporting
|
||||
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();
|
||||
}
|
||||
}
|
||||
zbPM25Sensor.report();
|
||||
}
|
||||
delay(100);
|
||||
}
|
||||
7
libraries/Zigbee/examples/Zigbee_PM25_Sensor/ci.json
Normal file
7
libraries/Zigbee/examples/Zigbee_PM25_Sensor/ci.json
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"fqbn_append": "PartitionScheme=zigbee,ZigbeeMode=ed",
|
||||
"requires": [
|
||||
"CONFIG_SOC_IEEE802154_SUPPORTED=y",
|
||||
"CONFIG_ZB_ENABLED=y"
|
||||
]
|
||||
}
|
||||
|
|
@ -85,9 +85,9 @@ void setup() {
|
|||
// Set tolerance for temperature measurement in °C (lowest possible value is 0.01°C)
|
||||
zbTempSensor.setTolerance(1);
|
||||
|
||||
// Set power source to battery and set battery percentage to measured value (now 100% for demonstration)
|
||||
// The value can be also updated by calling zbTempSensor.setBatteryPercentage(percentage) anytime
|
||||
zbTempSensor.setPowerSource(ZB_POWER_SOURCE_BATTERY, 100);
|
||||
// Set power source to battery, battery percentage and battery voltage (now 100% and 3.5V for demonstration)
|
||||
// The value can be also updated by calling zbTempSensor.setBatteryPercentage(percentage) or zbTempSensor.setBatteryVoltage(voltage) anytime after Zigbee.begin()
|
||||
zbTempSensor.setPowerSource(ZB_POWER_SOURCE_BATTERY, 100, 35);
|
||||
|
||||
// Add humidity cluster to the temperature sensor device with min, max and tolerance values
|
||||
zbTempSensor.addHumiditySensor(0, 100, 1);
|
||||
|
|
|
|||
|
|
@ -7,23 +7,29 @@
|
|||
#include "ZigbeeEP.h"
|
||||
|
||||
// Endpoints
|
||||
#include "ep/ZigbeeLight.h"
|
||||
#include "ep/ZigbeeSwitch.h"
|
||||
#include "ep/ZigbeeDimmableLight.h"
|
||||
#include "ep/ZigbeeColorDimmableLight.h"
|
||||
//// Switches
|
||||
#include "ep/ZigbeeColorDimmerSwitch.h"
|
||||
#include "ep/ZigbeeTempSensor.h"
|
||||
#include "ep/ZigbeeSwitch.h"
|
||||
//// Lights
|
||||
#include "ep/ZigbeeColorDimmableLight.h"
|
||||
#include "ep/ZigbeeDimmableLight.h"
|
||||
#include "ep/ZigbeeLight.h"
|
||||
//// Controllers
|
||||
#include "ep/ZigbeeThermostat.h"
|
||||
#include "ep/ZigbeePressureSensor.h"
|
||||
//// Sensors
|
||||
#include "ep/ZigbeeAnalog.h"
|
||||
#include "ep/ZigbeeFlowSensor.h"
|
||||
#include "ep/ZigbeeOccupancySensor.h"
|
||||
#include "ep/ZigbeeIlluminanceSensor.h"
|
||||
#include "ep/ZigbeeCarbonDioxideSensor.h"
|
||||
#include "ep/ZigbeeContactSwitch.h"
|
||||
#include "ep/ZigbeeDoorWindowHandle.h"
|
||||
#include "ep/ZigbeeWindowCovering.h"
|
||||
#include "ep/ZigbeeFlowSensor.h"
|
||||
#include "ep/ZigbeeIlluminanceSensor.h"
|
||||
#include "ep/ZigbeeOccupancySensor.h"
|
||||
#include "ep/ZigbeePM25Sensor.h"
|
||||
#include "ep/ZigbeePressureSensor.h"
|
||||
#include "ep/ZigbeeTempSensor.h"
|
||||
#include "ep/ZigbeeVibrationSensor.h"
|
||||
#include "ep/ZigbeeRangeExtender.h"
|
||||
#include "ep/ZigbeeGateway.h"
|
||||
#include "ep/ZigbeeWindSpeedSensor.h"
|
||||
#include "ep/ZigbeeWindowCovering.h"
|
||||
//// Other
|
||||
#include "ep/ZigbeeGateway.h"
|
||||
#include "ep/ZigbeeRangeExtender.h"
|
||||
|
|
|
|||
|
|
@ -19,6 +19,8 @@ ZigbeeEP::ZigbeeEP(uint8_t endpoint) {
|
|||
_ep_config.endpoint = 0;
|
||||
_cluster_list = nullptr;
|
||||
_on_identify = nullptr;
|
||||
_read_model = NULL;
|
||||
_read_manufacturer = NULL;
|
||||
_time_status = 0;
|
||||
if (!lock) {
|
||||
lock = xSemaphoreCreateBinary();
|
||||
|
|
@ -33,16 +35,23 @@ void ZigbeeEP::setVersion(uint8_t version) {
|
|||
}
|
||||
|
||||
bool ZigbeeEP::setManufacturerAndModel(const char *name, const char *model) {
|
||||
// Allocate a new array of size length + 2 (1 for the length, 1 for null terminator)
|
||||
char zb_name[ZB_MAX_NAME_LENGTH + 2];
|
||||
char zb_model[ZB_MAX_NAME_LENGTH + 2];
|
||||
|
||||
// Convert manufacturer to ZCL string
|
||||
size_t name_length = strlen(name);
|
||||
size_t model_length = strlen(model);
|
||||
if (name_length > 32 || model_length > 32) {
|
||||
if (name_length > ZB_MAX_NAME_LENGTH || model_length > ZB_MAX_NAME_LENGTH) {
|
||||
log_e("Manufacturer or model name is too long");
|
||||
return false;
|
||||
}
|
||||
// Allocate a new array of size length + 2 (1 for the length, 1 for null terminator)
|
||||
char *zb_name = new char[name_length + 2];
|
||||
char *zb_model = new char[model_length + 2];
|
||||
// Get and check the basic cluster
|
||||
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);
|
||||
if (basic_cluster == nullptr) {
|
||||
log_e("Failed to get basic cluster");
|
||||
return false;
|
||||
}
|
||||
// Store the length as the first element
|
||||
zb_name[0] = static_cast<char>(name_length); // Cast size_t to char
|
||||
zb_model[0] = static_cast<char>(model_length);
|
||||
|
|
@ -52,9 +61,7 @@ bool ZigbeeEP::setManufacturerAndModel(const char *name, const char *model) {
|
|||
// Null-terminate the array
|
||||
zb_name[name_length + 1] = '\0';
|
||||
zb_model[model_length + 1] = '\0';
|
||||
|
||||
// Get the basic cluster and update the manufacturer and model attributes
|
||||
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);
|
||||
// Update the manufacturer and model attributes
|
||||
esp_err_t ret_name = esp_zb_basic_cluster_add_attr(basic_cluster, ESP_ZB_ZCL_ATTR_BASIC_MANUFACTURER_NAME_ID, (void *)zb_name);
|
||||
if (ret_name != ESP_OK) {
|
||||
log_e("Failed to set manufacturer: 0x%x: %s", ret_name, esp_err_to_name(ret_name));
|
||||
|
|
@ -63,12 +70,10 @@ bool ZigbeeEP::setManufacturerAndModel(const char *name, const char *model) {
|
|||
if (ret_model != ESP_OK) {
|
||||
log_e("Failed to set model: 0x%x: %s", ret_model, esp_err_to_name(ret_model));
|
||||
}
|
||||
delete[] zb_name;
|
||||
delete[] zb_model;
|
||||
return ret_name == ESP_OK && ret_model == ESP_OK;
|
||||
}
|
||||
|
||||
bool ZigbeeEP::setPowerSource(zb_power_source_t power_source, uint8_t battery_percentage) {
|
||||
bool ZigbeeEP::setPowerSource(zb_power_source_t power_source, uint8_t battery_percentage, uint8_t battery_voltage) {
|
||||
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);
|
||||
esp_err_t ret = esp_zb_cluster_update_attr(basic_cluster, ESP_ZB_ZCL_ATTR_BASIC_POWER_SOURCE_ID, (void *)&power_source);
|
||||
if (ret != ESP_OK) {
|
||||
|
|
@ -88,6 +93,11 @@ bool ZigbeeEP::setPowerSource(zb_power_source_t power_source, uint8_t battery_pe
|
|||
log_e("Failed to add battery percentage attribute: 0x%x: %s", ret, esp_err_to_name(ret));
|
||||
return false;
|
||||
}
|
||||
ret = esp_zb_power_config_cluster_add_attr(power_config_cluster, ESP_ZB_ZCL_ATTR_POWER_CONFIG_BATTERY_VOLTAGE_ID, (void *)&battery_voltage);
|
||||
if (ret != ESP_OK) {
|
||||
log_e("Failed to add battery voltage attribute: 0x%x: %s", ret, esp_err_to_name(ret));
|
||||
return false;
|
||||
}
|
||||
ret = esp_zb_cluster_list_add_power_config_cluster(_cluster_list, power_config_cluster, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);
|
||||
if (ret != ESP_OK) {
|
||||
log_e("Failed to add power config cluster: 0x%x: %s", ret, esp_err_to_name(ret));
|
||||
|
|
@ -120,6 +130,21 @@ bool ZigbeeEP::setBatteryPercentage(uint8_t percentage) {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool ZigbeeEP::setBatteryVoltage(uint8_t voltage) {
|
||||
esp_zb_zcl_status_t ret = ESP_ZB_ZCL_STATUS_SUCCESS;
|
||||
esp_zb_lock_acquire(portMAX_DELAY);
|
||||
ret = esp_zb_zcl_set_attribute_val(
|
||||
_endpoint, ESP_ZB_ZCL_CLUSTER_ID_POWER_CONFIG, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_POWER_CONFIG_BATTERY_VOLTAGE_ID, &voltage, false
|
||||
);
|
||||
esp_zb_lock_release();
|
||||
if (ret != ESP_ZB_ZCL_STATUS_SUCCESS) {
|
||||
log_e("Failed to set battery voltage: 0x%x: %s", ret, esp_zb_zcl_status_to_name(ret));
|
||||
return false;
|
||||
}
|
||||
log_v("Battery voltage updated");
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ZigbeeEP::reportBatteryPercentage() {
|
||||
/* Send report attributes command */
|
||||
esp_zb_zcl_report_attr_cmd_t report_attr_cmd;
|
||||
|
|
@ -163,10 +188,10 @@ char *ZigbeeEP::readManufacturer(uint8_t endpoint, uint16_t short_addr, esp_zb_i
|
|||
read_req.attr_number = ZB_ARRAY_LENTH(attributes);
|
||||
read_req.attr_field = attributes;
|
||||
|
||||
if (_read_manufacturer != nullptr) {
|
||||
if (_read_manufacturer != NULL) {
|
||||
free(_read_manufacturer);
|
||||
}
|
||||
_read_manufacturer = nullptr;
|
||||
_read_manufacturer = NULL;
|
||||
|
||||
esp_zb_lock_acquire(portMAX_DELAY);
|
||||
esp_zb_zcl_read_attr_cmd_req(&read_req);
|
||||
|
|
@ -201,10 +226,10 @@ char *ZigbeeEP::readModel(uint8_t endpoint, uint16_t short_addr, esp_zb_ieee_add
|
|||
read_req.attr_number = ZB_ARRAY_LENTH(attributes);
|
||||
read_req.attr_field = attributes;
|
||||
|
||||
if (_read_model != nullptr) {
|
||||
if (_read_model != NULL) {
|
||||
free(_read_model);
|
||||
}
|
||||
_read_model = nullptr;
|
||||
_read_model = NULL;
|
||||
|
||||
esp_zb_lock_acquire(portMAX_DELAY);
|
||||
esp_zb_zcl_read_attr_cmd_req(&read_req);
|
||||
|
|
@ -245,20 +270,28 @@ void ZigbeeEP::zbReadBasicCluster(const esp_zb_zcl_attribute_t *attribute) {
|
|||
/* Basic cluster attributes */
|
||||
if (attribute->id == ESP_ZB_ZCL_ATTR_BASIC_MANUFACTURER_NAME_ID && attribute->data.type == ESP_ZB_ZCL_ATTR_TYPE_CHAR_STRING && attribute->data.value) {
|
||||
zbstring_t *zbstr = (zbstring_t *)attribute->data.value;
|
||||
char *string = (char *)malloc(zbstr->len + 1);
|
||||
memcpy(string, zbstr->data, zbstr->len);
|
||||
string[zbstr->len] = '\0';
|
||||
log_i("Peer Manufacturer is \"%s\"", string);
|
||||
_read_manufacturer = string;
|
||||
_read_manufacturer = (char *)malloc(zbstr->len + 1);
|
||||
if (_read_manufacturer == NULL) {
|
||||
log_e("Failed to allocate memory for manufacturer data");
|
||||
xSemaphoreGive(lock);
|
||||
return;
|
||||
}
|
||||
memcpy(_read_manufacturer, zbstr->data, zbstr->len);
|
||||
_read_manufacturer[zbstr->len] = '\0';
|
||||
log_i("Peer Manufacturer is \"%s\"", _read_manufacturer);
|
||||
xSemaphoreGive(lock);
|
||||
}
|
||||
if (attribute->id == ESP_ZB_ZCL_ATTR_BASIC_MODEL_IDENTIFIER_ID && attribute->data.type == ESP_ZB_ZCL_ATTR_TYPE_CHAR_STRING && attribute->data.value) {
|
||||
zbstring_t *zbstr = (zbstring_t *)attribute->data.value;
|
||||
char *string = (char *)malloc(zbstr->len + 1);
|
||||
memcpy(string, zbstr->data, zbstr->len);
|
||||
string[zbstr->len] = '\0';
|
||||
log_i("Peer Model is \"%s\"", string);
|
||||
_read_model = string;
|
||||
_read_model = (char *)malloc(zbstr->len + 1);
|
||||
if (_read_model == NULL) {
|
||||
log_e("Failed to allocate memory for model data");
|
||||
xSemaphoreGive(lock);
|
||||
return;
|
||||
}
|
||||
memcpy(_read_model, zbstr->data, zbstr->len);
|
||||
_read_model[zbstr->len] = '\0';
|
||||
log_i("Peer Model is \"%s\"", _read_model);
|
||||
xSemaphoreGive(lock);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -41,6 +41,10 @@ typedef enum {
|
|||
/* Zigbee End Device Class */
|
||||
class ZigbeeEP {
|
||||
public:
|
||||
// constants and limits
|
||||
static constexpr size_t ZB_MAX_NAME_LENGTH = 32;
|
||||
|
||||
// constructors and destructor
|
||||
ZigbeeEP(uint8_t endpoint = 10);
|
||||
~ZigbeeEP() {}
|
||||
|
||||
|
|
@ -77,9 +81,10 @@ public:
|
|||
char *readModel(uint8_t endpoint, uint16_t short_addr, esp_zb_ieee_addr_t ieee_addr);
|
||||
|
||||
// Set Power source and battery percentage for battery powered devices
|
||||
bool setPowerSource(zb_power_source_t power_source, uint8_t percentage = 255);
|
||||
bool setBatteryPercentage(uint8_t percentage);
|
||||
bool reportBatteryPercentage();
|
||||
bool setPowerSource(zb_power_source_t power_source, uint8_t percentage = 0xff, uint8_t voltage = 0xff); // voltage in 100mV
|
||||
bool setBatteryPercentage(uint8_t percentage); // 0-100 %
|
||||
bool setBatteryVoltage(uint8_t voltage); // voltage in 100mV (example value 35 for 3.5V)
|
||||
bool reportBatteryPercentage(); // battery voltage is not reportable attribute
|
||||
|
||||
// Set time
|
||||
bool addTimeCluster(tm time = {}, int32_t gmt_offset = 0); // gmt offset in seconds
|
||||
|
|
|
|||
118
libraries/Zigbee/src/ep/ZigbeePM25Sensor.cpp
Normal file
118
libraries/Zigbee/src/ep/ZigbeePM25Sensor.cpp
Normal file
|
|
@ -0,0 +1,118 @@
|
|||
#include "ZigbeePM25Sensor.h"
|
||||
#if CONFIG_ZB_ENABLED
|
||||
|
||||
esp_zb_cluster_list_t *zigbee_pm2_5_sensor_clusters_create(zigbee_pm2_5_sensor_cfg_t *pm2_5_sensor) {
|
||||
esp_zb_basic_cluster_cfg_t *basic_cfg = pm2_5_sensor ? &(pm2_5_sensor->basic_cfg) : NULL;
|
||||
esp_zb_identify_cluster_cfg_t *identify_cfg = pm2_5_sensor ? &(pm2_5_sensor->identify_cfg) : NULL;
|
||||
esp_zb_pm2_5_measurement_cluster_cfg_t *pm2_5_meas_cfg = pm2_5_sensor ? &(pm2_5_sensor->pm2_5_meas_cfg) : NULL;
|
||||
esp_zb_cluster_list_t *cluster_list = esp_zb_zcl_cluster_list_create();
|
||||
esp_zb_cluster_list_add_basic_cluster(cluster_list, esp_zb_basic_cluster_create(basic_cfg), ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);
|
||||
esp_zb_cluster_list_add_identify_cluster(cluster_list, esp_zb_identify_cluster_create(identify_cfg), ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);
|
||||
esp_zb_cluster_list_add_pm2_5_measurement_cluster(cluster_list, esp_zb_pm2_5_measurement_cluster_create(pm2_5_meas_cfg), ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);
|
||||
return cluster_list;
|
||||
}
|
||||
|
||||
ZigbeePM25Sensor::ZigbeePM25Sensor(uint8_t endpoint) : ZigbeeEP(endpoint) {
|
||||
_device_id = ESP_ZB_HA_SIMPLE_SENSOR_DEVICE_ID;
|
||||
|
||||
//Create custom PM2.5 sensor configuration
|
||||
zigbee_pm2_5_sensor_cfg_t pm2_5_sensor_cfg = ZIGBEE_DEFAULT_PM2_5_SENSOR_CONFIG();
|
||||
_cluster_list = zigbee_pm2_5_sensor_clusters_create(&pm2_5_sensor_cfg);
|
||||
|
||||
_ep_config = {.endpoint = _endpoint, .app_profile_id = ESP_ZB_AF_HA_PROFILE_ID, .app_device_id = ESP_ZB_HA_SIMPLE_SENSOR_DEVICE_ID, .app_device_version = 0};
|
||||
}
|
||||
|
||||
bool ZigbeePM25Sensor::setMinMaxValue(float min, float max) {
|
||||
esp_zb_attribute_list_t *pm2_5_measure_cluster =
|
||||
esp_zb_cluster_list_get_cluster(_cluster_list, ESP_ZB_ZCL_CLUSTER_ID_PM2_5_MEASUREMENT, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);
|
||||
esp_err_t ret = esp_zb_cluster_update_attr(pm2_5_measure_cluster, ESP_ZB_ZCL_ATTR_PM2_5_MEASUREMENT_MIN_MEASURED_VALUE_ID, (void *)&min);
|
||||
if (ret != ESP_OK) {
|
||||
log_e("Failed to set min value: 0x%x: %s", ret, esp_err_to_name(ret));
|
||||
return false;
|
||||
}
|
||||
ret = esp_zb_cluster_update_attr(pm2_5_measure_cluster, ESP_ZB_ZCL_ATTR_PM2_5_MEASUREMENT_MAX_MEASURED_VALUE_ID, (void *)&max);
|
||||
if (ret != ESP_OK) {
|
||||
log_e("Failed to set max value: 0x%x: %s", ret, esp_err_to_name(ret));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ZigbeePM25Sensor::setTolerance(float tolerance) {
|
||||
esp_zb_attribute_list_t *pm2_5_measure_cluster =
|
||||
esp_zb_cluster_list_get_cluster(_cluster_list, ESP_ZB_ZCL_CLUSTER_ID_PM2_5_MEASUREMENT, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE);
|
||||
esp_err_t ret = esp_zb_pm2_5_measurement_cluster_add_attr(pm2_5_measure_cluster, ESP_ZB_ZCL_ATTR_PM2_5_MEASUREMENT_TOLERANCE_ID, (void *)&tolerance);
|
||||
if (ret != ESP_OK) {
|
||||
log_e("Failed to set tolerance: 0x%x: %s", ret, esp_err_to_name(ret));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ZigbeePM25Sensor::setReporting(uint16_t min_interval, uint16_t max_interval, float delta) {
|
||||
esp_zb_zcl_reporting_info_t reporting_info;
|
||||
memset(&reporting_info, 0, sizeof(esp_zb_zcl_reporting_info_t));
|
||||
reporting_info.direction = ESP_ZB_ZCL_CMD_DIRECTION_TO_SRV;
|
||||
reporting_info.ep = _endpoint;
|
||||
reporting_info.cluster_id = ESP_ZB_ZCL_CLUSTER_ID_PM2_5_MEASUREMENT;
|
||||
reporting_info.cluster_role = ESP_ZB_ZCL_CLUSTER_SERVER_ROLE;
|
||||
reporting_info.attr_id = ESP_ZB_ZCL_ATTR_PM2_5_MEASUREMENT_MEASURED_VALUE_ID;
|
||||
reporting_info.u.send_info.min_interval = min_interval;
|
||||
reporting_info.u.send_info.max_interval = max_interval;
|
||||
reporting_info.u.send_info.def_min_interval = min_interval;
|
||||
reporting_info.u.send_info.def_max_interval = max_interval;
|
||||
// reporting_info.u.send_info.delta.u16 = (uint16_t)(delta * 100); // Convert delta to ZCL uint16_t
|
||||
reporting_info.dst.profile_id = ESP_ZB_AF_HA_PROFILE_ID;
|
||||
reporting_info.manuf_code = ESP_ZB_ZCL_ATTR_NON_MANUFACTURER_SPECIFIC;
|
||||
float delta_f = delta;
|
||||
memcpy(&reporting_info.u.send_info.delta.s32, &delta_f, sizeof(float));
|
||||
|
||||
esp_zb_lock_acquire(portMAX_DELAY);
|
||||
esp_err_t ret = esp_zb_zcl_update_reporting_info(&reporting_info);
|
||||
esp_zb_lock_release();
|
||||
if (ret != ESP_OK) {
|
||||
log_e("Failed to set reporting: 0x%x: %s", ret, esp_err_to_name(ret));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ZigbeePM25Sensor::setPM25(float pm25) {
|
||||
esp_zb_zcl_status_t ret = ESP_ZB_ZCL_STATUS_SUCCESS;
|
||||
log_v("Updating PM2.5 sensor value...");
|
||||
/* Update PM2.5 sensor measured value */
|
||||
log_d("Setting PM2.5 to %0.1f", pm25);
|
||||
esp_zb_lock_acquire(portMAX_DELAY);
|
||||
ret = esp_zb_zcl_set_attribute_val(
|
||||
_endpoint, ESP_ZB_ZCL_CLUSTER_ID_PM2_5_MEASUREMENT, ESP_ZB_ZCL_CLUSTER_SERVER_ROLE, ESP_ZB_ZCL_ATTR_PM2_5_MEASUREMENT_MEASURED_VALUE_ID, &pm25, false
|
||||
);
|
||||
esp_zb_lock_release();
|
||||
if (ret != ESP_ZB_ZCL_STATUS_SUCCESS) {
|
||||
log_e("Failed to set PM2.5: 0x%x: %s", ret, esp_zb_zcl_status_to_name(ret));
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool ZigbeePM25Sensor::report() {
|
||||
/* Send report attributes command */
|
||||
esp_zb_zcl_report_attr_cmd_t report_attr_cmd;
|
||||
report_attr_cmd.address_mode = ESP_ZB_APS_ADDR_MODE_DST_ADDR_ENDP_NOT_PRESENT;
|
||||
report_attr_cmd.attributeID = ESP_ZB_ZCL_ATTR_PM2_5_MEASUREMENT_MEASURED_VALUE_ID;
|
||||
report_attr_cmd.direction = ESP_ZB_ZCL_CMD_DIRECTION_TO_CLI;
|
||||
report_attr_cmd.clusterID = ESP_ZB_ZCL_CLUSTER_ID_PM2_5_MEASUREMENT;
|
||||
report_attr_cmd.zcl_basic_cmd.src_endpoint = _endpoint;
|
||||
report_attr_cmd.manuf_code = ESP_ZB_ZCL_ATTR_NON_MANUFACTURER_SPECIFIC;
|
||||
|
||||
esp_zb_lock_acquire(portMAX_DELAY);
|
||||
esp_err_t ret = esp_zb_zcl_report_attr_cmd_req(&report_attr_cmd);
|
||||
esp_zb_lock_release();
|
||||
if (ret != ESP_OK) {
|
||||
log_e("Failed to send PM2.5 report: 0x%x: %s", ret, esp_err_to_name(ret));
|
||||
return false;
|
||||
}
|
||||
log_v("PM2.5 report sent");
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif // CONFIG_ZB_ENABLED
|
||||
60
libraries/Zigbee/src/ep/ZigbeePM25Sensor.h
Normal file
60
libraries/Zigbee/src/ep/ZigbeePM25Sensor.h
Normal file
|
|
@ -0,0 +1,60 @@
|
|||
/* Class of Zigbee PM2.5 sensor endpoint inherited from common EP class */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "soc/soc_caps.h"
|
||||
#include "sdkconfig.h"
|
||||
#if CONFIG_ZB_ENABLED
|
||||
|
||||
#include "ZigbeeEP.h"
|
||||
#include "ha/esp_zigbee_ha_standard.h"
|
||||
|
||||
// clang-format off
|
||||
#define ZIGBEE_DEFAULT_PM2_5_SENSOR_CONFIG() \
|
||||
{ \
|
||||
.basic_cfg = \
|
||||
{ \
|
||||
.zcl_version = ESP_ZB_ZCL_BASIC_ZCL_VERSION_DEFAULT_VALUE, \
|
||||
.power_source = ESP_ZB_ZCL_BASIC_POWER_SOURCE_DEFAULT_VALUE, \
|
||||
}, \
|
||||
.identify_cfg = \
|
||||
{ \
|
||||
.identify_time = ESP_ZB_ZCL_IDENTIFY_IDENTIFY_TIME_DEFAULT_VALUE, \
|
||||
}, \
|
||||
.pm2_5_meas_cfg = \
|
||||
{ \
|
||||
.measured_value = 0.0, \
|
||||
.min_measured_value = 0.0, \
|
||||
.max_measured_value = 500.0, \
|
||||
}, \
|
||||
}
|
||||
// clang-format on
|
||||
|
||||
typedef struct zigbee_pm2_5_sensor_cfg_s {
|
||||
esp_zb_basic_cluster_cfg_t basic_cfg;
|
||||
esp_zb_identify_cluster_cfg_t identify_cfg;
|
||||
esp_zb_pm2_5_measurement_cluster_cfg_t pm2_5_meas_cfg;
|
||||
} zigbee_pm2_5_sensor_cfg_t;
|
||||
|
||||
class ZigbeePM25Sensor : public ZigbeeEP {
|
||||
public:
|
||||
ZigbeePM25Sensor(uint8_t endpoint);
|
||||
~ZigbeePM25Sensor() {}
|
||||
|
||||
// Set the PM2.5 value in 0.1 µg/m³
|
||||
bool setPM25(float pm25);
|
||||
|
||||
// Set the min and max value for the PM2.5 sensor in 0.1 µg/m³
|
||||
bool setMinMaxValue(float min, float max);
|
||||
|
||||
// Set the tolerance value for the PM2.5 sensor in 0.1 µg/m³
|
||||
bool setTolerance(float tolerance);
|
||||
|
||||
// Set the reporting interval for PM2.5 measurement in seconds and delta (PM2.5 change in 0.1 µg/m³)
|
||||
bool setReporting(uint16_t min_interval, uint16_t max_interval, float delta);
|
||||
|
||||
// Report the PM2.5 value
|
||||
bool report();
|
||||
};
|
||||
|
||||
#endif // CONFIG_ZB_ENABLED
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
#ifndef Pins_Arduino_h
|
||||
#define Pins_Arduino_h
|
||||
|
||||
#include <stdint.h>
|
||||
#define USB_VID 0xAFD0
|
||||
#define USB_PID 0x0003
|
||||
#define USB_MANUFACTURER "Alfredo"
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@
|
|||
#endif
|
||||
|
||||
#define USB_VID 0x303a
|
||||
#define USB_PID 0x82D1
|
||||
#define USB_PID 0x82D4
|
||||
#define USB_MANUFACTURER "LILYGO"
|
||||
#define USB_PRODUCT "T-LoRa-Pager"
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue