From 60d99d099b3098b5dda3af12d6968951f369cf88 Mon Sep 17 00:00:00 2001 From: mikecarper Date: Fri, 31 Jul 2026 16:01:07 -0700 Subject: [PATCH] Restore WiFi OTA to lean ESP32 builds --- build.sh | 48 ++++++++++++++++++++++++++++---- docs/WiFi.md | 4 +-- docs/cli_build_matrix.md | 2 +- docs/cli_command_availability.md | 2 +- docs/ota_easy.md | 6 ++-- docs/ota_protocol.md | 18 +++++++----- 6 files changed, 61 insertions(+), 19 deletions(-) diff --git a/build.sh b/build.sh index 42f244b78..8482fefd0 100755 --- a/build.sh +++ b/build.sh @@ -3,6 +3,7 @@ ALL_PIO_ENVS=() SUPPORTED_PIO_ENVS=() declare -A PIO_ENV_PLATFORM_BY_NAME=() +declare -A PIO_ENV_BOARD_BY_NAME=() declare -A PIO_ENV_MQTT_BY_NAME=() declare -A PIO_ENV_OTA_BY_NAME=() declare -A PIO_ENV_BUILD_BASE_BY_NAME=() @@ -165,12 +166,13 @@ init_project_context() { fi if [ ${#SUPPORTED_PIO_ENVS[@]} -eq 0 ]; then - while IFS=$'\t' read -r env_name env_platform env_mqtt env_ota env_full env_full_wifi; do + while IFS=$'\t' read -r env_name env_platform env_mqtt env_ota env_full env_full_wifi env_board; do if [ -z "$env_name" ] || [ -z "$env_platform" ]; then continue fi SUPPORTED_PIO_ENVS+=("$env_name") PIO_ENV_PLATFORM_BY_NAME["$env_name"]=$env_platform + PIO_ENV_BOARD_BY_NAME["$env_name"]=$env_board PIO_ENV_MQTT_BY_NAME["$env_name"]=$env_mqtt PIO_ENV_OTA_BY_NAME["$env_name"]=$env_ota PIO_ENV_FULL_BUILD_BY_NAME["$env_name"]=$env_full @@ -193,9 +195,13 @@ for section, options in data: admin_enabled = False espnow_enabled = "bridge_espnow" in env_name.lower() full_wifi_ota = False + board = None platform = None for key, value in options: values = value if isinstance(value, list) else str(value).split() + if key == "board": + board = str(value) + continue if key == "lib_deps": full_wifi_ota = any("AsyncElegantOTA" in str(item) for item in values) continue @@ -218,10 +224,12 @@ for section, options in data: full_enabled = platform == "ESP32_PLATFORM" and ( mqtt_enabled or espnow_enabled or admin_enabled ) + board_value = board or "-" print( f"{env_name}\t{platform}\t{1 if mqtt_enabled else 0}" f"\t{1 if ota_enabled and not ota_disabled else 0}" f"\t{1 if full_enabled else 0}\t{1 if full_wifi_ota else 0}" + f"\t{board_value}" ) ' "$SUPPORTED_PLATFORM_PATTERN" <<<"$PIO_CONFIG_JSON" ) @@ -250,6 +258,7 @@ for section, options in data: fi SUPPORTED_PIO_ENVS+=("$ota_env") PIO_ENV_PLATFORM_BY_NAME["$ota_env"]="${PIO_ENV_PLATFORM_BY_NAME[$env_name]}" + PIO_ENV_BOARD_BY_NAME["$ota_env"]="${PIO_ENV_BOARD_BY_NAME[$env_name]}" PIO_ENV_MQTT_BY_NAME["$ota_env"]=0 PIO_ENV_OTA_BY_NAME["$ota_env"]=1 PIO_ENV_FULL_BUILD_BY_NAME["$ota_env"]=0 @@ -1782,6 +1791,26 @@ requires_esp32_portable_app_slot() { && ! is_esp32_companion_build "$1" } +is_esp32_c6_target() { + [[ "${PIO_ENV_BOARD_BY_NAME[$1]:-}" == esp32-c6-* ]] +} + +requires_esp32_portable_size_ceiling() { + local env_name=$1 + + requires_esp32_portable_app_slot "$env_name" || return 1 + + # Arduino 3.x pulls substantially more WiFi runtime into ESP32-C6 images. + # These target-specific OTA siblings already used 1920 KiB or larger A/B app + # slots before the compact browser uploader was enabled, so retain their + # established partition contract and enforce the actual partition below. + if is_lora_ota_only_target "$env_name" && is_esp32_c6_target "$env_name"; then + return 1 + fi + + return 0 +} + supports_esp32_full_build() { local env_name=$1 @@ -1803,10 +1832,11 @@ apply_esp32_lora_ota_size_profile() { # All non-companion ESP32 artifacts must remain installable into the legacy # 0x10000..0x150000 app slot. The WebConfig portal is deliberately omitted. - # WiFi/MQTT observers retain their small WiFi updater, while radio-only roles - # avoid linking WiFi solely for that updater. Companions retain their target - # defaults because they are installed over USB. Keep ENV_INCLUDE_GPS for - # boards with onboard GPS; their target sensor managers require that support. + # WiFi/MQTT observers and lean LoRa-OTA repeaters retain the compact browser + # updater; other radio-only roles avoid linking WiFi solely for that updater. + # Companions retain their target defaults because they are installed over USB. + # Keep ENV_INCLUDE_GPS for boards with onboard GPS; their target sensor + # managers require that support. export PLATFORMIO_BUILD_FLAGS="${PLATFORMIO_BUILD_FLAGS} -DWEBCONFIG_DISABLED=1" if is_mqtt_bridge_target "$env_name"; then # Keep the standard ESP-IDF libc. Use its ABI with the chip-ROM formatter, @@ -1827,6 +1857,12 @@ apply_esp32_lora_ota_size_profile() { export PLATFORMIO_BUILD_FLAGS="${PLATFORMIO_BUILD_FLAGS} -DPORTABLE_ESP32_ROM_NANO_FORMAT=1" fi append_platformio_build_unflags "-DDISPLAY_CLASS=SSD1306Display -DENV_INCLUDE_AHTX0=1 -DENV_INCLUDE_BME280=1 -DENV_INCLUDE_BMP280=1 -DENV_INCLUDE_SHTC3=1 -DENV_INCLUDE_SHT4X=1 -DENV_INCLUDE_LPS22HB=1 -DENV_INCLUDE_INA3221=1 -DENV_INCLUDE_INA219=1 -DENV_INCLUDE_INA226=1 -DENV_INCLUDE_INA260=1 -DENV_INCLUDE_MLX90614=1 -DENV_INCLUDE_VL53L0X=1 -DENV_INCLUDE_BME680=1 -DENV_INCLUDE_BMP085=1 -DENV_INCLUDE_RAK12035=1 -DENV_INCLUDE_BME680_BSEC=1" + elif is_lora_ota_only_target "$env_name"; then + # The no-external-sensors image is also the self-updatable field image. Keep + # manual browser OTA available on every ESP32 family through the compact + # uploader, and use the full one-byte neighbor-index range. + append_platformio_build_unflags "-DDISABLE_WIFI_OTA=1 -DMAX_NEIGHBOURS=50 -DMAX_NEIGHBOURS=8" + export PLATFORMIO_BUILD_FLAGS="${PLATFORMIO_BUILD_FLAGS} -UDISABLE_WIFI_OTA -DLIGHTWEIGHT_WIFI_OTA=1 -DMAX_NEIGHBOURS=${ESP32_FULL_MAX_NEIGHBOURS}" else append_platformio_build_unflags "-DLIGHTWEIGHT_WIFI_OTA=1" export PLATFORMIO_BUILD_FLAGS="${PLATFORMIO_BUILD_FLAGS} -ULIGHTWEIGHT_WIFI_OTA -DDISABLE_WIFI_OTA=1" @@ -1990,7 +2026,7 @@ collect_esp32_artifacts() { ) local partsig_name=$env_name - if [ "$ESP32_FULL_BUILD" != "1" ] && requires_esp32_portable_app_slot "$env_name"; then + if [ "$ESP32_FULL_BUILD" != "1" ] && requires_esp32_portable_size_ceiling "$env_name"; then size_check_args+=("$ESP32_LORA_OTA_APP_LIMIT") fi diff --git a/docs/WiFi.md b/docs/WiFi.md index c39ad8acf..ea5917330 100644 --- a/docs/WiFi.md +++ b/docs/WiFi.md @@ -32,7 +32,7 @@ to MQTT unless its target name also contains `mqtt`. | Ethernet repeater/room server | No WiFi | No | Uses wired Ethernet for its role-specific network interface | | `*_sensor` | Build-dependent on ESP32 | No | A FULL ESP32 sensor can expose the TCP 5001 LoRa-OTA seeder through its browser-OTA setup AP | | Terminal-chat or KISS modem | No in current targets | No | Uses LoRa and its role-specific local interface | -| `*_lora_ota_no_external_sensors` | No | No | Lean repeater image for receiving firmware over LoRa | +| `*_lora_ota_no_external_sensors` | On demand on ESP32 | No | Lean LoRa-OTA repeater image; ESP32 builds retain the compact `start ota` browser uploader | Direct on-device WiFi and MQTT are currently ESP32 features. nRF52, STM32, and the currently enabled RP2040 targets do not run this MQTT bridge. An nRF52 @@ -337,7 +337,7 @@ role. | MQTT | Builds explicit MQTT observer or WiFi-companion-MQTT targets with USB packet logging off. | | FULL ESP32 | Uses the board's MQTT target with logging off, expanded dual-OTA partitions, 254 neighbors, LoRa OTA, and full-size ESP32 features such as WebConfig where supported. | | FULL ESP32 logging | Uses the board's non-MQTT target with debug and packet logging enabled, expanded dual-OTA partitions, 254 neighbors, and LoRa OTA. | -| LoRa-OTA no-external-sensors | A small radio-only repeater image; no WiFi or MQTT. | +| LoRa-OTA no-external-sensors | A lean repeater image with no MQTT; ESP32 builds retain the compact on-demand browser WiFi uploader and 254 neighbors. | The interactive Option 1 **FULL everything** choice selects the FULL logging profile: logging is enabled and MQTT is disabled. The standalone FULL ESP32 diff --git a/docs/cli_build_matrix.md b/docs/cli_build_matrix.md index 2b486e1ba..c03b27f6f 100644 --- a/docs/cli_build_matrix.md +++ b/docs/cli_build_matrix.md @@ -33,7 +33,7 @@ administrator. |---|---| | Standard non-MQTT repeater or room server | Keeps the normal role CLI. Size-constrained ESP32 artifacts can omit WebConfig and browser WiFi OTA, so their WebConfig/WiFi commands are unavailable. | | Standard logging | Logging does not remove commands by itself. It has the same CLI as the selected role/profile and adds the compiled logging behavior. | -| LoRa-OTA (`-ota-`) | LoRa OTA adds the `ota ...` commands; it does not otherwise reduce the role CLI. A portable OTA artifact can still have the portable restrictions described below. | +| LoRa-OTA (`-ota-`) | LoRa OTA adds the `ota ...` commands; it does not otherwise reduce the role CLI. ESP32 `no_external_sensors` artifacts retain the compact browser WiFi uploader and use a 254-entry neighbor table. A portable OTA artifact can still have the other portable restrictions described below. | | Portable MQTT observer | Keeps MQTT/WiFi commissioning, bridge control, radio essentials, update commands, basic identity/status commands, `neighbors`, `discover.neighbors`, `outpath`, and `altpath`. The large repeater administration tree is omitted to fit the legacy ESP32 application slot. | | Portable ESP-NOW bridge | Keeps the repeater's role-specific handlers and a reduced common configuration surface containing radio and bridge essentials, including `rxdelay`, `txdelay`, `outpath`, and `altpath`. | | FULL ESP32 | Uses the matching MQTT target with logging off, removes size-based CLI cuts, and restores the complete command surface supported by that role and hardware. | diff --git a/docs/cli_command_availability.md b/docs/cli_command_availability.md index ab762062e..36db2626d 100644 --- a/docs/cli_command_availability.md +++ b/docs/cli_command_availability.md @@ -312,7 +312,7 @@ fix, no WiFi connection, an inactive bridge, or an nRF52 bootloader without | Board | [`get bootloader.ver`](cli_commands.md#view-the-bootloader-version-nrf52-only) | nRF52 only | No | No | No | No | No | No | No | | Board | [`get pwrmgt.support`; `get pwrmgt.source`; `get pwrmgt.bootreason`; `get pwrmgt.bootmv`](nrf52_power_management.md#cli-commands) | nRF52 only | No | No | No | No | No | No | No | | Ethernet | [`eth.status`](cli_commands.md#view-ethernet-connection-status) | Ethernet target | Feature | Feature | No | No | No | No | Feature | -| Browser OTA | [`start ota [ap]`; `stop ota`](cli_commands.md#start-or-stop-an-over-the-air-ota-firmware-update) | Compiled browser uploader | No | No | No | Yes | No | Feature | Feature | +| Browser OTA | [`start ota [ap]`; `stop ota`](cli_commands.md#start-or-stop-an-over-the-air-ota-firmware-update) | Compiled browser uploader | No | No | Yes | Yes | No | Feature | Feature | | WebConfig | [`start webconfig [ap]`; `stop webconfig`; `get/set webui`](cli_commands.md#browser-configuration-portal-esp32-repeater-and-room-server) | Compiled WebConfig | No | No | No | No | No | Feature | Feature | | WiFi | [`get/set wifi.ssid`; `set wifi.pwd`; `get wifi.status`; `get/set wifi.powersave`](../MQTT_IMPLEMENTATION.md#wifi-commands) | MQTT WiFi, or standalone FULL WebConfig; standalone has no `get wifi.pwd` | No | No | No | Yes | No | Yes | Feature | | WiFi | [`get/set wifi.cli`](cli_commands.md#browser-configuration-portal-esp32-repeater-and-room-server) | Compiled WebConfig | No | No | No | No | No | Feature | Feature | diff --git a/docs/ota_easy.md b/docs/ota_easy.md index 94eab2b8e..3d446f6a3 100644 --- a/docs/ota_easy.md +++ b/docs/ota_easy.md @@ -55,8 +55,10 @@ overlapping window. repeater target. The normal repeater build keeps its external-sensor support and can serve as an intermediate OTA relay, but it cannot download or install an update for itself. The `-ota-` sibling omits optional external I2C environmental sensors to preserve the update workspace, while retaining board-native features such as its -display, buttons, battery monitoring, and integrated GPS. RP2040 and STM32 repeaters do not currently have a -safe self-apply path, but current repeater firmware can still relay OTA packets opaquely during TempRadio. +display, buttons, battery monitoring, and integrated GPS. ESP32 `-ota-` siblings also retain the compact +browser WiFi uploader (`start ota`) and use a 254-entry neighbor table. RP2040 and STM32 repeaters do not +currently have a safe self-apply path, but current repeater firmware can still relay OTA packets opaquely +during TempRadio. ESP32 `*-full-ota-*` artifacts retain all compiled features and enable LoRa OTA for every FULL role, including room servers, sensors, observers, and bridges. A FULL image requires its expanded partition table: diff --git a/docs/ota_protocol.md b/docs/ota_protocol.md index cbae222a5..bf7affe8c 100644 --- a/docs/ota_protocol.md +++ b/docs/ota_protocol.md @@ -112,15 +112,19 @@ LoRa OTA and carry `-ota-` in their filenames so they can seed a host folder ove their target partition table rather than using the FULL profile. A small set of high-capacity classic ESP32 companions cannot combine their configured contact, group-channel, and offline-queue capacities with LoRa OTA in internal DRAM. Their normal artifacts remain unchanged, and option 3 also emits `-full-ota-` and -`-full-logging-ota-` variants with 100 contacts, 8 group channels, and a 16-frame offline queue. Every other -ESP32 artifact, including room, +`-full-logging-ota-` variants with 100 contacts, 8 group channels, and a 16-frame offline queue. Except for +the ESP32-C6 case below, every other ESP32 artifact, including room, sensor, and repeater roles, must fit the legacy slot from `0x10000` up to `0x150000` (`0x140000`, 1,310,720 bytes), including the 56-byte `EndF` trailer. The build checks both that -limit and the target's actual app partition. For every standalone ESP32 and nRF52 repeater, `build.sh` also -exposes an explicit `*_lora_ota_no_external_sensors` artifact: the ordinary repeater remains sensor-enabled, -while that sibling disables optional external environmental-sensor drivers for LoRa distribution. Integrated -GPS and other board-native telemetry remain enabled. RP2040 and STM32 targets are not offered because those -platforms do not yet have a safe bootloader/apply path. +limit and the target's actual app partition. The ESP32-C6 `no_external_sensors` OTA siblings are the narrow +exception: the Arduino 3.x WiFi runtime cannot fit that cross-family ceiling, so those images retain their +established target-specific 1920 KiB or larger A/B app layout and are checked against the actual app +partition. For every standalone ESP32 and nRF52 repeater, `build.sh` also exposes an explicit +`*_lora_ota_no_external_sensors` artifact: the ordinary repeater remains sensor-enabled, while that sibling +disables optional external environmental-sensor drivers for LoRa distribution. Integrated GPS and other +board-native telemetry remain enabled. ESP32 siblings retain the compact browser WiFi updater and use the +full 254-entry neighbor table. RP2040 and STM32 targets are not offered because those platforms do not yet +have a safe bootloader/apply path. Two WiFi-heavy non-companion profiles need additional reductions to remain portable. MQTT observer builds keep MQTT/TLS, onboard GPS, and their WiFi pull-updater, but omit WebConfig, SNMP, debug logging, display