Preserve separate TLora Full transports within RAM budget

This commit is contained in:
mikecarper committed 2026-10-05 18:33:34 -07:00
1 parent 6765100c3a
commit 8d76923a4e
11 files changed
+207 -37

No files matched your search

+11 -4
View File
@@ -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.
+5
View File
@@ -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
+14 -6
View File
@@ -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
+2 -1
View File
@@ -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.
+4 -2
View File
@@ -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
+4
View File
@@ -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.
+12 -2
View File
@@ -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
+37 -6
View File
@@ -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
+47 -1
View File
@@ -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;
+69 -8
View File
@@ -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]):
+2 -7
View File
@@ -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>