|
| 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