diff --git a/.ha_mcp/backups/dashboard.sparkx-i7.20261009_002240.yaml b/.ha_mcp/backups/dashboard.sparkx-i7.20261009_002240.yaml
new file mode 100644
index 00000000..b19bf23e
--- /dev/null
+++ b/.ha_mcp/backups/dashboard.sparkx-i7.20261009_002240.yaml
@@ -0,0 +1,1267 @@
+# ha_mcp_backup
+schema_version: 1
+domain: dashboard
+entity_id: sparkx-i7
+captured: '2026-10-09T00:22:40.503278+00:00'
+tool: ha_config_set_dashboard
+config:
+ views:
+ - max_columns: 4
+ path: print
+ sections:
+ - cards:
+ - bed: sensor.sparkx_i7_bed_temperature
+ camera: camera.sparkx_i7_printer_camera
+ grid_options:
+ columns: full
+ layer: sensor.sparkx_i7_working_layer
+ light: light.sparkx_i7_light
+ name: SparkX i7
+ nozzle: sensor.sparkx_i7_nozzle_temperature
+ pause_btn: button.sparkx_i7_pause_print
+ progress: sensor.sparkx_i7_print_progress
+ resume_btn: button.sparkx_i7_resume_print
+ status: sensor.sparkx_i7_print_status
+ stop_btn: button.sparkx_i7_stop_print
+ time_left: sensor.sparkx_i7_print_time_left
+ total_layers: sensor.sparkx_i7_total_layers
+ type: custom:k-printer-card
+ - grid_options:
+ columns: full
+ type: custom:webrtc-camera
+ ui: true
+ url: octoprint
+ - grid_options:
+ columns: full
+ type: custom:webrtc-camera
+ ui: true
+ url: octoprint2
+ - camera_image: camera.sparkx_i7_printer_camera
+ camera_view: live
+ entity: camera.sparkx_i7_printer_camera
+ fit_mode: cover
+ grid_options:
+ columns: full
+ show_name: true
+ show_state: true
+ type: picture-entity
+ - cards:
+ - grid_options:
+ columns: 6
+ image_entity: image.sparkx_i7_current_print_preview
+ show_name: false
+ type: picture
+ - entity: sensor.sparkx_i7_active_filament_slot
+ icon: mdi:palette
+ icon_color: '{% set color = state_attr(''sensor.sparkx_i7_active_filament_slot'',
+ ''color'') | default('''') | string %}{% set core = color | replace(''#'',
+ '''') %}{% if core | length >= 6 %}#{{ core[-6:] }}{% else %}var(--primary-text-color){%
+ endif %}'
+ multiline_secondary: true
+ name: Active Color
+ primary: '{% set slot = states(''sensor.sparkx_i7_active_filament_slot'')
+ %}{% if ''Slot 1'' in slot %}{{ states(''sensor.sparkx_i7_slot_1_color_name'')
+ }}{% elif ''Slot 2'' in slot %}{{ states(''sensor.sparkx_i7_slot_2_color_name'')
+ }}{% elif ''Slot 3'' in slot %}{{ states(''sensor.sparkx_i7_slot_3_color_name'')
+ }}{% elif ''Slot 4'' in slot %}{{ states(''sensor.sparkx_i7_slot_4_color_name'')
+ }}{% elif slot == ''External'' %}{{ states(''sensor.sparkx_i7_external_color_name'')
+ }}{% else %}Unknown{% endif %}'
+ secondary: "{% set slot = states('sensor.sparkx_i7_active_filament_slot')\
+ \ %}{{ slot }}{% if state_attr('sensor.sparkx_i7_active_filament_slot',\
+ \ 'filament') %} \xB7 {{ state_attr('sensor.sparkx_i7_active_filament_slot',\
+ \ 'filament') }}{% endif %}"
+ type: custom:mushroom-template-card
+ grid_options:
+ columns: full
+ type: horizontal-stack
+ - entity: sensor.sparkx_i7_print_status
+ grid_options:
+ columns: 12
+ icon: mdi:state-machine
+ name: Status
+ type: tile
+ - entity: sensor.sparkx_i7_position_z_2_decimals
+ grid_options:
+ columns: 4
+ icon: mdi:axis-z-arrow
+ name: Current Z
+ type: tile
+ - entity: sensor.sparkx_i7_position_x
+ grid_options:
+ columns: 4
+ icon: mdi:axis-x-arrow
+ name: X
+ type: tile
+ - entity: sensor.sparkx_i7_position_y
+ grid_options:
+ columns: 4
+ icon: mdi:axis-y-arrow
+ name: Y
+ type: tile
+ - entity: sensor.sparkx_i7_print_status
+ grid_options:
+ columns: 6
+ icon: mdi:message-alert-outline
+ multiline_secondary: true
+ name: Printer Message
+ primary: '{{ states("sensor.sparkx_i7_print_status") | replace("_", " ") |
+ title }}'
+ secondary: '{% set err = state_attr("sensor.sparkx_i7_print_status", "err")
+ or {} %}{% set code = err.get("errcode", 0) | int(0) %}{% set msg = err.get("value",
+ "") %}{% if state_attr("sensor.sparkx_i7_print_status", "paused_flag") |
+ default(false) %}Print paused{% elif msg %}ERROR {{ code }}: {{ msg }}{%
+ elif code %}Printer error {{ code }}{% else %}No printer error{% endif %}'
+ type: custom:mushroom-template-card
+ - entity: sensor.sparkx_i7_print_status
+ grid_options:
+ columns: 6
+ icon: mdi:file-document-outline
+ multiline_secondary: true
+ name: Current File
+ primary: Current File
+ secondary: '{% set file = state_attr("sensor.sparkx_i7_print_status", "file")
+ or "" %}{% if file %}{{ file.split("/")[-1] | replace(".gcode", "") }}{%
+ else %}No active file{% endif %}'
+ type: custom:mushroom-template-card
+ type: grid
+ - cards:
+ - heading: Print Progress
+ icon: mdi:progress-clock
+ type: heading
+ - entity: sensor.sparkx_i7_print_progress
+ grid_options:
+ columns: 6
+ rows: 3
+ max: 100
+ min: 0
+ name: Progress
+ severity:
+ green: 0
+ red: 90
+ yellow: 40
+ type: gauge
+ unit: '%'
+ - grid_options:
+ columns: 6
+ icon: mdi:clock-start
+ multiline_secondary: true
+ name: Elapsed
+ primary: Elapsed
+ secondary: '{% set s = states(''sensor.sparkx_i7_print_job_time'') | float(0)
+ %}{% set h = (s / 3600) | int %}{% set m = ((s % 3600) / 60) | int %}{%
+ if h %}{{ h }} hr {{ m }} min{% else %}{{ m }} min{% endif %}'
+ type: custom:mushroom-template-card
+ - grid_options:
+ columns: 6
+ icon: mdi:clock-end
+ multiline_secondary: true
+ name: Remaining
+ primary: Remaining
+ secondary: '{% set s = states(''sensor.sparkx_i7_print_time_left'') | float(-1)
+ %}{% if s <= 0 %}No estimate{% else %}{% set h = (s / 3600) | int %}{% set
+ m = ((s % 3600) / 60) | int %}{% if h %}{{ h }} hr {{ m }} min{% else %}{{
+ m }} min{% endif %}{% endif %}'
+ type: custom:mushroom-template-card
+ - grid_options:
+ columns: 6
+ icon: mdi:clock-outline
+ multiline_secondary: true
+ primary: Est. Finish
+ secondary: "{% set left = states('sensor.sparkx_i7_print_time_left') | int(0)\
+ \ %}{% if left > 0 %}{{ (now() + timedelta(seconds=left)).strftime('%I:%M\
+ \ %p').lstrip('0') }}{% else %}\u2014{% endif %}"
+ type: custom:mushroom-template-card
+ - grid_options:
+ columns: 6
+ icon: mdi:layers
+ multiline_secondary: true
+ name: Layer
+ primary: Layer
+ secondary: '{% set c = states(''sensor.sparkx_i7_working_layer'') | int(0)
+ %}{% set t = states(''sensor.sparkx_i7_total_layers'') | int(0) %}{{ c }}
+ of {{ t }}'
+ type: custom:mushroom-template-card
+ - entity: light.sparkx_i7_light
+ grid_options:
+ columns: 6
+ icon: mdi:lightbulb
+ name: Printer Light
+ type: tile
+ - detail: 1
+ entity: sensor.sparkx_i7_print_progress
+ graph: line
+ grid_options:
+ columns: full
+ hours_to_show: 24
+ name: Progress History
+ type: sensor
+ - entity: number.sparkx_i7_print_tuning
+ grid_options:
+ columns: 6
+ icon: mdi:speedometer
+ name: Print Tuning
+ type: tile
+ - entity: sensor.sparkx_i7_print_speed
+ grid_options:
+ columns: 6
+ icon: mdi:speedometer
+ name: Speed
+ type: tile
+ - entity: sensor.sparkx_i7_real_time_flow
+ grid_options:
+ columns: 6
+ icon: mdi:cube-send
+ name: Real-Time Flow
+ type: tile
+ - entity: sensor.sparkx_i7_flow_rate
+ grid_options:
+ columns: 6
+ icon: mdi:chart-gantt
+ name: Flow Rate
+ type: tile
+ - entity: sensor.sparkx_i7_current_object
+ grid_options:
+ columns: 6
+ icon: mdi:cube-outline
+ name: Object
+ type: tile
+ - entity: sensor.sparkx_i7_object_count
+ grid_options:
+ columns: 6
+ icon: mdi:counter
+ name: Object Count
+ type: tile
+ type: grid
+ - cards:
+ - heading: Temperatures
+ icon: mdi:thermometer
+ type: heading
+ - entity: sensor.sparkx_i7_nozzle_temperature
+ grid_options:
+ columns: 4
+ max: 300
+ min: 0
+ name: Nozzle
+ severity:
+ green: 0
+ red: 240
+ yellow: 180
+ type: gauge
+ unit: "\xB0C"
+ - entity: sensor.sparkx_i7_bed_temperature
+ grid_options:
+ columns: 4
+ max: 100
+ min: 0
+ name: Bed
+ severity:
+ green: 0
+ red: 100
+ yellow: 60
+ type: gauge
+ unit: "\xB0C"
+ - entity: number.sparkx_i7_nozzle_target
+ grid_options:
+ columns: 6
+ icon: mdi:printer-3d-nozzle
+ name: Nozzle Target
+ type: tile
+ - entity: number.sparkx_i7_bed_target
+ grid_options:
+ columns: 6
+ icon: mdi:radiator
+ name: Bed Target
+ type: tile
+ - entities:
+ - color: '#ef5350'
+ entity: sensor.sparkx_i7_nozzle_temperature
+ name: Actual
+ - color: '#4caf50'
+ entity: number.sparkx_i7_nozzle_target
+ name: Target
+ expand_legend: true
+ grid_options:
+ columns: full
+ hours_to_show: 24
+ show_names: true
+ title: Nozzle Temperature
+ type: history-graph
+ - entities:
+ - color: '#42a5f5'
+ entity: sensor.sparkx_i7_bed_temperature
+ name: Actual
+ - color: '#4caf50'
+ entity: number.sparkx_i7_bed_target
+ name: Target
+ expand_legend: true
+ grid_options:
+ columns: full
+ hours_to_show: 24
+ show_names: true
+ title: Bed Temperature
+ type: history-graph
+ type: grid
+ - cards:
+ - heading: Controls
+ icon: mdi:gesture-tap-button
+ type: heading
+ - entity: button.sparkx_i7_pause_print
+ grid_options:
+ columns: 4
+ icon: mdi:pause
+ name: Pause
+ tap_action:
+ action: perform-action
+ perform_action: button.press
+ target:
+ entity_id: button.sparkx_i7_pause_print
+ type: tile
+ - entity: button.sparkx_i7_resume_print
+ grid_options:
+ columns: 4
+ icon: mdi:play
+ name: Resume
+ tap_action:
+ action: perform-action
+ perform_action: button.press
+ target:
+ entity_id: button.sparkx_i7_resume_print
+ type: tile
+ - entity: button.sparkx_i7_reconnect
+ grid_options:
+ columns: 4
+ icon: mdi:lan-connect
+ name: Connect
+ tap_action:
+ action: perform-action
+ perform_action: button.press
+ target:
+ entity_id: button.sparkx_i7_reconnect
+ type: tile
+ - entity: button.sparkx_i7_stop_print
+ grid_options:
+ columns: 4
+ icon: mdi:cancel
+ name: Cancel Print
+ tap_action:
+ action: perform-action
+ perform_action: button.press
+ target:
+ entity_id: button.sparkx_i7_stop_print
+ type: tile
+ - entity: button.sparkx_i7_home_xy_then_z
+ grid_options:
+ columns: 4
+ icon: mdi:home-circle
+ name: Home
+ tap_action:
+ action: perform-action
+ perform_action: button.press
+ target:
+ entity_id: button.sparkx_i7_home_xy_then_z
+ type: tile
+ type: grid
+ - cards:
+ - heading: Filament
+ icon: mdi:printer-3d-nozzle-outline
+ type: heading
+ - entity: sensor.sparkx_i7_filament_weight_estimated
+ grid_options:
+ columns: 6
+ icon: '{% set st = states(''sensor.sparkx_i7_print_status'') %}{% if st in
+ [''printing'', ''paused''] %}mdi:printer-3d-nozzle{% else %}mdi:calendar-today{%
+ endif %}'
+ multiline_secondary: true
+ name: Filament Used
+ primary: '{% set st = states(''sensor.sparkx_i7_print_status'') %}{% if st
+ in [''printing'', ''paused''] %}{{ states(''sensor.sparkx_i7_filament_weight_estimated'')
+ | round(1) }} g{% else %}No active job{% endif %}'
+ secondary: "{% set st = states('sensor.sparkx_i7_print_status') %}{% if st\
+ \ in ['printing', 'paused'] %}{{ states('sensor.sparkx_i7_used_material_length')\
+ \ | round(0) }} cm this job{% else %}{{ states('sensor.sparkx_i7_filament_weight_daily')\
+ \ | round(1) }} g \xB7 {{ states('sensor.sparkx_i7_filament_cost_daily')\
+ \ | round(2) }} $ today{% endif %}"
+ type: custom:mushroom-template-card
+ - entity: input_number.sparkx_i7_filament_g_cm
+ grid_options:
+ columns: 6
+ icon: mdi:weight-kilogram
+ name: g/cm
+ type: tile
+ - entity: sensor.sparkx_i7_used_material_length
+ grid_options:
+ columns: 6
+ icon: mdi:counter
+ multiline_secondary: true
+ name: Used Length
+ primary: '{% set st = states(''sensor.sparkx_i7_print_status'') %}{% if st
+ in [''printing'', ''paused''] %}{{ states(''sensor.sparkx_i7_used_material_length'')
+ | round(0) }} cm{% else %}{{ (states(''sensor.sparkx_i7_filament_weight_daily'')
+ | float(0) / states(''input_number.sparkx_i7_filament_g_cm'') | float(0.0298))
+ | round(0) }} cm{% endif %}'
+ secondary: '{% set st = states(''sensor.sparkx_i7_print_status'') %}{% if
+ st in [''printing'', ''paused''] %}this job (printer-reported){% else %}today,
+ from today''s weight{% endif %}'
+ type: custom:mushroom-template-card
+ - entity: sensor.sparkx_i7_filament_cost
+ grid_options:
+ columns: 3
+ icon: mdi:cash
+ name: Job Cost (total)
+ type: tile
+ - entity: sensor.sparkx_i7_filament_cost_daily
+ grid_options:
+ columns: 3
+ icon: mdi:cash-multiple
+ name: Today
+ type: tile
+ - entity: sensor.sparkx_i7_filament_cost_weekly
+ grid_options:
+ columns: 3
+ icon: mdi:cash-multiple
+ name: This Week
+ type: tile
+ - entity: sensor.sparkx_i7_filament_cost_monthly
+ grid_options:
+ columns: 3
+ icon: mdi:cash-multiple
+ name: This Month
+ type: tile
+ type: grid
+ title: Print
+ type: sections
+ - max_columns: 2
+ path: history
+ sections:
+ - cards:
+ - heading: Temperature History
+ icon: mdi:chart-line-variant
+ type: heading
+ - entities:
+ - color: '#ef5350'
+ entity: sensor.sparkx_i7_nozzle_temperature
+ name: Nozzle
+ - color: '#ffab91'
+ entity: number.sparkx_i7_nozzle_target
+ name: Nozzle Target
+ - color: '#42a5f5'
+ entity: sensor.sparkx_i7_bed_temperature
+ name: Bed
+ - color: '#90caf9'
+ entity: number.sparkx_i7_bed_target
+ name: Bed Target
+ expand_legend: true
+ grid_options:
+ columns: full
+ hours_to_show: 24
+ show_names: true
+ title: Temperatures (24h)
+ type: history-graph
+ - entities:
+ - color: '#ef5350'
+ entity: sensor.sparkx_i7_nozzle_temperature
+ name: Nozzle
+ - color: '#42a5f5'
+ entity: sensor.sparkx_i7_bed_temperature
+ name: Bed
+ expand_legend: true
+ grid_options:
+ columns: full
+ hours_to_show: 168
+ show_names: true
+ title: Temperatures (7 days)
+ type: history-graph
+ type: grid
+ - cards:
+ - heading: Print Activity
+ icon: mdi:chart-box-outline
+ type: heading
+ - apex_config:
+ chart:
+ height: 300
+ stroke:
+ width: 1
+ graph_span: 24h
+ grid_options:
+ columns: full
+ header:
+ colorize_states: true
+ show: true
+ show_states: true
+ title: Z Position (24h)
+ series:
+ - color: '#ab47bc'
+ curve: straight
+ entity: sensor.sparkx_i7_position_z
+ fill_raw: last
+ name: Current Z
+ type: line
+ type: custom:apexcharts-card
+ - entities:
+ - color: '#66bb6a'
+ entity: sensor.sparkx_i7_print_progress
+ name: Progress
+ grid_options:
+ columns: full
+ hours_to_show: 24
+ show_names: true
+ title: Print Progress (24h)
+ type: history-graph
+ - entities:
+ - color: '#26c6da'
+ entity: sensor.sparkx_i7_print_job_time
+ name: Elapsed
+ - color: '#ffa726'
+ entity: sensor.sparkx_i7_print_time_left
+ name: Remaining
+ grid_options:
+ columns: full
+ hours_to_show: 24
+ show_names: true
+ title: Print Duration (24h)
+ type: history-graph
+ type: grid
+ title: History
+ type: sections
+ - icon: mdi:printer-3d-nozzle-outline
+ max_columns: 4
+ path: cfs-fans
+ sections:
+ - cards:
+ - heading: CFS Box 1
+ icon: mdi:file-cabinet
+ type: heading
+ - entity: sensor.sparkx_i7_cfs_box_1_temperature
+ grid_options:
+ columns: 6
+ icon: mdi:thermometer
+ name: Temperature
+ type: tile
+ - entity: sensor.sparkx_i7_cfs_box_1_humidity
+ grid_options:
+ columns: 6
+ icon: mdi:water-percent
+ name: Humidity
+ type: tile
+ - grid_options:
+ columns: 6
+ icon: mdi:printer-3d-nozzle
+ icon_color: '{% set c = states(''sensor.sparkx_i7_cfs_box_1_slot_1_color'')|default('''')|string
+ %}{% set core = c|replace(''#'','''') %}{% if core|length >= 6 %}#{{ core[-6:]
+ }}{% endif %}'
+ multiline_secondary: true
+ name: Slot 1
+ primary: '{{ states(''sensor.sparkx_i7_cfs_box_1_slot_1_filament'') }}'
+ secondary: "{% set col = states('sensor.sparkx_i7_slot_1_color_name') %}{%\
+ \ if col %}{{ col }} \xB7 {% endif %}{{ states('sensor.sparkx_i7_cfs_box_1_slot_1_remaining')\
+ \ }}% left"
+ type: custom:mushroom-template-card
+ - grid_options:
+ columns: 6
+ icon: mdi:printer-3d-nozzle
+ icon_color: '{% set c = states(''sensor.sparkx_i7_cfs_box_1_slot_2_color'')|default('''')|string
+ %}{% set core = c|replace(''#'','''') %}{% if core|length >= 6 %}#{{ core[-6:]
+ }}{% endif %}'
+ multiline_secondary: true
+ name: Slot 2
+ primary: '{{ states(''sensor.sparkx_i7_cfs_box_1_slot_2_filament'') }}'
+ secondary: "{% set col = states('sensor.sparkx_i7_slot_2_color_name') %}{%\
+ \ if col %}{{ col }} \xB7 {% endif %}{{ states('sensor.sparkx_i7_cfs_box_1_slot_2_remaining')\
+ \ }}% left"
+ type: custom:mushroom-template-card
+ - grid_options:
+ columns: 6
+ icon: mdi:printer-3d-nozzle
+ icon_color: '{% set c = states(''sensor.sparkx_i7_cfs_box_1_slot_3_color'')|default('''')|string
+ %}{% set core = c|replace(''#'','''') %}{% if core|length >= 6 %}#{{ core[-6:]
+ }}{% endif %}'
+ multiline_secondary: true
+ name: Slot 3
+ primary: '{{ states(''sensor.sparkx_i7_cfs_box_1_slot_3_filament'') }}'
+ secondary: "{% set col = states('sensor.sparkx_i7_slot_3_color_name') %}{%\
+ \ if col %}{{ col }} \xB7 {% endif %}{{ states('sensor.sparkx_i7_cfs_box_1_slot_3_remaining')\
+ \ }}% left"
+ type: custom:mushroom-template-card
+ - grid_options:
+ columns: 6
+ icon: mdi:printer-3d-nozzle
+ icon_color: '{% set c = states(''sensor.sparkx_i7_cfs_box_1_slot_4_color'')|default('''')|string
+ %}{% set core = c|replace(''#'','''') %}{% if core|length >= 6 %}#{{ core[-6:]
+ }}{% endif %}'
+ multiline_secondary: true
+ name: Slot 4
+ primary: '{{ states(''sensor.sparkx_i7_cfs_box_1_slot_4_filament'') }}'
+ secondary: "{% set col = states('sensor.sparkx_i7_slot_4_color_name') %}{%\
+ \ if col %}{{ col }} \xB7 {% endif %}{{ states('sensor.sparkx_i7_cfs_box_1_slot_4_remaining')\
+ \ }}% left"
+ type: custom:mushroom-template-card
+ type: grid
+ - cards:
+ - heading: External / Active
+ icon: mdi:printer-3d
+ type: heading
+ - cards:
+ - entity: sensor.sparkx_i7_active_filament_slot
+ grid_options:
+ columns: 6
+ icon: mdi:swap-horizontal
+ name: Active Slot
+ type: tile
+ - entity: sensor.sparkx_i7_active_filament_slot
+ icon: mdi:palette
+ icon_color: '{% set color = state_attr(''sensor.sparkx_i7_active_filament_slot'',
+ ''color'') | default('''') | string %}{% set core = color | replace(''#'',
+ '''') %}{% if core | length >= 6 %}#{{ core[-6:] }}{% else %}var(--primary-text-color){%
+ endif %}'
+ multiline_secondary: true
+ name: Active Color
+ primary: '{% set slot = states(''sensor.sparkx_i7_active_filament_slot'')
+ %}{% if ''Slot 1'' in slot %}{{ states(''sensor.sparkx_i7_slot_1_color_name'')
+ }}{% elif ''Slot 2'' in slot %}{{ states(''sensor.sparkx_i7_slot_2_color_name'')
+ }}{% elif ''Slot 3'' in slot %}{{ states(''sensor.sparkx_i7_slot_3_color_name'')
+ }}{% elif ''Slot 4'' in slot %}{{ states(''sensor.sparkx_i7_slot_4_color_name'')
+ }}{% elif slot == ''External'' %}{{ states(''sensor.sparkx_i7_external_color_name'')
+ }}{% else %}Unknown{% endif %}'
+ secondary: "{% set slot = states('sensor.sparkx_i7_active_filament_slot')\
+ \ %}{{ slot }}{% if state_attr('sensor.sparkx_i7_active_filament_slot',\
+ \ 'filament') %} \xB7 {{ state_attr('sensor.sparkx_i7_active_filament_slot',\
+ \ 'filament') }}{% endif %}"
+ type: custom:mushroom-template-card
+ grid_options:
+ columns: full
+ type: horizontal-stack
+ - grid_options:
+ columns: 6
+ icon: mdi:lan-outline
+ icon_color: '{% set c = states(''sensor.sparkx_i7_cfs_external_color'')|default('''')|string
+ %}{% set core = c|replace(''#'','''') %}{% if core|length >= 6 %}#{{ core[-6:]
+ }}{% endif %}'
+ multiline_secondary: true
+ name: External Filament
+ primary: '{{ states(''sensor.sparkx_i7_cfs_external_filament'') }}'
+ secondary: "{% set col = states('sensor.sparkx_i7_external_color_name') %}{%\
+ \ if col %}{{ col }} \xB7 {% endif %}{{ states('sensor.sparkx_i7_cfs_external_remaining')\
+ \ }}% left"
+ type: custom:mushroom-template-card
+ - entity: sensor.sparkx_i7_filament_status
+ grid_options:
+ columns: 6
+ icon: mdi:printer-3d-nozzle-alert
+ name: Filament Status
+ type: tile
+ type: grid
+ - cards:
+ - heading: Fans
+ icon: mdi:fan
+ type: heading
+ - entity: fan.sparkx_i7_model_fan
+ features:
+ - type: fan-speed
+ grid_options:
+ columns: 4
+ icon: mdi:fan
+ name: Model Fan
+ type: tile
+ - entity: fan.sparkx_i7_case_fan
+ features:
+ - type: fan-speed
+ grid_options:
+ columns: 4
+ icon: mdi:fan
+ name: Case Fan
+ type: tile
+ - entity: fan.sparkx_i7_side_fan
+ features:
+ - type: fan-speed
+ grid_options:
+ columns: 4
+ icon: mdi:fan
+ name: Side Fan
+ type: tile
+ type: grid
+ title: CFS / Fans
+ type: sections
+ - title: Spoolman
+ path: spoolman
+ icon: mdi:package-variant-closed
+ type: sections
+ max_columns: 4
+ sections:
+ - type: grid
+ cards:
+ - type: heading
+ heading: "CFS Slots \u2014 per-color deduction"
+ icon: mdi:printer-filament
+ - type: custom:mushroom-template-card
+ entity: sensor.sparkx_i7_cfs_box_1_slot_1_color
+ name: Slot 1
+ icon: mdi:printer-filament
+ icon_color: '{% set c = states(''sensor.sparkx_i7_cfs_box_1_slot_1_color'')
+ | replace(''#'', '''') | lower %}{% if c | length == 6 %}#{{ c }}{% else
+ %}var(--primary-color){% endif %}'
+ primary: '{{ states(''sensor.sparkx_i7_slot_1_color_name'') }} (#{{ states(''sensor.sparkx_i7_cfs_box_1_slot_1_color'')
+ | replace(''#'', '''') | upper }})'
+ secondary: "{% set color = states('sensor.sparkx_i7_cfs_box_1_slot_1_color')\
+ \ | replace('#', '') | lower %}{% set ns = namespace(id='') %}{% for e in\
+ \ integration_entities('spoolman') %}{% if e.endswith('_color_hex') and\
+ \ (states(e) | replace('#', '') | lower) == color %}{% set b = e[:-10] %}{%\
+ \ if (states(b) | float(0)) > 0 and ns.id == '' %}{% set ns.id = states(b\
+ \ ~ '_id') %}{% endif %}{% endif %}{% endfor %}{% if ns.id %}\u2022 Spool\
+ \ {{ ns.id }} \xB7 {{ states('sensor.spoolman_spool_' ~ ns.id ~ '_vendor')\
+ \ | default('?', true) }} \xB7 {{ states('sensor.spoolman_spool_' ~ ns.id\
+ \ ~ '_material') | default('?', true) }} \xB7 {{ (states('sensor.spoolman_spool_'\
+ \ ~ ns.id) | float(0)) | round(1) }} g left{% elif color in ['', 'unknown',\
+ \ 'unavailable'] %}\u2022 Slot color unavailable{% else %}\u2022 No spool\
+ \ with stock matches this color{% endif %}\n\u2022 This print: {{ (states('input_number.sparkx_i7_slot_1_grams')\
+ \ | float(0)) | round(1) }} g"
+ multiline_secondary: true
+ grid_options:
+ columns: full
+ picture: '{% set c = states(''sensor.sparkx_i7_cfs_box_1_slot_1_color'') |
+ replace(''#'','''') | lower %}{% set svg = '''' %}{{ ''data:image/svg+xml;base64,''
+ ~ svg | base64_encode if c | length == 6 else '''' }}'
+ - type: custom:mushroom-template-card
+ entity: sensor.sparkx_i7_cfs_box_1_slot_2_color
+ name: Slot 2
+ icon: mdi:printer-filament
+ icon_color: '{% set c = states(''sensor.sparkx_i7_cfs_box_1_slot_2_color'')
+ | replace(''#'', '''') | lower %}{% if c | length == 6 %}#{{ c }}{% else
+ %}var(--primary-color){% endif %}'
+ primary: '{{ states(''sensor.sparkx_i7_slot_2_color_name'') }} (#{{ states(''sensor.sparkx_i7_cfs_box_1_slot_2_color'')
+ | replace(''#'', '''') | upper }})'
+ secondary: "{% set color = states('sensor.sparkx_i7_cfs_box_1_slot_2_color')\
+ \ | replace('#', '') | lower %}{% set ns = namespace(id='') %}{% for e in\
+ \ integration_entities('spoolman') %}{% if e.endswith('_color_hex') and\
+ \ (states(e) | replace('#', '') | lower) == color %}{% set b = e[:-10] %}{%\
+ \ if (states(b) | float(0)) > 0 and ns.id == '' %}{% set ns.id = states(b\
+ \ ~ '_id') %}{% endif %}{% endif %}{% endfor %}{% if ns.id %}\u2022 Spool\
+ \ {{ ns.id }} \xB7 {{ states('sensor.spoolman_spool_' ~ ns.id ~ '_vendor')\
+ \ | default('?', true) }} \xB7 {{ states('sensor.spoolman_spool_' ~ ns.id\
+ \ ~ '_material') | default('?', true) }} \xB7 {{ (states('sensor.spoolman_spool_'\
+ \ ~ ns.id) | float(0)) | round(1) }} g left{% elif color in ['', 'unknown',\
+ \ 'unavailable'] %}\u2022 Slot color unavailable{% else %}\u2022 No spool\
+ \ with stock matches this color{% endif %}\n\u2022 This print: {{ (states('input_number.sparkx_i7_slot_2_grams')\
+ \ | float(0)) | round(1) }} g"
+ multiline_secondary: true
+ grid_options:
+ columns: full
+ picture: '{% set c = states(''sensor.sparkx_i7_cfs_box_1_slot_2_color'') |
+ replace(''#'','''') | lower %}{% set svg = '''' %}{{ ''data:image/svg+xml;base64,''
+ ~ svg | base64_encode if c | length == 6 else '''' }}'
+ - type: custom:mushroom-template-card
+ entity: sensor.sparkx_i7_cfs_box_1_slot_3_color
+ name: Slot 3
+ icon: mdi:printer-filament
+ icon_color: '{% set c = states(''sensor.sparkx_i7_cfs_box_1_slot_3_color'')
+ | replace(''#'', '''') | lower %}{% if c | length == 6 %}#{{ c }}{% else
+ %}var(--primary-color){% endif %}'
+ primary: '{{ states(''sensor.sparkx_i7_slot_3_color_name'') }} (#{{ states(''sensor.sparkx_i7_cfs_box_1_slot_3_color'')
+ | replace(''#'', '''') | upper }})'
+ secondary: "{% set color = states('sensor.sparkx_i7_cfs_box_1_slot_3_color')\
+ \ | replace('#', '') | lower %}{% set ns = namespace(id='') %}{% for e in\
+ \ integration_entities('spoolman') %}{% if e.endswith('_color_hex') and\
+ \ (states(e) | replace('#', '') | lower) == color %}{% set b = e[:-10] %}{%\
+ \ if (states(b) | float(0)) > 0 and ns.id == '' %}{% set ns.id = states(b\
+ \ ~ '_id') %}{% endif %}{% endif %}{% endfor %}{% if ns.id %}\u2022 Spool\
+ \ {{ ns.id }} \xB7 {{ states('sensor.spoolman_spool_' ~ ns.id ~ '_vendor')\
+ \ | default('?', true) }} \xB7 {{ states('sensor.spoolman_spool_' ~ ns.id\
+ \ ~ '_material') | default('?', true) }} \xB7 {{ (states('sensor.spoolman_spool_'\
+ \ ~ ns.id) | float(0)) | round(1) }} g left{% elif color in ['', 'unknown',\
+ \ 'unavailable'] %}\u2022 Slot color unavailable{% else %}\u2022 No spool\
+ \ with stock matches this color{% endif %}\n\u2022 This print: {{ (states('input_number.sparkx_i7_slot_3_grams')\
+ \ | float(0)) | round(1) }} g"
+ multiline_secondary: true
+ grid_options:
+ columns: full
+ picture: '{% set c = states(''sensor.sparkx_i7_cfs_box_1_slot_3_color'') |
+ replace(''#'','''') | lower %}{% set svg = '''' %}{{ ''data:image/svg+xml;base64,''
+ ~ svg | base64_encode if c | length == 6 else '''' }}'
+ - type: custom:mushroom-template-card
+ entity: sensor.sparkx_i7_cfs_box_1_slot_4_color
+ name: Slot 4
+ icon: mdi:printer-filament
+ icon_color: '{% set c = states(''sensor.sparkx_i7_cfs_box_1_slot_4_color'')
+ | replace(''#'', '''') | lower %}{% if c | length == 6 %}#{{ c }}{% else
+ %}var(--primary-color){% endif %}'
+ primary: '{{ states(''sensor.sparkx_i7_slot_4_color_name'') }} (#{{ states(''sensor.sparkx_i7_cfs_box_1_slot_4_color'')
+ | replace(''#'', '''') | upper }})'
+ secondary: "{% set color = states('sensor.sparkx_i7_cfs_box_1_slot_4_color')\
+ \ | replace('#', '') | lower %}{% set ns = namespace(id='') %}{% for e in\
+ \ integration_entities('spoolman') %}{% if e.endswith('_color_hex') and\
+ \ (states(e) | replace('#', '') | lower) == color %}{% set b = e[:-10] %}{%\
+ \ if (states(b) | float(0)) > 0 and ns.id == '' %}{% set ns.id = states(b\
+ \ ~ '_id') %}{% endif %}{% endif %}{% endfor %}{% if ns.id %}\u2022 Spool\
+ \ {{ ns.id }} \xB7 {{ states('sensor.spoolman_spool_' ~ ns.id ~ '_vendor')\
+ \ | default('?', true) }} \xB7 {{ states('sensor.spoolman_spool_' ~ ns.id\
+ \ ~ '_material') | default('?', true) }} \xB7 {{ (states('sensor.spoolman_spool_'\
+ \ ~ ns.id) | float(0)) | round(1) }} g left{% elif color in ['', 'unknown',\
+ \ 'unavailable'] %}\u2022 Slot color unavailable{% else %}\u2022 No spool\
+ \ with stock matches this color{% endif %}\n\u2022 This print: {{ (states('input_number.sparkx_i7_slot_4_grams')\
+ \ | float(0)) | round(1) }} g"
+ multiline_secondary: true
+ grid_options:
+ columns: full
+ picture: '{% set c = states(''sensor.sparkx_i7_cfs_box_1_slot_4_color'') |
+ replace(''#'','''') | lower %}{% set svg = '''' %}{{ ''data:image/svg+xml;base64,''
+ ~ svg | base64_encode if c | length == 6 else '''' }}'
+ - type: tile
+ entity: input_number.sparkx_i7_spoolman_length_checkpoint
+ name: Length Checkpoint (cm)
+ icon: mdi:ruler-measure
+ grid_options:
+ columns: full
+ - type: tile
+ entity: input_text.sparkx_i7_print_spool_latch
+ name: Latched CFS Slot
+ icon: mdi:link-variant
+ grid_options:
+ columns: full
+ - type: tile
+ entity: sensor.sparkx_i7_used_material_length
+ name: Used Material Total (cm)
+ icon: mdi:plus-minus
+ grid_options:
+ columns: full
+ - type: tile
+ entity: sensor.sparkx_i7_filament_weight_estimated
+ name: Current Job Weight (est.)
+ icon: mdi:weight-gram
+ grid_options:
+ columns: 12
+ rows: 1
+ - type: custom:mushroom-template-card
+ entity: sensor.sparkx_i7_active_filament_slot
+ name: Next Deduction Match
+ icon: mdi:magnet
+ icon_color: '{% set slot = states(''sensor.sparkx_i7_active_filament_slot'')
+ %}{% set c = states(''sensor.sparkx_i7_cfs_'' ~ (slot | lower | replace(''
+ '', ''_'')) ~ ''_color'') | replace(''#'', '''') | lower %}{% if c | length
+ == 6 %}#{{ c }}{% else %}var(--primary-color){% endif %}'
+ primary: '{{ states(''sensor.sparkx_i7_active_filament_slot'') }}'
+ secondary: "{% set slot = states('sensor.sparkx_i7_active_filament_slot')\
+ \ %}{% set ce = 'sensor.sparkx_i7_cfs_' ~ (slot | lower | replace(' ', '_'))\
+ \ ~ '_color' %}{% set color = states(ce) | replace('#', '') | lower %}{%\
+ \ set ns = namespace(id='') %}{% for e in integration_entities('spoolman')\
+ \ %}{% if e.endswith('_color_hex') and (states(e) | replace('#', '') | lower)\
+ \ == color %}{% set b = e[:-10] %}{% if (states(b) | float(0)) > 0 and ns.id\
+ \ == '' %}{% set ns.id = states(b ~ '_id') %}{% endif %}{% endif %}{% endfor\
+ \ %}{% if ns.id %}Color #{{ color | upper }} \u2192 spool {{ ns.id }} ({{\
+ \ states('sensor.spoolman_spool_' ~ ns.id ~ '_filament_name') }} \xB7 {{\
+ \ (states('sensor.spoolman_spool_' ~ ns.id) | float(0)) | round(1) }} g\
+ \ left){% elif slot in ['', 'unknown', 'unavailable'] %}No slot latched{%\
+ \ elif color in ['', 'unknown', 'unavailable'] %}Slot color unavailable{%\
+ \ else %}Color #{{ color | upper }} \u2014 no spool with stock{% endif %}"
+ multiline_secondary: true
+ grid_options:
+ columns: full
+ - type: markdown
+ content: "**Spoolman UI:** [http://2c829f0e-spoolman.local.hass.io:7912](http://2c829f0e-spoolman.local.hass.io:7912)\n\
+ \nEach CFS slot is matched to the Spoolman spool with the same **color hex**\
+ \ that still has stock (remaining > 0). All 4 rolls live in the **CFS Lite**\
+ \ location in Spoolman.\n\n**Replaced a roll?** Register the new roll in\
+ \ Spoolman with the same color hex (location CFS Lite). No Home Assistant\
+ \ changes needed \u2014 exhausted spools are skipped automatically."
+ grid_options:
+ columns: full
+ - type: grid
+ cards:
+ - type: heading
+ heading: "Spool Details \u2014 CFS Lite"
+ icon: mdi:spool
+ - type: custom:mushroom-template-card
+ entity: sensor.sparkx_i7_cfs_box_1_slot_1_color
+ name: Slot 1
+ icon: mdi:spool
+ icon_color: '{% set c = states(''sensor.sparkx_i7_cfs_box_1_slot_1_color'')
+ | replace(''#'', '''') | lower %}{% if c | length == 6 %}#{{ c }}{% else
+ %}var(--primary-color){% endif %}'
+ picture: '{% set color = states(''sensor.sparkx_i7_cfs_box_1_slot_1_color'')
+ | replace(''#'', '''') | lower %}{% set ns = namespace(id='''') %}{% for
+ e in integration_entities(''spoolman'') %}{% if e.endswith(''_color_hex'')
+ and (states(e) | replace(''#'', '''') | lower) == color %}{% set b = e[:-10]
+ %}{% if (states(b) | float(0)) > 0 and ns.id == '''' %}{% set ns.id = states(b
+ ~ ''_id'') %}{% endif %}{% endif %}{% endfor %}{{ state_attr(''sensor.spoolman_spool_''
+ ~ ns.id, ''entity_picture'') if ns.id and state_attr(''sensor.spoolman_spool_''
+ ~ ns.id, ''entity_picture'') else '''' }}'
+ primary: "{% set color = states('sensor.sparkx_i7_cfs_box_1_slot_1_color')\
+ \ | replace('#', '') | lower %}{% set ns = namespace(id='') %}{% for e in\
+ \ integration_entities('spoolman') %}{% if e.endswith('_color_hex') and\
+ \ (states(e) | replace('#', '') | lower) == color %}{% set b = e[:-10] %}{%\
+ \ if (states(b) | float(0)) > 0 and ns.id == '' %}{% set ns.id = states(b\
+ \ ~ '_id') %}{% endif %}{% endif %}{% endfor %}{% if ns.id %}Spool {{ ns.id\
+ \ }} \xB7 {{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'filament_name')\
+ \ | default('?', true) }} \xB7 {{ (states('sensor.spoolman_spool_' ~ ns.id)\
+ \ | float(0)) | round(1) }} g left{% elif color in ['', 'unknown', 'unavailable']\
+ \ %}Slot color unavailable{% else %}No spool with stock matches this color{%\
+ \ endif %}"
+ secondary: "{% set color = states('sensor.sparkx_i7_cfs_box_1_slot_1_color')\
+ \ | replace('#', '') | lower %}{% set ns = namespace(id='') %}{% for e in\
+ \ integration_entities('spoolman') %}{% if e.endswith('_color_hex') and\
+ \ (states(e) | replace('#', '') | lower) == color %}{% set b = e[:-10] %}{%\
+ \ if (states(b) | float(0)) > 0 and ns.id == '' %}{% set ns.id = states(b\
+ \ ~ '_id') %}{% endif %}{% endif %}{% endfor %}{% if ns.id %}\u2022 {{ state_attr('sensor.spoolman_spool_'\
+ \ ~ ns.id, 'filament_vendor_name') | default('?', true) }} \xB7 {{ state_attr('sensor.spoolman_spool_'\
+ \ ~ ns.id, 'filament_material') | default('?', true) }} \xB7 #{{ color |\
+ \ upper }}\n\u2022 Remaining: {{ (states('sensor.spoolman_spool_' ~ ns.id)\
+ \ | float(0)) | round(1) }} g \xB7 used {{ (state_attr('sensor.spoolman_spool_'\
+ \ ~ ns.id, 'used_weight') | float(0)) | round(1) }} g ({{ (state_attr('sensor.spoolman_spool_'\
+ \ ~ ns.id, 'used_percentage') | float(0)) | round(1) }}%)\n\u2022 Remaining\
+ \ length: {{ ((state_attr('sensor.spoolman_spool_' ~ ns.id, 'remaining_length')\
+ \ | float(0)) / 1000) | round(1) }} m \xB7 used {{ ((state_attr('sensor.spoolman_spool_'\
+ \ ~ ns.id, 'used_length') | float(0)) / 1000) | round(1) }} m\n\u2022 Spool:\
+ \ \xD8{{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'filament_diameter')\
+ \ | default('?', true) }} mm \xB7 {{ state_attr('sensor.spoolman_spool_'\
+ \ ~ ns.id, 'filament_density') | default('?', true) }} g/cm\xB3 \xB7 {{\
+ \ state_attr('sensor.spoolman_spool_' ~ ns.id, 'filament_weight') | default('?',\
+ \ true) }} g \xB7 art. {{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'filament_article_number')\
+ \ | default('?', true) }}\n\u2022 Temps: bed {{ state_attr('sensor.spoolman_spool_'\
+ \ ~ ns.id, 'filament_settings_bed_temp') | default('?', true) }}\xB0C \xB7\
+ \ hotend {{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'filament_settings_extruder_temp')\
+ \ | default('?', true) }}\xB0C\n\u2022 Flow: {{ states('sensor.spoolman_spool_'\
+ \ ~ ns.id ~ '_flow_rate') }} \xB7 Runout est.: {{ states('sensor.spoolman_spool_'\
+ \ ~ ns.id ~ '_estimated_runout') }}\n\u2022 Registered: {{ state_attr('sensor.spoolman_spool_'\
+ \ ~ ns.id, 'registered') | default('?', true) }} \xB7 Location: {{ state_attr('sensor.spoolman_spool_'\
+ \ ~ ns.id, 'location') | default('?', true) }} \xB7 Price: {{ state_attr('sensor.spoolman_spool_'\
+ \ ~ ns.id, 'filament_price') | default('?', true) }}{% elif color in ['',\
+ \ 'unknown', 'unavailable'] %}\u2022 Slot color unavailable{% else %}\u2022\
+ \ No spool with stock matches this color{% endif %}"
+ multiline_secondary: true
+ grid_options:
+ columns: full
+ - type: custom:mushroom-template-card
+ entity: sensor.sparkx_i7_cfs_box_1_slot_2_color
+ name: Slot 2
+ icon: mdi:spool
+ icon_color: '{% set c = states(''sensor.sparkx_i7_cfs_box_1_slot_2_color'')
+ | replace(''#'', '''') | lower %}{% if c | length == 6 %}#{{ c }}{% else
+ %}var(--primary-color){% endif %}'
+ picture: '{% set color = states(''sensor.sparkx_i7_cfs_box_1_slot_2_color'')
+ | replace(''#'', '''') | lower %}{% set ns = namespace(id='''') %}{% for
+ e in integration_entities(''spoolman'') %}{% if e.endswith(''_color_hex'')
+ and (states(e) | replace(''#'', '''') | lower) == color %}{% set b = e[:-10]
+ %}{% if (states(b) | float(0)) > 0 and ns.id == '''' %}{% set ns.id = states(b
+ ~ ''_id'') %}{% endif %}{% endif %}{% endfor %}{{ state_attr(''sensor.spoolman_spool_''
+ ~ ns.id, ''entity_picture'') if ns.id and state_attr(''sensor.spoolman_spool_''
+ ~ ns.id, ''entity_picture'') else '''' }}'
+ primary: "{% set color = states('sensor.sparkx_i7_cfs_box_1_slot_2_color')\
+ \ | replace('#', '') | lower %}{% set ns = namespace(id='') %}{% for e in\
+ \ integration_entities('spoolman') %}{% if e.endswith('_color_hex') and\
+ \ (states(e) | replace('#', '') | lower) == color %}{% set b = e[:-10] %}{%\
+ \ if (states(b) | float(0)) > 0 and ns.id == '' %}{% set ns.id = states(b\
+ \ ~ '_id') %}{% endif %}{% endif %}{% endfor %}{% if ns.id %}Spool {{ ns.id\
+ \ }} \xB7 {{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'filament_name')\
+ \ | default('?', true) }} \xB7 {{ (states('sensor.spoolman_spool_' ~ ns.id)\
+ \ | float(0)) | round(1) }} g left{% elif color in ['', 'unknown', 'unavailable']\
+ \ %}Slot color unavailable{% else %}No spool with stock matches this color{%\
+ \ endif %}"
+ secondary: "{% set color = states('sensor.sparkx_i7_cfs_box_1_slot_2_color')\
+ \ | replace('#', '') | lower %}{% set ns = namespace(id='') %}{% for e in\
+ \ integration_entities('spoolman') %}{% if e.endswith('_color_hex') and\
+ \ (states(e) | replace('#', '') | lower) == color %}{% set b = e[:-10] %}{%\
+ \ if (states(b) | float(0)) > 0 and ns.id == '' %}{% set ns.id = states(b\
+ \ ~ '_id') %}{% endif %}{% endif %}{% endfor %}{% if ns.id %}\u2022 {{ state_attr('sensor.spoolman_spool_'\
+ \ ~ ns.id, 'filament_vendor_name') | default('?', true) }} \xB7 {{ state_attr('sensor.spoolman_spool_'\
+ \ ~ ns.id, 'filament_material') | default('?', true) }} \xB7 #{{ color |\
+ \ upper }}\n\u2022 Remaining: {{ (states('sensor.spoolman_spool_' ~ ns.id)\
+ \ | float(0)) | round(1) }} g \xB7 used {{ (state_attr('sensor.spoolman_spool_'\
+ \ ~ ns.id, 'used_weight') | float(0)) | round(1) }} g ({{ (state_attr('sensor.spoolman_spool_'\
+ \ ~ ns.id, 'used_percentage') | float(0)) | round(1) }}%)\n\u2022 Remaining\
+ \ length: {{ ((state_attr('sensor.spoolman_spool_' ~ ns.id, 'remaining_length')\
+ \ | float(0)) / 1000) | round(1) }} m \xB7 used {{ ((state_attr('sensor.spoolman_spool_'\
+ \ ~ ns.id, 'used_length') | float(0)) / 1000) | round(1) }} m\n\u2022 Spool:\
+ \ \xD8{{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'filament_diameter')\
+ \ | default('?', true) }} mm \xB7 {{ state_attr('sensor.spoolman_spool_'\
+ \ ~ ns.id, 'filament_density') | default('?', true) }} g/cm\xB3 \xB7 {{\
+ \ state_attr('sensor.spoolman_spool_' ~ ns.id, 'filament_weight') | default('?',\
+ \ true) }} g \xB7 art. {{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'filament_article_number')\
+ \ | default('?', true) }}\n\u2022 Temps: bed {{ state_attr('sensor.spoolman_spool_'\
+ \ ~ ns.id, 'filament_settings_bed_temp') | default('?', true) }}\xB0C \xB7\
+ \ hotend {{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'filament_settings_extruder_temp')\
+ \ | default('?', true) }}\xB0C\n\u2022 Flow: {{ states('sensor.spoolman_spool_'\
+ \ ~ ns.id ~ '_flow_rate') }} \xB7 Runout est.: {{ states('sensor.spoolman_spool_'\
+ \ ~ ns.id ~ '_estimated_runout') }}\n\u2022 Registered: {{ state_attr('sensor.spoolman_spool_'\
+ \ ~ ns.id, 'registered') | default('?', true) }} \xB7 Location: {{ state_attr('sensor.spoolman_spool_'\
+ \ ~ ns.id, 'location') | default('?', true) }} \xB7 Price: {{ state_attr('sensor.spoolman_spool_'\
+ \ ~ ns.id, 'filament_price') | default('?', true) }}{% elif color in ['',\
+ \ 'unknown', 'unavailable'] %}\u2022 Slot color unavailable{% else %}\u2022\
+ \ No spool with stock matches this color{% endif %}"
+ multiline_secondary: true
+ grid_options:
+ columns: full
+ - type: custom:mushroom-template-card
+ entity: sensor.sparkx_i7_cfs_box_1_slot_3_color
+ name: Slot 3
+ icon: mdi:spool
+ icon_color: '{% set c = states(''sensor.sparkx_i7_cfs_box_1_slot_3_color'')
+ | replace(''#'', '''') | lower %}{% if c | length == 6 %}#{{ c }}{% else
+ %}var(--primary-color){% endif %}'
+ picture: '{% set color = states(''sensor.sparkx_i7_cfs_box_1_slot_3_color'')
+ | replace(''#'', '''') | lower %}{% set ns = namespace(id='''') %}{% for
+ e in integration_entities(''spoolman'') %}{% if e.endswith(''_color_hex'')
+ and (states(e) | replace(''#'', '''') | lower) == color %}{% set b = e[:-10]
+ %}{% if (states(b) | float(0)) > 0 and ns.id == '''' %}{% set ns.id = states(b
+ ~ ''_id'') %}{% endif %}{% endif %}{% endfor %}{{ state_attr(''sensor.spoolman_spool_''
+ ~ ns.id, ''entity_picture'') if ns.id and state_attr(''sensor.spoolman_spool_''
+ ~ ns.id, ''entity_picture'') else '''' }}'
+ primary: "{% set color = states('sensor.sparkx_i7_cfs_box_1_slot_3_color')\
+ \ | replace('#', '') | lower %}{% set ns = namespace(id='') %}{% for e in\
+ \ integration_entities('spoolman') %}{% if e.endswith('_color_hex') and\
+ \ (states(e) | replace('#', '') | lower) == color %}{% set b = e[:-10] %}{%\
+ \ if (states(b) | float(0)) > 0 and ns.id == '' %}{% set ns.id = states(b\
+ \ ~ '_id') %}{% endif %}{% endif %}{% endfor %}{% if ns.id %}Spool {{ ns.id\
+ \ }} \xB7 {{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'filament_name')\
+ \ | default('?', true) }} \xB7 {{ (states('sensor.spoolman_spool_' ~ ns.id)\
+ \ | float(0)) | round(1) }} g left{% elif color in ['', 'unknown', 'unavailable']\
+ \ %}Slot color unavailable{% else %}No spool with stock matches this color{%\
+ \ endif %}"
+ secondary: "{% set color = states('sensor.sparkx_i7_cfs_box_1_slot_3_color')\
+ \ | replace('#', '') | lower %}{% set ns = namespace(id='') %}{% for e in\
+ \ integration_entities('spoolman') %}{% if e.endswith('_color_hex') and\
+ \ (states(e) | replace('#', '') | lower) == color %}{% set b = e[:-10] %}{%\
+ \ if (states(b) | float(0)) > 0 and ns.id == '' %}{% set ns.id = states(b\
+ \ ~ '_id') %}{% endif %}{% endif %}{% endfor %}{% if ns.id %}\u2022 {{ state_attr('sensor.spoolman_spool_'\
+ \ ~ ns.id, 'filament_vendor_name') | default('?', true) }} \xB7 {{ state_attr('sensor.spoolman_spool_'\
+ \ ~ ns.id, 'filament_material') | default('?', true) }} \xB7 #{{ color |\
+ \ upper }}\n\u2022 Remaining: {{ (states('sensor.spoolman_spool_' ~ ns.id)\
+ \ | float(0)) | round(1) }} g \xB7 used {{ (state_attr('sensor.spoolman_spool_'\
+ \ ~ ns.id, 'used_weight') | float(0)) | round(1) }} g ({{ (state_attr('sensor.spoolman_spool_'\
+ \ ~ ns.id, 'used_percentage') | float(0)) | round(1) }}%)\n\u2022 Remaining\
+ \ length: {{ ((state_attr('sensor.spoolman_spool_' ~ ns.id, 'remaining_length')\
+ \ | float(0)) / 1000) | round(1) }} m \xB7 used {{ ((state_attr('sensor.spoolman_spool_'\
+ \ ~ ns.id, 'used_length') | float(0)) / 1000) | round(1) }} m\n\u2022 Spool:\
+ \ \xD8{{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'filament_diameter')\
+ \ | default('?', true) }} mm \xB7 {{ state_attr('sensor.spoolman_spool_'\
+ \ ~ ns.id, 'filament_density') | default('?', true) }} g/cm\xB3 \xB7 {{\
+ \ state_attr('sensor.spoolman_spool_' ~ ns.id, 'filament_weight') | default('?',\
+ \ true) }} g \xB7 art. {{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'filament_article_number')\
+ \ | default('?', true) }}\n\u2022 Temps: bed {{ state_attr('sensor.spoolman_spool_'\
+ \ ~ ns.id, 'filament_settings_bed_temp') | default('?', true) }}\xB0C \xB7\
+ \ hotend {{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'filament_settings_extruder_temp')\
+ \ | default('?', true) }}\xB0C\n\u2022 Flow: {{ states('sensor.spoolman_spool_'\
+ \ ~ ns.id ~ '_flow_rate') }} \xB7 Runout est.: {{ states('sensor.spoolman_spool_'\
+ \ ~ ns.id ~ '_estimated_runout') }}\n\u2022 Registered: {{ state_attr('sensor.spoolman_spool_'\
+ \ ~ ns.id, 'registered') | default('?', true) }} \xB7 Location: {{ state_attr('sensor.spoolman_spool_'\
+ \ ~ ns.id, 'location') | default('?', true) }} \xB7 Price: {{ state_attr('sensor.spoolman_spool_'\
+ \ ~ ns.id, 'filament_price') | default('?', true) }}{% elif color in ['',\
+ \ 'unknown', 'unavailable'] %}\u2022 Slot color unavailable{% else %}\u2022\
+ \ No spool with stock matches this color{% endif %}"
+ multiline_secondary: true
+ grid_options:
+ columns: full
+ - type: custom:mushroom-template-card
+ entity: sensor.sparkx_i7_cfs_box_1_slot_4_color
+ name: Slot 4
+ icon: mdi:spool
+ icon_color: '{% set c = states(''sensor.sparkx_i7_cfs_box_1_slot_4_color'')
+ | replace(''#'', '''') | lower %}{% if c | length == 6 %}#{{ c }}{% else
+ %}var(--primary-color){% endif %}'
+ picture: '{% set color = states(''sensor.sparkx_i7_cfs_box_1_slot_4_color'')
+ | replace(''#'', '''') | lower %}{% set ns = namespace(id='''') %}{% for
+ e in integration_entities(''spoolman'') %}{% if e.endswith(''_color_hex'')
+ and (states(e) | replace(''#'', '''') | lower) == color %}{% set b = e[:-10]
+ %}{% if (states(b) | float(0)) > 0 and ns.id == '''' %}{% set ns.id = states(b
+ ~ ''_id'') %}{% endif %}{% endif %}{% endfor %}{{ state_attr(''sensor.spoolman_spool_''
+ ~ ns.id, ''entity_picture'') if ns.id and state_attr(''sensor.spoolman_spool_''
+ ~ ns.id, ''entity_picture'') else '''' }}'
+ primary: "{% set color = states('sensor.sparkx_i7_cfs_box_1_slot_4_color')\
+ \ | replace('#', '') | lower %}{% set ns = namespace(id='') %}{% for e in\
+ \ integration_entities('spoolman') %}{% if e.endswith('_color_hex') and\
+ \ (states(e) | replace('#', '') | lower) == color %}{% set b = e[:-10] %}{%\
+ \ if (states(b) | float(0)) > 0 and ns.id == '' %}{% set ns.id = states(b\
+ \ ~ '_id') %}{% endif %}{% endif %}{% endfor %}{% if ns.id %}Spool {{ ns.id\
+ \ }} \xB7 {{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'filament_name')\
+ \ | default('?', true) }} \xB7 {{ (states('sensor.spoolman_spool_' ~ ns.id)\
+ \ | float(0)) | round(1) }} g left{% elif color in ['', 'unknown', 'unavailable']\
+ \ %}Slot color unavailable{% else %}No spool with stock matches this color{%\
+ \ endif %}"
+ secondary: "{% set color = states('sensor.sparkx_i7_cfs_box_1_slot_4_color')\
+ \ | replace('#', '') | lower %}{% set ns = namespace(id='') %}{% for e in\
+ \ integration_entities('spoolman') %}{% if e.endswith('_color_hex') and\
+ \ (states(e) | replace('#', '') | lower) == color %}{% set b = e[:-10] %}{%\
+ \ if (states(b) | float(0)) > 0 and ns.id == '' %}{% set ns.id = states(b\
+ \ ~ '_id') %}{% endif %}{% endif %}{% endfor %}{% if ns.id %}\u2022 {{ state_attr('sensor.spoolman_spool_'\
+ \ ~ ns.id, 'filament_vendor_name') | default('?', true) }} \xB7 {{ state_attr('sensor.spoolman_spool_'\
+ \ ~ ns.id, 'filament_material') | default('?', true) }} \xB7 #{{ color |\
+ \ upper }}\n\u2022 Remaining: {{ (states('sensor.spoolman_spool_' ~ ns.id)\
+ \ | float(0)) | round(1) }} g \xB7 used {{ (state_attr('sensor.spoolman_spool_'\
+ \ ~ ns.id, 'used_weight') | float(0)) | round(1) }} g ({{ (state_attr('sensor.spoolman_spool_'\
+ \ ~ ns.id, 'used_percentage') | float(0)) | round(1) }}%)\n\u2022 Remaining\
+ \ length: {{ ((state_attr('sensor.spoolman_spool_' ~ ns.id, 'remaining_length')\
+ \ | float(0)) / 1000) | round(1) }} m \xB7 used {{ ((state_attr('sensor.spoolman_spool_'\
+ \ ~ ns.id, 'used_length') | float(0)) / 1000) | round(1) }} m\n\u2022 Spool:\
+ \ \xD8{{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'filament_diameter')\
+ \ | default('?', true) }} mm \xB7 {{ state_attr('sensor.spoolman_spool_'\
+ \ ~ ns.id, 'filament_density') | default('?', true) }} g/cm\xB3 \xB7 {{\
+ \ state_attr('sensor.spoolman_spool_' ~ ns.id, 'filament_weight') | default('?',\
+ \ true) }} g \xB7 art. {{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'filament_article_number')\
+ \ | default('?', true) }}\n\u2022 Temps: bed {{ state_attr('sensor.spoolman_spool_'\
+ \ ~ ns.id, 'filament_settings_bed_temp') | default('?', true) }}\xB0C \xB7\
+ \ hotend {{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'filament_settings_extruder_temp')\
+ \ | default('?', true) }}\xB0C\n\u2022 Flow: {{ states('sensor.spoolman_spool_'\
+ \ ~ ns.id ~ '_flow_rate') }} \xB7 Runout est.: {{ states('sensor.spoolman_spool_'\
+ \ ~ ns.id ~ '_estimated_runout') }}\n\u2022 Registered: {{ state_attr('sensor.spoolman_spool_'\
+ \ ~ ns.id, 'registered') | default('?', true) }} \xB7 Location: {{ state_attr('sensor.spoolman_spool_'\
+ \ ~ ns.id, 'location') | default('?', true) }} \xB7 Price: {{ state_attr('sensor.spoolman_spool_'\
+ \ ~ ns.id, 'filament_price') | default('?', true) }}{% elif color in ['',\
+ \ 'unknown', 'unavailable'] %}\u2022 Slot color unavailable{% else %}\u2022\
+ \ No spool with stock matches this color{% endif %}"
+ multiline_secondary: true
+ grid_options:
+ columns: full
+ - type: grid
+ cards:
+ - type: heading
+ heading: Adjust Remaining
+ icon: mdi:pencil-outline
+ - type: entities
+ title: Set value (g)
+ show_header_toggle: false
+ entities:
+ - input_number.spoolman_set_remaining
+ grid_options:
+ columns: full
+ - type: tile
+ entity: input_number.spoolman_set_remaining
+ name: Apply to Slot 1
+ icon: mdi:content-save-outline
+ grid_options:
+ columns: 3
+ tap_action:
+ action: perform-action
+ perform_action: script.spoolman_set_spool_remaining
+ data:
+ slot: 1
+ confirmation:
+ text: Overwrite remaining weight of the spool matching Slot 1 (by color
+ hex) in Spoolman?
+ - type: tile
+ entity: input_number.spoolman_set_remaining
+ name: Apply to Slot 2
+ icon: mdi:content-save-outline
+ grid_options:
+ columns: 3
+ tap_action:
+ action: perform-action
+ perform_action: script.spoolman_set_spool_remaining
+ data:
+ slot: 2
+ confirmation:
+ text: Overwrite remaining weight of the spool matching Slot 2 (by color
+ hex) in Spoolman?
+ - type: tile
+ entity: input_number.spoolman_set_remaining
+ name: Apply to Slot 3
+ icon: mdi:content-save-outline
+ grid_options:
+ columns: 3
+ tap_action:
+ action: perform-action
+ perform_action: script.spoolman_set_spool_remaining
+ data:
+ slot: 3
+ confirmation:
+ text: Overwrite remaining weight of the spool matching Slot 3 (by color
+ hex) in Spoolman?
+ - type: tile
+ entity: input_number.spoolman_set_remaining
+ name: Apply to Slot 4
+ icon: mdi:content-save-outline
+ grid_options:
+ columns: 3
+ tap_action:
+ action: perform-action
+ perform_action: script.spoolman_set_spool_remaining
+ data:
+ slot: 4
+ confirmation:
+ text: Overwrite remaining weight of the spool matching Slot 4 (by color
+ hex) in Spoolman?
+ - type: markdown
+ content: "**1.** Type the new remaining grams above. **2.** Tap **Apply to\
+ \ Slot N** for the slot holding that roll \u2014 it resolves the spool by\
+ \ the slot's color hex, so it also works when the spool is exhausted (e.g.\
+ \ right after replacing a roll). **3.** The value is **absolute** \u2014\
+ \ it replaces Spoolman's remaining weight; print deductions continue from\
+ \ there. Avoid adjusting during a running print."
+ grid_options:
+ columns: full
+ - type: grid
+ cards:
+ - type: heading
+ heading: Print Linkage
+ icon: mdi:printer-3d-nozzle
+ - type: tile
+ entity: automation.sparkx_i7_latch_print_spool_for_spoolman
+ name: Latch + Segment Deduction
+ icon: mdi:link-variant
+ grid_options:
+ columns: 3
+ - type: tile
+ entity: automation.sparkx_i7_deduct_filament_in_spoolman_on_print_complete
+ name: Print Complete Deduction
+ icon: mdi:minus-circle-outline
+ grid_options:
+ columns: 3
+ - type: tile
+ entity: sensor.sparkx_i7_filament_weight_estimated
+ name: Current Job Weight (est.)
+ icon: mdi:weight-gram
+ grid_options:
+ columns: 3
+ - type: tile
+ entity: input_number.sparkx_i7_filament_g_cm
+ name: Filament g/cm
+ icon: mdi:ruler
+ grid_options:
+ columns: 3
+ - type: tile
+ entity: sensor.sparkx_i7_active_filament_slot
+ name: Active CFS Slot
+ icon: mdi:palette-swatch-variant
+ grid_options:
+ columns: 3
+ - type: tile
+ entity: sensor.sparkx_i7_used_material_length
+ name: Used Material Total (cm)
+ icon: mdi:plus-minus
+ grid_options:
+ columns: 6
+ rows: 1
+ - type: grid
+ cards:
+ - type: heading
+ heading: "Spool History \u2014 CFS Lite (auto)"
+ icon: mdi:history
+ - type: custom:auto-entities
+ filter:
+ include:
+ - entity_id: sensor.spoolman_spool_*
+ attributes:
+ location: CFS Lite
+ sort:
+ method: attribute
+ attribute: id
+ numeric: true
+ card:
+ type: history-graph
+ title: Remaining weight (7 days)
+ hours_to_show: 168
+ show_names: true
+ show_empty: false
+ grid_options:
+ columns: full
+ - type: markdown
+ content: "Every spool with location **CFS Lite** joins this graph automatically\
+ \ \u2014 register a new roll in Spoolman (same color hex, location CFS Lite)\
+ \ and it appears without dashboard edits. History follows the spool entity;\
+ \ a replaced roll keeps its own history under its own spool id."
+ grid_options:
+ columns: full
diff --git a/.ha_mcp/backups/dashboard.spoolman-ui.20261009_002240.yaml b/.ha_mcp/backups/dashboard.spoolman-ui.20261009_002240.yaml
new file mode 100644
index 00000000..33915f80
--- /dev/null
+++ b/.ha_mcp/backups/dashboard.spoolman-ui.20261009_002240.yaml
@@ -0,0 +1,15 @@
+# ha_mcp_backup
+schema_version: 1
+domain: dashboard
+entity_id: spoolman-ui
+captured: '2026-10-09T00:22:40.531965+00:00'
+tool: ha_config_set_dashboard
+config:
+ views:
+ - title: Spoolman
+ path: spoolman
+ type: panel
+ cards:
+ - type: iframe
+ url: http://192.168.1.140:7912
+ aspect_ratio: 100%
diff --git a/.ha_mcp/logs/mcp_usage.jsonl b/.ha_mcp/logs/mcp_usage.jsonl
index 1d8d3edb..caf01a66 100644
--- a/.ha_mcp/logs/mcp_usage.jsonl
+++ b/.ha_mcp/logs/mcp_usage.jsonl
@@ -4138,3 +4138,5 @@
{"timestamp": "2026-10-09T00:21:27.113179+00:00", "tool_name": "ha_config_set_automation", "parameters": {"config": null, "identifier": "1791477238729", "python_transform": "config['actions'][2]['variables']['spool_id'] = \"{% set ns = namespace(id='') %}{% for e in integration_entities('spoolman') %}{% if e.endswith('_color_hex') and (states(e) | replace('#', '') | lower) == color and (state_attr(e[:-10], 'location') | default('', true) | lower) == 'cfs lite' %}{% set b = e[:-10] %}{% if (states(b) | float(0)) > 0 and ns.id == '' %}{% set ns.id = states(b ~ '_id') %}{% endif %}{% endif %}{% endfor %}{{ ns.id }}\"", "config_hash": "12ad28705dc169cf", "take_control_of_blueprint": false, "category": null, "wait": true, "enabled": null, "run_actions": false, "MandatoryBPS": false, "BestPracticeKey": null}, "execution_time_ms": 1505.1090717315674, "success": true, "error_message": null, "response_size_bytes": 7449, "user_context": null}
{"timestamp": "2026-10-09T00:21:42.895929+00:00", "tool_name": "ha_config_get_dashboard", "parameters": {"url_path": "sparkx-i7", "list_only": false, "force_reload": false, "entity_id": null, "card_type": null, "heading": null, "include_config": false, "include_screenshot": false, "view_path": "spoolman", "mode": null, "query": null}, "execution_time_ms": 21.6677188873291, "success": true, "error_message": null, "response_size_bytes": 32156, "user_context": null}
{"timestamp": "2026-10-09T00:21:42.900133+00:00", "tool_name": "ha_config_get_dashboard", "parameters": {"url_path": "spoolman-ui", "list_only": false, "force_reload": false, "entity_id": null, "card_type": null, "heading": null, "include_config": false, "include_screenshot": false, "view_path": null, "mode": null, "query": null}, "execution_time_ms": 25.4213809967041, "success": true, "error_message": null, "response_size_bytes": 461, "user_context": null}
+{"timestamp": "2026-10-09T00:22:40.631021+00:00", "tool_name": "ha_config_set_dashboard", "parameters": {"url_path": "spoolman-ui", "config": {"views": [{"title": "Spoolman", "path": "spoolman", "type": "panel", "cards": [{"type": "button", "tap_action": {"action": "[REDACTED]", "url_path": "[REDACTED]"}, "icon": "mdi:printer-3d-nozzle", "name": "Open Spoolman", "show_name": true}]}]}, "python_transform": null, "config_hash": "8a1ff2399acbcab1", "title": null, "icon": null, "require_admin": null, "show_in_sidebar": null, "MandatoryBPS": false, "BestPracticeKey": null, "return_screenshot": false, "view_path": null, "patch": null}, "execution_time_ms": 7.4634552001953125, "success": true, "error_message": null, "response_size_bytes": 485, "user_context": null}
+{"timestamp": "2026-10-09T00:22:40.723549+00:00", "tool_name": "ha_config_set_dashboard", "parameters": {"url_path": "sparkx-i7", "config": null, "python_transform": "n = '== color %}'\nr = \"== color and (state_attr(e[:-10], 'location') | default('', true) | lower) == 'cfs lite' %}\"\nc = 0\nfor s in config['views'][3]['sections']:\n for card in s.get('cards', []):\n for k, v in card.items():\n if isinstance(v, str) and n in v:\n card[k] = v.replace(n, r)\n c += 1", "config_hash": "473bd8180cfc8d35", "title": null, "icon": null, "require_admin": null, "show_in_sidebar": null, "MandatoryBPS": false, "BestPracticeKey": null, "return_screenshot": false, "view_path": null, "patch": null}, "execution_time_ms": 30.977249145507812, "success": true, "error_message": null, "response_size_bytes": 1194, "user_context": null}
diff --git a/.storage/lovelace.sparkx_i7 b/.storage/lovelace.sparkx_i7
index c1ae536c..81fbf71e 100644
--- a/.storage/lovelace.sparkx_i7
+++ b/.storage/lovelace.sparkx_i7
@@ -935,7 +935,7 @@
"icon": "mdi:printer-filament",
"icon_color": "{% set c = states('sensor.sparkx_i7_cfs_box_1_slot_1_color') | replace('#', '') | lower %}{% if c | length == 6 %}#{{ c }}{% else %}var(--primary-color){% endif %}",
"primary": "{{ states('sensor.sparkx_i7_slot_1_color_name') }} (#{{ states('sensor.sparkx_i7_cfs_box_1_slot_1_color') | replace('#', '') | upper }})",
- "secondary": "{% set color = states('sensor.sparkx_i7_cfs_box_1_slot_1_color') | replace('#', '') | lower %}{% set ns = namespace(id='') %}{% for e in integration_entities('spoolman') %}{% if e.endswith('_color_hex') and (states(e) | replace('#', '') | lower) == color %}{% set b = e[:-10] %}{% if (states(b) | float(0)) > 0 and ns.id == '' %}{% set ns.id = states(b ~ '_id') %}{% endif %}{% endif %}{% endfor %}{% if ns.id %}• Spool {{ ns.id }} · {{ states('sensor.spoolman_spool_' ~ ns.id ~ '_vendor') | default('?', true) }} · {{ states('sensor.spoolman_spool_' ~ ns.id ~ '_material') | default('?', true) }} · {{ (states('sensor.spoolman_spool_' ~ ns.id) | float(0)) | round(1) }} g left{% elif color in ['', 'unknown', 'unavailable'] %}• Slot color unavailable{% else %}• No spool with stock matches this color{% endif %}\n• This print: {{ (states('input_number.sparkx_i7_slot_1_grams') | float(0)) | round(1) }} g",
+ "secondary": "{% set color = states('sensor.sparkx_i7_cfs_box_1_slot_1_color') | replace('#', '') | lower %}{% set ns = namespace(id='') %}{% for e in integration_entities('spoolman') %}{% if e.endswith('_color_hex') and (states(e) | replace('#', '') | lower) == color and (state_attr(e[:-10], 'location') | default('', true) | lower) == 'cfs lite' %}{% set b = e[:-10] %}{% if (states(b) | float(0)) > 0 and ns.id == '' %}{% set ns.id = states(b ~ '_id') %}{% endif %}{% endif %}{% endfor %}{% if ns.id %}• Spool {{ ns.id }} · {{ states('sensor.spoolman_spool_' ~ ns.id ~ '_vendor') | default('?', true) }} · {{ states('sensor.spoolman_spool_' ~ ns.id ~ '_material') | default('?', true) }} · {{ (states('sensor.spoolman_spool_' ~ ns.id) | float(0)) | round(1) }} g left{% elif color in ['', 'unknown', 'unavailable'] %}• Slot color unavailable{% else %}• No spool with stock matches this color{% endif %}\n• This print: {{ (states('input_number.sparkx_i7_slot_1_grams') | float(0)) | round(1) }} g",
"multiline_secondary": true,
"grid_options": {
"columns": "full"
@@ -949,7 +949,7 @@
"icon": "mdi:printer-filament",
"icon_color": "{% set c = states('sensor.sparkx_i7_cfs_box_1_slot_2_color') | replace('#', '') | lower %}{% if c | length == 6 %}#{{ c }}{% else %}var(--primary-color){% endif %}",
"primary": "{{ states('sensor.sparkx_i7_slot_2_color_name') }} (#{{ states('sensor.sparkx_i7_cfs_box_1_slot_2_color') | replace('#', '') | upper }})",
- "secondary": "{% set color = states('sensor.sparkx_i7_cfs_box_1_slot_2_color') | replace('#', '') | lower %}{% set ns = namespace(id='') %}{% for e in integration_entities('spoolman') %}{% if e.endswith('_color_hex') and (states(e) | replace('#', '') | lower) == color %}{% set b = e[:-10] %}{% if (states(b) | float(0)) > 0 and ns.id == '' %}{% set ns.id = states(b ~ '_id') %}{% endif %}{% endif %}{% endfor %}{% if ns.id %}• Spool {{ ns.id }} · {{ states('sensor.spoolman_spool_' ~ ns.id ~ '_vendor') | default('?', true) }} · {{ states('sensor.spoolman_spool_' ~ ns.id ~ '_material') | default('?', true) }} · {{ (states('sensor.spoolman_spool_' ~ ns.id) | float(0)) | round(1) }} g left{% elif color in ['', 'unknown', 'unavailable'] %}• Slot color unavailable{% else %}• No spool with stock matches this color{% endif %}\n• This print: {{ (states('input_number.sparkx_i7_slot_2_grams') | float(0)) | round(1) }} g",
+ "secondary": "{% set color = states('sensor.sparkx_i7_cfs_box_1_slot_2_color') | replace('#', '') | lower %}{% set ns = namespace(id='') %}{% for e in integration_entities('spoolman') %}{% if e.endswith('_color_hex') and (states(e) | replace('#', '') | lower) == color and (state_attr(e[:-10], 'location') | default('', true) | lower) == 'cfs lite' %}{% set b = e[:-10] %}{% if (states(b) | float(0)) > 0 and ns.id == '' %}{% set ns.id = states(b ~ '_id') %}{% endif %}{% endif %}{% endfor %}{% if ns.id %}• Spool {{ ns.id }} · {{ states('sensor.spoolman_spool_' ~ ns.id ~ '_vendor') | default('?', true) }} · {{ states('sensor.spoolman_spool_' ~ ns.id ~ '_material') | default('?', true) }} · {{ (states('sensor.spoolman_spool_' ~ ns.id) | float(0)) | round(1) }} g left{% elif color in ['', 'unknown', 'unavailable'] %}• Slot color unavailable{% else %}• No spool with stock matches this color{% endif %}\n• This print: {{ (states('input_number.sparkx_i7_slot_2_grams') | float(0)) | round(1) }} g",
"multiline_secondary": true,
"grid_options": {
"columns": "full"
@@ -963,7 +963,7 @@
"icon": "mdi:printer-filament",
"icon_color": "{% set c = states('sensor.sparkx_i7_cfs_box_1_slot_3_color') | replace('#', '') | lower %}{% if c | length == 6 %}#{{ c }}{% else %}var(--primary-color){% endif %}",
"primary": "{{ states('sensor.sparkx_i7_slot_3_color_name') }} (#{{ states('sensor.sparkx_i7_cfs_box_1_slot_3_color') | replace('#', '') | upper }})",
- "secondary": "{% set color = states('sensor.sparkx_i7_cfs_box_1_slot_3_color') | replace('#', '') | lower %}{% set ns = namespace(id='') %}{% for e in integration_entities('spoolman') %}{% if e.endswith('_color_hex') and (states(e) | replace('#', '') | lower) == color %}{% set b = e[:-10] %}{% if (states(b) | float(0)) > 0 and ns.id == '' %}{% set ns.id = states(b ~ '_id') %}{% endif %}{% endif %}{% endfor %}{% if ns.id %}• Spool {{ ns.id }} · {{ states('sensor.spoolman_spool_' ~ ns.id ~ '_vendor') | default('?', true) }} · {{ states('sensor.spoolman_spool_' ~ ns.id ~ '_material') | default('?', true) }} · {{ (states('sensor.spoolman_spool_' ~ ns.id) | float(0)) | round(1) }} g left{% elif color in ['', 'unknown', 'unavailable'] %}• Slot color unavailable{% else %}• No spool with stock matches this color{% endif %}\n• This print: {{ (states('input_number.sparkx_i7_slot_3_grams') | float(0)) | round(1) }} g",
+ "secondary": "{% set color = states('sensor.sparkx_i7_cfs_box_1_slot_3_color') | replace('#', '') | lower %}{% set ns = namespace(id='') %}{% for e in integration_entities('spoolman') %}{% if e.endswith('_color_hex') and (states(e) | replace('#', '') | lower) == color and (state_attr(e[:-10], 'location') | default('', true) | lower) == 'cfs lite' %}{% set b = e[:-10] %}{% if (states(b) | float(0)) > 0 and ns.id == '' %}{% set ns.id = states(b ~ '_id') %}{% endif %}{% endif %}{% endfor %}{% if ns.id %}• Spool {{ ns.id }} · {{ states('sensor.spoolman_spool_' ~ ns.id ~ '_vendor') | default('?', true) }} · {{ states('sensor.spoolman_spool_' ~ ns.id ~ '_material') | default('?', true) }} · {{ (states('sensor.spoolman_spool_' ~ ns.id) | float(0)) | round(1) }} g left{% elif color in ['', 'unknown', 'unavailable'] %}• Slot color unavailable{% else %}• No spool with stock matches this color{% endif %}\n• This print: {{ (states('input_number.sparkx_i7_slot_3_grams') | float(0)) | round(1) }} g",
"multiline_secondary": true,
"grid_options": {
"columns": "full"
@@ -977,7 +977,7 @@
"icon": "mdi:printer-filament",
"icon_color": "{% set c = states('sensor.sparkx_i7_cfs_box_1_slot_4_color') | replace('#', '') | lower %}{% if c | length == 6 %}#{{ c }}{% else %}var(--primary-color){% endif %}",
"primary": "{{ states('sensor.sparkx_i7_slot_4_color_name') }} (#{{ states('sensor.sparkx_i7_cfs_box_1_slot_4_color') | replace('#', '') | upper }})",
- "secondary": "{% set color = states('sensor.sparkx_i7_cfs_box_1_slot_4_color') | replace('#', '') | lower %}{% set ns = namespace(id='') %}{% for e in integration_entities('spoolman') %}{% if e.endswith('_color_hex') and (states(e) | replace('#', '') | lower) == color %}{% set b = e[:-10] %}{% if (states(b) | float(0)) > 0 and ns.id == '' %}{% set ns.id = states(b ~ '_id') %}{% endif %}{% endif %}{% endfor %}{% if ns.id %}• Spool {{ ns.id }} · {{ states('sensor.spoolman_spool_' ~ ns.id ~ '_vendor') | default('?', true) }} · {{ states('sensor.spoolman_spool_' ~ ns.id ~ '_material') | default('?', true) }} · {{ (states('sensor.spoolman_spool_' ~ ns.id) | float(0)) | round(1) }} g left{% elif color in ['', 'unknown', 'unavailable'] %}• Slot color unavailable{% else %}• No spool with stock matches this color{% endif %}\n• This print: {{ (states('input_number.sparkx_i7_slot_4_grams') | float(0)) | round(1) }} g",
+ "secondary": "{% set color = states('sensor.sparkx_i7_cfs_box_1_slot_4_color') | replace('#', '') | lower %}{% set ns = namespace(id='') %}{% for e in integration_entities('spoolman') %}{% if e.endswith('_color_hex') and (states(e) | replace('#', '') | lower) == color and (state_attr(e[:-10], 'location') | default('', true) | lower) == 'cfs lite' %}{% set b = e[:-10] %}{% if (states(b) | float(0)) > 0 and ns.id == '' %}{% set ns.id = states(b ~ '_id') %}{% endif %}{% endif %}{% endfor %}{% if ns.id %}• Spool {{ ns.id }} · {{ states('sensor.spoolman_spool_' ~ ns.id ~ '_vendor') | default('?', true) }} · {{ states('sensor.spoolman_spool_' ~ ns.id ~ '_material') | default('?', true) }} · {{ (states('sensor.spoolman_spool_' ~ ns.id) | float(0)) | round(1) }} g left{% elif color in ['', 'unknown', 'unavailable'] %}• Slot color unavailable{% else %}• No spool with stock matches this color{% endif %}\n• This print: {{ (states('input_number.sparkx_i7_slot_4_grams') | float(0)) | round(1) }} g",
"multiline_secondary": true,
"grid_options": {
"columns": "full"
@@ -1028,7 +1028,7 @@
"icon": "mdi:magnet",
"icon_color": "{% set slot = states('sensor.sparkx_i7_active_filament_slot') %}{% set c = states('sensor.sparkx_i7_cfs_' ~ (slot | lower | replace(' ', '_')) ~ '_color') | replace('#', '') | lower %}{% if c | length == 6 %}#{{ c }}{% else %}var(--primary-color){% endif %}",
"primary": "{{ states('sensor.sparkx_i7_active_filament_slot') }}",
- "secondary": "{% set slot = states('sensor.sparkx_i7_active_filament_slot') %}{% set ce = 'sensor.sparkx_i7_cfs_' ~ (slot | lower | replace(' ', '_')) ~ '_color' %}{% set color = states(ce) | replace('#', '') | lower %}{% set ns = namespace(id='') %}{% for e in integration_entities('spoolman') %}{% if e.endswith('_color_hex') and (states(e) | replace('#', '') | lower) == color %}{% set b = e[:-10] %}{% if (states(b) | float(0)) > 0 and ns.id == '' %}{% set ns.id = states(b ~ '_id') %}{% endif %}{% endif %}{% endfor %}{% if ns.id %}Color #{{ color | upper }} → spool {{ ns.id }} ({{ states('sensor.spoolman_spool_' ~ ns.id ~ '_filament_name') }} · {{ (states('sensor.spoolman_spool_' ~ ns.id) | float(0)) | round(1) }} g left){% elif slot in ['', 'unknown', 'unavailable'] %}No slot latched{% elif color in ['', 'unknown', 'unavailable'] %}Slot color unavailable{% else %}Color #{{ color | upper }} — no spool with stock{% endif %}",
+ "secondary": "{% set slot = states('sensor.sparkx_i7_active_filament_slot') %}{% set ce = 'sensor.sparkx_i7_cfs_' ~ (slot | lower | replace(' ', '_')) ~ '_color' %}{% set color = states(ce) | replace('#', '') | lower %}{% set ns = namespace(id='') %}{% for e in integration_entities('spoolman') %}{% if e.endswith('_color_hex') and (states(e) | replace('#', '') | lower) == color and (state_attr(e[:-10], 'location') | default('', true) | lower) == 'cfs lite' %}{% set b = e[:-10] %}{% if (states(b) | float(0)) > 0 and ns.id == '' %}{% set ns.id = states(b ~ '_id') %}{% endif %}{% endif %}{% endfor %}{% if ns.id %}Color #{{ color | upper }} → spool {{ ns.id }} ({{ states('sensor.spoolman_spool_' ~ ns.id ~ '_filament_name') }} · {{ (states('sensor.spoolman_spool_' ~ ns.id) | float(0)) | round(1) }} g left){% elif slot in ['', 'unknown', 'unavailable'] %}No slot latched{% elif color in ['', 'unknown', 'unavailable'] %}Slot color unavailable{% else %}Color #{{ color | upper }} — no spool with stock{% endif %}",
"multiline_secondary": true,
"grid_options": {
"columns": "full"
@@ -1057,9 +1057,9 @@
"name": "Slot 1",
"icon": "mdi:spool",
"icon_color": "{% set c = states('sensor.sparkx_i7_cfs_box_1_slot_1_color') | replace('#', '') | lower %}{% if c | length == 6 %}#{{ c }}{% else %}var(--primary-color){% endif %}",
- "picture": "{% set color = states('sensor.sparkx_i7_cfs_box_1_slot_1_color') | replace('#', '') | lower %}{% set ns = namespace(id='') %}{% for e in integration_entities('spoolman') %}{% if e.endswith('_color_hex') and (states(e) | replace('#', '') | lower) == color %}{% set b = e[:-10] %}{% if (states(b) | float(0)) > 0 and ns.id == '' %}{% set ns.id = states(b ~ '_id') %}{% endif %}{% endif %}{% endfor %}{{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'entity_picture') if ns.id and state_attr('sensor.spoolman_spool_' ~ ns.id, 'entity_picture') else '' }}",
- "primary": "{% set color = states('sensor.sparkx_i7_cfs_box_1_slot_1_color') | replace('#', '') | lower %}{% set ns = namespace(id='') %}{% for e in integration_entities('spoolman') %}{% if e.endswith('_color_hex') and (states(e) | replace('#', '') | lower) == color %}{% set b = e[:-10] %}{% if (states(b) | float(0)) > 0 and ns.id == '' %}{% set ns.id = states(b ~ '_id') %}{% endif %}{% endif %}{% endfor %}{% if ns.id %}Spool {{ ns.id }} · {{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'filament_name') | default('?', true) }} · {{ (states('sensor.spoolman_spool_' ~ ns.id) | float(0)) | round(1) }} g left{% elif color in ['', 'unknown', 'unavailable'] %}Slot color unavailable{% else %}No spool with stock matches this color{% endif %}",
- "secondary": "{% set color = states('sensor.sparkx_i7_cfs_box_1_slot_1_color') | replace('#', '') | lower %}{% set ns = namespace(id='') %}{% for e in integration_entities('spoolman') %}{% if e.endswith('_color_hex') and (states(e) | replace('#', '') | lower) == color %}{% set b = e[:-10] %}{% if (states(b) | float(0)) > 0 and ns.id == '' %}{% set ns.id = states(b ~ '_id') %}{% endif %}{% endif %}{% endfor %}{% if ns.id %}• {{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'filament_vendor_name') | default('?', true) }} · {{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'filament_material') | default('?', true) }} · #{{ color | upper }}\n• Remaining: {{ (states('sensor.spoolman_spool_' ~ ns.id) | float(0)) | round(1) }} g · used {{ (state_attr('sensor.spoolman_spool_' ~ ns.id, 'used_weight') | float(0)) | round(1) }} g ({{ (state_attr('sensor.spoolman_spool_' ~ ns.id, 'used_percentage') | float(0)) | round(1) }}%)\n• Remaining length: {{ ((state_attr('sensor.spoolman_spool_' ~ ns.id, 'remaining_length') | float(0)) / 1000) | round(1) }} m · used {{ ((state_attr('sensor.spoolman_spool_' ~ ns.id, 'used_length') | float(0)) / 1000) | round(1) }} m\n• Spool: Ø{{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'filament_diameter') | default('?', true) }} mm · {{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'filament_density') | default('?', true) }} g/cm³ · {{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'filament_weight') | default('?', true) }} g · art. {{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'filament_article_number') | default('?', true) }}\n• Temps: bed {{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'filament_settings_bed_temp') | default('?', true) }}°C · hotend {{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'filament_settings_extruder_temp') | default('?', true) }}°C\n• Flow: {{ states('sensor.spoolman_spool_' ~ ns.id ~ '_flow_rate') }} · Runout est.: {{ states('sensor.spoolman_spool_' ~ ns.id ~ '_estimated_runout') }}\n• Registered: {{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'registered') | default('?', true) }} · Location: {{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'location') | default('?', true) }} · Price: {{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'filament_price') | default('?', true) }}{% elif color in ['', 'unknown', 'unavailable'] %}• Slot color unavailable{% else %}• No spool with stock matches this color{% endif %}",
+ "picture": "{% set color = states('sensor.sparkx_i7_cfs_box_1_slot_1_color') | replace('#', '') | lower %}{% set ns = namespace(id='') %}{% for e in integration_entities('spoolman') %}{% if e.endswith('_color_hex') and (states(e) | replace('#', '') | lower) == color and (state_attr(e[:-10], 'location') | default('', true) | lower) == 'cfs lite' %}{% set b = e[:-10] %}{% if (states(b) | float(0)) > 0 and ns.id == '' %}{% set ns.id = states(b ~ '_id') %}{% endif %}{% endif %}{% endfor %}{{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'entity_picture') if ns.id and state_attr('sensor.spoolman_spool_' ~ ns.id, 'entity_picture') else '' }}",
+ "primary": "{% set color = states('sensor.sparkx_i7_cfs_box_1_slot_1_color') | replace('#', '') | lower %}{% set ns = namespace(id='') %}{% for e in integration_entities('spoolman') %}{% if e.endswith('_color_hex') and (states(e) | replace('#', '') | lower) == color and (state_attr(e[:-10], 'location') | default('', true) | lower) == 'cfs lite' %}{% set b = e[:-10] %}{% if (states(b) | float(0)) > 0 and ns.id == '' %}{% set ns.id = states(b ~ '_id') %}{% endif %}{% endif %}{% endfor %}{% if ns.id %}Spool {{ ns.id }} · {{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'filament_name') | default('?', true) }} · {{ (states('sensor.spoolman_spool_' ~ ns.id) | float(0)) | round(1) }} g left{% elif color in ['', 'unknown', 'unavailable'] %}Slot color unavailable{% else %}No spool with stock matches this color{% endif %}",
+ "secondary": "{% set color = states('sensor.sparkx_i7_cfs_box_1_slot_1_color') | replace('#', '') | lower %}{% set ns = namespace(id='') %}{% for e in integration_entities('spoolman') %}{% if e.endswith('_color_hex') and (states(e) | replace('#', '') | lower) == color and (state_attr(e[:-10], 'location') | default('', true) | lower) == 'cfs lite' %}{% set b = e[:-10] %}{% if (states(b) | float(0)) > 0 and ns.id == '' %}{% set ns.id = states(b ~ '_id') %}{% endif %}{% endif %}{% endfor %}{% if ns.id %}• {{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'filament_vendor_name') | default('?', true) }} · {{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'filament_material') | default('?', true) }} · #{{ color | upper }}\n• Remaining: {{ (states('sensor.spoolman_spool_' ~ ns.id) | float(0)) | round(1) }} g · used {{ (state_attr('sensor.spoolman_spool_' ~ ns.id, 'used_weight') | float(0)) | round(1) }} g ({{ (state_attr('sensor.spoolman_spool_' ~ ns.id, 'used_percentage') | float(0)) | round(1) }}%)\n• Remaining length: {{ ((state_attr('sensor.spoolman_spool_' ~ ns.id, 'remaining_length') | float(0)) / 1000) | round(1) }} m · used {{ ((state_attr('sensor.spoolman_spool_' ~ ns.id, 'used_length') | float(0)) / 1000) | round(1) }} m\n• Spool: Ø{{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'filament_diameter') | default('?', true) }} mm · {{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'filament_density') | default('?', true) }} g/cm³ · {{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'filament_weight') | default('?', true) }} g · art. {{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'filament_article_number') | default('?', true) }}\n• Temps: bed {{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'filament_settings_bed_temp') | default('?', true) }}°C · hotend {{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'filament_settings_extruder_temp') | default('?', true) }}°C\n• Flow: {{ states('sensor.spoolman_spool_' ~ ns.id ~ '_flow_rate') }} · Runout est.: {{ states('sensor.spoolman_spool_' ~ ns.id ~ '_estimated_runout') }}\n• Registered: {{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'registered') | default('?', true) }} · Location: {{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'location') | default('?', true) }} · Price: {{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'filament_price') | default('?', true) }}{% elif color in ['', 'unknown', 'unavailable'] %}• Slot color unavailable{% else %}• No spool with stock matches this color{% endif %}",
"multiline_secondary": true,
"grid_options": {
"columns": "full"
@@ -1071,9 +1071,9 @@
"name": "Slot 2",
"icon": "mdi:spool",
"icon_color": "{% set c = states('sensor.sparkx_i7_cfs_box_1_slot_2_color') | replace('#', '') | lower %}{% if c | length == 6 %}#{{ c }}{% else %}var(--primary-color){% endif %}",
- "picture": "{% set color = states('sensor.sparkx_i7_cfs_box_1_slot_2_color') | replace('#', '') | lower %}{% set ns = namespace(id='') %}{% for e in integration_entities('spoolman') %}{% if e.endswith('_color_hex') and (states(e) | replace('#', '') | lower) == color %}{% set b = e[:-10] %}{% if (states(b) | float(0)) > 0 and ns.id == '' %}{% set ns.id = states(b ~ '_id') %}{% endif %}{% endif %}{% endfor %}{{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'entity_picture') if ns.id and state_attr('sensor.spoolman_spool_' ~ ns.id, 'entity_picture') else '' }}",
- "primary": "{% set color = states('sensor.sparkx_i7_cfs_box_1_slot_2_color') | replace('#', '') | lower %}{% set ns = namespace(id='') %}{% for e in integration_entities('spoolman') %}{% if e.endswith('_color_hex') and (states(e) | replace('#', '') | lower) == color %}{% set b = e[:-10] %}{% if (states(b) | float(0)) > 0 and ns.id == '' %}{% set ns.id = states(b ~ '_id') %}{% endif %}{% endif %}{% endfor %}{% if ns.id %}Spool {{ ns.id }} · {{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'filament_name') | default('?', true) }} · {{ (states('sensor.spoolman_spool_' ~ ns.id) | float(0)) | round(1) }} g left{% elif color in ['', 'unknown', 'unavailable'] %}Slot color unavailable{% else %}No spool with stock matches this color{% endif %}",
- "secondary": "{% set color = states('sensor.sparkx_i7_cfs_box_1_slot_2_color') | replace('#', '') | lower %}{% set ns = namespace(id='') %}{% for e in integration_entities('spoolman') %}{% if e.endswith('_color_hex') and (states(e) | replace('#', '') | lower) == color %}{% set b = e[:-10] %}{% if (states(b) | float(0)) > 0 and ns.id == '' %}{% set ns.id = states(b ~ '_id') %}{% endif %}{% endif %}{% endfor %}{% if ns.id %}• {{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'filament_vendor_name') | default('?', true) }} · {{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'filament_material') | default('?', true) }} · #{{ color | upper }}\n• Remaining: {{ (states('sensor.spoolman_spool_' ~ ns.id) | float(0)) | round(1) }} g · used {{ (state_attr('sensor.spoolman_spool_' ~ ns.id, 'used_weight') | float(0)) | round(1) }} g ({{ (state_attr('sensor.spoolman_spool_' ~ ns.id, 'used_percentage') | float(0)) | round(1) }}%)\n• Remaining length: {{ ((state_attr('sensor.spoolman_spool_' ~ ns.id, 'remaining_length') | float(0)) / 1000) | round(1) }} m · used {{ ((state_attr('sensor.spoolman_spool_' ~ ns.id, 'used_length') | float(0)) / 1000) | round(1) }} m\n• Spool: Ø{{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'filament_diameter') | default('?', true) }} mm · {{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'filament_density') | default('?', true) }} g/cm³ · {{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'filament_weight') | default('?', true) }} g · art. {{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'filament_article_number') | default('?', true) }}\n• Temps: bed {{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'filament_settings_bed_temp') | default('?', true) }}°C · hotend {{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'filament_settings_extruder_temp') | default('?', true) }}°C\n• Flow: {{ states('sensor.spoolman_spool_' ~ ns.id ~ '_flow_rate') }} · Runout est.: {{ states('sensor.spoolman_spool_' ~ ns.id ~ '_estimated_runout') }}\n• Registered: {{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'registered') | default('?', true) }} · Location: {{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'location') | default('?', true) }} · Price: {{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'filament_price') | default('?', true) }}{% elif color in ['', 'unknown', 'unavailable'] %}• Slot color unavailable{% else %}• No spool with stock matches this color{% endif %}",
+ "picture": "{% set color = states('sensor.sparkx_i7_cfs_box_1_slot_2_color') | replace('#', '') | lower %}{% set ns = namespace(id='') %}{% for e in integration_entities('spoolman') %}{% if e.endswith('_color_hex') and (states(e) | replace('#', '') | lower) == color and (state_attr(e[:-10], 'location') | default('', true) | lower) == 'cfs lite' %}{% set b = e[:-10] %}{% if (states(b) | float(0)) > 0 and ns.id == '' %}{% set ns.id = states(b ~ '_id') %}{% endif %}{% endif %}{% endfor %}{{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'entity_picture') if ns.id and state_attr('sensor.spoolman_spool_' ~ ns.id, 'entity_picture') else '' }}",
+ "primary": "{% set color = states('sensor.sparkx_i7_cfs_box_1_slot_2_color') | replace('#', '') | lower %}{% set ns = namespace(id='') %}{% for e in integration_entities('spoolman') %}{% if e.endswith('_color_hex') and (states(e) | replace('#', '') | lower) == color and (state_attr(e[:-10], 'location') | default('', true) | lower) == 'cfs lite' %}{% set b = e[:-10] %}{% if (states(b) | float(0)) > 0 and ns.id == '' %}{% set ns.id = states(b ~ '_id') %}{% endif %}{% endif %}{% endfor %}{% if ns.id %}Spool {{ ns.id }} · {{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'filament_name') | default('?', true) }} · {{ (states('sensor.spoolman_spool_' ~ ns.id) | float(0)) | round(1) }} g left{% elif color in ['', 'unknown', 'unavailable'] %}Slot color unavailable{% else %}No spool with stock matches this color{% endif %}",
+ "secondary": "{% set color = states('sensor.sparkx_i7_cfs_box_1_slot_2_color') | replace('#', '') | lower %}{% set ns = namespace(id='') %}{% for e in integration_entities('spoolman') %}{% if e.endswith('_color_hex') and (states(e) | replace('#', '') | lower) == color and (state_attr(e[:-10], 'location') | default('', true) | lower) == 'cfs lite' %}{% set b = e[:-10] %}{% if (states(b) | float(0)) > 0 and ns.id == '' %}{% set ns.id = states(b ~ '_id') %}{% endif %}{% endif %}{% endfor %}{% if ns.id %}• {{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'filament_vendor_name') | default('?', true) }} · {{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'filament_material') | default('?', true) }} · #{{ color | upper }}\n• Remaining: {{ (states('sensor.spoolman_spool_' ~ ns.id) | float(0)) | round(1) }} g · used {{ (state_attr('sensor.spoolman_spool_' ~ ns.id, 'used_weight') | float(0)) | round(1) }} g ({{ (state_attr('sensor.spoolman_spool_' ~ ns.id, 'used_percentage') | float(0)) | round(1) }}%)\n• Remaining length: {{ ((state_attr('sensor.spoolman_spool_' ~ ns.id, 'remaining_length') | float(0)) / 1000) | round(1) }} m · used {{ ((state_attr('sensor.spoolman_spool_' ~ ns.id, 'used_length') | float(0)) / 1000) | round(1) }} m\n• Spool: Ø{{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'filament_diameter') | default('?', true) }} mm · {{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'filament_density') | default('?', true) }} g/cm³ · {{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'filament_weight') | default('?', true) }} g · art. {{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'filament_article_number') | default('?', true) }}\n• Temps: bed {{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'filament_settings_bed_temp') | default('?', true) }}°C · hotend {{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'filament_settings_extruder_temp') | default('?', true) }}°C\n• Flow: {{ states('sensor.spoolman_spool_' ~ ns.id ~ '_flow_rate') }} · Runout est.: {{ states('sensor.spoolman_spool_' ~ ns.id ~ '_estimated_runout') }}\n• Registered: {{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'registered') | default('?', true) }} · Location: {{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'location') | default('?', true) }} · Price: {{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'filament_price') | default('?', true) }}{% elif color in ['', 'unknown', 'unavailable'] %}• Slot color unavailable{% else %}• No spool with stock matches this color{% endif %}",
"multiline_secondary": true,
"grid_options": {
"columns": "full"
@@ -1085,9 +1085,9 @@
"name": "Slot 3",
"icon": "mdi:spool",
"icon_color": "{% set c = states('sensor.sparkx_i7_cfs_box_1_slot_3_color') | replace('#', '') | lower %}{% if c | length == 6 %}#{{ c }}{% else %}var(--primary-color){% endif %}",
- "picture": "{% set color = states('sensor.sparkx_i7_cfs_box_1_slot_3_color') | replace('#', '') | lower %}{% set ns = namespace(id='') %}{% for e in integration_entities('spoolman') %}{% if e.endswith('_color_hex') and (states(e) | replace('#', '') | lower) == color %}{% set b = e[:-10] %}{% if (states(b) | float(0)) > 0 and ns.id == '' %}{% set ns.id = states(b ~ '_id') %}{% endif %}{% endif %}{% endfor %}{{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'entity_picture') if ns.id and state_attr('sensor.spoolman_spool_' ~ ns.id, 'entity_picture') else '' }}",
- "primary": "{% set color = states('sensor.sparkx_i7_cfs_box_1_slot_3_color') | replace('#', '') | lower %}{% set ns = namespace(id='') %}{% for e in integration_entities('spoolman') %}{% if e.endswith('_color_hex') and (states(e) | replace('#', '') | lower) == color %}{% set b = e[:-10] %}{% if (states(b) | float(0)) > 0 and ns.id == '' %}{% set ns.id = states(b ~ '_id') %}{% endif %}{% endif %}{% endfor %}{% if ns.id %}Spool {{ ns.id }} · {{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'filament_name') | default('?', true) }} · {{ (states('sensor.spoolman_spool_' ~ ns.id) | float(0)) | round(1) }} g left{% elif color in ['', 'unknown', 'unavailable'] %}Slot color unavailable{% else %}No spool with stock matches this color{% endif %}",
- "secondary": "{% set color = states('sensor.sparkx_i7_cfs_box_1_slot_3_color') | replace('#', '') | lower %}{% set ns = namespace(id='') %}{% for e in integration_entities('spoolman') %}{% if e.endswith('_color_hex') and (states(e) | replace('#', '') | lower) == color %}{% set b = e[:-10] %}{% if (states(b) | float(0)) > 0 and ns.id == '' %}{% set ns.id = states(b ~ '_id') %}{% endif %}{% endif %}{% endfor %}{% if ns.id %}• {{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'filament_vendor_name') | default('?', true) }} · {{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'filament_material') | default('?', true) }} · #{{ color | upper }}\n• Remaining: {{ (states('sensor.spoolman_spool_' ~ ns.id) | float(0)) | round(1) }} g · used {{ (state_attr('sensor.spoolman_spool_' ~ ns.id, 'used_weight') | float(0)) | round(1) }} g ({{ (state_attr('sensor.spoolman_spool_' ~ ns.id, 'used_percentage') | float(0)) | round(1) }}%)\n• Remaining length: {{ ((state_attr('sensor.spoolman_spool_' ~ ns.id, 'remaining_length') | float(0)) / 1000) | round(1) }} m · used {{ ((state_attr('sensor.spoolman_spool_' ~ ns.id, 'used_length') | float(0)) / 1000) | round(1) }} m\n• Spool: Ø{{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'filament_diameter') | default('?', true) }} mm · {{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'filament_density') | default('?', true) }} g/cm³ · {{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'filament_weight') | default('?', true) }} g · art. {{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'filament_article_number') | default('?', true) }}\n• Temps: bed {{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'filament_settings_bed_temp') | default('?', true) }}°C · hotend {{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'filament_settings_extruder_temp') | default('?', true) }}°C\n• Flow: {{ states('sensor.spoolman_spool_' ~ ns.id ~ '_flow_rate') }} · Runout est.: {{ states('sensor.spoolman_spool_' ~ ns.id ~ '_estimated_runout') }}\n• Registered: {{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'registered') | default('?', true) }} · Location: {{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'location') | default('?', true) }} · Price: {{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'filament_price') | default('?', true) }}{% elif color in ['', 'unknown', 'unavailable'] %}• Slot color unavailable{% else %}• No spool with stock matches this color{% endif %}",
+ "picture": "{% set color = states('sensor.sparkx_i7_cfs_box_1_slot_3_color') | replace('#', '') | lower %}{% set ns = namespace(id='') %}{% for e in integration_entities('spoolman') %}{% if e.endswith('_color_hex') and (states(e) | replace('#', '') | lower) == color and (state_attr(e[:-10], 'location') | default('', true) | lower) == 'cfs lite' %}{% set b = e[:-10] %}{% if (states(b) | float(0)) > 0 and ns.id == '' %}{% set ns.id = states(b ~ '_id') %}{% endif %}{% endif %}{% endfor %}{{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'entity_picture') if ns.id and state_attr('sensor.spoolman_spool_' ~ ns.id, 'entity_picture') else '' }}",
+ "primary": "{% set color = states('sensor.sparkx_i7_cfs_box_1_slot_3_color') | replace('#', '') | lower %}{% set ns = namespace(id='') %}{% for e in integration_entities('spoolman') %}{% if e.endswith('_color_hex') and (states(e) | replace('#', '') | lower) == color and (state_attr(e[:-10], 'location') | default('', true) | lower) == 'cfs lite' %}{% set b = e[:-10] %}{% if (states(b) | float(0)) > 0 and ns.id == '' %}{% set ns.id = states(b ~ '_id') %}{% endif %}{% endif %}{% endfor %}{% if ns.id %}Spool {{ ns.id }} · {{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'filament_name') | default('?', true) }} · {{ (states('sensor.spoolman_spool_' ~ ns.id) | float(0)) | round(1) }} g left{% elif color in ['', 'unknown', 'unavailable'] %}Slot color unavailable{% else %}No spool with stock matches this color{% endif %}",
+ "secondary": "{% set color = states('sensor.sparkx_i7_cfs_box_1_slot_3_color') | replace('#', '') | lower %}{% set ns = namespace(id='') %}{% for e in integration_entities('spoolman') %}{% if e.endswith('_color_hex') and (states(e) | replace('#', '') | lower) == color and (state_attr(e[:-10], 'location') | default('', true) | lower) == 'cfs lite' %}{% set b = e[:-10] %}{% if (states(b) | float(0)) > 0 and ns.id == '' %}{% set ns.id = states(b ~ '_id') %}{% endif %}{% endif %}{% endfor %}{% if ns.id %}• {{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'filament_vendor_name') | default('?', true) }} · {{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'filament_material') | default('?', true) }} · #{{ color | upper }}\n• Remaining: {{ (states('sensor.spoolman_spool_' ~ ns.id) | float(0)) | round(1) }} g · used {{ (state_attr('sensor.spoolman_spool_' ~ ns.id, 'used_weight') | float(0)) | round(1) }} g ({{ (state_attr('sensor.spoolman_spool_' ~ ns.id, 'used_percentage') | float(0)) | round(1) }}%)\n• Remaining length: {{ ((state_attr('sensor.spoolman_spool_' ~ ns.id, 'remaining_length') | float(0)) / 1000) | round(1) }} m · used {{ ((state_attr('sensor.spoolman_spool_' ~ ns.id, 'used_length') | float(0)) / 1000) | round(1) }} m\n• Spool: Ø{{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'filament_diameter') | default('?', true) }} mm · {{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'filament_density') | default('?', true) }} g/cm³ · {{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'filament_weight') | default('?', true) }} g · art. {{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'filament_article_number') | default('?', true) }}\n• Temps: bed {{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'filament_settings_bed_temp') | default('?', true) }}°C · hotend {{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'filament_settings_extruder_temp') | default('?', true) }}°C\n• Flow: {{ states('sensor.spoolman_spool_' ~ ns.id ~ '_flow_rate') }} · Runout est.: {{ states('sensor.spoolman_spool_' ~ ns.id ~ '_estimated_runout') }}\n• Registered: {{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'registered') | default('?', true) }} · Location: {{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'location') | default('?', true) }} · Price: {{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'filament_price') | default('?', true) }}{% elif color in ['', 'unknown', 'unavailable'] %}• Slot color unavailable{% else %}• No spool with stock matches this color{% endif %}",
"multiline_secondary": true,
"grid_options": {
"columns": "full"
@@ -1099,9 +1099,9 @@
"name": "Slot 4",
"icon": "mdi:spool",
"icon_color": "{% set c = states('sensor.sparkx_i7_cfs_box_1_slot_4_color') | replace('#', '') | lower %}{% if c | length == 6 %}#{{ c }}{% else %}var(--primary-color){% endif %}",
- "picture": "{% set color = states('sensor.sparkx_i7_cfs_box_1_slot_4_color') | replace('#', '') | lower %}{% set ns = namespace(id='') %}{% for e in integration_entities('spoolman') %}{% if e.endswith('_color_hex') and (states(e) | replace('#', '') | lower) == color %}{% set b = e[:-10] %}{% if (states(b) | float(0)) > 0 and ns.id == '' %}{% set ns.id = states(b ~ '_id') %}{% endif %}{% endif %}{% endfor %}{{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'entity_picture') if ns.id and state_attr('sensor.spoolman_spool_' ~ ns.id, 'entity_picture') else '' }}",
- "primary": "{% set color = states('sensor.sparkx_i7_cfs_box_1_slot_4_color') | replace('#', '') | lower %}{% set ns = namespace(id='') %}{% for e in integration_entities('spoolman') %}{% if e.endswith('_color_hex') and (states(e) | replace('#', '') | lower) == color %}{% set b = e[:-10] %}{% if (states(b) | float(0)) > 0 and ns.id == '' %}{% set ns.id = states(b ~ '_id') %}{% endif %}{% endif %}{% endfor %}{% if ns.id %}Spool {{ ns.id }} · {{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'filament_name') | default('?', true) }} · {{ (states('sensor.spoolman_spool_' ~ ns.id) | float(0)) | round(1) }} g left{% elif color in ['', 'unknown', 'unavailable'] %}Slot color unavailable{% else %}No spool with stock matches this color{% endif %}",
- "secondary": "{% set color = states('sensor.sparkx_i7_cfs_box_1_slot_4_color') | replace('#', '') | lower %}{% set ns = namespace(id='') %}{% for e in integration_entities('spoolman') %}{% if e.endswith('_color_hex') and (states(e) | replace('#', '') | lower) == color %}{% set b = e[:-10] %}{% if (states(b) | float(0)) > 0 and ns.id == '' %}{% set ns.id = states(b ~ '_id') %}{% endif %}{% endif %}{% endfor %}{% if ns.id %}• {{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'filament_vendor_name') | default('?', true) }} · {{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'filament_material') | default('?', true) }} · #{{ color | upper }}\n• Remaining: {{ (states('sensor.spoolman_spool_' ~ ns.id) | float(0)) | round(1) }} g · used {{ (state_attr('sensor.spoolman_spool_' ~ ns.id, 'used_weight') | float(0)) | round(1) }} g ({{ (state_attr('sensor.spoolman_spool_' ~ ns.id, 'used_percentage') | float(0)) | round(1) }}%)\n• Remaining length: {{ ((state_attr('sensor.spoolman_spool_' ~ ns.id, 'remaining_length') | float(0)) / 1000) | round(1) }} m · used {{ ((state_attr('sensor.spoolman_spool_' ~ ns.id, 'used_length') | float(0)) / 1000) | round(1) }} m\n• Spool: Ø{{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'filament_diameter') | default('?', true) }} mm · {{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'filament_density') | default('?', true) }} g/cm³ · {{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'filament_weight') | default('?', true) }} g · art. {{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'filament_article_number') | default('?', true) }}\n• Temps: bed {{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'filament_settings_bed_temp') | default('?', true) }}°C · hotend {{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'filament_settings_extruder_temp') | default('?', true) }}°C\n• Flow: {{ states('sensor.spoolman_spool_' ~ ns.id ~ '_flow_rate') }} · Runout est.: {{ states('sensor.spoolman_spool_' ~ ns.id ~ '_estimated_runout') }}\n• Registered: {{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'registered') | default('?', true) }} · Location: {{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'location') | default('?', true) }} · Price: {{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'filament_price') | default('?', true) }}{% elif color in ['', 'unknown', 'unavailable'] %}• Slot color unavailable{% else %}• No spool with stock matches this color{% endif %}",
+ "picture": "{% set color = states('sensor.sparkx_i7_cfs_box_1_slot_4_color') | replace('#', '') | lower %}{% set ns = namespace(id='') %}{% for e in integration_entities('spoolman') %}{% if e.endswith('_color_hex') and (states(e) | replace('#', '') | lower) == color and (state_attr(e[:-10], 'location') | default('', true) | lower) == 'cfs lite' %}{% set b = e[:-10] %}{% if (states(b) | float(0)) > 0 and ns.id == '' %}{% set ns.id = states(b ~ '_id') %}{% endif %}{% endif %}{% endfor %}{{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'entity_picture') if ns.id and state_attr('sensor.spoolman_spool_' ~ ns.id, 'entity_picture') else '' }}",
+ "primary": "{% set color = states('sensor.sparkx_i7_cfs_box_1_slot_4_color') | replace('#', '') | lower %}{% set ns = namespace(id='') %}{% for e in integration_entities('spoolman') %}{% if e.endswith('_color_hex') and (states(e) | replace('#', '') | lower) == color and (state_attr(e[:-10], 'location') | default('', true) | lower) == 'cfs lite' %}{% set b = e[:-10] %}{% if (states(b) | float(0)) > 0 and ns.id == '' %}{% set ns.id = states(b ~ '_id') %}{% endif %}{% endif %}{% endfor %}{% if ns.id %}Spool {{ ns.id }} · {{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'filament_name') | default('?', true) }} · {{ (states('sensor.spoolman_spool_' ~ ns.id) | float(0)) | round(1) }} g left{% elif color in ['', 'unknown', 'unavailable'] %}Slot color unavailable{% else %}No spool with stock matches this color{% endif %}",
+ "secondary": "{% set color = states('sensor.sparkx_i7_cfs_box_1_slot_4_color') | replace('#', '') | lower %}{% set ns = namespace(id='') %}{% for e in integration_entities('spoolman') %}{% if e.endswith('_color_hex') and (states(e) | replace('#', '') | lower) == color and (state_attr(e[:-10], 'location') | default('', true) | lower) == 'cfs lite' %}{% set b = e[:-10] %}{% if (states(b) | float(0)) > 0 and ns.id == '' %}{% set ns.id = states(b ~ '_id') %}{% endif %}{% endif %}{% endfor %}{% if ns.id %}• {{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'filament_vendor_name') | default('?', true) }} · {{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'filament_material') | default('?', true) }} · #{{ color | upper }}\n• Remaining: {{ (states('sensor.spoolman_spool_' ~ ns.id) | float(0)) | round(1) }} g · used {{ (state_attr('sensor.spoolman_spool_' ~ ns.id, 'used_weight') | float(0)) | round(1) }} g ({{ (state_attr('sensor.spoolman_spool_' ~ ns.id, 'used_percentage') | float(0)) | round(1) }}%)\n• Remaining length: {{ ((state_attr('sensor.spoolman_spool_' ~ ns.id, 'remaining_length') | float(0)) / 1000) | round(1) }} m · used {{ ((state_attr('sensor.spoolman_spool_' ~ ns.id, 'used_length') | float(0)) / 1000) | round(1) }} m\n• Spool: Ø{{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'filament_diameter') | default('?', true) }} mm · {{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'filament_density') | default('?', true) }} g/cm³ · {{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'filament_weight') | default('?', true) }} g · art. {{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'filament_article_number') | default('?', true) }}\n• Temps: bed {{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'filament_settings_bed_temp') | default('?', true) }}°C · hotend {{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'filament_settings_extruder_temp') | default('?', true) }}°C\n• Flow: {{ states('sensor.spoolman_spool_' ~ ns.id ~ '_flow_rate') }} · Runout est.: {{ states('sensor.spoolman_spool_' ~ ns.id ~ '_estimated_runout') }}\n• Registered: {{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'registered') | default('?', true) }} · Location: {{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'location') | default('?', true) }} · Price: {{ state_attr('sensor.spoolman_spool_' ~ ns.id, 'filament_price') | default('?', true) }}{% elif color in ['', 'unknown', 'unavailable'] %}• Slot color unavailable{% else %}• No spool with stock matches this color{% endif %}",
"multiline_secondary": true,
"grid_options": {
"columns": "full"
diff --git a/.storage/lovelace.spoolman_ui b/.storage/lovelace.spoolman_ui
index c0f8c4d9..854a58bf 100644
--- a/.storage/lovelace.spoolman_ui
+++ b/.storage/lovelace.spoolman_ui
@@ -11,9 +11,14 @@
"type": "panel",
"cards": [
{
- "type": "iframe",
- "url": "http://192.168.1.140:7912",
- "aspect_ratio": "100%"
+ "type": "button",
+ "tap_action": {
+ "action": "url",
+ "url_path": "http://192.168.1.140:7912"
+ },
+ "icon": "mdi:printer-3d-nozzle",
+ "name": "Open Spoolman",
+ "show_name": true
}
]
}
diff --git a/zigbee2mqtt/state.json b/zigbee2mqtt/state.json
index 9fbbf607..08968f02 100644
--- a/zigbee2mqtt/state.json
+++ b/zigbee2mqtt/state.json
@@ -1,13 +1,13 @@
{
"0xffffb40e0607ace4": {
- "energy": 23.33,
+ "energy": 23.34,
"state": "ON",
"led_brightness": 100,
"countdown_to_turn_off": 0,
- "voltage": 119.5,
+ "voltage": 119.7,
"countdown_to_turn_on": 0,
"ac_frequency": 60,
- "power_factor": 0.14,
+ "power_factor": 0.43,
"update": {
"state": "idle",
"installed_version": 268513381,
@@ -15,9 +15,9 @@
"latest_source": "https://raw.githubusercontent.com/Koenkk/zigbee-OTA/master/images/ThirdReality/SmartPlug_Zigbee_PROD_OTA_V101_1.01.01.ota",
"latest_release_notes": null
},
- "power": 0.4,
+ "power": 3.9,
"linkquality": 149,
- "current": 0.03,
+ "current": 0.07,
"power_on_behavior": "on"
},
"0xffffb40e0607af27": {
@@ -27,8 +27,8 @@
"led_brightness": 100,
"countdown_to_turn_off": 0,
"countdown_to_turn_on": 0,
- "power": 2,
- "current": 0.09,
+ "power": 2.2,
+ "current": 0.1,
"energy": 54.08,
"power_factor": 0.18,
"update": {
@@ -45,7 +45,7 @@
"state": "ON",
"led_brightness": 100,
"countdown_to_turn_off": 0,
- "voltage": 119.1,
+ "voltage": 119.6,
"countdown_to_turn_on": 0,
"energy": 103.89,
"power_factor": 0.2,
@@ -74,13 +74,13 @@
"led_brightness": 100,
"countdown_to_turn_off": 0,
"countdown_to_turn_on": 0,
- "voltage": 118.1,
+ "voltage": 117.6,
"state": "ON",
"ac_frequency": 60,
- "energy": 211.04,
- "power": 102.2,
+ "energy": 211.05,
+ "power": 100.2,
"current": 0.92,
- "power_factor": 0.94,
+ "power_factor": 0.95,
"update": {
"state": "idle",
"installed_version": 268513381,
@@ -95,13 +95,13 @@
"led_brightness": 100,
"countdown_to_turn_off": 0,
"countdown_to_turn_on": 0,
- "voltage": 119.6,
+ "voltage": 120,
"energy": 100.77,
"state": "ON",
- "power": 11.4,
- "current": 0.25,
+ "power": 23.5,
+ "current": 0.37,
"ac_frequency": 60,
- "power_factor": 0.5,
+ "power_factor": 0.58,
"update": {
"state": "idle",
"installed_version": 268513381,
@@ -114,7 +114,7 @@
},
"0xffffb40e060895b3": {
"state": "ON",
- "voltage": 119.8,
+ "voltage": 121.2,
"ac_frequency": 60,
"energy": 14.23,
"current": 0.01,
@@ -136,7 +136,7 @@
"0xffffb40e0608864e": {
"led_brightness": 100,
"countdown_to_turn_off": 0,
- "voltage": 119.8,
+ "voltage": 115.9,
"energy": 34.53,
"countdown_to_turn_on": 0,
"state": "ON",