|
Home IO Control
ESPHome add-on for IO-Homecontrol devices
|
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 |
| 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.
| 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.
| 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.
| 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.
| 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.
| 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.
| 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.
| 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.
| 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.
| 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.
|
protected |
Definition at line 39 of file lr1121_firmware.py.
|
protected |
Definition at line 41 of file lr1121_firmware.py.
|
protected |
Definition at line 45 of file lr1121_firmware.py.
| dict home_io_control.lr1121_firmware.KNOWN_BOOTLOADER_REQUIREMENTS |
Definition at line 190 of file lr1121_firmware.py.
| int home_io_control.lr1121_firmware.LR1121_BOOTLOADER_2100 = 0x2100 |
Definition at line 196 of file lr1121_firmware.py.
| int home_io_control.lr1121_firmware.LR1121_BOOTLOADER_2101 = 0x2101 |
Definition at line 197 of file lr1121_firmware.py.