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

233 lines
11 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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)**:
```bash
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**:
```bash
docker inspect --format '{{.State.Health.Status}}' homeassistant
# expected: healthy
```
- **Reverse-proxy reachability**:
```bash
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
```bash
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:
```bash
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.
```bash
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:
- https://www.home-assistant.io/changelogs/core-2024.6/
- https://www.home-assistant.io/changelogs/core-2024.7/
- https://www.home-assistant.io/changelogs/core-2024.8/
- https://www.home-assistant.io/changelogs/core-2024.9/
- https://www.home-assistant.io/changelogs/core-2024.10/
- https://www.home-assistant.io/changelogs/core-2024.11/
- https://www.home-assistant.io/changelogs/core-2024.12/
- https://www.home-assistant.io/changelogs/core-2025.1/
- https://www.home-assistant.io/changelogs/core-2025.2/
- https://www.home-assistant.io/changelogs/core-2025.3/
- https://www.home-assistant.io/changelogs/core-2025.4/
- https://www.home-assistant.io/changelogs/core-2025.5/
- https://www.home-assistant.io/changelogs/core-2025.6/
- https://www.home-assistant.io/changelogs/core-2025.7/
- https://www.home-assistant.io/changelogs/core-2025.8/
- https://www.home-assistant.io/changelogs/core-2025.9/
- https://www.home-assistant.io/changelogs/core-2025.10/
- https://www.home-assistant.io/changelogs/core-2025.11/
- https://www.home-assistant.io/changelogs/core-2025.12/
- https://www.home-assistant.io/changelogs/core-2026.1/
- https://www.home-assistant.io/changelogs/core-2026.2/
- https://www.home-assistant.io/changelogs/core-2026.3/
- https://www.home-assistant.io/changelogs/core-2026.4/
- https://www.home-assistant.io/changelogs/core-2026.5/
High-impact themes across this window:
- **2024.6**: AlarmDecoder entities renamed with `alarmdecoder_` prefix; Ping integration `disconnected` → `unavailable`.
- **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:
```yaml
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:
```bash
cd /home/padriano/projects/composer
docker compose config
```
## 5. Pull and start
```bash
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):
```bash
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**:
```bash
docker inspect --format '{{.State.Health.Status}}' homeassistant
# wait until: healthy
```
- **Version (auth-free)**:
```bash
docker exec homeassistant python -c "from homeassistant.const import __version__; print(__version__)"
# expected: 2026.5.4
```
- **Local HTTP**:
```bash
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):
```bash
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:
```bash
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:
```bash
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.