You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

300 lines
15 KiB

######################################################################
# @CCOSTAN - Follow Me on X
# For more info visit https://www.vcloudinfo.com/click-here
# Original Repo : https://github.com/CCOSTAN/Home-AssistantConfig
# -------------------------------------------------------------------
# Tugtainer Updates - Container update notifications via webhook
# Related Issue: 1561
# Receives Apprise JSON payloads from Tugtainer and posts outcome alerts.
# -------------------------------------------------------------------
# Notes: Expects JSON with title/message/type from the Tugtainer template.
# Notes: Available-only reports stay silent in HA; Updated, Failed, and Rolled-back reports remain visible.
# Notes: Fires update events independently when a report has both Available and Updated sections.
# Notes: Fires `tugtainer_home_assistant_core_updated` when `### Updated:` includes Home Assistant.
# Notes: Every Available report dispatches Joanna; Tugtainer owns report scheduling and de-duplication.
# Notes: Home Assistant changelog dispatch uses core-YYYY.M URL format from parsed/fallback version.
# Notes: Home Assistant is auto-update eligible after its Tugtainer pre-update config check; no per-release approval is required.
# Notes: Portainer image-update entities are auto-disabled because Tugtainer/Compose own container rollouts.
# - Video: https://youtu.be/4NNOkXzUyYw
# - Blog: https://www.vcloudinfo.com/2026/07/home-assistant-tugtainer-docker-updates.html
# Notes: Changelog digest follow-up https://www.vcloudinfo.com/2026/04/joanna-home-assistant-changelog-digest-tugtainer.html
# Notes: Prior background post https://www.vcloudinfo.com/2026/02/tugtainer-docker-updates-home-assistant-notifications.html
######################################################################
input_datetime:
tugtainer_last_update:
name: "Tugtainer last update"
has_date: true
has_time: true
automation:
- alias: "Tugtainer - Disable Duplicate Portainer Image Updates"
id: tugtainer_disable_duplicate_portainer_image_updates
description: "Keep Portainer's per-container image-update entities disabled while preserving its health telemetry."
mode: queued
trigger:
- platform: event
event_type: entity_registry_updated
event_data:
action: create
- platform: homeassistant
event: start
variables:
portainer_update_entities: >-
{% set found = namespace(entities=[]) %}
{% if trigger.platform == 'event' %}
{% set candidate = trigger.event.data.entity_id | default('', true) | string %}
{% if candidate.startswith('update.') and
candidate.endswith('_image_update_available') and
config_entry_attr(config_entry_id(candidate), 'domain') == 'portainer' %}
{% set found.entities = [candidate] %}
{% endif %}
{% else %}
{% for candidate in states.update | map(attribute='entity_id') | list %}
{% if candidate.endswith('_image_update_available') and
config_entry_attr(config_entry_id(candidate), 'domain') == 'portainer' %}
{% set found.entities = found.entities + [candidate] %}
{% endif %}
{% endfor %}
{% endif %}
{{ found.entities }}
condition:
- condition: template
value_template: "{{ portainer_update_entities | count > 0 }}"
action:
- repeat:
for_each: "{{ portainer_update_entities }}"
sequence:
- service: homeassistant.disable_entity
data:
entity_id: "{{ repeat.item }}"
- service: script.send_to_logbook
data:
topic: "DOCKER"
message: >-
Disabled {{ portainer_update_entities | count }} duplicate Portainer
image-update {{ 'entity' if portainer_update_entities | count == 1 else 'entities' }};
Tugtainer and Compose remain the rollout owners.
- alias: "Tugtainer Update Report"
id: tugtainer_update_report
description: "Receive Tugtainer reports, suppress Available-only alerts, and dispatch update work."
mode: queued
trigger:
- platform: webhook
webhook_id: !secret tugtainer_updates_webhook
allowed_methods:
- POST
local_only: true
variables:
payload: "{{ trigger.json | default({}) }}"
title: "{{ payload.title | default('Tugtainer update') }}"
message: "{{ payload.message | default('Update event received') }}"
event_type: "{{ payload.type | default('info') }}"
has_available_section: "{{ '### available:' in (message | lower) }}"
has_failed_section: "{{ '### failed:' in (message | lower) }}"
has_rolled_back_section: "{{ '### rolled-back:' in (message | lower) }}"
has_failure_section: "{{ has_failed_section or has_rolled_back_section }}"
updated_section: >-
{% set sections = message | regex_findall('(?is)###\\s*updated:\\s*(.*?)(?:\\n###\\s|$)') %}
{{ sections[0] if sections | count > 0 else '' }}
has_updated_section: "{{ updated_section | trim != '' }}"
show_persistent_notification: >-
{{ not has_available_section or has_updated_section or has_failure_section }}
ha_updated_line: >-
{% set matches = updated_section | regex_findall('(?im)^.*(?:home-assistant|ghcr\\.io/home-assistant/home-assistant).*$') %}
{{ matches[0] if matches | count > 0 else '' }}
ha_core_update_detected: "{{ has_updated_section and (ha_updated_line | trim != '') }}"
ha_version_from_updated_line: >-
{% set arrow_match = ha_updated_line | regex_findall('(?i)(?:->|→|to)\\s*v?([0-9]{4}\\.[0-9]+(?:\\.[0-9]+)?)') %}
{% if arrow_match | count > 0 %}
{{ arrow_match[-1] }}
{% else %}
{% set any_match = ha_updated_line | regex_findall('(?i)v?([0-9]{4}\\.[0-9]+(?:\\.[0-9]+)?)') %}
{{ any_match[-1] if any_match | count > 0 else '' }}
{% endif %}
ha_sensor_version: "{{ states('sensor.ha_installed_version') | string | trim }}"
ha_core_version_full: >-
{% set parsed = ha_version_from_updated_line | trim %}
{% if parsed != '' %}
{{ parsed }}
{% else %}
{% set sensor_matches = ha_sensor_version | regex_findall('([0-9]{4}\\.[0-9]+(?:\\.[0-9]+)?)') %}
{{ sensor_matches[0] if sensor_matches | count > 0 else '' }}
{% endif %}
ha_core_version_minor: >-
{% set minor = ha_core_version_full | trim | regex_findall('^([0-9]{4}\\.[0-9]+)') %}
{{ minor[0] if minor | count > 0 else '' }}
ha_core_changelog_url: >-
{% if ha_core_version_minor | trim != '' %}
https://www.home-assistant.io/changelogs/core-{{ ha_core_version_minor | trim }}
{% else %}
{% endif %}
ha_report_excerpt: >-
{% set excerpt = ha_updated_line | trim %}
{{ excerpt if excerpt != '' else (message | truncate(280, true)) }}
full_message: >-
{{ message }}{% if event_type %} ({{ event_type | upper }}){% endif %}
action:
- service: input_datetime.set_datetime
target:
entity_id: input_datetime.tugtainer_last_update
data:
datetime: "{{ now().strftime('%Y-%m-%d %H:%M:%S') }}"
- if:
- condition: template
value_template: "{{ show_persistent_notification }}"
then:
- service: persistent_notification.create
data:
title: "{{ title }}"
message: "{{ full_message }}"
- if:
- condition: template
value_template: "{{ has_available_section }}"
then:
- event: tugtainer_available_detected
event_data:
title: "{{ title }}"
event_type: "{{ event_type }}"
message: "{{ message }}"
- if:
- condition: template
value_template: "{{ has_failure_section }}"
then:
- service: script.send_to_logbook
data:
topic: "DOCKER"
message: >-
Tugtainer reported failed or rolled-back container updates.
Joanna dispatch requested.
- service: script.joanna_dispatch
data:
trigger_context: "HA automation tugtainer_update_report (Tugtainer Update Report)"
source: "home_assistant_automation.tugtainer_update_report"
summary: "Tugtainer reported failed or rolled-back container updates"
entity_ids:
- "input_datetime.tugtainer_last_update"
diagnostics: >-
title={{ title }},
event_type={{ event_type }},
failed_section={{ has_failed_section }},
rolled_back_section={{ has_rolled_back_section }},
message={{ message }}
request: >-
Investigate this Tugtainer failure report. Inspect the owning Docker
host, Tugtainer logs, and live container state before changing
anything. Recover failed or rolled-back services through their
Compose definitions when safe, verify application health, and
reconcile Tugtainer state. For a Home Assistant failure, use its
validated configuration, retained prior image, HTTP healthcheck,
and owning Compose definition to recover it without waiting for
per-release approval. Report what was fixed and any remaining
blockers.
- if:
- condition: template
value_template: "{{ ha_core_update_detected and (ha_core_version_minor | trim != '') }}"
then:
- event: tugtainer_home_assistant_core_updated
event_data:
title: "{{ title }}"
event_type: "{{ event_type }}"
message: "{{ message }}"
core_version_full: "{{ ha_core_version_full | trim }}"
core_version_minor: "{{ ha_core_version_minor | trim }}"
changelog_url: "{{ ha_core_changelog_url | trim }}"
report_excerpt: "{{ ha_report_excerpt | trim }}"
- alias: "Tugtainer - Dispatch Joanna For Available Updates"
id: tugtainer_dispatch_joanna_for_available_updates
description: "Dispatch Joanna for every Tugtainer Available report."
mode: queued
trigger:
- platform: event
event_type: tugtainer_available_detected
variables:
title: "{{ trigger.event.data.title | default('Tugtainer update') }}"
message: "{{ trigger.event.data.message | default('Update event received') }}"
event_type: "{{ trigger.event.data.event_type | default('info') }}"
trigger_context: "HA automation tugtainer_dispatch_joanna_for_available_updates (Tugtainer - Dispatch Joanna For Available Updates)"
action:
- service: script.send_to_logbook
data:
topic: "DOCKER"
message: >-
Tugtainer reported Available container updates. Joanna dispatch requested.
- service: script.joanna_dispatch
data:
trigger_context: "{{ trigger_context }}"
source: "home_assistant_automation.tugtainer_dispatch_joanna_for_available_updates"
summary: "Tugtainer reported container updates scheduled for automatic rollout"
entity_ids:
- "input_datetime.tugtainer_last_update"
diagnostics: >-
title={{ title }},
event_type={{ event_type }},
message={{ message }}
request: >-
Review the Tugtainer report for containers listed under Available.
Eligible containers, including Home Assistant core, are scheduled for
Tugtainer's 07:00 automatic rollout and do not require per-release
approval. When Home Assistant is listed, confirm its pre-update config
check, HTTP healthcheck, and rollback safeguards remain configured;
do not race the scheduled rollout with an early manual recreation.
Protected Tugtainer control-plane containers cannot self-update; update
those one host at a time through their owning Compose definitions when
low-risk. Verify the scheduled and manual updates, reconcile Tugtainer's
inventory, and report any failures or rollbacks.
- alias: "Tugtainer - Dispatch Joanna For Home Assistant Core Digest"
id: tugtainer_dispatch_joanna_for_home_assistant_core_digest
description: "Dispatch Joanna after Home Assistant core is updated so relevant changelog notes reach the morning digest."
mode: queued
trigger:
- platform: event
event_type: tugtainer_home_assistant_core_updated
variables:
report_title: "{{ trigger.event.data.title | default('Tugtainer update') }}"
report_message: "{{ trigger.event.data.message | default('Update event received') }}"
report_event_type: "{{ trigger.event.data.event_type | default('info') }}"
core_version_full: "{{ trigger.event.data.core_version_full | default('', true) | string | trim }}"
core_version_minor: "{{ trigger.event.data.core_version_minor | default('', true) | string | trim }}"
changelog_url: "{{ trigger.event.data.changelog_url | default('', true) | string | trim }}"
report_excerpt: "{{ trigger.event.data.report_excerpt | default('', true) | string | replace('\n', ' ') | replace('\r', ' ') | trim }}"
trigger_context: "HA automation tugtainer_dispatch_joanna_for_home_assistant_core_digest (Tugtainer - Dispatch Joanna For Home Assistant Core Digest)"
structured_request: |-
HA_CORE_UPDATE_DIGEST_REQUEST
core_version_full={{ core_version_full }}
core_version_minor={{ core_version_minor }}
changelog_url={{ changelog_url }}
report_title={{ report_title | string | replace('\n', ' ') | trim }}
report_event_type={{ report_event_type }}
report_excerpt={{ report_excerpt }}
condition:
- condition: template
value_template: "{{ core_version_minor != '' and changelog_url != '' }}"
action:
- service: script.send_to_logbook
data:
topic: "DOCKER"
message: >-
Home Assistant core update detected via Tugtainer ({{ core_version_full }}).
Joanna digest dispatch requested.
- service: script.joanna_dispatch
data:
trigger_context: "{{ trigger_context }}"
source: "home_assistant_automation.tugtainer_home_assistant_core_digest"
summary: >-
Home Assistant core updated to {{ core_version_full }} via Tugtainer.
Queue a concise changelog note for the morning digest.
entity_ids:
- "input_datetime.tugtainer_last_update"
diagnostics: >-
report_title={{ report_title }},
report_event_type={{ report_event_type }},
core_version_full={{ core_version_full }},
core_version_minor={{ core_version_minor }},
changelog_url={{ changelog_url }}
request: "{{ structured_request }}"

Powered by TurnKey Linux.