diff --git a/tasmota/CHANGELOG.md b/tasmota/CHANGELOG.md index 7e30dc269..f25414319 100644 --- a/tasmota/CHANGELOG.md +++ b/tasmota/CHANGELOG.md @@ -13,6 +13,7 @@ - Add command ``Sensor10 31..254`` to control BH1750 measurement time which defaults to 69 (#8016) - Add command ``SetOption91 1`` to enable fading at startup / power on - Add quick wifi connect using saved AP parameters when ``SetOption56 0`` (#3189) +- Add command ``SetOption41 `` to force sending gratuitous ARP every seconds ### 8.2.0.2 20200328 diff --git a/tasmota/settings.ino b/tasmota/settings.ino index 3bb58ff43..caa87eb05 100644 --- a/tasmota/settings.ino +++ b/tasmota/settings.ino @@ -1298,8 +1298,8 @@ void SettingsDelta(void) Settings.tuya_fnid_map[tuyaindex].dpid = 1; tuyaindex++; } - if (Settings.param[P_ex_TUYA_RELAYS] > 0) { - for (uint8_t i = 0 ; i < Settings.param[P_ex_TUYA_RELAYS]; i++) { // ex SetOption41 + if (Settings.param[P_ARP_GRATUITOUS] > 0) { // Was P_ex_TUYA_RELAYS + for (uint8_t i = 0 ; i < Settings.param[P_ARP_GRATUITOUS]; i++) { // ex SetOption41 Settings.tuya_fnid_map[tuyaindex].fnid = 12 + i; // TUYA_MCU_FUNC_REL2 - Create FnID for Switches Settings.tuya_fnid_map[tuyaindex].dpid = i + 2; tuyaindex++; diff --git a/tasmota/support_tasmota.ino b/tasmota/support_tasmota.ino index ed0355a88..a0a3bacaf 100644 --- a/tasmota/support_tasmota.ino +++ b/tasmota/support_tasmota.ino @@ -814,6 +814,9 @@ void PerformEverySecond(void) } } } + + // Wifi keep alive to send Gratuitous ARP + wifiKeepAlive(); } /*-------------------------------------------------------------------------------------------*\ diff --git a/tasmota/support_wifi.ino b/tasmota/support_wifi.ino index 7e6ed05d2..389a7f8a1 100644 --- a/tasmota/support_wifi.ino +++ b/tasmota/support_wifi.ino @@ -708,3 +708,51 @@ void EspRestart(void) // ESP.restart(); // This results in exception 3 on restarts on core 2.3.0 ESP.reset(); } + +// +// Gratuitous ARP, backported from https://github.com/esp8266/Arduino/pull/6889 +// +extern "C" { +#if LWIP_VERSION_MAJOR == 1 +#include "netif/wlan_lwip_if.h" // eagle_lwip_getif() +#include "netif/etharp.h" // gratuitous arp +#else +#include "lwip/etharp.h" // gratuitous arp +#endif +} + +unsigned long wifiTimer = 0; + +void stationKeepAliveNow(void) { + AddLog_P2(LOG_LEVEL_DEBUG, PSTR(D_LOG_WIFI "Sending Gratuitous ARP")); + for (netif* interface = netif_list; interface != nullptr; interface = interface->next) + if ( + (interface->flags & NETIF_FLAG_LINK_UP) + && (interface->flags & NETIF_FLAG_UP) +#if LWIP_VERSION_MAJOR == 1 + && interface == eagle_lwip_getif(STATION_IF) /* lwip1 does not set if->num properly */ + && (!ip_addr_isany(&interface->ip_addr)) +#else + && interface->num == STATION_IF + && (!ip4_addr_isany_val(*netif_ip4_addr(interface))) +#endif + ) + { + etharp_gratuitous(interface); + break; + } +} + +void wifiKeepAlive(void) { + uint32_t wifiTimerSec = Settings.param[P_ARP_GRATUITOUS]; // 8-bits number of seconds, or minutes if > 100 + + if ((WL_CONNECTED != Wifi.status) || (0 == wifiTimerSec)) { return; } // quick exit if wifi not connected or feature disabled + + if (wifiTimerSec > 100) { + wifiTimerSec = (wifiTimerSec - 100) * 60; // convert >100 as minutes, ex: 105 = 5 minutes, 110 = 10 minutes + } + if (TimeReached(wifiTimer)) { + stationKeepAliveNow(); + SetNextTimeInterval(wifiTimer, wifiTimerSec * 1000); + } +} diff --git a/tasmota/tasmota.h b/tasmota/tasmota.h index 431a116ec..1fa8d89af 100644 --- a/tasmota/tasmota.h +++ b/tasmota/tasmota.h @@ -256,7 +256,7 @@ enum ButtonStates { PRESSED, NOT_PRESSED }; enum Shortcuts { SC_CLEAR, SC_DEFAULT, SC_USER }; enum SettingsParamIndex { P_HOLD_TIME, P_MAX_POWER_RETRY, P_BACKLOG_DELAY, P_MDNS_DELAYED_START, P_BOOT_LOOP_OFFSET, P_RGB_REMAP, P_IR_UNKNOW_THRESHOLD, // SetOption32 .. SetOption38 - P_CSE7766_INVALID_POWER, P_HOLD_IGNORE, P_ex_TUYA_RELAYS, P_OVER_TEMP, // SetOption39 .. SetOption42 + P_CSE7766_INVALID_POWER, P_HOLD_IGNORE, P_ARP_GRATUITOUS, P_OVER_TEMP, // SetOption39 .. SetOption42 P_ex_DIMMER_MAX, P_ex_TUYA_VOLTAGE_ID, P_ex_TUYA_CURRENT_ID, P_ex_TUYA_POWER_ID, // SetOption43 .. SetOption46 P_ex_ENERGY_TARIFF1, P_ex_ENERGY_TARIFF2, // SetOption47 .. SetOption48 P_MAX_PARAM8 }; // Max is PARAM8_SIZE (18) - SetOption32 until SetOption49