diff --git a/tasmota/tasmota.ino b/tasmota/tasmota.ino index 6ba81d416..a8f92e795 100644 --- a/tasmota/tasmota.ino +++ b/tasmota/tasmota.ino @@ -269,11 +269,6 @@ struct TasmotaGlobal_t { GpioOptionABits gpio_optiona; // GPIO Option_A flags void *log_buffer_mutex; // Control access to log buffer -#ifdef CONFIG_ESP_WIFI_REMOTE_ENABLED - char *hosted_ota_url; // ESP32-P4 hosted OTA URL - int hosted_ota_state_flag; // ESP32-P4 hosted OTA initiated flag -#endif // CONFIG_ESP_WIFI_REMOTE_ENABLED - power_t power; // Current copy of Settings->power power_t power_latching; // Current state of single pin latching power power_t rel_inverted; // Relay inverted flag (1 = (0 = On, 1 = Off)) diff --git a/tasmota/tasmota_support/support_command.ino b/tasmota/tasmota_support/support_command.ino index a43c12f86..14bec975e 100644 --- a/tasmota/tasmota_support/support_command.ino +++ b/tasmota/tasmota_support/support_command.ino @@ -22,9 +22,6 @@ const char kTasmotaCommands[] PROGMEM = "|" // No prefix D_SO_WIFINOSLEEP "|" // Other commands D_CMND_UPGRADE "|" D_CMND_UPLOAD "|" D_CMND_OTAURL "|" D_CMND_SERIALLOG "|" D_CMND_RESTART "|" -#ifdef CONFIG_ESP_WIFI_REMOTE_ENABLED - D_CMND_HOSTEDOTA "|" -#endif // CONFIG_ESP_WIFI_REMOTE_ENABLED #ifndef FIRMWARE_MINIMAL D_CMND_BACKLOG "|" D_CMND_DELAY "|" D_CMND_POWER "|" D_CMND_POWERLOCK "|" D_CMND_TIMEDPOWER "|" D_CMND_STATUS "|" D_CMND_STATE "|" D_CMND_SLEEP "|" D_CMND_POWERONSTATE "|" D_CMND_PULSETIME "|" D_CMND_BLINKTIME "|" D_CMND_BLINKCOUNT "|" D_CMND_STATETEXT "|" D_CMND_SAVEDATA "|" @@ -74,9 +71,6 @@ SO_SYNONYMS(kTasmotaSynonyms, void (* const TasmotaCommand[])(void) PROGMEM = { &CmndUpgrade, &CmndUpgrade, &CmndOtaUrl, &CmndSeriallog, &CmndRestart, -#ifdef CONFIG_ESP_WIFI_REMOTE_ENABLED - &CmdHostedOta, -#endif // CONFIG_ESP_WIFI_REMOTE_ENABLED #ifndef FIRMWARE_MINIMAL &CmndBacklog, &CmndDelay, &CmndPower, &CmndPowerLock, &CmndTimedPower, &CmndStatus, &CmndState, &CmndSleep, &CmndPowerOnState, &CmndPulsetime, &CmndBlinktime, &CmndBlinkcount, &CmndStateText, &CmndSavedata, @@ -1341,41 +1335,6 @@ void CmndOtaUrl(void) ResponseCmndChar(SettingsText(SET_OTAURL)); } -#ifdef CONFIG_ESP_WIFI_REMOTE_ENABLED -void CmdHostedOta() { - /* - If OtaUrl = "https://ota.tasmota.com/tasmota32/tasmota32p4.bin" - Then use "https://ota.tasmota.com/tasmota32/coprocessor/network_adapter_" CONFIG_ESP_HOSTED_IDF_SLAVE_TARGET ".bin" - As an option allow user to enter URL like: - HostedOta https://ota.tasmota.com/tasmota32/coprocessor/network_adapter_esp32c6.bin - HostedOta https://ota.tasmota.com/tasmota32/coprocessor/v2.0.14/network_adapter_esp32c6.bin - Or allow user to enter required version like: - HostedOta v2.0.17 - */ - TasmotaGlobal.hosted_ota_url = (char*)calloc(200, sizeof(char)); - if (!TasmotaGlobal.hosted_ota_url) { return; } // Unable to allocate memory - if (XdrvMailbox.data_len > 15) { - strlcpy(TasmotaGlobal.hosted_ota_url, XdrvMailbox.data, 200); - } else { - // Replace https://ota.tasmota.com/tasmota32/tasmota32p4.bin with https://ota.tasmota.com/tasmota32/coprocessor/network_adapter_esp32c6.bin - char ota_url[TOPSZ]; - strlcpy(TasmotaGlobal.hosted_ota_url, GetOtaUrl(ota_url, sizeof(ota_url)), 200); - char *bch = strrchr(TasmotaGlobal.hosted_ota_url, '/'); // Only consider filename after last backslash - if (bch == nullptr) { bch = TasmotaGlobal.hosted_ota_url; } // No path found so use filename only - *bch = '\0'; // full_ota_url = https://ota.tasmota.com/tasmota32 - char version[16] = { 0 }; - if (XdrvMailbox.data_len) { - snprintf_P(version, sizeof(version), PSTR("/%s"), XdrvMailbox.data); - } - snprintf_P(TasmotaGlobal.hosted_ota_url, 200, PSTR("%s/coprocessor%s/network_adapter_" CONFIG_ESP_HOSTED_IDF_SLAVE_TARGET ".bin"), - TasmotaGlobal.hosted_ota_url, version); - } - TasmotaGlobal.hosted_ota_state_flag = 1; - Response_P(PSTR("{\"%s\":\"" D_JSON_VERSION " %s " D_JSON_FROM " %s\"}"), - XdrvMailbox.command, GetHostedMCUFwVersion().c_str(), TasmotaGlobal.hosted_ota_url); -} -#endif // CONFIG_ESP_WIFI_REMOTE_ENABLED - void CmndSeriallog(void) { if ((XdrvMailbox.payload >= LOG_LEVEL_NONE) && (XdrvMailbox.payload <= LOG_LEVEL_DEBUG_MORE)) { diff --git a/tasmota/tasmota_support/support_hosted_mcu.ino b/tasmota/tasmota_support/support_hosted_mcu.ino deleted file mode 100644 index f31fda743..000000000 --- a/tasmota/tasmota_support/support_hosted_mcu.ino +++ /dev/null @@ -1,104 +0,0 @@ -/* - support_hosted_mcu.ino - eeprom support for Tasmota - - Copyright (C) 2025 Theo Arends & Christian Baars - - 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 CONFIG_ESP_WIFI_REMOTE_ENABLED - -#include "esp_hosted.h" -#include "esp_hosted_api_types.h" -#include "esp_hosted_ota.h" - -String GetHostedMCU(void) { - // Function is not yet implemented in Arduino Core so emulate it here - if (0 == strcasecmp_P(CONFIG_ESP_HOSTED_IDF_SLAVE_TARGET, PSTR("esp32c6"))) { - return String("ESP32-C6"); - } - return String("Unknown"); -} - -int GetFwVersionNumber(void) { - // Function is not yet implemented in Arduino Core so emulate it here - return 0x0200000E; // v2.0.14 -} - -int GetHostedMCUFwVersionNumber(void) { - static int version = -1; - - if (!esp_hosted_is_config_valid()) { - return 0; - } - if (-1 == version) { - version = 6; // v0.0.6 - esp_hosted_coprocessor_fwver_t ver_info; - esp_err_t err = esp_hosted_get_coprocessor_fwversion(&ver_info); // This takes almost 4 seconds on > 24; - uint8_t minor1 = version >> 16; - uint16_t patch1 = version; - char data[40]; - snprintf_P(data, sizeof(data), PSTR("%d.%d.%d"), major1, minor1, patch1); - return String(data); -} - -int OTAHostedMCU(const char* image_url) { - AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("HST: About to OTA update with %s"), image_url); - int result = esp_hosted_slave_ota(image_url); - AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("HST: Done with result %d"), result); - return result; -} - -void HostedMCUStatus(void) { - // Execute after HostedMCU is init by WiFi.mode() - static bool once_shown = false; - - if (once_shown) { return; } - if (esp_hosted_is_config_valid()) { - once_shown = true; - char config[128] = { 0 }; - struct esp_hosted_transport_config *pconfig; - if (ESP_TRANSPORT_OK == esp_hosted_transport_get_config(&pconfig)) { - if (pconfig->transport_in_use == H_TRANSPORT_SDIO) { - struct esp_hosted_sdio_config *psdio_config; - if (ESP_TRANSPORT_OK == esp_hosted_sdio_get_config(&psdio_config)) { - snprintf_P(config, sizeof(config), PSTR(" using GPIO%02d(CLK), GPIO%02d(CMD), GPIO%02d(D0), GPIO%02d(D1), GPIO%02d(D2), GPIO%02d(D3) and GPIO%02d(RST)"), - psdio_config->pin_clk.pin, psdio_config->pin_cmd.pin, psdio_config->pin_d0.pin, psdio_config->pin_d1.pin, psdio_config->pin_d2.pin, psdio_config->pin_d3.pin, psdio_config->pin_reset.pin); - } - } - } - AddLog(LOG_LEVEL_INFO, PSTR("HST: Hosted MCU %s v%s%s"), - GetHostedMCU().c_str(), GetHostedMCUFwVersion().c_str(), config); - } -} - -#endif // CONFIG_ESP_WIFI_REMOTE_ENABLED \ No newline at end of file diff --git a/tasmota/tasmota_support/support_tasmota.ino b/tasmota/tasmota_support/support_tasmota.ino index 39cf3d58a..33f961e28 100644 --- a/tasmota/tasmota_support/support_tasmota.ino +++ b/tasmota/tasmota_support/support_tasmota.ino @@ -1517,34 +1517,6 @@ void Every250mSeconds(void) AllowInterrupts(1); } } - -#ifdef CONFIG_ESP_WIFI_REMOTE_ENABLED - if (TasmotaGlobal.hosted_ota_state_flag && CommandsReady()) { - TasmotaGlobal.hosted_ota_state_flag--; -/* - if (2 == TasmotaGlobal.hosted_ota_state_flag) { - SettingsSave(0); - } -*/ - if (TasmotaGlobal.hosted_ota_state_flag <= 0) { - // Blocking - int ret = OTAHostedMCU(TasmotaGlobal.hosted_ota_url); - free(TasmotaGlobal.hosted_ota_url); - TasmotaGlobal.hosted_ota_url = nullptr; - Response_P(PSTR("{\"" D_CMND_HOSTEDOTA "\":\"")); - if (ret == ESP_OK) { - // next lines are questionable, because currently the system will reboot immediately on succesful upgrade - ResponseAppend_P(PSTR(D_JSON_SUCCESSFUL ". " D_JSON_RESTARTING)); - TasmotaGlobal.restart_flag = 5; // Allow time for webserver to update console - } else { - ResponseAppend_P(PSTR(D_JSON_FAILED " %d\"}"), ret); - } - ResponseAppend_P(PSTR("\"}")); - MqttPublishPrefixTopicRulesProcess_P(STAT, PSTR(D_CMND_HOSTEDOTA)); - } - } -#endif // CONFIG_ESP_WIFI_REMOTE_ENABLED - break; case 1: // Every x.25 second if (MidnightNow()) { diff --git a/tasmota/tasmota_xdrv_driver/xdrv_84_esp32_hosted.ino b/tasmota/tasmota_xdrv_driver/xdrv_84_esp32_hosted.ino new file mode 100644 index 000000000..d16c43b4d --- /dev/null +++ b/tasmota/tasmota_xdrv_driver/xdrv_84_esp32_hosted.ino @@ -0,0 +1,193 @@ +/* + xdrv_84_esp32_hosted.ino - ESP32 Hosted MCU support for Tasmota + + SPDX-FileCopyrightText: 2025 Theo Arends + + SPDX-License-Identifier: GPL-3.0-only +*/ + +#ifdef ESP32 +#ifdef CONFIG_ESP_WIFI_REMOTE_ENABLED +/*********************************************************************************************\ + * Support for Hosted MCU to be used on ESP32-H2 and ESP32-P4 +\*********************************************************************************************/ + +#define XDRV_84 84 + +#include "esp_hosted.h" +#include "esp_hosted_api_types.h" +#include "esp_hosted_ota.h" + +struct Hosted_t { + char *hosted_ota_url; // Hosted MCU OTA URL + int hosted_ota_state_flag; // Hosted MCU OTA initiated flag +} Hosted; + +/*********************************************************************************************/ + +String GetHostedMCU(void) { + // Function is not yet implemented in Arduino Core so emulate it here + if (0 == strcasecmp_P(CONFIG_ESP_HOSTED_IDF_SLAVE_TARGET, PSTR("esp32c6"))) { + return String("ESP32-C6"); + } + return String("Unknown"); +} + +int GetFwVersionNumber(void) { + // Function is not yet implemented in Arduino Core so emulate it here + return 0x0200000E; // v2.0.14 +} + +int GetHostedMCUFwVersionNumber(void) { + static int version = -1; + + if (!esp_hosted_is_config_valid()) { + return 0; + } + if (-1 == version) { + version = 6; // v0.0.6 + esp_hosted_coprocessor_fwver_t ver_info; + esp_err_t err = esp_hosted_get_coprocessor_fwversion(&ver_info); // This takes almost 4 seconds on > 24; + uint8_t minor1 = version >> 16; + uint16_t patch1 = version; + char data[40]; + snprintf_P(data, sizeof(data), PSTR("%d.%d.%d"), major1, minor1, patch1); + return String(data); +} + +void HostedMCUStatus(void) { + // Execute after HostedMCU is init by WiFi.mode() + static bool once_shown = false; + + if (once_shown) { return; } + if (esp_hosted_is_config_valid()) { + once_shown = true; + char config[128] = { 0 }; + struct esp_hosted_transport_config *pconfig; + if (ESP_TRANSPORT_OK == esp_hosted_transport_get_config(&pconfig)) { + if (pconfig->transport_in_use == H_TRANSPORT_SDIO) { + struct esp_hosted_sdio_config *psdio_config; + if (ESP_TRANSPORT_OK == esp_hosted_sdio_get_config(&psdio_config)) { + snprintf_P(config, sizeof(config), PSTR(" using GPIO%02d(CLK), GPIO%02d(CMD), GPIO%02d(D0), GPIO%02d(D1), GPIO%02d(D2), GPIO%02d(D3) and GPIO%02d(RST)"), + psdio_config->pin_clk.pin, psdio_config->pin_cmd.pin, psdio_config->pin_d0.pin, psdio_config->pin_d1.pin, psdio_config->pin_d2.pin, psdio_config->pin_d3.pin, psdio_config->pin_reset.pin); + } + } + } + AddLog(LOG_LEVEL_INFO, PSTR("HST: Hosted MCU %s v%s%s"), + GetHostedMCU().c_str(), GetHostedMCUFwVersion().c_str(), config); + } +} + +/*********************************************************************************************\ + * Every second +\*********************************************************************************************/ + +void HostedMCUEverySecond(void) { + if (Hosted.hosted_ota_state_flag && CommandsReady()) { + Hosted.hosted_ota_state_flag--; +/* + if (2 == Hosted.hosted_ota_state_flag) { + SettingsSave(0); + } +*/ + if (Hosted.hosted_ota_state_flag <= 0) { + // Blocking + AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("HST: About to OTA update with %s"), Hosted.hosted_ota_url); + int ret = esp_hosted_slave_ota(Hosted.hosted_ota_url); + AddLog(LOG_LEVEL_DEBUG_MORE, PSTR("HST: Done with result %d"), ret); + free(Hosted.hosted_ota_url); + Hosted.hosted_ota_url = nullptr; + Response_P(PSTR("{\"" D_CMND_HOSTEDOTA "\":\"")); + if (ret == ESP_OK) { + // next lines are questionable, because currently the system will reboot immediately on succesful upgrade + ResponseAppend_P(PSTR(D_JSON_SUCCESSFUL ". " D_JSON_RESTARTING)); + TasmotaGlobal.restart_flag = 5; // Allow time for webserver to update console + } else { + ResponseAppend_P(PSTR(D_JSON_FAILED " %d\"}"), ret); + } + ResponseAppend_P(PSTR("\"}")); + MqttPublishPrefixTopicRulesProcess_P(STAT, PSTR(D_CMND_HOSTEDOTA)); + } + } +} + +/*********************************************************************************************\ + * Commands +\*********************************************************************************************/ + +const char kHostedCommands[] PROGMEM = "Hosted|" // Prefix + "Ota"; + +void (* const HostedCommand[])(void) PROGMEM = { + &CmndHostedOta }; + +void CmndHostedOta(void) { + /* + If OtaUrl = "https://ota.tasmota.com/tasmota32/tasmota32p4.bin" + Then use "https://ota.tasmota.com/tasmota32/coprocessor/network_adapter_" CONFIG_ESP_HOSTED_IDF_SLAVE_TARGET ".bin" + As an option allow user to enter URL like: + HostedOta https://ota.tasmota.com/tasmota32/coprocessor/network_adapter_esp32c6.bin + HostedOta https://ota.tasmota.com/tasmota32/coprocessor/v2.0.14/network_adapter_esp32c6.bin + Or allow user to enter required version like: + HostedOta v2.0.17 + */ + Hosted.hosted_ota_url = (char*)calloc(200, sizeof(char)); + if (!Hosted.hosted_ota_url) { return; } // Unable to allocate memory + if (XdrvMailbox.data_len > 15) { + strlcpy(Hosted.hosted_ota_url, XdrvMailbox.data, 200); + } else { + // Replace https://ota.tasmota.com/tasmota32/tasmota32p4.bin with https://ota.tasmota.com/tasmota32/coprocessor/network_adapter_esp32c6.bin + char ota_url[TOPSZ]; + strlcpy(Hosted.hosted_ota_url, GetOtaUrl(ota_url, sizeof(ota_url)), 200); + char *bch = strrchr(Hosted.hosted_ota_url, '/'); // Only consider filename after last backslash + if (bch == nullptr) { bch = Hosted.hosted_ota_url; } // No path found so use filename only + *bch = '\0'; // full_ota_url = https://ota.tasmota.com/tasmota32 + char version[16] = { 0 }; + if (XdrvMailbox.data_len) { + snprintf_P(version, sizeof(version), PSTR("/%s"), XdrvMailbox.data); + } + snprintf_P(Hosted.hosted_ota_url, 200, PSTR("%s/coprocessor%s/network_adapter_" CONFIG_ESP_HOSTED_IDF_SLAVE_TARGET ".bin"), + Hosted.hosted_ota_url, version); + } + Hosted.hosted_ota_state_flag = 1; + Response_P(PSTR("{\"%s\":\"" D_JSON_VERSION " %s " D_JSON_FROM " %s\"}"), + XdrvMailbox.command, GetHostedMCUFwVersion().c_str(), Hosted.hosted_ota_url); +} + +/*********************************************************************************************\ + * Interface +\*********************************************************************************************/ + +bool Xdrv84(uint32_t function) { + bool result = false; + + switch (function) { + case FUNC_EVERY_SECOND: + HostedMCUEverySecond(); + break; + case FUNC_COMMAND: + result = DecodeCommand(kHostedCommands, HostedCommand); + break; + } + return result; +} + +#endif // CONFIG_ESP_WIFI_REMOTE_ENABLED +#endif // ESP32 \ No newline at end of file