-
released this
2026-08-07 23:29:27 +01:00 | 27 commits to main since this release-
mobius-scan's default now also connects to ONE device and dumps
real mesh addresses for its whole network, not just the pan_id
listing. Reuses the exact same verbose discovery--dump-mesh-peers
already used (_debug_mesh_discovery()--MLPrefix/
NetworkedThreadDevicesfirst, falling back to the older Cowboy-hub
mechanism), so the output is identical in shape whether it happens via
the default run or that flag explicitly.--scan-onlynow has real
meaning again (it had briefly become a no-op after the previous
change made the pan_id listing itself the whole default): it skips
this connection step, for a genuinely connection-free run.
--dump-tanksstill exists separately for connecting to EVERY pan_id
group rather than just one, useful when multiple genuinely separate
tanks/networks are in range at once. Verified end-to-end with the
scan/connect layer mocked out: confirmed exactly oneMobiusDevice
connection gets created by the plain default (to the correct,
first-found serial), and confirmed--scan-onlystill makes zero. -
Added
Tankanddiscover_tank(): the connection-based building
block for full tank discovery (device + address + age + shared
prefix, all in one call) -- the "basic block" a downstream integration
(e.g. ha-mobius) can call to trigger an on-demand scan and show
address/age/prefix for its devices.discover_tank(mdevice)takes an
already-connectedMobiusDevice, callsdiscover_mesh_peers_auto()
plusget_own_mesh_address()/get_device_info()to include the
connected device itself in the result (the peer-discovery calls only
ever report OTHER devices, never themselves) -- so a single-device
tank correctly comes back with that one device as its sole peer, not
an empty list that would be indistinguishable from "discovery failed
entirely."tank.prefixisNone(andpeersalways empty) if the
connected device didn't report a valid mesh address at all. 3 new
tests. Also exportedmesh_local_prefix_from_mlprefix()from the
top-levelmobiuspackage -- a real gap from when it was first added,
caught while adding these new exports alongside it. -
mobius-scan's default behavior changed: now genuinely just scans
and lists devices grouped by tank, no connections at all -- it used
to print that same pan_id-grouped listing (already existed, already
connection-free) and then STILL go on to connect to every single
scanned device for a full summary regardless. That's now opt-in via a
new--full-summariesflag instead of being the implicit default.
Added--dump-tanks: connects to just ONE device per pan_id group
(not every device) and calls the newdiscover_tank()on it, printing
the full mesh-address/age for every device sharing that tank --
richer than the default listing, which only has whatever's in the BLE
advertisement (model/serial), not address or age.--scan-onlykept
accepted as a no-op (it's redundant now that its old behavior IS the
default) rather than removed, so no existing script using it
explicitly breaks. Renamed the printed header from "Pan ID groups" to
"Tanks" to match. Verified end-to-end with the scan/connect layer
mocked out, for both the new default (confirmed zero MobiusDevice
connections created) and--dump-tanks(confirmed it correctly
prints prefix/address/age for a 2-device tank), not just via
--help's rendered text. -
discover_networked_thread_devices()confirmed against real
hardware (a live 4-device tank: 2 VorTech pumps, 2 Radion lights) --
the byte layout, little-endian field order, and all 4 real peers'
model/serial/age/derived-address all matched exactly. One real
correction from this: empty slots on real hardware are encoded as 28
bytes of raw zero (an all-null-byte serial), not the ASCII
"00000000000000"sentinel stringdiscover_mesh_peers()'s older
mechanism uses -- the existingif not serialfilter already handled
this correctly (an all-null-byte serial decodes to an empty string
after stripping), but the docstring incorrectly claimed this newer
mechanism used the same ASCII convention as the older one. Docstring
corrected; added a dedicated test for the actual null-byte case, plus
a new test replaying the exact real capture end-to-end (all 4 peers,
interleaved with the 26 real empty slots). -
Added
NetworkedThreadDevices(1001) +MLPrefix(2128) support: a
second, better Thread mesh peer-discovery mechanism. Confirmed via
reverse engineering the app's own tank-setup logic to be checked via a
generic support check on the connected device, not gated to a
Cowboy hub the way the existing three-parallel-arrays mechanism
(discover_mesh_peers()) is -- found while investigating whether the
app caches device mesh addresses at all (it does, persisting them to
a local file and syncing them to a cloud backend as part of each
device's saved state; this attribute is what actually populates that
cache in the first place).MobiusDevice.discover_networked_thread_devices()
fetches both attributes and returns every peer the connected device
knows about in a single round-trip, including a per-peer "age" value
(present in the confirmed wire format, but its exact meaning isn't
independently confirmed against real hardware -- seeMeshPeer's own
docstring).MeshPeergained anage: Optional[int] = Nonefield
(only ever set by this new method;Nonefrom every other source, a
non-breaking addition verified against all 4 existingMeshPeer(...)
construction sites, all of which use keyword arguments). Added
mesh_local_prefix_from_mlprefix()tomobius.mesh_address
(MLPrefix's own response is 24 bytes; only the first 8 are the real
prefix, confirmed via reverse engineering). -
Added
MobiusDevice.discover_mesh_peers_auto(): the new
recommended default entry point for mesh peer discovery, replacing
the previous recommendation to calldiscover_mesh_peers()or
discover_mesh_peers_via_direct_connect()directly depending on
hardware. Triesdiscover_networked_thread_devices()first, falling
back todiscover_mesh_peers()only if that finds nothing --
discover_mesh_peers_via_direct_connect()isn't included in this
chain, since it needs a list of scanned devices as input rather than
an already-connectedMobiusDevice; it remains the right fallback to
reach for explicitly if both of the above come back empty. -
On "discovering Tanks": investigated and confirmed not locally
possible -- the app's own "Tank" grouping is account-level and
cloud-synced, with user-edited metadata (name, photo) that has no
local/BLE equivalent to read. The closest local approximation this
library can offer: every peerdiscover_networked_thread_devices()
returns shares the connected device's ownMLPrefix, which in
practice is "every device on the same Thread mesh" -- for a typical
setup, the same thing as "every device in the same aquarium."
Documented as an approximation, not presented as equivalent to the
app's own Tank object. -
mobius-scanCLI updated to match:--dump-mesh-peersand
--relay-targetnow run the newdiscover_mesh_peers_auto()
priority order (step 0:MLPrefix/NetworkedThreadDevices, falling
through to the existing Cowboy-hub-specific steps only if that finds
nothing) instead of only ever exercising the older mechanism;
--dump-mesh-peers' output now also prints each peer'sagewhen
set.--build-peer-mapunchanged in behavior, now documented as the
last-resort fallback when both attribute-based mechanisms come back
empty. 10 new tests covering the new discovery method, the prefix
helper, and both branches ofdiscover_mesh_peers_auto()'s fallback
logic -- plus two direct end-to-end simulations of the updated CLI
debug path (both the new-mechanism-succeeds case and the
falls-through-to-the-old-mechanism case) run manually before
delivery, not just unit-level mocks.
Downloads
-
Source code (ZIP)
2 downloads
-
Source code (TAR.GZ)
1 download
-