This commit is contained in:
Home Assistant Version Control
2026-10-15 13:23:24 +00:00
parent c181946323
commit c85606c96e
3 changed files with 368 additions and 83 deletions
@@ -0,0 +1,171 @@
# ha_mcp_backup
schema_version: 1
domain: automation
entity_id: '1791477238729'
captured: '2026-10-15T13:23:17.499559+00:00'
tool: ha_config_set_automation
config:
id: '1791477238729'
alias: SparkX i7 - Deduct filament in Spoolman on print complete
description: On print completion, deducts the final segment (used_material_length
delta since last checkpoint x g/cm) from the Spoolman spool in the CFS Lite location
matching the latched slot color (remaining weight > 0 guard), accumulates it per
slot, then sends a summary notification with total and per-slot breakdown whenever
anything was deducted. Silent when total is 0. Clears the latch and re-baselines
the checkpoint.
triggers:
- trigger: state
entity_id: sensor.sparkx_i7_print_status
from: printing
to: completed
id: complete
- trigger: state
entity_id: sensor.sparkx_i7_print_status
to: stopped
id: stopped
- trigger: state
entity_id: sensor.sparkx_i7_print_status
to: error
id: error
conditions:
- condition: template
value_template: '{{ trigger.id == ''complete'' or states(''input_text.sparkx_i7_print_spool_latch'')
not in ['''', ''unknown'', ''unavailable''] }}'
actions:
- variables:
old_slot: '{{ states(''input_text.sparkx_i7_print_spool_latch'') }}'
cur: '{{ states(''sensor.sparkx_i7_used_material_length'') | float(0) }}'
checkpoint: '{{ states(''input_number.sparkx_i7_spoolman_length_checkpoint'')
| float(0) }}'
outcome: '{% set tid = trigger.id | default(''complete'') %}{{ ''cancelled''
if tid == ''stopped'' else (''error'' if tid == ''error'' else ''complete'')
}}'
- variables:
final_grams: '{{ (([cur | float - (checkpoint | float), 0] | max) * (states(''input_number.sparkx_i7_filament_g_cm'')
| float(0.03))) | round(2) }}'
color: '{{ states(''sensor.sparkx_i7_cfs_'' ~ (old_slot | lower | replace(''
'', ''_'')) ~ ''_color'') | replace(''#'', '''') | lower }}'
- variables:
spool_id: '{% set ns = namespace(id='''') %}{% for e in integration_entities(''spoolman'')
%}{% if e.endswith(''_color_hex'') and (state_attr(e[:-10], ''location'')
| default('''', true) | lower) == (''cfs lite '' ~ old_slot.split(''_'')[-1])
%}{% set b = e[:-10] %}{% if (states(b) | float(0)) > 0 and ns.id == ''''
%}{% set ns.id = states(b ~ ''_id'') %}{% endif %}{% endif %}{% endfor %}{{
ns.id }}'
- variables:
helper_idx: '{{ old_slot.split(''_'')[-1] if old_slot.split(''_'')[-1] in [''1'',
''2'', ''3'', ''4''] else '''' }}'
- variables:
nonhelper_g: '{{ final_grams if (final_grams | float > 0) and (spool_id not
in ['''', ''unknown'', ''unavailable'']) and (helper_idx == '''') else 0 }}'
- if:
condition: template
value_template: '{{ final_grams | float > 0 }}'
then:
- choose:
- conditions:
condition: template
value_template: '{{ spool_id not in ['''', ''unknown'', ''unavailable'']
}}'
sequence:
- action: spoolman.use_spool_filament
data:
id: '{{ spool_id | int(0) }}'
use_weight: '{{ final_grams | float(0) }}'
- if:
condition: template
value_template: '{{ helper_idx != '''' }}'
then:
- action: input_number.set_value
target:
entity_id: input_number.sparkx_i7_slot_{{ helper_idx }}_grams
data:
value: '{{ (states(''input_number.sparkx_i7_slot_'' ~ helper_idx ~ ''_grams'')
| float(0)) + (final_grams | float) }}'
default:
- action: notify.persistent_notification
data:
title: 'Spoolman: no spool for slot color'
message: 'Print {{ outcome }}: final segment of {{ final_grams }} g from
{{ old_slot if old_slot else ''the active slot'' }} (color #{{ color |
upper }}) could not be deducted - no Spoolman spool in the CFS Lite location
with remaining weight matches that color. Register the new roll in Spoolman
with location CFS Lite, then adjust manually if needed.'
- action: notify.mobile_app_francos_ipad
data:
title: 'Spoolman: no spool for slot color'
message: 'Print {{ outcome }}: final segment of {{ final_grams }} g from
{{ old_slot if old_slot else ''the active slot'' }} (color #{{ color |
upper }}) could not be deducted - no Spoolman spool in the CFS Lite location
with remaining weight matches that color. Register the new roll in Spoolman
with location CFS Lite, then adjust manually if needed.'
- action: notify.mobile_app_sm_f956w
data:
title: 'Spoolman: no spool for slot color'
message: 'Print {{ outcome }}: final segment of {{ final_grams }} g from
{{ old_slot if old_slot else ''the active slot'' }} (color #{{ color |
upper }}) could not be deducted - no Spoolman spool in the CFS Lite location
with remaining weight matches that color. Register the new roll in Spoolman
with location CFS Lite, then adjust manually if needed.'
- variables:
summary_total: '{% set ns = namespace(t = 0) %}{% for n in [''1'', ''2'', ''3'',
''4''] %}{% set g = states(''input_number.sparkx_i7_slot_'' ~ n ~ ''_grams'')
| float(0) %}{% if g > 0 %}{% set ns.t = ns.t + g %}{% endif %}{% endfor %}{{
(ns.t + (nonhelper_g | float)) | round(1) }}'
- variables:
summary_lines: '{% set ns = namespace(l = []) %}{% for n in [''1'', ''2'', ''3'',
''4''] %}{% set g = states(''input_number.sparkx_i7_slot_'' ~ n ~ ''_grams'')
| float(0) %}{% if g > 0 %}{% set ns.l = ns.l + [''Slot '' ~ n ~ '' ('' ~
states(''sensor.sparkx_i7_slot_'' ~ n ~ ''_color_name'') ~ ''): '' ~ (g |
round(1)) ~ '' g''] %}{% endif %}{% endfor %}{% if nonhelper_g | float > 0
%}{% set ns.l = ns.l + [(old_slot if old_slot else ''Unlatched'') ~ '': ''
~ (nonhelper_g | float | round(1)) ~ '' g''] %}{% endif %}{{ ns.l | join(''\n'')
}}'
- if:
condition: template
value_template: '{{ summary_total | float > 0 }}'
then:
- action: notify.persistent_notification
data:
title: Print {{ outcome }} - Spoolman updated
message: 'Print {{ outcome }} - Spoolman deducted {{ summary_total }} g
{{ summary_lines }}'
- action: notify.mobile_app_francos_ipad
data:
title: Print {{ outcome }} - Spoolman updated
message: 'Print {{ outcome }} - Spoolman deducted {{ summary_total }} g
{{ summary_lines }}'
- action: notify.mobile_app_sm_f956w
data:
title: Print {{ outcome }} - Spoolman updated
message: 'Print {{ outcome }} - Spoolman deducted {{ summary_total }} g
{{ summary_lines }}'
- if:
condition: template
value_template: '{{ trigger.id == ''complete'' }}'
then:
- action: input_number.set_value
target:
entity_id: input_number.sparkx_i7_last_job_filament_weight
data:
value: '{{ summary_total }}'
- action: input_number.set_value
target:
entity_id: input_number.sparkx_i7_last_job_cost
data:
value: '{{ ((summary_total | float) * (states(''input_number.filament_price_per_kg'')
| float(25)) / 1000) | round(2) }}'
- action: input_number.set_value
target:
entity_id: input_number.sparkx_i7_spoolman_length_checkpoint
data:
value: '{{ cur }}'
- action: input_text.set_value
target:
entity_id: input_text.sparkx_i7_print_spool_latch
data:
value: ''
mode: single
+1
View File
@@ -4563,3 +4563,4 @@
{"timestamp": "2026-10-15T13:22:39.599656+00:00", "tool_name": "ha_config_get_script", "parameters": {"script_id": "spoolman_set_spool_remaining"}, "execution_time_ms": 108.43968391418457, "success": true, "error_message": null, "response_size_bytes": 2239, "user_context": null}
{"timestamp": "2026-10-15T13:22:39.822007+00:00", "tool_name": "ha_config_get_automation", "parameters": {"identifier": "1791477238762"}, "execution_time_ms": 334.63048934936523, "success": true, "error_message": null, "response_size_bytes": 5649, "user_context": null}
{"timestamp": "2026-10-15T13:22:39.905414+00:00", "tool_name": "ha_config_get_automation", "parameters": {"identifier": "1791477238799"}, "execution_time_ms": 413.3596420288086, "success": true, "error_message": null, "response_size_bytes": 7574, "user_context": null}
{"timestamp": "2026-10-15T13:23:18.159012+00:00", "tool_name": "ha_config_set_automation", "parameters": {"config": null, "identifier": "1791477238729", "python_transform": "_repl = [(\"matching the latched slot color\", \"matching the latched slot's CFS Lite location\"), (\"Spoolman: no spool for slot color\", \"Spoolman: no spool for the latched slot\"), (\"no Spoolman spool in the CFS Lite location with remaining weight matches that color. Register the new roll in Spoolman with location CFS Lite, then adjust manually if needed.\", \"no Spoolman spool with remaining weight is in that slot's CFS Lite location. Register the new roll in Spoolman in that location, then adjust manually if needed.\")]\nstack = [config]\nfor _ in range(20000):\n if not stack:\n break\n node = stack.pop()\n if isinstance(node, dict):\n for k in list(node.keys()):\n v = node[k]\n if isinstance(v, str):\n for a, b in _repl:\n if a in v:\n v = v.replace(a, b)\n node[k] = v\n elif isinstance(v, (dict, list)):\n stack.append(v)\n elif isinstance(node, list):\n for i in range(len(node)):\n v = node[i]\n if isinstance(v, str):\n for a, b in _repl:\n if a in v:\n v = v.replace(a, b)\n node[i] = v\n elif isinstance(v, (dict, list)):\n stack.append(v)", "config_hash": "75d85b947ad8ec44", "take_control_of_blueprint": false, "category": null, "wait": true, "enabled": null, "run_actions": false, "MandatoryBPS": true, "BestPracticeKey": null}, "execution_time_ms": 622.8833198547363, "success": true, "error_message": null, "response_size_bytes": 83935, "user_context": null}
+196 -83
View File
@@ -4388,9 +4388,9 @@
alias: SparkX i7 - Deduct filament in Spoolman on print complete
description: On print completion, deducts the final segment (used_material_length
delta since last checkpoint x g/cm) from the Spoolman spool in the CFS Lite location
matching the latched slot color (remaining weight > 0 guard), accumulates it per
slot, then sends a summary notification with total and per-slot breakdown whenever
anything was deducted. Silent when total is 0. Clears the latch and re-baselines
matching the latched slot's CFS Lite location (remaining weight > 0 guard), accumulates
it per slot, then sends a summary notification with total and per-slot breakdown
whenever anything was deducted. Silent when total is 0. Clears the latch and re-baselines
the checkpoint.
triggers:
- trigger: state
@@ -4426,8 +4426,8 @@
'', ''_'')) ~ ''_color'') | replace(''#'', '''') | lower }}'
- variables:
spool_id: '{% set ns = namespace(id='''') %}{% for e in integration_entities(''spoolman'')
%}{% if e.endswith(''_color_hex'') and (state_attr(e[:-10], ''location'') |
default('''', true) | lower) == (''cfs lite '' ~ old_slot.split(''_'')[-1])
%}{% if e.endswith(''_color_hex'') and (state_attr(e[:-10], ''location'')
| default('''', true) | lower) == (''cfs lite '' ~ old_slot.split(''_'')[-1])
%}{% set b = e[:-10] %}{% if (states(b) | float(0)) > 0 and ns.id == ''''
%}{% set ns.id = states(b ~ ''_id'') %}{% endif %}{% endif %}{% endfor %}{{
ns.id }}'
@@ -4464,28 +4464,28 @@
default:
- action: notify.persistent_notification
data:
title: 'Spoolman: no spool for slot color'
title: 'Spoolman: no spool for the latched slot'
message: 'Print {{ outcome }}: final segment of {{ final_grams }} g from
{{ old_slot if old_slot else ''the active slot'' }} (color #{{ color |
upper }}) could not be deducted - no Spoolman spool in the CFS Lite location
with remaining weight matches that color. Register the new roll in Spoolman
with location CFS Lite, then adjust manually if needed.'
upper }}) could not be deducted - no Spoolman spool with remaining weight
is in that slot''s CFS Lite location. Register the new roll in Spoolman
in that location, then adjust manually if needed.'
- action: notify.mobile_app_francos_ipad
data:
title: 'Spoolman: no spool for slot color'
title: 'Spoolman: no spool for the latched slot'
message: 'Print {{ outcome }}: final segment of {{ final_grams }} g from
{{ old_slot if old_slot else ''the active slot'' }} (color #{{ color |
upper }}) could not be deducted - no Spoolman spool in the CFS Lite location
with remaining weight matches that color. Register the new roll in Spoolman
with location CFS Lite, then adjust manually if needed.'
upper }}) could not be deducted - no Spoolman spool with remaining weight
is in that slot''s CFS Lite location. Register the new roll in Spoolman
in that location, then adjust manually if needed.'
- action: notify.mobile_app_sm_f956w
data:
title: 'Spoolman: no spool for slot color'
title: 'Spoolman: no spool for the latched slot'
message: 'Print {{ outcome }}: final segment of {{ final_grams }} g from
{{ old_slot if old_slot else ''the active slot'' }} (color #{{ color |
upper }}) could not be deducted - no Spoolman spool in the CFS Lite location
with remaining weight matches that color. Register the new roll in Spoolman
with location CFS Lite, then adjust manually if needed.'
upper }}) could not be deducted - no Spoolman spool with remaining weight
is in that slot''s CFS Lite location. Register the new roll in Spoolman
in that location, then adjust manually if needed.'
- variables:
summary_total: '{% set ns = namespace(t = 0) %}{% for n in [''1'', ''2'', ''3'',
''4''] %}{% set g = states(''input_number.sparkx_i7_slot_'' ~ n ~ ''_grams'')
@@ -4615,8 +4615,8 @@
spool_id: '{% set ns = namespace(id='''') %}{% for e in integration_entities(''spoolman'')
%}{% if e.endswith(''_color_hex'') and (state_attr(e[:-10], ''location'')
| default('''', true) | lower) == (''cfs lite '' ~ old_slot.split(''_'')[-1])
%}{% set b = e[:-10] %}{% if (states(b) | float(0)) > 0 and ns.id ==
'''' %}{% set ns.id = states(b ~ ''_id'') %}{% endif %}{% endif %}{% endfor
%}{% set b = e[:-10] %}{% if (states(b) | float(0)) > 0 and ns.id == ''''
%}{% set ns.id = states(b ~ ''_id'') %}{% endif %}{% endif %}{% endfor
%}{{ ns.id }}'
- if:
condition: template
@@ -4772,106 +4772,219 @@
target:
entity_id: notify.franco
mode: single
- id: '1791477238799'
alias: SparkX i7 - Filament sufficiency check at print start
description: >-
When a print starts and stays printing for 45 s, reports how much filament the
job needs, how much has already been used and how much is left, then compares
description: When a print starts and stays printing for 45 s, reports how much filament
the job needs, how much has already been used and how much is left, then compares
the loaded CFS Lite spools against that. A single-colour job whose colour is in
a loaded slot is checked exactly against that slot's spool; otherwise the
slicer gives no per-colour figure, so each loaded spool is compared against the
whole job total. Always sends a notification.
a loaded slot is checked exactly against that slot's spool; otherwise the slicer
gives no per-colour figure, so each loaded spool is compared against the whole
job total. Always sends a notification.
triggers:
- trigger: state
entity_id: sensor.sparkx_i7_print_status
to: printing
for: '00:00:45'
for: 00:00:45
conditions: []
actions:
- variables:
gcm: "{{ states('input_number.sparkx_i7_filament_g_cm') | float(0.0298) }}"
length_cm: "{{ states('sensor.sparkx_i7_expected_material_length') | float(0) }}"
weight_g: "{{ states('sensor.sparkx_i7_expected_material_weight') | float(0) }}"
job_g: "{{ ((weight_g | float) if (weight_g | float) > 0 else (length_cm | float) * (gcm | float)) | round(1) }}"
used_len: "{{ states('sensor.sparkx_i7_used_material_length') | float(0) }}"
used_g: "{{ (((used_len | float) * (gcm | float)) | round(1)) }}"
gcode_file: "{{ state_attr('sensor.sparkx_i7_expected_material_length', 'gcode_file') | default('', true) }}"
gcm: '{{ states(''input_number.sparkx_i7_filament_g_cm'') | float(0.0298) }}'
length_cm: '{{ states(''sensor.sparkx_i7_expected_material_length'') | float(0)
}}'
weight_g: '{{ states(''sensor.sparkx_i7_expected_material_weight'') | float(0)
}}'
job_g: '{{ ((weight_g | float) if (weight_g | float) > 0 else (length_cm | float)
* (gcm | float)) | round(1) }}'
used_len: '{{ states(''sensor.sparkx_i7_used_material_length'') | float(0) }}'
used_g: '{{ (((used_len | float) * (gcm | float)) | round(1)) }}'
gcode_file: '{{ state_attr(''sensor.sparkx_i7_expected_material_length'', ''gcode_file'')
| default('''', true) }}'
- variables:
report: |-
{% set cols = namespace(list=[]) %}
{% for n in ['1','2','3','4'] %}{% set cc = states('sensor.sparkx_i7_cfs_box_1_slot_' ~ n ~ '_color') | replace('#','') | lower %}{% if cc not in ['','none','unknown','unavailable'] %}{% set cols.list = cols.list + [cc] %}{% endif %}{% endfor %}
report: '{% set cols = namespace(list=[]) %}
{% for n in [''1'',''2'',''3'',''4''] %}{% set cc = states(''sensor.sparkx_i7_cfs_box_1_slot_''
~ n ~ ''_color'') | replace(''#'','''') | lower %}{% if cc not in ['''',''none'',''unknown'',''unavailable'']
%}{% set cols.list = cols.list + [cc] %}{% endif %}{% endfor %}
{% set gc = namespace(list=[]) %}
{% for p in (state_attr('sensor.sparkx_i7_expected_material_length','color') | default('', true) | string).split(';') %}{% set q = p | replace('#','') | lower | trim %}{% if q not in ['','none','unknown','unavailable'] %}{% set gc.list = gc.list + [q] %}{% endif %}{% endfor %}
{% for p in (state_attr(''sensor.sparkx_i7_expected_material_length'',''color'')
| default('''', true) | string).split('';'') %}{% set q = p | replace(''#'','''')
| lower | trim %}{% if q not in ['''',''none'',''unknown'',''unavailable'']
%}{% set gc.list = gc.list + [q] %}{% endif %}{% endfor %}
{% set mc = namespace(list=[]) %}
{% for p in (state_attr('sensor.sparkx_i7_expected_material_length','material') | default('', true) | string).split(';') %}{% set q = p | trim %}{% if q not in ['','none','unknown','unavailable'] %}{% set mc.list = mc.list + [q] %}{% endif %}{% endfor %}
{% for p in (state_attr(''sensor.sparkx_i7_expected_material_length'',''material'')
| default('''', true) | string).split('';'') %}{% set q = p | trim %}{% if
q not in ['''',''none'',''unknown'',''unavailable''] %}{% set mc.list = mc.list
+ [q] %}{% endif %}{% endfor %}
{% set single = (gc.list | length) == 1 %}
{% set gcol = gc.list[0] if single else '' %}
{% set aslot = (states('sensor.sparkx_i7_active_filament_slot') | default('', true) | string).split('_')[-1] %}
{% set aslot = aslot if aslot in ['1','2','3','4'] else '' %}
{% set rem_g = ([((job_g | float) - (used_g | float)), 0] | max) | round(1) %}
{% set ns = namespace(cover=[], below=[], short=[], ok=[], missing=[], loaded=[], match_label='', match_rem=0) %}
{% for n in ['1','2','3','4'] %}
{% set c = states('sensor.sparkx_i7_cfs_box_1_slot_' ~ n ~ '_color') | replace('#','') | lower %}
{% if c not in ['','none','unknown','unavailable'] %}
{% set cname = states('sensor.sparkx_i7_slot_' ~ n ~ '_color_name') %}
{% set flabel = states('sensor.sparkx_i7_cfs_box_1_slot_' ~ n ~ '_filament') %}
{% set label = 'Slot ' ~ n ~ ' ' ~ (cname if cname not in ['','unknown','unavailable'] else (flabel if flabel not in ['','unknown','unavailable'] else ('#' ~ (c | upper)))) %}
{% set sp = namespace(id='', rem=0, fw=0) %}
{% for e in integration_entities('spoolman') if e.endswith('_color_hex') %}
{% if sp.id == '' and (state_attr(e[:-10],'location') | default('', true) | lower) == ('cfs lite ' ~ n) %}
{% set gcol = gc.list[0] if single else '''' %}
{% set aslot = (states(''sensor.sparkx_i7_active_filament_slot'') | default('''',
true) | string).split(''_'')[-1] %}
{% set aslot = aslot if aslot in [''1'',''2'',''3'',''4''] else '''' %}
{% set rem_g = ([((job_g | float) - (used_g | float)), 0] | max) | round(1)
%}
{% set ns = namespace(cover=[], below=[], short=[], ok=[], missing=[], loaded=[],
match_label='''', match_rem=0) %}
{% for n in [''1'',''2'',''3'',''4''] %}
{% set c = states(''sensor.sparkx_i7_cfs_box_1_slot_'' ~ n ~ ''_color'') |
replace(''#'','''') | lower %}
{% if c not in ['''',''none'',''unknown'',''unavailable''] %}
{% set cname = states(''sensor.sparkx_i7_slot_'' ~ n ~ ''_color_name'') %}
{% set flabel = states(''sensor.sparkx_i7_cfs_box_1_slot_'' ~ n ~ ''_filament'')
%}
{% set label = ''Slot '' ~ n ~ '' '' ~ (cname if cname not in ['''',''unknown'',''unavailable'']
else (flabel if flabel not in ['''',''unknown'',''unavailable''] else (''#''
~ (c | upper)))) %}
{% set sp = namespace(id='''', rem=0, fw=0) %}
{% for e in integration_entities(''spoolman'') if e.endswith(''_color_hex'')
%}
{% if sp.id == '''' and (state_attr(e[:-10],''location'') | default('''',
true) | lower) == (''cfs lite '' ~ n) %}
{% set sp.id = e[:-10] %}
{% set sp.rem = states(e[:-10]) | float(0) %}
{% set sp.fw = state_attr(e[:-10],'filament_weight') | float(0) %}
{% set sp.fw = state_attr(e[:-10],''filament_weight'') | float(0) %}
{% endif %}
{% endfor %}
{% set pct = ((((sp.rem | float) / (sp.fw | float)) * 100) | round(0) | int) if (sp.fw | float) > 0 else 0 %}
{% if sp.id != '' %}{% set ns.loaded = ns.loaded + [label ~ ': ' ~ (sp.rem | round(1)) ~ ' g (' ~ pct ~ '%)'] %}{% endif %}
{% if sp.id != '' and single and n == aslot %}{% set ns.match_label = label %}{% set ns.match_rem = sp.rem %}{% endif %}
{% if sp.id != '' %}
{% set pct = ((((sp.rem | float) / (sp.fw | float)) * 100) | round(0) | int)
if (sp.fw | float) > 0 else 0 %}
{% if sp.id != '''' %}{% set ns.loaded = ns.loaded + [label ~ '': '' ~ (sp.rem
| round(1)) ~ '' g ('' ~ pct ~ ''%)''] %}{% endif %}
{% if sp.id != '''' and single and n == aslot %}{% set ns.match_label = label
%}{% set ns.match_rem = sp.rem %}{% endif %}
{% if sp.id != '''' %}
{% if single and n == aslot %}
{% if (sp.rem | float) < (job_g | float) %}{% set ns.short = ns.short + [label ~ ': ' ~ (sp.rem | round(1)) ~ ' g (' ~ pct ~ '%) left, ' ~ job_g ~ ' g needed'] %}
{% else %}{% set ns.ok = ns.ok + [label ~ ': ' ~ (sp.rem | round(1)) ~ ' g (' ~ pct ~ '%) left, ' ~ job_g ~ ' g needed'] %}{% endif %}
{% if (sp.rem | float) < (job_g | float) %}{% set ns.short = ns.short + [label
~ '': '' ~ (sp.rem | round(1)) ~ '' g ('' ~ pct ~ ''%) left, '' ~ job_g ~
'' g needed''] %}
{% else %}{% set ns.ok = ns.ok + [label ~ '': '' ~ (sp.rem | round(1)) ~ ''
g ('' ~ pct ~ ''%) left, '' ~ job_g ~ '' g needed''] %}{% endif %}
{% elif single %}
{% if (sp.rem | float) >= (job_g | float) %}{% set ns.cover = ns.cover + [label ~ ': ' ~ (sp.rem | round(1)) ~ ' g (' ~ pct ~ '%)'] %}
{% else %}{% set ns.below = ns.below + [label ~ ': ' ~ (sp.rem | round(1)) ~ ' g (' ~ pct ~ '%)'] %}{% endif %}
{% if (sp.rem | float) >= (job_g | float) %}{% set ns.cover = ns.cover + [label
~ '': '' ~ (sp.rem | round(1)) ~ '' g ('' ~ pct ~ ''%)''] %}
{% else %}{% set ns.below = ns.below + [label ~ '': '' ~ (sp.rem | round(1))
~ '' g ('' ~ pct ~ ''%)''] %}{% endif %}
{% else %}
{% if (sp.rem | float) < (job_g | float) %}{% set ns.short = ns.short + [label ~ ': ' ~ (sp.rem | round(1)) ~ ' g (' ~ pct ~ '%) left, up to ' ~ job_g ~ ' g needed'] %}
{% else %}{% set ns.ok = ns.ok + [label ~ ': ' ~ (sp.rem | round(1)) ~ ' g (' ~ pct ~ '%) left, up to ' ~ job_g ~ ' g needed'] %}{% endif %}
{% if (sp.rem | float) < (job_g | float) %}{% set ns.short = ns.short + [label
~ '': '' ~ (sp.rem | round(1)) ~ '' g ('' ~ pct ~ ''%) left, up to '' ~ job_g
~ '' g needed''] %}
{% else %}{% set ns.ok = ns.ok + [label ~ '': '' ~ (sp.rem | round(1)) ~ ''
g ('' ~ pct ~ ''%) left, up to '' ~ job_g ~ '' g needed''] %}{% endif %}
{% endif %}
{% elif job_g > 0 %}
{% set ns.missing = ns.missing + [label ~ ' (#' ~ (c | upper) ~ ')'] %}
{% set ns.missing = ns.missing + [label ~ '' (#'' ~ (c | upper) ~ '')''] %}
{% endif %}
{% endif %}
{% endfor %}
Job: {{ gcode_file if gcode_file not in ['','unknown','unavailable'] else (state_attr('sensor.sparkx_i7_print_status','file') | default('', true) | string).split('/')[-1] }}
Needs {{ job_g | round(1) }} g ({{ length_cm | round(1) }} cm) · used {{ used_g }} g · {{ rem_g }} g left to print
Slicer: {{ (mc.list | join(', ')) if mc.list else 'material unknown' }} · {{ ('single colour #' ~ (gcol | upper)) if single else ((gc.list | length) ~ ' colours') }}
{% if job_g <= 0 %}Cannot verify: slicer filament estimate not available yet.{% if ns.loaded %}
Job: {{ gcode_file if gcode_file not in ['''',''unknown'',''unavailable'']
else (state_attr(''sensor.sparkx_i7_print_status'',''file'') | default('''',
true) | string).split(''/'')[-1] }}
Needs {{ job_g | round(1) }} g ({{ length_cm | round(1) }} cm) · used {{ used_g
}} g · {{ rem_g }} g left to print
Slicer: {{ (mc.list | join('', '')) if mc.list else ''material unknown'' }}
· {{ (''single colour #'' ~ (gcol | upper)) if single else ((gc.list | length)
~ '' colours'') }}
{% if job_g <= 0 %}Cannot verify: slicer filament estimate not available yet.{%
if ns.loaded %}
Loaded:
- {{ ns.loaded | join('\n- ') }}{% endif %}
{% elif single and aslot != '' %}
- {{ ns.loaded | join(''\n- '') }}{% endif %}
{% elif single and aslot != '''' %}
{% if ns.short %}NOT ENOUGH filament:
- {{ ns.short | join('\n- ') }}
{% elif ns.match_label %}Enough filament: {{ ns.match_label }}: {{ ns.match_rem | round(1) }} g left, {{ job_g }} g needed.
{% else %}Active slot {{ aslot }} has no Spoolman spool at CFS Lite, so remaining cannot be checked.{% endif %}
{% elif single %}No exact colour match for the print colour #{{ gcol | upper }} in a loaded CFS slot, so the exact spool cannot be identified.{% if ns.cover %}
- {{ ns.short | join(''\n- '') }}
{% elif ns.match_label %}Enough filament: {{ ns.match_label }}: {{ ns.match_rem
| round(1) }} g left, {{ job_g }} g needed.
{% else %}Active slot {{ aslot }} has no Spoolman spool at CFS Lite, so remaining
cannot be checked.{% endif %}
{% elif single %}No exact colour match for the print colour #{{ gcol | upper
}} in a loaded CFS slot, so the exact spool cannot be identified.{% if ns.cover
%}
Would cover {{ job_g }} g:
- {{ ns.cover | join('\n- ') }}{% endif %}{% if ns.below %}
- {{ ns.cover | join(''\n- '') }}{% endif %}{% if ns.below %}
Below {{ job_g }} g:
- {{ ns.below | join('\n- ') }}{% endif %}{% if not ns.cover and not ns.below %}
- {{ ns.below | join(''\n- '') }}{% endif %}{% if not ns.cover and not ns.below
%}
No loaded CFS slot has a matching Spoolman spool to compare.{% endif %}
{% elif ns.short %}NOT ENOUGH filament - possible shortfall:
- {{ ns.short | join('\n- ') }}{% if ns.ok %}
- {{ ns.short | join(''\n- '') }}{% if ns.ok %}
OK (would still cover the whole job):
- {{ ns.ok | join('\n- ') }}{% endif %}{% if ns.missing %}
- {{ ns.ok | join(''\n- '') }}{% endif %}{% if ns.missing %}
No Spoolman spool matched for:
- {{ ns.missing | join('\n- ') }}{% endif %}
- {{ ns.missing | join(''\n- '') }}{% endif %}
{% elif ns.ok %}Enough filament:
- {{ ns.ok | join('\n- ') }}{% if ns.missing %}
- {{ ns.ok | join(''\n- '') }}{% if ns.missing %}
No Spoolman spool matched for:
- {{ ns.missing | join('\n- ') }}{% endif %}
{% elif ns.missing %}Could not match any loaded CFS slot to a Spoolman spool.{% endif %}
- {{ ns.missing | join(''\n- '') }}{% endif %}
{% elif ns.missing %}Could not match any loaded CFS slot to a Spoolman spool.{%
endif %}'
- action: notify.persistent_notification
data:
title: Print started - filament check