mirror of
https://github.com/esphome/esphome.git
synced 2026-02-08 00:31:58 +00:00
[ethernet_info] Convert to event-driven IP state listener pattern (#13203)
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -61,6 +61,21 @@ DEPENDENCIES = ["esp32"]
|
|||||||
AUTO_LOAD = ["network"]
|
AUTO_LOAD = ["network"]
|
||||||
LOGGER = logging.getLogger(__name__)
|
LOGGER = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
# Key for tracking IP state listener count in CORE.data
|
||||||
|
ETHERNET_IP_STATE_LISTENERS_KEY = "ethernet_ip_state_listeners"
|
||||||
|
|
||||||
|
|
||||||
|
def request_ethernet_ip_state_listener() -> None:
|
||||||
|
"""Request an IP state listener slot.
|
||||||
|
|
||||||
|
Components that implement EthernetIPStateListener should call this
|
||||||
|
in their to_code() to register for IP state notifications.
|
||||||
|
"""
|
||||||
|
CORE.data[ETHERNET_IP_STATE_LISTENERS_KEY] = (
|
||||||
|
CORE.data.get(ETHERNET_IP_STATE_LISTENERS_KEY, 0) + 1
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
# RMII pins that are hardcoded on ESP32 classic and cannot be changed
|
# RMII pins that are hardcoded on ESP32 classic and cannot be changed
|
||||||
# These pins are used by the internal Ethernet MAC when using RMII PHYs
|
# These pins are used by the internal Ethernet MAC when using RMII PHYs
|
||||||
ESP32_RMII_FIXED_PINS = {
|
ESP32_RMII_FIXED_PINS = {
|
||||||
@@ -411,6 +426,8 @@ async def to_code(config):
|
|||||||
if CORE.using_arduino:
|
if CORE.using_arduino:
|
||||||
cg.add_library("WiFi", None)
|
cg.add_library("WiFi", None)
|
||||||
|
|
||||||
|
CORE.add_job(final_step)
|
||||||
|
|
||||||
|
|
||||||
def _final_validate_rmii_pins(config: ConfigType) -> None:
|
def _final_validate_rmii_pins(config: ConfigType) -> None:
|
||||||
"""Validate that RMII pins are not used by other components."""
|
"""Validate that RMII pins are not used by other components."""
|
||||||
@@ -467,3 +484,11 @@ def _final_validate(config: ConfigType) -> ConfigType:
|
|||||||
|
|
||||||
|
|
||||||
FINAL_VALIDATE_SCHEMA = _final_validate
|
FINAL_VALIDATE_SCHEMA = _final_validate
|
||||||
|
|
||||||
|
|
||||||
|
@coroutine_with_priority(CoroPriority.FINAL)
|
||||||
|
async def final_step():
|
||||||
|
"""Final code generation step to configure optional Ethernet features."""
|
||||||
|
if ip_state_count := CORE.data.get(ETHERNET_IP_STATE_LISTENERS_KEY, 0):
|
||||||
|
cg.add_define("USE_ETHERNET_IP_STATE_LISTENERS")
|
||||||
|
cg.add_define("ESPHOME_ETHERNET_IP_STATE_LISTENERS", ip_state_count)
|
||||||
|
|||||||
@@ -472,6 +472,12 @@ void EthernetComponent::eth_event_handler(void *arg, esp_event_base_t event_base
|
|||||||
break;
|
break;
|
||||||
case ETHERNET_EVENT_CONNECTED:
|
case ETHERNET_EVENT_CONNECTED:
|
||||||
event_name = "ETH connected";
|
event_name = "ETH connected";
|
||||||
|
// For static IP configurations, GOT_IP event may not fire, so notify IP listeners here
|
||||||
|
#if defined(USE_ETHERNET_IP_STATE_LISTENERS) && defined(USE_ETHERNET_MANUAL_IP)
|
||||||
|
if (global_eth_component->manual_ip_.has_value()) {
|
||||||
|
global_eth_component->notify_ip_state_listeners_();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
break;
|
break;
|
||||||
case ETHERNET_EVENT_DISCONNECTED:
|
case ETHERNET_EVENT_DISCONNECTED:
|
||||||
event_name = "ETH disconnected";
|
event_name = "ETH disconnected";
|
||||||
@@ -498,6 +504,9 @@ void EthernetComponent::got_ip_event_handler(void *arg, esp_event_base_t event_b
|
|||||||
global_eth_component->connected_ = true;
|
global_eth_component->connected_ = true;
|
||||||
global_eth_component->enable_loop_soon_any_context(); // Enable loop when connection state changes
|
global_eth_component->enable_loop_soon_any_context(); // Enable loop when connection state changes
|
||||||
#endif /* USE_NETWORK_IPV6 */
|
#endif /* USE_NETWORK_IPV6 */
|
||||||
|
#ifdef USE_ETHERNET_IP_STATE_LISTENERS
|
||||||
|
global_eth_component->notify_ip_state_listeners_();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
#if USE_NETWORK_IPV6
|
#if USE_NETWORK_IPV6
|
||||||
@@ -514,9 +523,23 @@ void EthernetComponent::got_ip6_event_handler(void *arg, esp_event_base_t event_
|
|||||||
global_eth_component->connected_ = global_eth_component->got_ipv4_address_;
|
global_eth_component->connected_ = global_eth_component->got_ipv4_address_;
|
||||||
global_eth_component->enable_loop_soon_any_context(); // Enable loop when connection state changes
|
global_eth_component->enable_loop_soon_any_context(); // Enable loop when connection state changes
|
||||||
#endif
|
#endif
|
||||||
|
#ifdef USE_ETHERNET_IP_STATE_LISTENERS
|
||||||
|
global_eth_component->notify_ip_state_listeners_();
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
#endif /* USE_NETWORK_IPV6 */
|
#endif /* USE_NETWORK_IPV6 */
|
||||||
|
|
||||||
|
#ifdef USE_ETHERNET_IP_STATE_LISTENERS
|
||||||
|
void EthernetComponent::notify_ip_state_listeners_() {
|
||||||
|
auto ips = this->get_ip_addresses();
|
||||||
|
auto dns1 = this->get_dns_address(0);
|
||||||
|
auto dns2 = this->get_dns_address(1);
|
||||||
|
for (auto *listener : this->ip_state_listeners_) {
|
||||||
|
listener->on_ip_state(ips, dns1, dns2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif // USE_ETHERNET_IP_STATE_LISTENERS
|
||||||
|
|
||||||
void EthernetComponent::finish_connect_() {
|
void EthernetComponent::finish_connect_() {
|
||||||
#if USE_NETWORK_IPV6
|
#if USE_NETWORK_IPV6
|
||||||
// Retry IPv6 link-local setup if it failed during initial connect
|
// Retry IPv6 link-local setup if it failed during initial connect
|
||||||
|
|||||||
@@ -17,6 +17,22 @@
|
|||||||
namespace esphome {
|
namespace esphome {
|
||||||
namespace ethernet {
|
namespace ethernet {
|
||||||
|
|
||||||
|
#ifdef USE_ETHERNET_IP_STATE_LISTENERS
|
||||||
|
/** Listener interface for Ethernet IP state changes.
|
||||||
|
*
|
||||||
|
* Components can implement this interface to receive IP address updates
|
||||||
|
* without the overhead of std::function callbacks or polling.
|
||||||
|
*
|
||||||
|
* @note Components must call ethernet.request_ethernet_ip_state_listener() in their
|
||||||
|
* Python to_code() to register for this listener type.
|
||||||
|
*/
|
||||||
|
class EthernetIPStateListener {
|
||||||
|
public:
|
||||||
|
virtual void on_ip_state(const network::IPAddresses &ips, const network::IPAddress &dns1,
|
||||||
|
const network::IPAddress &dns2) = 0;
|
||||||
|
};
|
||||||
|
#endif // USE_ETHERNET_IP_STATE_LISTENERS
|
||||||
|
|
||||||
enum EthernetType : uint8_t {
|
enum EthernetType : uint8_t {
|
||||||
ETHERNET_TYPE_UNKNOWN = 0,
|
ETHERNET_TYPE_UNKNOWN = 0,
|
||||||
ETHERNET_TYPE_LAN8720,
|
ETHERNET_TYPE_LAN8720,
|
||||||
@@ -99,12 +115,19 @@ class EthernetComponent : public Component {
|
|||||||
eth_speed_t get_link_speed();
|
eth_speed_t get_link_speed();
|
||||||
bool powerdown();
|
bool powerdown();
|
||||||
|
|
||||||
|
#ifdef USE_ETHERNET_IP_STATE_LISTENERS
|
||||||
|
void add_ip_state_listener(EthernetIPStateListener *listener) { this->ip_state_listeners_.push_back(listener); }
|
||||||
|
#endif
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
static void eth_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data);
|
static void eth_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data);
|
||||||
static void got_ip_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data);
|
static void got_ip_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data);
|
||||||
#if LWIP_IPV6
|
#if LWIP_IPV6
|
||||||
static void got_ip6_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data);
|
static void got_ip6_event_handler(void *arg, esp_event_base_t event_base, int32_t event_id, void *event_data);
|
||||||
#endif /* LWIP_IPV6 */
|
#endif /* LWIP_IPV6 */
|
||||||
|
#ifdef USE_ETHERNET_IP_STATE_LISTENERS
|
||||||
|
void notify_ip_state_listeners_();
|
||||||
|
#endif
|
||||||
|
|
||||||
void start_connect_();
|
void start_connect_();
|
||||||
void finish_connect_();
|
void finish_connect_();
|
||||||
@@ -163,6 +186,10 @@ class EthernetComponent : public Component {
|
|||||||
esp_eth_phy_t *phy_{nullptr};
|
esp_eth_phy_t *phy_{nullptr};
|
||||||
optional<std::array<uint8_t, 6>> fixed_mac_;
|
optional<std::array<uint8_t, 6>> fixed_mac_;
|
||||||
|
|
||||||
|
#ifdef USE_ETHERNET_IP_STATE_LISTENERS
|
||||||
|
StaticVector<EthernetIPStateListener *, ESPHOME_ETHERNET_IP_STATE_LISTENERS> ip_state_listeners_;
|
||||||
|
#endif
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// Stores a pointer to a string literal (static storage duration).
|
// Stores a pointer to a string literal (static storage duration).
|
||||||
// ONLY set from Python-generated code with string literals - never dynamic strings.
|
// ONLY set from Python-generated code with string literals - never dynamic strings.
|
||||||
|
|||||||
@@ -7,8 +7,44 @@ namespace esphome::ethernet_info {
|
|||||||
|
|
||||||
static const char *const TAG = "ethernet_info";
|
static const char *const TAG = "ethernet_info";
|
||||||
|
|
||||||
|
#ifdef USE_ETHERNET_IP_STATE_LISTENERS
|
||||||
|
void IPAddressEthernetInfo::setup() { ethernet::global_eth_component->add_ip_state_listener(this); }
|
||||||
|
|
||||||
void IPAddressEthernetInfo::dump_config() { LOG_TEXT_SENSOR("", "EthernetInfo IPAddress", this); }
|
void IPAddressEthernetInfo::dump_config() { LOG_TEXT_SENSOR("", "EthernetInfo IPAddress", this); }
|
||||||
|
|
||||||
|
void IPAddressEthernetInfo::on_ip_state(const network::IPAddresses &ips, const network::IPAddress &dns1,
|
||||||
|
const network::IPAddress &dns2) {
|
||||||
|
char buf[network::IP_ADDRESS_BUFFER_SIZE];
|
||||||
|
ips[0].str_to(buf);
|
||||||
|
this->publish_state(buf);
|
||||||
|
uint8_t sensor = 0;
|
||||||
|
for (const auto &ip : ips) {
|
||||||
|
if (ip.is_set()) {
|
||||||
|
if (this->ip_sensors_[sensor] != nullptr) {
|
||||||
|
ip.str_to(buf);
|
||||||
|
this->ip_sensors_[sensor]->publish_state(buf);
|
||||||
|
}
|
||||||
|
sensor++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void DNSAddressEthernetInfo::setup() { ethernet::global_eth_component->add_ip_state_listener(this); }
|
||||||
|
|
||||||
void DNSAddressEthernetInfo::dump_config() { LOG_TEXT_SENSOR("", "EthernetInfo DNS Address", this); }
|
void DNSAddressEthernetInfo::dump_config() { LOG_TEXT_SENSOR("", "EthernetInfo DNS Address", this); }
|
||||||
|
|
||||||
|
void DNSAddressEthernetInfo::on_ip_state(const network::IPAddresses &ips, const network::IPAddress &dns1,
|
||||||
|
const network::IPAddress &dns2) {
|
||||||
|
// IP_ADDRESS_BUFFER_SIZE (40) = max IP (39) + null; space reuses first null's slot
|
||||||
|
char buf[network::IP_ADDRESS_BUFFER_SIZE * 2];
|
||||||
|
dns1.str_to(buf);
|
||||||
|
size_t len1 = strlen(buf);
|
||||||
|
buf[len1] = ' ';
|
||||||
|
dns2.str_to(buf + len1 + 1);
|
||||||
|
this->publish_state(buf);
|
||||||
|
}
|
||||||
|
#endif // USE_ETHERNET_IP_STATE_LISTENERS
|
||||||
|
|
||||||
void MACAddressEthernetInfo::dump_config() { LOG_TEXT_SENSOR("", "EthernetInfo MAC Address", this); }
|
void MACAddressEthernetInfo::dump_config() { LOG_TEXT_SENSOR("", "EthernetInfo MAC Address", this); }
|
||||||
|
|
||||||
} // namespace esphome::ethernet_info
|
} // namespace esphome::ethernet_info
|
||||||
|
|||||||
@@ -8,64 +8,37 @@
|
|||||||
|
|
||||||
namespace esphome::ethernet_info {
|
namespace esphome::ethernet_info {
|
||||||
|
|
||||||
class IPAddressEthernetInfo : public PollingComponent, public text_sensor::TextSensor {
|
#ifdef USE_ETHERNET_IP_STATE_LISTENERS
|
||||||
|
class IPAddressEthernetInfo final : public Component,
|
||||||
|
public text_sensor::TextSensor,
|
||||||
|
public ethernet::EthernetIPStateListener {
|
||||||
public:
|
public:
|
||||||
void update() override {
|
void setup() override;
|
||||||
auto ips = ethernet::global_eth_component->get_ip_addresses();
|
|
||||||
if (ips != this->last_ips_) {
|
|
||||||
this->last_ips_ = ips;
|
|
||||||
char buf[network::IP_ADDRESS_BUFFER_SIZE];
|
|
||||||
ips[0].str_to(buf);
|
|
||||||
this->publish_state(buf);
|
|
||||||
uint8_t sensor = 0;
|
|
||||||
for (auto &ip : ips) {
|
|
||||||
if (ip.is_set()) {
|
|
||||||
if (this->ip_sensors_[sensor] != nullptr) {
|
|
||||||
ip.str_to(buf);
|
|
||||||
this->ip_sensors_[sensor]->publish_state(buf);
|
|
||||||
}
|
|
||||||
sensor++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
float get_setup_priority() const override { return setup_priority::ETHERNET; }
|
|
||||||
void dump_config() override;
|
void dump_config() override;
|
||||||
void add_ip_sensors(uint8_t index, text_sensor::TextSensor *s) { this->ip_sensors_[index] = s; }
|
void add_ip_sensors(uint8_t index, text_sensor::TextSensor *s) { this->ip_sensors_[index] = s; }
|
||||||
|
|
||||||
|
// EthernetIPStateListener interface
|
||||||
|
void on_ip_state(const network::IPAddresses &ips, const network::IPAddress &dns1,
|
||||||
|
const network::IPAddress &dns2) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
network::IPAddresses last_ips_;
|
std::array<text_sensor::TextSensor *, 5> ip_sensors_{};
|
||||||
std::array<text_sensor::TextSensor *, 5> ip_sensors_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class DNSAddressEthernetInfo : public PollingComponent, public text_sensor::TextSensor {
|
class DNSAddressEthernetInfo final : public Component,
|
||||||
|
public text_sensor::TextSensor,
|
||||||
|
public ethernet::EthernetIPStateListener {
|
||||||
public:
|
public:
|
||||||
void update() override {
|
void setup() override;
|
||||||
auto dns1 = ethernet::global_eth_component->get_dns_address(0);
|
|
||||||
auto dns2 = ethernet::global_eth_component->get_dns_address(1);
|
|
||||||
|
|
||||||
if (dns1 != this->last_dns1_ || dns2 != this->last_dns2_) {
|
|
||||||
this->last_dns1_ = dns1;
|
|
||||||
this->last_dns2_ = dns2;
|
|
||||||
// IP_ADDRESS_BUFFER_SIZE (40) = max IP (39) + null; space reuses first null's slot
|
|
||||||
char buf[network::IP_ADDRESS_BUFFER_SIZE * 2];
|
|
||||||
dns1.str_to(buf);
|
|
||||||
size_t len1 = strlen(buf);
|
|
||||||
buf[len1] = ' ';
|
|
||||||
dns2.str_to(buf + len1 + 1);
|
|
||||||
this->publish_state(buf);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
float get_setup_priority() const override { return setup_priority::ETHERNET; }
|
|
||||||
void dump_config() override;
|
void dump_config() override;
|
||||||
|
|
||||||
protected:
|
// EthernetIPStateListener interface
|
||||||
network::IPAddress last_dns1_;
|
void on_ip_state(const network::IPAddresses &ips, const network::IPAddress &dns1,
|
||||||
network::IPAddress last_dns2_;
|
const network::IPAddress &dns2) override;
|
||||||
};
|
};
|
||||||
|
#endif // USE_ETHERNET_IP_STATE_LISTENERS
|
||||||
|
|
||||||
class MACAddressEthernetInfo : public Component, public text_sensor::TextSensor {
|
class MACAddressEthernetInfo final : public Component, public text_sensor::TextSensor {
|
||||||
public:
|
public:
|
||||||
void setup() override {
|
void setup() override {
|
||||||
char buf[MAC_ADDRESS_PRETTY_BUFFER_SIZE];
|
char buf[MAC_ADDRESS_PRETTY_BUFFER_SIZE];
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import esphome.codegen as cg
|
import esphome.codegen as cg
|
||||||
from esphome.components import text_sensor
|
from esphome.components import ethernet, text_sensor
|
||||||
import esphome.config_validation as cv
|
import esphome.config_validation as cv
|
||||||
from esphome.const import (
|
from esphome.const import (
|
||||||
CONF_DNS_ADDRESS,
|
CONF_DNS_ADDRESS,
|
||||||
@@ -13,24 +13,22 @@ DEPENDENCIES = ["ethernet"]
|
|||||||
ethernet_info_ns = cg.esphome_ns.namespace("ethernet_info")
|
ethernet_info_ns = cg.esphome_ns.namespace("ethernet_info")
|
||||||
|
|
||||||
IPAddressEthernetInfo = ethernet_info_ns.class_(
|
IPAddressEthernetInfo = ethernet_info_ns.class_(
|
||||||
"IPAddressEthernetInfo", text_sensor.TextSensor, cg.PollingComponent
|
"IPAddressEthernetInfo", text_sensor.TextSensor, cg.Component
|
||||||
)
|
)
|
||||||
|
|
||||||
DNSAddressEthernetInfo = ethernet_info_ns.class_(
|
DNSAddressEthernetInfo = ethernet_info_ns.class_(
|
||||||
"DNSAddressEthernetInfo", text_sensor.TextSensor, cg.PollingComponent
|
"DNSAddressEthernetInfo", text_sensor.TextSensor, cg.Component
|
||||||
)
|
)
|
||||||
|
|
||||||
MACAddressEthernetInfo = ethernet_info_ns.class_(
|
MACAddressEthernetInfo = ethernet_info_ns.class_(
|
||||||
"MACAddressEthernetInfo", text_sensor.TextSensor, cg.PollingComponent
|
"MACAddressEthernetInfo", text_sensor.TextSensor, cg.Component
|
||||||
)
|
)
|
||||||
|
|
||||||
CONFIG_SCHEMA = cv.Schema(
|
CONFIG_SCHEMA = cv.Schema(
|
||||||
{
|
{
|
||||||
cv.Optional(CONF_IP_ADDRESS): text_sensor.text_sensor_schema(
|
cv.Optional(CONF_IP_ADDRESS): text_sensor.text_sensor_schema(
|
||||||
IPAddressEthernetInfo, entity_category=ENTITY_CATEGORY_DIAGNOSTIC
|
IPAddressEthernetInfo, entity_category=ENTITY_CATEGORY_DIAGNOSTIC
|
||||||
)
|
).extend(
|
||||||
.extend(cv.polling_component_schema("1s"))
|
|
||||||
.extend(
|
|
||||||
{
|
{
|
||||||
cv.Optional(f"address_{x}"): text_sensor.text_sensor_schema(
|
cv.Optional(f"address_{x}"): text_sensor.text_sensor_schema(
|
||||||
entity_category=ENTITY_CATEGORY_DIAGNOSTIC,
|
entity_category=ENTITY_CATEGORY_DIAGNOSTIC,
|
||||||
@@ -40,7 +38,7 @@ CONFIG_SCHEMA = cv.Schema(
|
|||||||
),
|
),
|
||||||
cv.Optional(CONF_DNS_ADDRESS): text_sensor.text_sensor_schema(
|
cv.Optional(CONF_DNS_ADDRESS): text_sensor.text_sensor_schema(
|
||||||
DNSAddressEthernetInfo, entity_category=ENTITY_CATEGORY_DIAGNOSTIC
|
DNSAddressEthernetInfo, entity_category=ENTITY_CATEGORY_DIAGNOSTIC
|
||||||
).extend(cv.polling_component_schema("1s")),
|
),
|
||||||
cv.Optional(CONF_MAC_ADDRESS): text_sensor.text_sensor_schema(
|
cv.Optional(CONF_MAC_ADDRESS): text_sensor.text_sensor_schema(
|
||||||
MACAddressEthernetInfo, entity_category=ENTITY_CATEGORY_DIAGNOSTIC
|
MACAddressEthernetInfo, entity_category=ENTITY_CATEGORY_DIAGNOSTIC
|
||||||
),
|
),
|
||||||
@@ -49,6 +47,12 @@ CONFIG_SCHEMA = cv.Schema(
|
|||||||
|
|
||||||
|
|
||||||
async def to_code(config):
|
async def to_code(config):
|
||||||
|
# Request Ethernet IP state listener slots - one per sensor type
|
||||||
|
if CONF_IP_ADDRESS in config:
|
||||||
|
ethernet.request_ethernet_ip_state_listener()
|
||||||
|
if CONF_DNS_ADDRESS in config:
|
||||||
|
ethernet.request_ethernet_ip_state_listener()
|
||||||
|
|
||||||
if conf := config.get(CONF_IP_ADDRESS):
|
if conf := config.get(CONF_IP_ADDRESS):
|
||||||
ip_info = await text_sensor.new_text_sensor(config[CONF_IP_ADDRESS])
|
ip_info = await text_sensor.new_text_sensor(config[CONF_IP_ADDRESS])
|
||||||
await cg.register_component(ip_info, config[CONF_IP_ADDRESS])
|
await cg.register_component(ip_info, config[CONF_IP_ADDRESS])
|
||||||
@@ -57,8 +61,8 @@ async def to_code(config):
|
|||||||
sens = await text_sensor.new_text_sensor(sensor_conf)
|
sens = await text_sensor.new_text_sensor(sensor_conf)
|
||||||
cg.add(ip_info.add_ip_sensors(x, sens))
|
cg.add(ip_info.add_ip_sensors(x, sens))
|
||||||
if conf := config.get(CONF_DNS_ADDRESS):
|
if conf := config.get(CONF_DNS_ADDRESS):
|
||||||
dns_info = await text_sensor.new_text_sensor(config[CONF_DNS_ADDRESS])
|
dns_info = await text_sensor.new_text_sensor(conf)
|
||||||
await cg.register_component(dns_info, config[CONF_DNS_ADDRESS])
|
await cg.register_component(dns_info, conf)
|
||||||
if conf := config.get(CONF_MAC_ADDRESS):
|
if conf := config.get(CONF_MAC_ADDRESS):
|
||||||
mac_info = await text_sensor.new_text_sensor(config[CONF_MAC_ADDRESS])
|
mac_info = await text_sensor.new_text_sensor(conf)
|
||||||
await cg.register_component(mac_info, config[CONF_MAC_ADDRESS])
|
await cg.register_component(mac_info, conf)
|
||||||
|
|||||||
@@ -238,6 +238,8 @@
|
|||||||
#define USE_ETHERNET
|
#define USE_ETHERNET
|
||||||
#define USE_ETHERNET_KSZ8081
|
#define USE_ETHERNET_KSZ8081
|
||||||
#define USE_ETHERNET_MANUAL_IP
|
#define USE_ETHERNET_MANUAL_IP
|
||||||
|
#define USE_ETHERNET_IP_STATE_LISTENERS
|
||||||
|
#define ESPHOME_ETHERNET_IP_STATE_LISTENERS 2
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef USE_ESP32
|
#ifdef USE_ESP32
|
||||||
|
|||||||
Reference in New Issue
Block a user