From e306c60ee04d2afcc2dbdb69e63cce76384b8b2a Mon Sep 17 00:00:00 2001 From: Home Assistant Version Control Date: Mon, 12 Oct 2026 16:31:21 +0000 Subject: [PATCH] 3 files --- ...omation.1791477238762.20261012_163106.yaml | 152 ++++++++++++++++++ ...omation.1791477238762.20261012_163120.yaml | 152 ++++++++++++++++++ .ha_mcp/logs/mcp_usage.jsonl | 2 + 3 files changed, 306 insertions(+) create mode 100644 .ha_mcp/backups/automation.1791477238762.20261012_163106.yaml create mode 100644 .ha_mcp/backups/automation.1791477238762.20261012_163120.yaml diff --git a/.ha_mcp/backups/automation.1791477238762.20261012_163106.yaml b/.ha_mcp/backups/automation.1791477238762.20261012_163106.yaml new file mode 100644 index 00000000..566eecac --- /dev/null +++ b/.ha_mcp/backups/automation.1791477238762.20261012_163106.yaml @@ -0,0 +1,152 @@ +# ha_mcp_backup +schema_version: 1 +domain: automation +entity_id: '1791477238762' +captured: '2026-10-12T16:31:06.438795+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 (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 }}' + - 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 diff --git a/.ha_mcp/backups/automation.1791477238762.20261012_163120.yaml b/.ha_mcp/backups/automation.1791477238762.20261012_163120.yaml new file mode 100644 index 00000000..0573e25f --- /dev/null +++ b/.ha_mcp/backups/automation.1791477238762.20261012_163120.yaml @@ -0,0 +1,152 @@ +# ha_mcp_backup +schema_version: 1 +domain: automation +entity_id: '1791477238762' +captured: '2026-10-12T16:31:20.387625+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 (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 }}' + - 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 diff --git a/.ha_mcp/logs/mcp_usage.jsonl b/.ha_mcp/logs/mcp_usage.jsonl index 97882206..b1a615b4 100644 --- a/.ha_mcp/logs/mcp_usage.jsonl +++ b/.ha_mcp/logs/mcp_usage.jsonl @@ -4458,3 +4458,5 @@ {"timestamp": "2026-10-12T16:25:49.085943+00:00", "tool_name": "ha_search", "parameters": {"query": "sparkx_i7", "domain_filter": "input_number", "area_filter": null, "search_types": null, "limit": 50, "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": 71.00105285644531, "success": true, "error_message": null, "response_size_bytes": 1275, "user_context": null} {"timestamp": "2026-10-12T16:25:49.093161+00:00", "tool_name": "ha_get_overview", "parameters": {"detail_level": "minimal", "domains": null, "limit": null, "offset": 0, "max_entities_per_domain": null, "include_state": null, "include_entity_id": null, "include_notifications": true, "include_dismissed_repairs": false, "fields": ["notifications", "notification_count"]}, "execution_time_ms": 65.95253944396973, "success": true, "error_message": null, "response_size_bytes": 377, "user_context": null} {"timestamp": "2026-10-12T16:29:38.717387+00:00", "tool_name": "ha_eval_template", "parameters": {"template": "{{ (states('input_number.sparkx_i7_filament_g_cm') | float) }} | {{ (1992.9 * (states('input_number.sparkx_i7_filament_g_cm') | float)) | round(1) }} | {{ (((1992.9 * (states('input_number.sparkx_i7_filament_g_cm') | float)) | round(1)) * (states('input_number.filament_price_per_kg') | float(25)) / 1000) | round(2) }}", "condition": null, "variables": null, "strict": false, "timeout": 3, "report_errors": true}, "execution_time_ms": 19.358396530151367, "success": true, "error_message": null, "response_size_bytes": 537, "user_context": null} +{"timestamp": "2026-10-12T16:31:06.568338+00:00", "tool_name": "ha_config_set_automation", "parameters": {"config": null, "identifier": "1791477238762", "python_transform": "stack = [config]\nfor _ in range(500):\n if not stack:\n break\n node = stack.pop()\n if isinstance(node, dict):\n for k in list(node.keys()):\n if isinstance(node[k], str) and \"split(' ')\" in node[k]:\n node[k] = node[k].replace(\"split(' ')\", \"split('_')\")\n elif isinstance(node[k], (dict, list)):\n stack.append(node[k])\n elif isinstance(node, list):\n for i in range(len(node)):\n if isinstance(node[i], str) and \"split(' ')\" in node[i]:\n node[i] = node[i].replace(\"split(' ')\", \"split('_')\")\n elif isinstance(node[i], (dict, list)):\n stack.append(node[i])", "config_hash": "ea2dd4d9f2623a01", "take_control_of_blueprint": false, "category": null, "wait": true, "enabled": null, "run_actions": false, "MandatoryBPS": false, "BestPracticeKey": null}, "execution_time_ms": 105.04531860351562, "success": false, "error_message": "{\n \"success\": false,\n \"error\": {\n \"code\": \"SERVICE_CALL_FAILED\",\n \"message\": \"Automation modified since last read (conflict)\",\n \"suggestion\": \"Call ha_config_get_automation() again\",\n \"suggestions\": [\n \"Call ha_config_get_automation() again\",\n \"Use the fresh config_hash from that response\",\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 \"action\": \"python_transform\",\n \"identifier\": \"1791477238762\"\n}", "response_size_bytes": null, "user_context": null} +{"timestamp": "2026-10-12T16:31:14.057677+00:00", "tool_name": "ha_config_get_automation", "parameters": {"identifier": "1791477238762"}, "execution_time_ms": 357.1889400482178, "success": true, "error_message": null, "response_size_bytes": 5672, "user_context": null}