mirror of
https://github.com/mikecarper/MeshCore.git
synced 2026-10-23 08:43:48 +00:00
Preserve separate TLora Full transports within RAM budget
This commit is contained in:
1 parent
51d74a200e
commit
8af0511f54
11 files changed
+207
-37
No files matched your search
+11
-4
@@ -2460,8 +2460,8 @@ get_unified_full_infrastructure_target() {
|
||||
|
||||
# These plain Full recipes retain more routing capacity than their MQTT
|
||||
# siblings (T-Beam flood rules / room neighbors, TLora repeater neighbors).
|
||||
# Keep them available for an explicit exact-identity build; the ordinary
|
||||
# release chooses the MQTT observer for these board/role groups.
|
||||
# T-Beam keeps the observer as its ordinary release choice. TLora retains
|
||||
# both identities: its UART cannot fit alongside MQTT and ESP-NOW.
|
||||
case "${mqtt_base,,}" in
|
||||
tbeam_sx1262_repeater|tbeam_sx1276_repeater|\
|
||||
tbeam_sx1262_room_server|tbeam_sx1276_room_server|\
|
||||
@@ -6372,7 +6372,8 @@ get_esp32_full_profile_target() {
|
||||
echo "$target"
|
||||
}
|
||||
|
||||
# The ordinary release offers one Full image per physical board and role.
|
||||
# The ordinary release combines Full images per physical board and role
|
||||
# where the runtime memory budget permits all transports.
|
||||
# Keep the exact environment names for direct --full-exact builds and for
|
||||
# legacy/partition migration packages; this selection applies only to bulk
|
||||
# Full passes. Include the board in the key so similarly named recipes cannot
|
||||
@@ -6416,6 +6417,12 @@ get_ordinary_full_group_key() {
|
||||
*_repeater|*_room_server) ;;
|
||||
*) role_base=$base ;;
|
||||
esac
|
||||
# Real qualification found the triple-transport TLora image 6496 bytes
|
||||
# short of its required internal heap. Preserve UART and MQTT as two Full
|
||||
# identities, with ESP-NOW available in each.
|
||||
if [ "${base,,}" = lilygo_tlora_v2_1_1_6_repeater_observer_mqtt ]; then
|
||||
role_base=$base
|
||||
fi
|
||||
printf '%s|%s\n' "${PIO_ENV_BOARD_BY_NAME[$target]:-$target}" "${role_base,,}"
|
||||
}
|
||||
|
||||
@@ -6425,7 +6432,7 @@ get_ordinary_full_priority() {
|
||||
case "${base,,}" in
|
||||
*_observer_mqtt) echo 20 ;;
|
||||
*_bridge_espnow) echo 10 ;;
|
||||
tbeam_sx1262_repeater|tbeam_sx1276_repeater|lilygo_tlora_v2_1_1_6_repeater) echo 0 ;;
|
||||
tbeam_sx1262_repeater|tbeam_sx1276_repeater) echo 0 ;;
|
||||
*)
|
||||
# G2's deployed Full identity is the observer. Other audited plain
|
||||
# targets keep their own identity, with observer sources where needed.
|
||||
|
||||
@@ -620,6 +620,11 @@
|
||||
|
||||
return (profiles || []).filter(function (profile) {
|
||||
const target = String(profile && profile.target || "");
|
||||
// TLora cannot fit UART, MQTT and ESP-NOW together. Its normal Full
|
||||
// UART image and Full MQTT observer are both intentional choices.
|
||||
if (/^LilyGo_TLora_V2_1_1_6_repeater_observer_mqtt_?-full-usb-wifi$/i.test(target)) {
|
||||
return true;
|
||||
}
|
||||
// Same-partition ESP32 migrations publish the ordinary target's Full
|
||||
// image with its established mOTA identity. The former observer-named
|
||||
// Full image remains in the release for deployed devices that still use
|
||||
|
||||
@@ -49,8 +49,11 @@ The direct observer and Full-matrix paths use the same `full-usb-wifi-ota`
|
||||
artifact and runtime output controls. The ordinary bulk release publishes one
|
||||
Full OTA identity per exact ESP32 board and role. Audited plain targets keep
|
||||
their identity while compiling the combined observer/ESP-NOW sources; G2 keeps
|
||||
its deployed observer identity. T-Beam SX1262/SX1276 and TLora V2 choose the
|
||||
observer in the ordinary release. Their plain Full recipes remain available
|
||||
its deployed observer identity. T-Beam SX1262/SX1276 choose the observer in
|
||||
the ordinary release. TLora V2 retains two Full images because UART, MQTT
|
||||
and ESP-NOW together exceed its internal RAM budget: the normal repeater
|
||||
provides UART plus ESP-NOW, and the observer provides MQTT plus ESP-NOW.
|
||||
T-Beam plain Full recipes remain available
|
||||
as explicit alternatives with different routing capacities. Build one with
|
||||
`bash build.sh build-firmware <target> --full-exact`, then deliberately install
|
||||
it over LoRa with `ota pull <MID8> flash` and `ota install` on compatible
|
||||
@@ -204,10 +207,9 @@ available from a canonical image:
|
||||
target remains directly buildable with its bridge-on default but is omitted
|
||||
from bulk releases. Browser OTA pauses ESP-NOW while leaving RS-232 running;
|
||||
`stop ota` restores ESP-NOW when its saved setting is on.
|
||||
- Full Heltec V3, Wireless Stick Lite V3, RAK3112 and LilyGo T-LoRa V2.1-1.6
|
||||
MQTT repeaters retain RS-232 alongside MQTT and ESP-NOW. The first three
|
||||
use UART2 with RX on GPIO5 and TX on GPIO6; T-LoRa uses UART2 with RX on
|
||||
GPIO34 and TX on GPIO25. Use `set rs232.enabled on|off` and
|
||||
- Full Heltec V3, Wireless Stick Lite V3 and RAK3112 MQTT repeaters retain
|
||||
RS-232 alongside MQTT and ESP-NOW. They use UART2 with RX on GPIO5 and
|
||||
TX on GPIO6. Use `set rs232.enabled on|off` and
|
||||
`get rs232.running` independently of `mqtt.enabled` and `espnow.enabled`.
|
||||
`bridge.baud` and `bridge.uart` configure the UART. Old MQTT preferences
|
||||
do not enable this newly added UART; its saved intent needs a validated
|
||||
@@ -216,6 +218,12 @@ available from a canonical image:
|
||||
verifies the linked UART driver even when compiling observer sources for a
|
||||
normal repeater, and resumed release selection rejects Full images without
|
||||
that proof.
|
||||
- LilyGo T-LoRa V2.1-1.6 retains a normal Full UART/ESP-NOW repeater and a
|
||||
separate Full MQTT/ESP-NOW observer. Real triple-transport qualification
|
||||
fell 6,496 bytes short of the required internal heap, including the UART
|
||||
driver allowance. The normal UART remains on RX GPIO34 and TX GPIO25;
|
||||
use `bridge.enabled` or `rs232.enabled` to control it. Both Full identities
|
||||
remain in bulk releases instead of reducing routing capacity or RAM margins.
|
||||
- MeshTower V2 repeaters use
|
||||
`Heltec_tower_v2_sdcard_repeater_lora_ota_no_external_sensors` as the one
|
||||
canonical target. Its SD OTA target `0A9DBBF0`, hardware ID
|
||||
|
||||
@@ -26,7 +26,8 @@ Open each board's [USB console](https://flasher.meshcore.io/console) at
|
||||
get bridge.type
|
||||
```
|
||||
|
||||
The answer can be `espnow`, `mqtt+espnow`, or `rs232+espnow`. Confirm the
|
||||
The answer can be `espnow`, `mqtt+espnow`, `rs232+espnow`, or
|
||||
`mqtt+rs232+espnow`, depending on the image. Confirm the
|
||||
independent ESP-NOW control is present with `get espnow.enabled` and
|
||||
`get espnow.running`. The `espnow` commands select this transport without
|
||||
changing another bridge in a combined image.
|
||||
|
||||
@@ -208,9 +208,11 @@ supported, `set mqtt.enabled on|off` for MQTT. Newly combined ordinary
|
||||
repeaters start with ESP-NOW off until explicitly enabled, including the first
|
||||
upgrade from unmarked legacy preferences. Later reboots preserve that setting.
|
||||
On combined RS-232 boards without MQTT, `bridge.enabled` controls the UART.
|
||||
Full Heltec V3, WSL3, RAK3112 and T-LoRa V2.1 MQTT images also retain RS-232;
|
||||
Full Heltec V3, WSL3 and RAK3112 MQTT images also retain RS-232;
|
||||
use `set rs232.enabled on|off` and `get rs232.running` for their independent
|
||||
UART. MQTT and ESP-NOW use one 2.4 GHz radio, so when both are enabled the ESP-NOW bridge channel must
|
||||
UART. T-LoRa V2.1 keeps two Full choices due to its internal RAM limit:
|
||||
the normal repeater has UART plus ESP-NOW, and the observer has MQTT plus
|
||||
ESP-NOW. MQTT and ESP-NOW use one 2.4 GHz radio, so when both are enabled the ESP-NOW bridge channel must
|
||||
match the connected WiFi access point's fixed channel. ESP-NOW-only mode does
|
||||
not require WiFi credentials. Its runtime
|
||||
`bridge.format` setting chooses the peer protocol: `wrapped` (the
|
||||
|
||||
@@ -30,6 +30,10 @@ MQTT connections, OTA scratch and transient allocations. ESP32 images with
|
||||
RS-232 reserve another 8 KiB even when UART defaults off: 4 KiB for the
|
||||
source-bounded bridge object and 4 KiB for the UART driver and buffers. This
|
||||
keeps runtime UART enablement in the budget beside MQTT and ESP-NOW.
|
||||
T-LoRa V2.1-1.6 cannot fit all three transports: the qualified linked triple
|
||||
image had 190,488 available internal bytes against 196,984 required bytes.
|
||||
Its ordinary release retains separate UART/ESP-NOW and MQTT/ESP-NOW Full
|
||||
images; the memory policy and routing capacities remain unchanged.
|
||||
A 160x80 ST7735
|
||||
framebuffer needs 25,602 bytes; an OLED allowance is 4 KiB. nRF52 Full with that
|
||||
color framebuffer must have at least 72 KiB available before startup allocations.
|
||||
|
||||
@@ -154,8 +154,17 @@ def select_ordinary_full_records(records: list[dict]) -> list[dict]:
|
||||
|
||||
# These normal repeaters already supply a UART. Full MQTT source
|
||||
# substitution must never remove it while retiring the dedicated image.
|
||||
# TLora cannot fit all three transports; its normal and observer Full
|
||||
# images remain separate, and only its normal image requires UART.
|
||||
uart_full_targets = {"heltec_v3_repeater", "heltec_wsl3_repeater",
|
||||
"rak_3112_repeater", "lilygo_tlora_v2_1_1_6_repeater"}
|
||||
tlora_uart_target = "lilygo_tlora_v2_1_1_6_repeater"
|
||||
|
||||
def requires_uart_full(target: str) -> bool:
|
||||
base = role_base(target)
|
||||
return (base in uart_full_targets
|
||||
and (base != tlora_uart_target or target.rstrip("_").lower() == base))
|
||||
|
||||
combined_rs232 = {role_base(record["manifest"]["target"]) for record in records
|
||||
if proven_rs232(record["manifest"])} & uart_full_targets
|
||||
|
||||
@@ -227,6 +236,8 @@ def select_ordinary_full_records(records: list[dict]) -> list[dict]:
|
||||
base = bridge_base
|
||||
kind = "bridge"
|
||||
key = base.lower()
|
||||
if key == tlora_uart_target and kind == "observer":
|
||||
key = target.rstrip("_").lower()
|
||||
# G2's observer is the deployed Full identity. The other listed
|
||||
# observer/bridge recipes offer features that their plain images do
|
||||
# not combine, so keep the richer ordinary release choice.
|
||||
@@ -234,7 +245,6 @@ def select_ordinary_full_records(records: list[dict]) -> list[dict]:
|
||||
"station_g2_repeater", "station_g2_room_server",
|
||||
"tbeam_sx1262_repeater", "tbeam_sx1276_repeater",
|
||||
"tbeam_sx1262_room_server", "tbeam_sx1276_room_server",
|
||||
"lilygo_tlora_v2_1_1_6_repeater",
|
||||
}
|
||||
# Capacity exceptions may still need a dedicated bridge. Old plain
|
||||
# Meshadventurer images without the linked driver must not supersede it.
|
||||
@@ -253,7 +263,7 @@ def select_ordinary_full_records(records: list[dict]) -> list[dict]:
|
||||
selected = [item[1] for item in chosen.values()]
|
||||
for record in selected:
|
||||
manifest = record["manifest"]
|
||||
if role_base(manifest["target"]) in uart_full_targets and not proven_rs232(manifest):
|
||||
if requires_uart_full(manifest["target"]) and not proven_rs232(manifest):
|
||||
raise ValueError(manifest["target"] + ": Full release requires the verified "
|
||||
"RS232 bridge from its normal repeater")
|
||||
return passthrough + selected
|
||||
|
||||
@@ -347,7 +347,6 @@ for env_name, rx, tx in (
|
||||
("Heltec_v3_repeater_observer_mqtt", 5, 6),
|
||||
("Heltec_WSL3_repeater_observer_mqtt", 5, 6),
|
||||
("RAK_3112_repeater_observer_mqtt", 5, 6),
|
||||
("LilyGo_TLora_V2_1_1_6_repeater_observer_mqtt_", 34, 25),
|
||||
):
|
||||
require(env_name, "build_flags", "WITH_MQTT_BRIDGE=1")
|
||||
require(env_name, "build_flags", "WITH_RS232_BRIDGE=Serial2")
|
||||
@@ -358,6 +357,14 @@ for env_name, rx, tx in (
|
||||
require(env_name, "build_src_filter", "helpers/bridges/RS232Bridge.cpp")
|
||||
reject(env_name, "build_flags", "RS232_BRIDGE_DEFAULT_ON")
|
||||
|
||||
# The T-LoRa runtime RAM budget cannot fit MQTT, ESP-NOW and UART together.
|
||||
# Keep its UART in the normal Full image and its MQTT recipe independent.
|
||||
tlora_observer = "LilyGo_TLora_V2_1_1_6_repeater_observer_mqtt_"
|
||||
require(tlora_observer, "build_flags", "WITH_MQTT_BRIDGE=1")
|
||||
reject(tlora_observer, "build_flags", "WITH_RS232_BRIDGE")
|
||||
reject(tlora_observer, "build_flags", "RS232_BRIDGE_MERGED")
|
||||
reject(tlora_observer, "build_src_filter", "helpers/bridges/RS232Bridge.cpp")
|
||||
|
||||
# MKE keeps its ordinary role and UART wiring while exposing the existing
|
||||
# persistent bridge controls. The merged marker selects the disabled default;
|
||||
# the explicit legacy bridge remains enabled for deliberate direct builds.
|
||||
@@ -1086,10 +1093,28 @@ done
|
||||
[ "$(select_ordinary_full_targets MKE_s3_repeater_bridge_espnow MKE_s3_repeater)" \
|
||||
= MKE_s3_repeater ] \
|
||||
|| fail "MKE S3 bridge input order changed its canonical Full image"
|
||||
[ "$(select_ordinary_full_targets LilyGo_TLora_V2_1_1_6_repeater_bridge_espnow \
|
||||
LilyGo_TLora_V2_1_1_6_repeater_observer_mqtt_)" \
|
||||
= LilyGo_TLora_V2_1_1_6_repeater_observer_mqtt_ ] \
|
||||
|| fail "TLora trailing-underscore observer failed to replace its ESP-NOW sibling"
|
||||
tlora_normal=LilyGo_TLora_V2_1_1_6_repeater
|
||||
tlora_observer=${tlora_normal}_observer_mqtt_
|
||||
tlora_espnow=${tlora_normal}_bridge_espnow
|
||||
[ "$(get_ordinary_full_group_key "$tlora_normal")" \
|
||||
!= "$(get_ordinary_full_group_key "$tlora_observer")" ] \
|
||||
|| fail "TLora RAM exception collapsed its independent UART and MQTT Full groups"
|
||||
for tlora_order in normal-first observer-first bridge-first; do
|
||||
case "$tlora_order" in
|
||||
normal-first) tlora_candidates=("$tlora_normal" "$tlora_observer" "$tlora_espnow") ;;
|
||||
observer-first) tlora_candidates=("$tlora_observer" "$tlora_espnow" "$tlora_normal") ;;
|
||||
bridge-first) tlora_candidates=("$tlora_espnow" "$tlora_normal" "$tlora_observer") ;;
|
||||
esac
|
||||
mapfile -t tlora_selected < <(select_ordinary_full_targets "${tlora_candidates[@]}")
|
||||
[ "${#tlora_selected[@]}" = 2 ] \
|
||||
|| fail "TLora $tlora_order did not retain exactly two capacity-safe Full images"
|
||||
[[ " ${tlora_selected[*]} " == *" $tlora_normal "* ]] \
|
||||
|| fail "TLora $tlora_order discarded its UART Full image"
|
||||
[[ " ${tlora_selected[*]} " == *" $tlora_observer "* ]] \
|
||||
|| fail "TLora $tlora_order discarded its MQTT Full image"
|
||||
[[ " ${tlora_selected[*]} " != *" $tlora_espnow "* ]] \
|
||||
|| fail "TLora $tlora_order retained the replaced dedicated ESP-NOW image"
|
||||
done
|
||||
ESP32_FULL_BUILD=0
|
||||
PLATFORMIO_BUILD_FLAGS=""
|
||||
PLATFORMIO_BUILD_SRC_FILTER=""
|
||||
@@ -1626,7 +1651,7 @@ fi
|
||||
(
|
||||
BUILD_PROFILE_FOR_TARGET=full
|
||||
for uart_target in Heltec_v3_repeater Heltec_WSL3_repeater RAK_3112_repeater \
|
||||
LilyGo_TLora_V2_1_1_6_repeater_observer_mqtt_; do
|
||||
LilyGo_TLora_V2_1_1_6_repeater; do
|
||||
BUILD_EXPECTATIONS=()
|
||||
declare_build_capability_contract "$uart_target" ESP32_PLATFORM
|
||||
[[ " ${BUILD_EXPECTATIONS[*]} " == *"bridge.rs232=_ZN11RS232Bridge5beginEv"* ]] \
|
||||
@@ -1634,6 +1659,12 @@ fi
|
||||
[[ " ${BUILD_EXPECTATIONS[*]} " == *"bridge.espnow=_ZN12ESPNowBridge5beginEv"* ]] \
|
||||
|| fail "$uart_target Full contract omitted the linked ESP-NOW driver"
|
||||
done
|
||||
BUILD_EXPECTATIONS=()
|
||||
declare_build_capability_contract LilyGo_TLora_V2_1_1_6_repeater_observer_mqtt_ ESP32_PLATFORM
|
||||
[[ " ${BUILD_EXPECTATIONS[*]} " != *"bridge.rs232="* ]] \
|
||||
|| fail "TLora MQTT capacity exception falsely promised a linked UART driver"
|
||||
[[ " ${BUILD_EXPECTATIONS[*]} " == *"bridge.espnow=_ZN12ESPNowBridge5beginEv"* ]] \
|
||||
|| fail "TLora MQTT capacity exception omitted its linked ESP-NOW driver"
|
||||
)
|
||||
|
||||
# A WiFi base's final -UENABLE_OTA must not win over the Full Companion's
|
||||
|
||||
@@ -1287,7 +1287,7 @@ console.log('combined UART/ESP-NOW picker modes, independent commands and histor
|
||||
// MQTT, ESP-NOW and UART coexist in the same qualified Full artifact. UART
|
||||
// instructions must never use MQTT's historical ESP-NOW bridge alias.
|
||||
const tripleTargets = ['Heltec_v3_repeater', 'Heltec_WSL3_repeater',
|
||||
'RAK_3112_repeater', 'LilyGo_TLora_V2_1_1_6_repeater_observer_mqtt_']
|
||||
'RAK_3112_repeater']
|
||||
.map(target => target + '-full-usb-wifi');
|
||||
const tripleCatalog = picker.buildCatalog([
|
||||
release(bridgeFamily, '2026-10-05T00:00:00Z', tripleTargets.map(target =>
|
||||
@@ -1318,6 +1318,52 @@ for (const profile of tripleCatalog.profiles) {
|
||||
assert.strictEqual(tripleCatalog.profiles.length, tripleTargets.length);
|
||||
console.log('three-transport Full picker uses independent UART, MQTT and ESP-NOW controls');
|
||||
|
||||
// T-LoRa cannot fit all three transports in its runtime RAM budget. Both
|
||||
// capacity-safe Full images remain selectable with their actual capabilities.
|
||||
const tloraNormalTarget = 'LilyGo_TLora_V2_1_1_6_repeater-full-usb-wifi';
|
||||
const tloraObserverTarget = 'LilyGo_TLora_V2_1_1_6_repeater_observer_mqtt_-full-usb-wifi';
|
||||
const tloraCatalog = picker.buildCatalog([
|
||||
release(bridgeFamily, '2026-10-05T00:00:00Z', [tloraNormalTarget, tloraObserverTarget]
|
||||
.map(target => asset(target + '-ota-' + bridgeFamily + '.bin'))),
|
||||
], {
|
||||
familyTag: bridgeFamily,
|
||||
profiles: {
|
||||
[tloraNormalTarget]: {
|
||||
platform: 'ESP32_PLATFORM', rs232: true, mqtt: false, espnowBridge: true,
|
||||
updateMethods: ['wifi', 'lora'],
|
||||
loggingModes: ['none', 'usb'], loggingControl: 'usb.logging',
|
||||
},
|
||||
[tloraObserverTarget]: {
|
||||
platform: 'ESP32_PLATFORM', rs232: false, mqtt: true, espnowBridge: true,
|
||||
updateMethods: ['wifi', 'lora'],
|
||||
loggingModes: ['none', 'usb', 'wifi', 'both'], loggingControl: 'logging.output',
|
||||
},
|
||||
},
|
||||
});
|
||||
assert.strictEqual(tloraCatalog.profiles.length, 2);
|
||||
const tloraNormalProfile = tloraCatalog.profiles.find(profile => profile.target === tloraNormalTarget);
|
||||
const tloraObserverProfile = tloraCatalog.profiles.find(profile => profile.target === tloraObserverTarget);
|
||||
assert(tloraNormalProfile && tloraObserverProfile);
|
||||
assert.deepStrictEqual(picker.profileFieldValues(tloraNormalProfile, 'mode'),
|
||||
['standard', 'rs232', 'espnow']);
|
||||
assert.deepStrictEqual(picker.profileFieldValues(tloraObserverProfile, 'mode'),
|
||||
['standard', 'espnow']);
|
||||
assert.deepStrictEqual(picker.profileFieldValues(tloraNormalProfile, 'logging'), ['none', 'usb']);
|
||||
assert.deepStrictEqual(picker.profileFieldValues(tloraObserverProfile, 'logging'),
|
||||
['none', 'usb', 'wifi', 'both']);
|
||||
assert(!picker.profileMatches(tloraNormalProfile, {logging: 'wifi'}, ['logging']));
|
||||
assert(picker.profileMatches(tloraObserverProfile, {logging: 'wifi'}, ['logging']));
|
||||
const tloraNormalDirections = picker.runtimeDirections(tloraNormalProfile, {mode: 'rs232'});
|
||||
const tloraObserverDirections = picker.runtimeDirections(tloraObserverProfile, {mode: 'espnow'});
|
||||
assert(tloraNormalDirections.some(section => /^RS232 bridge/.test(section.title)));
|
||||
assert(tloraNormalDirections.some(section => section.title === 'ESP-NOW bridge'));
|
||||
assert(!tloraNormalDirections.some(section => section.title === 'MQTT broker connections'));
|
||||
assert(tloraObserverDirections.some(section => section.title === 'MQTT broker connections'));
|
||||
assert(tloraObserverDirections.some(section => section.title === 'ESP-NOW bridge'));
|
||||
assert(!tloraObserverDirections.some(section => /^RS232 bridge/.test(section.title)));
|
||||
assert(!commands(tloraObserverDirections).some(command => command.startsWith('set rs232.')));
|
||||
console.log('T-LoRa RAM exception preserves separate UART and MQTT Full picker choices');
|
||||
|
||||
// Partition expansion uses the packager's lookup and published utility assets,
|
||||
// not hardware labels or guessed slugs (several historical names differ).
|
||||
const migrationFamily = currentControls.familyTag;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#!/usr/bin/env python3
|
||||
"""The ordinary release has one ESP32 Full OTA identity per board and role."""
|
||||
"""Full selection preserves qualified transports and board capacity exceptions."""
|
||||
|
||||
import sys
|
||||
import unittest
|
||||
@@ -23,7 +23,9 @@ class ReleaseFullSelectionTest(unittest.TestCase):
|
||||
def test_full_uart_source_substitution_requires_linked_driver_proof(self):
|
||||
for base in ("Heltec_v3_repeater", "Heltec_WSL3_repeater", "RAK_3112_repeater",
|
||||
"LilyGo_TLora_V2_1_1_6_repeater"):
|
||||
for suffix in ("", "_observer_mqtt", "_observer_mqtt_"):
|
||||
suffixes = ("",) if base.startswith("LilyGo_TLora_") else (
|
||||
"", "_observer_mqtt", "_observer_mqtt_")
|
||||
for suffix in suffixes:
|
||||
for fault in ("missing_capability", "missing_proof", "false_proof", "unverified"):
|
||||
image = record(base + suffix, capabilities=("bridge.rs232", "bridge.espnow"))
|
||||
manifest = image["manifest"]
|
||||
@@ -40,8 +42,7 @@ class ReleaseFullSelectionTest(unittest.TestCase):
|
||||
select_ordinary_full_records([image])
|
||||
|
||||
def test_new_combined_full_displaces_stale_plain_and_both_dedicated_bridges(self):
|
||||
for base in ("Heltec_v3_repeater", "Heltec_WSL3_repeater", "RAK_3112_repeater",
|
||||
"LilyGo_TLora_V2_1_1_6_repeater"):
|
||||
for base in ("Heltec_v3_repeater", "Heltec_WSL3_repeater", "RAK_3112_repeater"):
|
||||
stale = record(base, capabilities=("bridge.espnow",))
|
||||
primary = record(base + "_observer_mqtt_",
|
||||
capabilities=("bridge.rs232", "bridge.espnow"))
|
||||
@@ -52,6 +53,65 @@ class ReleaseFullSelectionTest(unittest.TestCase):
|
||||
with self.subTest(base=base, profile=profile):
|
||||
self.assertEqual(select_ordinary_full_records(inputs), [primary])
|
||||
|
||||
def test_tlora_ram_exception_keeps_uart_and_mqtt_full_images(self):
|
||||
base = "LilyGo_TLora_V2_1_1_6_repeater"
|
||||
normal = record(base, capabilities=("bridge.rs232", "bridge.espnow"))
|
||||
observer = record(base + "_observer_mqtt_", capabilities=("bridge.espnow",))
|
||||
for profile in ("standard", "full"):
|
||||
legacy = [record(base + "_bridge_" + bridge, profile)
|
||||
for bridge in ("rs232", "espnow")]
|
||||
for inputs in ([normal, observer] + legacy, legacy + [observer, normal],
|
||||
[observer] + legacy + [normal]):
|
||||
with self.subTest(profile=profile, first=inputs[0]["manifest"]["target"]):
|
||||
selected = select_ordinary_full_records(inputs)
|
||||
self.assertCountEqual(selected, [normal, observer])
|
||||
self.assertEqual(len(selected), 2)
|
||||
self.assertTrue(all(item is normal or item is observer for item in selected))
|
||||
|
||||
def test_tlora_observer_cannot_retire_uart_without_normal_driver_proof(self):
|
||||
base = "LilyGo_TLora_V2_1_1_6_repeater"
|
||||
observer = record(base + "_observer_mqtt_", capabilities=("bridge.espnow",))
|
||||
for profile in ("standard", "full"):
|
||||
uart = record(base + "_bridge_rs232", profile, capabilities=("bridge.rs232",))
|
||||
wireless = record(base + "_bridge_espnow", profile, capabilities=("bridge.espnow",))
|
||||
for inputs in ([observer, uart, wireless], [wireless, uart, observer]):
|
||||
with self.subTest(profile=profile):
|
||||
self.assertCountEqual(select_ordinary_full_records(inputs), [observer, uart])
|
||||
for fault in ("missing_capability", "missing_proof", "false_proof", "unverified"):
|
||||
normal = record(base, capabilities=("bridge.rs232", "bridge.espnow"))
|
||||
manifest = normal["manifest"]
|
||||
if fault == "missing_capability":
|
||||
manifest["capabilities"].remove("bridge.rs232")
|
||||
elif fault == "missing_proof":
|
||||
manifest["verification"] = []
|
||||
elif fault == "false_proof":
|
||||
manifest["verification"][0]["present"] = False
|
||||
else:
|
||||
manifest["verified"] = False
|
||||
for inputs in ([normal, observer], [observer, normal]):
|
||||
with self.subTest(fault=fault):
|
||||
with self.assertRaisesRegex(ValueError, "verified RS232 bridge"):
|
||||
select_ordinary_full_records(inputs)
|
||||
|
||||
def test_tlora_legacy_espnow_needs_verified_replacement(self):
|
||||
base = "LilyGo_TLora_V2_1_1_6_repeater"
|
||||
for fault in ("missing_capability", "missing_proof", "false_proof", "unverified"):
|
||||
observer = record(base + "_observer_mqtt_", capabilities=("bridge.espnow",))
|
||||
manifest = observer["manifest"]
|
||||
if fault == "missing_capability":
|
||||
manifest["capabilities"] = []
|
||||
elif fault == "missing_proof":
|
||||
manifest["verification"] = []
|
||||
elif fault == "false_proof":
|
||||
manifest["verification"][0]["present"] = False
|
||||
else:
|
||||
manifest["verified"] = False
|
||||
for profile in ("standard", "full"):
|
||||
legacy = record(base + "_bridge_espnow", profile, capabilities=("bridge.espnow",))
|
||||
with self.subTest(fault=fault, profile=profile):
|
||||
self.assertCountEqual(select_ordinary_full_records([observer, legacy]),
|
||||
[observer, legacy])
|
||||
|
||||
def test_meshtower_sd_primary_filters_stale_internal_images_without_relabeling(self):
|
||||
primary = "Heltec_tower_v2_sdcard_repeater_lora_ota_no_external_sensors"
|
||||
variants = []
|
||||
@@ -102,8 +162,8 @@ class ReleaseFullSelectionTest(unittest.TestCase):
|
||||
record("Station_G2_repeater_observer_mqtt"),
|
||||
record("Tbeam_SX1262_repeater_bridge_espnow"),
|
||||
record("Tbeam_SX1262_repeater_observer_mqtt", capabilities=("bridge.espnow",)),
|
||||
record("LilyGo_TLora_V2_1_1_6_repeater"),
|
||||
record("LilyGo_TLora_V2_1_1_6_repeater_observer_mqtt_", capabilities=("bridge.rs232",)),
|
||||
record("LilyGo_TLora_V2_1_1_6_repeater", capabilities=("bridge.rs232", "bridge.espnow")),
|
||||
record("LilyGo_TLora_V2_1_1_6_repeater_observer_mqtt_", capabilities=("bridge.espnow",)),
|
||||
record("Meshadventurer_sx1262_repeater"),
|
||||
record("Meshadventurer_sx1262_repeater_bridge_espnow"),
|
||||
record("RAK_4631_repeater", platform="NRF52_PLATFORM"),
|
||||
@@ -113,11 +173,12 @@ class ReleaseFullSelectionTest(unittest.TestCase):
|
||||
"Heltec_v3_repeater", "Heltec_v3_room_server",
|
||||
"Station_G2_repeater_observer_mqtt",
|
||||
"Tbeam_SX1262_repeater_observer_mqtt",
|
||||
"LilyGo_TLora_V2_1_1_6_repeater",
|
||||
"LilyGo_TLora_V2_1_1_6_repeater_observer_mqtt_",
|
||||
"Meshadventurer_sx1262_repeater_bridge_espnow",
|
||||
"RAK_4631_repeater",
|
||||
})
|
||||
self.assertEqual(len(selected), 8) # standard V3 remains alongside Full V3
|
||||
self.assertEqual(len(selected), 9) # standard V3 and both TLora Full profiles remain
|
||||
|
||||
def test_mke_combined_repeater_filters_stale_bridge_identities_without_relabeling(self):
|
||||
primary = record("MKE_s3_repeater", capabilities=("bridge.rs232", "bridge.espnow"))
|
||||
@@ -253,7 +314,7 @@ class ReleaseFullSelectionTest(unittest.TestCase):
|
||||
|
||||
def test_combined_observer_with_trailing_underscore_replaces_matching_espnow(self):
|
||||
observer = record("LilyGo_TLora_V2_1_1_6_repeater_observer_mqtt_",
|
||||
capabilities=("bridge.espnow", "bridge.rs232"))
|
||||
capabilities=("bridge.espnow",))
|
||||
legacy = record("LilyGo_TLora_V2_1_1_6_repeater_bridge_espnow",
|
||||
capabilities=("bridge.espnow",))
|
||||
for inputs in ([observer, legacy], [legacy, observer]):
|
||||
|
||||
@@ -191,12 +191,8 @@ build_flags =
|
||||
-D MAX_NEIGHBOURS=50
|
||||
-D MAX_RECENT_REPEATERS=256 ; no-PSRAM observer must retain internal DRAM for MQTT/TLS
|
||||
-D WITH_MQTT_BRIDGE=1
|
||||
; Keep the normal repeater UART in the combined Full image; disabled until enabled.
|
||||
-D WITH_RS232_BRIDGE=Serial2
|
||||
-D WITH_RS232_BRIDGE_UART=2
|
||||
-D WITH_RS232_BRIDGE_RX=34
|
||||
-D WITH_RS232_BRIDGE_TX=25
|
||||
-D RS232_BRIDGE_MERGED=1
|
||||
; UART plus MQTT and ESP-NOW exceeds the internal heap budget by 6496 bytes.
|
||||
; Keep UART in the separate normal Full repeater; retain MQTT/ESP-NOW here.
|
||||
-D WEBCONFIG_DISABLED=1 ; async portal exceeds this 4 MB target's dual-OTA app slot; use CLI setup
|
||||
-D FLOOD_CHANNEL_SCOPE_SLOTS=4 ; no-PSRAM observer must retain internal DRAM for MQTT/TLS
|
||||
-D MQTT_MAX_PACKET_SIZE=1024
|
||||
@@ -215,7 +211,6 @@ build_flags =
|
||||
# -D MQTT_PASSWORD='"your-password"'
|
||||
build_src_filter = ${LilyGo_TLora_V2_1_1_6_core.build_src_filter}
|
||||
+<helpers/bridges/MQTTBridge.cpp>
|
||||
+<helpers/bridges/RS232Bridge.cpp>
|
||||
+<helpers/MQTTMessageBuilder.cpp>
|
||||
+<helpers/JWTHelper.cpp>
|
||||
+<helpers/ui/SSD1306Display.cpp>
|
||||
|
||||
Reference in new issue
Block a user