diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 2f9d95ed2..72fd4b113 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -52,7 +52,7 @@ The following binary downloads have been compiled with ESP8266/Arduino library c ## Changelog -### Version 8.3.1.3 +### Version 8.3.1.4 - Change IRremoteESP8266 library updated to v2.7.7 - Change Adafruit_SGP30 library from v1.0.3 to v1.2.0 (#8519) @@ -79,3 +79,4 @@ The following binary downloads have been compiled with ESP8266/Arduino library c - Add initial support for Telegram bot (#8619) - Add support for HP303B Temperature and Pressure sensor by Robert Jaakke (#8638) - Add rule trigger ``System#Init`` to allow early rule execution without wifi and mqtt initialized yet +- Add basic support for ESP32 ethernet adding commands ``Wifi 0/1`` and ``Ethernet 0/1`` both default ON diff --git a/tasmota/CHANGELOG.md b/tasmota/CHANGELOG.md index 73582dfb7..02b4dc209 100644 --- a/tasmota/CHANGELOG.md +++ b/tasmota/CHANGELOG.md @@ -1,5 +1,9 @@ ## Unreleased (development) +### 8.3.1.4 20200615 + +- Add basic support for ESP32 ethernet adding commands ``Wifi 0/1`` and ``Ethernet 0/1`` both default ON + ### 8.3.1.3 20200611 - Add initial support for Telegram bot (#8619) diff --git a/tasmota/i18n.h b/tasmota/i18n.h index 01122fabd..1a254bdfc 100644 --- a/tasmota/i18n.h +++ b/tasmota/i18n.h @@ -271,6 +271,8 @@ #define D_CMND_SSID "SSId" #define D_CMND_PASSWORD "Password" #define D_CMND_HOSTNAME "Hostname" +#define D_CMND_WIFI "Wifi" +#define D_CMND_ETHERNET "Ethernet" #define D_CMND_WIFICONFIG "WifiConfig" #define D_WCFG_0_RESTART "Restart" #define D_WCFG_2_WIFIMANAGER "WifiManager" diff --git a/tasmota/settings.h b/tasmota/settings.h index 08175d7db..afc2f5672 100644 --- a/tasmota/settings.h +++ b/tasmota/settings.h @@ -114,8 +114,8 @@ typedef union { // Restricted by MISRA-C Rule 18.4 bu uint32_t pwm_ct_mode : 1; // bit 10 (v8.2.0.4) - SetOption92 - Set PWM Mode from regular PWM to ColorTemp control (Xiaomi Philips ...) uint32_t compress_rules_cpu : 1; // bit 11 (v8.2.0.6) - SetOption93 - Keep uncompressed rules in memory to avoid CPU load of uncompressing at each tick uint32_t max6675 : 1; // bit 12 (v8.3.1.2) - SetOption94 - Implement simpler MAX6675 protocol instead of MAX31855 - uint32_t spare13 : 1; - uint32_t spare14 : 1; + uint32_t network_wifi : 1; // bit 13 (v8.3.1.3) - CMND_WIFI + uint32_t network_ethernet : 1; // bit 14 (v8.3.1.3) = CMND_ETHERNET uint32_t spare15 : 1; uint32_t spare16 : 1; uint32_t spare17 : 1; @@ -676,10 +676,10 @@ typedef union { // Restricted by MISRA-C Rule 18.4 bu typedef union { uint8_t data; struct { - uint8_t wifi_down : 1; + uint8_t network_down : 1; uint8_t mqtt_down : 1; - uint8_t spare02 : 1; - uint8_t spare03 : 1; + uint8_t wifi_down : 1; + uint8_t eth_down : 1; uint8_t spare04 : 1; uint8_t spare05 : 1; uint8_t spare06 : 1; diff --git a/tasmota/settings.ino b/tasmota/settings.ino index f8aa19ab9..1b2dca82d 100644 --- a/tasmota/settings.ino +++ b/tasmota/settings.ino @@ -798,7 +798,11 @@ void SettingsDefaultSet2(void) Settings.serial_delimiter = 0xff; Settings.seriallog_level = SERIAL_LOG_LEVEL; + // Ethernet + flag4.network_ethernet |= 1; + // Wifi + flag4.network_wifi |= 1; flag3.use_wifi_scan |= WIFI_SCAN_AT_RESTART; flag3.use_wifi_rescan |= WIFI_SCAN_REGULARLY; Settings.wifi_output_power = 170; @@ -1439,6 +1443,10 @@ void SettingsDelta(void) Settings.ledpwm_on = 255; Settings.ledpwm_mask = 0; } + if (Settings.version < 0x08030104) { + Settings.flag4.network_wifi = 1; + Settings.flag4.network_ethernet = 1; + } Settings.version = VERSION; SettingsSave(1); diff --git a/tasmota/support.ino b/tasmota/support.ino index 0a5d26f10..8b2c144f7 100644 --- a/tasmota/support.ino +++ b/tasmota/support.ino @@ -156,7 +156,7 @@ float CharToFloat(const char *str) signed char sign = 1; if (*pt == '-') { sign = -1; } - if (*pt == '-' || *pt=='+') { pt++; } // Skip any sign + if (*pt == '-' || *pt == '+') { pt++; } // Skip any sign float left = 0; if (*pt != '.') { @@ -167,8 +167,9 @@ float CharToFloat(const char *str) float right = 0; if (*pt == '.') { pt++; - // limit decimals to float max - pt[7]=0; + uint32_t max_decimals = 0; + while ((max_decimals < 8) && isdigit(pt[max_decimals])) { max_decimals++; } + pt[max_decimals] = '\0'; // Limit decimals to float max of 8 right = atoi(pt); // Decimal part while (isdigit(*pt)) { pt++; @@ -1740,7 +1741,7 @@ void Syslog(void) } if (PortUdp.beginPacket(syslog_host_addr, Settings.syslog_port)) { char syslog_preamble[64]; // Hostname + Id - snprintf_P(syslog_preamble, sizeof(syslog_preamble), PSTR("%s ESP-"), my_hostname); + snprintf_P(syslog_preamble, sizeof(syslog_preamble), PSTR("%s ESP-"), NetworkHostname()); memmove(log_data + strlen(syslog_preamble), log_data, sizeof(log_data) - strlen(syslog_preamble)); log_data[sizeof(log_data) -1] = '\0'; memcpy(log_data, syslog_preamble, strlen(syslog_preamble)); @@ -1787,7 +1788,7 @@ void AddLog(uint32_t loglevel) !global_state.mqtt_down && (loglevel <= Settings.mqttlog_level)) { MqttPublishLogging(mxtime); } - if (!global_state.wifi_down && + if (!global_state.network_down && (loglevel <= syslog_level)) { Syslog(); } prepped_loglevel = 0; @@ -1910,4 +1911,4 @@ String Decompress(const char * compressed, size_t uncompressed_size) { return content; } -#endif // USE_UNISHOX_COMPRESSION +#endif // USE_UNISHOX_COMPRESSION \ No newline at end of file diff --git a/tasmota/support_command.ino b/tasmota/support_command.ino index fe855ee92..5d0180005 100644 --- a/tasmota/support_command.ino +++ b/tasmota/support_command.ino @@ -27,7 +27,7 @@ const char kTasmotaCommands[] PROGMEM = "|" // No prefix D_CMND_SERIALDELIMITER "|" D_CMND_IPADDRESS "|" D_CMND_NTPSERVER "|" D_CMND_AP "|" D_CMND_SSID "|" D_CMND_PASSWORD "|" D_CMND_HOSTNAME "|" D_CMND_WIFICONFIG "|" D_CMND_DEVICENAME "|" D_CMND_FRIENDLYNAME "|" D_CMND_SWITCHMODE "|" D_CMND_INTERLOCK "|" D_CMND_TELEPERIOD "|" D_CMND_RESET "|" D_CMND_TIME "|" D_CMND_TIMEZONE "|" D_CMND_TIMESTD "|" D_CMND_TIMEDST "|" D_CMND_ALTITUDE "|" D_CMND_LEDPOWER "|" D_CMND_LEDSTATE "|" D_CMND_LEDMASK "|" D_CMND_LEDPWM_ON "|" D_CMND_LEDPWM_OFF "|" D_CMND_LEDPWM_MODE "|" - D_CMND_WIFIPOWER "|" D_CMND_TEMPOFFSET "|" D_CMND_HUMOFFSET "|" D_CMND_SPEEDUNIT "|" D_CMND_GLOBAL_TEMP "|" D_CMND_GLOBAL_HUM "|" + D_CMND_WIFIPOWER "|" D_CMND_TEMPOFFSET "|" D_CMND_HUMOFFSET "|" D_CMND_SPEEDUNIT "|" D_CMND_GLOBAL_TEMP "|" D_CMND_GLOBAL_HUM "|" D_CMND_WIFI "|" #ifdef USE_I2C D_CMND_I2CSCAN "|" D_CMND_I2CDRIVER "|" #endif @@ -54,7 +54,7 @@ void (* const TasmotaCommand[])(void) PROGMEM = { &CmndSerialDelimiter, &CmndIpAddress, &CmndNtpServer, &CmndAp, &CmndSsid, &CmndPassword, &CmndHostname, &CmndWifiConfig, &CmndDevicename, &CmndFriendlyname, &CmndSwitchMode, &CmndInterlock, &CmndTeleperiod, &CmndReset, &CmndTime, &CmndTimezone, &CmndTimeStd, &CmndTimeDst, &CmndAltitude, &CmndLedPower, &CmndLedState, &CmndLedMask, &CmndLedPwmOn, &CmndLedPwmOff, &CmndLedPwmMode, - &CmndWifiPower, &CmndTempOffset, &CmndHumOffset, &CmndSpeedUnit, &CmndGlobalTemp, &CmndGlobalHum, + &CmndWifiPower, &CmndTempOffset, &CmndHumOffset, &CmndSpeedUnit, &CmndGlobalTemp, &CmndGlobalHum, &CmndWifi, #ifdef USE_I2C &CmndI2cScan, CmndI2cDriver, #endif @@ -499,8 +499,8 @@ void CmndStatus(void) Response_P(PSTR("{\"" D_CMND_STATUS D_STATUS5_NETWORK "\":{\"" D_CMND_HOSTNAME "\":\"%s\",\"" D_CMND_IPADDRESS "\":\"%s\",\"" D_JSON_GATEWAY "\":\"%s\",\"" D_JSON_SUBNETMASK "\":\"%s\",\"" D_JSON_DNSSERVER "\":\"%s\",\"" D_JSON_MAC "\":\"%s\",\"" D_CMND_WEBSERVER "\":%d,\"" D_CMND_WIFICONFIG "\":%d,\"" D_CMND_WIFIPOWER "\":%s}}"), - my_hostname, WiFi.localIP().toString().c_str(), IPAddress(Settings.ip_address[1]).toString().c_str(), - IPAddress(Settings.ip_address[2]).toString().c_str(), IPAddress(Settings.ip_address[3]).toString().c_str(), WiFi.macAddress().c_str(), + NetworkHostname(), NetworkAddress().toString().c_str(), IPAddress(Settings.ip_address[1]).toString().c_str(), + IPAddress(Settings.ip_address[2]).toString().c_str(), IPAddress(Settings.ip_address[3]).toString().c_str(), NetworkMacAddress().c_str(), Settings.webserver, Settings.sta_config, WifiGetOutputPower().c_str()); MqttPublishPrefixTopic_P(option, PSTR(D_CMND_STATUS "5")); } @@ -1497,6 +1497,15 @@ void CmndWifiConfig(void) Response_P(S_JSON_COMMAND_NVALUE_SVALUE, XdrvMailbox.command, Settings.sta_config, GetTextIndexed(stemp1, sizeof(stemp1), Settings.sta_config, kWifiConfig)); } +void CmndWifi(void) +{ + if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 1)) { + Settings.flag4.network_wifi = XdrvMailbox.payload; + restart_flag = 2; + } + ResponseCmndStateText(Settings.flag4.network_wifi); +} + void CmndDevicename(void) { if (!XdrvMailbox.grpflg && (XdrvMailbox.data_len > 0)) { diff --git a/tasmota/support_tasmota.ino b/tasmota/support_tasmota.ino index 3cbfb497c..a7430dfbb 100644 --- a/tasmota/support_tasmota.ino +++ b/tasmota/support_tasmota.ino @@ -684,10 +684,14 @@ void MqttShowState(void) MqttShowPWMState(); } - int32_t rssi = WiFi.RSSI(); - ResponseAppend_P(PSTR(",\"" D_JSON_WIFI "\":{\"" D_JSON_AP "\":%d,\"" D_JSON_SSID "\":\"%s\",\"" D_JSON_BSSID "\":\"%s\",\"" D_JSON_CHANNEL "\":%d,\"" D_JSON_RSSI "\":%d,\"" D_JSON_SIGNAL "\":%d,\"" D_JSON_LINK_COUNT "\":%d,\"" D_JSON_DOWNTIME "\":\"%s\"}}"), - Settings.sta_active +1, SettingsText(SET_STASSID1 + Settings.sta_active), WiFi.BSSIDstr().c_str(), WiFi.channel(), - WifiGetRssiAsQuality(rssi), rssi, WifiLinkCount(), WifiDowntime().c_str()); + if (!global_state.wifi_down) { + int32_t rssi = WiFi.RSSI(); + ResponseAppend_P(PSTR(",\"" D_JSON_WIFI "\":{\"" D_JSON_AP "\":%d,\"" D_JSON_SSID "\":\"%s\",\"" D_JSON_BSSID "\":\"%s\",\"" D_JSON_CHANNEL "\":%d,\"" D_JSON_RSSI "\":%d,\"" D_JSON_SIGNAL "\":%d,\"" D_JSON_LINK_COUNT "\":%d,\"" D_JSON_DOWNTIME "\":\"%s\"}"), + Settings.sta_active +1, SettingsText(SET_STASSID1 + Settings.sta_active), WiFi.BSSIDstr().c_str(), WiFi.channel(), + WifiGetRssiAsQuality(rssi), rssi, WifiLinkCount(), WifiDowntime().c_str()); + } + + ResponseJsonEnd(); } void MqttPublishTeleState(void) @@ -824,7 +828,7 @@ void PerformEverySecond(void) if (Settings.tele_period) { if (tele_period >= 9999) { - if (!global_state.wifi_down) { + if (!global_state.network_down) { tele_period = 0; // Allow teleperiod once wifi is connected } } else { @@ -916,10 +920,12 @@ void Every250mSeconds(void) state_250mS++; state_250mS &= 0x3; + global_state.network_down = (global_state.wifi_down && global_state.eth_down); + if (!Settings.flag.global_state) { // Problem blinkyblinky enabled - SetOption31 - Control link led blinking - if (global_state.data) { // Any problem + if (global_state.data &0x03) { // Any problem if (global_state.mqtt_down) { blinkinterval = 7; } // MQTT problem so blink every 2 seconds (slowest) - if (global_state.wifi_down) { blinkinterval = 3; } // Wifi problem so blink every second (slow) + if (global_state.network_down) { blinkinterval = 3; } // Network problem so blink every second (slow) blinks = 201; // Allow only a single blink in case the problem is solved } } @@ -1151,11 +1157,75 @@ void Every250mSeconds(void) } break; case 2: // Every x.5 second - WifiCheck(wifi_state_flag); - wifi_state_flag = WIFI_RESTART; + if (Settings.flag4.network_wifi) { + WifiCheck(wifi_state_flag); + wifi_state_flag = WIFI_RESTART; + } break; case 3: // Every x.75 second - if (!global_state.wifi_down) { MqttCheck(); } + if (!global_state.network_down) { +#ifdef FIRMWARE_MINIMAL + if (1 == RtcSettings.ota_loader) { + RtcSettings.ota_loader = 0; + ota_state_flag = 3; + } +#endif // FIRMWARE_MINIMAL + +#ifdef USE_DISCOVERY + StartMdns(); +#endif // USE_DISCOVERY + +#ifdef USE_WEBSERVER + if (Settings.webserver) { + +#ifdef ESP8266 + StartWebserver(Settings.webserver, WiFi.localIP()); +#else // ESP32 +#ifdef USE_ETHERNET + StartWebserver(Settings.webserver, (EthernetLocalIP()) ? EthernetLocalIP() : WiFi.localIP()); +#else + StartWebserver(Settings.webserver, WiFi.localIP()); +#endif +#endif + +#ifdef USE_DISCOVERY +#ifdef WEBSERVER_ADVERTISE + MdnsAddServiceHttp(); +#endif // WEBSERVER_ADVERTISE +#endif // USE_DISCOVERY + } else { + StopWebserver(); + } +#ifdef USE_EMULATION + if (Settings.flag2.emulation) { UdpConnect(); } +#endif // USE_EMULATION +#endif // USE_WEBSERVER + +#ifdef USE_DEVICE_GROUPS + DeviceGroupsStart(); +#endif // USE_DEVICE_GROUPS + +#ifdef USE_KNX + if (!knx_started && Settings.flag.knx_enabled) { // CMND_KNX_ENABLED + KNXStart(); + knx_started = true; + } +#endif // USE_KNX + + MqttCheck(); + } else { +#ifdef USE_EMULATION + UdpDisconnect(); +#endif // USE_EMULATION + +#ifdef USE_DEVICE_GROUPS + DeviceGroupsStop(); +#endif // USE_DEVICE_GROUPS + +#ifdef USE_KNX + knx_started = false; +#endif // USE_KNX + } break; } } @@ -1174,7 +1244,7 @@ uint16_t arduino_ota_progress_dot_count = 0; void ArduinoOTAInit(void) { ArduinoOTA.setPort(8266); - ArduinoOTA.setHostname(my_hostname); + ArduinoOTA.setHostname(NetworkHostname()); if (strlen(SettingsText(SET_WEBPWD))) { ArduinoOTA.setPassword(SettingsText(SET_WEBPWD)); } diff --git a/tasmota/support_wifi.ino b/tasmota/support_wifi.ino index c42e1d49a..2829481f9 100644 --- a/tasmota/support_wifi.ino +++ b/tasmota/support_wifi.ino @@ -352,6 +352,9 @@ void WifiSetState(uint8_t state) } } global_state.wifi_down = state ^1; + if (!global_state.wifi_down) { + global_state.network_down = 0; + } } #if LWIP_IPV6 @@ -373,6 +376,39 @@ String WifiGetIPv6(void) return ""; } +#ifdef USE_DISCOVERY +void StartMdns(void) { + if (Settings.flag3.mdns_enabled) { // SetOption55 - Control mDNS service + if (!Wifi.mdns_begun) { +// if (mdns_delayed_start) { +// AddLog_P(LOG_LEVEL_INFO, PSTR(D_LOG_MDNS D_ATTEMPTING_CONNECTION)); +// mdns_delayed_start--; +// } else { +// mdns_delayed_start = Settings.param[P_MDNS_DELAYED_START]; + Wifi.mdns_begun = (uint8_t)MDNS.begin(my_hostname); + AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_MDNS "%s"), (Wifi.mdns_begun) ? D_INITIALIZED : D_FAILED); +// } + } + } +} + +#ifdef WEBSERVER_ADVERTISE +void MdnsAddServiceHttp(void) { + if (1 == Wifi.mdns_begun) { + Wifi.mdns_begun = 2; + MDNS.addService("http", "tcp", WEB_PORT); + } +} + +void MdnsUpdate(void) { + if (2 == Wifi.mdns_begun) { + MDNS.update(); + AddLog_P(LOG_LEVEL_DEBUG_MORE, D_LOG_MDNS, "MDNS.update"); + } +} +#endif // WEBSERVER_ADVERTISE +#endif // USE_DISCOVERY + bool WifiCheckIPAddrStatus(void) // Return false for 169.254.x.x or fe80::/64 { bool ip_global=false; @@ -410,10 +446,7 @@ void WifiCheckIp(void) Wifi.status = WL_CONNECTED; #ifdef USE_DISCOVERY #ifdef WEBSERVER_ADVERTISE - if (2 == Wifi.mdns_begun) { - MDNS.update(); - AddLog_P(LOG_LEVEL_DEBUG_MORE, D_LOG_MDNS, "MDNS.update"); - } + MdnsUpdate(); #endif // USE_DISCOVERY #endif // WEBSERVER_ADVERTISE } else { @@ -529,75 +562,14 @@ void WifiCheck(uint8_t param) if ((WL_CONNECTED == WiFi.status()) && (static_cast(WiFi.localIP()) != 0) && !Wifi.config_type) { #endif // LWIP_IPV6=1 WifiSetState(1); - if (Settings.flag3.use_wifi_rescan) { // SetOption57 - Scan wifi network every 44 minutes for configured AP's if (!(uptime % (60 * WIFI_RESCAN_MINUTES))) { Wifi.scan_state = 2; } } - -#ifdef FIRMWARE_MINIMAL - if (1 == RtcSettings.ota_loader) { - RtcSettings.ota_loader = 0; - ota_state_flag = 3; - } -#endif // FIRMWARE_MINIMAL - -#ifdef USE_DISCOVERY - if (Settings.flag3.mdns_enabled) { // SetOption55 - Control mDNS service - if (!Wifi.mdns_begun) { -// if (mdns_delayed_start) { -// AddLog_P(LOG_LEVEL_INFO, PSTR(D_LOG_MDNS D_ATTEMPTING_CONNECTION)); -// mdns_delayed_start--; -// } else { -// mdns_delayed_start = Settings.param[P_MDNS_DELAYED_START]; - Wifi.mdns_begun = (uint8_t)MDNS.begin(my_hostname); - AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_MDNS "%s"), (Wifi.mdns_begun) ? D_INITIALIZED : D_FAILED); -// } - } - } -#endif // USE_DISCOVERY - -#ifdef USE_WEBSERVER - if (Settings.webserver) { - StartWebserver(Settings.webserver, WiFi.localIP()); -#ifdef USE_DISCOVERY -#ifdef WEBSERVER_ADVERTISE - if (1 == Wifi.mdns_begun) { - Wifi.mdns_begun = 2; - MDNS.addService("http", "tcp", WEB_PORT); - } -#endif // WEBSERVER_ADVERTISE -#endif // USE_DISCOVERY - } else { - StopWebserver(); - } -#ifdef USE_EMULATION - if (Settings.flag2.emulation) { UdpConnect(); } -#endif // USE_EMULATION -#endif // USE_WEBSERVER -#ifdef USE_DEVICE_GROUPS - DeviceGroupsStart(); -#endif // USE_DEVICE_GROUPS -#ifdef USE_KNX - if (!knx_started && Settings.flag.knx_enabled) { // CMND_KNX_ENABLED - KNXStart(); - knx_started = true; - } -#endif // USE_KNX - } else { WifiSetState(0); -#ifdef USE_EMULATION - UdpDisconnect(); -#endif // USE_EMULATION -#ifdef USE_DEVICE_GROUPS - DeviceGroupsStop(); -#endif // USE_DEVICE_GROUPS Wifi.mdns_begun = 0; -#ifdef USE_KNX - knx_started = false; -#endif // USE_KNX } } } @@ -652,6 +624,8 @@ RF_PRE_INIT() void WifiConnect(void) { + if (!Settings.flag4.network_wifi) { return; } + WifiSetState(0); WifiSetOutputPower(); WiFi.persistent(false); // Solve possible wifi init errors @@ -760,4 +734,44 @@ void wifiKeepAlive(void) { SetNextTimeInterval(wifiTimer, wifiTimerSec * 1000); } } -#endif // ARDUINO_ESP8266_RELEASE_2_3_0 \ No newline at end of file +#endif // ARDUINO_ESP8266_RELEASE_2_3_0 + + +char* NetworkHostname(void) { + if (global_state.eth_down) { + return my_hostname; + } +#ifdef ESP32 +#ifdef USE_ETHERNET + else { + return EthernetHostname(); + } +#endif +#endif +} + +IPAddress NetworkAddress(void) { + if (global_state.eth_down) { + return WiFi.localIP(); + } +#ifdef ESP32 +#ifdef USE_ETHERNET + else { + return EthernetLocalIP(); + } +#endif +#endif +} + +String NetworkMacAddress(void) { + if (global_state.eth_down) { + return WiFi.macAddress(); + } +#ifdef ESP32 +#ifdef USE_ETHERNET + else { + return EthernetMacAddress(); + } +#endif +#endif +} diff --git a/tasmota/tasmota.ino b/tasmota/tasmota.ino index 06bd8d9e7..4a35d4327 100644 --- a/tasmota/tasmota.ino +++ b/tasmota/tasmota.ino @@ -205,7 +205,7 @@ void setup(void) { #endif #endif - global_state.data = 3; // Init global state (wifi_down, mqtt_down) to solve possible network issues + global_state.data = 0xF; // Init global state (wifi_down, mqtt_down) to solve possible network issues RtcRebootLoad(); if (!RtcRebootValid()) { @@ -413,7 +413,7 @@ void loop(void) { if (my_activity < (uint32_t)ssleep) { SleepDelay((uint32_t)ssleep - my_activity); // Provide time for background tasks like wifi } else { - if (global_state.wifi_down) { + if (global_state.network_down) { SleepDelay(my_activity /2); // If wifi down and my_activity > setoption36 then force loop delay to 1/3 of my_activity period } } diff --git a/tasmota/tasmota_globals.h b/tasmota/tasmota_globals.h index f33024c45..c2acc6911 100644 --- a/tasmota/tasmota_globals.h +++ b/tasmota/tasmota_globals.h @@ -43,6 +43,16 @@ char* ToHex_P(const unsigned char * in, size_t insz, char * out, size_t outsz, c extern "C" void custom_crash_callback(struct rst_info * rst_info, uint32_t stack, uint32_t stack_end); extern "C" void resetPins(); +#ifdef ESP32 + +#ifdef USE_ETHERNET +IPAddress EthernetLocalIP(void); +char* EthernetHostname(void); +String EthernetMacAddress(void); +#endif + +#endif // ESP32 + /*********************************************************************************************\ * Preconfigured configurations \*********************************************************************************************/ diff --git a/tasmota/tasmota_version.h b/tasmota/tasmota_version.h index f22a0288b..e01e1bcce 100644 --- a/tasmota/tasmota_version.h +++ b/tasmota/tasmota_version.h @@ -20,7 +20,7 @@ #ifndef _TASMOTA_VERSION_H_ #define _TASMOTA_VERSION_H_ -const uint32_t VERSION = 0x08030103; +const uint32_t VERSION = 0x08030104; // Lowest compatible version const uint32_t VERSION_COMPATIBLE = 0x07010006; diff --git a/tasmota/xdrv_01_webserver.ino b/tasmota/xdrv_01_webserver.ino index 7fcd82a9f..52bdda713 100644 --- a/tasmota/xdrv_01_webserver.ino +++ b/tasmota/xdrv_01_webserver.ino @@ -868,10 +868,16 @@ void StartWebserver(int type, IPAddress ipweb) if (Web.state != type) { #if LWIP_IPV6 String ipv6_addr = WifiGetIPv6(); - if(ipv6_addr!="") AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_HTTP D_WEBSERVER_ACTIVE_ON " %s%s " D_WITH_IP_ADDRESS " %s and IPv6 global address %s "), my_hostname, (Wifi.mdns_begun) ? ".local" : "", ipweb.toString().c_str(),ipv6_addr.c_str()); - else AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_HTTP D_WEBSERVER_ACTIVE_ON " %s%s " D_WITH_IP_ADDRESS " %s"), my_hostname, (Wifi.mdns_begun) ? ".local" : "", ipweb.toString().c_str()); + if (ipv6_addr!="") { + AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_HTTP D_WEBSERVER_ACTIVE_ON " %s%s " D_WITH_IP_ADDRESS " %s and IPv6 global address %s "), + NetworkHostname(), (Wifi.mdns_begun) ? ".local" : "", ipweb.toString().c_str(), ipv6_addr.c_str()); + } else { + AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_HTTP D_WEBSERVER_ACTIVE_ON " %s%s " D_WITH_IP_ADDRESS " %s"), + NetworkHostname(), (Wifi.mdns_begun) ? ".local" : "", ipweb.toString().c_str()); + } #else - AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_HTTP D_WEBSERVER_ACTIVE_ON " %s%s " D_WITH_IP_ADDRESS " %s"), my_hostname, (Wifi.mdns_begun) ? ".local" : "", ipweb.toString().c_str()); + AddLog_P2(LOG_LEVEL_INFO, PSTR(D_LOG_HTTP D_WEBSERVER_ACTIVE_ON " %s%s " D_WITH_IP_ADDRESS " %s"), + NetworkHostname(), (Wifi.mdns_begun) ? ".local" : "", ipweb.toString().c_str()); #endif // LWIP_IPV6 = 1 rules_flag.http_init = 1; } @@ -1151,7 +1157,7 @@ void WSContentSendStyle_P(const char* formatP, ...) bool lip = (static_cast(WiFi.localIP()) != 0); bool sip = (static_cast(WiFi.softAPIP()) != 0); WSContentSend_P(PSTR("

%s%s (%s%s%s)

"), // tasmota.local (192.168.2.12, 192.168.4.1) - my_hostname, + NetworkHostname(), (Wifi.mdns_begun) ? ".local" : "", (lip) ? WiFi.localIP().toString().c_str() : "", (lip && sip) ? ", " : "", @@ -2471,26 +2477,39 @@ void HandleInformation(void) WSContentSend_P(PSTR("}1" D_FRIENDLY_NAME " %d}2%s"), i +1, SettingsText(SET_FRIENDLYNAME1 +i)); } WSContentSend_P(PSTR("}1}2 ")); // Empty line - int32_t rssi = WiFi.RSSI(); - WSContentSend_P(PSTR("}1" D_AP "%d " D_SSID " (" D_RSSI ")}2%s (%d%%, %d dBm)"), Settings.sta_active +1, SettingsText(SET_STASSID1 + Settings.sta_active), WifiGetRssiAsQuality(rssi), rssi); - WSContentSend_P(PSTR("}1" D_HOSTNAME "}2%s%s"), my_hostname, (Wifi.mdns_begun) ? ".local" : ""); +#ifdef ESP32 +#ifdef USE_ETHERNET + if (static_cast(EthernetLocalIP()) != 0) { + WSContentSend_P(PSTR("}1" D_HOSTNAME "}2%s%s"), EthernetHostname(), (Wifi.mdns_begun) ? ".local" : ""); + WSContentSend_P(PSTR("}1" D_MAC_ADDRESS "}2%s"), EthernetMacAddress().c_str()); + WSContentSend_P(PSTR("}1" D_IP_ADDRESS "}2%s"), EthernetLocalIP().toString().c_str()); + } +#endif +#endif + if (Settings.flag4.network_wifi) { + int32_t rssi = WiFi.RSSI(); + WSContentSend_P(PSTR("}1" D_AP "%d " D_SSID " (" D_RSSI ")}2%s (%d%%, %d dBm)"), Settings.sta_active +1, SettingsText(SET_STASSID1 + Settings.sta_active), WifiGetRssiAsQuality(rssi), rssi); + WSContentSend_P(PSTR("}1" D_HOSTNAME "}2%s%s"), my_hostname, (Wifi.mdns_begun) ? ".local" : ""); #if LWIP_IPV6 String ipv6_addr = WifiGetIPv6(); - if(ipv6_addr != ""){ + if (ipv6_addr != "") { WSContentSend_P(PSTR("}1 IPv6 Address }2%s"), ipv6_addr.c_str()); } #endif - if (static_cast(WiFi.localIP()) != 0) { - WSContentSend_P(PSTR("}1" D_IP_ADDRESS "}2%s"), WiFi.localIP().toString().c_str()); + if (static_cast(WiFi.localIP()) != 0) { + WSContentSend_P(PSTR("}1" D_MAC_ADDRESS "}2%s"), WiFi.macAddress().c_str()); + WSContentSend_P(PSTR("}1" D_IP_ADDRESS "}2%s"), WiFi.localIP().toString().c_str()); + } + } + if (!global_state.network_down) { WSContentSend_P(PSTR("}1" D_GATEWAY "}2%s"), IPAddress(Settings.ip_address[1]).toString().c_str()); WSContentSend_P(PSTR("}1" D_SUBNET_MASK "}2%s"), IPAddress(Settings.ip_address[2]).toString().c_str()); WSContentSend_P(PSTR("}1" D_DNS_SERVER "}2%s"), IPAddress(Settings.ip_address[3]).toString().c_str()); - WSContentSend_P(PSTR("}1" D_MAC_ADDRESS "}2%s"), WiFi.macAddress().c_str()); } if (static_cast(WiFi.softAPIP()) != 0) { + WSContentSend_P(PSTR("}1" D_MAC_ADDRESS "}2%s"), WiFi.softAPmacAddress().c_str()); WSContentSend_P(PSTR("}1" D_IP_ADDRESS "}2%s"), WiFi.softAPIP().toString().c_str()); WSContentSend_P(PSTR("}1" D_GATEWAY "}2%s"), WiFi.softAPIP().toString().c_str()); - WSContentSend_P(PSTR("}1" D_MAC_ADDRESS "}2%s"), WiFi.softAPmacAddress().c_str()); } WSContentSend_P(PSTR("}1}2 ")); // Empty line if (Settings.flag.mqtt_enabled) { // SetOption3 - Enable MQTT @@ -3288,7 +3307,7 @@ void CmndWebServer(void) } if (Settings.webserver) { Response_P(PSTR("{\"" D_CMND_WEBSERVER "\":\"" D_JSON_ACTIVE_FOR " %s " D_JSON_ON_DEVICE " %s " D_JSON_WITH_IP_ADDRESS " %s\"}"), - (2 == Settings.webserver) ? D_ADMIN : D_USER, my_hostname, WiFi.localIP().toString().c_str()); + (2 == Settings.webserver) ? D_ADMIN : D_USER, NetworkHostname(), NetworkAddress().toString().c_str()); } else { ResponseCmndStateText(0); } diff --git a/tasmota/xdrv_02_mqtt.ino b/tasmota/xdrv_02_mqtt.ino index 9e06f4e90..c06cb7dd1 100644 --- a/tasmota/xdrv_02_mqtt.ino +++ b/tasmota/xdrv_02_mqtt.ino @@ -539,10 +539,10 @@ void MqttConnected(void) if (Settings.webserver) { #if LWIP_IPV6 Response_P(PSTR("{\"" D_JSON_WEBSERVER_MODE "\":\"%s\",\"" D_CMND_HOSTNAME "\":\"%s\",\"" D_CMND_IPADDRESS "\":\"%s\",\"IPv6Address\":\"%s\"}"), - (2 == Settings.webserver) ? D_ADMIN : D_USER, my_hostname, WiFi.localIP().toString().c_str(),WifiGetIPv6().c_str()); + (2 == Settings.webserver) ? D_ADMIN : D_USER, NetworkHostname(), NetworkAddress().toString().c_str(), WifiGetIPv6().c_str()); #else Response_P(PSTR("{\"" D_JSON_WEBSERVER_MODE "\":\"%s\",\"" D_CMND_HOSTNAME "\":\"%s\",\"" D_CMND_IPADDRESS "\":\"%s\"}"), - (2 == Settings.webserver) ? D_ADMIN : D_USER, my_hostname, WiFi.localIP().toString().c_str()); + (2 == Settings.webserver) ? D_ADMIN : D_USER, NetworkHostname(), NetworkAddress().toString().c_str()); #endif // LWIP_IPV6 = 1 MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_INFO "2")); } diff --git a/tasmota/xdrv_10_scripter.ino b/tasmota/xdrv_10_scripter.ino index 163419cc8..7fc893ffc 100755 --- a/tasmota/xdrv_10_scripter.ino +++ b/tasmota/xdrv_10_scripter.ino @@ -799,7 +799,7 @@ char *script; IPAddress script_udp_remote_ip; void Script_Init_UDP() { - if (global_state.wifi_down) return; + if (global_state.network_down) return; if (glob_script_mem.udp_flags.udp_connected) return; if (PortUdp.beginMulticast(WiFi.localIP(), IPAddress(239,255,255,250), SCRIPT_UDP_PORT)) { diff --git a/tasmota/xdrv_11_knx.ino b/tasmota/xdrv_11_knx.ino index 47b62547d..f23e896fd 100644 --- a/tasmota/xdrv_11_knx.ino +++ b/tasmota/xdrv_11_knx.ino @@ -1208,7 +1208,7 @@ bool Xdrv11(uint8_t function) bool result = false; switch (function) { case FUNC_LOOP: - if (!global_state.wifi_down) { knx.loop(); } // Process knx events + if (!global_state.network_down) { knx.loop(); } // Process knx events break; case FUNC_EVERY_50_MSECOND: if (toggle_inhibit) { diff --git a/tasmota/xdrv_12_home_assistant.ino b/tasmota/xdrv_12_home_assistant.ino index 7ede88b44..70ab6d620 100644 --- a/tasmota/xdrv_12_home_assistant.ino +++ b/tasmota/xdrv_12_home_assistant.ino @@ -201,7 +201,7 @@ void HAssAnnounceRelayLight(void) uint8_t max_lights = 1; #ifdef ESP8266 - if (PWM_DIMMER == my_module_type) { PwmMod = true; } + if (PWM_DIMMER == my_module_type) { PwmMod = true; } #endif //ESP8266 // If there is a special Light to be enabled and managed with SetOption68 or SetOption37 >= 128, Discovery calculates the maximum number of entities to be generated in advance @@ -719,7 +719,7 @@ void HAssPublishStatus(void) "\"" D_CMND_IPADDRESS "\":\"%s\",\"" D_JSON_RSSI "\":\"%d\",\"" D_JSON_SIGNAL " (dBm)""\":\"%d\"," "\"WiFi " D_JSON_LINK_COUNT "\":%d,\"WiFi " D_JSON_DOWNTIME "\":\"%s\",\"" D_JSON_MQTT_COUNT "\":%d,\"LoadAvg\":%lu}"), my_version, my_image, GetBuildDateAndTime().c_str(), ModuleName().c_str(), GetResetReason().c_str(), - GetUptime().c_str(), my_hostname, WiFi.localIP().toString().c_str(), WifiGetRssiAsQuality(WiFi.RSSI()), + GetUptime().c_str(), NetworkHostname(), WiFi.localIP().toString().c_str(), WifiGetRssiAsQuality(WiFi.RSSI()), WiFi.RSSI(), WifiLinkCount(), WifiDowntime().c_str(), MqttConnectCount(), loop_load_avg); MqttPublishPrefixTopic_P(TELE, PSTR(D_RSLT_HASS_STATE)); } diff --git a/tasmota/xdrv_13_display.ino b/tasmota/xdrv_13_display.ino index 43245c794..20e95eeb1 100644 --- a/tasmota/xdrv_13_display.ino +++ b/tasmota/xdrv_13_display.ino @@ -1013,14 +1013,14 @@ void DisplayLogBufferInit(void) snprintf_P(buffer, sizeof(buffer), PSTR("Display mode %d"), Settings.display_mode); DisplayLogBufferAdd(buffer); - snprintf_P(buffer, sizeof(buffer), PSTR(D_CMND_HOSTNAME " %s"), my_hostname); + snprintf_P(buffer, sizeof(buffer), PSTR(D_CMND_HOSTNAME " %s"), NetworkHostname()); DisplayLogBufferAdd(buffer); - snprintf_P(buffer, sizeof(buffer), PSTR(D_JSON_SSID " %s"), SettingsText(SET_STASSID1 + Settings.sta_active)); + snprintf_P(buffer, sizeof(buffer), PSTR(D_JSON_MAC " %s"), NetworkMacAddress().c_str()); DisplayLogBufferAdd(buffer); - snprintf_P(buffer, sizeof(buffer), PSTR(D_JSON_MAC " %s"), WiFi.macAddress().c_str()); + snprintf_P(buffer, sizeof(buffer), PSTR("IP %s"), NetworkAddress().toString().c_str()); DisplayLogBufferAdd(buffer); if (!global_state.wifi_down) { - snprintf_P(buffer, sizeof(buffer), PSTR("IP %s"), WiFi.localIP().toString().c_str()); + snprintf_P(buffer, sizeof(buffer), PSTR(D_JSON_SSID " %s"), SettingsText(SET_STASSID1 + Settings.sta_active)); DisplayLogBufferAdd(buffer); snprintf_P(buffer, sizeof(buffer), PSTR(D_JSON_RSSI " %d%%"), WifiGetRssiAsQuality(WiFi.RSSI())); DisplayLogBufferAdd(buffer); diff --git a/tasmota/xdrv_82_ethernet.ino b/tasmota/xdrv_82_ethernet.ino new file mode 100644 index 000000000..6d9725332 --- /dev/null +++ b/tasmota/xdrv_82_ethernet.ino @@ -0,0 +1,131 @@ +/* + xdrv_82_ethernet.ino - ESP32 (PoE) ethernet support for Tasmota + + Copyright (C) 2020 Theo Arends + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . +*/ + +#ifdef ESP32 +#ifdef USE_ETHERNET +/*********************************************************************************************\ + * Ethernet support for ESP32 +\*********************************************************************************************/ + +#define XDRV_82 82 + +// Olimex ESP32-PoE +#define ETH_CLK_MODE ETH_CLOCK_GPIO17_OUT +#define ETH_PHY_POWER 12 + +#include + +struct { + char hostname[33]; +} Eth; + +void EthernetEvent(WiFiEvent_t event) { + switch (event) { + case SYSTEM_EVENT_ETH_START: + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("ETH: " D_ATTEMPTING_CONNECTION)); + ETH.setHostname(Eth.hostname); + break; + case SYSTEM_EVENT_ETH_CONNECTED: + AddLog_P2(LOG_LEVEL_INFO, PSTR("ETH: " D_CONNECTED)); + break; + case SYSTEM_EVENT_ETH_GOT_IP: + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("ETH: Mac %s, IPAddress %s, Hostname %s"), + ETH.macAddress().c_str(), ETH.localIP().toString().c_str(), Eth.hostname); +/* + if (ETH.fullDuplex()) { + Serial.print(", FULL_DUPLEX"); + } + Serial.print(", "); + Serial.print(ETH.linkSpeed()); + Serial.println("Mbps"); +*/ + global_state.eth_down = 0; + break; + case SYSTEM_EVENT_ETH_DISCONNECTED: + AddLog_P2(LOG_LEVEL_INFO, PSTR("ETH: Disconnected")); + global_state.eth_down = 1; + break; + case SYSTEM_EVENT_ETH_STOP: + AddLog_P2(LOG_LEVEL_DEBUG, PSTR("ETH: Stopped")); + global_state.eth_down = 1; + break; + default: + break; + } +} + +void EthernetInit(void) { + if (!Settings.flag4.network_ethernet) { return; } + + snprintf_P(Eth.hostname, sizeof(Eth.hostname), PSTR("%s_eth"), my_hostname); + WiFi.onEvent(EthernetEvent); + ETH.begin(); +} + +IPAddress EthernetLocalIP(void) { + return ETH.localIP(); +} + +char* EthernetHostname(void) { + return Eth.hostname; +} + +String EthernetMacAddress(void) { + return ETH.macAddress(); +} + +/*********************************************************************************************\ + * Commands +\*********************************************************************************************/ + +const char kEthernetCommands[] PROGMEM = "|" // No prefix + D_CMND_ETHERNET; + +void (* const EthernetCommand[])(void) PROGMEM = { + &CmndEthernet }; + +void CmndEthernet(void) +{ + if ((XdrvMailbox.payload >= 0) && (XdrvMailbox.payload <= 1)) { + Settings.flag4.network_ethernet = XdrvMailbox.payload; + restart_flag = 2; + } + ResponseCmndStateText(Settings.flag4.network_ethernet); +} + +/*********************************************************************************************\ + * Interface +\*********************************************************************************************/ + +bool Xdrv82(uint8_t function) { + bool result = false; + + switch (function) { + case FUNC_COMMAND: + result = DecodeCommand(kEthernetCommands, EthernetCommand); + break; + case FUNC_INIT: + EthernetInit(); + break; + } + return result; +} + +#endif // USE_ETHERNET +#endif // ESP32 diff --git a/tasmota/xdsp_04_ili9341.ino b/tasmota/xdsp_04_ili9341.ino index f755314c8..f5c485e6f 100644 --- a/tasmota/xdsp_04_ili9341.ino +++ b/tasmota/xdsp_04_ili9341.ino @@ -90,7 +90,11 @@ void Ili9341InitDriver(void) if (Settings.display_height != ILI9341_TFTHEIGHT) { Settings.display_height = ILI9341_TFTHEIGHT; } +#ifdef ESP8266 tft = new Adafruit_ILI9341(Pin(GPIO_SPI_CS), Pin(GPIO_SPI_DC)); +#else // ESP32 + tft = new Adafruit_ILI9341(Pin (GPIO_TFT_CS), Pin (GPIO_TFT_DC), Pin (GPIO_TFT_MOSI), Pin (GPIO_TFT_CLK), Pin (GPIO_TFT_RST), Pin(GPIO_TFT_MISO)); +#endif tft->begin(); #ifdef USE_DISPLAY_MODES1TO5 diff --git a/tools/decode-status.py b/tools/decode-status.py index 2ec5b472e..095e23e71 100755 --- a/tools/decode-status.py +++ b/tools/decode-status.py @@ -209,7 +209,7 @@ a_features = [[ "USE_HP303B","","","", "","","","", "","","","", - "","","","USE_WEBCAM" + "","","USE_ETHERNET","USE_WEBCAM" ]] usage = "usage: decode-status {-d | -f} arg"