-
Notifications
You must be signed in to change notification settings - Fork 6
feat: Bambu AMS dashboard blueprint + tray_assign command (#148) #150
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
9 commits
Select commit
Hold shift + click to select a range
4a48254
feat(#148): add Bambu AMS dashboard HA blueprint
sjordan0228 d8fa741
feat(#148): replace input_text helpers with cmd/tray_assign MQTT publish
sjordan0228 be92ca2
feat(#148): add uid and spoolman_id fields to TrayData
sjordan0228 4a2edb6
feat(#148): add cmd/tray_assign handler with Spoolman weight lookup
sjordan0228 6f44ad8
feat(#148): wire Spoolman sync response to dashboard tray weight
sjordan0228 7d6be30
docs(#148): update flow diagram for cmd/tray_assign and no-helpers ap…
sjordan0228 9bd5bfc
fix(#148): move dashboard cache display to post-boot sequence for rel…
sjordan0228 5c6ca02
feat(#148): add cmd/deduct_tray handler and updated deduction blueprint
sjordan0228 b499cc7
fix(#148): address CodeRabbit findings — tojson filter, lang attr, or…
sjordan0228 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,259 @@ | ||
| <!DOCTYPE html> | ||
| <html lang="en"> | ||
| <head> | ||
| <title>Bambu AMS Dashboard — Data Flow</title> | ||
| <style> | ||
| body { | ||
| background: #1a1a2e; | ||
| font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; | ||
| display: flex; | ||
| justify-content: center; | ||
| padding: 30px; | ||
| color: #e0e0e0; | ||
| } | ||
| .diagram { width: 720px; } | ||
| h1 { text-align: center; color: #fff; font-size: 18px; margin-bottom: 30px; } | ||
| .row { display: flex; align-items: center; justify-content: center; margin-bottom: 6px; } | ||
| .box { | ||
| border-radius: 10px; padding: 14px 20px; text-align: center; | ||
| font-size: 13px; min-width: 200px; position: relative; | ||
| } | ||
| .box .label { font-weight: 700; font-size: 14px; margin-bottom: 4px; } | ||
| .box .detail { font-size: 11px; opacity: 0.85; } | ||
| .scanner { background: #2d6a4f; border: 2px solid #52b788; } | ||
| .nfc { background: #3a5a40; border: 2px solid #95d5b2; } | ||
| .printer { background: #5a189a; border: 2px solid #9d4edd; } | ||
| .ha { background: #1565c0; border: 2px solid #42a5f5; } | ||
| .blueprint { background: #0d47a1; border: 2px solid #1e88e5; } | ||
| .spoolman { background: #00695c; border: 2px solid #26a69a; } | ||
| .tft { background: #bf360c; border: 2px solid #ff7043; } | ||
| .arrow { | ||
| display: flex; flex-direction: column; align-items: center; | ||
| margin: 4px 0; color: #aaa; font-size: 11px; | ||
| } | ||
| .arrow .line { width: 2px; height: 18px; background: #555; } | ||
| .arrow .head { | ||
| width: 0; height: 0; | ||
| border-left: 6px solid transparent; border-right: 6px solid transparent; | ||
| border-top: 8px solid #555; | ||
| } | ||
| .arrow .msg { | ||
| background: #2a2a3e; padding: 3px 10px; border-radius: 6px; | ||
| border: 1px solid #444; margin: 2px 0; | ||
| font-family: 'Courier New', monospace; font-size: 11px; color: #ffd54f; | ||
| } | ||
| .split { display: flex; gap: 20px; justify-content: center; align-items: flex-start; } | ||
| .split-col { display: flex; flex-direction: column; align-items: center; } | ||
| .phase { | ||
| text-align: center; font-size: 11px; color: #888; | ||
| text-transform: uppercase; letter-spacing: 2px; | ||
| margin: 24px 0 12px; border-top: 1px dashed #333; | ||
| padding-top: 14px; width: 100%; | ||
| } | ||
| .note { | ||
| background: #2a2a3e; border: 1px dashed #555; border-radius: 8px; | ||
| padding: 10px 16px; font-size: 11px; color: #aaa; | ||
| text-align: center; margin: 6px 0; max-width: 400px; | ||
| } | ||
| </style> | ||
| </head> | ||
| <body> | ||
| <div class="diagram"> | ||
| <h1>Bambu AMS Dashboard — Full Data Flow</h1> | ||
|
|
||
| <!-- Phase 1: Spool Scan & Loading --> | ||
| <div class="phase">Phase 1 — Spool Scan & Loading</div> | ||
|
|
||
| <div class="row"> | ||
| <div class="box nfc"> | ||
| <div class="label">NFC Tag on Spool</div> | ||
| <div class="detail">UID, material, color, temps, weight</div> | ||
| </div> | ||
| </div> | ||
| <div class="arrow"> | ||
| <div class="line"></div> | ||
| <div class="msg">scan</div> | ||
| <div class="head"></div> | ||
| </div> | ||
| <div class="row"> | ||
| <div class="box scanner"> | ||
| <div class="label">SpoolSense Scanner</div> | ||
| <div class="detail">Reads NFC tag → publishes to MQTT</div> | ||
| </div> | ||
| </div> | ||
|
|
||
| <div class="split"> | ||
| <div class="split-col"> | ||
| <div class="arrow"> | ||
| <div class="line"></div> | ||
| <div class="msg">MQTT: spoolsense/{id}/tag/state</div> | ||
| <div class="detail" style="color:#aaa;font-size:10px">uid, material, color, remaining_g,<br>spoolman_id, temps</div> | ||
| <div class="head"></div> | ||
| </div> | ||
| <div class="row"> | ||
| <div class="box ha"> | ||
| <div class="label">Home Assistant</div> | ||
| <div class="detail">sensor.spoolsense_{id}_spool → "present"</div> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| <div class="split-col"> | ||
| <div class="arrow"> | ||
| <div class="line"></div> | ||
| <div class="msg">HTTP: Spoolman UID lookup (async)</div> | ||
| <div class="head"></div> | ||
| </div> | ||
| <div class="row"> | ||
| <div class="box spoolman" style="min-width:160px"> | ||
| <div class="label">Spoolman</div> | ||
| <div class="detail">Returns weight, spoolman_id</div> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| </div> | ||
|
|
||
| <div class="arrow"> | ||
| <div class="line"></div> | ||
| <div class="msg">trigger: sensor state → "present"</div> | ||
| <div class="head"></div> | ||
| </div> | ||
| <div class="row"> | ||
| <div class="box blueprint"> | ||
| <div class="label">Blueprint: SpoolSense → Bambu AMS</div> | ||
| <div class="detail">spoolsense_bambu_ams.yaml</div> | ||
| </div> | ||
| </div> | ||
|
|
||
| <div class="note">Waits for user to physically load spool into AMS tray<br>(wait_for_trigger: tray empty → not empty)</div> | ||
|
|
||
| <div class="split"> | ||
| <div class="split-col"> | ||
| <div class="arrow"> | ||
| <div class="line"></div> | ||
| <div class="msg">bambu_lab.set_filament</div> | ||
| <div class="detail" style="color:#aaa;font-size:10px">tray_type, tray_color,<br>tray_info_idx, temps</div> | ||
| <div class="head"></div> | ||
| </div> | ||
| <div class="row"> | ||
| <div class="box printer"> | ||
| <div class="label">Bambu Printer</div> | ||
| <div class="detail">Updates AMS tray info</div> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| <div class="split-col"> | ||
| <div class="arrow"> | ||
| <div class="line"></div> | ||
| <div class="msg">MQTT: cmd/tray_assign</div> | ||
| <div class="detail" style="color:#aaa;font-size:10px">{tray_index, uid, spoolman_id}</div> | ||
| <div class="head"></div> | ||
| </div> | ||
| <div class="row"> | ||
| <div class="box scanner" style="min-width:180px"> | ||
| <div class="label">Scanner stores UID→Tray</div> | ||
| <div class="detail">NVS: maps UID to tray index<br>Enqueues Spoolman weight lookup</div> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| </div> | ||
|
|
||
| <!-- Phase 2: Dashboard Update --> | ||
| <div class="phase">Phase 2 — Dashboard Update</div> | ||
|
|
||
| <div class="row"> | ||
| <div class="box printer"> | ||
| <div class="label">Bambu Printer</div> | ||
| <div class="detail">Reports tray state via Bambu MQTT</div> | ||
| </div> | ||
| </div> | ||
| <div class="arrow"> | ||
| <div class="line"></div> | ||
| <div class="msg">HA Bambu Lab Integration</div> | ||
| <div class="head"></div> | ||
| </div> | ||
| <div class="row"> | ||
| <div class="box ha"> | ||
| <div class="label">sensor.{printer}_ams_tray_{1-N}</div> | ||
| <div class="detail">type, color, empty, name</div> | ||
| </div> | ||
| </div> | ||
| <div class="arrow"> | ||
| <div class="line"></div> | ||
| <div class="msg">trigger: any tray state change</div> | ||
| <div class="head"></div> | ||
| </div> | ||
| <div class="row"> | ||
| <div class="box blueprint"> | ||
| <div class="label">Blueprint: Bambu AMS Dashboard</div> | ||
| <div class="detail">spoolsense_bambu_dashboard.yaml</div> | ||
| </div> | ||
| </div> | ||
| <div class="arrow"> | ||
| <div class="detail" style="color:#aaa;font-size:11px">Reads tray attributes (type, color, empty)<br>Builds JSON array, skips empty trays</div> | ||
| <div class="line"></div> | ||
| <div class="msg">MQTT: spoolsense/{id}/cmd/tray_update</div> | ||
| <div class="msg" style="font-size:10px;color:#ccc">[{tray_index, ams_id, material, color}, ...]</div> | ||
| <div class="head"></div> | ||
| </div> | ||
| <div class="row"> | ||
| <div class="box scanner"> | ||
| <div class="label">SpoolSense Scanner</div> | ||
| <div class="detail">Parses tray data → persists to NVS → renders dashboard</div> | ||
| </div> | ||
| </div> | ||
|
|
||
| <!-- Phase 3: Weight Enrichment --> | ||
| <div class="phase">Phase 3 — Weight Enrichment</div> | ||
|
|
||
| <div class="split"> | ||
| <div class="split-col"> | ||
| <div class="row"> | ||
| <div class="box scanner" style="min-width:220px"> | ||
| <div class="label">Spoolman Weight Lookup</div> | ||
| <div class="detail">Triggered by cmd/tray_assign<br>For trays with stored UIDs</div> | ||
| </div> | ||
| </div> | ||
| <div class="arrow"> | ||
| <div class="line"></div> | ||
| <div class="msg">HTTP: streaming UID lookup</div> | ||
| <div class="head"></div> | ||
| </div> | ||
| <div class="row"> | ||
| <div class="box spoolman"> | ||
| <div class="label">Spoolman</div> | ||
| <div class="detail">Returns remaining weight for UID</div> | ||
| </div> | ||
| </div> | ||
| <div class="arrow"> | ||
| <div class="line"></div> | ||
| <div class="msg">SPOOLMAN_SYNCED → update weight_g → re-render</div> | ||
| <div class="head"></div> | ||
| </div> | ||
| </div> | ||
| <div class="split-col" style="margin-top:10px"> | ||
| <div class="row"> | ||
| <div class="box scanner" style="min-width:200px"> | ||
| <div class="label">Deduction (follow-up)</div> | ||
| <div class="detail">cmd/deduct_tray arrives →<br>scanner resolves tray → UID →<br>subtract weight → re-render</div> | ||
| </div> | ||
| </div> | ||
| <div class="note" style="max-width:200px;margin-top:10px"> | ||
| Automatic weight updates<br>after every print —<br>pending print test verification | ||
| </div> | ||
| </div> | ||
| </div> | ||
|
|
||
| <div class="arrow"> | ||
| <div class="line"></div> | ||
| <div class="head"></div> | ||
| </div> | ||
| <div class="row"> | ||
| <div class="box tft"> | ||
| <div class="label">TFT Dashboard</div> | ||
| <div class="detail">2x2 / 2x4 / 4x4 grid — color, material, weight per tray</div> | ||
| </div> | ||
| </div> | ||
|
|
||
| </div> | ||
| </body> | ||
| </html> |
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
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,60 @@ | ||
| blueprint: | ||
| name: "SpoolSense → Bambu AMS Dashboard" | ||
| description: > | ||
| Keeps the SpoolSense TFT tray dashboard in sync with your Bambu AMS. | ||
| When any AMS tray changes (spool loaded, removed, or filament info updated), | ||
| the blueprint publishes the current tray state to the scanner via MQTT. | ||
| Requires the Bambu AMS Dashboard toggle enabled on the scanner config page. | ||
| domain: automation | ||
| input: | ||
| spoolsense_device_id: | ||
| name: SpoolSense Scanner Device ID | ||
| description: > | ||
| The scanner's device ID (e.g., 4d9620). Found on the scanner's landing page | ||
| or in the MQTT topic prefix. | ||
| selector: | ||
| text: {} | ||
| ams_tray_entities: | ||
| name: AMS Tray Sensors | ||
| description: > | ||
| Select all AMS tray sensor entities to monitor. Order matters — the first | ||
| entity is tray index 0, second is index 1, etc. For a single AMS, select | ||
| all 4 trays in order. For multiple AMS units, select all trays across units. | ||
| selector: | ||
| entity: | ||
| multiple: true | ||
| filter: | ||
| - domain: sensor | ||
|
|
||
| mode: queued | ||
| max_exceeded: silent | ||
| max: 3 | ||
|
|
||
| triggers: | ||
| - trigger: state | ||
| entity_id: !input ams_tray_entities | ||
|
|
||
| actions: | ||
| - variables: | ||
| scanner_id: !input spoolsense_device_id | ||
| tray_entities: !input ams_tray_entities | ||
|
|
||
| - variables: | ||
| tray_json: > | ||
| {% set ns = namespace(trays=[]) %} | ||
| {% for entity in tray_entities %} | ||
| {% set a = state_attr(entity, 'type') | default('') %} | ||
| {% set empty = state_attr(entity, 'empty') | default(true) %} | ||
| {% if not empty and a != '' and a != 'Empty' %} | ||
| {% set color_raw = state_attr(entity, 'color') | default('#000000FF') %} | ||
| {% set color = (color_raw | replace('#', ''))[:6] %} | ||
| {% set tray = {"tray_index": loop.index0, "ams_id": (loop.index0 // 4), "material": a, "color": color} | tojson %} | ||
| {% set ns.trays = ns.trays + [tray] %} | ||
| {% endif %} | ||
| {% endfor %} | ||
| [{{ ns.trays | join(',') }}] | ||
|
|
||
| - action: mqtt.publish | ||
| data: | ||
| topic: "spoolsense/{{ scanner_id }}/cmd/tray_update" | ||
| payload: "{{ tray_json }}" |
Oops, something went wrong.
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.
Uh oh!
There was an error while loading. Please reload this page.