Update Mesh America Companion catalogs for 1.17.1.2
This commit is contained in:
1 parent
c9652754cf
commit
23e91b792e
5 files changed
+2253
-2115
No files matched your search
+25
-18
@@ -16,16 +16,18 @@ Provider name: Keymind Cascade Logging
|
||||
Catalog URL: https://raw.githubusercontent.com/mikecarper/MeshCore/keymindCascade/mesh-america/keymind-cascade-logging-v1.16.0-provider.json
|
||||
```
|
||||
|
||||
The standard catalog currently tracks the v1.17.1.1 Cascade/USA release. Update
|
||||
its curated device and role choices from a completed all-target release with:
|
||||
The standard catalog currently keeps unaffected infrastructure on v1.17.1.1
|
||||
and tracks the corrective v1.17.1.2 release for every Companion role. Update
|
||||
only those Companion choices from the completed corrective matrix with:
|
||||
|
||||
```text
|
||||
python3 mesh-america/update-provider-release.py \
|
||||
--release-dir /path/to/release \
|
||||
--artifact-version v1.17.1.1-759a35fc \
|
||||
--main-tag v1.17.1.1-halo-keymind-cascade-759a35fc \
|
||||
--advanced-tag lora-ota-v1.17.1.1-halo-keymind-cascade-759a35fc \
|
||||
--utility-tag kiss-v1.17.1.1-halo-keymind-cascade-759a35fc
|
||||
--artifact-version v1.17.1.2-c9652754 \
|
||||
--main-tag v1.17.1.2-halo-keymind-cascade-c9652754 \
|
||||
--advanced-tag lora-ota-v1.17.1.2-halo-keymind-cascade-c9652754 \
|
||||
--utility-tag kiss-v1.17.1.1-halo-keymind-cascade-759a35fc \
|
||||
--companion-only
|
||||
```
|
||||
|
||||
The updater preserves the catalog's curated device names, role choices, and
|
||||
@@ -33,25 +35,30 @@ hardware guidance; validates every referenced artifact; routes URLs to the
|
||||
correct GitHub release page; and replaces legacy FULL MQTT choices with the
|
||||
matching portable MQTT observer builds.
|
||||
|
||||
The logging catalog tracks the diagnostic and expanded-partition profiles in
|
||||
the supplemental v1.17.1.1 release pages. Update it from the same completed
|
||||
matrix with:
|
||||
The logging catalog likewise keeps unaffected roles on v1.17.1.1 while its
|
||||
Companion, Full Companion, and expanded Companion logging profiles track the
|
||||
v1.17.1.2 correction. Logging builds are for a USB-connected MQTT/logging host;
|
||||
they are not the direct on-device Wi-Fi MQTT bridge. Update only the Companion
|
||||
choices from the same completed matrix with:
|
||||
|
||||
```text
|
||||
python3 mesh-america/update-logging-provider-release.py \
|
||||
--release-dir /path/to/release \
|
||||
--artifact-version v1.17.1.1-759a35fc \
|
||||
--logging-main-tag logging-v1.17.1.1-halo-keymind-cascade-759a35fc \
|
||||
--artifact-version v1.17.1.2-c9652754 \
|
||||
--logging-main-tag logging-v1.17.1.2-halo-keymind-cascade-c9652754 \
|
||||
--logging-utility-tag logging-utility-v1.17.1.1-halo-keymind-cascade-759a35fc \
|
||||
--full-tag full-profiles-v1.17.1.1-halo-keymind-cascade-759a35fc \
|
||||
--main-tag v1.17.1.1-halo-keymind-cascade-759a35fc \
|
||||
--advanced-tag lora-ota-v1.17.1.1-halo-keymind-cascade-759a35fc \
|
||||
--utility-tag kiss-v1.17.1.1-halo-keymind-cascade-759a35fc
|
||||
--full-tag full-profiles-v1.17.1.2-halo-keymind-cascade-c9652754 \
|
||||
--main-tag v1.17.1.2-halo-keymind-cascade-c9652754 \
|
||||
--advanced-tag lora-ota-v1.17.1.2-halo-keymind-cascade-c9652754 \
|
||||
--utility-tag kiss-v1.17.1.1-halo-keymind-cascade-759a35fc \
|
||||
--companion-only
|
||||
```
|
||||
|
||||
This updater preserves the logging catalog's curated role and hardware
|
||||
guidance, validates all 648 referenced firmware identities, and selects the
|
||||
release page that owns each file.
|
||||
In Companion-only mode, each updater preserves every unaffected catalog entry,
|
||||
validates every selected replacement artifact, and adds the one-time
|
||||
power-saving migration guidance. Without `--companion-only`, the existing
|
||||
all-role behavior remains available for a future complete matrix release; the
|
||||
logging updater then validates all 648 referenced firmware identities.
|
||||
|
||||
The older PowerShell generator remains available for the historical standard
|
||||
and logging source folders:
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
@@ -54,6 +54,14 @@ def parse_args() -> argparse.Namespace:
|
||||
parser.add_argument("--repo", default="mikecarper/MeshCore")
|
||||
parser.add_argument("--output", type=Path)
|
||||
parser.add_argument("--check-only", action="store_true")
|
||||
parser.add_argument(
|
||||
"--companion-only",
|
||||
action="store_true",
|
||||
help=(
|
||||
"update only Companion roles, preserving the versions and files for "
|
||||
"all unaffected roles"
|
||||
),
|
||||
)
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
@@ -83,23 +91,37 @@ def release_tag(identity: str, args: argparse.Namespace) -> str:
|
||||
return args.advanced_tag
|
||||
if is_logging_utility(identity):
|
||||
return args.utility_tag
|
||||
if any(marker in lowered for marker in ("companion", "repeater", "room_server")):
|
||||
if any(
|
||||
marker in lowered
|
||||
for marker in ("companion", "comp_radio", "repeater", "room_server")
|
||||
):
|
||||
return args.main_tag
|
||||
return args.utility_tag
|
||||
|
||||
|
||||
def update_catalog(catalog: dict, release_files: dict[str, list[Path]], args: argparse.Namespace) -> dict:
|
||||
display_version = args.artifact_version.rsplit("-", 1)[0]
|
||||
catalog["description"] = (
|
||||
f"Keymind Cascade MeshCore {display_version} firmware with Halo/Keymind "
|
||||
"retry tuning, Cascade defaults, and the USA/Canada 910.525 MHz / SF7 / "
|
||||
"BW62.5 / CR5 preset. This catalog contains packet-logging builds with "
|
||||
"USB debug enabled except on seven flash-constrained STM32 targets, "
|
||||
"selected non-logging utility and portable MQTT observer builds, "
|
||||
"and expanded-partition FULL USB-logging LoRa-OTA builds. Host software "
|
||||
"can consume the USB serial log and publish it separately. Open Release "
|
||||
"notes for role, hardware, installation, and partition requirements."
|
||||
)
|
||||
if args.companion_only:
|
||||
catalog["description"] = (
|
||||
"Keymind Cascade MeshCore v1.17.1.1 infrastructure firmware plus "
|
||||
f"corrected {display_version} Companion firmware, with Halo/Keymind "
|
||||
"retry tuning, Cascade defaults, and the USA/Canada 910.525 MHz / "
|
||||
"SF7 / BW62.5 / CR5 preset. Companion device power saving is enabled "
|
||||
"by default and migrated on once in the corrected release. Logging "
|
||||
"profiles are intended for a USB-connected MQTT/logging host. "
|
||||
"Unaffected roles remain on v1.17.1.1."
|
||||
)
|
||||
else:
|
||||
catalog["description"] = (
|
||||
f"Keymind Cascade MeshCore {display_version} firmware with Halo/Keymind "
|
||||
"retry tuning, Cascade defaults, and the USA/Canada 910.525 MHz / SF7 / "
|
||||
"BW62.5 / CR5 preset. This catalog contains packet-logging builds with "
|
||||
"USB debug enabled except on seven flash-constrained STM32 targets, "
|
||||
"selected non-logging utility and portable MQTT observer builds, "
|
||||
"and expanded-partition FULL USB-logging LoRa-OTA builds. Host software "
|
||||
"can consume the USB serial log and publish it separately. Open Release "
|
||||
"notes for role, hardware, installation, and partition requirements."
|
||||
)
|
||||
|
||||
entry_count = 0
|
||||
file_count = 0
|
||||
@@ -116,6 +138,8 @@ def update_catalog(catalog: dict, release_files: dict[str, list[Path]], args: ar
|
||||
for device in catalog["device"]:
|
||||
device_type = device["type"]
|
||||
for firmware in device["firmware"]:
|
||||
if args.companion_only and not firmware["role"].startswith("companion"):
|
||||
continue
|
||||
old_keys = list(firmware["version"])
|
||||
old_version = next(iter(firmware["version"].values()))
|
||||
old_notes = old_version["notes"]
|
||||
@@ -123,7 +147,7 @@ def update_catalog(catalog: dict, release_files: dict[str, list[Path]], args: ar
|
||||
paths: list[Path] = []
|
||||
for identity in identities:
|
||||
if identity not in release_files:
|
||||
raise ValueError(f"no v1.17.1.1 artifact matches {identity!r}")
|
||||
raise ValueError(f"no release artifact matches {identity!r}")
|
||||
used_identities.add(identity)
|
||||
paths.extend(release_files[identity])
|
||||
|
||||
@@ -181,7 +205,9 @@ def update_catalog(catalog: dict, release_files: dict[str, list[Path]], args: ar
|
||||
"turns packet logging ON while keeping USB debug OFF to fit this "
|
||||
"flash-constrained STM32 target."
|
||||
)
|
||||
if old_profile in notes:
|
||||
if replacement in notes:
|
||||
pass
|
||||
elif old_profile in notes:
|
||||
notes = notes.replace(old_profile, replacement, 1)
|
||||
elif standard_profile in notes:
|
||||
notes = notes.replace(
|
||||
@@ -196,14 +222,34 @@ def update_catalog(catalog: dict, release_files: dict[str, list[Path]], args: ar
|
||||
"cannot update constrained logging guidance for "
|
||||
f"{identities!r}"
|
||||
)
|
||||
if firmware["role"].startswith("companion"):
|
||||
notes = common.append_companion_power_saving_note(
|
||||
notes, display_version
|
||||
)
|
||||
if any("-logging" in identity.lower() for identity in identities):
|
||||
logging_note = (
|
||||
"LOGGING USE - This USB packet-logging build is for a "
|
||||
"USB-connected MQTT/logging host that reads the serial stream "
|
||||
"and publishes it. It is not the direct on-device Wi-Fi MQTT "
|
||||
"bridge."
|
||||
)
|
||||
if logging_note not in notes:
|
||||
notes += "\n\n" + logging_note
|
||||
firmware["version"] = {version_key: {"notes": notes, "files": files}}
|
||||
entry_count += 1
|
||||
file_count += len(files)
|
||||
|
||||
if entry_count != 596:
|
||||
raise ValueError(f"expected 596 curated firmware entries, found {entry_count}")
|
||||
if len(used_identities) != 648:
|
||||
raise ValueError(f"expected 648 curated identities, found {len(used_identities)}")
|
||||
expected_entries = 129 if args.companion_only else 596
|
||||
expected_identities = None if args.companion_only else 648
|
||||
if entry_count != expected_entries:
|
||||
raise ValueError(
|
||||
f"expected {expected_entries} curated firmware entries, found {entry_count}"
|
||||
)
|
||||
if expected_identities is not None and len(used_identities) != expected_identities:
|
||||
raise ValueError(
|
||||
f"expected {expected_identities} curated identities, "
|
||||
f"found {len(used_identities)}"
|
||||
)
|
||||
if file_count == 0:
|
||||
raise ValueError("catalog update produced no files")
|
||||
print(
|
||||
@@ -213,6 +259,7 @@ def update_catalog(catalog: dict, release_files: dict[str, list[Path]], args: ar
|
||||
"catalog_files": file_count,
|
||||
"release_identities_used": len(used_identities),
|
||||
"identity_categories": category_counts,
|
||||
"update_mode": "companion-only" if args.companion_only else "all",
|
||||
},
|
||||
sort_keys=True,
|
||||
)
|
||||
|
||||
@@ -36,6 +36,15 @@ LEGACY_PORTABLE_CEILING_EXCEPTIONS = {
|
||||
"t_beam_s3_supreme_sx1262_repeater_observer_mqtt",
|
||||
}
|
||||
|
||||
LEGACY_COMPANION_IDENTITY_ALIASES = {
|
||||
# The short-lived install-capable LoRa-OTA Wi-Fi Companion profile was
|
||||
# replaced by the ordinary Wi-Fi Companion plus the safer, serve-only Full
|
||||
# Companion profile. Keep the curated role available without claiming that
|
||||
# the replacement can LoRa-install firmware onto itself.
|
||||
"LilyGo_TBeam_1W_companion_radio_wifi-ota":
|
||||
"LilyGo_TBeam_1W_companion_radio_wifi",
|
||||
}
|
||||
|
||||
|
||||
def parse_args() -> argparse.Namespace:
|
||||
script_dir = Path(__file__).resolve().parent
|
||||
@@ -62,6 +71,14 @@ def parse_args() -> argparse.Namespace:
|
||||
action="store_true",
|
||||
help="validate and report without writing the output catalog",
|
||||
)
|
||||
parser.add_argument(
|
||||
"--companion-only",
|
||||
action="store_true",
|
||||
help=(
|
||||
"update only Companion roles, preserving the versions and files for "
|
||||
"all unaffected roles"
|
||||
),
|
||||
)
|
||||
return parser.parse_args()
|
||||
|
||||
|
||||
@@ -116,6 +133,10 @@ def resolve_release_identity(
|
||||
if old_identity in release_files:
|
||||
return old_identity, False
|
||||
|
||||
alias = LEGACY_COMPANION_IDENTITY_ALIASES.get(old_identity)
|
||||
if alias is not None and alias in release_files:
|
||||
return alias, False
|
||||
|
||||
# The previous catalog used expanded-partition FULL MQTT images. The new
|
||||
# standard matrix emits a portable MQTT observer under the same target name
|
||||
# without the build-only "-full-ota" filename marker.
|
||||
@@ -128,6 +149,25 @@ def resolve_release_identity(
|
||||
raise ValueError(f"no new release artifact matches catalog target {old_identity!r}")
|
||||
|
||||
|
||||
def replace_legacy_companion_ota_notes(notes: str) -> str:
|
||||
paragraphs: list[str] = []
|
||||
for paragraph in notes.split("\n\n"):
|
||||
if paragraph.startswith("PROFILE ") and "LoRa OTA companion:" in paragraph:
|
||||
paragraphs.append(
|
||||
"PROFILE - Standard Wi-Fi Companion: keeps the normal Wi-Fi and "
|
||||
"USB Companion interfaces with LoRa self-update off. Use Full "
|
||||
"Companion when the complete transports and host-backed LoRa-OTA "
|
||||
"seeding tools are needed."
|
||||
)
|
||||
elif paragraph.startswith("LORA OTA "):
|
||||
continue
|
||||
elif paragraph.startswith("SELECTION "):
|
||||
paragraphs.append(paragraph.replace(", OTA.", "."))
|
||||
else:
|
||||
paragraphs.append(paragraph)
|
||||
return "\n\n".join(paragraphs)
|
||||
|
||||
|
||||
def release_tag_for_identity(identity: str, args: argparse.Namespace) -> str:
|
||||
lowered = identity.lower()
|
||||
if (
|
||||
@@ -144,6 +184,7 @@ def release_tag_for_identity(identity: str, args: argparse.Namespace) -> str:
|
||||
return args.utility_tag
|
||||
if (
|
||||
"companion" in lowered
|
||||
or "comp_radio" in lowered
|
||||
or "repeater" in lowered
|
||||
or "room_server" in lowered
|
||||
):
|
||||
@@ -217,6 +258,21 @@ def append_partition_warning(notes: str, identities: list[str]) -> str:
|
||||
return notes + "\n\n" + warning
|
||||
|
||||
|
||||
def append_companion_power_saving_note(notes: str, display_version: str) -> str:
|
||||
paragraph = (
|
||||
f"POWER SAVING - {display_version} enables Companion device power saving "
|
||||
"by default. On first boot it migrates the saved Companion setting to on "
|
||||
"once, repairing devices that carried the regressed off value. A later "
|
||||
"explicit `powersaving off` choice remains persistent. This controls "
|
||||
"MCU/GPS idle saving and is separate from LoRa receive power saving "
|
||||
"(RXPS). On nRF52, an active USB data-host connection can intentionally "
|
||||
"keep the device awake; USB power from a charger alone does not."
|
||||
)
|
||||
if paragraph in notes:
|
||||
return notes
|
||||
return notes + "\n\n" + paragraph
|
||||
|
||||
|
||||
def observer_notes(
|
||||
role: str, display_version: str, identities: list[str], old_notes: str
|
||||
) -> str:
|
||||
@@ -270,16 +326,27 @@ def observer_notes(
|
||||
|
||||
def update_catalog(catalog: dict, release_files: dict[str, list[Path]], args: argparse.Namespace) -> dict:
|
||||
display_version = args.artifact_version.rsplit("-", 1)[0]
|
||||
catalog["description"] = (
|
||||
f"Keymind Cascade MeshCore {display_version} firmware with Halo/Keymind "
|
||||
"retry tuning, Cascade defaults, and the USA/Canada 910.525 MHz / SF7 / "
|
||||
"BW62.5 / CR5 preset. This catalog contains standard builds, Full "
|
||||
"Companion builds, compact LoRa-OTA builds, and portable MQTT observer "
|
||||
"builds with USB debug/packet logging off. On nRF52, Full Companion "
|
||||
"replaces separate BLE and USB choices; on ESP32, Full Companion is "
|
||||
"offered next to the BLE/USB variants. Open Release notes for role, "
|
||||
"hardware, installation, and partition requirements."
|
||||
)
|
||||
if args.companion_only:
|
||||
catalog["description"] = (
|
||||
"Keymind Cascade MeshCore v1.17.1.1 infrastructure firmware plus "
|
||||
f"corrected {display_version} Companion firmware, with Halo/Keymind "
|
||||
"retry tuning, Cascade defaults, and the USA/Canada 910.525 MHz / "
|
||||
"SF7 / BW62.5 / CR5 preset. Companion device power saving is enabled "
|
||||
"by default and migrated on once in the corrected release. Unaffected "
|
||||
"roles remain on v1.17.1.1. Open Release notes for role, hardware, "
|
||||
"installation, and partition requirements."
|
||||
)
|
||||
else:
|
||||
catalog["description"] = (
|
||||
f"Keymind Cascade MeshCore {display_version} firmware with Halo/Keymind "
|
||||
"retry tuning, Cascade defaults, and the USA/Canada 910.525 MHz / SF7 / "
|
||||
"BW62.5 / CR5 preset. This catalog contains standard builds, Full "
|
||||
"Companion builds, compact LoRa-OTA builds, and portable MQTT observer "
|
||||
"builds with USB debug/packet logging off. On nRF52, Full Companion "
|
||||
"replaces separate BLE and USB choices; on ESP32, Full Companion is "
|
||||
"offered next to the BLE/USB variants. Open Release notes for role, "
|
||||
"hardware, installation, and partition requirements."
|
||||
)
|
||||
|
||||
updated_entries = 0
|
||||
updated_files = 0
|
||||
@@ -289,13 +356,20 @@ def update_catalog(catalog: dict, release_files: dict[str, list[Path]], args: ar
|
||||
for device in catalog["device"]:
|
||||
device_type = device["type"]
|
||||
for firmware in device["firmware"]:
|
||||
if args.companion_only and not firmware["role"].startswith("companion"):
|
||||
continue
|
||||
old_keys = list(firmware["version"])
|
||||
old_notes = next(iter(firmware["version"].values()))["notes"]
|
||||
resolved_identities: list[str] = []
|
||||
converted_observer = False
|
||||
converted_legacy_companion_ota = False
|
||||
|
||||
for old_identity in ordered_catalog_identities(firmware):
|
||||
identity, converted = resolve_release_identity(old_identity, release_files)
|
||||
converted_legacy_companion_ota = (
|
||||
converted_legacy_companion_ota
|
||||
or old_identity in LEGACY_COMPANION_IDENTITY_ALIASES
|
||||
)
|
||||
if identity not in resolved_identities:
|
||||
resolved_identities.append(identity)
|
||||
converted_observer = (
|
||||
@@ -337,12 +411,21 @@ def update_catalog(catalog: dict, release_files: dict[str, list[Path]], args: ar
|
||||
else:
|
||||
version_key = replacement_version_key(old_keys[0], args.artifact_version)
|
||||
notes = replace_release_version(old_notes, display_version)
|
||||
if converted_legacy_companion_ota:
|
||||
notes = replace_legacy_companion_ota_notes(notes)
|
||||
notes = append_partition_warning(notes, resolved_identities)
|
||||
|
||||
if firmware["role"].startswith("companion"):
|
||||
notes = append_companion_power_saving_note(notes, display_version)
|
||||
|
||||
firmware["version"] = {version_key: {"notes": notes, "files": files}}
|
||||
updated_entries += 1
|
||||
updated_files += len(files)
|
||||
|
||||
if args.companion_only and updated_entries != 216:
|
||||
raise ValueError(
|
||||
f"expected 216 curated Companion entries, found {updated_entries}"
|
||||
)
|
||||
if updated_entries == 0 or updated_files == 0:
|
||||
raise ValueError("catalog update produced no firmware entries")
|
||||
|
||||
@@ -353,6 +436,7 @@ def update_catalog(catalog: dict, release_files: dict[str, list[Path]], args: ar
|
||||
"catalog_files": updated_files,
|
||||
"observer_entries": observer_entries,
|
||||
"release_identities_used": len(used_identities),
|
||||
"update_mode": "companion-only" if args.companion_only else "all",
|
||||
},
|
||||
sort_keys=True,
|
||||
)
|
||||
|
||||
Reference in new issue
Block a user