From c365fd9d74cbbd63d2b008a4f807368eb955f958 Mon Sep 17 00:00:00 2001 From: tbnobody Date: Fri, 13 Nov 2020 18:25:13 +0100 Subject: [PATCH] Ethernet Support (#1316) Ethernet Support --- platformio.ini | 10 ++ wled00/Network.cpp | 59 ++++++++++ wled00/Network.h | 23 ++++ wled00/src/dependencies/e131/ESPAsyncE131.cpp | 3 +- wled00/src/dependencies/espalexa/Espalexa.h | 7 +- wled00/udp.cpp | 4 +- wled00/wled.cpp | 103 +++++++++++++----- wled00/wled.h | 10 +- wled00/xml.cpp | 13 ++- 9 files changed, 191 insertions(+), 41 deletions(-) create mode 100644 wled00/Network.cpp create mode 100644 wled00/Network.h diff --git a/platformio.ini b/platformio.ini index 48927b04..139eaf30 100644 --- a/platformio.ini +++ b/platformio.ini @@ -39,6 +39,7 @@ default_envs = travis_esp8266, travis_esp32 ; default_envs = d1_mini_5CH_Shojo_PCB ; default_envs = wemos_shield_esp32 ; default_envs = m5atom +; default_envs = esp32_poe [common] # ------------------------------------------------------------------------------ @@ -248,6 +249,15 @@ lib_ignore = ESPAsyncTCP ESPAsyncUDP +[env:esp32_poe] +board = esp32-poe +platform = espressif32@1.12.4 +upload_speed = 921600 +build_flags = ${common.build_flags_esp32} ${common.debug_flags} -D RLYPIN=-1 -D WLED_USE_ETHERNET +lib_ignore = + ESPAsyncTCP + ESPAsyncUDP + [env:esp8285_4CH_MagicHome] board = esp8285 platform = ${common.platform_latest} diff --git a/wled00/Network.cpp b/wled00/Network.cpp new file mode 100644 index 00000000..edd3d13c --- /dev/null +++ b/wled00/Network.cpp @@ -0,0 +1,59 @@ +#include "Network.h" + +IPAddress NetworkClass::localIP() +{ +#if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_ETHERNET) + if (ETH.localIP()[0] != 0) { + return ETH.localIP(); + } +#endif + if (WiFi.localIP()[0] != 0) { + return WiFi.localIP(); + } + return INADDR_NONE; +} + +IPAddress NetworkClass::subnetMask() +{ +#if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_ETHERNET) + if (ETH.localIP()[0] != 0) { + return ETH.subnetMask(); + } +#endif + if (WiFi.localIP()[0] != 0) { + return WiFi.subnetMask(); + } + return IPAddress(255, 255, 255, 0); +} + +IPAddress NetworkClass::gatewayIP() +{ +#if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_ETHERNET) + if (ETH.localIP()[0] != 0) { + return ETH.gatewayIP(); + } +#endif + if (WiFi.localIP()[0] != 0) { + return WiFi.gatewayIP(); + } + return INADDR_NONE; +} + +bool NetworkClass::isConnected() +{ +#if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_ETHERNET) + return (WiFi.localIP()[0] != 0 && WiFi.status() == WL_CONNECTED) || ETH.localIP()[0] != 0; +#else + return (WiFi.localIP()[0] != 0 && WiFi.status() == WL_CONNECTED); +#endif +} + +bool NetworkClass::isEthernet() +{ +#if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_ETHERNET) + return (ETH.localIP()[0] != 0); +#endif + return false; +} + +NetworkClass Network; \ No newline at end of file diff --git a/wled00/Network.h b/wled00/Network.h new file mode 100644 index 00000000..4dd8678a --- /dev/null +++ b/wled00/Network.h @@ -0,0 +1,23 @@ +#ifdef ESP8266 + #include +#else // ESP32 + #include + #include +#endif + +#ifndef Network_h +#define Network_h + +class NetworkClass +{ +public: + IPAddress localIP(); + IPAddress subnetMask(); + IPAddress gatewayIP(); + bool isConnected(); + bool isEthernet(); +}; + +extern NetworkClass Network; + +#endif \ No newline at end of file diff --git a/wled00/src/dependencies/e131/ESPAsyncE131.cpp b/wled00/src/dependencies/e131/ESPAsyncE131.cpp index 12f6ab3c..450dff57 100644 --- a/wled00/src/dependencies/e131/ESPAsyncE131.cpp +++ b/wled00/src/dependencies/e131/ESPAsyncE131.cpp @@ -18,6 +18,7 @@ */ #include "ESPAsyncE131.h" +#include "Network.h" #include // E1.17 ACN Packet Identifier @@ -75,7 +76,7 @@ bool ESPAsyncE131::initMulticast(uint16_t port, uint16_t universe, uint8_t n) { ip4_addr_t ifaddr; ip4_addr_t multicast_addr; - ifaddr.addr = static_cast(WiFi.localIP()); + ifaddr.addr = static_cast(Network.localIP()); for (uint8_t i = 1; i < n; i++) { multicast_addr.addr = static_cast(IPAddress(239, 255, (((universe + i) >> 8) & 0xff), (((universe + i) >> 0) diff --git a/wled00/src/dependencies/espalexa/Espalexa.h b/wled00/src/dependencies/espalexa/Espalexa.h index c088be60..10b61c08 100644 --- a/wled00/src/dependencies/espalexa/Espalexa.h +++ b/wled00/src/dependencies/espalexa/Espalexa.h @@ -47,6 +47,7 @@ #endif #endif #include +#include "Network.h" #ifdef ESPALEXA_DEBUG #pragma message "Espalexa 2.4.6 debug mode" @@ -207,7 +208,7 @@ private: void serveDescription() { EA_DEBUGLN("# Responding to description.xml ... #\n"); - IPAddress localIP = WiFi.localIP(); + IPAddress localIP = Network.localIP(); char s[16]; sprintf(s, "%d.%d.%d.%d", localIP[0], localIP[1], localIP[2], localIP[3]); char buf[1024]; @@ -281,7 +282,7 @@ private: //respond to UDP SSDP M-SEARCH void respondToSearch() { - IPAddress localIP = WiFi.localIP(); + IPAddress localIP = Network.localIP(); char s[16]; sprintf(s, "%d.%d.%d.%d", localIP[0], localIP[1], localIP[2], localIP[3]); @@ -333,7 +334,7 @@ public: #ifdef ARDUINO_ARCH_ESP32 udpConnected = espalexaUdp.beginMulticast(IPAddress(239, 255, 255, 250), 1900); #else - udpConnected = espalexaUdp.beginMulticast(WiFi.localIP(), IPAddress(239, 255, 255, 250), 1900); + udpConnected = espalexaUdp.beginMulticast(Network.localIP(), IPAddress(239, 255, 255, 250), 1900); #endif if (udpConnected){ diff --git a/wled00/udp.cpp b/wled00/udp.cpp index 7c9a1839..a7cff12c 100644 --- a/wled00/udp.cpp +++ b/wled00/udp.cpp @@ -61,7 +61,7 @@ void notify(byte callMode, bool followUp) udpOut[28] = (t >> 0) & 0xFF; IPAddress broadcastIp; - broadcastIp = ~uint32_t(WiFi.subnetMask()) | uint32_t(WiFi.gatewayIP()); + broadcastIp = ~uint32_t(Network.subnetMask()) | uint32_t(Network.gatewayIP()); notifierUdp.beginPacket(broadcastIp, udpPort); notifierUdp.write(udpOut, WLEDPACKETSIZE); @@ -157,7 +157,7 @@ void handleNotifications() //notifier and UDP realtime if (!packetSize || packetSize > UDP_IN_MAXSIZE) return; - if (!isSupp && notifierUdp.remoteIP() == WiFi.localIP()) return; //don't process broadcasts we send ourselves + if (!isSupp && notifierUdp.remoteIP() == Network.localIP()) return; //don't process broadcasts we send ourselves uint8_t udpIn[packetSize +1]; if (isSupp) notifier2Udp.read(udpIn, packetSize); diff --git a/wled00/wled.cpp b/wled00/wled.cpp index 91f2943a..a4329a76 100644 --- a/wled00/wled.cpp +++ b/wled00/wled.cpp @@ -43,6 +43,68 @@ bool oappend(const char* txt) return true; } +void prepareHostname(char* hostname) +{ + const char *pC = serverDescription; + uint8_t pos = 5; + + while (*pC && pos < 24) { // while !null and not over length + if (isalnum(*pC)) { // if the current char is alpha-numeric append it to the hostname + hostname[pos] = *pC; + pos++; + } else if (*pC == ' ' || *pC == '_' || *pC == '-' || *pC == '+' || *pC == '!' || *pC == '?' || *pC == '*') { + hostname[pos] = '-'; + pos++; + } + // else do nothing - no leading hyphens and do not include hyphens for all other characters. + pC++; + } + // if the hostname is left blank, use the mac address/default mdns name + if (pos < 6) { + sprintf(hostname + 5, "%*s", 6, escapedMac.c_str() + 6); + } else { //last character must not be hyphen + while (pos > 0 && hostname[pos -1] == '-') { + hostname[pos -1] = 0; + pos--; + } + } +} + +//handle Ethernet connection event +void WiFiEvent(WiFiEvent_t event) +{ + char hostname[25] = "wled-"; + + switch (event) { +#if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_ETHERNET) + case SYSTEM_EVENT_ETH_START: + DEBUG_PRINT("ETH Started"); + break; + case SYSTEM_EVENT_ETH_CONNECTED: + DEBUG_PRINT("ETH Connected"); + if (!apActive) { + WiFi.disconnect(true); + } + if (staticIP != (uint32_t)0x00000000 && staticGateway != (uint32_t)0x00000000) { + ETH.config(staticIP, staticGateway, staticSubnet, IPAddress(8, 8, 8, 8)); + } else { + ETH.config(INADDR_NONE, INADDR_NONE, INADDR_NONE); + } + // convert the "serverDescription" into a valid DNS hostname (alphanumeric) + prepareHostname(hostname); + ETH.setHostname(hostname); + showWelcomePage = false; + break; + case SYSTEM_EVENT_ETH_DISCONNECTED: + DEBUG_PRINT("ETH Disconnected"); + forceReconnect = true; + break; +#endif + default: + break; + } +} + void WLED::loop() { handleIR(); // 2nd call to function needed for ESP32 to return valid results -- should be good for ESP8266, too @@ -120,7 +182,7 @@ void WLED::loop() lastWifiState = WiFi.status(); DEBUG_PRINT("State time: "); DEBUG_PRINTLN(wifiStateChangedTime); DEBUG_PRINT("NTP last sync: "); DEBUG_PRINTLN(ntpLastSyncTime); - DEBUG_PRINT("Client IP: "); DEBUG_PRINTLN(WiFi.localIP()); + DEBUG_PRINT("Client IP: "); DEBUG_PRINTLN(Network.localIP()); DEBUG_PRINT("Loops/sec: "); DEBUG_PRINTLN(loops / 10); loops = 0; debugTime = millis(); @@ -187,6 +249,7 @@ void WLED::setup() if (strcmp(clientSSID, DEFAULT_CLIENT_SSID) == 0) showWelcomePage = true; WiFi.persistent(false); + WiFi.onEvent(WiFiEvent); if (macroBoot > 0) applyMacro(macroBoot); @@ -303,6 +366,10 @@ void WLED::initConnection() ws.onEvent(wsEvent); #endif +#if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_ETHERNET) + ETH.begin(); +#endif + WiFi.disconnect(true); // close old connections #ifdef ESP8266 WiFi.setPhyMode(WIFI_PHY_MODE_11N); @@ -338,29 +405,7 @@ void WLED::initConnection() // convert the "serverDescription" into a valid DNS hostname (alphanumeric) char hostname[25] = "wled-"; - const char *pC = serverDescription; - uint8_t pos = 5; - - while (*pC && pos < 24) { // while !null and not over length - if (isalnum(*pC)) { // if the current char is alpha-numeric append it to the hostname - hostname[pos] = *pC; - pos++; - } else if (*pC == ' ' || *pC == '_' || *pC == '-' || *pC == '+' || *pC == '!' || *pC == '?' || *pC == '*') { - hostname[pos] = '-'; - pos++; - } - // else do nothing - no leading hyphens and do not include hyphens for all other characters. - pC++; - } - // if the hostname is left blank, use the mac address/default mdns name - if (pos < 6) { - sprintf(hostname + 5, "%*s", 6, escapedMac.c_str() + 6); - } else { //last character must not be hyphen - while (pos > 0 && hostname[pos -1] == '-') { - hostname[pos -1] = 0; - pos--; - } - } + prepareHostname(hostname); #ifdef ESP8266 WiFi.hostname(hostname); @@ -381,9 +426,9 @@ void WLED::initInterfaces() DEBUG_PRINTLN(F("Init STA interfaces")); if (hueIP[0] == 0) { - hueIP[0] = WiFi.localIP()[0]; - hueIP[1] = WiFi.localIP()[1]; - hueIP[2] = WiFi.localIP()[2]; + hueIP[0] = Network.localIP()[0]; + hueIP[1] = Network.localIP()[1]; + hueIP[2] = Network.localIP()[2]; } // init Alexa hue emulation @@ -482,7 +527,7 @@ void WLED::handleConnection() wasConnected = false; return; } - if (!WLED_CONNECTED) { + if (!Network.isConnected()) { if (interfacesInited) { DEBUG_PRINTLN(F("Disconnected!")); interfacesInited = false; @@ -495,7 +540,7 @@ void WLED::handleConnection() } else if (!interfacesInited) { // newly connected DEBUG_PRINTLN(""); DEBUG_PRINT(F("Connected! IP address: ")); - DEBUG_PRINTLN(WiFi.localIP()); + DEBUG_PRINTLN(Network.localIP()); initInterfaces(); userConnected(); usermods.connected(); diff --git a/wled00/wled.h b/wled00/wled.h index 064a1f2b..5ac31259 100644 --- a/wled00/wled.h +++ b/wled00/wled.h @@ -54,12 +54,15 @@ } #else // ESP32 #include + #include #include "esp_wifi.h" #include #include #include "SPIFFS.h" #endif +#include "Network.h" + #include #include #include @@ -521,8 +524,11 @@ WLED_GLOBAL UsermodManager usermods _INIT(UsermodManager()); WLED_GLOBAL int loops _INIT(0); #endif - -#define WLED_CONNECTED (WiFi.status() == WL_CONNECTED) +#ifdef ARDUINO_ARCH_ESP32 + #define WLED_CONNECTED (WiFi.status() == WL_CONNECTED || ETH.localIP()[0] != 0) +#else + #define WLED_CONNECTED (WiFi.status() == WL_CONNECTED) +#endif #define WLED_WIFI_CONFIGURED (strlen(clientSSID) >= 1 && strcmp(clientSSID, DEFAULT_CLIENT_SSID) != 0) #define WLED_MQTT_CONNECTED (mqtt != nullptr && mqtt->connected()) diff --git a/wled00/xml.cpp b/wled00/xml.cpp index 73301316..7789babf 100644 --- a/wled00/xml.cpp +++ b/wled00/xml.cpp @@ -83,9 +83,10 @@ void URL_response(AsyncWebServerRequest *request) char s[16]; oappend(SET_F("http://")); - IPAddress localIP = WiFi.localIP(); + IPAddress localIP = Network.localIP(); sprintf(s, "%d.%d.%d.%d", localIP[0], localIP[1], localIP[2], localIP[3]); oappend(s); + oappend(SET_F("/win&A=")); oappendi(bri); oappend(SET_F("&CL=h")); @@ -219,11 +220,15 @@ void getSettingsJS(byte subPage, char* dest) sappend('c',SET_F("WS"),noWifiSleep); - if (WiFi.localIP()[0] != 0) //is connected + if (Network.isConnected()) //is connected { - char s[16]; - IPAddress localIP = WiFi.localIP(); + char s[32]; + IPAddress localIP = Network.localIP(); sprintf(s, "%d.%d.%d.%d", localIP[0], localIP[1], localIP[2], localIP[3]); + + #if defined(ARDUINO_ARCH_ESP32) && defined(WLED_USE_ETHERNET) + if (Network.isEthernet()) strcat_P(s ,SET_F(" (Ethernet)")); + #endif sappends('m',SET_F("(\"sip\")[0]"),s); } else {