Home IO Control
ESPHome add-on for IO-Homecontrol devices
Loading...
Searching...
No Matches
home_io_control.lr1121_firmware Namespace Reference

Classes

class  Lr1121FirmwareError
class  Lr1121FirmwareNotFoundError
class  FirmwareImage

Functions

 parse_github_source (value)
 resolve_raw_url (owner, repo, path, ref)
 parse_md5_sidecar (text)
 validate_image_class (path, *, expect_loader)
 parse_version_from_filename (path)
 validate_image (data, url)
 validate_bootloader_reachability (radio_type, has_busy_pin, busy_pin_inverted)
 resolve_target_version (source, target_version)
 classify_bootloader_upgrade_class (target_fw)
 fetch_and_verify (source, ref, checksum_md5, target_version, fetch)

Variables

 _GITHUB_SOURCE_RE = re.compile(r"^github://(?P<owner>[^/]+)/(?P<repo>[^/]+)/(?P<path>[^@]+?)(?:@(?P<ref>[^@]+))?$")
 _MD5_HEX_RE = re.compile(r"^[0-9a-f]{32}$")
 _VERSION_RE = re.compile(r"_(?P<major>[0-9a-f]{2})(?P<minor>[0-9a-f]{2})\.bin$", re.IGNORECASE)
dict KNOWN_BOOTLOADER_REQUIREMENTS
int LR1121_BOOTLOADER_2100 = 0x2100
int LR1121_BOOTLOADER_2101 = 0x2101

Function Documentation

◆ classify_bootloader_upgrade_class()

home_io_control.lr1121_firmware.classify_bootloader_upgrade_class ( target_fw)
Classify whether a `bootloader:` sub-block is safe given the outer `source:`'s target.

Implements the build-time half of ADR 0021's compatibility rule: it
must stay three-way, like the C++ side's runtime compatibility rule, or it rots the first time
Semtech ships a new firmware release this table has never heard of.
@return "accept" (target known, requires the new bootloader 0x2101 -- C3),
        "hard_error" (target known, requires the OLD bootloader 0x2100 -- C4; post-upgrade
        this image would be unflashable, so the block would be arming a trap),
        "unknown" (target absent from the table -- C5; accept with a warning, since refusing
        outright would rot on the next Semtech release).

Definition at line 200 of file lr1121_firmware.py.

◆ fetch_and_verify()

home_io_control.lr1121_firmware.fetch_and_verify ( source,
ref,
checksum_md5,
target_version,
fetch )
Fetch, verify, and interpret the firmware image a YAML block points at.

Ties together every function above: resolves the URL, fetches the `.bin`, fetches its
`.md5` sidecar (falling back to `checksum_md5` when absent, failing only if neither is
available), verifies the hash, validates the image shape, and resolves the target version.

@param source Raw `source:` YAML value (a github:// shorthand string).
@param ref Optional YAML `ref:` override; takes precedence over an `@ref` embedded in `source`.
@param checksum_md5 Optional user-supplied hash (lowercase or uppercase hex), or None.
@param target_version Optional user-supplied version override (int), or None/0 to derive
       from the filename.
@param fetch Callable `fetch(url: str, expected_hash: str | None = None) -> bytes`, raising
       Lr1121FirmwareNotFoundError for a definite "does not exist" (e.g. HTTP 404) and any
       other exception on a harder failure (network error, ...), which is left to propagate
       uncaught. `expected_hash`, when given, is a hint a caching `fetch` may use to key its
       cache (see __init__.py's _cached_http_fetch) -- it carries no meaning here beyond that.
@return A verified FirmwareImage.
@raises Lr1121FirmwareError (or whatever `fetch` raises) on any failure.

Definition at line 227 of file lr1121_firmware.py.

Here is the call graph for this function:

◆ parse_github_source()

home_io_control.lr1121_firmware.parse_github_source ( value)
Parse a `github://` shorthand into (owner, repo, path, ref).

`ref` defaults to "HEAD" when no `@ref` suffix is present.
@raises Lr1121FirmwareError if `value` doesn't match the expected shape.

Definition at line 48 of file lr1121_firmware.py.

◆ parse_md5_sidecar()

home_io_control.lr1121_firmware.parse_md5_sidecar ( text)
Extract the hash from a `.bin.md5` sidecar's contents.

Only the first whitespace-separated token is the hash. The second field is NOT a stable
filename -- some published sidecars carry a bare filename, others a relative release-artefact
path -- so it is read and then deliberately never validated.
@raises Lr1121FirmwareError if the first token isn't 32 lowercase hex characters.

Definition at line 69 of file lr1121_firmware.py.

◆ parse_version_from_filename()

home_io_control.lr1121_firmware.parse_version_from_filename ( path)
Derive a firmware version from a filename like `lr1121_transceiver_0104.bin`.

@return The version as a 16-bit int (major<<8 | minor), or None when the filename carries
        no parseable version -- that is NOT an error, see fetch_and_verify().

Definition at line 118 of file lr1121_firmware.py.

◆ resolve_raw_url()

home_io_control.lr1121_firmware.resolve_raw_url ( owner,
repo,
path,
ref )
Resolve a parsed github:// source to its raw.githubusercontent.com URL.

Definition at line 64 of file lr1121_firmware.py.

◆ resolve_target_version()

home_io_control.lr1121_firmware.resolve_target_version ( source,
target_version )
Resolve the target firmware version from `source`/`target_version` without any network access.

Same resolution order fetch_and_verify() uses (explicit override, else filename, else 0 ==
unknown) -- factored out so schema-time bootloader-compatibility checks (see
classify_bootloader_upgrade_class() below) can classify a `bootloader:` block's outer target
before to_code()'s network fetch happens.
@raises Lr1121FirmwareError if `source` doesn't match the expected github:// shape.

Definition at line 170 of file lr1121_firmware.py.

Here is the call graph for this function:

◆ validate_bootloader_reachability()

home_io_control.lr1121_firmware.validate_bootloader_reachability ( radio_type,
has_busy_pin,
busy_pin_inverted )
Reject configurations that can't reach the LR1121 bootloader, or would reach it wrong.

Pure mirror of __init__.py's schema-time checks -- kept here, not there, so it is
host-testable like every other check in this module (see file header). @raises
Lr1121FirmwareError; __init__.py is the only place that translates it to cv.Invalid.

Definition at line 151 of file lr1121_firmware.py.

◆ validate_image()

home_io_control.lr1121_firmware.validate_image ( data,
url )
Validate that `data` has the shape of an LR1121 transceiver firmware image.

Deliberately narrow -- length must be a whole (and non-zero) number of 32-bit words, and the
URL must name the chip family. No size band: published images range from 65 KB to 245 KB, both
legitimate, so guessing a plausible size band from a sample would reject valid images.
@raises Lr1121FirmwareError on any check failing.

Definition at line 130 of file lr1121_firmware.py.

◆ validate_image_class()

home_io_control.lr1121_firmware.validate_image_class ( path,
* ,
expect_loader )
Reject a `source:` naming the wrong LR1121 image class, by filename.

A blocklist of two known-bad patterns, not an allowlist requiring e.g. "transceiver" in the
name -- an allowlist would break a user mirroring images under their own names. Semtech's own
tool refuses a loader image as an ordinary firmware target outright; this project had no
such guard, and a loader/modem source previously passed validation
and was routed through the two-press UNKNOWN_TARGET confirmation, leaving the radio running a
non-transceiver image after the flash -- SPI still answers, but there is no radio function.
@param expect_loader True when validating the bootloader sub-block's `source:` (must BE a
       loader image); False for the ordinary transceiver `source:` (must NOT be one).
@raises Lr1121FirmwareError on a filename/class mismatch.

Definition at line 85 of file lr1121_firmware.py.

Variable Documentation

◆ _GITHUB_SOURCE_RE

home_io_control.lr1121_firmware._GITHUB_SOURCE_RE = re.compile(r"^github://(?P<owner>[^/]+)/(?P<repo>[^/]+)/(?P<path>[^@]+?)(?:@(?P<ref>[^@]+))?$")
protected

Definition at line 39 of file lr1121_firmware.py.

◆ _MD5_HEX_RE

home_io_control.lr1121_firmware._MD5_HEX_RE = re.compile(r"^[0-9a-f]{32}$")
protected

Definition at line 41 of file lr1121_firmware.py.

◆ _VERSION_RE

home_io_control.lr1121_firmware._VERSION_RE = re.compile(r"_(?P<major>[0-9a-f]{2})(?P<minor>[0-9a-f]{2})\.bin$", re.IGNORECASE)
protected

Definition at line 45 of file lr1121_firmware.py.

◆ KNOWN_BOOTLOADER_REQUIREMENTS

dict home_io_control.lr1121_firmware.KNOWN_BOOTLOADER_REQUIREMENTS
Initial value:
1= {
2 0x0101: 0x2100,
3 0x0102: 0x2100,
4 0x0103: 0x2100,
5 0x0104: 0x2101,
6}

Definition at line 190 of file lr1121_firmware.py.

◆ LR1121_BOOTLOADER_2100

int home_io_control.lr1121_firmware.LR1121_BOOTLOADER_2100 = 0x2100

Definition at line 196 of file lr1121_firmware.py.

◆ LR1121_BOOTLOADER_2101

int home_io_control.lr1121_firmware.LR1121_BOOTLOADER_2101 = 0x2101

Definition at line 197 of file lr1121_firmware.py.