Granular network state events for backup/restore#46
Conversation
|
We may not be able to get XNCP support merged anytime soon but at least the new AFAIK, |
|
I'm debating whether or not it would be better to break the "no state" seal and maybe persist some of this info to disk as cache, to simplify implementations? Right now this hardcodes "one NWK one route" but in the future this will not be the case... On the other hand, the whole purpose of this change is to bootstrap the stack after reloading, as otherwise things are slow for a few minutes. We could also just...not reset Ziggurat after connecting, to sidestep this issue entirely. Or accept "incomplete" cache restoration as an acceptable limitation. |
Being able to backup the entire network incl. routes is pretty huge, IMHO.
I like the idea of |
Yeah. At the end of the day this is all just cache, the network won't really suffer if this data isn't persisted. I think the actual impact of not storing/restoring the route cache is minimal, IMO: EmberZNet already keeps it all in RAM and discards it when you reset the adapter. zigpy and I think herdsman reset adapters pretty religiously on startup. With Rust's memory safety, maybe we can skip a startup reset if the current network settings are already correct, since all expected state is effectively contained to a few tables? That way, a host-side app can keep running indefinitely and survive Zigbee integration restarts. The only "downtime" would be after a full reboot, in which case you end up with a slow start scenario like you have with EmberZNet (though I imagine we can maybe do some hacks to speed up a cold start or at least make one feel more responsive). |
Both libraries were designed with finicky NCPs in mind, so it makes sense to at least offer the (default?) option to skip reset for Zigbee-on-Host setups.
Good compromise, IMO. It's unlikely that network parameters change during Z2M/ZHA reset, but |
|
Since these are strictly new commands, I'm going to merge this PR. We can remove them in a v1.0.0 release if they don't find much use or pose issues. |
ziggurat-spinel's SpinelClient was hard-coded to tokio_serial::SerialStream. Generalize it to a boxed RcpTransport (any AsyncRead + AsyncWrite), and teach ziggurat-server to open a TcpStream when --device is given as tcp://host:port, falling back to the existing serial-port path otherwise. Rebased onto dev (through zigpy#46, "Granular network state events for backup/restore"). The wire protocol was rewritten from JSON-over-WebSocket to a COBS-framed binary protocol (zigpy#38, ziggurat-protocol) since this was last rebased; only ziggurat-spinel/src/client.rs and the transport-opening half of ziggurat-server/src/main.rs (SerialConfig, open_transport, fn phy and its callers) needed re-applying — the request/response dispatch layer itself was untouched by this change and is left as upstream has it. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Adds a few new commands:
LoadRouteTable([destination: Nwk, next_hop: Nwk, path_cost: u8]): load a batch of routesLoadSourceRoutes([destination: Nwk, relays: [Nwk]]): load a batch of source route relays.RouteChanged(destination: Nwk, next_hop: Nwk, path_cost: u8, removed: bool): a route todestinationhas changed or has been removed.RouteRecord(destination: Nwk, relays: [Nwk]): a node sent a route record notification after forwarding some data.ApsFrameCounter(frame_counter: u32): APS frame counter has incremented by 100This allows zigpy to fully maintain a clone of the network state at runtime without performing periodic backups. On my network it's only a few events per minute. This allows zigpy to re-seed the entire Ziggurat state on startup.
Implemented in zigpy/zigpy-ziggurat#3 + zigpy/zigpy#1856