This commit is contained in:
Home Assistant Version Control
2026-10-12 01:05:06 +00:00
parent c6b93676ed
commit 3eb9411a32
4 changed files with 213 additions and 40 deletions
@@ -0,0 +1,152 @@
# ha_mcp_backup
schema_version: 1
domain: automation
entity_id: automation.sparkx_i7_deduct_filament_in_spoolman_on_print_complete
captured: '2026-10-12T01:04:58.210558+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
conditions: []
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) }}'
- 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 (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 }}'
- 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 completed: 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 completed: 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 completed: 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 complete - Spoolman updated
message: 'Print complete - Spoolman deducted {{ summary_total }} g
{{ summary_lines }}'
- action: notify.mobile_app_francos_ipad
data:
title: Print complete - Spoolman updated
message: 'Print complete - Spoolman deducted {{ summary_total }} g
{{ summary_lines }}'
- action: notify.mobile_app_sm_f956w
data:
title: Print complete - Spoolman updated
message: 'Print complete - Spoolman deducted {{ summary_total }} g
{{ summary_lines }}'
- action: input_number.set_value
target:
entity_id: input_number.sparkx_i7_last_job_filament_weight
data:
value: '{{ final_grams }}'
- action: input_number.set_value
target:
entity_id: input_number.sparkx_i7_last_job_cost
data:
value: '{{ ((final_grams | 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
+2
View File
@@ -4439,3 +4439,5 @@
{"timestamp": "2026-10-12T01:00:39.356786+00:00", "tool_name": "ha_get_state", "parameters": {"entity_id": ["sensor.sparkx_i7_print_status", "input_text.sparkx_i7_print_spool_latch", "input_number.sparkx_i7_spoolman_length_checkpoint", "sensor.sparkx_i7_used_material_length", "input_number.sparkx_i7_filament_g_cm", "input_number.sparkx_i7_last_job_filament_weight", "input_number.sparkx_i7_last_job_cost", "input_number.sparkx_i7_slot_1_grams"], "fields": null, "attribute_keys": null}, "execution_time_ms": 3.2265186309814453, "success": true, "error_message": null, "response_size_bytes": 5235, "user_context": null} {"timestamp": "2026-10-12T01:00:39.356786+00:00", "tool_name": "ha_get_state", "parameters": {"entity_id": ["sensor.sparkx_i7_print_status", "input_text.sparkx_i7_print_spool_latch", "input_number.sparkx_i7_spoolman_length_checkpoint", "sensor.sparkx_i7_used_material_length", "input_number.sparkx_i7_filament_g_cm", "input_number.sparkx_i7_last_job_filament_weight", "input_number.sparkx_i7_last_job_cost", "input_number.sparkx_i7_slot_1_grams"], "fields": null, "attribute_keys": null}, "execution_time_ms": 3.2265186309814453, "success": true, "error_message": null, "response_size_bytes": 5235, "user_context": null}
{"timestamp": "2026-10-12T01:00:39.601889+00:00", "tool_name": "ha_config_get_automation", "parameters": {"identifier": "1791477238762"}, "execution_time_ms": 249.27139282226562, "success": true, "error_message": null, "response_size_bytes": 5672, "user_context": null} {"timestamp": "2026-10-12T01:00:39.601889+00:00", "tool_name": "ha_config_get_automation", "parameters": {"identifier": "1791477238762"}, "execution_time_ms": 249.27139282226562, "success": true, "error_message": null, "response_size_bytes": 5672, "user_context": null}
{"timestamp": "2026-10-12T01:01:32.109907+00:00", "tool_name": "ha_eval_template", "parameters": {"template": "{% set old_slot = states('input_text.sparkx_i7_print_spool_latch') %}\n{% set color = states('sensor.sparkx_i7_cfs_' ~ (old_slot | lower | replace(' ', '_')) ~ '_color') | replace('#','') | lower %}\ncolor_hex={{ color }}\n{% set ns = namespace(id='', base='', remain='') %}\n{% for e in integration_entities('spoolman') %}\n{% if e.endswith('_color_hex') and (states(e) | replace('#','') | lower) == color and (state_attr(e[:-10], 'location') | default('', true) | lower) == 'cfs lite' and (states(e[:-10]) | float(0)) > 0 and ns.id == '' %}\n{% set ns.id = states(e[:-10] ~ '_id') %}{% set ns.base = e[:-10] %}{% set ns.remain = states(e[:-10]) %}\n{% endif %}\n{% endfor %}\nspool_id={{ ns.id }}\nspool_name={{ state_attr(ns.base, 'friendly_name') if ns.base else '' }}\nremaining_weight={{ ns.remain }}\nfinal_grams={{ (([states('sensor.sparkx_i7_used_material_length') | float(0) - (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) }}", "condition": null, "variables": null, "strict": false, "timeout": 3, "report_errors": true}, "execution_time_ms": 36.53764724731445, "success": true, "error_message": null, "response_size_bytes": 2510, "user_context": null} {"timestamp": "2026-10-12T01:01:32.109907+00:00", "tool_name": "ha_eval_template", "parameters": {"template": "{% set old_slot = states('input_text.sparkx_i7_print_spool_latch') %}\n{% set color = states('sensor.sparkx_i7_cfs_' ~ (old_slot | lower | replace(' ', '_')) ~ '_color') | replace('#','') | lower %}\ncolor_hex={{ color }}\n{% set ns = namespace(id='', base='', remain='') %}\n{% for e in integration_entities('spoolman') %}\n{% if e.endswith('_color_hex') and (states(e) | replace('#','') | lower) == color and (state_attr(e[:-10], 'location') | default('', true) | lower) == 'cfs lite' and (states(e[:-10]) | float(0)) > 0 and ns.id == '' %}\n{% set ns.id = states(e[:-10] ~ '_id') %}{% set ns.base = e[:-10] %}{% set ns.remain = states(e[:-10]) %}\n{% endif %}\n{% endfor %}\nspool_id={{ ns.id }}\nspool_name={{ state_attr(ns.base, 'friendly_name') if ns.base else '' }}\nremaining_weight={{ ns.remain }}\nfinal_grams={{ (([states('sensor.sparkx_i7_used_material_length') | float(0) - (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) }}", "condition": null, "variables": null, "strict": false, "timeout": 3, "report_errors": true}, "execution_time_ms": 36.53764724731445, "success": true, "error_message": null, "response_size_bytes": 2510, "user_context": null}
{"timestamp": "2026-10-12T01:04:58.659731+00:00", "tool_name": "ha_config_set_automation", "parameters": {"config": null, "identifier": "automation.sparkx_i7_deduct_filament_in_spoolman_on_print_complete", "python_transform": "config['triggers'][0]['id'] = 'complete'\nconfig['triggers'].append({'trigger': 'state', 'entity_id': 'sensor.sparkx_i7_print_status', 'to': 'stopped', 'id': 'stopped'})\nconfig['triggers'].append({'trigger': 'state', 'entity_id': 'sensor.sparkx_i7_print_status', 'to': 'error', 'id': 'error'})\nconfig['conditions'] = [{'condition': 'template', 'value_template': \"{{ trigger.id == 'complete' or states('input_text.sparkx_i7_print_spool_latch') not in ['', 'unknown', 'unavailable'] }}\"}]\nconfig['actions'][0]['variables']['outcome'] = \"{% set tid = trigger.id | default('complete') %}{{ 'cancelled' if tid == 'stopped' else ('error' if tid == 'error' else 'complete') }}\"\nfor n in config['actions'][5]['then'][0]['default']:\n n['data']['message'] = n['data']['message'].replace('Print completed:', 'Print {{ outcome }}:')\nfor n in config['actions'][8]['then']:\n n['data']['title'] = n['data']['title'].replace('Print complete - Spoolman', 'Print {{ outcome }} - Spoolman')\n n['data']['message'] = n['data']['message'].replace('Print complete - Spoolman', 'Print {{ outcome }} - Spoolman')\n_ljw = config['actions'][9]\n_ljc = config['actions'][10]\nconfig['actions'][9:11] = [{'if': {'condition': 'template', 'value_template': \"{{ trigger.id == 'complete' }}\"}, 'then': [_ljw, _ljc]}]", "config_hash": "48957ef7384c9039", "take_control_of_blueprint": false, "category": null, "wait": true, "enabled": null, "run_actions": false, "MandatoryBPS": false, "BestPracticeKey": null}, "execution_time_ms": 424.70407485961914, "success": true, "error_message": null, "response_size_bytes": 8590, "user_context": null}
{"timestamp": "2026-10-12T01:05:04.991332+00:00", "tool_name": "ha_call_service", "parameters": {"domain": "automation", "service": "reload", "entity_id": null, "data": null, "return_response": false, "wait": true, "verbose": false, "result_fields": null, "result_attribute_keys": null, "ws_command": null}, "execution_time_ms": 722.9030132293701, "success": true, "error_message": null, "response_size_bytes": 169, "user_context": null}
+46 -27
View File
@@ -4397,13 +4397,28 @@
entity_id: sensor.sparkx_i7_print_status entity_id: sensor.sparkx_i7_print_status
from: printing from: printing
to: completed to: completed
conditions: [] 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: actions:
- variables: - variables:
old_slot: '{{ states(''input_text.sparkx_i7_print_spool_latch'') }}' old_slot: '{{ states(''input_text.sparkx_i7_print_spool_latch'') }}'
cur: '{{ states(''sensor.sparkx_i7_used_material_length'') | float(0) }}' cur: '{{ states(''sensor.sparkx_i7_used_material_length'') | float(0) }}'
checkpoint: '{{ states(''input_number.sparkx_i7_spoolman_length_checkpoint'') checkpoint: '{{ states(''input_number.sparkx_i7_spoolman_length_checkpoint'')
| float(0) }}' | float(0) }}'
outcome: '{% set tid = trigger.id | default(''complete'') %}{{ ''cancelled''
if tid == ''stopped'' else (''error'' if tid == ''error'' else ''complete'')
}}'
- variables: - variables:
final_grams: '{{ (([cur | float - (checkpoint | float), 0] | max) * (states(''input_number.sparkx_i7_filament_g_cm'') final_grams: '{{ (([cur | float - (checkpoint | float), 0] | max) * (states(''input_number.sparkx_i7_filament_g_cm'')
| float(0.03))) | round(2) }}' | float(0.03))) | round(2) }}'
@@ -4450,25 +4465,25 @@
- action: notify.persistent_notification - action: notify.persistent_notification
data: data:
title: 'Spoolman: no spool for slot color' title: 'Spoolman: no spool for slot color'
message: 'Print completed: final segment of {{ final_grams }} g from {{ message: 'Print {{ outcome }}: final segment of {{ final_grams }} g from
old_slot if old_slot else ''the active slot'' }} (color #{{ color | upper {{ old_slot if old_slot else ''the active slot'' }} (color #{{ color |
}}) could not be deducted - no Spoolman spool in the CFS Lite location 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 remaining weight matches that color. Register the new roll in Spoolman
with location CFS Lite, then adjust manually if needed.' with location CFS Lite, then adjust manually if needed.'
- action: notify.mobile_app_francos_ipad - action: notify.mobile_app_francos_ipad
data: data:
title: 'Spoolman: no spool for slot color' title: 'Spoolman: no spool for slot color'
message: 'Print completed: final segment of {{ final_grams }} g from {{ message: 'Print {{ outcome }}: final segment of {{ final_grams }} g from
old_slot if old_slot else ''the active slot'' }} (color #{{ color | upper {{ old_slot if old_slot else ''the active slot'' }} (color #{{ color |
}}) could not be deducted - no Spoolman spool in the CFS Lite location 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 remaining weight matches that color. Register the new roll in Spoolman
with location CFS Lite, then adjust manually if needed.' with location CFS Lite, then adjust manually if needed.'
- action: notify.mobile_app_sm_f956w - action: notify.mobile_app_sm_f956w
data: data:
title: 'Spoolman: no spool for slot color' title: 'Spoolman: no spool for slot color'
message: 'Print completed: final segment of {{ final_grams }} g from {{ message: 'Print {{ outcome }}: final segment of {{ final_grams }} g from
old_slot if old_slot else ''the active slot'' }} (color #{{ color | upper {{ old_slot if old_slot else ''the active slot'' }} (color #{{ color |
}}) could not be deducted - no Spoolman spool in the CFS Lite location 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 remaining weight matches that color. Register the new roll in Spoolman
with location CFS Lite, then adjust manually if needed.' with location CFS Lite, then adjust manually if needed.'
- variables: - variables:
@@ -4491,33 +4506,37 @@
then: then:
- action: notify.persistent_notification - action: notify.persistent_notification
data: data:
title: Print complete - Spoolman updated title: Print {{ outcome }} - Spoolman updated
message: 'Print complete - Spoolman deducted {{ summary_total }} g message: 'Print {{ outcome }} - Spoolman deducted {{ summary_total }} g
{{ summary_lines }}' {{ summary_lines }}'
- action: notify.mobile_app_francos_ipad - action: notify.mobile_app_francos_ipad
data: data:
title: Print complete - Spoolman updated title: Print {{ outcome }} - Spoolman updated
message: 'Print complete - Spoolman deducted {{ summary_total }} g message: 'Print {{ outcome }} - Spoolman deducted {{ summary_total }} g
{{ summary_lines }}' {{ summary_lines }}'
- action: notify.mobile_app_sm_f956w - action: notify.mobile_app_sm_f956w
data: data:
title: Print complete - Spoolman updated title: Print {{ outcome }} - Spoolman updated
message: 'Print complete - Spoolman deducted {{ summary_total }} g message: 'Print {{ outcome }} - Spoolman deducted {{ summary_total }} g
{{ summary_lines }}' {{ summary_lines }}'
- action: input_number.set_value - if:
target: condition: template
entity_id: input_number.sparkx_i7_last_job_filament_weight value_template: '{{ trigger.id == ''complete'' }}'
data: then:
value: '{{ final_grams }}' - action: input_number.set_value
- action: input_number.set_value target:
target: entity_id: input_number.sparkx_i7_last_job_filament_weight
entity_id: input_number.sparkx_i7_last_job_cost data:
data: value: '{{ final_grams }}'
value: '{{ ((final_grams | float) * (states(''input_number.filament_price_per_kg'') - action: input_number.set_value
| float(25)) / 1000) | round(2) }}' target:
entity_id: input_number.sparkx_i7_last_job_cost
data:
value: '{{ ((final_grams | float) * (states(''input_number.filament_price_per_kg'')
| float(25)) / 1000) | round(2) }}'
- action: input_number.set_value - action: input_number.set_value
target: target:
entity_id: input_number.sparkx_i7_spoolman_length_checkpoint entity_id: input_number.sparkx_i7_spoolman_length_checkpoint
+13 -13
View File
@@ -27,7 +27,7 @@
"led_brightness": 100, "led_brightness": 100,
"countdown_to_turn_off": 0, "countdown_to_turn_off": 0,
"countdown_to_turn_on": 0, "countdown_to_turn_on": 0,
"power": 2.1, "power": 1.9,
"current": 0.1, "current": 0.1,
"energy": 54.9, "energy": 54.9,
"power_factor": 0.16, "power_factor": 0.16,
@@ -45,10 +45,10 @@
"state": "ON", "state": "ON",
"led_brightness": 100, "led_brightness": 100,
"countdown_to_turn_off": 0, "countdown_to_turn_off": 0,
"voltage": 121.3, "voltage": 121.8,
"countdown_to_turn_on": 0, "countdown_to_turn_on": 0,
"energy": 106.56, "energy": 106.57,
"power_factor": 0.88, "power_factor": 0.2,
"ac_frequency": 60, "ac_frequency": 60,
"update": { "update": {
"state": "idle", "state": "idle",
@@ -58,7 +58,7 @@
"latest_release_notes": null "latest_release_notes": null
}, },
"linkquality": 145, "linkquality": 145,
"power": 87.7, "power": 86,
"current": 0.82, "current": 0.82,
"power_on_behavior": "on" "power_on_behavior": "on"
}, },
@@ -77,9 +77,9 @@
"voltage": 119.9, "voltage": 119.9,
"state": "ON", "state": "ON",
"ac_frequency": 60, "ac_frequency": 60,
"energy": 216.59, "energy": 216.6,
"power": 100.4, "power": 94.9,
"current": 0.89, "current": 0.84,
"power_factor": 0.94, "power_factor": 0.94,
"update": { "update": {
"state": "idle", "state": "idle",
@@ -98,8 +98,8 @@
"voltage": 121.9, "voltage": 121.9,
"energy": 102.22, "energy": 102.22,
"state": "ON", "state": "ON",
"power": 32.3, "power": 26.6,
"current": 0.44, "current": 0.36,
"ac_frequency": 60, "ac_frequency": 60,
"power_factor": 0.7, "power_factor": 0.7,
"update": { "update": {
@@ -114,7 +114,7 @@
}, },
"0xffffb40e060895b3": { "0xffffb40e060895b3": {
"state": "ON", "state": "ON",
"voltage": 121.9, "voltage": 121.4,
"ac_frequency": 60, "ac_frequency": 60,
"energy": 14.92, "energy": 14.92,
"current": 0.02, "current": 0.02,
@@ -136,7 +136,7 @@
"0xffffb40e0608864e": { "0xffffb40e0608864e": {
"led_brightness": 100, "led_brightness": 100,
"countdown_to_turn_off": 0, "countdown_to_turn_off": 0,
"voltage": 121.7, "voltage": 121.2,
"energy": 36.31, "energy": 36.31,
"countdown_to_turn_on": 0, "countdown_to_turn_on": 0,
"state": "ON", "state": "ON",
@@ -171,7 +171,7 @@
}, },
"0xa4c1380d0679ffff": { "0xa4c1380d0679ffff": {
"battery": 100, "battery": 100,
"temperature": 17.8, "temperature": 17.7,
"temperature_units": "celsius", "temperature_units": "celsius",
"temperature_calibration": 0, "temperature_calibration": 0,
"update": { "update": {