[network] Add Zephyr IPv6 networking support for nRF52 (#16336)

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: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Co-authored-by: tomaszduda23 <tomaszduda23@gmail.com>
This commit is contained in:
Ardumine
2026-05-27 08:43:38 +01:00
committed by GitHub
parent 8d19c55be2
commit 7463a15c7e
18 changed files with 99 additions and 23 deletions

View File

@@ -52,6 +52,8 @@ class E131Component : public esphome::Component {
if (!this->udp_.parsePacket()) if (!this->udp_.parsePacket())
return -1; return -1;
return this->udp_.read(buf, len); return this->udp_.read(buf, len);
#else
return -1;
#endif #endif
} }
bool packet_(const uint8_t *data, size_t len, int &universe, E131Packet &packet); bool packet_(const uint8_t *data, size_t len, int &universe, E131Packet &packet);

View File

@@ -280,5 +280,6 @@ FILTER_SOURCE_FILES = filter_source_files_from_platform(
PlatformFramework.RTL87XX_ARDUINO, PlatformFramework.RTL87XX_ARDUINO,
PlatformFramework.LN882X_ARDUINO, PlatformFramework.LN882X_ARDUINO,
}, },
"mdns_zephyr.cpp": {PlatformFramework.NRF52_ZEPHYR},
} }
) )

View File

@@ -0,0 +1,17 @@
#include "esphome/core/defines.h"
#if defined(USE_ZEPHYR) && defined(USE_MDNS)
#include "mdns_component.h"
#include "esphome/core/log.h"
namespace esphome::mdns {
static const char *const TAG = "mdns.zephyr";
void MDNSComponent::setup() { ESP_LOGW(TAG, "mDNS is not implemented for Zephyr"); }
void MDNSComponent::on_shutdown() {}
} // namespace esphome::mdns
#endif // USE_ZEPHYR && USE_MDNS

View File

@@ -4,6 +4,7 @@ import logging
import esphome.codegen as cg import esphome.codegen as cg
from esphome.components.esp32 import add_idf_sdkconfig_option from esphome.components.esp32 import add_idf_sdkconfig_option
from esphome.components.psram import is_guaranteed as psram_is_guaranteed from esphome.components.psram import is_guaranteed as psram_is_guaranteed
from esphome.components.zephyr import zephyr_add_prj_conf
import esphome.config_validation as cv import esphome.config_validation as cv
from esphome.const import CONF_ENABLE_IPV6, CONF_ID, CONF_MIN_IPV6_ADDR_COUNT from esphome.const import CONF_ENABLE_IPV6, CONF_ID, CONF_MIN_IPV6_ADDR_COUNT
from esphome.core import CORE, CoroPriority, coroutine_with_priority from esphome.core import CORE, CoroPriority, coroutine_with_priority
@@ -117,6 +118,7 @@ CONFIG_SCHEMA = cv.Schema(
esp8266=False, esp8266=False,
host=False, host=False,
rp2040=False, rp2040=False,
nrf52=True,
): cv.All( ): cv.All(
cv.boolean, cv.boolean,
cv.Any( cv.Any(
@@ -127,6 +129,7 @@ CONFIG_SCHEMA = cv.Schema(
esp8266_arduino=cv.Version(0, 0, 0), esp8266_arduino=cv.Version(0, 0, 0),
host=cv.Version(0, 0, 0), host=cv.Version(0, 0, 0),
rp2040_arduino=cv.Version(0, 0, 0), rp2040_arduino=cv.Version(0, 0, 0),
nrf52_zephyr=cv.Version(0, 0, 0),
), ),
cv.boolean_false, cv.boolean_false,
), ),
@@ -205,6 +208,19 @@ async def to_code(config):
add_idf_sdkconfig_option("CONFIG_LWIP_TCP_RECVMBOX_SIZE", 64) add_idf_sdkconfig_option("CONFIG_LWIP_TCP_RECVMBOX_SIZE", 64)
add_idf_sdkconfig_option("CONFIG_LWIP_TCPIP_RECVMBOX_SIZE", 64) add_idf_sdkconfig_option("CONFIG_LWIP_TCPIP_RECVMBOX_SIZE", 64)
if CORE.is_nrf52:
enable_ipv6 = config.get(CONF_ENABLE_IPV6, True)
if not enable_ipv6:
_LOGGER.warning(
"IPv6 cannot be disabled on nRF52 because the Zephyr IPAddress implementation is IPv6-only. "
"Forcing CONFIG_NET_IPV6=y."
)
config[CONF_ENABLE_IPV6] = True
zephyr_add_prj_conf("NETWORKING", True)
zephyr_add_prj_conf("NET_IPV6", True)
zephyr_add_prj_conf("NET_TCP", True)
zephyr_add_prj_conf("NET_UDP", True)
if (enable_ipv6 := config.get(CONF_ENABLE_IPV6, None)) is not None: if (enable_ipv6 := config.get(CONF_ENABLE_IPV6, None)) is not None:
cg.add_define("USE_NETWORK_IPV6", enable_ipv6) cg.add_define("USE_NETWORK_IPV6", enable_ipv6)
if enable_ipv6: if enable_ipv6:

View File

@@ -5,13 +5,13 @@
#include <string> #include <string>
#include <cstdio> #include <cstdio>
#include <array> #include <array>
#include <cstring>
#include "esphome/core/helpers.h" #include "esphome/core/helpers.h"
#include "esphome/core/macros.h" #include "esphome/core/macros.h"
#if defined(USE_ESP32) || defined(USE_LIBRETINY) || USE_ARDUINO_VERSION_CODE > VERSION_CODE(3, 0, 0) #if defined(USE_ESP32) || defined(USE_LIBRETINY) || USE_ARDUINO_VERSION_CODE > VERSION_CODE(3, 0, 0)
#include <lwip/ip_addr.h> #include <lwip/ip_addr.h>
#endif #endif
#if USE_ARDUINO #if USE_ARDUINO
#include <Arduino.h> #include <Arduino.h>
#include <IPAddress.h> #include <IPAddress.h>
@@ -24,6 +24,14 @@ using ip4_addr_t = in_addr;
#define ipaddr_aton(x, y) inet_aton((x), (y)) #define ipaddr_aton(x, y) inet_aton((x), (y))
#endif #endif
#ifdef USE_ZEPHYR
#include <zephyr/net/net_ip.h>
#include <zephyr/net/socket.h>
#include <zephyr/posix/arpa/inet.h>
using ip_addr_t = struct in6_addr;
static inline int ipaddr_aton(const char *cp, ip_addr_t *addr) { return inet_pton(AF_INET6, cp, addr) == 1 ? 1 : 0; }
#endif
#if USE_ESP32_FRAMEWORK_ARDUINO #if USE_ESP32_FRAMEWORK_ARDUINO
#define arduino_ns Arduino_h #define arduino_ns Arduino_h
#elif USE_LIBRETINY #elif USE_LIBRETINY
@@ -33,7 +41,6 @@ using ip4_addr_t = in_addr;
#endif #endif
#ifdef USE_ESP32 #ifdef USE_ESP32
#include <cstring>
#include <esp_netif.h> #include <esp_netif.h>
#endif #endif
@@ -52,7 +59,36 @@ inline void lowercase_ip_str(char *buf) {
struct IPAddress { struct IPAddress {
public: public:
#ifdef USE_HOST #ifdef USE_ZEPHYR
IPAddress() { memset(&ip_addr_, 0, sizeof(ip_addr_)); }
IPAddress(const std::string &in_address) : ip_addr_{} { ipaddr_aton(in_address.c_str(), &ip_addr_); }
IPAddress(const struct in6_addr *other_ip) { ip_addr_ = *other_ip; }
IPAddress(const struct sockaddr_in6 *addr) { ip_addr_ = addr->sin6_addr; }
operator struct in6_addr() const { return ip_addr_; }
bool is_set() const { return !net_ipv6_is_addr_unspecified(&ip_addr_); }
bool is_ip4() const { return false; }
bool is_ip6() const { return this->is_set(); }
bool is_multicast() const { return net_ipv6_is_addr_mcast(&ip_addr_); }
// Remove before 2026.8.0
ESPDEPRECATED(
"str() is deprecated: use 'char buf[IP_ADDRESS_BUFFER_SIZE]; ip.str_to(buf);' instead. Removed in 2026.8.0",
"2026.2.0")
std::string str() const {
char buf[IP_ADDRESS_BUFFER_SIZE];
this->str_to(buf);
return buf;
}
char *str_to(char *buf) const {
if (inet_ntop(AF_INET6, &ip_addr_, buf, IP_ADDRESS_BUFFER_SIZE) == nullptr)
buf[0] = '\0';
return buf;
}
bool operator==(const IPAddress &other) const { return net_ipv6_addr_cmp(&ip_addr_, &other.ip_addr_); }
bool operator!=(const IPAddress &other) const { return !net_ipv6_addr_cmp(&ip_addr_, &other.ip_addr_); }
#elif defined(USE_HOST)
IPAddress() { ip_addr_.s_addr = 0; } IPAddress() { ip_addr_.s_addr = 0; }
IPAddress(uint8_t first, uint8_t second, uint8_t third, uint8_t fourth) { IPAddress(uint8_t first, uint8_t second, uint8_t third, uint8_t fourth) {
this->ip_addr_.s_addr = htonl((first << 24) | (second << 16) | (third << 8) | fourth); this->ip_addr_.s_addr = htonl((first << 24) | (second << 16) | (third << 8) | fourth);

View File

@@ -1,6 +1,6 @@
#pragma once #pragma once
#include "esphome/core/defines.h" #include "esphome/core/defines.h"
#ifdef USE_NETWORK #if defined(USE_NETWORK) && !defined(USE_ZEPHYR)
#include <map> #include <map>
#include <utility> #include <utility>
@@ -219,4 +219,4 @@ class PrometheusHandler : public AsyncWebHandler, public Component {
} // namespace esphome::prometheus } // namespace esphome::prometheus
#endif #endif // USE_NETWORK && !USE_ZEPHYR

View File

@@ -2,7 +2,7 @@
#include "statsd.h" #include "statsd.h"
#ifdef USE_NETWORK #if defined(USE_NETWORK) && !defined(USE_ZEPHYR)
namespace esphome::statsd { namespace esphome::statsd {

View File

@@ -3,7 +3,7 @@
#include <vector> #include <vector>
#include "esphome/core/defines.h" #include "esphome/core/defines.h"
#ifdef USE_NETWORK #if defined(USE_NETWORK) && !defined(USE_ZEPHYR)
#include "esphome/core/component.h" #include "esphome/core/component.h"
#include "esphome/components/socket/socket.h" #include "esphome/components/socket/socket.h"
#include "esphome/components/network/ip_address.h" #include "esphome/components/network/ip_address.h"
@@ -83,4 +83,4 @@ class StatsdComponent : public PollingComponent {
} // namespace esphome::statsd } // namespace esphome::statsd
#endif #endif // USE_NETWORK && !USE_ZEPHYR

View File

@@ -51,7 +51,7 @@ class SX1509Component : public Component,
this->cols_ = cols; this->cols_ = cols;
this->has_keypad_ = true; this->has_keypad_ = true;
}; };
void set_keys(std::string keys) { this->keys_ = std::move(keys); }; void set_keys(std::string keys) { this->keys_ = std::move(keys); }; // NOLINT(performance-unnecessary-value-param)
void set_sleep_time(uint16_t sleep_time) { this->sleep_time_ = sleep_time; }; void set_sleep_time(uint16_t sleep_time) { this->sleep_time_ = sleep_time; };
void set_scan_time(uint8_t scan_time) { this->scan_time_ = scan_time; }; void set_scan_time(uint8_t scan_time) { this->scan_time_ = scan_time; };
void set_debounce_time(uint8_t debounce_time = 1) { this->debounce_time_ = debounce_time; }; void set_debounce_time(uint8_t debounce_time = 1) { this->debounce_time_ = debounce_time; };
@@ -62,10 +62,10 @@ class SX1509Component : public Component,
void setup_led_driver(uint8_t pin); void setup_led_driver(uint8_t pin);
protected: protected:
// Virtual methods from CachedGpioExpander // Virtual methods from CachedGpioExpander — names come from base class
bool digital_read_hw(uint8_t pin) override; bool digital_read_hw(uint8_t pin) override; // NOLINT(readability-identifier-naming)
bool digital_read_cache(uint8_t pin) override; bool digital_read_cache(uint8_t pin) override; // NOLINT(readability-identifier-naming)
void digital_write_hw(uint8_t pin, bool value) override; void digital_write_hw(uint8_t pin, bool value) override; // NOLINT(readability-identifier-naming)
uint32_t clk_x_ = 2000000; uint32_t clk_x_ = 2000000;
uint8_t frequency_ = 0; uint8_t frequency_ = 0;

View File

@@ -27,9 +27,10 @@ class TCA9555Component : public Component,
protected: protected:
static void IRAM_ATTR gpio_intr(TCA9555Component *arg); static void IRAM_ATTR gpio_intr(TCA9555Component *arg);
bool digital_read_hw(uint8_t pin) override; // Virtual methods from GpioExpander base class — names come from base
bool digital_read_cache(uint8_t pin) override; bool digital_read_hw(uint8_t pin) override; // NOLINT(readability-identifier-naming)
void digital_write_hw(uint8_t pin, bool value) override; bool digital_read_cache(uint8_t pin) override; // NOLINT(readability-identifier-naming)
void digital_write_hw(uint8_t pin, bool value) override; // NOLINT(readability-identifier-naming)
/// Mask for the pin mode - 1 means output, 0 means input /// Mask for the pin mode - 1 means output, 0 means input
uint16_t mode_mask_{0x00}; uint16_t mode_mask_{0x00};

View File

@@ -1,5 +1,5 @@
#include "wake_on_lan.h" #include "wake_on_lan.h"
#ifdef USE_NETWORK #if defined(USE_NETWORK) && !defined(USE_ZEPHYR)
#include "esphome/core/log.h" #include "esphome/core/log.h"
#include "esphome/components/network/ip_address.h" #include "esphome/components/network/ip_address.h"
#include "esphome/components/network/util.h" #include "esphome/components/network/util.h"

View File

@@ -1,6 +1,6 @@
#pragma once #pragma once
#include "esphome/core/defines.h" #include "esphome/core/defines.h"
#ifdef USE_NETWORK #if defined(USE_NETWORK) && !defined(USE_ZEPHYR)
#include "esphome/components/button/button.h" #include "esphome/components/button/button.h"
#include "esphome/core/component.h" #include "esphome/core/component.h"
#if defined(USE_SOCKET_IMPL_BSD_SOCKETS) || defined(USE_SOCKET_IMPL_LWIP_SOCKETS) #if defined(USE_SOCKET_IMPL_BSD_SOCKETS) || defined(USE_SOCKET_IMPL_LWIP_SOCKETS)
@@ -32,4 +32,4 @@ class WakeOnLanButton : public button::Button, public Component {
} // namespace esphome::wake_on_lan } // namespace esphome::wake_on_lan
#endif #endif // USE_NETWORK && !USE_ZEPHYR

View File

@@ -1,5 +1,5 @@
#include "web_server_base.h" #include "web_server_base.h"
#ifdef USE_NETWORK #if defined(USE_NETWORK) && !defined(USE_ZEPHYR)
namespace esphome::web_server_base { namespace esphome::web_server_base {

View File

@@ -1,6 +1,6 @@
#pragma once #pragma once
#include "esphome/core/defines.h" #include "esphome/core/defines.h"
#ifdef USE_NETWORK #if defined(USE_NETWORK) && !defined(USE_ZEPHYR)
#include <utility> #include <utility>
#include <vector> #include <vector>
@@ -145,4 +145,4 @@ class WebServerBase {
}; };
} // namespace esphome::web_server_base } // namespace esphome::web_server_base
#endif #endif // USE_NETWORK && !USE_ZEPHYR

View File

@@ -133,6 +133,7 @@
#define SNTP_SERVER_COUNT 3 #define SNTP_SERVER_COUNT 3
#define USE_MEDIA_PLAYER #define USE_MEDIA_PLAYER
#define USE_MEDIA_SOURCE #define USE_MEDIA_SOURCE
#define USE_NETWORK
#define USE_NEXTION_COMMAND_SPACING #define USE_NEXTION_COMMAND_SPACING
#define USE_NEXTION_CONF_START_UP_PAGE #define USE_NEXTION_CONF_START_UP_PAGE
#define USE_NEXTION_CONFIG_EXIT_REPARSE_ON_START #define USE_NEXTION_CONFIG_EXIT_REPARSE_ON_START
@@ -202,7 +203,6 @@
#define USE_SHA256 #define USE_SHA256
#define USE_MQTT #define USE_MQTT
#define USE_MQTT_COVER_JSON #define USE_MQTT_COVER_JSON
#define USE_NETWORK
#define USE_RTTTL_FINISHED_PLAYBACK_CALLBACK #define USE_RTTTL_FINISHED_PLAYBACK_CALLBACK
#define USE_RUNTIME_IMAGE_BMP #define USE_RUNTIME_IMAGE_BMP
#define USE_RUNTIME_IMAGE_PNG #define USE_RUNTIME_IMAGE_PNG

View File

@@ -0,0 +1 @@
network:

View File

@@ -0,0 +1 @@
network:

View File

@@ -0,0 +1 @@
network: