Skip to content

Commit 3e35634

Browse files
authored
Implement automated update management for Home Assistant
Added a comprehensive automation for managing, filtering, and installing updates for Home Assistant Core, add-ons, and integrations, including features like automatic backups and detailed notifications.
1 parent 36bbbad commit 3e35634

File tree

1 file changed

+320
-0
lines changed

1 file changed

+320
-0
lines changed

blueprint

Lines changed: 320 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,320 @@
1+
blueprint:
2+
name: Automatisierte Update-Verwaltung
3+
description: >-
4+
Eine umfassende Automatisierung zur Verwaltung, Filterung und Installation von Updates
5+
für Home Assistant Core, Add-ons, Integrationen und mehr.
6+
Inklusive automatischer Backups, detaillierter Benachrichtigungen und intelligenter Neustart-Logik.
7+
domain: automation
8+
input:
9+
# Auslöser
10+
schedule_trigger:
11+
name: Zeitplan für Updates
12+
description: Wähle einen Helfer mit einem Zeitplan (schedule), wann die Updates gestartet werden sollen.
13+
selector:
14+
entity:
15+
domain: schedule
16+
17+
# Update-Filterung
18+
update_exclusions:
19+
name: Updates ausschließen
20+
description: Wähle Update-Entitäten aus, die von dieser Automatisierung ignoriert werden sollen.
21+
selector:
22+
entity:
23+
domain: update
24+
multiple: true
25+
default: {}
26+
27+
# Versionssprung-Filter
28+
core_os_update_level:
29+
name: Update-Stufe für Core & OS
30+
description: Wähle, welche Art von Versionssprüngen für Core- und OS-Updates installiert werden sollen.
31+
selector:
32+
select:
33+
options:
34+
- label: Nur Patches (z.B. 2023.10.1 -> 2023.10.2)
35+
value: 'patch'
36+
- label: Patches und Minor-Updates (z.B. 2023.10.x -> 2023.11.0)
37+
value: 'minor'
38+
- label: Alle (Major, Minor, Patches)
39+
value: 'all'
40+
default: 'patch'
41+
42+
firmware_update_level:
43+
name: Update-Stufe für Firmware
44+
description: Wähle, welche Art von Versionssprüngen für Firmware-Updates installiert werden sollen.
45+
selector:
46+
select:
47+
options:
48+
- label: Nur Patches
49+
value: 'patch'
50+
- label: Patches und Minor-Updates
51+
value: 'minor'
52+
- label: Alle
53+
value: 'all'
54+
default: 'minor'
55+
56+
general_update_level:
57+
name: Update-Stufe für allgemeine Updates
58+
description: Wähle, welche Art von Versionssprüngen für Add-ons, Integrationen etc. installiert werden sollen.
59+
selector:
60+
select:
61+
options:
62+
- label: Nur Patches
63+
value: 'patch'
64+
- label: Patches und Minor-Updates
65+
value: 'minor'
66+
- label: Alle
67+
value: 'all'
68+
default: 'all'
69+
70+
# Pre-Update-Aktionen
71+
create_backup:
72+
name: Backup vor Updates erstellen
73+
description: Erstellt ein vollständiges Backup von Home Assistant vor der Installation der Updates.
74+
selector:
75+
boolean:
76+
default: true
77+
78+
max_backup_age_seconds:
79+
name: Maximales Backup-Alter in Sekunden
80+
description: Wenn ein Backup jünger ist als dieser Wert, wird kein neues erstellt (Standard: 43200s = 12 Stunden).
81+
selector:
82+
number:
83+
min: 3600
84+
max: 86400
85+
unit_of_measurement: "Sekunden"
86+
default: 43200
87+
88+
notify_device:
89+
name: Benachrichtigungsgerät
90+
description: Das Gerät, das Benachrichtigungen über den Update-Prozess erhält.
91+
selector:
92+
device:
93+
integration: mobile_app
94+
95+
# Sonstige/Optionale Funktionen
96+
pause_entities:
97+
name: Updates pausieren (Entitäten)
98+
description: Wenn eine dieser Entitäten 'on' oder 'true' ist, wird das Update nicht gestartet.
99+
selector:
100+
entity:
101+
domain:
102+
- input_boolean
103+
- binary_sensor
104+
multiple: true
105+
default: {}
106+
107+
force_restart_for_hacs:
108+
name: Neustart für HACS erzwingen
109+
description: Erzwingt einen Neustart, wenn eine HACS-Integration aktualisiert wurde.
110+
selector:
111+
boolean:
112+
default: true
113+
114+
restart_type:
115+
name: Neustart-Typ
116+
description: Wähle die Art des Neustarts, der nach den Updates durchgeführt werden soll (falls erforderlich).
117+
selector:
118+
select:
119+
options:
120+
- label: Core Neustart
121+
value: 'core'
122+
- label: Host-Neustart (System)
123+
value: 'host'
124+
default: 'core'
125+
126+
verbose_logging_bool:
127+
name: Detaillierte Protokollierung (Debugging)
128+
description: Aktiviert zusätzliche Log-Einträge zur Fehlerbehebung.
129+
selector:
130+
boolean:
131+
default: false
132+
133+
variables:
134+
# Eingabevariablen
135+
schedule: !input schedule_trigger
136+
exclusions: !input update_exclusions
137+
core_os_level: !input core_os_update_level
138+
firmware_level: !input firmware_update_level
139+
general_level: !input general_update_level
140+
create_backup: !input create_backup
141+
max_backup_age: !input max_backup_age_seconds
142+
notify_device: !input notify_device
143+
pause_entities: !input pause_entities
144+
force_restart_for_hacs: !input force_restart_for_hacs
145+
restart_type: !input restart_type
146+
verbose_logging: !input verbose_logging_bool
147+
148+
# Filterlogik für Updates
149+
all_available_updates: >
150+
{{ states.update
151+
| selectattr('state', 'eq', 'on')
152+
| map(attribute='entity_id')
153+
| reject('in', exclusions)
154+
| list }}
155+
156+
# Semantische Versionierungsprüfung (Helfer-Template)
157+
is_allowed_update: >
158+
{% macro is_allowed(installed, latest, level) %}
159+
{% set installed_parts = installed.split('.') %}
160+
{% set latest_parts = latest.split('.') %}
161+
{% if installed_parts | length < 3 or latest_parts | length < 3 %}
162+
{{ true }} {# Fallback für nicht-semantische Versionen #}
163+
{% else %}
164+
{% set i_major = installed_parts[0] | int %}
165+
{% set i_minor = installed_parts[1] | int %}
166+
{% set i_patch = installed_parts[2] | int %}
167+
{% set l_major = latest_parts[0] | int %}
168+
{% set l_minor = latest_parts[1] | int %}
169+
{% set l_patch = latest_parts[2] | int %}
170+
171+
{% if level == 'patch' and i_major == l_major and i_minor == l_minor and i_patch < l_patch %}
172+
{{ true }}
173+
{% elif level == 'minor' and i_major == l_major and (i_minor < l_minor or (i_minor == l_minor and i_patch < l_patch)) %}
174+
{{ true }}
175+
{% elif level == 'all' %}
176+
{{ true }}
177+
{% else %}
178+
{{ false }}
179+
{% endif %}
180+
{% endif %}
181+
{% endmacro %}
182+
183+
trigger:
184+
- platform: time
185+
at: "00:00:01"
186+
- platform: homeassistant
187+
event: start
188+
- platform: event
189+
event_type: automation_reloaded
190+
- platform: state
191+
entity_id: !input schedule_trigger
192+
to: 'on'
193+
- platform: state
194+
entity_id: sensor.potential_updates # Erfordert einen Template-Sensor, der alle Updates zählt
195+
from: '0'
196+
197+
condition:
198+
- condition: template
199+
value_template: "{{ states(schedule) == 'on' }}"
200+
- condition: template
201+
value_template: "{{ expand(pause_entities) | selectattr('state', 'in', ['on', 'true']) | list | count == 0 }}"
202+
- condition: template
203+
value_template: "{{ all_available_updates | count > 0 }}"
204+
205+
action:
206+
- service: homeassistant.update_entity
207+
target:
208+
entity_id: "{{ states.update | map(attribute='entity_id') | list }}"
209+
- delay: '00:00:10' # Wartezeit, damit die Entitäten aktualisiert werden
210+
211+
- choose:
212+
- conditions: "{{ verbose_logging }}"
213+
sequence:
214+
- service: persistent_notification.create
215+
data:
216+
title: "Update-Automatisierung"
217+
message: "Verfügbare Updates gefunden: {{ all_available_updates | join(', ') }}"
218+
219+
- if:
220+
- condition: template
221+
value_template: "{{ create_backup }}"
222+
- condition: template
223+
value_template: >-
224+
{% set last_backup = states.sensor.backup_state.attributes.last_backup %}
225+
{% if last_backup is not none %}
226+
{{ (now() - as_datetime(last_backup)).total_seconds() > max_backup_age }}
227+
{% else %}
228+
true
229+
{% endif %}
230+
then:
231+
- service: notify.devices
232+
data:
233+
title: "Backup wird erstellt"
234+
message: "Ein vollständiges Backup wird vor den Updates erstellt."
235+
target: !input notify_device
236+
- service: hassio.backup_full
237+
data:
238+
name: "Automatisches Backup vor Update {{ now().strftime('%Y-%m-%d') }}"
239+
- delay: '00:01:00' # Wartezeit nach Backup-Start
240+
241+
- service: notify.devices
242+
data:
243+
title: "Updates werden gestartet"
244+
message: "Die Installation der folgenden Updates beginnt: {{ all_available_updates | join(', ') }}"
245+
target: !input notify_device
246+
247+
- variables:
248+
hacs_update_done: false
249+
250+
- repeat:
251+
for_each: "{{ all_available_updates }}"
252+
sequence:
253+
- variables:
254+
entity: "{{ repeat.item }}"
255+
installed_version: "{{ state_attr(entity, 'installed_version') }}"
256+
latest_version: "{{ state_attr(entity, 'latest_version') }}"
257+
allowed: >-
258+
{% set level = 'general' %}
259+
{% if 'core' in entity or 'operating_system' in entity %}
260+
{% set level = core_os_level %}
261+
{% elif 'firmware' in entity %}
262+
{% set level = firmware_level %}
263+
{% endif %}
264+
{{ is_allowed(installed_version, latest_version, level) }}
265+
266+
- if:
267+
- condition: template
268+
value_template: "{{ allowed | bool }}"
269+
then:
270+
- choose:
271+
- conditions: "{{ verbose_logging }}"
272+
sequence:
273+
- service: persistent_notification.create
274+
data:
275+
title: "Update wird installiert"
276+
message: "Installiere {{ entity }} (von {{ installed_version }} auf {{ latest_version }})"
277+
278+
- service: update.install
279+
target:
280+
entity_id: "{{ entity }}"
281+
data:
282+
backup: false # Backup wurde bereits erstellt
283+
- wait_for_template:
284+
template: "{{ states(entity) == 'off' }}"
285+
timeout:
286+
hours: 1
287+
continue_on_timeout: true
288+
289+
- if:
290+
- condition: template
291+
value_template: "{{ 'hacs' in entity and force_restart_for_hacs }}"
292+
then:
293+
- variables:
294+
hacs_update_done: true
295+
296+
# Neustart-Logik
297+
- delay: '00:00:30' # Kurze Pause vor der Neustart-Prüfung
298+
- choose:
299+
- conditions:
300+
- condition: template
301+
value_template: "{{ hacs_update_done }}"
302+
sequence:
303+
- service: notify.devices
304+
data:
305+
title: "Neustart erforderlich"
306+
message: "Ein Neustart ist nach der HACS-Aktualisierung erforderlich und wird durchgeführt."
307+
target: !input notify_device
308+
- choose:
309+
- conditions: "{{ restart_type == 'host' }}"
310+
sequence:
311+
- service: hassio.host_reboot
312+
- conditions: "{{ restart_type == 'core' }}"
313+
sequence:
314+
- service: homeassistant.restart
315+
default:
316+
- service: notify.devices
317+
data:
318+
title: "Updates abgeschlossen"
319+
message: "Alle Updates wurden erfolgreich installiert. Kein Neustart erforderlich."
320+
target: !input notify_device

0 commit comments

Comments
 (0)