Skip to content

feat: Add HACS Home Assistant Integration for AMS Tray Management#16

Closed
Switchbot-Nova wants to merge 18 commits intogibz104:mainfrom
Switchbot-Nova:main
Closed

feat: Add HACS Home Assistant Integration for AMS Tray Management#16
Switchbot-Nova wants to merge 18 commits intogibz104:mainfrom
Switchbot-Nova:main

Conversation

@Switchbot-Nova
Copy link

@Switchbot-Nova Switchbot-Nova commented Feb 15, 2026

Add Home Assistant HACS Integration for AMS Tray Management

🎯 Summary

This PR adds a fully-featured HACS-compatible Home Assistant integration that allows users to manage Bambu Lab AMS tray spool assignments directly from Home Assistant dashboards, without needing the SpoolmanSync web UI.

✨ New Features

  • Config Flow: Simple setup asking for SpoolmanSync URL (e.g., http://192.168.0.34:3000).
  • AMS Tray Entities: select entities for AMS Tray 1-4 and External Spool, grouped under printer devices.
  • Spool Info Sensors: Detailed sensors showing vendor, material, remaining weight, color, etc.
  • Custom Lovelace Card: Native Tile-based card with visual editor (4 entity pickers for trays). Matches modern HA aesthetic.
  • Device Grouping: Entities organized under printer devices for clean UI.
  • Automatic Sync: Polls SpoolmanSync API every 30s for real-time updates.

📦 HACS Installation

  1. Add custom repository: https://github.com/gibz104/SpoolmanSync (Integration category).
  2. Download & restart HA.
  3. Add integration → Enter SpoolmanSync URL.

🛠️ Technical Details

  • Directory: custom_components/spoolmansync/
  • HACS Support: hacs.json + manifest.json.
  • Custom Card: www/spoolmansync-card.js with Shadow DOM, entity pickers, cache-busting.
  • Static Resources: Auto-registered.
  • Dependencies: ha-bambulab (for printer discovery via SpoolmanSync API).

📱 Dashboard Example

image image

Renders as a 2x2 grid of colored Tile cards.

🔄 Backward Compatibility

  • Add-on remains unchanged.
  • Updated README with both Add-on and Integration sections.

🧪 Testing

  • Verified on HA 2026.2.1+.
  • HACS integration loads without errors.
  • Entities group under devices.
  • Custom card appears in "Add Card" menu with visual editor.

@gibz104
Copy link
Owner

gibz104 commented Feb 16, 2026

Hey @Switchbot-Nova, thanks for putting this together. I can tell it took real effort and I appreciate the contribution.

After reviewing the code, I've decided not to merge this. Here's my reasoning:

Overlap with the add-on

SpoolmanSync now ships as an HA add-on that embeds the full web UI directly in the HA sidebar. This already gives HA OS users one-click access to tray assignment, spool management, QR labels, NFC writing, and everything else without leaving Home Assistant. The add-on automatically stays in sync with new features since it runs the same codebase.

This PR recreates a subset of that functionality (tray assignment only) as native HA entities. While I understand the appeal of native entities for automations, the maintenance cost of keeping a parallel Python integration in sync with SpoolmanSync's API doesn't justify the limited additional functionality it provides over the add-on.

Architecture concerns

Hosting a HACS integration in the same repo as the add-on creates problems. HACS expects repos to be one category, either an integration or an add-on. Users adding this repo as a custom repository would have to pick a category, and it can't be both. This would also affect the existing add-on store listing since the PR changes repository.yaml.

Code issues

Even if I were open to the direction, there are a number of issues that would need to be addressed:

  • repository.yaml rename -- This changes the repo name from "SpoolmanSync Add-ons" to "SpoolmanSync", which could cause issues for existing users who have this repo registered as an add-on repository.
  • Card re-renders on every HA state change -- The set hass() setter fires on every state change across the entire HA instance (any light toggle, sensor update, etc.). Each time, update() clears innerHTML, calls await window.loadCardHelpers(), and recreates all tile card elements from scratch. The correct pattern is to create the tile elements once and only update tile.hass on subsequent calls. As-is, this will cause visible flickering and unnecessary performance overhead.
  • Card editor uses Lit template syntax in plain innerHTML -- The editor sets properties like .hass=${this._hass} and .includeDomains=${['select']} inside an innerHTML template string. This dot-prefix syntax only works with Lit's html tagged template literal. With plain innerHTML, these are treated as HTML attributes and the JS objects aren't actually passed through. The entity pickers need hass set as a JavaScript property to function. They should be created with document.createElement() and have properties assigned programmatically.
  • Version inconsistency -- manifest.json says 1.2.4, card.js logs 1.2.3, and __init__.py uses 1.2.1 for the static asset cache-busting path. The __init__.py version is particularly impactful since it constructs the URL path for the card JS. If the card is updated but this version string isn't bumped, browsers will serve stale cached versions.
  • Missing strings.json -- The config flow uses errors["base"] = "cannot_connect" but there's no strings.json or translations/en.json. Without it, HA will display raw error keys instead of human-readable messages, and form field labels/descriptions will be missing.
  • Fragile spool ID parsing -- async_select_option extracts the spool ID from the display string via int(option.split(" ")[0].replace("#", "")). This couples the parsing logic to the exact display format of the options property. If the format ever changes, this silently breaks. A lookup dict from display string to spool ID would be more robust.
  • Spool matching logic duplicated 5 times -- The active_tray JSON parsing with json.loads() / except / .strip('"') fallback is copy-pasted across select.py (in current_option and async_select_option) and sensor.py (in native_value and extra_state_attributes). This should be a shared helper function.
  • hacs.json declares filename -- The filename field is for Lovelace plugin type repos, but this PR adds custom_components/ which makes it an integration type repo. The card JS is already served by the integration via async_register_custom_card, so this field is incorrect metadata that could confuse HACS about the repo type.
  • config_flow.py hardcodes a default URL -- The default value http://192.168.0.34:3000 appears to be a personal network IP. This should be empty or use a placeholder.

If you'd like to maintain this as a standalone HACS integration in your own repo, that's totally fine, anyone could point HACS at your repo and install it. It just doesn't fit as part of the main SpoolmanSync project.

Thanks again for the effort!

@gibz104 gibz104 closed this Feb 16, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants