composer/plans/Plan-HA-upgrade.md
padriano a36751b7ca retarget HA upgrade plan to 2026.5.4 (latest 2026.5 patch)
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 14:41:42 +01:00

11 KiB
Raw Permalink Blame History

Home Assistant Upgrade Plan: 2024.5.4 → 2026.5.4 (revised)

Direct jump (no intermediate version stops). Two structural compose changes are folded into this upgrade: bump the image: tag, and swap the healthcheck endpoint to one that doesn't require auth on modern HA.

Current versions

  • Core: 2024.5.4
  • Frontend: 20240501.1

Target versions (as of May 2026)

  • Core: 2026.5.4 (released May 22, 2026) — the final/latest patch of the 2026.5 line (there is no 2026.5.5; 2026.6.0 shipped June 3, 2026). Bug-fix-only over 2026.5.0, so no additional breaking changes vs. that release.
  • Frontend: bundled inside the core image, version tracks the chosen core tag — no separate action needed

Scope

The Home Assistant instance runs as a Docker container defined in docker-compose.yml, pinned to homeassistant/home-assistant:2024.5.4. The config is volume-mounted at /home/padriano/projects/ha/config.

1. Pre-flight checks (read-only)

Before touching anything, gather facts and confirm assumptions:

  • Architecture: uname -m — confirm x86_64 (the official HA image supports it; armhf was dropped in 2025).

  • Custom components / HACS: ls /home/padriano/projects/ha/config/custom_components 2>/dev/null — currently empty, good. If anything appears, abort and check each integration's HA 2026.5 compatibility first.

  • USB device passthrough: confirm no devices: mapping in docker-compose.yml (none today — no Z-Wave/Zigbee radios at risk).

  • Recorder DB size: du -sh /home/padriano/projects/ha/config/home-assistant_v2.db* — record this. The bigger it is, the longer the first-boot schema migration will take.

  • Free disk: df -h /home/padriano/projects/ha — already 405 GB free, plenty for backup + image pull.

  • Current version (auth-free):

    docker exec homeassistant python -c "from homeassistant.const import __version__; print(__version__)"
    # expected: 2024.5.4
    

    (The old curl /api/ | grep version is unreliable and won't work post-upgrade because /api/ requires auth on modern HA.)

  • Current container health:

    docker inspect --format '{{.State.Health.Status}}' homeassistant
    # expected: healthy
    
  • Reverse-proxy reachability:

    curl -fsS -o /dev/null -w "%{http_code}\n" https://ha-padriano.duckdns.org
    # record current status code so we can compare post-upgrade
    

2. Backups

2a. Record image digest and pin a local rollback tag

docker inspect --format '{{.Image}}' homeassistant > /home/padriano/projects/ha/image-digest-2024.5.4.txt
docker tag "$(cat /home/padriano/projects/ha/image-digest-2024.5.4.txt)" homeassistant/home-assistant:2024.5.4-rollback

The local :2024.5.4-rollback tag guarantees the exact previous image stays resolvable even if the upstream :2024.5.4 tag is ever repushed or GC'd.

2b. Create a HA backup from within Home Assistant

Open Home Assistant UI → Settings → System → Backups → Create backup (full backup). This captures integrations state, .storage/, and all config managed by HA. Download the .tar file.

2c. Off-host copy of the HA backup

The backup from 2b lands in /home/padriano/projects/ha/config/backups/ (HA writes it inside /config, same disk). Copy it off to /home/padriano/share/ so we don't only rely on a same-disk copy:

cp /home/padriano/projects/ha/config/backups/*.tar /home/padriano/share/ha-backup-2024.5.4.tar

2d. Filesystem backup of the config directory

Stop the container first to get a consistent SQLite snapshot — otherwise home-assistant_v2.db-wal may be mid-write and the copy may be inconsistent.

docker compose stop homeassistant
cp -a /home/padriano/projects/ha/config /home/padriano/projects/ha/config.bak-2024.5.4
diff -rq /home/padriano/projects/ha/config /home/padriano/projects/ha/config.bak-2024.5.4 && echo "Backup OK" || echo "Backup MISMATCH"

(The container will be restarted in step 5; you can also docker compose up -d homeassistant here briefly if you want HA running while you do step 3.)

3. Review breaking changes

Read the "Backward-incompatible changes" section for each monthly release between 2024.6 and 2026.5:

High-impact themes across this window:

  • 2024.6: AlarmDecoder entities renamed with alarmdecoder_ prefix; Ping integration disconnectedunavailable.
  • 2024.72024.12: many YAML-only integration configs removed in favor of UI config flow.
  • 2025.x: SQLAlchemy / recorder schema bumps (long first-boot migration expected); legacy_templates removal; tightened http: / trusted_proxies validation.
  • 2026.x: skim release notes the day of upgrade for any last-minute regressions/hotfixes.

Grep /home/padriano/projects/ha/config for any deprecated YAML keys flagged by the changelogs before proceeding.

4. Edit docker-compose.yml

Two changes to the homeassistant service:

homeassistant:
  image: homeassistant/home-assistant:2026.5.4   # was 2024.5.4
  ...
  healthcheck:
    test: ["CMD", "curl", "-fsSL", "http://localhost:8123/manifest.json"]  # was /api/ (now requires auth)
    interval: 30s
    timeout: 10s
    retries: 5
    start_period: 30m   # was 60s — first-boot recorder schema migration can take a long time

Rationale for start_period: 30m: during start_period, failing health checks don't mark the container unhealthy. The first-boot recorder schema migration can run for many minutes, and a stock 60s start_period would flip the container to unhealthy mid-migration. Note this is cosmetic/observability — plain Docker does not kill or restart an unhealthy-but-running container (restart: unless-stopped only acts on container exit), and nothing here gates on HA's health (caddy's depends_on has no condition: service_healthy). So the only real risk of a too-short start_period is a misleading unhealthy status and noisy monitoring during migration. 30 min gives headroom; revert to a shorter value in a follow-up once we've measured the real first-boot time.

Validate before applying:

cd /home/padriano/projects/composer
docker compose config

5. Pull and start

cd /home/padriano/projects/composer
docker compose pull homeassistant
docker compose up -d homeassistant

pull only fetches the homeassistant image; duckdns, caddy, forgejo, samba, timemachine are untouched (intended).

6. Verify

  • Watch the HA log (where migration detail actually goes — docker compose logs only shows stdout):

    tail -F /home/padriano/projects/ha/config/home-assistant.log
    

    Look for Database upgrade in progress, then Setup of domain X took …, finally Home Assistant initialized in ….

  • Container health:

    docker inspect --format '{{.State.Health.Status}}' homeassistant
    # wait until: healthy
    
  • Version (auth-free):

    docker exec homeassistant python -c "from homeassistant.const import __version__; print(__version__)"
    # expected: 2026.5.4
    
  • Local HTTP:

    curl -fsS -o /dev/null -w "%{http_code}\n" http://localhost:8123/manifest.json
    # expected: 200
    
  • Reverse proxy (validates trusted_proxies still works against modern HA http: validation):

    curl -fsS -o /dev/null -w "%{http_code}\n" https://ha-padriano.duckdns.org
    # expected: same status code as recorded in step 1
    
  • UI: open Home Assistant → Settings → Repairs and address any flagged migration items.

7. Rollback

Decide which option by where the upgrade failed. Once 2026.5.4 has booted successfully it migrates the recorder DB schema and .storage/ to the new format, and HA does not support schema downgrade. So whether reverting the image tag alone is safe depends entirely on whether migration started — check the HA log (step 6) for Database upgrade in progress:

  • Migration never started (new container crashed/failed early, you never saw that line) → the on-disk config is untouched. Use Option A (revert tag only).
  • Migration started or completed (you saw that line, or HA reached the UI) → the DB/.storage/ are now on the new schema. Option A will fail — old core will refuse the newer recorder schema. Use Option B (restore the config backup).

Option A — revert image tag only (safe ONLY if migration never started)

Edit docker-compose.yml:

  • set image: back to homeassistant/home-assistant:2024.5.4
  • revert the healthcheck test line to http://localhost:8123/api/
  • revert start_period: 60s

Then:

cd /home/padriano/projects/composer
docker compose up -d homeassistant

The local homeassistant/home-assistant:2024.5.4-rollback tag from step 2a guarantees the exact previous image is still resolvable even if the upstream tag was repushed.

Option B — restore config backup (default once migration has run)

Revert the image tag and healthcheck per Option A, then restore the pre-upgrade config so the DB/.storage/ schema matches 2024.5.4:

docker compose stop homeassistant
mv /home/padriano/projects/ha/config /home/padriano/projects/ha/config.failed-2026.5.4   # keep the failed state for diagnosis instead of rm -rf
cp -a /home/padriano/projects/ha/config.bak-2024.5.4 /home/padriano/projects/ha/config
docker compose up -d homeassistant

Option C — last resort

Restore the HA .tar backup (from step 2b/2c) via the HA UI recovery mode on a fresh 2024.5.4 container.

8. Post-upgrade follow-up

  • Measure the actual first-boot migration time from the HA log and lower healthcheck.start_period back to a sensible steady-state value (e.g. 2m) in a follow-up commit.
  • Once stable for a few days, delete /home/padriano/projects/ha/config.bak-2024.5.4 and the local :2024.5.4-rollback image tag (docker rmi homeassistant/home-assistant:2024.5.4-rollback) to reclaim disk.