From 0161cf335455e16f2000e682afe808692bb8566b Mon Sep 17 00:00:00 2001 From: Home Assistant Version Control Date: Thu, 8 Oct 2026 17:50:35 +0000 Subject: [PATCH] 3 files --- ...man_on_print_complete.20261008_175027.yaml | 57 +++++++ .ha_mcp/logs/mcp_usage.jsonl | 2 + automations.yaml | 150 ++++++++++++++---- 3 files changed, 175 insertions(+), 34 deletions(-) create mode 100644 .ha_mcp/backups/automation.automation.sparkx_i7_deduct_filament_in_spoolman_on_print_complete.20261008_175027.yaml diff --git a/.ha_mcp/backups/automation.automation.sparkx_i7_deduct_filament_in_spoolman_on_print_complete.20261008_175027.yaml b/.ha_mcp/backups/automation.automation.sparkx_i7_deduct_filament_in_spoolman_on_print_complete.20261008_175027.yaml new file mode 100644 index 00000000..1c44b83c --- /dev/null +++ b/.ha_mcp/backups/automation.automation.sparkx_i7_deduct_filament_in_spoolman_on_print_complete.20261008_175027.yaml @@ -0,0 +1,57 @@ +# ha_mcp_backup +schema_version: 1 +domain: automation +entity_id: automation.sparkx_i7_deduct_filament_in_spoolman_on_print_complete +captured: '2026-10-08T17:50:27.997890+00:00' +tool: ha_config_set_automation +config: + id: '1791477238729' + alias: SparkX i7 - Deduct filament in Spoolman on print complete + triggers: + - trigger: state + entity_id: sensor.sparkx_i7_print_status + from: printing + to: completed + conditions: + - condition: numeric_state + entity_id: sensor.sparkx_i7_filament_weight_estimated + above: 0 + actions: + - variables: + weight: '{{ states(''sensor.sparkx_i7_filament_weight_estimated'') | float(0) + }}' + spool_id: '{{ states(''input_text.sparkx_i7_print_spool_latch'') | int(0) }}' + - choose: + - conditions: + condition: template + value_template: '{{ spool_id > 0 }}' + sequence: + - action: spoolman.use_spool_filament + data: + id: '{{ spool_id | int(0) }}' + use_weight: '{{ weight | float(0) }}' + - action: input_text.set_value + target: + entity_id: input_text.sparkx_i7_print_spool_latch + data: + value: '' + - conditions: + condition: template + value_template: '{{ spool_id <= 0 }}' + sequence: + - action: notify.persistent_notification + data: + title: Spoolman deduction skipped + message: "Print completed: {{ weight }} g used, but no Spoolman spool was\ + \ latched for this print \u2014 nothing deducted." + - action: notify.mobile_app_francos_ipad + data: + title: Spoolman deduction skipped + message: "Print completed: {{ weight }} g used, but no Spoolman spool was\ + \ latched for this print \u2014 nothing deducted." + - action: notify.mobile_app_sm_f956w + data: + title: Spoolman deduction skipped + message: "Print completed: {{ weight }} g used, but no Spoolman spool was\ + \ latched for this print \u2014 nothing deducted." + mode: single diff --git a/.ha_mcp/logs/mcp_usage.jsonl b/.ha_mcp/logs/mcp_usage.jsonl index efaab60d..83a3bb18 100644 --- a/.ha_mcp/logs/mcp_usage.jsonl +++ b/.ha_mcp/logs/mcp_usage.jsonl @@ -4025,3 +4025,5 @@ {"timestamp": "2026-10-08T17:45:59.226035+00:00", "tool_name": "ha_config_get_automation", "parameters": {"identifier": "automation.sparkx_i7_deduct_filament_in_spoolman_on_print_complete"}, "execution_time_ms": 229.57611083984375, "success": true, "error_message": null, "response_size_bytes": 1823, "user_context": null} {"timestamp": "2026-10-08T17:47:57.951850+00:00", "tool_name": "ha_config_set_automation", "parameters": {"config": null, "identifier": "automation.sparkx_i7_deduct_filament_in_spoolman_on_print_complete", "python_transform": "msgc = \"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 with remaining weight matches that color. Register the new roll in Spoolman, then adjust manually if needed.\"\nnt = [{'action': 'notify.persistent_notification', 'data': {'title': 'Spoolman: no spool for slot color', 'message': msgc}}, {'action': 'notify.mobile_app_francos_ipad', 'data': {'title': 'Spoolman: no spool for slot color', 'message': msgc}}, {'action': 'notify.mobile_app_sm_f956w', 'data': {'title': 'Spoolman: no spool for slot color', 'message': msgc}}]\nms = \"Print complete - Spoolman deducted {{ summary_total }} g\\n{{ summary_lines }}\"\nns = [{'action': 'notify.persistent_notification', 'data': {'title': 'Print complete - Spoolman updated', 'message': ms}}, {'action': 'notify.mobile_app_francos_ipad', 'data': {'title': 'Print complete - Spoolman updated', 'message': ms}}, {'action': 'notify.mobile_app_sm_f956w', 'data': {'title': 'Print complete - Spoolman updated', 'message': ms}}]\nconfig['description'] = 'On print completion, deducts the final segment (used_material_length delta since last checkpoint x g/cm) from the Spoolman spool 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.'\nconfig['conditions'] = []\nconfig['actions'] = [\n {'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) }}\"}},\n {'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 }}\"}},\n {'variables': {'spool_id': \"{% 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 %}{{ ns.id }}\"}},\n {'variables': {'helper_idx': \"{{ old_slot.split(' ')[-1] if old_slot.split(' ')[-1] in ['1', '2', '3', '4'] else '' }}\"}},\n {'variables': {'nonhelper_g': \"{{ final_grams if (final_grams | float > 0) and (spool_id not in ['', 'unknown', 'unavailable']) and (helper_idx == '') else 0 }}\"}},\n {'if': {'condition': 'template', 'value_template': '{{ final_grams | float > 0 }}'},\n 'then': [{'choose': [\n {'conditions': {'condition': 'template', 'value_template': \"{{ spool_id not in ['', 'unknown', 'unavailable'] }}\"},\n 'sequence': [\n {'action': 'spoolman.use_spool_filament', 'data': {'id': '{{ spool_id | int(0) }}', 'use_weight': '{{ final_grams | float(0) }}'}},\n {'if': {'condition': 'template', 'value_template': \"{{ helper_idx != '' }}\"},\n '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) }}\"}}]}\n ]}\n ], 'default': nt}]},\n {'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) }}\"}},\n {'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'] %}{{ ns.l | join('\\\\n') }}\"}},\n {'if': {'condition': 'template', 'value_template': '{{ summary_total | float > 0 }}'}, 'then': ns},\n {'action': 'input_number.set_value', 'target': {'entity_id': 'input_number.sparkx_i7_spoolman_length_checkpoint'}, 'data': {'value': '{{ cur }}'}},\n {'action': 'input_text.set_value', 'target': {'entity_id': 'input_text.sparkx_i7_print_spool_latch'}, 'data': {'value': ''}}\n]", "config_hash": "9a6285e4401f42ad", "take_control_of_blueprint": false, "category": null, "wait": true, "enabled": null, "run_actions": false, "MandatoryBPS": true, "BestPracticeKey": null}, "execution_time_ms": 99.09272193908691, "success": false, "error_message": "{\n \"success\": false,\n \"error\": {\n \"code\": \"VALIDATION_FAILED\",\n \"message\": \"Invalid automation configuration: API error: 400 - Message malformed: invalid template (TemplateSyntaxError: unexpected ']', expected ')') at 'actions[7].variables.summary_lines'\",\n \"suggestion\": \"Check automation configuration format\",\n \"suggestions\": [\n \"Check automation configuration format\",\n \"Ensure required fields: alias, triggers, actions\",\n \"Use entity_id format: automation.morning_routine or unique_id\",\n \"Use ha_search(domain_filter='automation') to find automations\",\n \"Use ha_get_skill_guide for automation examples\",\n \"For Home Assistant best-practice guidance, call ha_get_skill_guide() to read SKILL.md, then the reference file its table points to, before retrying.\"\n ]\n },\n \"identifier\": \"automation.sparkx_i7_deduct_filament_in_spoolman_on_print_complete\"\n}", "response_size_bytes": null, "user_context": null} {"timestamp": "2026-10-08T17:49:35.528476+00:00", "tool_name": "ha_config_set_automation", "parameters": {"config": null, "identifier": "automation.sparkx_i7_deduct_filament_in_spoolman_on_print_complete", "python_transform": "msgc = \"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 with remaining weight matches that color. Register the new roll in Spoolman, then adjust manually if needed.\"\nnt = [{'action': 'notify.persistent_notification', 'data': {'title': 'Spoolman: no spool for slot color', 'message': msgc}}, {'action': 'notify.mobile_app_francos_ipad', 'data': {'title': 'Spoolman: no spool for slot color', 'message': msgc}}, {'action': 'notify.mobile_app_sm_f956w', 'data': {'title': 'Spoolman: no spool for slot color', 'message': msgc}}]\nms = \"Print complete - Spoolman deducted {{ summary_total }} g\\n{{ summary_lines }}\"\nns = [{'action': 'notify.persistent_notification', 'data': {'title': 'Print complete - Spoolman updated', 'message': ms}}, {'action': 'notify.mobile_app_francos_ipad', 'data': {'title': 'Print complete - Spoolman updated', 'message': ms}}, {'action': 'notify.mobile_app_sm_f956w', 'data': {'title': 'Print complete - Spoolman updated', 'message': ms}}]\nconfig['description'] = 'On print completion, deducts the final segment (used_material_length delta since last checkpoint x g/cm) from the Spoolman spool 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.'\nconfig['conditions'] = []\nconfig['actions'] = [\n {'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) }}\"}},\n {'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 }}\"}},\n {'variables': {'spool_id': \"{% 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 %}{{ ns.id }}\"}},\n {'variables': {'helper_idx': \"{{ old_slot.split(' ')[-1] if old_slot.split(' ')[-1] in ['1', '2', '3', '4'] else '' }}\"}},\n {'variables': {'nonhelper_g': \"{{ final_grams if (final_grams | float > 0) and (spool_id not in ['', 'unknown', 'unavailable']) and (helper_idx == '') else 0 }}\"}},\n {'if': {'condition': 'template', 'value_template': '{{ final_grams | float > 0 }}'},\n 'then': [{'choose': [\n {'conditions': {'condition': 'template', 'value_template': \"{{ spool_id not in ['', 'unknown', 'unavailable'] }}\"},\n 'sequence': [\n {'action': 'spoolman.use_spool_filament', 'data': {'id': '{{ spool_id | int(0) }}', 'use_weight': '{{ final_grams | float(0) }}'}},\n {'if': {'condition': 'template', 'value_template': \"{{ helper_idx != '' }}\"},\n '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) }}\"}}]}\n ]}\n ], 'default': nt}]},\n {'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) }}\"}},\n {'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'] %}{{ ns.l | join('\\\\n') }}\"}},\n {'if': {'condition': 'template', 'value_template': '{{ summary_total | float > 0 }}'}, 'then': ns},\n {'action': 'input_number.set_value', 'target': {'entity_id': 'input_number.sparkx_i7_spoolman_length_checkpoint'}, 'data': {'value': '{{ cur }}'}},\n {'action': 'input_text.set_value', 'target': {'entity_id': 'input_text.sparkx_i7_print_spool_latch'}, 'data': {'value': ''}}\n]", "config_hash": "9a6285e4401f42ad", "take_control_of_blueprint": false, "category": null, "wait": true, "enabled": null, "run_actions": false, "MandatoryBPS": true, "BestPracticeKey": null}, "execution_time_ms": 213.8080596923828, "success": false, "error_message": "{\n \"success\": false,\n \"error\": {\n \"code\": \"VALIDATION_FAILED\",\n \"message\": \"Invalid automation configuration: API error: 400 - Message malformed: invalid template (TemplateSyntaxError: Unexpected end of template. Jinja was looking for the following tags: 'elif' or 'else' or 'endif'. The innermost block that needs to be closed is 'if'.) at 'actions[7].variables.summary_lines'\",\n \"suggestion\": \"Check automation configuration format\",\n \"suggestions\": [\n \"Check automation configuration format\",\n \"Ensure required fields: alias, triggers, actions\",\n \"Use entity_id format: automation.morning_routine or unique_id\",\n \"Use ha_search(domain_filter='automation') to find automations\",\n \"Use ha_get_skill_guide for automation examples\",\n \"For Home Assistant best-practice guidance, call ha_get_skill_guide() to read SKILL.md, then the reference file its table points to, before retrying.\"\n ]\n },\n \"identifier\": \"automation.sparkx_i7_deduct_filament_in_spoolman_on_print_complete\"\n}", "response_size_bytes": null, "user_context": null} +{"timestamp": "2026-10-08T17:50:28.001933+00:00", "tool_name": "ha_search", "parameters": {"query": "spoolman_spool_3", "domain_filter": null, "area_filter": null, "search_types": null, "limit": 20, "offset": 0, "exact_match": true, "include_hidden": true, "include_config": false, "group_by_domain": false, "per_domain_limit": null, "state_filter": null, "result_fields": ["entity_id", "state"], "fields": null, "config_time_budget": null, "ctx": {"_STATE_TTL_SECONDS": 86400}}, "execution_time_ms": 157.64760971069336, "success": true, "error_message": null, "response_size_bytes": 1924, "user_context": null} +{"timestamp": "2026-10-08T17:50:29.608770+00:00", "tool_name": "ha_config_set_automation", "parameters": {"config": null, "identifier": "automation.sparkx_i7_deduct_filament_in_spoolman_on_print_complete", "python_transform": "msgc = \"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 with remaining weight matches that color. Register the new roll in Spoolman, then adjust manually if needed.\"\nnt = [{'action': 'notify.persistent_notification', 'data': {'title': 'Spoolman: no spool for slot color', 'message': msgc}}, {'action': 'notify.mobile_app_francos_ipad', 'data': {'title': 'Spoolman: no spool for slot color', 'message': msgc}}, {'action': 'notify.mobile_app_sm_f956w', 'data': {'title': 'Spoolman: no spool for slot color', 'message': msgc}}]\nms = \"Print complete - Spoolman deducted {{ summary_total }} g\\n{{ summary_lines }}\"\nns = [{'action': 'notify.persistent_notification', 'data': {'title': 'Print complete - Spoolman updated', 'message': ms}}, {'action': 'notify.mobile_app_francos_ipad', 'data': {'title': 'Print complete - Spoolman updated', 'message': ms}}, {'action': 'notify.mobile_app_sm_f956w', 'data': {'title': 'Print complete - Spoolman updated', 'message': ms}}]\nconfig['description'] = 'On print completion, deducts the final segment (used_material_length delta since last checkpoint x g/cm) from the Spoolman spool 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.'\nconfig['conditions'] = []\nconfig['actions'] = [\n {'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) }}\"}},\n {'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 }}\"}},\n {'variables': {'spool_id': \"{% 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 %}{{ ns.id }}\"}},\n {'variables': {'helper_idx': \"{{ old_slot.split(' ')[-1] if old_slot.split(' ')[-1] in ['1', '2', '3', '4'] else '' }}\"}},\n {'variables': {'nonhelper_g': \"{{ final_grams if (final_grams | float > 0) and (spool_id not in ['', 'unknown', 'unavailable']) and (helper_idx == '') else 0 }}\"}},\n {'if': {'condition': 'template', 'value_template': '{{ final_grams | float > 0 }}'},\n 'then': [{'choose': [\n {'conditions': {'condition': 'template', 'value_template': \"{{ spool_id not in ['', 'unknown', 'unavailable'] }}\"},\n 'sequence': [\n {'action': 'spoolman.use_spool_filament', 'data': {'id': '{{ spool_id | int(0) }}', 'use_weight': '{{ final_grams | float(0) }}'}},\n {'if': {'condition': 'template', 'value_template': \"{{ helper_idx != '' }}\"},\n '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) }}\"}}]}\n ]}\n ], 'default': nt}]},\n {'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) }}\"}},\n {'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') }}\"}},\n {'if': {'condition': 'template', 'value_template': '{{ summary_total | float > 0 }}'}, 'then': ns},\n {'action': 'input_number.set_value', 'target': {'entity_id': 'input_number.sparkx_i7_spoolman_length_checkpoint'}, 'data': {'value': '{{ cur }}'}},\n {'action': 'input_text.set_value', 'target': {'entity_id': 'input_text.sparkx_i7_print_spool_latch'}, 'data': {'value': ''}}\n]", "config_hash": "9a6285e4401f42ad", "take_control_of_blueprint": false, "category": null, "wait": true, "enabled": null, "run_actions": false, "MandatoryBPS": true, "BestPracticeKey": null}, "execution_time_ms": 1595.430850982666, "success": true, "error_message": null, "response_size_bytes": 84889, "user_context": null} diff --git a/automations.yaml b/automations.yaml index 7d63eaba..20e8c4b6 100644 --- a/automations.yaml +++ b/automations.yaml @@ -4376,53 +4376,135 @@ | int }}' - 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 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: - - condition: numeric_state - entity_id: sensor.sparkx_i7_filament_weight_estimated - above: 0 + conditions: [] actions: - variables: - weight: '{{ states(''sensor.sparkx_i7_filament_weight_estimated'') | float(0) - }}' - spool_id: '{{ states(''input_text.sparkx_i7_print_spool_latch'') | int(0) }}' - - choose: - - conditions: - condition: template - value_template: '{{ spool_id > 0 }}' - sequence: - - action: spoolman.use_spool_filament - data: - id: '{{ spool_id | int(0) }}' - use_weight: '{{ weight | float(0) }}' - - action: input_text.set_value - target: - entity_id: input_text.sparkx_i7_print_spool_latch - data: - value: '' - - conditions: - condition: template - value_template: '{{ spool_id <= 0 }}' - sequence: + 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 %}{% 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 deduction skipped - message: 'Print completed: {{ weight }} g used, but no Spoolman spool was - latched for this print — nothing deducted.' + 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 with remaining weight matches + that color. Register the new roll in Spoolman, then adjust manually if + needed.' - action: notify.mobile_app_francos_ipad data: - title: Spoolman deduction skipped - message: 'Print completed: {{ weight }} g used, but no Spoolman spool was - latched for this print — nothing deducted.' + 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 with remaining weight matches + that color. Register the new roll in Spoolman, then adjust manually if + needed.' - action: notify.mobile_app_sm_f956w data: - title: Spoolman deduction skipped - message: 'Print completed: {{ weight }} g used, but no Spoolman spool was - latched for this print — nothing deducted.' + 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 with remaining weight matches + that color. Register the new roll in Spoolman, 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_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 - id: '1791477238762' alias: SparkX i7 - Latch print spool for Spoolman