From 8921a42f79de4041ab11a70a92d8dc0dd2ebaad9 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Tue, 15 Apr 2025 12:35:55 +0200 Subject: [PATCH 1/3] Add filesystem command ``UfsList[2]`` --- CHANGELOG.md | 1 + RELEASENOTES.md | 1 + .../tasmota_xdrv_driver/xdrv_120_xyzmodem.ino | 1 + .../xdrv_50_filesystem.ino | 99 +++++++++++++++---- 4 files changed, 82 insertions(+), 20 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e5b9cf643..04c1459c5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ All notable changes to this project will be documented in this file. - AlpineJS 2.8.2 - optional for now (#23259) - Support for XMODEM over serial and telnet if enabled with `#define USE_XYZMODEM` - PZEM_AC device address in JSON and GUI (#23268) +- Filesystem command ``UfsList[2]`` ### Breaking Changed - HASPmota added `y2_min` and `y2_max` to control the second series of `chart` (#23287) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 24675a949..63589e8d4 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -116,6 +116,7 @@ The latter links can be used for OTA upgrades too like ``OtaUrl https://ota.tasm ## Changelog v14.5.0.3 ### Added +- Filesystem command ``UfsList[2]`` - Extend command `GPIO` with different display options and allowing updating of module GPIO's in one go - Support Vango Technologies V924x ultralow power, single-phase, power measurement [#23127](https://github.com/arendst/Tasmota/issues/23127) - Support for HLK-LD2402 24GHz smart wave motion sensor [#23133](https://github.com/arendst/Tasmota/issues/23133) diff --git a/tasmota/tasmota_xdrv_driver/xdrv_120_xyzmodem.ino b/tasmota/tasmota_xdrv_driver/xdrv_120_xyzmodem.ino index 33a636721..05a562202 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_120_xyzmodem.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_120_xyzmodem.ino @@ -791,6 +791,7 @@ bool XYZModemLoop(void) { if (millis() > XYZModem.timeout) { XYZModem.timeout = millis() + (2 * 1000); // Protocol 10 second receive timeout - here 2 seconds XYZModemSendNakOrC(); + XYZModem.nak_count--; if (XYZModemReadAvailable(1)) { // Timeout after 1 second XYZModem.nak_count = (XYZModem.oldChecksum) ? 10 : 3; AddLog(LOG_LEVEL_DEBUG, PSTR("XMD: Receive started")); diff --git a/tasmota/tasmota_xdrv_driver/xdrv_50_filesystem.ino b/tasmota/tasmota_xdrv_driver/xdrv_50_filesystem.ino index c144f22c1..ff911f63e 100644 --- a/tasmota/tasmota_xdrv_driver/xdrv_50_filesystem.ino +++ b/tasmota/tasmota_xdrv_driver/xdrv_50_filesystem.ino @@ -373,6 +373,17 @@ uint8_t UfsReject(char *name) { return 0; } +// return true if SDC +bool UfsIsSDC(void) { +#ifndef SDC_HIDE_INVISIBLES + return false; +#else + if (((uint32_t)ufsp != (uint32_t)ffsp) && ((uint32_t)ffsp == (uint32_t)dfsp)) return false; + if (((uint32_t)ufsp == (uint32_t)ffsp) && (ufs_type != UFS_TSDC)) return false; + return true; +#endif +} + /*********************************************************************************************\ * Tfs low level functions \*********************************************************************************************/ @@ -478,8 +489,10 @@ bool TfsDeleteFile(const char *fname) { if (!ffs_type) { return false; } if (!ffsp->remove(fname)) { - AddLog(LOG_LEVEL_INFO, PSTR("TFS: Delete failed")); - return false; + if (!ffsp->rmdir(fname)) { + AddLog(LOG_LEVEL_INFO, PSTR("TFS: Delete failed")); + return false; + } } return true; } @@ -912,7 +925,7 @@ char* UfsFilename(char* fname, char* fname_in) { } const char kUFSCommands[] PROGMEM = "Ufs|" // Prefix - "|Type|Size|Free|Delete|Rename|Run" + "|Type|Size|Free|Delete|Rename|Run|List" #ifdef UFILESYS_STATIC_SERVING "|Serve" #endif @@ -922,7 +935,7 @@ const char kUFSCommands[] PROGMEM = "Ufs|" // Prefix ; void (* const kUFSCommand[])(void) PROGMEM = { - &UFSInfo, &UFSType, &UFSSize, &UFSFree, &UFSDelete, &UFSRename, &UFSRun + &UFSInfo, &UFSType, &UFSSize, &UFSFree, &UFSDelete, &UFSRename, &UFSRun, &UFSList #ifdef UFILESYS_STATIC_SERVING ,&UFSServe #endif @@ -973,7 +986,7 @@ void UFSDelete(void) { if (ffs_type && (ffs_type != ufs_type) && (2 == XdrvMailbox.index)) { result = TfsDeleteFile(fname); } else { - result = (ufs_type && ufsp->remove(fname)); + result = (ufs_type && (ufsp->remove(fname) || ufsp->rmdir(fname))); } if (!result) { ResponseCmndFailed(); @@ -1009,6 +1022,65 @@ void UFSRename(void) { } } +bool UFSListDir(char *path, bool hide_dot) { + bool update = false; + + File dir = dfsp->open(path, UFS_FILE_READ); + if (dir) { + dir.rewindDirectory(); + char *ep; + while (true) { + File entry = dir.openNextFile(); + if (!entry) { + break; + } + // esp32 returns path here, shorten to filename + ep = (char*)entry.name(); + if (*ep == '/') { ep++; } + char *lcp = strrchr(ep,'/'); + if (lcp) { + ep = lcp + 1; + } + if (hide_dot && (*ep == '.')) { continue; } + + // osx formatted disks contain a lot of stuff we dont want + bool hiddable = UfsReject((char*)ep); + if (!hiddable || !UfsIsSDC() ) { + String tstr = ""; + if (!entry.isDirectory()) { // ESP32 does not support isFile() + uint32_t tm = entry.getLastWrite(); + tstr = GetDT(tm); + } + ResponseAppend_P(PSTR("%c[\"%s\",\"%s\",%d]"), (!update)?'[':',', EscapeJSONString(ep).c_str(), tstr.c_str(), entry.size()); + update = true; + entry.close(); + + yield(); // trigger watchdog reset + } + } + dir.close(); + } + return update; +} + +void UFSList(void) { + // UfsList - List all non-dot files and directories in root directory + // UfsList / - List all non-dot files and directories in root directory + // UfsList2 - List all files and directories in root directory + // UfsList /dir1 - List all non-dot files and directories in directory dir1 + bool hide_dot = (XdrvMailbox.index != 2); + strcpy(ufs_path, "/"); + if (XdrvMailbox.data_len > 0) { + strlcpy(ufs_path, XdrvMailbox.data, sizeof(ufs_path)); + } + ResponseCmnd(); + if (UFSListDir(ufs_path, hide_dot)) { + ResponseAppend_P(PSTR("]}")); + } else { + ResponseCmndDone(); + } +} + #ifdef UFILESYS_STATIC_SERVING /* * Serves a filesystem folder at a web url. @@ -1183,8 +1255,6 @@ void UFSRun(void) { } } - - /*********************************************************************************************\ * Web support \*********************************************************************************************/ @@ -1387,7 +1457,7 @@ void UfsDirectory(void) { #ifdef GUI_EDIT_FILE WSContentSend_P(UFS_FORM_FILE_UPGb, ufs_path); #endif - if (!isSDC()) { + if (!UfsIsSDC()) { WSContentSend_P(UFS_FORM_FILE_UPGb1); } WSContentSend_P(UFS_FORM_FILE_UPGb2); @@ -1398,17 +1468,6 @@ void UfsDirectory(void) { Web.upload_file_type = UPL_UFSFILE; } -// return true if SDC -bool isSDC(void) { -#ifndef SDC_HIDE_INVISIBLES - return false; -#else - if (((uint32_t)ufsp != (uint32_t)ffsp) && ((uint32_t)ffsp == (uint32_t)dfsp)) return false; - if (((uint32_t)ufsp == (uint32_t)ffsp) && (ufs_type != UFS_TSDC)) return false; - return true; -#endif -} - void UfsListDir(char *path, uint8_t depth) { char name[48]; char npath[128]; @@ -1462,7 +1521,7 @@ void UfsListDir(char *path, uint8_t depth) { // osx formatted disks contain a lot of stuff we dont want bool hiddable = UfsReject((char*)ep); - if (!hiddable || !isSDC() ) { + if (!hiddable || !UfsIsSDC() ) { for (uint8_t cnt = 0; cnt Date: Tue, 15 Apr 2025 13:21:14 +0200 Subject: [PATCH 2/3] Show network interface priority in 'Status 5' debug logging (#23302) --- CHANGELOG.md | 1 + tasmota/tasmota_support/support_wifi.ino | 9 ++++++--- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 04c1459c5..ddc89392b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ All notable changes to this project will be documented in this file. - Support for XMODEM over serial and telnet if enabled with `#define USE_XYZMODEM` - PZEM_AC device address in JSON and GUI (#23268) - Filesystem command ``UfsList[2]`` +- Show network interface priority in `Status 5` debug logging ### Breaking Changed - HASPmota added `y2_min` and `y2_max` to control the second series of `chart` (#23287) diff --git a/tasmota/tasmota_support/support_wifi.ino b/tasmota/tasmota_support/support_wifi.ino index 0c0c6f692..e4942679c 100644 --- a/tasmota/tasmota_support/support_wifi.ino +++ b/tasmota/tasmota_support/support_wifi.ino @@ -648,15 +648,18 @@ String DNSGetIPStr(uint32_t idx) // #include "lwip/dns.h" +#include "esp_netif_net_stack.h" void WifiDumpAddressesIPv6(void) { for (netif* intf = netif_list; intf != nullptr; intf = intf->next) { - if (!ip_addr_isany_val(intf->ip_addr)) AddLog(LOG_LEVEL_DEBUG, "WIF: '%c%c%i' IPv4 %s", intf->name[0], intf->name[1], intf->num, IPAddress(&intf->ip_addr).toString(true).c_str()); + esp_netif_t *esp_netif = esp_netif_get_handle_from_netif_impl(intf); + int32_t route_prio = esp_netif ? esp_netif_get_route_prio(esp_netif) : -1; + if (!ip_addr_isany_val(intf->ip_addr)) AddLog(LOG_LEVEL_DEBUG, "WIF: '%c%c%i' IPv4 %s (%i)", intf->name[0], intf->name[1], intf->num, IPAddress(&intf->ip_addr).toString(true).c_str(), route_prio); for (uint32_t i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { if (!ip_addr_isany_val(intf->ip6_addr[i])) - AddLog(LOG_LEVEL_DEBUG, "IP : '%c%c%i' IPv6 %s %s", intf->name[0], intf->name[1], intf->num, + AddLog(LOG_LEVEL_DEBUG, "IP : '%c%c%i' IPv6 %s %s (%i)", intf->name[0], intf->name[1], intf->num, IPAddress(&intf->ip6_addr[i]).toString(true).c_str(), - ip_addr_islinklocal(&intf->ip6_addr[i]) ? "local" : ""); + ip_addr_islinklocal(&intf->ip6_addr[i]) ? "local" : "", route_prio); } } AddLog(LOG_LEVEL_DEBUG, "IP : DNS: %s %s", IPAddress(dns_getserver(0)).toString().c_str(), IPAddress(dns_getserver(1)).toString(true).c_str()); From e6918d8b9cd635daf0749fb73e6a10dd6c3e08d5 Mon Sep 17 00:00:00 2001 From: Theo Arends <11044339+arendst@users.noreply.github.com> Date: Wed, 16 Apr 2025 11:35:06 +0200 Subject: [PATCH 3/3] Fix ESP8266 IPv6 compilation --- CHANGELOG.md | 2 +- RELEASENOTES.md | 1 + tasmota/tasmota_support/support_wifi.ino | 13 +++++++++++++ 3 files changed, 15 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ddc89392b..15edc441e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,7 +12,7 @@ All notable changes to this project will be documented in this file. - Support for XMODEM over serial and telnet if enabled with `#define USE_XYZMODEM` - PZEM_AC device address in JSON and GUI (#23268) - Filesystem command ``UfsList[2]`` -- Show network interface priority in `Status 5` debug logging +- ESP32 show network interface priority in `Status 5` debug logging (#23302) ### Breaking Changed - HASPmota added `y2_min` and `y2_max` to control the second series of `chart` (#23287) diff --git a/RELEASENOTES.md b/RELEASENOTES.md index 63589e8d4..bd12c1ca5 100644 --- a/RELEASENOTES.md +++ b/RELEASENOTES.md @@ -125,6 +125,7 @@ The latter links can be used for OTA upgrades too like ``OtaUrl https://ota.tasm - PZEM_AC device address in JSON and GUI [#23268](https://github.com/arendst/Tasmota/issues/23268) - Allow acl in mqtt when client certificate is in use with `#define USE_MQTT_CLIENT_CERT` [#22998](https://github.com/arendst/Tasmota/issues/22998) - AlpineJS 2.8.2 - optional for now [#23259](https://github.com/arendst/Tasmota/issues/23259) +- ESP32 show network interface priority in `Status 5` debug logging [#23302](https://github.com/arendst/Tasmota/issues/23302) - Berry experimental driver for AXP2101 for M5Core2v1.1 [#23039](https://github.com/arendst/Tasmota/issues/23039) - Berry `tasmota.when_network_up()` and simplified Matter using it [#23057](https://github.com/arendst/Tasmota/issues/23057) - Berry `introspect.solidified()` to know if a Berry object is solidified or in RAM [#23063](https://github.com/arendst/Tasmota/issues/23063) diff --git a/tasmota/tasmota_support/support_wifi.ino b/tasmota/tasmota_support/support_wifi.ino index e4942679c..57e737072 100644 --- a/tasmota/tasmota_support/support_wifi.ino +++ b/tasmota/tasmota_support/support_wifi.ino @@ -648,10 +648,13 @@ String DNSGetIPStr(uint32_t idx) // #include "lwip/dns.h" +#ifdef ESP32 #include "esp_netif_net_stack.h" +#endif void WifiDumpAddressesIPv6(void) { for (netif* intf = netif_list; intf != nullptr; intf = intf->next) { +#ifdef ESP32 esp_netif_t *esp_netif = esp_netif_get_handle_from_netif_impl(intf); int32_t route_prio = esp_netif ? esp_netif_get_route_prio(esp_netif) : -1; if (!ip_addr_isany_val(intf->ip_addr)) AddLog(LOG_LEVEL_DEBUG, "WIF: '%c%c%i' IPv4 %s (%i)", intf->name[0], intf->name[1], intf->num, IPAddress(&intf->ip_addr).toString(true).c_str(), route_prio); @@ -661,7 +664,17 @@ void WifiDumpAddressesIPv6(void) IPAddress(&intf->ip6_addr[i]).toString(true).c_str(), ip_addr_islinklocal(&intf->ip6_addr[i]) ? "local" : "", route_prio); } +#else + if (!ip_addr_isany_val(intf->ip_addr)) AddLog(LOG_LEVEL_DEBUG, "WIF: '%c%c%i' IPv4 %s", intf->name[0], intf->name[1], intf->num, IPAddress(&intf->ip_addr).toString(true).c_str()); + for (uint32_t i = 0; i < LWIP_IPV6_NUM_ADDRESSES; i++) { + if (!ip_addr_isany_val(intf->ip6_addr[i])) + AddLog(LOG_LEVEL_DEBUG, "IP : '%c%c%i' IPv6 %s %s", intf->name[0], intf->name[1], intf->num, + IPAddress(&intf->ip6_addr[i]).toString(true).c_str(), + ip_addr_islinklocal(&intf->ip6_addr[i]) ? "local" : ""); + } +#endif } + AddLog(LOG_LEVEL_DEBUG, "IP : DNS: %s %s", IPAddress(dns_getserver(0)).toString().c_str(), IPAddress(dns_getserver(1)).toString(true).c_str()); AddLog(LOG_LEVEL_DEBUG, "WIF: v4IP: %_I v6IP: %s mainIP: %s", (uint32_t) WiFi.localIP(), WifiGetIPv6Str().c_str(), WifiGetIPStr().c_str()); //#if defined(ESP32) && CONFIG_IDF_TARGET_ESP32 && defined(USE_ETHERNET)