Files
HomeAssistantVS/.ha_mcp/backups/automation.1791477238799.20261015_132353.yaml
T

123 lines
8.2 KiB
YAML

# ha_mcp_backup
schema_version: 1
domain: automation
entity_id: '1791477238799'
captured: '2026-10-15T13:23:53.149869+00:00'
tool: ha_config_set_automation
config:
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
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.
triggers:
- trigger: state
entity_id: sensor.sparkx_i7_print_status
to: printing
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) }}'
- variables:
report: "{% set cols = namespace(list=[]) %}\n{% 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 %}\n{% set\
\ gc = namespace(list=[]) %}\n{% 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 %}\n{% set mc = namespace(list=[])\
\ %}\n{% 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 %}\n{% set single = (gc.list | length) == 1 %}\n\
{% set gcol = gc.list[0] if single else '' %}\n{% set aslot = (states('sensor.sparkx_i7_active_filament_slot')\
\ | default('', true) | string).split('_')[-1] %}\n{% set aslot = aslot if\
\ aslot in ['1','2','3','4'] else '' %}\n{% set rem_g = ([((job_g | float)\
\ - (used_g | float)), 0] | max) | round(1) %}\n{% set ns = namespace(cover=[],\
\ below=[], short=[], ok=[], missing=[], loaded=[], match_label='', match_rem=0)\
\ %}\n{% for n in ['1','2','3','4'] %}\n{% set c = states('sensor.sparkx_i7_cfs_box_1_slot_'\
\ ~ n ~ '_color') | replace('#','') | lower %}\n{% if c not in ['','none','unknown','unavailable']\
\ %}\n{% set cname = states('sensor.sparkx_i7_slot_' ~ n ~ '_color_name')\
\ %}\n{% set flabel = states('sensor.sparkx_i7_cfs_box_1_slot_' ~ n ~ '_filament')\
\ %}\n{% set label = 'Slot ' ~ n ~ ' ' ~ (cname if cname not in ['','unknown','unavailable']\
\ else (flabel if flabel not in ['','unknown','unavailable'] else ('#' ~ (c\
\ | upper)))) %}\n{% set sp = namespace(id='', rem=0, fw=0) %}\n{% for e in\
\ integration_entities('spoolman') if e.endswith('_color_hex') %}\n{% if sp.id\
\ == '' and (state_attr(e[:-10],'location') | default('', true) | lower) ==\
\ ('cfs lite ' ~ n) %}\n{% set sp.id = e[:-10] %}\n{% set sp.rem = states(e[:-10])\
\ | float(0) %}\n{% set sp.fw = state_attr(e[:-10],'filament_weight') | float(0)\
\ %}\n{% endif %}\n{% endfor %}\n{% set pct = ((((sp.rem | float) / (sp.fw\
\ | float)) * 100) | round(0) | int) if (sp.fw | float) > 0 else 0 %}\n{%\
\ if sp.id != '' %}{% set ns.loaded = ns.loaded + [label ~ ': ' ~ (sp.rem\
\ | round(1)) ~ ' g (' ~ pct ~ '%)'] %}{% endif %}\n{% if sp.id != '' and\
\ single and n == aslot %}{% set ns.match_label = label %}{% set ns.match_rem\
\ = sp.rem %}{% endif %}\n{% if sp.id != '' %}\n{% if single and n == aslot\
\ %}\n{% if (sp.rem | float) < (job_g | float) %}{% set ns.short = ns.short\
\ + [label ~ ': ' ~ (sp.rem | round(1)) ~ ' g (' ~ pct ~ '%) left, ' ~ job_g\
\ ~ ' g needed'] %}\n{% else %}{% set ns.ok = ns.ok + [label ~ ': ' ~ (sp.rem\
\ | round(1)) ~ ' g (' ~ pct ~ '%) left, ' ~ job_g ~ ' g needed'] %}{% endif\
\ %}\n{% elif single %}\n{% if (sp.rem | float) >= (job_g | float) %}{% set\
\ ns.cover = ns.cover + [label ~ ': ' ~ (sp.rem | round(1)) ~ ' g (' ~ pct\
\ ~ '%)'] %}\n{% else %}{% set ns.below = ns.below + [label ~ ': ' ~ (sp.rem\
\ | round(1)) ~ ' g (' ~ pct ~ '%)'] %}{% endif %}\n{% else %}\n{% 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']\
\ %}\n{% else %}{% set ns.ok = ns.ok + [label ~ ': ' ~ (sp.rem | round(1))\
\ ~ ' g (' ~ pct ~ '%) left, up to ' ~ job_g ~ ' g needed'] %}{% endif %}\n\
{% endif %}\n{% elif job_g > 0 %}\n{% set ns.missing = ns.missing + [label\
\ ~ ' (#' ~ (c | upper) ~ ')'] %}\n{% endif %}\n{% endif %}\n{% endfor %}\n\
Job: {{ gcode_file if gcode_file not in ['','unknown','unavailable'] else\
\ (state_attr('sensor.sparkx_i7_print_status','file') | default('', true)\
\ | string).split('/')[-1] }}\nNeeds {{ job_g | round(1) }} g ({{ length_cm\
\ | round(1) }} cm) \xB7 used {{ used_g }} g \xB7 {{ rem_g }} g left to print\n\
Slicer: {{ (mc.list | join(', ')) if mc.list else 'material unknown' }} \xB7\
\ {{ ('single colour #' ~ (gcol | upper)) if single else ((gc.list | length)\
\ ~ ' colours') }}\n{% if job_g <= 0 %}Cannot verify: slicer filament estimate\
\ not available yet.{% if ns.loaded %}\nLoaded:\n- {{ ns.loaded | join('\\\
n- ') }}{% endif %}\n{% elif single and aslot != '' %}\n{% if ns.short %}NOT\
\ ENOUGH filament:\n- {{ ns.short | join('\\n- ') }}\n{% elif ns.match_label\
\ %}Enough filament: {{ ns.match_label }}: {{ ns.match_rem | round(1) }} g\
\ left, {{ job_g }} g needed.\n{% else %}Active slot {{ aslot }} has no Spoolman\
\ spool at CFS Lite, so remaining cannot be checked.{% endif %}\n{% 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 %}\nWould\
\ cover {{ job_g }} g:\n- {{ ns.cover | join('\\n- ') }}{% endif %}{% if ns.below\
\ %}\nBelow {{ job_g }} g:\n- {{ ns.below | join('\\n- ') }}{% endif %}{%\
\ if not ns.cover and not ns.below %}\nNo loaded CFS slot has a matching Spoolman\
\ spool to compare.{% endif %}\n{% elif ns.short %}NOT ENOUGH filament - possible\
\ shortfall:\n- {{ ns.short | join('\\n- ') }}{% if ns.ok %}\nOK (would still\
\ cover the whole job):\n- {{ ns.ok | join('\\n- ') }}{% endif %}{% if ns.missing\
\ %}\nNo Spoolman spool matched for:\n- {{ ns.missing | join('\\n- ') }}{%\
\ endif %}\n{% elif ns.ok %}Enough filament:\n- {{ ns.ok | join('\\n- ') }}{%\
\ if ns.missing %}\nNo Spoolman spool matched for:\n- {{ ns.missing | join('\\\
n- ') }}{% endif %}\n{% 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
message: '{{ report }}'
- action: notify.mobile_app_francos_ipad
data:
title: Print started - filament check
message: '{{ report }}'
- action: notify.mobile_app_sm_f956w
data:
title: Print started - filament check
message: '{{ report }}'
mode: single