mirror of
https://github.com/esphome/esphome.git
synced 2026-02-08 00:31:58 +00:00
[nrf52,zigbee] Time synchronization (#12236)
Co-authored-by: Jonathan Swoboda <154711427+swoboda1337@users.noreply.github.com>
This commit is contained in:
@@ -27,6 +27,9 @@ void RealTimeClock::dump_config() {
|
|||||||
#ifdef USE_TIME_TIMEZONE
|
#ifdef USE_TIME_TIMEZONE
|
||||||
ESP_LOGCONFIG(TAG, "Timezone: '%s'", this->timezone_.c_str());
|
ESP_LOGCONFIG(TAG, "Timezone: '%s'", this->timezone_.c_str());
|
||||||
#endif
|
#endif
|
||||||
|
auto time = this->now();
|
||||||
|
ESP_LOGCONFIG(TAG, "Current time: %04d-%02d-%02d %02d:%02d:%02d", time.year, time.month, time.day_of_month, time.hour,
|
||||||
|
time.minute, time.second);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RealTimeClock::synchronize_epoch_(uint32_t epoch) {
|
void RealTimeClock::synchronize_epoch_(uint32_t epoch) {
|
||||||
|
|||||||
@@ -120,7 +120,7 @@ async def setup_switch(entity: cg.MockObj, config: ConfigType) -> None:
|
|||||||
def consume_endpoint(config: ConfigType) -> ConfigType:
|
def consume_endpoint(config: ConfigType) -> ConfigType:
|
||||||
if not config.get(CONF_ZIGBEE_ID) or config.get(CONF_INTERNAL):
|
if not config.get(CONF_ZIGBEE_ID) or config.get(CONF_INTERNAL):
|
||||||
return config
|
return config
|
||||||
if " " in config[CONF_NAME]:
|
if CONF_NAME in config and " " in config[CONF_NAME]:
|
||||||
_LOGGER.warning(
|
_LOGGER.warning(
|
||||||
"Spaces in '%s' work with ZHA but not Zigbee2MQTT. For Zigbee2MQTT use '%s'",
|
"Spaces in '%s' work with ZHA but not Zigbee2MQTT. For Zigbee2MQTT use '%s'",
|
||||||
config[CONF_NAME],
|
config[CONF_NAME],
|
||||||
|
|||||||
86
esphome/components/zigbee/time/__init__.py
Normal file
86
esphome/components/zigbee/time/__init__.py
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
import esphome.codegen as cg
|
||||||
|
from esphome.components import time as time_
|
||||||
|
import esphome.config_validation as cv
|
||||||
|
from esphome.const import CONF_ID
|
||||||
|
from esphome.core import CORE
|
||||||
|
from esphome.types import ConfigType
|
||||||
|
|
||||||
|
from .. import consume_endpoint
|
||||||
|
from ..const_zephyr import CONF_ZIGBEE_ID, zigbee_ns
|
||||||
|
from ..zigbee_zephyr import (
|
||||||
|
ZigbeeClusterDesc,
|
||||||
|
ZigbeeComponent,
|
||||||
|
get_slot_index,
|
||||||
|
zigbee_new_attr_list,
|
||||||
|
zigbee_new_cluster_list,
|
||||||
|
zigbee_new_variable,
|
||||||
|
zigbee_register_ep,
|
||||||
|
)
|
||||||
|
|
||||||
|
DEPENDENCIES = ["zigbee"]
|
||||||
|
|
||||||
|
ZigbeeTime = zigbee_ns.class_("ZigbeeTime", time_.RealTimeClock)
|
||||||
|
|
||||||
|
CONFIG_SCHEMA = cv.All(
|
||||||
|
time_.TIME_SCHEMA.extend(
|
||||||
|
{
|
||||||
|
cv.GenerateID(): cv.declare_id(ZigbeeTime),
|
||||||
|
cv.OnlyWith(CONF_ZIGBEE_ID, ["nrf52", "zigbee"]): cv.use_id(
|
||||||
|
ZigbeeComponent
|
||||||
|
),
|
||||||
|
}
|
||||||
|
)
|
||||||
|
.extend(cv.COMPONENT_SCHEMA)
|
||||||
|
.extend(cv.polling_component_schema("1s")),
|
||||||
|
consume_endpoint,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
async def to_code(config: ConfigType) -> None:
|
||||||
|
CORE.add_job(_add_time, config)
|
||||||
|
|
||||||
|
|
||||||
|
async def _add_time(config: ConfigType) -> None:
|
||||||
|
slot_index = get_slot_index()
|
||||||
|
|
||||||
|
# Create unique names for this sensor's variables based on slot index
|
||||||
|
prefix = f"zigbee_ep{slot_index + 1}"
|
||||||
|
attrs_name = f"{prefix}_time_attrs"
|
||||||
|
attr_list_name = f"{prefix}_time_attrib_list"
|
||||||
|
cluster_list_name = f"{prefix}_cluster_list"
|
||||||
|
ep_name = f"{prefix}_ep"
|
||||||
|
|
||||||
|
# Create the binary attributes structure
|
||||||
|
time_attrs = zigbee_new_variable(attrs_name, "zb_zcl_time_attrs_t")
|
||||||
|
attr_list = zigbee_new_attr_list(
|
||||||
|
attr_list_name,
|
||||||
|
"ZB_ZCL_DECLARE_TIME_ATTR_LIST",
|
||||||
|
str(time_attrs),
|
||||||
|
)
|
||||||
|
|
||||||
|
# Create cluster list and register endpoint
|
||||||
|
cluster_list_name, clusters = zigbee_new_cluster_list(
|
||||||
|
cluster_list_name,
|
||||||
|
[
|
||||||
|
ZigbeeClusterDesc("ZB_ZCL_CLUSTER_ID_TIME", attr_list),
|
||||||
|
ZigbeeClusterDesc("ZB_ZCL_CLUSTER_ID_TIME"),
|
||||||
|
],
|
||||||
|
)
|
||||||
|
zigbee_register_ep(
|
||||||
|
ep_name,
|
||||||
|
cluster_list_name,
|
||||||
|
0,
|
||||||
|
clusters,
|
||||||
|
slot_index,
|
||||||
|
"ZB_HA_CUSTOM_ATTR_DEVICE_ID",
|
||||||
|
)
|
||||||
|
|
||||||
|
# Create the ZigbeeTime component
|
||||||
|
var = cg.new_Pvariable(config[CONF_ID])
|
||||||
|
await time_.register_time(var, config)
|
||||||
|
await cg.register_component(var, config)
|
||||||
|
|
||||||
|
cg.add(var.set_endpoint(slot_index + 1))
|
||||||
|
cg.add(var.set_cluster_attributes(time_attrs))
|
||||||
|
hub = await cg.get_variable(config[CONF_ZIGBEE_ID])
|
||||||
|
cg.add(var.set_parent(hub))
|
||||||
87
esphome/components/zigbee/time/zigbee_time_zephyr.cpp
Normal file
87
esphome/components/zigbee/time/zigbee_time_zephyr.cpp
Normal file
@@ -0,0 +1,87 @@
|
|||||||
|
#include "zigbee_time_zephyr.h"
|
||||||
|
#if defined(USE_ZIGBEE) && defined(USE_NRF52) && defined(USE_TIME)
|
||||||
|
#include "esphome/core/log.h"
|
||||||
|
|
||||||
|
namespace esphome::zigbee {
|
||||||
|
|
||||||
|
static const char *const TAG = "zigbee.time";
|
||||||
|
|
||||||
|
// This time standard is the number of
|
||||||
|
// seconds since 0 hrs 0 mins 0 sec on 1st January 2000 UTC (Universal Coordinated Time).
|
||||||
|
constexpr time_t EPOCH_2000 = 946684800;
|
||||||
|
|
||||||
|
ZigbeeTime *global_time = nullptr; // NOLINT(cppcoreguidelines-avoid-non-const-global-variables)
|
||||||
|
|
||||||
|
void ZigbeeTime::sync_time(zb_ret_t status, zb_uint32_t auth_level, zb_uint16_t short_addr, zb_uint8_t endpoint,
|
||||||
|
zb_uint32_t nw_time) {
|
||||||
|
if (status == RET_OK && auth_level >= ZB_ZCL_TIME_HAS_SYNCHRONIZED_BIT) {
|
||||||
|
global_time->set_epoch_time(nw_time + EPOCH_2000);
|
||||||
|
} else if (status != RET_TIMEOUT || !global_time->has_time_) {
|
||||||
|
ESP_LOGE(TAG, "Status: %d, auth_level: %u, short_addr: %d, endpoint: %d, nw_time: %u", status, auth_level,
|
||||||
|
short_addr, endpoint, nw_time);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZigbeeTime::setup() {
|
||||||
|
global_time = this;
|
||||||
|
this->parent_->add_callback(this->endpoint_, [this](zb_bufid_t bufid) { this->zcl_device_cb_(bufid); });
|
||||||
|
synchronize_epoch_(EPOCH_2000);
|
||||||
|
this->parent_->add_join_callback([this]() { zb_zcl_time_server_synchronize(this->endpoint_, sync_time); });
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZigbeeTime::dump_config() {
|
||||||
|
ESP_LOGCONFIG(TAG,
|
||||||
|
"Zigbee Time\n"
|
||||||
|
" Endpoint: %d",
|
||||||
|
this->endpoint_);
|
||||||
|
RealTimeClock::dump_config();
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZigbeeTime::update() {
|
||||||
|
time_t time = timestamp_now();
|
||||||
|
this->cluster_attributes_->time = time - EPOCH_2000;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZigbeeTime::set_epoch_time(uint32_t epoch) {
|
||||||
|
this->defer([this, epoch]() {
|
||||||
|
this->synchronize_epoch_(epoch);
|
||||||
|
this->has_time_ = true;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
void ZigbeeTime::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;
|
||||||
|
|
||||||
|
switch (device_cb_id) {
|
||||||
|
/* ZCL set attribute value */
|
||||||
|
case ZB_ZCL_SET_ATTR_VALUE_CB_ID:
|
||||||
|
if (cluster_id == ZB_ZCL_CLUSTER_ID_TIME) {
|
||||||
|
if (attr_id == ZB_ZCL_ATTR_TIME_TIME_ID) {
|
||||||
|
zb_uint32_t value = p_device_cb_param->cb_param.set_attr_value_param.values.data32;
|
||||||
|
ESP_LOGI(TAG, "Synchronize time to %u", value);
|
||||||
|
this->defer([this, value]() { synchronize_epoch_(value + EPOCH_2000); });
|
||||||
|
} else if (attr_id == ZB_ZCL_ATTR_TIME_TIME_STATUS_ID) {
|
||||||
|
zb_uint8_t value = p_device_cb_param->cb_param.set_attr_value_param.values.data8;
|
||||||
|
ESP_LOGI(TAG, "Time status %hd", value);
|
||||||
|
this->defer([this, value]() { this->has_time_ = ZB_ZCL_TIME_TIME_STATUS_SYNCHRONIZED_BIT_IS_SET(value); });
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
/* other clusters attribute handled here */
|
||||||
|
ESP_LOGI(TAG, "Unhandled cluster attribute id: %d", cluster_id);
|
||||||
|
p_device_cb_param->status = RET_NOT_IMPLEMENTED;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
p_device_cb_param->status = RET_NOT_IMPLEMENTED;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
ESP_LOGD(TAG, "Zcl_device_cb_ status: %hd", p_device_cb_param->status);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace esphome::zigbee
|
||||||
|
|
||||||
|
#endif
|
||||||
38
esphome/components/zigbee/time/zigbee_time_zephyr.h
Normal file
38
esphome/components/zigbee/time/zigbee_time_zephyr.h
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "esphome/core/defines.h"
|
||||||
|
#if defined(USE_ZIGBEE) && defined(USE_NRF52) && defined(USE_TIME)
|
||||||
|
#include "esphome/core/component.h"
|
||||||
|
#include "esphome/components/time/real_time_clock.h"
|
||||||
|
#include "esphome/components/zigbee/zigbee_zephyr.h"
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
#include <zboss_api.h>
|
||||||
|
#include <zboss_api_addons.h>
|
||||||
|
}
|
||||||
|
|
||||||
|
namespace esphome::zigbee {
|
||||||
|
|
||||||
|
class ZigbeeTime : public time::RealTimeClock, public ZigbeeEntity {
|
||||||
|
public:
|
||||||
|
void setup() override;
|
||||||
|
void dump_config() override;
|
||||||
|
void update() override;
|
||||||
|
|
||||||
|
void set_cluster_attributes(zb_zcl_time_attrs_t &cluster_attributes) {
|
||||||
|
this->cluster_attributes_ = &cluster_attributes;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_epoch_time(uint32_t epoch);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
static void sync_time(zb_ret_t status, zb_uint32_t auth_level, zb_uint16_t short_addr, zb_uint8_t endpoint,
|
||||||
|
zb_uint32_t nw_time);
|
||||||
|
void zcl_device_cb_(zb_bufid_t bufid);
|
||||||
|
zb_zcl_time_attrs_t *cluster_attributes_{nullptr};
|
||||||
|
|
||||||
|
bool has_time_{false};
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace esphome::zigbee
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -22,7 +22,7 @@ void ZigbeeBinarySensor::setup() {
|
|||||||
ZB_ZCL_SET_ATTRIBUTE(this->endpoint_, ZB_ZCL_CLUSTER_ID_BINARY_INPUT, ZB_ZCL_CLUSTER_SERVER_ROLE,
|
ZB_ZCL_SET_ATTRIBUTE(this->endpoint_, 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_ZCL_ATTR_BINARY_INPUT_PRESENT_VALUE_ID, &this->cluster_attributes_->present_value,
|
||||||
ZB_FALSE);
|
ZB_FALSE);
|
||||||
this->parent_->flush();
|
this->parent_->force_report();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -21,7 +21,7 @@ void ZigbeeSensor::setup() {
|
|||||||
ZB_ZCL_SET_ATTRIBUTE(this->endpoint_, ZB_ZCL_CLUSTER_ID_ANALOG_INPUT, ZB_ZCL_CLUSTER_SERVER_ROLE,
|
ZB_ZCL_SET_ATTRIBUTE(this->endpoint_, ZB_ZCL_CLUSTER_ID_ANALOG_INPUT, ZB_ZCL_CLUSTER_SERVER_ROLE,
|
||||||
ZB_ZCL_ATTR_ANALOG_INPUT_PRESENT_VALUE_ID,
|
ZB_ZCL_ATTR_ANALOG_INPUT_PRESENT_VALUE_ID,
|
||||||
(zb_uint8_t *) &this->cluster_attributes_->present_value, ZB_FALSE);
|
(zb_uint8_t *) &this->cluster_attributes_->present_value, ZB_FALSE);
|
||||||
this->parent_->flush();
|
this->parent_->force_report();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ void ZigbeeSwitch::setup() {
|
|||||||
ZB_ZCL_SET_ATTRIBUTE(this->endpoint_, ZB_ZCL_CLUSTER_ID_BINARY_OUTPUT, ZB_ZCL_CLUSTER_SERVER_ROLE,
|
ZB_ZCL_SET_ATTRIBUTE(this->endpoint_, ZB_ZCL_CLUSTER_ID_BINARY_OUTPUT, ZB_ZCL_CLUSTER_SERVER_ROLE,
|
||||||
ZB_ZCL_ATTR_BINARY_OUTPUT_PRESENT_VALUE_ID, &this->cluster_attributes_->present_value,
|
ZB_ZCL_ATTR_BINARY_OUTPUT_PRESENT_VALUE_ID, &this->cluster_attributes_->present_value,
|
||||||
ZB_FALSE);
|
ZB_FALSE);
|
||||||
this->parent_->flush();
|
this->parent_->force_report();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -41,8 +41,6 @@ void ZigbeeSwitch::zcl_device_cb_(zb_bufid_t bufid) {
|
|||||||
zb_uint16_t cluster_id = p_device_cb_param->cb_param.set_attr_value_param.cluster_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;
|
zb_uint16_t attr_id = p_device_cb_param->cb_param.set_attr_value_param.attr_id;
|
||||||
|
|
||||||
p_device_cb_param->status = RET_OK;
|
|
||||||
|
|
||||||
switch (device_cb_id) {
|
switch (device_cb_id) {
|
||||||
/* ZCL set attribute value */
|
/* ZCL set attribute value */
|
||||||
case ZB_ZCL_SET_ATTR_VALUE_CB_ID:
|
case ZB_ZCL_SET_ATTR_VALUE_CB_ID:
|
||||||
@@ -58,10 +56,11 @@ void ZigbeeSwitch::zcl_device_cb_(zb_bufid_t bufid) {
|
|||||||
} else {
|
} else {
|
||||||
/* other clusters attribute handled here */
|
/* other clusters attribute handled here */
|
||||||
ESP_LOGI(TAG, "Unhandled cluster attribute id: %d", cluster_id);
|
ESP_LOGI(TAG, "Unhandled cluster attribute id: %d", cluster_id);
|
||||||
|
p_device_cb_param->status = RET_NOT_IMPLEMENTED;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
p_device_cb_param->status = RET_ERROR;
|
p_device_cb_param->status = RET_NOT_IMPLEMENTED;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -112,10 +112,10 @@ void ZigbeeComponent::zcl_device_cb(zb_bufid_t bufid) {
|
|||||||
const auto &cb = global_zigbee->callbacks_[endpoint - 1];
|
const auto &cb = global_zigbee->callbacks_[endpoint - 1];
|
||||||
if (cb) {
|
if (cb) {
|
||||||
cb(bufid);
|
cb(bufid);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
p_device_cb_param->status = RET_ERROR;
|
p_device_cb_param->status = RET_NOT_IMPLEMENTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ZigbeeComponent::on_join_() {
|
void ZigbeeComponent::on_join_() {
|
||||||
@@ -230,11 +230,11 @@ static void send_attribute_report(zb_bufid_t bufid, zb_uint16_t cmd_id) {
|
|||||||
zb_buf_free(bufid);
|
zb_buf_free(bufid);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ZigbeeComponent::flush() { this->need_flush_ = true; }
|
void ZigbeeComponent::force_report() { this->force_report_ = true; }
|
||||||
|
|
||||||
void ZigbeeComponent::loop() {
|
void ZigbeeComponent::loop() {
|
||||||
if (this->need_flush_) {
|
if (this->force_report_) {
|
||||||
this->need_flush_ = false;
|
this->force_report_ = false;
|
||||||
zb_buf_get_out_delayed_ext(send_attribute_report, 0, 0);
|
zb_buf_get_out_delayed_ext(send_attribute_report, 0, 0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ class ZigbeeComponent : public Component {
|
|||||||
void zboss_signal_handler_esphome(zb_bufid_t bufid);
|
void zboss_signal_handler_esphome(zb_bufid_t bufid);
|
||||||
void factory_reset();
|
void factory_reset();
|
||||||
Trigger<> *get_join_trigger() { return &this->join_trigger_; };
|
Trigger<> *get_join_trigger() { return &this->join_trigger_; };
|
||||||
void flush();
|
void force_report();
|
||||||
void loop() override;
|
void loop() override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
@@ -84,7 +84,7 @@ class ZigbeeComponent : public Component {
|
|||||||
std::array<std::function<void(zb_bufid_t bufid)>, ZIGBEE_ENDPOINTS_COUNT> callbacks_{};
|
std::array<std::function<void(zb_bufid_t bufid)>, ZIGBEE_ENDPOINTS_COUNT> callbacks_{};
|
||||||
CallbackManager<void()> join_cb_;
|
CallbackManager<void()> join_cb_;
|
||||||
Trigger<> join_trigger_;
|
Trigger<> join_trigger_;
|
||||||
bool need_flush_{false};
|
bool force_report_{false};
|
||||||
};
|
};
|
||||||
|
|
||||||
class ZigbeeEntity {
|
class ZigbeeEntity {
|
||||||
|
|||||||
@@ -336,14 +336,14 @@ async def zephyr_setup_switch(entity: cg.MockObj, config: ConfigType) -> None:
|
|||||||
CORE.add_job(_add_switch, entity, config)
|
CORE.add_job(_add_switch, entity, config)
|
||||||
|
|
||||||
|
|
||||||
def _slot_index() -> int:
|
def get_slot_index() -> int:
|
||||||
"""Find the next available endpoint slot"""
|
"""Find the next available endpoint slot."""
|
||||||
slot = next(
|
slot = next(
|
||||||
(i for i, v in enumerate(CORE.data[KEY_ZIGBEE][KEY_EP_NUMBER]) if v == ""), None
|
(i for i, v in enumerate(CORE.data[KEY_ZIGBEE][KEY_EP_NUMBER]) if v == ""), None
|
||||||
)
|
)
|
||||||
if slot is None:
|
if slot is None:
|
||||||
raise cv.Invalid(
|
raise cv.Invalid(
|
||||||
f"Not found empty slot, size ({len(CORE.data[KEY_ZIGBEE][KEY_EP_NUMBER])})"
|
f"No available Zigbee endpoint slots ({len(CORE.data[KEY_ZIGBEE][KEY_EP_NUMBER])} in use)"
|
||||||
)
|
)
|
||||||
return slot
|
return slot
|
||||||
|
|
||||||
@@ -358,7 +358,7 @@ async def _add_zigbee_ep(
|
|||||||
app_device_id: str,
|
app_device_id: str,
|
||||||
extra_field_values: dict[str, int] | None = None,
|
extra_field_values: dict[str, int] | None = None,
|
||||||
) -> None:
|
) -> None:
|
||||||
slot_index = _slot_index()
|
slot_index = get_slot_index()
|
||||||
|
|
||||||
prefix = f"zigbee_ep{slot_index + 1}"
|
prefix = f"zigbee_ep{slot_index + 1}"
|
||||||
attrs_name = f"{prefix}_attrs"
|
attrs_name = f"{prefix}_attrs"
|
||||||
|
|||||||
@@ -16,7 +16,6 @@
|
|||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <concepts>
|
#include <concepts>
|
||||||
|
|
||||||
#include <strings.h>
|
#include <strings.h>
|
||||||
|
|
||||||
#include "esphome/core/optional.h"
|
#include "esphome/core/optional.h"
|
||||||
|
|||||||
@@ -8,8 +8,6 @@ binary_sensor:
|
|||||||
name: "Garage Door Open 3"
|
name: "Garage Door Open 3"
|
||||||
- platform: template
|
- platform: template
|
||||||
name: "Garage Door Open 4"
|
name: "Garage Door Open 4"
|
||||||
- platform: template
|
|
||||||
name: "Garage Door Open 5"
|
|
||||||
- platform: template
|
- platform: template
|
||||||
name: "Garage Door Internal"
|
name: "Garage Door Internal"
|
||||||
internal: True
|
internal: True
|
||||||
@@ -21,6 +19,10 @@ sensor:
|
|||||||
- platform: template
|
- platform: template
|
||||||
name: "Analog 2"
|
name: "Analog 2"
|
||||||
lambda: return 11.0;
|
lambda: return 11.0;
|
||||||
|
- platform: template
|
||||||
|
name: "Analog 3"
|
||||||
|
lambda: return 12.0;
|
||||||
|
internal: True
|
||||||
|
|
||||||
zigbee:
|
zigbee:
|
||||||
wipe_on_boot: true
|
wipe_on_boot: true
|
||||||
@@ -35,6 +37,9 @@ output:
|
|||||||
write_action:
|
write_action:
|
||||||
- zigbee.factory_reset
|
- zigbee.factory_reset
|
||||||
|
|
||||||
|
time:
|
||||||
|
- platform: zigbee
|
||||||
|
|
||||||
switch:
|
switch:
|
||||||
- platform: template
|
- platform: template
|
||||||
name: "Template Switch"
|
name: "Template Switch"
|
||||||
|
|||||||
Reference in New Issue
Block a user