feat: add support for W5500 SPI Ethernet in gateway

- Introduced configuration options for wired Ethernet support in Kconfig and sdkconfig.
- Implemented Ethernet initialization and event handling in GatewayNetworkService.
- Enhanced app_main to manage Ethernet alongside Wi-Fi.
- Updated GatewayRuntime to store Ethernet information.
- Modified CMakeLists and include files to accommodate new Ethernet dependencies.
- Ensured backward compatibility by allowing Ethernet initialization failures to be ignored.

Signed-off-by: Tony <tonylu@tony-cloud.com>
This commit is contained in:
Tony
2026-05-12 08:42:10 +08:00
parent 36d10702da
commit 626f86ec4e
10 changed files with 600 additions and 17 deletions
+2 -2
View File
@@ -17,14 +17,14 @@ This folder hosts the native ESP-IDF C++ rewrite of the Lua DALI gateway.
- `gateway_bacnet/`: BACnet/IP server adapter backed by bacnet-stack, including the gateway-owned BACnet bridge model adapter. - `gateway_bacnet/`: BACnet/IP server adapter backed by bacnet-stack, including the gateway-owned BACnet bridge model adapter.
- `gateway_ble/`: NimBLE GATT bridge for BLE transport parity on `FFF1`/`FFF2`/`FFF3`, including raw DALI notifications. - `gateway_ble/`: NimBLE GATT bridge for BLE transport parity on `FFF1`/`FFF2`/`FFF3`, including raw DALI notifications.
- `gateway_controller/`: Lua-compatible gateway command dispatcher, internal scene/group state, and notification fan-out. - `gateway_controller/`: Lua-compatible gateway command dispatcher, internal scene/group state, and notification fan-out.
- `gateway_network/`: HTTP `/info`, `/dali/cmd`, `/led/1`, `/led/0`, `/jq.js`, UDP port `2020` command/notify routing, Wi-Fi STA lifecycle, ESP-Touch smartconfig, setup AP mode, ESP-NOW setup ingress, and BOOT-button Wi-Fi reset for the native gateway. - `gateway_network/`: HTTP `/info`, `/dali/cmd`, `/led/1`, `/led/0`, `/jq.js`, UDP port `2020` command/notify routing, Wi-Fi STA lifecycle, W5500 SPI Ethernet startup/teardown, ESP-Touch smartconfig, setup AP mode, ESP-NOW setup ingress, and BOOT-button Wi-Fi reset for the native gateway.
- `gateway_runtime/`: persistent runtime state, command queueing, and device info services. - `gateway_runtime/`: persistent runtime state, command queueing, and device info services.
- `gateway_485_control/`: optional 485 Lua control bridge for framed `0x28 0x01` commands and `0x22 ... checksum` notifications at `9600 8N1`; disabled by default because UART0 must be moved off the ESP-IDF console first. - `gateway_485_control/`: optional 485 Lua control bridge for framed `0x28 0x01` commands and `0x22 ... checksum` notifications at `9600 8N1`; disabled by default because UART0 must be moved off the ESP-IDF console first.
- `gateway_usb_setup/`: optional USB Serial/JTAG setup bridge; disabled by default so USB remains available for debug at boot. - `gateway_usb_setup/`: optional USB Serial/JTAG setup bridge; disabled by default so USB remains available for debug at boot.
## Current status ## Current status
The native rewrite now wires a shared `gateway_core` bootstrap component, a multi-channel `dali_domain` wrapper over `dali_cpp`, a local vendored `dali` hardware backend from the LuatOS ESP-IDF port with raw receive fan-out, an initial `gateway_runtime` service that provides persistent settings, device info, Lua-compatible command framing helpers, and Lua-style query command deduplication, plus a `gateway_controller` service that starts the gateway command task, dispatches core Lua gateway opcodes, and owns internal scene/group state. The gateway app also includes a `gateway_ble` NimBLE bridge that advertises a Lua-compatible GATT service and forwards `FFF3` framed notifications, incoming `FFF1`/`FFF2`/`FFF3` writes, and native raw DALI frame notifications into the matching raw channel, a `gateway_network` service that provides the native HTTP `/info`, `GET`/`POST /dali/cmd`, `/led/1`, `/led/0`, `/jq.js`, UDP control-plane router on port `2020`, Wi-Fi STA lifecycle, ESP-Touch smartconfig credential provisioning, the Lua-style `LAMMIN_Gateway` setup AP on `192.168.3.1`, ESP-NOW setup ingress for Lua-compatible `connReq`/`connAck`/`echo`/`cmd`/`data`/`uart` packets, native raw DALI frame forwarding back to connected setup peers, and BOOT-button Wi-Fi credential clearing, and an optional `gateway_485_control` bridge that claims UART0 for Lua-compatible framed command ingress plus `0x22` notification egress when the console is moved off UART0. Startup behavior is configured in `main/Kconfig.projbuild`: BLE is enabled by default, Wi-Fi STA, smartconfig, and ESP-NOW setup mode are disabled by default, the built-in USB Serial/JTAG interface stays in debug mode unless the optional USB setup bridge mode is selected, and the UART0 control bridge stays disabled unless the deployment explicitly repurposes UART0 away from the ESP-IDF console. Runtime settings and internal scene/group data are cached in RAM after load, skip unchanged flash writes, and batch Wi-Fi credential commits to reduce flash stalls on ESP32-S3 boards where flash and PSRAM share the SPI bus. The gateway app exposes per-channel PHY selection through `main/Kconfig.projbuild`; each channel can be disabled, bound to the native DALI GPIO HAL, or bound to a UART1/UART2 serial PHY. The checked-in `sdkconfig` is aligned with the app's custom 16 MB partition table so the Wi-Fi/BLE/network-enabled image fits the OTA app slots. The native rewrite now wires a shared `gateway_core` bootstrap component, a multi-channel `dali_domain` wrapper over `dali_cpp`, a local vendored `dali` hardware backend from the LuatOS ESP-IDF port with raw receive fan-out, an initial `gateway_runtime` service that provides persistent settings, device info, Lua-compatible command framing helpers, and Lua-style query command deduplication, plus a `gateway_controller` service that starts the gateway command task, dispatches core Lua gateway opcodes, and owns internal scene/group state. The gateway app also includes a `gateway_ble` NimBLE bridge that advertises a Lua-compatible GATT service and forwards `FFF3` framed notifications, incoming `FFF1`/`FFF2`/`FFF3` writes, and native raw DALI frame notifications into the matching raw channel, a `gateway_network` service that provides the native HTTP `/info`, `GET`/`POST /dali/cmd`, `/led/1`, `/led/0`, `/jq.js`, UDP control-plane router on port `2020`, W5500 SPI Ethernet with DHCP, Wi-Fi STA lifecycle, ESP-Touch smartconfig credential provisioning, the Lua-style `LAMMIN_Gateway` setup AP on `192.168.3.1`, ESP-NOW setup ingress for Lua-compatible `connReq`/`connAck`/`echo`/`cmd`/`data`/`uart` packets, native raw DALI frame forwarding back to connected setup peers, and BOOT-button Wi-Fi credential clearing, and an optional `gateway_485_control` bridge that claims UART0 for Lua-compatible framed command ingress plus `0x22` notification egress when the console is moved off UART0. Startup behavior is configured in `main/Kconfig.projbuild`: BLE and wired Ethernet are enabled by default, W5500 initialization and startup probe failures are ignored by default for boards without populated Ethernet hardware by fully disabling Ethernet for that boot, Wi-Fi STA, smartconfig, and ESP-NOW setup mode are disabled by default, the built-in USB Serial/JTAG interface stays in debug mode unless the optional USB setup bridge mode is selected, and the UART0 control bridge stays disabled unless the deployment explicitly repurposes UART0 away from the ESP-IDF console. Runtime settings and internal scene/group data are cached in RAM after load, skip unchanged flash writes, and batch Wi-Fi credential commits to reduce flash stalls on ESP32-S3 boards where flash and PSRAM share the SPI bus. The gateway app exposes per-channel PHY selection through `main/Kconfig.projbuild`; each channel can be disabled, bound to the native DALI GPIO HAL, or bound to a UART1/UART2 serial PHY. The checked-in `sdkconfig` is aligned with the app's custom 16 MB partition table so the Wi-Fi/BLE/network-enabled image fits the OTA app slots.
## Modbus ## Modbus
+107 -4
View File
@@ -380,6 +380,109 @@ config GATEWAY_SMARTCONFIG_TIMEOUT_SEC
help help
Timeout passed to ESP-IDF smartconfig before provisioning restarts internally. Timeout passed to ESP-IDF smartconfig before provisioning restarts internally.
config GATEWAY_ETHERNET_SUPPORTED
bool "Wired Ethernet gateway transport is supported"
default y
select ETH_USE_SPI_ETHERNET
select ETH_SPI_ETHERNET_W5500
help
Enables the ESP-IDF Ethernet driver path for wired gateway networking. The
native gateway currently provisions a W5500 SPI Ethernet controller and
exposes the same HTTP, UDP, KNXnet/IP, BACnet/IP, Modbus TCP, and cloud
services over the wired netif.
config GATEWAY_START_ETHERNET_ENABLED
bool "Start wired Ethernet at startup"
depends on GATEWAY_ETHERNET_SUPPORTED
default y
help
Starts the configured W5500 Ethernet netif during boot and uses DHCP for
address assignment. Disable this when the board is built without Ethernet
hardware even though the firmware keeps Ethernet support compiled in.
config GATEWAY_ETHERNET_IGNORE_INIT_FAILURE
bool "Ignore wired Ethernet init failures"
depends on GATEWAY_START_ETHERNET_ENABLED
default y
help
Continues booting if the W5500 Ethernet controller is missing, held in
reset, miswired, or otherwise fails ESP-IDF Ethernet driver startup.
Disable this for strict hardware bring-up where Ethernet failure should
abort application startup.
menu "Gateway Wired Ethernet"
depends on GATEWAY_ETHERNET_SUPPORTED
config GATEWAY_ETHERNET_W5500_SPI_HOST
int "W5500 SPI host number"
range 1 2
default 1
help
SPI host used for the W5500 Ethernet controller. On ESP32-S3, host 1 maps
to SPI2 and host 2 maps to SPI3; do not use host 0 because it is reserved
by flash/PSRAM.
config GATEWAY_ETHERNET_W5500_SCLK_GPIO
int "W5500 SPI SCLK GPIO"
range 0 48
default 14
config GATEWAY_ETHERNET_W5500_MOSI_GPIO
int "W5500 SPI MOSI GPIO"
range 0 48
default 13
config GATEWAY_ETHERNET_W5500_MISO_GPIO
int "W5500 SPI MISO GPIO"
range 0 48
default 12
config GATEWAY_ETHERNET_W5500_CS_GPIO
int "W5500 SPI CS GPIO"
range 0 48
default 15
config GATEWAY_ETHERNET_W5500_INT_GPIO
int "W5500 interrupt GPIO"
range -1 48
default 4
help
W5500 interrupt pin. Set to -1 to disable interrupt mode and poll RX
status periodically.
config GATEWAY_ETHERNET_W5500_POLL_PERIOD_MS
int "W5500 polling period ms"
range 0 1000
default 0
help
Polling interval used when the W5500 interrupt pin is disabled. A value of
0 keeps interrupt mode when an interrupt GPIO is configured; if the
interrupt GPIO is -1, the gateway falls back to 100 ms polling.
config GATEWAY_ETHERNET_W5500_CLOCK_MHZ
int "W5500 SPI clock MHz"
range 5 80
default 36
config GATEWAY_ETHERNET_PHY_RESET_GPIO
int "Ethernet PHY reset GPIO"
range -1 48
default 5
help
GPIO used to reset the W5500 PHY. Set to -1 to disable hardware reset.
config GATEWAY_ETHERNET_PHY_ADDR
int "Ethernet PHY address"
range 0 31
default 1
config GATEWAY_ETHERNET_RX_TASK_STACK_SIZE
int "Ethernet RX task stack bytes"
range 2048 8192
default 3072
endmenu
config GATEWAY_BRIDGE_SUPPORTED config GATEWAY_BRIDGE_SUPPORTED
bool "dali_cpp bridge runtime is supported" bool "dali_cpp bridge runtime is supported"
default y default y
@@ -411,7 +514,7 @@ choice GATEWAY_MODBUS_DEFAULT_TRANSPORT
config GATEWAY_MODBUS_DEFAULT_TRANSPORT_TCP config GATEWAY_MODBUS_DEFAULT_TRANSPORT_TCP
bool "TCP server" bool "TCP server"
depends on GATEWAY_WIFI_SUPPORTED depends on GATEWAY_WIFI_SUPPORTED || GATEWAY_ETHERNET_SUPPORTED
config GATEWAY_MODBUS_DEFAULT_TRANSPORT_RTU config GATEWAY_MODBUS_DEFAULT_TRANSPORT_RTU
bool "RTU server on UART" bool "RTU server on UART"
@@ -488,7 +591,7 @@ config GATEWAY_MODBUS_SERIAL_RS485_DE_PIN
config GATEWAY_BACNET_BRIDGE_SUPPORTED config GATEWAY_BACNET_BRIDGE_SUPPORTED
bool "BACnet/IP bridge is supported" bool "BACnet/IP bridge is supported"
depends on GATEWAY_BRIDGE_SUPPORTED && GATEWAY_WIFI_SUPPORTED depends on GATEWAY_BRIDGE_SUPPORTED && (GATEWAY_WIFI_SUPPORTED || GATEWAY_ETHERNET_SUPPORTED)
default n default n
help help
Enables BACnet bridge configuration, binding discovery, and the bacnet-stack BACnet/IP server adapter. Enables BACnet bridge configuration, binding discovery, and the bacnet-stack BACnet/IP server adapter.
@@ -503,7 +606,7 @@ config GATEWAY_START_BACNET_BRIDGE_ENABLED
config GATEWAY_KNX_BRIDGE_SUPPORTED config GATEWAY_KNX_BRIDGE_SUPPORTED
bool "KNX to DALI bridge is supported" bool "KNX to DALI bridge is supported"
depends on GATEWAY_BRIDGE_SUPPORTED && GATEWAY_WIFI_SUPPORTED depends on GATEWAY_BRIDGE_SUPPORTED && (GATEWAY_WIFI_SUPPORTED || GATEWAY_ETHERNET_SUPPORTED)
default n default n
help help
Enables the gateway-owned KNX group-address router and KNXnet/IP TP/IP Enables the gateway-owned KNX group-address router and KNXnet/IP TP/IP
@@ -595,7 +698,7 @@ config GATEWAY_BRIDGE_KNX_TASK_PRIORITY
config GATEWAY_CLOUD_BRIDGE_SUPPORTED config GATEWAY_CLOUD_BRIDGE_SUPPORTED
bool "MQTT cloud bridge is supported" bool "MQTT cloud bridge is supported"
depends on GATEWAY_BRIDGE_SUPPORTED && GATEWAY_WIFI_SUPPORTED depends on GATEWAY_BRIDGE_SUPPORTED && (GATEWAY_WIFI_SUPPORTED || GATEWAY_ETHERNET_SUPPORTED)
default y default y
help help
Enables per-channel DaliCloudBridge provisioning and MQTT downlink execution. Enables per-channel DaliCloudBridge provisioning and MQTT downlink execution.
+89 -8
View File
@@ -96,6 +96,54 @@
#define CONFIG_GATEWAY_SMARTCONFIG_TIMEOUT_SEC 60 #define CONFIG_GATEWAY_SMARTCONFIG_TIMEOUT_SEC 60
#endif #endif
#ifndef CONFIG_GATEWAY_ETHERNET_IGNORE_INIT_FAILURE
#define CONFIG_GATEWAY_ETHERNET_IGNORE_INIT_FAILURE 0
#endif
#ifndef CONFIG_GATEWAY_ETHERNET_W5500_SPI_HOST
#define CONFIG_GATEWAY_ETHERNET_W5500_SPI_HOST 1
#endif
#ifndef CONFIG_GATEWAY_ETHERNET_W5500_SCLK_GPIO
#define CONFIG_GATEWAY_ETHERNET_W5500_SCLK_GPIO 14
#endif
#ifndef CONFIG_GATEWAY_ETHERNET_W5500_MOSI_GPIO
#define CONFIG_GATEWAY_ETHERNET_W5500_MOSI_GPIO 13
#endif
#ifndef CONFIG_GATEWAY_ETHERNET_W5500_MISO_GPIO
#define CONFIG_GATEWAY_ETHERNET_W5500_MISO_GPIO 12
#endif
#ifndef CONFIG_GATEWAY_ETHERNET_W5500_CS_GPIO
#define CONFIG_GATEWAY_ETHERNET_W5500_CS_GPIO 15
#endif
#ifndef CONFIG_GATEWAY_ETHERNET_W5500_INT_GPIO
#define CONFIG_GATEWAY_ETHERNET_W5500_INT_GPIO 4
#endif
#ifndef CONFIG_GATEWAY_ETHERNET_W5500_POLL_PERIOD_MS
#define CONFIG_GATEWAY_ETHERNET_W5500_POLL_PERIOD_MS 0
#endif
#ifndef CONFIG_GATEWAY_ETHERNET_W5500_CLOCK_MHZ
#define CONFIG_GATEWAY_ETHERNET_W5500_CLOCK_MHZ 36
#endif
#ifndef CONFIG_GATEWAY_ETHERNET_PHY_RESET_GPIO
#define CONFIG_GATEWAY_ETHERNET_PHY_RESET_GPIO 5
#endif
#ifndef CONFIG_GATEWAY_ETHERNET_PHY_ADDR
#define CONFIG_GATEWAY_ETHERNET_PHY_ADDR 1
#endif
#ifndef CONFIG_GATEWAY_ETHERNET_RX_TASK_STACK_SIZE
#define CONFIG_GATEWAY_ETHERNET_RX_TASK_STACK_SIZE 3072
#endif
#ifndef CONFIG_GATEWAY_BRIDGE_MODBUS_TASK_STACK_SIZE #ifndef CONFIG_GATEWAY_BRIDGE_MODBUS_TASK_STACK_SIZE
#define CONFIG_GATEWAY_BRIDGE_MODBUS_TASK_STACK_SIZE 6144 #define CONFIG_GATEWAY_BRIDGE_MODBUS_TASK_STACK_SIZE 6144
#endif #endif
@@ -199,12 +247,24 @@ constexpr bool kWifiSupported = true;
constexpr bool kWifiSupported = false; constexpr bool kWifiSupported = false;
#endif #endif
#ifdef CONFIG_GATEWAY_ETHERNET_SUPPORTED
constexpr bool kEthernetSupported = true;
#else
constexpr bool kEthernetSupported = false;
#endif
#ifdef CONFIG_GATEWAY_START_WIFI_STA_ENABLED #ifdef CONFIG_GATEWAY_START_WIFI_STA_ENABLED
constexpr bool kWifiStartupEnabled = true; constexpr bool kWifiStartupEnabled = true;
#else #else
constexpr bool kWifiStartupEnabled = false; constexpr bool kWifiStartupEnabled = false;
#endif #endif
#ifdef CONFIG_GATEWAY_START_ETHERNET_ENABLED
constexpr bool kEthernetStartupEnabled = true;
#else
constexpr bool kEthernetStartupEnabled = false;
#endif
#ifdef CONFIG_GATEWAY_BLE_SUPPORTED #ifdef CONFIG_GATEWAY_BLE_SUPPORTED
constexpr bool kBleSupported = true; constexpr bool kBleSupported = true;
#else #else
@@ -642,7 +702,7 @@ extern "C" void app_main(void) {
"gateway", "gateway",
kWifiSupported, kWifiSupported,
kBleSupported, kBleSupported,
true, kEthernetSupported,
kEspnowSetupSupported, kEspnowSetupSupported,
kUsbSetupStartupEnabled, kUsbSetupStartupEnabled,
}; };
@@ -678,10 +738,11 @@ extern "C" void app_main(void) {
ESP_ERROR_CHECK(s_cache->start()); ESP_ERROR_CHECK(s_cache->start());
gateway::GatewayControllerConfig controller_config; gateway::GatewayControllerConfig controller_config;
const bool network_transport_supported = profile.enable_wifi || profile.enable_eth;
controller_config.setup_supported = true; controller_config.setup_supported = true;
controller_config.ble_supported = profile.enable_ble; controller_config.ble_supported = profile.enable_ble;
controller_config.wifi_supported = profile.enable_wifi; controller_config.wifi_supported = profile.enable_wifi;
controller_config.ip_router_supported = profile.enable_wifi || profile.enable_eth; controller_config.ip_router_supported = network_transport_supported;
controller_config.internal_scene_supported = true; controller_config.internal_scene_supported = true;
controller_config.internal_group_supported = true; controller_config.internal_group_supported = true;
@@ -715,14 +776,14 @@ extern "C" void app_main(void) {
bridge_config.bridge_enabled = true; bridge_config.bridge_enabled = true;
bridge_config.modbus_enabled = kModbusBridgeSupported; bridge_config.modbus_enabled = kModbusBridgeSupported;
bridge_config.modbus_startup_enabled = kModbusBridgeSupported && kModbusBridgeStartupEnabled; bridge_config.modbus_startup_enabled = kModbusBridgeSupported && kModbusBridgeStartupEnabled;
bridge_config.bacnet_enabled = profile.enable_wifi && kBacnetBridgeSupported; bridge_config.bacnet_enabled = network_transport_supported && kBacnetBridgeSupported;
bridge_config.bacnet_startup_enabled = profile.enable_wifi && kBacnetBridgeSupported && bridge_config.bacnet_startup_enabled = network_transport_supported && kBacnetBridgeSupported &&
kBacnetBridgeStartupEnabled; kBacnetBridgeStartupEnabled;
bridge_config.knx_enabled = profile.enable_wifi && kKnxBridgeSupported; bridge_config.knx_enabled = network_transport_supported && kKnxBridgeSupported;
bridge_config.knx_startup_enabled = profile.enable_wifi && kKnxBridgeSupported && bridge_config.knx_startup_enabled = network_transport_supported && kKnxBridgeSupported &&
kKnxBridgeStartupEnabled; kKnxBridgeStartupEnabled;
bridge_config.cloud_enabled = profile.enable_wifi && kCloudBridgeSupported; bridge_config.cloud_enabled = network_transport_supported && kCloudBridgeSupported;
bridge_config.cloud_startup_enabled = profile.enable_wifi && kCloudBridgeSupported && bridge_config.cloud_startup_enabled = network_transport_supported && kCloudBridgeSupported &&
kCloudBridgeStartupEnabled; kCloudBridgeStartupEnabled;
bridge_config.modbus_task_stack_size = bridge_config.modbus_task_stack_size =
static_cast<uint32_t>(CONFIG_GATEWAY_BRIDGE_MODBUS_TASK_STACK_SIZE); static_cast<uint32_t>(CONFIG_GATEWAY_BRIDGE_MODBUS_TASK_STACK_SIZE);
@@ -796,6 +857,12 @@ extern "C" void app_main(void) {
if (profile.enable_wifi || profile.enable_eth) { if (profile.enable_wifi || profile.enable_eth) {
gateway::GatewayNetworkServiceConfig network_config; gateway::GatewayNetworkServiceConfig network_config;
network_config.wifi_enabled = profile.enable_wifi && kWifiStartupEnabled; network_config.wifi_enabled = profile.enable_wifi && kWifiStartupEnabled;
network_config.ethernet_enabled = profile.enable_eth && kEthernetStartupEnabled;
#if CONFIG_GATEWAY_ETHERNET_IGNORE_INIT_FAILURE
network_config.ethernet_ignore_init_failure = true;
#else
network_config.ethernet_ignore_init_failure = false;
#endif
network_config.espnow_setup_enabled = profile.enable_espnow; network_config.espnow_setup_enabled = profile.enable_espnow;
network_config.espnow_setup_startup_enabled = network_config.espnow_setup_startup_enabled =
profile.enable_espnow && kEspnowSetupStartupEnabled; profile.enable_espnow && kEspnowSetupStartupEnabled;
@@ -815,6 +882,20 @@ extern "C" void app_main(void) {
#endif #endif
network_config.http_port = static_cast<uint16_t>(CONFIG_GATEWAY_NETWORK_HTTP_PORT); network_config.http_port = static_cast<uint16_t>(CONFIG_GATEWAY_NETWORK_HTTP_PORT);
network_config.udp_port = static_cast<uint16_t>(CONFIG_GATEWAY_NETWORK_UDP_PORT); network_config.udp_port = static_cast<uint16_t>(CONFIG_GATEWAY_NETWORK_UDP_PORT);
network_config.ethernet_spi_host = CONFIG_GATEWAY_ETHERNET_W5500_SPI_HOST;
network_config.ethernet_spi_sclk_gpio = CONFIG_GATEWAY_ETHERNET_W5500_SCLK_GPIO;
network_config.ethernet_spi_mosi_gpio = CONFIG_GATEWAY_ETHERNET_W5500_MOSI_GPIO;
network_config.ethernet_spi_miso_gpio = CONFIG_GATEWAY_ETHERNET_W5500_MISO_GPIO;
network_config.ethernet_spi_cs_gpio = CONFIG_GATEWAY_ETHERNET_W5500_CS_GPIO;
network_config.ethernet_spi_int_gpio = CONFIG_GATEWAY_ETHERNET_W5500_INT_GPIO;
network_config.ethernet_poll_period_ms =
static_cast<uint32_t>(CONFIG_GATEWAY_ETHERNET_W5500_POLL_PERIOD_MS);
network_config.ethernet_spi_clock_mhz =
static_cast<uint8_t>(CONFIG_GATEWAY_ETHERNET_W5500_CLOCK_MHZ);
network_config.ethernet_phy_reset_gpio = CONFIG_GATEWAY_ETHERNET_PHY_RESET_GPIO;
network_config.ethernet_phy_addr = CONFIG_GATEWAY_ETHERNET_PHY_ADDR;
network_config.ethernet_rx_task_stack_size =
static_cast<uint32_t>(CONFIG_GATEWAY_ETHERNET_RX_TASK_STACK_SIZE);
network_config.status_led_gpio = CONFIG_GATEWAY_STATUS_LED_GPIO; network_config.status_led_gpio = CONFIG_GATEWAY_STATUS_LED_GPIO;
network_config.boot_button_gpio = CONFIG_GATEWAY_BOOT_BUTTON_GPIO; network_config.boot_button_gpio = CONFIG_GATEWAY_BOOT_BUTTON_GPIO;
network_config.boot_button_long_press_ms = CONFIG_GATEWAY_BOOT_BUTTON_LONG_PRESS_MS; network_config.boot_button_long_press_ms = CONFIG_GATEWAY_BOOT_BUTTON_LONG_PRESS_MS;
+20
View File
@@ -656,6 +656,26 @@ CONFIG_GATEWAY_SMARTCONFIG_SUPPORTED=y
# CONFIG_GATEWAY_START_ESPNOW_SETUP_ENABLED is not set # CONFIG_GATEWAY_START_ESPNOW_SETUP_ENABLED is not set
# CONFIG_GATEWAY_START_SMARTCONFIG_ENABLED is not set # CONFIG_GATEWAY_START_SMARTCONFIG_ENABLED is not set
CONFIG_GATEWAY_SMARTCONFIG_TIMEOUT_SEC=60 CONFIG_GATEWAY_SMARTCONFIG_TIMEOUT_SEC=60
CONFIG_GATEWAY_ETHERNET_SUPPORTED=y
CONFIG_GATEWAY_START_ETHERNET_ENABLED=y
CONFIG_GATEWAY_ETHERNET_IGNORE_INIT_FAILURE=y
#
# Gateway Wired Ethernet
#
CONFIG_GATEWAY_ETHERNET_W5500_SPI_HOST=1
CONFIG_GATEWAY_ETHERNET_W5500_SCLK_GPIO=14
CONFIG_GATEWAY_ETHERNET_W5500_MOSI_GPIO=13
CONFIG_GATEWAY_ETHERNET_W5500_MISO_GPIO=12
CONFIG_GATEWAY_ETHERNET_W5500_CS_GPIO=15
CONFIG_GATEWAY_ETHERNET_W5500_INT_GPIO=4
CONFIG_GATEWAY_ETHERNET_W5500_POLL_PERIOD_MS=0
CONFIG_GATEWAY_ETHERNET_W5500_CLOCK_MHZ=36
CONFIG_GATEWAY_ETHERNET_PHY_RESET_GPIO=5
CONFIG_GATEWAY_ETHERNET_PHY_ADDR=1
CONFIG_GATEWAY_ETHERNET_RX_TASK_STACK_SIZE=3072
# end of Gateway Wired Ethernet
CONFIG_GATEWAY_BRIDGE_SUPPORTED=y CONFIG_GATEWAY_BRIDGE_SUPPORTED=y
CONFIG_GATEWAY_MODBUS_BRIDGE_SUPPORTED=y CONFIG_GATEWAY_MODBUS_BRIDGE_SUPPORTED=y
# CONFIG_GATEWAY_START_MODBUS_BRIDGE_ENABLED is not set # CONFIG_GATEWAY_START_MODBUS_BRIDGE_ENABLED is not set
+4 -1
View File
@@ -12,4 +12,7 @@ CONFIG_BT_NIMBLE_ENABLED=y
CONFIG_ETH_ENABLED=y CONFIG_ETH_ENABLED=y
CONFIG_ETH_USE_SPI_ETHERNET=y CONFIG_ETH_USE_SPI_ETHERNET=y
CONFIG_ETH_SPI_ETHERNET_W5500=y CONFIG_ETH_SPI_ETHERNET_W5500=y
CONFIG_GATEWAY_ETHERNET_SUPPORTED=y
CONFIG_GATEWAY_START_ETHERNET_ENABLED=y
CONFIG_GATEWAY_ETHERNET_IGNORE_INIT_FAILURE=y
+1 -1
View File
@@ -1,7 +1,7 @@
idf_component_register( idf_component_register(
SRCS "src/gateway_network.cpp" SRCS "src/gateway_network.cpp"
INCLUDE_DIRS "include" INCLUDE_DIRS "include"
REQUIRES dali_domain esp_event esp_http_server esp_netif esp_wifi freertos gateway_bridge gateway_controller gateway_runtime log lwip espressif__cjson REQUIRES dali_domain esp_driver_gpio esp_driver_spi esp_eth esp_event esp_http_server esp_hw_support esp_netif esp_wifi freertos gateway_bridge gateway_controller gateway_runtime log lwip espressif__cjson
) )
set_property(TARGET ${COMPONENT_LIB} PROPERTY CXX_STANDARD 17) set_property(TARGET ${COMPONENT_LIB} PROPERTY CXX_STANDARD 17)
@@ -8,6 +8,10 @@
#include "esp_err.h" #include "esp_err.h"
#include "esp_event.h" #include "esp_event.h"
#include "esp_eth.h"
#include "esp_eth_mac.h"
#include "esp_eth_netif_glue.h"
#include "esp_eth_phy.h"
#include "esp_http_server.h" #include "esp_http_server.h"
#include "esp_netif.h" #include "esp_netif.h"
#include "esp_now.h" #include "esp_now.h"
@@ -26,6 +30,8 @@ struct DaliRawFrame;
struct GatewayNetworkServiceConfig { struct GatewayNetworkServiceConfig {
bool wifi_enabled{true}; bool wifi_enabled{true};
bool ethernet_enabled{false};
bool ethernet_ignore_init_failure{false};
bool espnow_setup_enabled{true}; bool espnow_setup_enabled{true};
bool espnow_setup_startup_enabled{false}; bool espnow_setup_startup_enabled{false};
bool smartconfig_enabled{true}; bool smartconfig_enabled{true};
@@ -35,6 +41,17 @@ struct GatewayNetworkServiceConfig {
bool udp_enabled{true}; bool udp_enabled{true};
uint16_t http_port{80}; uint16_t http_port{80};
uint16_t udp_port{2020}; uint16_t udp_port{2020};
int ethernet_spi_host{1};
int ethernet_spi_sclk_gpio{14};
int ethernet_spi_mosi_gpio{13};
int ethernet_spi_miso_gpio{12};
int ethernet_spi_cs_gpio{15};
int ethernet_spi_int_gpio{4};
uint32_t ethernet_poll_period_ms{0};
uint8_t ethernet_spi_clock_mhz{36};
int ethernet_phy_reset_gpio{5};
int ethernet_phy_addr{1};
uint32_t ethernet_rx_task_stack_size{3072};
int status_led_gpio{-1}; int status_led_gpio{-1};
bool status_led_active_high{true}; bool status_led_active_high{true};
int boot_button_gpio{-1}; int boot_button_gpio{-1};
@@ -66,12 +83,17 @@ class GatewayNetworkService {
static esp_err_t HandleLedOnGet(httpd_req_t* req); static esp_err_t HandleLedOnGet(httpd_req_t* req);
static esp_err_t HandleLedOffGet(httpd_req_t* req); static esp_err_t HandleLedOffGet(httpd_req_t* req);
static esp_err_t HandleJqJsGet(httpd_req_t* req); static esp_err_t HandleJqJsGet(httpd_req_t* req);
static void HandleEthernetEvent(void* arg, esp_event_base_t event_base, int32_t event_id,
void* event_data);
static void HandleWifiEvent(void* arg, esp_event_base_t event_base, int32_t event_id, static void HandleWifiEvent(void* arg, esp_event_base_t event_base, int32_t event_id,
void* event_data); void* event_data);
static void HandleEspNowReceive(const esp_now_recv_info_t* info, const uint8_t* data, static void HandleEspNowReceive(const esp_now_recv_info_t* info, const uint8_t* data,
int data_len); int data_len);
esp_err_t ensureNetworkStack(); esp_err_t ensureNetworkStack();
esp_err_t startEthernet();
esp_err_t probeEthernetStartup();
void stopEthernet();
esp_err_t startWifi(); esp_err_t startWifi();
esp_err_t startSetupAp(); esp_err_t startSetupAp();
esp_err_t startSmartconfig(); esp_err_t startSmartconfig();
@@ -89,6 +111,7 @@ class GatewayNetworkService {
void bootButtonTaskLoop(); void bootButtonTaskLoop();
void handleGatewayNotification(const std::vector<uint8_t>& frame); void handleGatewayNotification(const std::vector<uint8_t>& frame);
void handleWifiControl(uint8_t mode); void handleWifiControl(uint8_t mode);
void handleEthernetEvent(esp_event_base_t event_base, int32_t event_id, void* event_data);
void handleWifiEvent(esp_event_base_t event_base, int32_t event_id, void* event_data); void handleWifiEvent(esp_event_base_t event_base, int32_t event_id, void* event_data);
void handleEspNowReceive(const esp_now_recv_info_t* info, const uint8_t* data, int data_len); void handleEspNowReceive(const esp_now_recv_info_t* info, const uint8_t* data, int data_len);
void handleSetupUartFrame(int setup_id, const std::vector<uint8_t>& frame); void handleSetupUartFrame(int setup_id, const std::vector<uint8_t>& frame);
@@ -106,8 +129,15 @@ class GatewayNetworkService {
GatewayBridgeService* bridge_service_{nullptr}; GatewayBridgeService* bridge_service_{nullptr};
bool started_{false}; bool started_{false};
httpd_handle_t http_server_{nullptr}; httpd_handle_t http_server_{nullptr};
esp_netif_t* eth_netif_{nullptr};
esp_netif_t* wifi_sta_netif_{nullptr}; esp_netif_t* wifi_sta_netif_{nullptr};
esp_netif_t* wifi_ap_netif_{nullptr}; esp_netif_t* wifi_ap_netif_{nullptr};
esp_eth_handle_t eth_handle_{nullptr};
esp_eth_mac_t* eth_mac_{nullptr};
esp_eth_phy_t* eth_phy_{nullptr};
esp_eth_netif_glue_handle_t eth_glue_{nullptr};
bool ethernet_started_{false};
bool ethernet_event_handlers_registered_{false};
bool wifi_started_{false}; bool wifi_started_{false};
bool wifi_event_handlers_registered_{false}; bool wifi_event_handlers_registered_{false};
bool setup_ap_started_{false}; bool setup_ap_started_{false};
@@ -7,8 +7,12 @@
#include "cJSON.h" #include "cJSON.h"
#include "driver/gpio.h" #include "driver/gpio.h"
#include "driver/spi_master.h"
#include "esp_event.h" #include "esp_event.h"
#include "esp_eth_driver.h"
#include "esp_eth_mac_spi.h"
#include "esp_log.h" #include "esp_log.h"
#include "esp_mac.h"
#include "esp_netif.h" #include "esp_netif.h"
#include "esp_netif_ip_addr.h" #include "esp_netif_ip_addr.h"
#include "esp_smartconfig.h" #include "esp_smartconfig.h"
@@ -268,6 +272,19 @@ esp_err_t GatewayNetworkService::start() {
return err; return err;
} }
if (config_.ethernet_enabled) {
err = startEthernet();
if (err != ESP_OK) {
if (config_.ethernet_ignore_init_failure) {
ESP_LOGW(kTag, "Ethernet init failed; Ethernet is disabled for this boot: %s",
esp_err_to_name(err));
config_.ethernet_enabled = false;
} else {
return err;
}
}
}
if (config_.espnow_setup_startup_enabled) { if (config_.espnow_setup_startup_enabled) {
err = startSetupAp(); err = startSetupAp();
if (err != ESP_OK) { if (err != ESP_OK) {
@@ -320,7 +337,8 @@ esp_err_t GatewayNetworkService::start() {
} }
started_ = true; started_ = true;
ESP_LOGI(kTag, "network service started http=%d udp=%d", config_.http_enabled, ESP_LOGI(kTag, "network service started eth=%d wifi=%d http=%d udp=%d",
config_.ethernet_enabled, config_.wifi_enabled, config_.http_enabled,
config_.udp_enabled); config_.udp_enabled);
return ESP_OK; return ESP_OK;
} }
@@ -341,6 +359,234 @@ esp_err_t GatewayNetworkService::ensureNetworkStack() {
return ESP_OK; return ESP_OK;
} }
esp_err_t GatewayNetworkService::startEthernet() {
if (ethernet_started_) {
return ESP_OK;
}
#if CONFIG_ETH_SPI_ETHERNET_W5500
if (eth_netif_ == nullptr) {
esp_netif_config_t netif_config = ESP_NETIF_DEFAULT_ETH();
eth_netif_ = esp_netif_new(&netif_config);
if (eth_netif_ == nullptr) {
ESP_LOGE(kTag, "failed to create Ethernet netif");
return ESP_ERR_NO_MEM;
}
}
if (!ethernet_event_handlers_registered_) {
esp_err_t err = esp_event_handler_register(ETH_EVENT, ESP_EVENT_ANY_ID,
&GatewayNetworkService::HandleEthernetEvent, this);
if (err != ESP_OK && err != ESP_ERR_INVALID_STATE) {
ESP_LOGE(kTag, "failed to register Ethernet event handler: %s", esp_err_to_name(err));
stopEthernet();
return err;
}
err = esp_event_handler_register(IP_EVENT, IP_EVENT_ETH_GOT_IP,
&GatewayNetworkService::HandleEthernetEvent, this);
if (err != ESP_OK && err != ESP_ERR_INVALID_STATE) {
ESP_LOGE(kTag, "failed to register Ethernet IP event handler: %s", esp_err_to_name(err));
ESP_ERROR_CHECK_WITHOUT_ABORT(esp_event_handler_unregister(
ETH_EVENT, ESP_EVENT_ANY_ID, &GatewayNetworkService::HandleEthernetEvent));
stopEthernet();
return err;
}
ethernet_event_handlers_registered_ = true;
}
if (config_.ethernet_spi_int_gpio >= 0) {
esp_err_t err = gpio_install_isr_service(0);
if (err != ESP_OK && err != ESP_ERR_INVALID_STATE) {
ESP_LOGE(kTag, "failed to install GPIO ISR service for Ethernet: %s", esp_err_to_name(err));
stopEthernet();
return err;
}
}
const auto spi_host = static_cast<spi_host_device_t>(config_.ethernet_spi_host);
spi_bus_config_t bus_config = {};
bus_config.miso_io_num = config_.ethernet_spi_miso_gpio;
bus_config.mosi_io_num = config_.ethernet_spi_mosi_gpio;
bus_config.sclk_io_num = config_.ethernet_spi_sclk_gpio;
bus_config.quadwp_io_num = -1;
bus_config.quadhd_io_num = -1;
esp_err_t err = spi_bus_initialize(spi_host, &bus_config, SPI_DMA_CH_AUTO);
if (err != ESP_OK && err != ESP_ERR_INVALID_STATE) {
ESP_LOGE(kTag, "failed to initialize Ethernet SPI host %d: %s", config_.ethernet_spi_host,
esp_err_to_name(err));
stopEthernet();
return err;
}
spi_device_interface_config_t spi_device_config = {};
spi_device_config.mode = 0;
spi_device_config.clock_speed_hz = static_cast<int>(config_.ethernet_spi_clock_mhz) * 1000 * 1000;
spi_device_config.spics_io_num = config_.ethernet_spi_cs_gpio;
spi_device_config.queue_size = 20;
eth_mac_config_t mac_config = ETH_MAC_DEFAULT_CONFIG();
mac_config.rx_task_stack_size = config_.ethernet_rx_task_stack_size;
eth_phy_config_t phy_config = ETH_PHY_DEFAULT_CONFIG();
phy_config.phy_addr = config_.ethernet_phy_addr;
phy_config.reset_gpio_num = config_.ethernet_phy_reset_gpio;
eth_w5500_config_t w5500_config = ETH_W5500_DEFAULT_CONFIG(spi_host, &spi_device_config);
w5500_config.int_gpio_num = config_.ethernet_spi_int_gpio;
w5500_config.poll_period_ms = config_.ethernet_poll_period_ms;
if (w5500_config.int_gpio_num < 0 && w5500_config.poll_period_ms == 0) {
w5500_config.poll_period_ms = 100;
}
eth_mac_ = esp_eth_mac_new_w5500(&w5500_config, &mac_config);
if (eth_mac_ == nullptr) {
ESP_LOGE(kTag, "failed to create W5500 Ethernet MAC");
stopEthernet();
return ESP_ERR_NO_MEM;
}
eth_phy_ = esp_eth_phy_new_w5500(&phy_config);
if (eth_phy_ == nullptr) {
ESP_LOGE(kTag, "failed to create W5500 Ethernet PHY");
stopEthernet();
return ESP_ERR_NO_MEM;
}
esp_eth_config_t eth_config = ETH_DEFAULT_CONFIG(eth_mac_, eth_phy_);
err = esp_eth_driver_install(&eth_config, &eth_handle_);
if (err != ESP_OK) {
ESP_LOGE(kTag, "failed to install Ethernet driver: %s", esp_err_to_name(err));
stopEthernet();
return err;
}
uint8_t eth_mac[6] = {};
err = esp_read_mac(eth_mac, ESP_MAC_ETH);
if (err == ESP_OK) {
err = esp_eth_ioctl(eth_handle_, ETH_CMD_S_MAC_ADDR, eth_mac);
if (err != ESP_OK) {
ESP_LOGE(kTag, "failed to set Ethernet MAC address: %s", esp_err_to_name(err));
stopEthernet();
return err;
}
EthernetInfo info;
info.mac = MacToHex(eth_mac);
runtime_.setEthernetInfo(std::move(info));
} else {
ESP_LOGW(kTag, "failed to read Ethernet MAC address: %s", esp_err_to_name(err));
}
eth_glue_ = esp_eth_new_netif_glue(eth_handle_);
if (eth_glue_ == nullptr) {
ESP_LOGE(kTag, "failed to create Ethernet netif glue");
stopEthernet();
return ESP_ERR_NO_MEM;
}
err = esp_netif_attach(eth_netif_, eth_glue_);
if (err != ESP_OK) {
ESP_LOGE(kTag, "failed to attach Ethernet netif: %s", esp_err_to_name(err));
stopEthernet();
return err;
}
err = esp_eth_start(eth_handle_);
if (err != ESP_OK) {
ESP_LOGE(kTag, "failed to start Ethernet: %s", esp_err_to_name(err));
stopEthernet();
return err;
}
ethernet_started_ = true;
err = probeEthernetStartup();
if (err != ESP_OK) {
ESP_LOGE(kTag, "Ethernet startup probe failed: %s", esp_err_to_name(err));
stopEthernet();
return err;
}
ESP_LOGI(kTag,
"Ethernet W5500 started spi_host=%d sclk=%d mosi=%d miso=%d cs=%d int=%d reset=%d",
config_.ethernet_spi_host, config_.ethernet_spi_sclk_gpio,
config_.ethernet_spi_mosi_gpio, config_.ethernet_spi_miso_gpio,
config_.ethernet_spi_cs_gpio, config_.ethernet_spi_int_gpio,
config_.ethernet_phy_reset_gpio);
return ESP_OK;
#else
ESP_LOGW(kTag, "Ethernet requested but W5500 support is not enabled in esp-eth");
return ESP_ERR_NOT_SUPPORTED;
#endif
}
esp_err_t GatewayNetworkService::probeEthernetStartup() {
if (eth_handle_ == nullptr || !ethernet_started_) {
return ESP_ERR_INVALID_STATE;
}
esp_err_t err = esp_eth_stop(eth_handle_);
ethernet_started_ = false;
if (err != ESP_OK) {
return err;
}
err = esp_eth_start(eth_handle_);
if (err == ESP_OK) {
ethernet_started_ = true;
}
return err;
}
void GatewayNetworkService::stopEthernet() {
if (ethernet_event_handlers_registered_) {
ESP_ERROR_CHECK_WITHOUT_ABORT(esp_event_handler_unregister(
IP_EVENT, IP_EVENT_ETH_GOT_IP, &GatewayNetworkService::HandleEthernetEvent));
ESP_ERROR_CHECK_WITHOUT_ABORT(esp_event_handler_unregister(
ETH_EVENT, ESP_EVENT_ANY_ID, &GatewayNetworkService::HandleEthernetEvent));
ethernet_event_handlers_registered_ = false;
}
if (eth_handle_ != nullptr) {
const esp_err_t stop_err = esp_eth_stop(eth_handle_);
if (stop_err != ESP_OK && stop_err != ESP_ERR_INVALID_STATE) {
ESP_LOGW(kTag, "failed to stop Ethernet during disable: %s", esp_err_to_name(stop_err));
}
ethernet_started_ = false;
}
if (eth_glue_ != nullptr) {
const esp_err_t glue_err = esp_eth_del_netif_glue(eth_glue_);
if (glue_err != ESP_OK) {
ESP_LOGW(kTag, "failed to delete Ethernet netif glue: %s", esp_err_to_name(glue_err));
} else {
eth_glue_ = nullptr;
}
}
if (eth_handle_ != nullptr) {
const esp_err_t uninstall_err = esp_eth_driver_uninstall(eth_handle_);
if (uninstall_err != ESP_OK) {
ESP_LOGW(kTag, "failed to uninstall Ethernet driver: %s", esp_err_to_name(uninstall_err));
} else {
eth_handle_ = nullptr;
}
}
if (eth_phy_ != nullptr && eth_handle_ == nullptr) {
ESP_ERROR_CHECK_WITHOUT_ABORT(eth_phy_->del(eth_phy_));
eth_phy_ = nullptr;
}
if (eth_mac_ != nullptr && eth_handle_ == nullptr) {
ESP_ERROR_CHECK_WITHOUT_ABORT(eth_mac_->del(eth_mac_));
eth_mac_ = nullptr;
}
if (eth_netif_ != nullptr && eth_glue_ == nullptr) {
esp_netif_destroy(eth_netif_);
eth_netif_ = nullptr;
}
runtime_.clearEthernetInfo();
}
esp_err_t GatewayNetworkService::startWifi() { esp_err_t GatewayNetworkService::startWifi() {
if (wifi_started_) { if (wifi_started_) {
return ESP_OK; return ESP_OK;
@@ -778,6 +1024,69 @@ void GatewayNetworkService::HandleEspNowReceive(const esp_now_recv_info_t* info,
} }
} }
void GatewayNetworkService::HandleEthernetEvent(void* arg, esp_event_base_t event_base,
int32_t event_id, void* event_data) {
auto* service = static_cast<GatewayNetworkService*>(arg);
if (service != nullptr) {
service->handleEthernetEvent(event_base, event_id, event_data);
}
}
void GatewayNetworkService::handleEthernetEvent(esp_event_base_t event_base, int32_t event_id,
void* event_data) {
if (event_base == ETH_EVENT) {
esp_eth_handle_t handle = eth_handle_;
if (event_data != nullptr) {
handle = *static_cast<esp_eth_handle_t*>(event_data);
}
if (event_id == ETHERNET_EVENT_CONNECTED) {
uint8_t mac[6] = {};
if (handle != nullptr && esp_eth_ioctl(handle, ETH_CMD_G_MAC_ADDR, mac) == ESP_OK) {
const std::string mac_hex = MacToHex(mac);
EthernetInfo info = runtime_.deviceInfo().eth.value_or(EthernetInfo{});
info.mac = mac_hex;
runtime_.setEthernetInfo(std::move(info));
ESP_LOGI(kTag, "Ethernet link up mac=%s", mac_hex.c_str());
} else {
ESP_LOGI(kTag, "Ethernet link up");
}
return;
}
if (event_id == ETHERNET_EVENT_DISCONNECTED) {
runtime_.clearEthernetIp();
ESP_LOGI(kTag, "Ethernet link down");
return;
}
if (event_id == ETHERNET_EVENT_START) {
ESP_LOGI(kTag, "Ethernet driver started");
return;
}
if (event_id == ETHERNET_EVENT_STOP) {
runtime_.clearEthernetIp();
ESP_LOGI(kTag, "Ethernet driver stopped");
}
return;
}
if (event_base == IP_EVENT && event_id == IP_EVENT_ETH_GOT_IP && event_data != nullptr) {
auto* event = static_cast<ip_event_got_ip_t*>(event_data);
char ip[16] = {0};
esp_ip4addr_ntoa(&event->ip_info.ip, ip, sizeof(ip));
EthernetInfo info = runtime_.deviceInfo().eth.value_or(EthernetInfo{});
uint8_t mac[6] = {};
if (eth_handle_ != nullptr && esp_eth_ioctl(eth_handle_, ETH_CMD_G_MAC_ADDR, mac) == ESP_OK) {
info.mac = MacToHex(mac);
}
info.ip = ip;
runtime_.setEthernetInfo(std::move(info));
ESP_LOGI(kTag, "Ethernet got IP %s", ip);
}
}
void GatewayNetworkService::handleWifiEvent(esp_event_base_t event_base, int32_t event_id, void GatewayNetworkService::handleWifiEvent(esp_event_base_t event_base, int32_t event_id,
void* event_data) { void* event_data) {
if (!config_.wifi_enabled) { if (!config_.wifi_enabled) {
@@ -1168,6 +1477,15 @@ std::string GatewayNetworkService::deviceInfoJson() const {
} }
} }
if (info.eth.has_value()) {
cJSON* eth = cJSON_CreateObject();
if (eth != nullptr) {
cJSON_AddStringToObject(eth, "mac", info.eth->mac.c_str());
cJSON_AddStringToObject(eth, "IP", info.eth->ip.c_str());
cJSON_AddItemToObject(root, "ethInfo", eth);
}
}
const std::string rendered = PrintJson(root); const std::string rendered = PrintJson(root);
cJSON_Delete(root); cJSON_Delete(root);
return rendered; return rendered;
@@ -30,6 +30,11 @@ struct WirelessInfo {
std::string ip; std::string ip;
}; };
struct EthernetInfo {
std::string mac;
std::string ip;
};
struct GatewayRuntimeConfig { struct GatewayRuntimeConfig {
std::string_view project_name; std::string_view project_name;
std::string_view version; std::string_view version;
@@ -47,6 +52,7 @@ struct GatewayDeviceInfo {
size_t dali_gateway_count{0}; size_t dali_gateway_count{0};
bool ble_enabled{false}; bool ble_enabled{false};
std::optional<WirelessInfo> wlan; std::optional<WirelessInfo> wlan;
std::optional<EthernetInfo> eth;
}; };
class GatewaySettingsStore { class GatewaySettingsStore {
@@ -119,6 +125,9 @@ class GatewayRuntime {
void setGatewayCount(size_t gateway_count); void setGatewayCount(size_t gateway_count);
void setWirelessInfo(WirelessInfo info); void setWirelessInfo(WirelessInfo info);
bool clearWirelessInfo(); bool clearWirelessInfo();
void setEthernetInfo(EthernetInfo info);
void clearEthernetInfo();
void clearEthernetIp();
void setCommandAddressResolver(std::function<uint8_t(uint8_t gw, uint8_t raw_addr)> resolver); void setCommandAddressResolver(std::function<uint8_t(uint8_t gw, uint8_t raw_addr)> resolver);
GatewayDeviceInfo deviceInfo() const; GatewayDeviceInfo deviceInfo() const;
@@ -159,6 +168,7 @@ class GatewayRuntime {
CommandDropReason last_enqueue_drop_reason_{CommandDropReason::kNone}; CommandDropReason last_enqueue_drop_reason_{CommandDropReason::kNone};
std::function<uint8_t(uint8_t gw, uint8_t raw_addr)> command_address_resolver_; std::function<uint8_t(uint8_t gw, uint8_t raw_addr)> command_address_resolver_;
std::optional<WirelessInfo> wireless_info_; std::optional<WirelessInfo> wireless_info_;
std::optional<EthernetInfo> ethernet_info_;
SemaphoreHandle_t command_lock_{nullptr}; SemaphoreHandle_t command_lock_{nullptr};
}; };
@@ -450,6 +450,23 @@ bool GatewayRuntime::clearWirelessInfo() {
return settings_.clearWifiCredentials(); return settings_.clearWifiCredentials();
} }
void GatewayRuntime::setEthernetInfo(EthernetInfo info) {
LockGuard guard(command_lock_);
ethernet_info_ = std::move(info);
}
void GatewayRuntime::clearEthernetInfo() {
LockGuard guard(command_lock_);
ethernet_info_.reset();
}
void GatewayRuntime::clearEthernetIp() {
LockGuard guard(command_lock_);
if (ethernet_info_.has_value()) {
ethernet_info_->ip.clear();
}
}
void GatewayRuntime::setCommandAddressResolver( void GatewayRuntime::setCommandAddressResolver(
std::function<uint8_t(uint8_t gw, uint8_t raw_addr)> resolver) { std::function<uint8_t(uint8_t gw, uint8_t raw_addr)> resolver) {
LockGuard guard(command_lock_); LockGuard guard(command_lock_);
@@ -470,6 +487,7 @@ GatewayDeviceInfo GatewayRuntime::deviceInfo() const {
info.dali_gateway_count = gateway_count_; info.dali_gateway_count = gateway_count_;
info.ble_enabled = ble_enabled_; info.ble_enabled = ble_enabled_;
info.wlan = wireless_info_; info.wlan = wireless_info_;
info.eth = ethernet_info_;
return info; return info;
} }