Prepare 1.17.1.7 Cascade release catalogs and STM32WL USB images

This commit is contained in:
mikecarper committed 2026-09-27 10:20:43 -07:00
1 parent a134c509d5
commit 4db7780ba7
10 files changed
+16021 -14616

No files matched your search

+10
View File
@@ -2693,6 +2693,16 @@ apply_debug_overrides() {
uses_merged_standard_usb_logging() {
local env_name=$1
# The four 256 KiB STM32WL USB Companions exceed their 32 KiB LittleFS
# boundary when packet diagnostics are linked. Keep their framed USB
# Companion transport and storage layout intact.
case "$env_name" in
RAK_3x72_companion_radio_usb|Tiny_Relay_companion_radio_usb|\
wio-e5-mini_companion_radio_usb|wio-e5_companion_radio_usb)
return 1
;;
esac
# These profiles either own Serial for framed traffic, deliberately trade
# logging for OTA space, or provide their own logging contract. Keep those
# contracts unchanged.
File diff suppressed because it is too large. Load diff
+1 -1
View File
@@ -17,7 +17,7 @@ The picker reads public release metadata from GitHub. It does not upload device
information. Hardware names, target names, and download links come directly
from the published firmware assets.
<div class="firmware-picker" data-firmware-picker data-release-repo="mikecarper/MeshCore" data-controls-url="../_data/firmware_controls.json?v=1.17.1.6-runtime-2" data-share-url="https://mikecarper.github.io/MeshCore/firmware_picker/">
<div class="firmware-picker" data-firmware-picker data-release-repo="mikecarper/MeshCore" data-controls-url="../_data/firmware_controls.json?v=1.17.1.7-runtime-1" data-share-url="https://mikecarper.github.io/MeshCore/firmware_picker/">
<div class="firmware-picker-intro" role="note">
<strong>Current release set</strong>
<p data-role="release-set">Loading release information...</p>
+18
View File
@@ -0,0 +1,18 @@
# MeshCore 1.17.1.7 USA Cascade
This development release uses 910.525 MHz, 62.5 kHz bandwidth, SF7, and CR5 with Cascade defaults. Saved radio settings take precedence. The firmware source is `2d03e098cf75d58adcf35fe3d4dbbeaf0af114e1`.
The release family contains 536 qualified firmware profiles on five GitHub release pages. The companion page is the main release; the repeater and room server, sensor and utility, LoRa OTA, and expanded ESP32 Full pages have the same version suffix. The [firmware picker](../firmware_picker.md) selects the exact board, role, storage and update file.
## Installation
- Match the exact board and radio variant. Use the application image only with a compatible bootloader and partition layout.
- For an ESP32 that needs the expanded Full layout, use its exact board and role package from the utility release page. The 94 migration packages and complete migration bundle are included there. Read the package README before installation.
- nRF52 application UF2 and DFU packages do not install a bootloader. Use the matching OTAFIX 2.4.8 bootloader where required.
- The RAK 3x72, Tiny Relay, Wio-E5 Mini, and Wio-E5 USB Companion images retain their framed USB transport and 32 KiB LittleFS area. Packet diagnostics are omitted on these four 256 KiB STM32WL targets to keep the application within flash.
## Build verification
The original matrix produced 532 qualified images and four STM32WL USB Companion flash overflows. Those four were rebuilt individually with packet diagnostics omitted and passed capability, flash size and memory checks. The [repair record](https://github.com/mikecarper/MeshCore/releases/download/v1.17.1.7-halo-keymind-cascade-dev-2d03e098/REPAIR-PROVENANCE.json) identifies them. The local release package also verified all 94 ESP32 migration archives and generated SHA-256 sums.
Automated qualification does not establish physical update compatibility on every board. Verify critical deployed devices with the matching image and recovery path before a fleet upgrade.
+5 -66
View File
@@ -1,80 +1,19 @@
# Mesh America provider catalogs
Both active provider catalogs now use **1.17.1.5 USA Cascade**, published from
original firmware commit `26303793`, with **52 memory-corrected entries** from
`aa20e927`. All 11 release profiles that failed the RAM budget have replacements;
all 43 nRF52 Full Companions use shared mOTA/queue storage. Wireless Paper Full
now uses source `1e4d1e16`, restoring 350 contacts and 40 channels with 256
message slots normally, or 128 while mOTA borrows the other half. The other six
corrected ESP32 Full profiles use 150 contacts and keep their 256-message queue; read
the entry notes and export contacts before upgrading if you exceed that limit.
The release audit also covers 43 supplemental Full repeater profiles available
on GitHub and in the firmware picker. The catalogs retain their canonical
selection and cover **94 device cards, 540 selectable
entries, 539 unique firmware profiles, and 1,078 unique firmware files**.
One Full Companion image is listed under two compatible device/accessory cards.
The MQTT simulation environment is a laboratory target and is not a device
choice. Entries without a qualified replacement in this OTA-required release
are omitted; no download silently points to an older firmware release.
## Stable provider URLs
The `v1.16.0` text in these filenames is part of the existing provider URL,
not the firmware version. Keep these URLs in Mesh America; they now load
1.17.1.5 choices.
The two active provider catalogs select the 1.17.1.7 USA Cascade release family. Each lists 536 unique qualified firmware profiles across 103 hardware cards; one compatible profile appears under two cards. Both catalogs use the same binaries. The logging catalog remains a separate stable provider URL for existing Mesh America installations.
```text
Provider name: Keymind Cascade
Catalog URL: https://raw.githubusercontent.com/mikecarper/MeshCore/keymindCascade/mesh-america/keymind-cascade-v1.16.0-provider.json
```
```text
Provider name: Keymind Cascade Logging
Catalog URL: https://raw.githubusercontent.com/mikecarper/MeshCore/keymindCascade/mesh-america/keymind-cascade-logging-v1.16.0-provider.json
```
## Logging and former variants
The `v1.16.0` part of those filenames is a stable provider URL, not the firmware version. Both JSON files contain exact 1.17.1.7 asset URLs, including the separate Companion, repeater and room server, utility, LoRa OTA, and Full ESP32 release pages.
Both catalogs now select from the same canonical firmware set. Logging,
power-saving, and controllable gain variants are runtime settings; selecting
the logging provider does not itself change the device's saved settings.
Each entry includes the appropriate commands, update methods, hardware
requirements, and its actual GitHub release page.
Four 256 KiB STM32WL USB Companion images (RAK 3x72, Tiny Relay, Wio-E5 Mini, and Wio-E5) omit packet diagnostics to preserve their 32 KiB LittleFS layout. Their USB Companion transport remains available. Their entries say so explicitly. Other logging controls follow each exact image's capability manifest.
- **Full Companion:** ESP32 uses `set usb.logging on` / `set usb.logging off`;
nRF52 uses `set usb.logging on reboot` / `set usb.logging off reboot` for its
optional second USB port. On 1.17.1.5 ESP32, run `set powersaving off` first.
- **Shared controls:** All roles use `get usb.logging` / `set usb.logging on|off`
for live USB logs. MQTT-capable images use `set mqtt.enabled on|off` without
erasing broker slots. Images with both outputs use
`set logging.output off|usb|wifi|both`. Check `get mqtt.running` and
`get mqtt.status`; configure brokers with `set mqtt1.preset` and related
settings or WebConfig. RS232/ESP-NOW bridges use `bridge.enabled` separately.
- Open the [USB web console](https://flasher.meshcore.io/console) at 115200 baud.
Full Companion and infrastructure start in ASCII mode. Download-only board
entries retain their external programming requirements.
See the [1.17.1.7 release guide](../docs/releases/1.17.1.7.md) and [firmware picker](../docs/firmware_picker.md). ESP32 partition migration packages are on the utility release page. nRF52 application images require a matching OTAFIX bootloader when the installed bootloader is not already compatible.
See [feature switches by role](../docs/role_feature_switches.md), the
[release guide](../docs/releases/1.17.1.5.md), and the
[old-variant map](../docs/releases/1.17.1.5-variant-map.tsv).
For nRF52 OTAFIX installations use the exact board/storage profile from
[OTAFIX 2.4.6](https://github.com/mikecarper/Adafruit_nRF52_Bootloader_OTAFIX/releases/tag/0.11.0-OTAFIX2.4.6).
## Catalog maintenance
The 1.17.1.5 catalog download URLs were reconciled with `release-plan.json`
and each group's qualified `TARGET-MANIFEST.json`, then verified against the
published GitHub assets. Preserve the exact tag for each file: Companion,
Repeater/Room Server, Sensor, LoRa OTA, and expanded Full profiles are on
separate release pages. Do not update these catalogs by replacing version
strings alone.
The older `update-provider-release.py`, `update-logging-provider-release.py`,
and PowerShell generator target earlier flat release directories and tag
layouts. Their default routing is not sufficient for the five-page 1.17.1.5
staging layout. Before using them for another release, reconcile canonical
aliases, omitted targets, runtime feature descriptions, and release-group
routing against that release's manifests.
Files ending in `provider-backup.json` are historical backups and intentionally
retain their original versions. They are not the active provider URLs above.
Catalogs are generated from the staged release manifest, with every asset URL checked against the staged file and tag. Historical `provider-backup.json` files are retained unchanged.
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
+25 -4
View File
@@ -296,10 +296,8 @@ def normalize_reduced_profile_metadata(
paragraphs.append(paragraph)
if not profile_found:
raise ValueError(
"reduced LoRa OTA catalog entry has no Compact LoRa OTA profile: "
+ ", ".join(identities)
)
paragraphs.append(REDUCED_PROFILE_DESCRIPTION)
paragraphs.extend(reduced_profile_special_notes(identities))
return "\n\n".join(paragraphs)
@@ -716,6 +714,29 @@ def resolve_release_identity(
if identity in release_files:
return identity, "observer_mqtt" in identity.lower()
# The canonical matrix may replace a portable, ESP-NOW, or observer
# sibling with one expanded Full image for that board and role.
for candidate in candidates:
base = re.sub(r"-(?:full-usb-wifi-ota|full-logging-ota|full-ota|ota|logging)$", "", candidate)
base = re.sub(r"_lora_ota_no_external_sensors$", "", base)
base = re.sub(r"_bridge_espnow_?$", "", base)
base = re.sub(r"_observer_mqtt$", "", base)
bases = (base, base + "_") if not base.endswith("_") else (base, base.rstrip("_"))
preferred = tuple(name for variant in bases for name in (
f"{variant}_observer_mqtt-full-usb-wifi-ota",
f"{variant}-full-usb-wifi-ota",
f"{variant}-full-logging-ota",
variant + "-ota",
variant,
))
if not any(marker in candidate.lower() for marker in
("full", "lora_ota", "bridge_espnow", "observer_mqtt")):
preferred = tuple(name for variant in bases for name in (variant, variant + "-ota")) \
+ tuple(name for name in preferred if name not in bases)
for identity in preferred:
if identity in release_files:
return identity, identity.endswith("-full-usb-wifi-ota")
raise ValueError(f"no new release artifact matches catalog target {old_identity!r}")
+3 -3
View File
@@ -51,7 +51,7 @@ def capacity_note(reductions, defines):
return ' '.join(notes)
def runtime_metadata(manifest, mqtt):
def runtime_metadata(manifest, mqtt, release_source=None):
"""Keep picker choices tied to capabilities proven in this exact image."""
capabilities = set(manifest['capabilities'])
verified = {check['capability'] for check in manifest.get('verification', [])
@@ -68,7 +68,7 @@ def runtime_metadata(manifest, mqtt):
if {'logging.usb.packets', 'logging.usb.control'} <= packaged:
result['loggingModes'] = ['none', 'usb', 'wifi', 'both'] if mqtt else ['none', 'usb']
result['loggingControl'] = 'logging.output' if mqtt else 'usb.logging'
result['loggingSource'] = manifest['source_commit']
result['loggingSource'] = manifest.get('source_commit', release_source)
if 'companion.dedicated_usb_logging' in verified:
result['dedicatedUsbLogging'] = True
return result
@@ -121,7 +121,7 @@ def generate(stage, config):
'snmp': enabled('WITH_SNMP'),
'updateMethods': manifest.get('ota_update_methods', []),
}
controls.update(runtime_metadata(manifest, controls['mqtt']))
controls.update(runtime_metadata(manifest, controls['mqtt'], plan['source']))
if manifest.get('ota_update_requirements'):
controls['updateRequirements'] = manifest['ota_update_requirements']
note = capacity_note(manifest.get('reductions', []), defines)
+9 -8
View File
@@ -1065,19 +1065,16 @@ assert.strictEqual(currentCatalog.rows.length, currentAssets.length);
assert(currentCatalog.profiles.every(profile => profile.controls && profile.chipFamily !== 'unknown'));
const ikokaNormal = currentCatalog.profiles.find(profile =>
profile.target === 'ikoka_stick_nrf_30dbm_repeater');
const ikokaLean = currentCatalog.profiles.find(profile =>
profile.target === 'ikoka_stick_nrf_30dbm_repeater_lora_ota_no_external_sensors');
assert(!currentCatalog.profiles.some(profile =>
profile.target === 'ikoka_stick_nrf_30dbm_repeater_lora_ota_no_external_sensors'));
assert.strictEqual(ikokaNormal.ota, 'lora-receiver');
assert.strictEqual(ikokaNormal.logging, 'usb-runtime');
assert.deepStrictEqual(ikokaNormal.loggingModes, ['none', 'usb']);
assert.deepStrictEqual(picker.runtimeDirections(ikokaNormal, {logging: 'usb'})[0].actions[0].commands,
['set usb.logging on']);
assert.strictEqual(ikokaLean.ota, 'lora-receiver');
assert.strictEqual(ikokaLean.logging, 'none');
assert.deepStrictEqual(ikokaLean.loggingModes, ['none']);
const ikokaUrl = 'https://example.com/firmware_picker/?chipFamily=nrf52&hardwareFamily=ikoka_stick_nrf_30dbm&hardware=ikoka_stick_nrf_30dbm&role=repeater&variant=default&install=zip&chipAuto=1';
const ikokaRelease = release(currentControls.familyTag, '2026-09-13T00:00:00Z',
[ikokaNormal, ikokaLean].map(profile => {
[ikokaNormal].map(profile => {
const source = currentControls.profiles[profile.target].loggingSource;
const tag = currentControls.familyTag.replace(/-[0-9a-f]{8}$/, '-' + source.slice(0, 8));
return asset(profile.target + '-ota-' + tag + '.zip');
@@ -1090,7 +1087,8 @@ assert.deepStrictEqual(ikokaCatalog.profiles.filter(profile =>
['ikoka_stick_nrf_30dbm_repeater']);
const mismatchedIkoka = picker.buildCatalog([
release(currentControls.familyTag, '2026-09-13T00:00:00Z', [
asset('ikoka_stick_nrf_30dbm_repeater-ota-' + currentControls.familyTag + '.zip'),
asset('ikoka_stick_nrf_30dbm_repeater-ota-' +
currentControls.familyTag.replace(/-[0-9a-f]{8}$/, '-306feebe') + '.zip'),
]),
], currentControls).profiles[0];
assert.strictEqual(mismatchedIkoka.logging, 'none', 'Logging metadata must match the published build source');
@@ -1099,7 +1097,10 @@ assert(capacityProfiles.length > 0, 'Regeneration must preserve capacity directi
for (const profile of capacityProfiles) {
assert(picker.installSteps(profile, profile.installKinds[0]).includes(profile.controls.memoryNote), profile.target);
}
const currentObserver = currentCatalog.profiles.find(profile => profile.target === observer.target);
const currentObserver = currentCatalog.profiles.find(profile =>
profile.controls && profile.controls.mqtt &&
profile.controls.loggingModes && profile.controls.loggingModes.includes('both'));
assert(currentObserver);
assert.deepStrictEqual(picker.runtimeDirections(currentObserver, {logging: 'usb'})[0].actions[0].commands,
['set logging.output usb', 'get logging.output']);
const combinedControlData = JSON.parse(JSON.stringify(currentControls));