Stream memory snapshots to one client IP instead of network broadcast - #369
Open
mullinmax wants to merge 7 commits into
Open
Stream memory snapshots to one client IP instead of network broadcast#369mullinmax wants to merge 7 commits into
mullinmax wants to merge 7 commits into
Conversation
Broadcasting memory snapshots to 255.255.255.255 sprayed every Vector board (and everything else) on the network with UDP traffic. The /api/memory/toggle-broadcast route now unicasts to a single target IP: the "ip" field in the request body, or by default the requesting client's IP (now captured on Request.client_ip from the connection's peername; None over USB, where "ip" must be supplied). The target IP is baked into a per-enable closure that lives only in the scheduler's task list — no module-level state remembers it, so nothing is held in memory when streaming is off. A new unschedule_by_name() helper in phew removes the closure without needing a reference to it, and each enable replaces any previous sender so there is always at most one stream target. The admin page toggle is removed entirely (HTML + JS); this is API-only now, driven by tools like Memory Mapper. Route docs regenerated. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Xy1GfVJXuAkgZTMwUDDRTb
Contributor
|
Developer build links: Sys11 (Tiny) WPC EM WhiteStar DataEast Classic |
mullinmax
commented
Jul 16, 2026
Comment on lines
1771
to
1803
| @@ -1742,12 +1788,18 @@ def app_memory_broadcast(request): | |||
| elif freq > 60000: | |||
| freq = 60000 | |||
|
|
|||
| # Ensure we don't accumulate multiple scheduled entries for the same function | |||
| unschedule(broadcast_memory_snapshot) | |||
| schedule(broadcast_memory_snapshot, phase_ms=0, frequency_ms=freq) # broadcast every freq milliseconds | |||
| # Stream to the explicitly requested IP, or back to whoever asked. | |||
| # (Over USB there is no client IP, so "ip" must be supplied.) | |||
| ip = data.get("ip") or request.client_ip | |||
| if not ip or not _valid_ipv4(str(ip)): | |||
| return '{"error":"a target ip is required"}', 400 | |||
|
|
|||
| # Never accumulate senders: one stream target at a time. | |||
| unschedule_by_name("send_memory_snapshot") | |||
| schedule(_make_memory_snapshot_sender(str(ip)), phase_ms=0, frequency_ms=freq) | |||
| else: | |||
| # remove function call from scheduler | |||
| unschedule(broadcast_memory_snapshot) | |||
| # Remove the sender from the scheduler (drops its baked-in IP too) | |||
| unschedule_by_name("send_memory_snapshot") | |||
| return | |||
Contributor
Author
There was a problem hiding this comment.
This function can be cleaner by making the disable path a guard clause
Contributor
There was a problem hiding this comment.
Pull request overview
This PR changes the memory snapshot streaming behavior so /api/memory/toggle-broadcast no longer UDP-broadcasts to the subnet, but instead unicasts snapshots to a single target IPv4 address (explicit ip in the request body, or defaulting to the requesting client’s IP captured by phew). It also removes the admin UI toggle for this feature and updates the generated route docs accordingly.
Changes:
- Capture the requesting client IP in
phew.server.Request.client_ipand addunschedule_by_name()for unscheduling closure-based tasks. - Update
/api/memory/toggle-broadcastto stream snapshots to a single target IP (with optionalfrequency_ms), replacing any prior sender. - Remove the admin page “Broadcast Memory Snapshots” UI and regenerate route docs; bump
VectorVersion.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| src/common/web/js/admin.js | Removes the admin JS handler for the memory broadcast toggle. |
| src/common/web/html/admin.html | Removes the “Broadcast Memory Snapshots” toggle UI from the Debug section. |
| src/common/SharedState.py | Bumps VectorVersion to 1.11.28. |
| src/common/phew/server.py | Adds Request.client_ip capture and unschedule_by_name() for scheduled tasks. |
| src/common/backend.py | Switches memory snapshot streaming from broadcast to per-client unicast with IP validation and task replacement. |
| docs/routes.md | Updates autogenerated route documentation for the new request/response shape and handler line references. |
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
Address review feedback: the closure docstring implied zero memory retention; state precisely that the target IP is held only by the closure in the scheduler's task list and is released on unschedule. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Xy1GfVJXuAkgZTMwUDDRTb
The build_and_release run failed in a github-script step with a GitHub 5xx error page, unrelated to the changes. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Xy1GfVJXuAkgZTMwUDDRTb
build_and_release failed twice in a row when the git-data API returned a GitHub-side 500 (Unicorn page) while publishing PR update artifacts; the step ran with retries: 0 so a single transient server error failed the whole build. Let github-script retry these calls (5xx is retried by default; 4xx stays exempt). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Xy1GfVJXuAkgZTMwUDDRTb
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
/api/memory/toggle-broadcastno longer broadcasts memory snapshots to255.255.255.255— it unicasts them to a single target IP. The target is the optional"ip"field in the request body, defaulting to the requesting client's IP, which phew now captures onRequest.client_ipfrom the connection's peername (Noneover USB, where"ip"must be supplied; a missing/invalid target returns 400).The target IP is baked into a per-enable closure (
_make_memory_snapshot_sender(ip)) that lives only in the scheduler's task list — no module-level state remembers it, so no memory is held at all when streaming is off. A newunschedule_by_name()helper inphew/server.pyremoves the closure without needing a reference to it, and each enable replaces any previous sender so there is at most one stream target at a time.The "Broadcast Memory Snapshots" toggle is removed from the admin page entirely (HTML fieldset +
initMemoryBroadcastToggle()in admin.js) — this is API-only now, driven by tools like Memory Mapper. Route docs regenerated withtools/gen_api_docs.py.Related Issues
Companion PRs: python-library#13 (library wrapper gains the
ipparameter) and memory-mapper#31 (consumes the new behavior).Motivation and Context
Broadcasting the full SRAM as UDP to the whole subnet sprayed every Vector board (and everything else) on the network with traffic and caused issues on multi-board networks. Sending directly to the one client that asked eliminates that entirely.
Testing
python -m py_compileon the modified Python files;node --checkon admin.js.unschedule_by_namepairing against the scheduler's tuple-based task list (t[0].__name__matching), and that repeated enables replace rather than accumulate senders.{"enable": true, "frequency_ms": N, "ip": "..."}and disable{"enable": false}.writer.get_extra_info("peername")and closure__name__behavior on the deployed MicroPython build.Screenshots (if applicable)
N/A — the only UI change is the removal of the Debug-section toggle.
Types of Changes
Checklist
Additional Notes
Breaking for callers that enabled the broadcast over USB without an
ip(there is no client IP to default to). Packet format on the wire is unchanged (4-byte big-endian offset header + up to 256 data bytes, UDP port 2040), so existing listeners keep working — they just have to be the requested target.🤖 Generated with Claude Code
https://claude.ai/code/session_01Xy1GfVJXuAkgZTMwUDDRTb
Generated by Claude Code