mirror of
https://github.com/esphome/esphome.git
synced 2026-10-14 02:02:51 +00:00
[zigbee] add support for SED on esp32 (#20487)
This commit is contained in:
@@ -13,7 +13,14 @@ from esphome.components.esp32.const import (
|
||||
VARIANT_ESP32S31,
|
||||
)
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import CONF_ID, CONF_INTERNAL, CONF_MODEL, CONF_NAME, CONF_ON_START
|
||||
from esphome.const import (
|
||||
CONF_ID,
|
||||
CONF_INTERNAL,
|
||||
CONF_MODEL,
|
||||
CONF_NAME,
|
||||
CONF_ON_START,
|
||||
CONF_POLLING_INTERVAL,
|
||||
)
|
||||
from esphome.core import CORE, CoroPriority, coroutine_with_priority
|
||||
from esphome.types import ConfigType
|
||||
|
||||
@@ -25,6 +32,7 @@ from .const import (
|
||||
CONF_POWER_SOURCE,
|
||||
CONF_REPORT,
|
||||
CONF_ROUTER,
|
||||
CONF_SLEEPY,
|
||||
CONF_USE_DEVICE_TYPE,
|
||||
CONF_WIPE_ON_BOOT,
|
||||
KEY_ZIGBEE,
|
||||
@@ -35,7 +43,6 @@ from .const import (
|
||||
from .const_zephyr import (
|
||||
CONF_IEEE802154_VENDOR_OUI,
|
||||
CONF_MAX_EP_NUMBER_ZEPHYR,
|
||||
CONF_SLEEPY,
|
||||
CONF_ZIGBEE_ID,
|
||||
KEY_EP_NUMBER,
|
||||
)
|
||||
@@ -128,8 +135,11 @@ NUMBER_SCHEMA = (
|
||||
|
||||
|
||||
def _validate_router_sleepy(config: ConfigType) -> ConfigType:
|
||||
if config.get(CONF_ROUTER) and config.get(CONF_SLEEPY):
|
||||
raise cv.Invalid("router and sleepy are mutually exclusive")
|
||||
if config.get(CONF_ROUTER):
|
||||
if config.get(CONF_SLEEPY):
|
||||
raise cv.Invalid("router and sleepy are mutually exclusive")
|
||||
if config.get(CONF_POLLING_INTERVAL):
|
||||
raise cv.Invalid(f"{CONF_POLLING_INTERVAL} is only valid for end devices.")
|
||||
return config
|
||||
|
||||
|
||||
@@ -160,9 +170,17 @@ CONFIG_SCHEMA = cv.All(
|
||||
),
|
||||
cv.requires_component("nrf52"),
|
||||
),
|
||||
cv.OnlyWith(CONF_SLEEPY, "nrf52", default=False): cv.All(
|
||||
cv.Optional(CONF_SLEEPY, default=False): cv.All(
|
||||
cv.boolean,
|
||||
),
|
||||
cv.Optional(CONF_POLLING_INTERVAL): cv.All(
|
||||
cv.requires_component(ESP32_DOMAIN),
|
||||
cv.positive_time_period_milliseconds,
|
||||
cv.Range(
|
||||
min=cv.TimePeriodMilliseconds(milliseconds=200),
|
||||
max=cv.TimePeriodMinutes(minutes=60), # 1 hour
|
||||
),
|
||||
),
|
||||
}
|
||||
).extend(cv.COMPONENT_SCHEMA),
|
||||
_validate_router_sleepy,
|
||||
|
||||
@@ -72,6 +72,7 @@ CONF_WIPE_ON_BOOT = "wipe_on_boot"
|
||||
CONF_REPORT = "report"
|
||||
CONF_ROUTER = "router"
|
||||
CONF_POWER_SOURCE = "power_source"
|
||||
CONF_SLEEPY = "sleepy"
|
||||
CONF_USE_DEVICE_TYPE = "use_device_type"
|
||||
POWER_SOURCE = {
|
||||
"UNKNOWN": 0x00, # ZB_ZCL_BASIC_POWER_SOURCE_UNKNOWN
|
||||
|
||||
@@ -4,7 +4,6 @@ CONF_ZIGBEE_BINARY_SENSOR = "zigbee_binary_sensor"
|
||||
CONF_ZIGBEE_SENSOR = "zigbee_sensor"
|
||||
CONF_ZIGBEE_SWITCH = "zigbee_switch"
|
||||
CONF_ZIGBEE_NUMBER = "zigbee_number"
|
||||
CONF_SLEEPY = "sleepy"
|
||||
CONF_IEEE802154_VENDOR_OUI = "ieee802154_vendor_oui"
|
||||
|
||||
# Keys for CORE.data storage
|
||||
|
||||
@@ -319,7 +319,7 @@ void ZigbeeComponent::setup() {
|
||||
#else
|
||||
esp_zigbee_zed_config_s zb_zed_cfg = {
|
||||
.ed_timeout = EZB_NWK_ED_TIMEOUT_64MIN,
|
||||
.keep_alive = ED_KEEP_ALIVE,
|
||||
.keep_alive = this->keep_alive_,
|
||||
};
|
||||
device_config.zed_config = zb_zed_cfg;
|
||||
#endif
|
||||
@@ -339,6 +339,8 @@ void ZigbeeComponent::setup() {
|
||||
|
||||
#ifdef CONFIG_ZB_ZCZR
|
||||
ezb_bdb_set_router_rejoin_required(true);
|
||||
#else
|
||||
ezb_nwk_set_rx_on_when_idle(!this->sleepy_); // if sleepy, disable RX when idle
|
||||
#endif
|
||||
|
||||
ezb_aps_secur_enable_distributed_security(false);
|
||||
@@ -419,18 +421,27 @@ void ZigbeeComponent::loop() {
|
||||
|
||||
void ZigbeeComponent::dump_config() {
|
||||
if (esp_zigbee_lock_acquire(10 / portTICK_PERIOD_MS)) {
|
||||
ESP_LOGCONFIG(TAG,
|
||||
"Zigbee\n"
|
||||
" Model: %.*s\n"
|
||||
" Router: %s\n"
|
||||
" Device is joined to the network: %s\n"
|
||||
" Current channel: %d\n"
|
||||
" Short addr: 0x%04X\n"
|
||||
" Short pan id: 0x%04X",
|
||||
this->basic_cluster_data_.model[0],
|
||||
reinterpret_cast<const char *>(this->basic_cluster_data_.model + 1),
|
||||
YESNO(this->device_role_ == EZB_NWK_DEVICE_TYPE_ROUTER), YESNO(ezb_bdb_dev_joined()),
|
||||
ezb_nwk_get_current_channel(), ezb_nwk_get_short_address(), ezb_nwk_get_panid());
|
||||
ESP_LOGCONFIG(
|
||||
TAG,
|
||||
"Zigbee\n"
|
||||
" Model: %.*s\n"
|
||||
#ifdef CONFIG_ZB_ZCZR
|
||||
" Router: %s\n"
|
||||
#else
|
||||
" Sleepy end device: %s\n"
|
||||
" Poll interval: %" PRIu32 " ms\n"
|
||||
#endif
|
||||
" Device is joined to the network: %s\n"
|
||||
" Current channel: %d\n"
|
||||
" Short addr: 0x%04X\n"
|
||||
" Short pan id: 0x%04X",
|
||||
this->basic_cluster_data_.model[0], reinterpret_cast<const char *>(this->basic_cluster_data_.model + 1),
|
||||
#ifdef CONFIG_ZB_ZCZR
|
||||
YESNO(this->device_role_ == EZB_NWK_DEVICE_TYPE_ROUTER),
|
||||
#else
|
||||
YESNO(this->sleepy_), this->keep_alive_,
|
||||
#endif
|
||||
YESNO(ezb_bdb_dev_joined()), ezb_nwk_get_current_channel(), ezb_nwk_get_short_address(), ezb_nwk_get_panid());
|
||||
esp_zigbee_lock_release();
|
||||
} else {
|
||||
ESP_LOGCONFIG(TAG,
|
||||
|
||||
@@ -20,7 +20,6 @@
|
||||
namespace esphome::zigbee {
|
||||
|
||||
/* Zigbee configuration */
|
||||
static const uint16_t ED_KEEP_ALIVE = 3000; /* 3000 millisecond */
|
||||
static const uint8_t MAX_CHILDREN = 10;
|
||||
static const uint32_t EZB_PRIMARY_CHANNEL_MASK = 0x07FFF800U; /* channels 11-26 */
|
||||
static constexpr uint8_t MAX_ZB_QUEUE_SIZE = 32;
|
||||
@@ -43,6 +42,8 @@ class ZigbeeComponent final : public Component {
|
||||
void loop() override;
|
||||
void dump_config() override;
|
||||
|
||||
void set_sleepy(bool sleepy) { this->sleepy_ = sleepy; }
|
||||
void set_keep_alive(uint32_t keep_alive) { this->keep_alive_ = keep_alive; }
|
||||
void set_basic_cluster(const char *model, const char *manufacturer, uint8_t power_source);
|
||||
void add_cluster(uint8_t endpoint_id, uint16_t cluster_id, uint8_t role);
|
||||
void create_default_cluster(uint8_t endpoint_id, uint16_t device_id);
|
||||
@@ -73,6 +74,8 @@ class ZigbeeComponent final : public Component {
|
||||
bool is_joined() { return this->joined_; }
|
||||
|
||||
protected:
|
||||
bool sleepy_{false};
|
||||
uint32_t keep_alive_{3000};
|
||||
struct {
|
||||
uint8_t *model;
|
||||
uint8_t *manufacturer;
|
||||
|
||||
@@ -24,6 +24,7 @@ from esphome.const import (
|
||||
CONF_MAX_LENGTH,
|
||||
CONF_MODEL,
|
||||
CONF_NAME,
|
||||
CONF_POLLING_INTERVAL,
|
||||
CONF_TYPE,
|
||||
CONF_UNIT_OF_MEASUREMENT,
|
||||
CONF_VALUE,
|
||||
@@ -45,6 +46,7 @@ from .const import (
|
||||
CONF_POWER_SOURCE,
|
||||
CONF_REPORT,
|
||||
CONF_ROUTER,
|
||||
CONF_SLEEPY,
|
||||
CONF_USE_DEVICE_TYPE,
|
||||
KEY_ZIGBEE,
|
||||
POWER_SOURCE,
|
||||
@@ -412,6 +414,11 @@ async def esp32_to_code(config: ConfigType) -> "MockObj":
|
||||
# setup zigbee components
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
await cg.register_component(var, config)
|
||||
if config.get(CONF_SLEEPY):
|
||||
cg.add(var.set_sleepy(True))
|
||||
if (keep_alive := config.get(CONF_POLLING_INTERVAL, 3000)) != 3000:
|
||||
cg.add(var.set_keep_alive(keep_alive))
|
||||
|
||||
cg.add(
|
||||
var.set_basic_cluster(
|
||||
config[CONF_MODEL],
|
||||
|
||||
@@ -24,6 +24,7 @@ from .const import (
|
||||
BACNET_UNITS,
|
||||
CONF_POWER_SOURCE,
|
||||
CONF_ROUTER,
|
||||
CONF_SLEEPY,
|
||||
CONF_WIPE_ON_BOOT,
|
||||
KEY_ZIGBEE,
|
||||
POWER_SOURCE,
|
||||
@@ -35,7 +36,6 @@ from .const import (
|
||||
)
|
||||
from .const_zephyr import (
|
||||
CONF_IEEE802154_VENDOR_OUI,
|
||||
CONF_SLEEPY,
|
||||
CONF_ZIGBEE_BINARY_SENSOR,
|
||||
CONF_ZIGBEE_ID,
|
||||
CONF_ZIGBEE_NUMBER,
|
||||
|
||||
@@ -58,8 +58,9 @@ switch:
|
||||
|
||||
zigbee:
|
||||
model: zigbee_test
|
||||
router: false
|
||||
power_source: MAINS_SINGLE_PHASE
|
||||
sleepy: true
|
||||
polling_interval: 2s
|
||||
power_source: BATTERY
|
||||
on_join:
|
||||
then:
|
||||
- logger.log: "Joined network"
|
||||
|
||||
Reference in New Issue
Block a user