6 files
This commit is contained in:
1 parent
c85606c96e
commit
90d32d5573
6 files changed
+368
-31
No files matched your search
@@ -0,0 +1,152 @@
|
||||
# ha_mcp_backup
|
||||
schema_version: 1
|
||||
domain: automation
|
||||
entity_id: '1791477238762'
|
||||
captured: '2026-10-15T13:23:53.053853+00:00'
|
||||
tool: ha_config_set_automation
|
||||
config:
|
||||
id: '1791477238762'
|
||||
alias: SparkX i7 - Latch print spool for Spoolman
|
||||
description: 'Segment tracking for Spoolman: at print start resets the length checkpoint
|
||||
and per-slot gram counters and latches the active CFS slot. On every slot change
|
||||
mid-print, deducts the exact extrusion of the finished segment (used_material_length
|
||||
delta x g/cm) from the Spoolman spool in the CFS Lite location matching the previous
|
||||
slot color hex (only if that spool has remaining weight), accumulates grams per
|
||||
slot, notifies on no-match, then re-baselines the checkpoint and advances the
|
||||
latch.'
|
||||
triggers:
|
||||
- trigger: state
|
||||
entity_id: sensor.sparkx_i7_print_status
|
||||
to: printing
|
||||
id: print_started
|
||||
- trigger: state
|
||||
entity_id: sensor.sparkx_i7_active_filament_slot
|
||||
id: slot_changed
|
||||
conditions:
|
||||
- condition: state
|
||||
entity_id: sensor.sparkx_i7_print_status
|
||||
state: printing
|
||||
actions:
|
||||
- variables:
|
||||
new_slot: '{{ states(''sensor.sparkx_i7_active_filament_slot'') }}'
|
||||
old_slot: '{{ states(''input_text.sparkx_i7_print_spool_latch'') }}'
|
||||
cur: '{{ states(''sensor.sparkx_i7_used_material_length'') | float(0) }}'
|
||||
- choose:
|
||||
- conditions:
|
||||
condition: trigger
|
||||
id: print_started
|
||||
sequence:
|
||||
- action: input_number.set_value
|
||||
target:
|
||||
entity_id: input_number.sparkx_i7_spoolman_length_checkpoint
|
||||
data:
|
||||
value: '{{ cur }}'
|
||||
- action: input_number.set_value
|
||||
target:
|
||||
entity_id:
|
||||
- input_number.sparkx_i7_slot_1_grams
|
||||
- input_number.sparkx_i7_slot_2_grams
|
||||
- input_number.sparkx_i7_slot_3_grams
|
||||
- input_number.sparkx_i7_slot_4_grams
|
||||
data:
|
||||
value: 0
|
||||
- action: input_text.set_value
|
||||
target:
|
||||
entity_id: input_text.sparkx_i7_print_spool_latch
|
||||
data:
|
||||
value: '{{ new_slot if new_slot not in [''unknown'', ''unavailable''] else
|
||||
'''' }}'
|
||||
- conditions:
|
||||
condition: template
|
||||
value_template: '{{ old_slot not in ['''', ''unknown'', ''unavailable''] and
|
||||
new_slot not in ['''', ''unknown'', ''unavailable''] and new_slot != old_slot
|
||||
}}'
|
||||
sequence:
|
||||
- variables:
|
||||
grams: '{{ (([cur | float - (states(''input_number.sparkx_i7_spoolman_length_checkpoint'')
|
||||
| float(0)), 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 }}'
|
||||
- if:
|
||||
condition: template
|
||||
value_template: '{{ 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: '{{ grams | float(0) }}'
|
||||
- if:
|
||||
condition: template
|
||||
value_template: '{{ old_slot.split(''_'')[-1] in [''1'', ''2'', ''3'',
|
||||
''4''] }}'
|
||||
then:
|
||||
- action: input_number.set_value
|
||||
target:
|
||||
entity_id: input_number.sparkx_i7_slot_{{ old_slot.split('_')[-1]
|
||||
}}_grams
|
||||
data:
|
||||
value: '{{ (states(''input_number.sparkx_i7_slot_'' ~ old_slot.split(''_'')[-1]
|
||||
~ ''_grams'') | float(0)) + (grams | float) }}'
|
||||
default:
|
||||
- action: notify.persistent_notification
|
||||
data:
|
||||
title: 'Spoolman: no spool for slot color'
|
||||
message: 'Segment of {{ grams }} g from {{ old_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: 'Segment of {{ grams }} g from {{ old_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: 'Segment of {{ grams }} g from {{ old_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: 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: '{{ new_slot }}'
|
||||
- conditions:
|
||||
condition: template
|
||||
value_template: '{{ old_slot in ['''', ''unknown'', ''unavailable''] and new_slot
|
||||
not in ['''', ''unknown'', ''unavailable''] }}'
|
||||
sequence:
|
||||
- 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: '{{ new_slot }}'
|
||||
mode: queued
|
||||
max: 10
|
||||
@@ -0,0 +1,122 @@
|
||||
# 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
|
||||
@@ -0,0 +1,60 @@
|
||||
# ha_mcp_backup
|
||||
schema_version: 1
|
||||
domain: script
|
||||
entity_id: spoolman_set_spool_remaining
|
||||
captured: '2026-10-15T13:23:53.118614+00:00'
|
||||
tool: ha_config_set_script
|
||||
config:
|
||||
alias: Spoolman - Set Spool Remaining
|
||||
fields:
|
||||
slot:
|
||||
name: CFS Slot
|
||||
description: CFS slot number 1-4 - resolves the spool by the slot color hex
|
||||
selector:
|
||||
number:
|
||||
min: 1
|
||||
max: 4
|
||||
mode: box
|
||||
spool_id:
|
||||
name: Spool ID
|
||||
description: Direct Spoolman spool ID - used when no slot is given
|
||||
selector:
|
||||
number:
|
||||
min: 1
|
||||
max: 9999
|
||||
mode: box
|
||||
sequence:
|
||||
- variables:
|
||||
resolved_id: '{% set n = (slot | int(0)) if slot is defined else 0 %}{% if n
|
||||
>= 1 %}{% 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 '' ~ (n | int)) and ns.id ==
|
||||
'''' %}{% set ns.id = states(e[:-10] ~ ''_id'') %}{% endif %}{% endfor %}{{
|
||||
ns.id }}{% else %}{{ (spool_id | int(0)) if spool_id is defined else 0 }}{%
|
||||
endif %}'
|
||||
slot_n: '{{ (slot | int(0)) if slot is defined else 0 }}'
|
||||
- choose:
|
||||
- conditions:
|
||||
condition: template
|
||||
value_template: '{{ resolved_id | int(0) > 0 }}'
|
||||
sequence:
|
||||
- action: spoolman.patch_spool
|
||||
data:
|
||||
id: '{{ resolved_id | int(0) }}'
|
||||
remaining_weight: '{{ states(''input_number.spoolman_set_remaining'') |
|
||||
float(0) }}'
|
||||
default:
|
||||
- action: notify.persistent_notification
|
||||
data:
|
||||
title: Spoolman - remaining not set
|
||||
message: '{% if slot_n | int >= 1 %}No Spoolman spool matched CFS slot {{
|
||||
slot_n }} (color {{ states(''sensor.sparkx_i7_cfs_box_1_slot_'' ~ (slot_n
|
||||
| int) ~ ''_color'') }}) in the CFS Lite location - register a spool with
|
||||
that color hex and location in Spoolman, then try again.{% else %}No spool
|
||||
resolved - pass spool_id or a CFS slot 1-4. Nothing was set.{% endif %}'
|
||||
mode: single
|
||||
description: Sets a Spoolman spool remaining weight from the shared helper input_number.spoolman_set_remaining.
|
||||
Pass slot (1-4) to resolve the spool by the CFS slot color hex in the CFS Lite
|
||||
location (no remaining-weight guard, so an exhausted spool can be reset to full),
|
||||
or pass spool_id directly. Notifies via persistent notification when nothing could
|
||||
be resolved.
|
||||
Reference in new issue
Block a user