mirror of
https://github.com/esphome/esphome.git
synced 2026-01-08 19:20:51 -07:00
[nrf52,zigbee] add support for binary_input (#11535)
Co-authored-by: J. Nick Koston <nick@koston.org> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: J. Nick Koston <nick+github@koston.org> Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com> Co-authored-by: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com> Co-authored-by: J. Nick Koston <nick@home-assistant.io>
This commit is contained in:
@@ -575,5 +575,6 @@ esphome/components/xpt2046/touchscreen/* @nielsnl68 @numo68
|
||||
esphome/components/xxtea/* @clydebarrow
|
||||
esphome/components/zephyr/* @tomaszduda23
|
||||
esphome/components/zhlt01/* @cfeenstra1024
|
||||
esphome/components/zigbee/* @tomaszduda23
|
||||
esphome/components/zio_ultrasonic/* @kahrendt
|
||||
esphome/components/zwave_proxy/* @kbx81
|
||||
|
||||
@@ -3,7 +3,7 @@ from logging import getLogger
|
||||
from esphome import automation, core
|
||||
from esphome.automation import Condition, maybe_simple_id
|
||||
import esphome.codegen as cg
|
||||
from esphome.components import mqtt, web_server
|
||||
from esphome.components import mqtt, web_server, zigbee
|
||||
from esphome.components.const import CONF_ON_STATE_CHANGE
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import (
|
||||
@@ -439,6 +439,7 @@ def validate_publish_initial_state(value):
|
||||
_BINARY_SENSOR_SCHEMA = (
|
||||
cv.ENTITY_BASE_SCHEMA.extend(web_server.WEBSERVER_SORTING_SCHEMA)
|
||||
.extend(cv.MQTT_COMPONENT_SCHEMA)
|
||||
.extend(zigbee.BINARY_SENSOR_SCHEMA)
|
||||
.extend(
|
||||
{
|
||||
cv.GenerateID(): cv.declare_id(BinarySensor),
|
||||
@@ -520,6 +521,7 @@ _BINARY_SENSOR_SCHEMA = (
|
||||
|
||||
|
||||
_BINARY_SENSOR_SCHEMA.add_extra(entity_duplicate_validator("binary_sensor"))
|
||||
_BINARY_SENSOR_SCHEMA.add_extra(zigbee.validate_binary_sensor)
|
||||
|
||||
|
||||
def binary_sensor_schema(
|
||||
@@ -621,6 +623,8 @@ async def setup_binary_sensor_core_(var, config):
|
||||
if web_server_config := config.get(CONF_WEB_SERVER):
|
||||
await web_server.add_entity_config(var, web_server_config)
|
||||
|
||||
await zigbee.setup_binary_sensor(var, config)
|
||||
|
||||
|
||||
async def register_binary_sensor(var, config):
|
||||
if not CORE.has_id(config[CONF_ID]):
|
||||
|
||||
@@ -26,7 +26,12 @@ void arch_init() {
|
||||
if (device_is_ready(WDT)) {
|
||||
static wdt_timeout_cfg wdt_config{};
|
||||
wdt_config.flags = WDT_FLAG_RESET_SOC;
|
||||
#ifdef USE_ZIGBEE
|
||||
// zboss thread use a lot of cpu cycles during start
|
||||
wdt_config.window.max = 10000;
|
||||
#else
|
||||
wdt_config.window.max = 2000;
|
||||
#endif
|
||||
wdt_channel_id = wdt_install_timeout(WDT, &wdt_config);
|
||||
if (wdt_channel_id >= 0) {
|
||||
uint8_t options = 0;
|
||||
|
||||
124
esphome/components/zigbee/__init__.py
Normal file
124
esphome/components/zigbee/__init__.py
Normal file
@@ -0,0 +1,124 @@
|
||||
from typing import Any
|
||||
|
||||
from esphome import automation, core
|
||||
import esphome.codegen as cg
|
||||
from esphome.components.nrf52.boards import BOOTLOADER_CONFIG, Section
|
||||
from esphome.components.zephyr import zephyr_add_pm_static, zephyr_data
|
||||
from esphome.components.zephyr.const import KEY_BOOTLOADER
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import CONF_ID, CONF_INTERNAL
|
||||
from esphome.core import CORE
|
||||
from esphome.types import ConfigType
|
||||
|
||||
from .const_zephyr import (
|
||||
CONF_MAX_EP_NUMBER,
|
||||
CONF_ON_JOIN,
|
||||
CONF_WIPE_ON_BOOT,
|
||||
CONF_ZIGBEE_ID,
|
||||
KEY_EP_NUMBER,
|
||||
KEY_ZIGBEE,
|
||||
ZigbeeComponent,
|
||||
zigbee_ns,
|
||||
)
|
||||
from .zigbee_zephyr import zephyr_binary_sensor
|
||||
|
||||
CODEOWNERS = ["@tomaszduda23"]
|
||||
|
||||
|
||||
def zigbee_set_core_data(config: ConfigType) -> ConfigType:
|
||||
if zephyr_data()[KEY_BOOTLOADER] in BOOTLOADER_CONFIG:
|
||||
zephyr_add_pm_static(
|
||||
[Section("empty_after_zboss_offset", 0xF4000, 0xC000, "flash_primary")]
|
||||
)
|
||||
|
||||
return config
|
||||
|
||||
|
||||
BINARY_SENSOR_SCHEMA = cv.Schema({}).extend(zephyr_binary_sensor)
|
||||
|
||||
CONFIG_SCHEMA = cv.All(
|
||||
cv.Schema(
|
||||
{
|
||||
cv.GenerateID(CONF_ID): cv.declare_id(ZigbeeComponent),
|
||||
cv.Optional(CONF_ON_JOIN): automation.validate_automation(single=True),
|
||||
cv.Optional(CONF_WIPE_ON_BOOT, default=False): cv.All(
|
||||
cv.boolean,
|
||||
cv.requires_component("nrf52"),
|
||||
),
|
||||
}
|
||||
).extend(cv.COMPONENT_SCHEMA),
|
||||
zigbee_set_core_data,
|
||||
cv.only_with_framework("zephyr"),
|
||||
)
|
||||
|
||||
|
||||
def validate_number_of_ep(config: ConfigType) -> None:
|
||||
if KEY_ZIGBEE not in CORE.data:
|
||||
raise cv.Invalid("At least one zigbee device need to be included")
|
||||
count = len(CORE.data[KEY_ZIGBEE][KEY_EP_NUMBER])
|
||||
if count == 1:
|
||||
raise cv.Invalid(
|
||||
"Single endpoint is not supported https://github.com/Koenkk/zigbee2mqtt/issues/29888"
|
||||
)
|
||||
if count > CONF_MAX_EP_NUMBER:
|
||||
raise cv.Invalid(f"Maximum number of end points is {CONF_MAX_EP_NUMBER}")
|
||||
|
||||
|
||||
FINAL_VALIDATE_SCHEMA = cv.All(
|
||||
validate_number_of_ep,
|
||||
)
|
||||
|
||||
|
||||
async def to_code(config: ConfigType) -> None:
|
||||
cg.add_define("USE_ZIGBEE")
|
||||
if CORE.using_zephyr:
|
||||
from .zigbee_zephyr import zephyr_to_code
|
||||
|
||||
await zephyr_to_code(config)
|
||||
|
||||
|
||||
async def setup_binary_sensor(entity: cg.MockObj, config: ConfigType) -> None:
|
||||
if not config.get(CONF_ZIGBEE_ID) or config.get(CONF_INTERNAL):
|
||||
return
|
||||
if CORE.using_zephyr:
|
||||
from .zigbee_zephyr import zephyr_setup_binary_sensor
|
||||
|
||||
await zephyr_setup_binary_sensor(entity, config)
|
||||
|
||||
|
||||
def validate_binary_sensor(config: ConfigType) -> ConfigType:
|
||||
if not config.get(CONF_ZIGBEE_ID) or config.get(CONF_INTERNAL):
|
||||
return config
|
||||
data: dict[str, Any] = CORE.data.setdefault(KEY_ZIGBEE, {})
|
||||
slots: list[str] = data.setdefault(KEY_EP_NUMBER, [])
|
||||
slots.extend([""])
|
||||
return config
|
||||
|
||||
|
||||
ZIGBEE_ACTION_SCHEMA = automation.maybe_simple_id(
|
||||
cv.Schema(
|
||||
{
|
||||
cv.GenerateID(): cv.use_id(ZigbeeComponent),
|
||||
}
|
||||
)
|
||||
)
|
||||
|
||||
FactoryResetAction = zigbee_ns.class_(
|
||||
"FactoryResetAction", automation.Action, cg.Parented.template(ZigbeeComponent)
|
||||
)
|
||||
|
||||
|
||||
@automation.register_action(
|
||||
"zigbee.factory_reset",
|
||||
FactoryResetAction,
|
||||
ZIGBEE_ACTION_SCHEMA,
|
||||
)
|
||||
async def reset_zigbee_to_code(
|
||||
config: ConfigType,
|
||||
action_id: core.ID,
|
||||
template_arg: cg.TemplateArguments,
|
||||
args: list[tuple],
|
||||
) -> cg.Pvariable:
|
||||
var = cg.new_Pvariable(action_id, template_arg)
|
||||
await cg.register_parented(var, config[CONF_ID])
|
||||
return var
|
||||
16
esphome/components/zigbee/automation.h
Normal file
16
esphome/components/zigbee/automation.h
Normal file
@@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
#include "esphome/core/defines.h"
|
||||
#ifdef USE_ZIGBEE
|
||||
#ifdef USE_NRF52
|
||||
#include "zigbee_zephyr.h"
|
||||
#endif
|
||||
namespace esphome::zigbee {
|
||||
|
||||
template<typename... Ts> class FactoryResetAction : public Action<Ts...>, public Parented<ZigbeeComponent> {
|
||||
public:
|
||||
void play(const Ts &...x) override { this->parent_->factory_reset(); }
|
||||
};
|
||||
|
||||
} // namespace esphome::zigbee
|
||||
|
||||
#endif
|
||||
24
esphome/components/zigbee/const_zephyr.py
Normal file
24
esphome/components/zigbee/const_zephyr.py
Normal file
@@ -0,0 +1,24 @@
|
||||
import esphome.codegen as cg
|
||||
|
||||
zigbee_ns = cg.esphome_ns.namespace("zigbee")
|
||||
ZigbeeComponent = zigbee_ns.class_("ZigbeeComponent", cg.Component)
|
||||
BinaryAttrs = zigbee_ns.struct("BinaryAttrs")
|
||||
|
||||
CONF_MAX_EP_NUMBER = 8
|
||||
CONF_ZIGBEE_ID = "zigbee_id"
|
||||
CONF_ON_JOIN = "on_join"
|
||||
CONF_WIPE_ON_BOOT = "wipe_on_boot"
|
||||
CONF_ZIGBEE_BINARY_SENSOR = "zigbee_binary_sensor"
|
||||
|
||||
# Keys for CORE.data storage
|
||||
KEY_ZIGBEE = "zigbee"
|
||||
KEY_EP_NUMBER = "ep_number"
|
||||
|
||||
# External ZBOSS SDK types (just strings for codegen)
|
||||
ZB_ZCL_BASIC_ATTRS_EXT_T = "zb_zcl_basic_attrs_ext_t"
|
||||
ZB_ZCL_IDENTIFY_ATTRS_T = "zb_zcl_identify_attrs_t"
|
||||
|
||||
# Cluster IDs
|
||||
ZB_ZCL_CLUSTER_ID_BASIC = "ZB_ZCL_CLUSTER_ID_BASIC"
|
||||
ZB_ZCL_CLUSTER_ID_IDENTIFY = "ZB_ZCL_CLUSTER_ID_IDENTIFY"
|
||||
ZB_ZCL_CLUSTER_ID_BINARY_INPUT = "ZB_ZCL_CLUSTER_ID_BINARY_INPUT"
|
||||
37
esphome/components/zigbee/zigbee_binary_sensor_zephyr.cpp
Normal file
37
esphome/components/zigbee/zigbee_binary_sensor_zephyr.cpp
Normal file
@@ -0,0 +1,37 @@
|
||||
#include "zigbee_binary_sensor_zephyr.h"
|
||||
#if defined(USE_ZIGBEE) && defined(USE_NRF52) && defined(USE_BINARY_SENSOR)
|
||||
#include "esphome/core/log.h"
|
||||
extern "C" {
|
||||
#include <zboss_api.h>
|
||||
#include <zboss_api_addons.h>
|
||||
#include <zb_nrf_platform.h>
|
||||
#include <zigbee/zigbee_app_utils.h>
|
||||
#include <zb_error_to_string.h>
|
||||
}
|
||||
namespace esphome::zigbee {
|
||||
|
||||
static const char *const TAG = "zigbee.binary_sensor";
|
||||
|
||||
ZigbeeBinarySensor::ZigbeeBinarySensor(binary_sensor::BinarySensor *binary_sensor) : binary_sensor_(binary_sensor) {}
|
||||
|
||||
void ZigbeeBinarySensor::setup() {
|
||||
this->binary_sensor_->add_on_state_callback([this](bool state) {
|
||||
this->cluster_attributes_->present_value = state ? ZB_TRUE : ZB_FALSE;
|
||||
ESP_LOGD(TAG, "Set attribute end point: %d, present_value %d", this->end_point_,
|
||||
this->cluster_attributes_->present_value);
|
||||
ZB_ZCL_SET_ATTRIBUTE(this->end_point_, ZB_ZCL_CLUSTER_ID_BINARY_INPUT, ZB_ZCL_CLUSTER_SERVER_ROLE,
|
||||
ZB_ZCL_ATTR_BINARY_INPUT_PRESENT_VALUE_ID, &this->cluster_attributes_->present_value,
|
||||
ZB_FALSE);
|
||||
this->parent_->flush();
|
||||
});
|
||||
}
|
||||
|
||||
void ZigbeeBinarySensor::dump_config() {
|
||||
ESP_LOGCONFIG(TAG,
|
||||
"Zigbee Binary Sensor\n"
|
||||
" End point: %d, present_value %u",
|
||||
this->end_point_, this->cluster_attributes_->present_value);
|
||||
}
|
||||
|
||||
} // namespace esphome::zigbee
|
||||
#endif
|
||||
45
esphome/components/zigbee/zigbee_binary_sensor_zephyr.h
Normal file
45
esphome/components/zigbee/zigbee_binary_sensor_zephyr.h
Normal file
@@ -0,0 +1,45 @@
|
||||
#pragma once
|
||||
#include "esphome/core/defines.h"
|
||||
#if defined(USE_ZIGBEE) && defined(USE_NRF52) && defined(USE_BINARY_SENSOR)
|
||||
#include "esphome/components/zigbee/zigbee_zephyr.h"
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/components/binary_sensor/binary_sensor.h"
|
||||
extern "C" {
|
||||
#include <zboss_api.h>
|
||||
#include <zboss_api_addons.h>
|
||||
}
|
||||
|
||||
// it should have been defined inside of sdk. It is missing though
|
||||
#define ZB_SET_ATTR_DESCR_WITH_ZB_ZCL_ATTR_BINARY_INPUT_DESCRIPTION_ID(data_ptr) \
|
||||
{ \
|
||||
ZB_ZCL_ATTR_BINARY_INPUT_DESCRIPTION_ID, ZB_ZCL_ATTR_TYPE_CHAR_STRING, ZB_ZCL_ATTR_ACCESS_READ_ONLY, \
|
||||
(ZB_ZCL_NON_MANUFACTURER_SPECIFIC), (void *) (data_ptr) \
|
||||
}
|
||||
|
||||
// copy of ZB_ZCL_DECLARE_BINARY_INPUT_ATTRIB_LIST + description
|
||||
#define ESPHOME_ZB_ZCL_DECLARE_BINARY_INPUT_ATTRIB_LIST(attr_list, out_of_service, present_value, status_flag, \
|
||||
description) \
|
||||
ZB_ZCL_START_DECLARE_ATTRIB_LIST_CLUSTER_REVISION(attr_list, ZB_ZCL_BINARY_INPUT) \
|
||||
ZB_ZCL_SET_ATTR_DESC(ZB_ZCL_ATTR_BINARY_INPUT_OUT_OF_SERVICE_ID, (out_of_service)) \
|
||||
ZB_ZCL_SET_ATTR_DESC(ZB_ZCL_ATTR_BINARY_INPUT_PRESENT_VALUE_ID, (present_value)) \
|
||||
ZB_ZCL_SET_ATTR_DESC(ZB_ZCL_ATTR_BINARY_INPUT_STATUS_FLAG_ID, (status_flag)) \
|
||||
ZB_ZCL_SET_ATTR_DESC(ZB_ZCL_ATTR_BINARY_INPUT_DESCRIPTION_ID, (description)) \
|
||||
ZB_ZCL_FINISH_DECLARE_ATTRIB_LIST
|
||||
|
||||
namespace esphome::zigbee {
|
||||
|
||||
class ZigbeeBinarySensor : public ZigbeeEntity, public Component {
|
||||
public:
|
||||
explicit ZigbeeBinarySensor(binary_sensor::BinarySensor *binary_sensor);
|
||||
void set_cluster_attributes(BinaryAttrs &cluster_attributes) { this->cluster_attributes_ = &cluster_attributes; }
|
||||
|
||||
void setup() override;
|
||||
void dump_config() override;
|
||||
|
||||
protected:
|
||||
BinaryAttrs *cluster_attributes_{nullptr};
|
||||
binary_sensor::BinarySensor *binary_sensor_;
|
||||
};
|
||||
|
||||
} // namespace esphome::zigbee
|
||||
#endif
|
||||
190
esphome/components/zigbee/zigbee_zephyr.cpp
Normal file
190
esphome/components/zigbee/zigbee_zephyr.cpp
Normal file
@@ -0,0 +1,190 @@
|
||||
#include "zigbee_zephyr.h"
|
||||
#if defined(USE_ZIGBEE) && defined(USE_NRF52)
|
||||
#include "esphome/core/log.h"
|
||||
#include <zephyr/settings/settings.h>
|
||||
#include <zephyr/storage/flash_map.h>
|
||||
|
||||
extern "C" {
|
||||
#include <zboss_api.h>
|
||||
#include <zboss_api_addons.h>
|
||||
#include <zb_nrf_platform.h>
|
||||
#include <zigbee/zigbee_app_utils.h>
|
||||
#include <zb_error_to_string.h>
|
||||
}
|
||||
|
||||
namespace esphome::zigbee {
|
||||
|
||||
static const char *const TAG = "zigbee";
|
||||
|
||||
ZigbeeComponent *global_zigbee = nullptr; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
|
||||
|
||||
const uint8_t IEEE_ADDR_BUF_SIZE = 17;
|
||||
|
||||
void ZigbeeComponent::zboss_signal_handler_esphome(zb_bufid_t bufid) {
|
||||
zb_zdo_app_signal_hdr_t *sig_hndler = nullptr;
|
||||
zb_zdo_app_signal_type_t sig = zb_get_app_signal(bufid, &sig_hndler);
|
||||
zb_ret_t status = ZB_GET_APP_SIGNAL_STATUS(bufid);
|
||||
|
||||
switch (sig) {
|
||||
case ZB_ZDO_SIGNAL_SKIP_STARTUP:
|
||||
ESP_LOGD(TAG, "ZB_ZDO_SIGNAL_SKIP_STARTUP, status: %d", status);
|
||||
break;
|
||||
case ZB_ZDO_SIGNAL_PRODUCTION_CONFIG_READY:
|
||||
ESP_LOGD(TAG, "ZB_ZDO_SIGNAL_PRODUCTION_CONFIG_READY, status: %d", status);
|
||||
break;
|
||||
case ZB_ZDO_SIGNAL_LEAVE:
|
||||
ESP_LOGD(TAG, "ZB_ZDO_SIGNAL_LEAVE, status: %d", status);
|
||||
break;
|
||||
case ZB_BDB_SIGNAL_DEVICE_REBOOT:
|
||||
ESP_LOGD(TAG, "ZB_BDB_SIGNAL_DEVICE_REBOOT, status: %d", status);
|
||||
if (status == RET_OK) {
|
||||
on_join_();
|
||||
}
|
||||
break;
|
||||
case ZB_BDB_SIGNAL_STEERING:
|
||||
break;
|
||||
case ZB_COMMON_SIGNAL_CAN_SLEEP:
|
||||
ESP_LOGV(TAG, "ZB_COMMON_SIGNAL_CAN_SLEEP, status: %d", status);
|
||||
break;
|
||||
case ZB_BDB_SIGNAL_DEVICE_FIRST_START:
|
||||
ESP_LOGD(TAG, "ZB_BDB_SIGNAL_DEVICE_FIRST_START, status: %d", status);
|
||||
break;
|
||||
case ZB_NLME_STATUS_INDICATION:
|
||||
ESP_LOGD(TAG, "ZB_NLME_STATUS_INDICATION, status: %d", status);
|
||||
break;
|
||||
case ZB_BDB_SIGNAL_TC_REJOIN_DONE:
|
||||
ESP_LOGD(TAG, "ZB_BDB_SIGNAL_TC_REJOIN_DONE, status: %d", status);
|
||||
break;
|
||||
default:
|
||||
ESP_LOGD(TAG, "zboss_signal_handler sig: %d, status: %d", sig, status);
|
||||
break;
|
||||
}
|
||||
|
||||
auto err = zigbee_default_signal_handler(bufid);
|
||||
if (err != RET_OK) {
|
||||
ESP_LOGE(TAG, "Zigbee_default_signal_handler ERROR %u [%s]", err, zb_error_to_string_get(err));
|
||||
}
|
||||
|
||||
switch (sig) {
|
||||
case ZB_BDB_SIGNAL_STEERING:
|
||||
ESP_LOGD(TAG, "ZB_BDB_SIGNAL_STEERING, status: %d", status);
|
||||
if (status == RET_OK) {
|
||||
zb_ext_pan_id_t extended_pan_id;
|
||||
char ieee_addr_buf[IEEE_ADDR_BUF_SIZE] = {0};
|
||||
int addr_len;
|
||||
|
||||
zb_get_extended_pan_id(extended_pan_id);
|
||||
addr_len = ieee_addr_to_str(ieee_addr_buf, sizeof(ieee_addr_buf), extended_pan_id);
|
||||
|
||||
for (int i = 0; i < addr_len; ++i) {
|
||||
if (ieee_addr_buf[i] != '0') {
|
||||
on_join_();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* All callbacks should either reuse or free passed buffers.
|
||||
* If bufid == 0, the buffer is invalid (not passed).
|
||||
*/
|
||||
if (bufid) {
|
||||
zb_buf_free(bufid);
|
||||
}
|
||||
}
|
||||
|
||||
void ZigbeeComponent::zcl_device_cb(zb_bufid_t bufid) {
|
||||
zb_zcl_device_callback_param_t *p_device_cb_param = ZB_BUF_GET_PARAM(bufid, zb_zcl_device_callback_param_t);
|
||||
zb_zcl_device_callback_id_t device_cb_id = p_device_cb_param->device_cb_id;
|
||||
zb_uint16_t cluster_id = p_device_cb_param->cb_param.set_attr_value_param.cluster_id;
|
||||
zb_uint16_t attr_id = p_device_cb_param->cb_param.set_attr_value_param.attr_id;
|
||||
auto endpoint = p_device_cb_param->endpoint;
|
||||
|
||||
ESP_LOGI(TAG, "Zcl_device_cb %s id %hd, cluster_id %d, attr_id %d, endpoint: %d", __func__, device_cb_id, cluster_id,
|
||||
attr_id, endpoint);
|
||||
|
||||
// endpoints are enumerated from 1
|
||||
if (global_zigbee->callbacks_.size() >= endpoint) {
|
||||
global_zigbee->callbacks_[endpoint - 1](bufid);
|
||||
return;
|
||||
}
|
||||
p_device_cb_param->status = RET_ERROR;
|
||||
}
|
||||
|
||||
void ZigbeeComponent::on_join_() {
|
||||
this->defer([this]() {
|
||||
ESP_LOGD(TAG, "Joined the network");
|
||||
this->join_trigger_.trigger();
|
||||
this->join_cb_.call();
|
||||
});
|
||||
}
|
||||
|
||||
#ifdef USE_ZIGBEE_WIPE_ON_BOOT
|
||||
void ZigbeeComponent::erase_flash_(int area) {
|
||||
const struct flash_area *fap;
|
||||
flash_area_open(area, &fap);
|
||||
flash_area_erase(fap, 0, fap->fa_size);
|
||||
flash_area_close(fap);
|
||||
}
|
||||
#endif
|
||||
|
||||
void ZigbeeComponent::setup() {
|
||||
global_zigbee = this;
|
||||
auto err = settings_subsys_init();
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "Failed to initialize settings subsystem, err: %d", err);
|
||||
return;
|
||||
}
|
||||
|
||||
#ifdef USE_ZIGBEE_WIPE_ON_BOOT
|
||||
erase_flash_(FIXED_PARTITION_ID(ZBOSS_NVRAM));
|
||||
erase_flash_(FIXED_PARTITION_ID(ZBOSS_PRODUCT_CONFIG));
|
||||
erase_flash_(FIXED_PARTITION_ID(SETTINGS_STORAGE));
|
||||
#endif
|
||||
|
||||
ZB_ZCL_REGISTER_DEVICE_CB(zcl_device_cb);
|
||||
err = settings_load();
|
||||
if (err) {
|
||||
ESP_LOGE(TAG, "Cannot load settings, err: %d", err);
|
||||
return;
|
||||
}
|
||||
zigbee_enable();
|
||||
}
|
||||
|
||||
void ZigbeeComponent::dump_config() {
|
||||
bool wipe = false;
|
||||
#ifdef USE_ZIGBEE_WIPE_ON_BOOT
|
||||
wipe = true;
|
||||
#endif
|
||||
ESP_LOGCONFIG(TAG,
|
||||
"Zigbee\n"
|
||||
" Wipe on boot: %s",
|
||||
YESNO(wipe));
|
||||
}
|
||||
|
||||
static void send_attribute_report(zb_bufid_t bufid, zb_uint16_t cmd_id) {
|
||||
ESP_LOGD(TAG, "Force zboss scheduler to wake and send attribute report");
|
||||
zb_buf_free(bufid);
|
||||
}
|
||||
|
||||
void ZigbeeComponent::flush() { this->need_flush_ = true; }
|
||||
|
||||
void ZigbeeComponent::loop() {
|
||||
if (this->need_flush_) {
|
||||
this->need_flush_ = false;
|
||||
zb_buf_get_out_delayed_ext(send_attribute_report, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
void ZigbeeComponent::factory_reset() {
|
||||
ESP_LOGD(TAG, "Factory reset");
|
||||
ZB_SCHEDULE_APP_CALLBACK(zb_bdb_reset_via_local_action, 0);
|
||||
}
|
||||
|
||||
} // namespace esphome::zigbee
|
||||
|
||||
extern "C" void zboss_signal_handler(zb_uint8_t param) {
|
||||
esphome::zigbee::global_zigbee->zboss_signal_handler_esphome(param);
|
||||
}
|
||||
#endif
|
||||
104
esphome/components/zigbee/zigbee_zephyr.h
Normal file
104
esphome/components/zigbee/zigbee_zephyr.h
Normal file
@@ -0,0 +1,104 @@
|
||||
#pragma once
|
||||
#include "esphome/core/defines.h"
|
||||
#if defined(USE_ZIGBEE) && defined(USE_NRF52)
|
||||
#include "esphome/core/component.h"
|
||||
#include "esphome/core/automation.h"
|
||||
extern "C" {
|
||||
#include <zboss_api.h>
|
||||
#include <zboss_api_addons.h>
|
||||
}
|
||||
|
||||
// copy of ZB_DECLARE_SIMPLE_DESC. Due to https://github.com/nrfconnect/sdk-nrfxlib/pull/666
|
||||
#define ESPHOME_ZB_DECLARE_SIMPLE_DESC(ep_name, in_clusters_count, out_clusters_count) \
|
||||
typedef ZB_PACKED_PRE struct zb_af_simple_desc_##ep_name##_##in_clusters_count##_##out_clusters_count##_s { \
|
||||
zb_uint8_t endpoint; /* Endpoint */ \
|
||||
zb_uint16_t app_profile_id; /* Application profile identifier */ \
|
||||
zb_uint16_t app_device_id; /* Application device identifier */ \
|
||||
zb_bitfield_t app_device_version : 4; /* Application device version */ \
|
||||
zb_bitfield_t reserved : 4; /* Reserved */ \
|
||||
zb_uint8_t app_input_cluster_count; /* Application input cluster count */ \
|
||||
zb_uint8_t app_output_cluster_count; /* Application output cluster count */ \
|
||||
/* Application input and output cluster list */ \
|
||||
zb_uint16_t app_cluster_list[(in_clusters_count) + (out_clusters_count)]; \
|
||||
} ZB_PACKED_STRUCT zb_af_simple_desc_##ep_name##_##in_clusters_count##_##out_clusters_count##_t
|
||||
|
||||
#define ESPHOME_CAT7(a, b, c, d, e, f, g) a##b##c##d##e##f##g
|
||||
// needed to use ESPHOME_ZB_DECLARE_SIMPLE_DESC
|
||||
#define ESPHOME_ZB_AF_SIMPLE_DESC_TYPE(ep_name, in_num, out_num) \
|
||||
ESPHOME_CAT7(zb_af_simple_desc_, ep_name, _, in_num, _, out_num, _t)
|
||||
|
||||
// needed to use ESPHOME_ZB_DECLARE_SIMPLE_DESC
|
||||
#define ESPHOME_ZB_ZCL_DECLARE_SIMPLE_DESC(ep_name, ep_id, in_clust_num, out_clust_num, ...) \
|
||||
ESPHOME_ZB_DECLARE_SIMPLE_DESC(ep_name, in_clust_num, out_clust_num); \
|
||||
ESPHOME_ZB_AF_SIMPLE_DESC_TYPE(ep_name, in_clust_num, out_clust_num) \
|
||||
simple_desc_##ep_name = {ep_id, ZB_AF_HA_PROFILE_ID, ZB_HA_SIMPLE_SENSOR_DEVICE_ID, 0, 0, in_clust_num, \
|
||||
out_clust_num, {__VA_ARGS__}}
|
||||
|
||||
// needed to use ESPHOME_ZB_ZCL_DECLARE_SIMPLE_DESC
|
||||
#define ESPHOME_ZB_HA_DECLARE_EP(ep_name, ep_id, cluster_list, in_cluster_num, out_cluster_num, report_attr_count, \
|
||||
...) \
|
||||
ESPHOME_ZB_ZCL_DECLARE_SIMPLE_DESC(ep_name, ep_id, in_cluster_num, out_cluster_num, __VA_ARGS__); \
|
||||
ZBOSS_DEVICE_DECLARE_REPORTING_CTX(reporting_info##ep_name, report_attr_count); \
|
||||
ZB_AF_DECLARE_ENDPOINT_DESC(ep_name, ep_id, ZB_AF_HA_PROFILE_ID, 0, NULL, \
|
||||
ZB_ZCL_ARRAY_SIZE(cluster_list, zb_zcl_cluster_desc_t), cluster_list, \
|
||||
(zb_af_simple_desc_1_1_t *) &simple_desc_##ep_name, report_attr_count, \
|
||||
reporting_info##ep_name, 0, NULL)
|
||||
|
||||
namespace esphome::zigbee {
|
||||
|
||||
struct BinaryAttrs {
|
||||
zb_bool_t out_of_service;
|
||||
zb_bool_t present_value;
|
||||
zb_uint8_t status_flags;
|
||||
zb_uchar_t description[ZB_ZCL_MAX_STRING_SIZE];
|
||||
};
|
||||
|
||||
struct AnalogAttrs {
|
||||
zb_bool_t out_of_service;
|
||||
float present_value;
|
||||
zb_uint8_t status_flags;
|
||||
zb_uchar_t description[ZB_ZCL_MAX_STRING_SIZE];
|
||||
float max_present_value;
|
||||
float min_present_value;
|
||||
float resolution;
|
||||
};
|
||||
|
||||
class ZigbeeComponent : public Component {
|
||||
public:
|
||||
void setup() override;
|
||||
void dump_config() override;
|
||||
void add_callback(zb_uint8_t endpoint, std::function<void(zb_bufid_t bufid)> &&cb) {
|
||||
// endpoints are enumerated from 1
|
||||
this->callbacks_[endpoint - 1] = std::move(cb);
|
||||
}
|
||||
void add_join_callback(std::function<void()> &&cb) { this->join_cb_.add(std::move(cb)); }
|
||||
void zboss_signal_handler_esphome(zb_bufid_t bufid);
|
||||
void factory_reset();
|
||||
Trigger<> *get_join_trigger() { return &this->join_trigger_; };
|
||||
void flush();
|
||||
void loop() override;
|
||||
|
||||
protected:
|
||||
static void zcl_device_cb(zb_bufid_t bufid);
|
||||
void on_join_();
|
||||
#ifdef USE_ZIGBEE_WIPE_ON_BOOT
|
||||
void erase_flash_(int area);
|
||||
#endif
|
||||
StaticVector<std::function<void(zb_bufid_t bufid)>, ZIGBEE_ENDPOINTS_COUNT> callbacks_;
|
||||
CallbackManager<void()> join_cb_;
|
||||
Trigger<> join_trigger_;
|
||||
bool need_flush_{false};
|
||||
};
|
||||
|
||||
class ZigbeeEntity {
|
||||
public:
|
||||
void set_parent(ZigbeeComponent *parent) { this->parent_ = parent; }
|
||||
void set_end_point(zb_uint8_t end_point) { this->end_point_ = end_point; }
|
||||
|
||||
protected:
|
||||
zb_uint8_t end_point_{0};
|
||||
ZigbeeComponent *parent_{nullptr};
|
||||
};
|
||||
|
||||
} // namespace esphome::zigbee
|
||||
#endif
|
||||
265
esphome/components/zigbee/zigbee_zephyr.py
Normal file
265
esphome/components/zigbee/zigbee_zephyr.py
Normal file
@@ -0,0 +1,265 @@
|
||||
from datetime import datetime
|
||||
|
||||
from esphome import automation
|
||||
import esphome.codegen as cg
|
||||
from esphome.components.zephyr import zephyr_add_prj_conf
|
||||
import esphome.config_validation as cv
|
||||
from esphome.const import CONF_ID, CONF_NAME, __version__
|
||||
from esphome.core import CORE, CoroPriority, coroutine_with_priority
|
||||
from esphome.cpp_generator import (
|
||||
AssignmentExpression,
|
||||
MockObj,
|
||||
VariableDeclarationExpression,
|
||||
)
|
||||
from esphome.types import ConfigType
|
||||
|
||||
from .const_zephyr import (
|
||||
CONF_ON_JOIN,
|
||||
CONF_WIPE_ON_BOOT,
|
||||
CONF_ZIGBEE_BINARY_SENSOR,
|
||||
CONF_ZIGBEE_ID,
|
||||
KEY_EP_NUMBER,
|
||||
KEY_ZIGBEE,
|
||||
ZB_ZCL_BASIC_ATTRS_EXT_T,
|
||||
ZB_ZCL_CLUSTER_ID_BASIC,
|
||||
ZB_ZCL_CLUSTER_ID_BINARY_INPUT,
|
||||
ZB_ZCL_CLUSTER_ID_IDENTIFY,
|
||||
ZB_ZCL_IDENTIFY_ATTRS_T,
|
||||
BinaryAttrs,
|
||||
ZigbeeComponent,
|
||||
zigbee_ns,
|
||||
)
|
||||
|
||||
ZigbeeBinarySensor = zigbee_ns.class_("ZigbeeBinarySensor", cg.Component)
|
||||
|
||||
zephyr_binary_sensor = cv.Schema(
|
||||
{
|
||||
cv.OnlyWith(CONF_ZIGBEE_ID, ["nrf52", "zigbee"]): cv.use_id(ZigbeeComponent),
|
||||
cv.OnlyWith(CONF_ZIGBEE_BINARY_SENSOR, ["nrf52", "zigbee"]): cv.declare_id(
|
||||
ZigbeeBinarySensor
|
||||
),
|
||||
}
|
||||
)
|
||||
|
||||
|
||||
async def zephyr_to_code(config: ConfigType) -> None:
|
||||
zephyr_add_prj_conf("ZIGBEE", True)
|
||||
zephyr_add_prj_conf("ZIGBEE_APP_UTILS", True)
|
||||
zephyr_add_prj_conf("ZIGBEE_ROLE_END_DEVICE", True)
|
||||
|
||||
zephyr_add_prj_conf("ZIGBEE_CHANNEL_SELECTION_MODE_MULTI", True)
|
||||
|
||||
zephyr_add_prj_conf("CRYPTO", True)
|
||||
|
||||
zephyr_add_prj_conf("NET_IPV6", False)
|
||||
zephyr_add_prj_conf("NET_IP_ADDR_CHECK", False)
|
||||
zephyr_add_prj_conf("NET_UDP", False)
|
||||
|
||||
if config[CONF_WIPE_ON_BOOT]:
|
||||
cg.add_define("USE_ZIGBEE_WIPE_ON_BOOT")
|
||||
var = cg.new_Pvariable(config[CONF_ID])
|
||||
|
||||
if on_join_config := config.get(CONF_ON_JOIN):
|
||||
await automation.build_automation(var.get_join_trigger(), [], on_join_config)
|
||||
|
||||
await cg.register_component(var, config)
|
||||
|
||||
await _attr_to_code(config)
|
||||
CORE.add_job(_ctx_to_code, config)
|
||||
|
||||
|
||||
async def _attr_to_code(config: ConfigType) -> None:
|
||||
# Create the basic attributes structure and attribute list
|
||||
basic_attrs = zigbee_new_variable("zigbee_basic_attrs", ZB_ZCL_BASIC_ATTRS_EXT_T)
|
||||
zigbee_new_attr_list(
|
||||
"zigbee_basic_attrib_list",
|
||||
"ZB_ZCL_DECLARE_BASIC_ATTRIB_LIST_EXT",
|
||||
zigbee_assign(basic_attrs.zcl_version, cg.RawExpression("ZB_ZCL_VERSION")),
|
||||
zigbee_assign(basic_attrs.app_version, 0),
|
||||
zigbee_assign(basic_attrs.stack_version, 0),
|
||||
zigbee_assign(basic_attrs.hw_version, 0),
|
||||
zigbee_set_string(basic_attrs.mf_name, "esphome"),
|
||||
zigbee_set_string(basic_attrs.model_id, CORE.name),
|
||||
zigbee_set_string(
|
||||
basic_attrs.date_code, datetime.now().strftime("%d/%m/%y %H:%M")
|
||||
),
|
||||
zigbee_assign(
|
||||
basic_attrs.power_source,
|
||||
cg.RawExpression("ZB_ZCL_BASIC_POWER_SOURCE_DC_SOURCE"),
|
||||
),
|
||||
zigbee_set_string(basic_attrs.location_id, ""),
|
||||
zigbee_assign(
|
||||
basic_attrs.ph_env, cg.RawExpression("ZB_ZCL_BASIC_ENV_UNSPECIFIED")
|
||||
),
|
||||
zigbee_set_string(basic_attrs.sw_ver, __version__),
|
||||
)
|
||||
|
||||
# Create the identify attributes structure and attribute list
|
||||
identify_attrs = zigbee_new_variable(
|
||||
"zigbee_identify_attrs", ZB_ZCL_IDENTIFY_ATTRS_T
|
||||
)
|
||||
zigbee_new_attr_list(
|
||||
"zigbee_identify_attrib_list",
|
||||
"ZB_ZCL_DECLARE_IDENTIFY_ATTRIB_LIST",
|
||||
zigbee_assign(
|
||||
identify_attrs.identify_time,
|
||||
cg.RawExpression("ZB_ZCL_IDENTIFY_IDENTIFY_TIME_DEFAULT_VALUE"),
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
def zigbee_new_variable(name: str, type_: str) -> cg.MockObj:
|
||||
"""Create a global variable with the given name and type."""
|
||||
decl = VariableDeclarationExpression(type_, "", name)
|
||||
CORE.add_global(decl)
|
||||
return MockObj(name, ".")
|
||||
|
||||
|
||||
def zigbee_assign(target: cg.MockObj, expression: cg.RawExpression | int) -> str:
|
||||
"""Assign an expression to a target and return a reference to it."""
|
||||
cg.add(AssignmentExpression("", "", target, expression))
|
||||
return f"&{target}"
|
||||
|
||||
|
||||
def zigbee_set_string(target: cg.MockObj, value: str) -> str:
|
||||
"""Set a ZCL string value and return the target name (arrays decay to pointers)."""
|
||||
cg.add(
|
||||
cg.RawExpression(
|
||||
f"ZB_ZCL_SET_STRING_VAL({target}, {cg.safe_exp(value)}, ZB_ZCL_STRING_CONST_SIZE({cg.safe_exp(value)}))"
|
||||
)
|
||||
)
|
||||
return str(target)
|
||||
|
||||
|
||||
def zigbee_new_attr_list(name: str, macro: str, *args: str) -> str:
|
||||
"""Create an attribute list using a ZBOSS macro and return the name."""
|
||||
obj = cg.RawExpression(f"{macro}({name}, {', '.join(args)})")
|
||||
CORE.add_global(obj)
|
||||
return name
|
||||
|
||||
|
||||
class ZigbeeClusterDesc:
|
||||
"""Represents a Zigbee cluster descriptor for code generation."""
|
||||
|
||||
def __init__(self, cluster_id: str, attr_list_name: str | None = None) -> None:
|
||||
self._cluster_id = cluster_id
|
||||
self._attr_list_name = attr_list_name
|
||||
|
||||
@property
|
||||
def cluster_id(self) -> str:
|
||||
return self._cluster_id
|
||||
|
||||
@property
|
||||
def has_attrs(self) -> bool:
|
||||
return self._attr_list_name is not None
|
||||
|
||||
def __str__(self) -> str:
|
||||
role = (
|
||||
"ZB_ZCL_CLUSTER_SERVER_ROLE"
|
||||
if self._attr_list_name
|
||||
else "ZB_ZCL_CLUSTER_CLIENT_ROLE"
|
||||
)
|
||||
if self._attr_list_name:
|
||||
attr_count = f"ZB_ZCL_ARRAY_SIZE({self._attr_list_name}, zb_zcl_attr_t)"
|
||||
return f"ZB_ZCL_CLUSTER_DESC({self._cluster_id}, {attr_count}, {self._attr_list_name}, {role}, ZB_ZCL_MANUF_CODE_INVALID)"
|
||||
return f"ZB_ZCL_CLUSTER_DESC({self._cluster_id}, 0, NULL, {role}, ZB_ZCL_MANUF_CODE_INVALID)"
|
||||
|
||||
|
||||
def zigbee_new_cluster_list(
|
||||
name: str, clusters: list[ZigbeeClusterDesc]
|
||||
) -> tuple[str, list[ZigbeeClusterDesc]]:
|
||||
"""Create a cluster list array and return its name and the clusters."""
|
||||
# Always include basic and identify clusters first
|
||||
all_clusters = [
|
||||
ZigbeeClusterDesc(ZB_ZCL_CLUSTER_ID_BASIC, "zigbee_basic_attrib_list"),
|
||||
ZigbeeClusterDesc(ZB_ZCL_CLUSTER_ID_IDENTIFY, "zigbee_identify_attrib_list"),
|
||||
]
|
||||
all_clusters.extend(clusters)
|
||||
|
||||
cluster_strs = [str(c) for c in all_clusters]
|
||||
CORE.add_global(
|
||||
cg.RawExpression(
|
||||
f"zb_zcl_cluster_desc_t {name}[] = {{{', '.join(cluster_strs)}}}"
|
||||
)
|
||||
)
|
||||
return (name, all_clusters)
|
||||
|
||||
|
||||
def zigbee_register_ep(
|
||||
ep_name: str,
|
||||
cluster_list_name: str,
|
||||
report_attr_count: int,
|
||||
clusters: list[ZigbeeClusterDesc],
|
||||
slot_index: int,
|
||||
) -> None:
|
||||
"""Register a Zigbee endpoint."""
|
||||
in_cluster_num = sum(1 for c in clusters if c.has_attrs)
|
||||
out_cluster_num = len(clusters) - in_cluster_num
|
||||
cluster_ids = [c.cluster_id for c in clusters]
|
||||
|
||||
# Store endpoint name for device context generation
|
||||
CORE.data[KEY_ZIGBEE][KEY_EP_NUMBER][slot_index] = ep_name
|
||||
|
||||
# Generate the endpoint declaration
|
||||
ep_id = slot_index + 1 # Endpoints are 1-indexed
|
||||
obj = cg.RawExpression(
|
||||
f"ESPHOME_ZB_HA_DECLARE_EP({ep_name}, {ep_id}, {cluster_list_name}, "
|
||||
f"{in_cluster_num}, {out_cluster_num}, {report_attr_count}, {', '.join(cluster_ids)})"
|
||||
)
|
||||
CORE.add_global(obj)
|
||||
|
||||
|
||||
@coroutine_with_priority(CoroPriority.LATE)
|
||||
async def _ctx_to_code(config: ConfigType) -> None:
|
||||
cg.add_define("ZIGBEE_ENDPOINTS_COUNT", len(CORE.data[KEY_ZIGBEE][KEY_EP_NUMBER]))
|
||||
cg.add_global(
|
||||
cg.RawExpression(
|
||||
f"ZBOSS_DECLARE_DEVICE_CTX_EP_VA(zb_device_ctx, &{', &'.join(CORE.data[KEY_ZIGBEE][KEY_EP_NUMBER])})"
|
||||
)
|
||||
)
|
||||
cg.add(cg.RawExpression("ZB_AF_REGISTER_DEVICE_CTX(&zb_device_ctx)"))
|
||||
|
||||
|
||||
async def zephyr_setup_binary_sensor(entity: cg.MockObj, config: ConfigType) -> None:
|
||||
CORE.add_job(_add_binary_sensor, entity, config)
|
||||
|
||||
|
||||
async def _add_binary_sensor(entity: cg.MockObj, config: ConfigType) -> None:
|
||||
# Find the next available endpoint slot
|
||||
slot_index = next(
|
||||
(i for i, v in enumerate(CORE.data[KEY_ZIGBEE][KEY_EP_NUMBER]) if v == ""), None
|
||||
)
|
||||
|
||||
# Create unique names for this sensor's variables based on slot index
|
||||
prefix = f"zigbee_ep{slot_index + 1}"
|
||||
attrs_name = f"{prefix}_binary_attrs"
|
||||
attr_list_name = f"{prefix}_binary_input_attrib_list"
|
||||
cluster_list_name = f"{prefix}_cluster_list"
|
||||
ep_name = f"{prefix}_ep"
|
||||
|
||||
# Create the binary attributes structure
|
||||
binary_attrs = zigbee_new_variable(attrs_name, BinaryAttrs)
|
||||
attr_list = zigbee_new_attr_list(
|
||||
attr_list_name,
|
||||
"ESPHOME_ZB_ZCL_DECLARE_BINARY_INPUT_ATTRIB_LIST",
|
||||
zigbee_assign(binary_attrs.out_of_service, 0),
|
||||
zigbee_assign(binary_attrs.present_value, 0),
|
||||
zigbee_assign(binary_attrs.status_flags, 0),
|
||||
zigbee_set_string(binary_attrs.description, config[CONF_NAME]),
|
||||
)
|
||||
|
||||
# Create cluster list and register endpoint
|
||||
cluster_list_name, clusters = zigbee_new_cluster_list(
|
||||
cluster_list_name,
|
||||
[ZigbeeClusterDesc(ZB_ZCL_CLUSTER_ID_BINARY_INPUT, attr_list)],
|
||||
)
|
||||
zigbee_register_ep(ep_name, cluster_list_name, 2, clusters, slot_index)
|
||||
|
||||
# Create the ZigbeeBinarySensor component
|
||||
var = cg.new_Pvariable(config[CONF_ZIGBEE_BINARY_SENSOR], entity)
|
||||
await cg.register_component(var, config)
|
||||
|
||||
cg.add(var.set_end_point(slot_index + 1))
|
||||
cg.add(var.set_cluster_attributes(binary_attrs))
|
||||
hub = await cg.get_variable(config[CONF_ZIGBEE_ID])
|
||||
cg.add(var.set_parent(hub))
|
||||
@@ -299,6 +299,9 @@
|
||||
#define USE_NRF52_UICR_ERASE
|
||||
#define USE_SOFTDEVICE_ID 7
|
||||
#define USE_SOFTDEVICE_VERSION 1
|
||||
#define USE_ZIGBEE
|
||||
#define USE_ZIGBEE_WIPE_ON_BOOT
|
||||
#define ZIGBEE_ENDPOINTS_COUNT 8
|
||||
#endif
|
||||
|
||||
// Disabled feature flags
|
||||
|
||||
@@ -17,6 +17,7 @@ def load_idedata(environment, temp_folder, platformio_ini):
|
||||
"""
|
||||
#include <zephyr/kernel.h>
|
||||
int main() { return 0;}
|
||||
extern "C" void zboss_signal_handler() {};
|
||||
""",
|
||||
encoding="utf-8",
|
||||
)
|
||||
@@ -27,6 +28,12 @@ int main() { return 0;}
|
||||
CONFIG_NEWLIB_LIBC=y
|
||||
CONFIG_BT=y
|
||||
CONFIG_ADC=y
|
||||
#zigbee begin
|
||||
CONFIG_ZIGBEE=y
|
||||
CONFIG_CRYPTO=y
|
||||
CONFIG_NVS=y
|
||||
CONFIG_SETTINGS=y
|
||||
#zigbee end
|
||||
""",
|
||||
encoding="utf-8",
|
||||
)
|
||||
@@ -44,10 +51,11 @@ CONFIG_ADC=y
|
||||
|
||||
def extract_defines(command):
|
||||
define_pattern = re.compile(r"-D\s*([^\s]+)")
|
||||
ignore_prefixes = ("_ASMLANGUAGE", "NRF_802154_ECB_PRIORITY=")
|
||||
return [
|
||||
match
|
||||
match.replace("\\", "")
|
||||
for match in define_pattern.findall(command)
|
||||
if match not in ("_ASMLANGUAGE")
|
||||
if not any(match.startswith(prefix) for prefix in ignore_prefixes)
|
||||
]
|
||||
|
||||
def find_cxx_path(commands):
|
||||
|
||||
34
tests/components/zigbee/common.yaml
Normal file
34
tests/components/zigbee/common.yaml
Normal file
@@ -0,0 +1,34 @@
|
||||
---
|
||||
binary_sensor:
|
||||
- platform: template
|
||||
name: "Garage Door Open 1"
|
||||
- platform: template
|
||||
name: "Garage Door Open 2"
|
||||
- platform: template
|
||||
name: "Garage Door Open 3"
|
||||
- platform: template
|
||||
name: "Garage Door Open 4"
|
||||
- platform: template
|
||||
name: "Garage Door Open 5"
|
||||
- platform: template
|
||||
name: "Garage Door Open 6"
|
||||
- platform: template
|
||||
name: "Garage Door Open 7"
|
||||
internal: True
|
||||
- platform: template
|
||||
name: "Garage Door Open 8"
|
||||
- platform: template
|
||||
name: "Garage Door Open 9"
|
||||
|
||||
zigbee:
|
||||
wipe_on_boot: true
|
||||
on_join:
|
||||
then:
|
||||
- logger.log: "Joined network"
|
||||
|
||||
output:
|
||||
- platform: template
|
||||
id: output_factory
|
||||
type: binary
|
||||
write_action:
|
||||
- zigbee.factory_reset
|
||||
1
tests/components/zigbee/test.nrf52-adafruit.yaml
Normal file
1
tests/components/zigbee/test.nrf52-adafruit.yaml
Normal file
@@ -0,0 +1 @@
|
||||
<<: !include common.yaml
|
||||
1
tests/components/zigbee/test.nrf52-mcumgr.yaml
Normal file
1
tests/components/zigbee/test.nrf52-mcumgr.yaml
Normal file
@@ -0,0 +1 @@
|
||||
<<: !include common.yaml
|
||||
1
tests/components/zigbee/test.nrf52-xiao-ble.yaml
Normal file
1
tests/components/zigbee/test.nrf52-xiao-ble.yaml
Normal file
@@ -0,0 +1 @@
|
||||
<<: !include common.yaml
|
||||
Reference in New Issue
Block a user