Awesome
Spoolman Home Assistant Integration
This integration integrates Spoolman (https://github.com/Donkie/Spoolman/) into Home Assistant. This enables you to observe your filament spools and in example get notified when a spool runs out of filament.
✨ Features
- Locations in Spoolman are created as devices
- Spools are added to the devices
- Monitoring of filament consumption (used and remaining length/weight)
- Configurable thresholds for info, warning and critical states. This is useful to trigger notifications in HomeAssistant within an automation (see the automation example)
- Enable/disabled archived spools
- Archived spools are grouped into one
Archived
device - If a Klipper url is configured, the active spool will have an attribute
klipper_active_spool
- Creation of a service
spoolman.patch_spool
to enable you to change values of a spool from automations
[!NOTE] If one of the threshold is exceeded the integration fires an event. The event is named
spoolman_spool_threshold_exceeded
. Currently there are three thresholds defined:info
,warning
andcritical
.
[!IMPORTANT] If one of the threshold is exceeded, there is no other event for that particular threshold and spool until restart of HomeAssistant.
🏗️ Installation
Just add this repo to the custom repos in HACS (https://hacs.xyz/docs/faq/custom_repositories/) and you're good to go. You should now see the integration in HACS where you can download the latest version.
🛠️ Usage
Just add a new integration for Spoolman and fill in the URL to your Spoolman instance, like this:
You should now see a new integration entry with one device per location (your spoolman instance) and all archived spools grouped in an own device:
For every spool there is a sensor created with the exact color you've provided. Additionally the integration tracks your current weight and lengths.
All other information provides by Spoolman are stored in the attributes of the sensor:
[!IMPORTANT] Your spool needs at least a name and a material to get added to Home Assistant.
Usage in cards
You can use the default entities
card for this:
Or auto-entities-card
for getting all entities by this integration dynamically:
https://github.com/thomasloven/lovelace-auto-entities
And a mushroom-template-card
card for example.
https://github.com/piitaya/lovelace-mushroom/blob/main/docs/cards/template.md
A simple card utilizing mushroom-template-card
and auto-entities
to dynamically show all spools could look like this:
type: custom:auto-entities
filter:
include:
- integration: '*spoolman*'
sort:
method: attribute
attribute: location
reverse: false
attributes:
archived: false
options:
type: custom:mushroom-template-card
vertical: false
icon_color: '#{{ state_attr(entity, ''filament_color_hex'') }}'
icon: mdi:printer-3d-nozzle
badge_icon: |
{% if state_attr(entity, 'archived') == true %}
mdi:archive
{% elif state_attr(entity, 'klipper_active_spool') == true %}
mdi:check-circle
{% endif %}
badge_color: |
{% if state_attr(entity, 'archived') == true %}
orange
{% elif state_attr(entity, 'klipper_active_spool') == true %}
green
{% else %}
default_color
{% endif %}
primary: |
{% set location = state_attr(entity, 'location') %} {% if location %}
{{ state_attr(entity, 'filament_name') }} ({{ location }})
{% else %}
{{ state_attr(entity, 'filament_name') }}
{% endif %}
secondary: '{{ (state_attr(entity, ''remaining_weight'') | float) | round(2) }} g'
tap_action:
action: more-info
sort:
method: attribute
attribute: klipper_active_spool
reverse: true
card:
type: grid
columns: 2
square: false
card_param: cards
This card does:
- Filtering out all
archived
spools, if not filters allarchived
spools have an orange badge - Sort by
klipper_active_spool
(only when Klipper url is set in config, active spools is always the first one with green badge) - Sort by
location
from A-Z - Shows the
location
after the spool name - Click on an entity opens the
more_info
dialog
Automation example
An automation in Homeassistant could be something like this:
alias: Filament almost empty
description: ""
trigger:
- platform: event
event_type: spoolman_spool_threshold_exceeded
condition: []
action:
- service: notify.notify
data_template:
title: >-
{{ trigger.event.data['threshold_name'] | capitalize }}: Spool almost
empty
message: >-
The spool {{ trigger.event.data['spool']['filament']['vendor']['name']
}} {{ trigger.event.data['spool']['filament']['name'] }} {{
trigger.event.data['spool']['filament']['material'] }} has reached {{
trigger.event.data['spool']['used_percentage'] }}% usage
mode: restart
You can use the following data within your templates:
{
"entity_id": self.entity_id,
"spool": spool,
"threshold_name": threshold_name,
"threshold_value": config_threshold,
"used_percentage": used_percentage,
}
A spool has this structure (according to the OpenAPI description of Spoolman):
{
"id": 1,
"registered": "2023-09-22T19:52:36Z",
"first_used": "2023-09-23T04:22:26.975000Z",
"last_used": "2023-09-30T04:09:34.242017Z",
"filament": {
"id": 1,
"registered": "2023-09-22T19:52:07Z",
"name": "Black",
"vendor": {
"id": 1,
"registered": "2023-09-22T19:43:26Z",
"name": "Jayo"
},
"material": "PLA+",
"price": 15.99,
"density": 1.24,
"diameter": 1.75,
"weight": 1100,
"article_number": "B0BJ1FR86Y",
"comment": "",
"settings_extruder_temp": 210,
"settings_bed_temp": 60,
"color_hex": "000000"
},
"remaining_weight": 4.468290721106769,
"used_weight": 1095.5317092788932,
"remaining_length": 1498.1446855790216,
"used_length": 367313.8366728618,
"location": "Lager",
"lot_nr": "1704306141A",
"archived": false
}
Home Assistant services
This integration creates services to be used in automations:
spoolman.patch_spool
This service is used to change values and properties if a spool. The data
must match the data for the Spoolman API
[!IMPORTANT] You can't update
remaining_weight
andused_weight
in one update. You can only set one of them. Spoolmann calculates the missing field by itself.
service: spoolman.patch_spool
data:
id: 45
first_used: "2019-08-24T14:15:22.000Z"
last_used: "2019-08-24T14:15:22.000Z"
price: 20
initial_weight: 200
spool_weight: 200
location: Shelf B
remaining_weight: 200
lot_nr: 52342
Contributing
If you're developer and want to contribute to the project, please feel free to do a PR! But there are some contraints I want to enforce by convention (currently I evaluate the possibility to enforce this by rules. If you have a good hint, please let me know 🎉):
- Please merge your PR to the dev branch. PRs against
main
will be rejected. - Branch
main
only reflects thelatest
state of the integration - Branch
dev
reflects thenext
state of the integration - Please make use of conventional commits. This ensures the build pipeline works together with semantic release and your PRs will start a new release.
- I would recommend using visual studio code (since there is everything working out of the box)