From ad36e6d0a3ebedb07eaea5a032301c90e1911856 Mon Sep 17 00:00:00 2001 From: Fredrik Ahlgren Date: Wed, 7 Oct 2026 13:37:31 +0200 Subject: [PATCH 01/29] docs: simple update steps for the first native stable Put a one-table answer at the top of Install and update FTW and its Swedish copy: what each kind of install does to reach v0.140.1. Make the install recipes use a stable placeholder, document the Update button and how channels follow the running release, and drop text saying no 0.x stable exists. Co-Authored-By: Claude Opus 5.5 --- docs/native-beta.md | 77 +++++++++++++++++++++-------------- docs/operations.md | 6 +-- docs/self-update.md | 12 +++--- docs/setup-guide/update-sv.md | 58 ++++++++++++++++---------- scripts/test_install_docs.py | 20 +++++---- 5 files changed, 104 insertions(+), 69 deletions(-) diff --git a/docs/native-beta.md b/docs/native-beta.md index 6fb3c9995..87202e3be 100644 --- a/docs/native-beta.md +++ b/docs/native-beta.md @@ -1,21 +1,32 @@ # Install and update FTW -**FTW 2.x and 3.x will receive no further updates. All new development and -releases use the new 0.x line. Move to it now to follow the latest fixes and -features. Do not install 3.x beta or use it as an intermediate upgrade.** +**The first stable release of the new line is `v0.140.1`.** FTW 2.x and 3.x +get no more updates. [Svenska](setup-guide/update-sv.md). -The new line starts at `v0.131.0-beta.1`. Older 0.x releases, up to 0.130.x, -belong to the retired line too. The lower version number is deliberate. -Choosing `beta` in an old installation does not move it to the new line. +## Quick answer -You can switch now with a new setup and separate data. The guided migration -that preserves old settings, history, identity and goals is not ready yet. -If you need those data moved before switching, get help for your exact -installation; do not copy old databases into a new install. - -Use this guide for both people and agents. [Svenska](setup-guide/update-sv.md). -The owner runs the host; FTW supplies the commands. Native systemd and Docker -on 64-bit Linux use the same release package. +| You run | Do this | +|---|---| +| New FTW 0.x, native | Open **More → Version → Update FTW** in the web UI, or run `ftw update` on the box. Nothing else. | +| New FTW 0.x in Docker | Set `FTW_VERSION=v0.140.1` in `.env` and run `docker compose up -d --build`. [Details](#update-new-docker) | +| No FTW yet, on 64-bit Linux or a new Pi card | [Install](#install) with the stable tag. | +| Old FTW 2.x, 3.x or the old Pi image | No update in place. Set up new FTW on a second SD card or host and keep the old one. [Steps](#coming-from-an-older-ftw) | +| Home Assistant app | No new app yet. Run new FTW on another Linux host and connect Home Assistant over MQTT. [Steps](#coming-from-an-older-ftw) | +| Windows or macOS | Not supported. Use a Raspberry Pi or another 64-bit Linux machine. | + +While an update runs, keep the box powered and do not press Restart. It takes +about a minute. To go back, run `ftw rollback`. + +The new line starts with empty data. Moving old settings, history, identity +and goals is not ready yet. Do not copy old databases into a new install; +if you need the old data moved, ask for help with your exact installation. + +The rest of this page has the details, for people and agents. The owner runs +the host; FTW supplies the commands. Native systemd and Docker on 64-bit Linux +use the same release package. The new line starts at `v0.131.0-beta.1`; older +0.x releases, up to 0.130.x, belong to the retired line. Choosing `beta` in an +old installation does not move it to the new line, and 3.x beta is not a step +on the way. ## Choose your path @@ -172,11 +183,12 @@ with a separate FTW host still works; see [Home Assistant](ha-integration.md). return to [the second-card steps](#raspberry-pi-use-a-second-sd-card) first. This section does not update or migrate an old installation. -Choose an exact published new 0.x beta from [Releases](https://github.com/srcfl/ftw/releases). -Check that it includes the Linux package for your architecture and its SHA-256 -file. Do not use `releases/latest`: it still points to the retired 2.x line. -Copy the tag from the release title; do not retype it. Replace only -`v0.X.Y-beta.N` in the block below. Paste the **whole block, including `(` +Use the newest stable tag from [Releases](https://github.com/srcfl/ftw/releases), +`v0.140.1` or later with no `-beta` in it. Choose a beta only if you test new +builds. Check that the release includes the Linux package for your +architecture and its SHA-256 file. Do not use `releases/latest`: it still +points to the retired 2.x line. Copy the tag from the release title; do not +retype it. Replace only `v0.X.Y` in the block below. Paste the **whole block, including `(` and `)`**, into SSH on the new host. It stops at the first error and downloads that release's installer to a temporary file. `--fresh-host` confirms that this host has no existing FTW site, including @@ -185,7 +197,7 @@ stopped containers or data in a custom directory: ```bash ( set -eu - tag=v0.X.Y-beta.N + tag=v0.X.Y if [[ ! "$tag" =~ ^v0\.([0-9]+)\.[0-9]+(-beta\.[0-9]+)?$ ]] || (( 10#${BASH_REMATCH[1]} < 131 )); then echo "STOP: copy an exact published new 0.x tag from Releases." >&2 exit 1 @@ -228,7 +240,7 @@ closing or reloading the page does not cancel or repeat the update. ftw status # version, releases, last update, disk, health ftw update # install the next release on the saved channel ftw rollback # return to the previous release -ftw backup --output-dir /media/usb/ftw # make a verified backup and copy it off the disk +ftw backup # make a verified backup in /var/lib/ftw/backups ftw support # write the redacted support file for a report journalctl -u ftw -n 100 # logs sudo systemctl restart ftw # restart @@ -239,9 +251,8 @@ when the box is current or the update succeeded, and 1 when a step failed. ## Update a native box -Run the commands on the box. From another computer, connect with -`ssh @` first. The native web UI shows the version and -update notice; it has no Update button. +Use **More → Version → Update FTW** in the web UI, or run the commands on the +box. From another computer, connect with `ssh @` first. ```bash ftw status # check the running version, saved channel and health @@ -250,9 +261,13 @@ ftw status # confirm the running version and health afterward journalctl -u ftw --since "10 minutes ago" --no-pager ``` -`ftw update` follows the saved channel. Use `ftw update --channel beta` if -you mean to switch this site to beta. Publishing a beta does not update a -box by itself. Do not rerun the installer for a routine Core update. +`ftw update` follows the channel you chose with `--channel`. If you never +chose one, it follows what the box runs: a stable release follows stable, a +beta follows beta. Beta also offers a newer stable, so a beta box moves to +stable when one comes out. To stay on beta after that, run +`ftw update --channel beta`; to leave beta, run `ftw update --channel stable`. +Publishing a release does not update a box by itself. Do not rerun the +installer for a routine Core update. The command shows each step and waits until Core is ready. Check that its `Now running` line and the final `ftw status` name the expected version, @@ -335,7 +350,7 @@ the installer from that release. Replace the placeholder with its exact tag: ```bash ( set -eu - tag=v0.X.Y-beta.N + tag=v0.X.Y if [[ ! "$tag" =~ ^v0\.([0-9]+)\.[0-9]+(-beta\.[0-9]+)?$ ]] || (( 10#${BASH_REMATCH[1]} < 131 )); then echo "STOP: copy an exact published new 0.x tag from Releases." >&2 exit 1 @@ -360,8 +375,8 @@ include both plugins. Do not reinstall Docker on a running site without checking its existing services. Docker Desktop has a different network setup; this Linux host-network recipe does not establish LAN device access there. -Copy an exact published new 0.x tag from [Releases](https://github.com/srcfl/ftw/releases). -Replace only `v0.X.Y-beta.N` and paste the **whole block, including `(` and `)`**. +Copy the newest stable tag from [Releases](https://github.com/srcfl/ftw/releases). +Replace only `v0.X.Y` and paste the **whole block, including `(` and `)`**. It downloads both files to a temporary directory before creating the project, so a failed download leaves no project behind. Correct the tag or connection and paste the whole block again. It stops at the first error and refuses an @@ -371,7 +386,7 @@ else; do not delete it to make the command pass. ```bash ( set -eu - tag=v0.X.Y-beta.N + tag=v0.X.Y if [[ ! "$tag" =~ ^v0\.([0-9]+)\.[0-9]+(-beta\.[0-9]+)?$ ]] || (( 10#${BASH_REMATCH[1]} < 131 )); then echo "STOP: copy an exact published new 0.x tag from Releases." >&2 exit 1 diff --git a/docs/operations.md b/docs/operations.md index 338969ceb..d7cbca493 100644 --- a/docs/operations.md +++ b/docs/operations.md @@ -10,7 +10,7 @@ safely when it is unavailable. ## Install [Install and update FTW](native-beta.md) is the full guide and explains how -to choose a published new 0.x beta. Use the installer from the same tag you +to choose a published stable or beta tag. Use the installer from the same tag you install, on a fresh 64-bit Raspberry Pi OS, Debian or Ubuntu host. Follow the complete [native install block](native-beta.md#install). It stops @@ -430,8 +430,8 @@ the `ftw` command and the unit move with `install.sh --refresh` ## Release recovery -No 0.x stable has shipped; run a beta only on an agreed test site. A beta and -its promoted stable build identify the same commit. +Stable is the default for every site; run a beta only on an agreed test site. +A beta and its promoted stable build identify the same commit. - Native: `ftw rollback` returns to the previous release when it reads the same data. If Core does not start and `ftw` cannot reach it, roll back diff --git a/docs/self-update.md b/docs/self-update.md index a698bfcea..d50878e03 100644 --- a/docs/self-update.md +++ b/docs/self-update.md @@ -1,8 +1,9 @@ # Updates and release channels [ADR 0007](adr/0007-self-updating-binary.md) defines the move to a native -Core. `v0.131.0-beta.1` is the first published native beta. No native stable -release or guided migration for an existing box has shipped. +Core. `v0.131.0-beta.1` is the first published native beta and `v0.140.1` +the first native stable. Guided migration for an existing old box has not +shipped. There are two channels: @@ -99,7 +100,8 @@ local terminal and check the running version, health and live readings. Publishing the release and installing it on a box are separate steps. A native beta must run for a week on the home box and at least one other real -site with no open `release-blocker`. Only then can the owner dispatch the same +site with no open `release-blocker`; the owner may shorten that and must say +so in the stable release notes. Only then can the owner dispatch the same workflow for `v0.X.Y` stable, naming the tested `source_beta`. Stable checks the published beta receipt and package hashes and uses the same source commit. Beta and stable contain different embedded version strings, so each @@ -108,8 +110,8 @@ alone is not field validation. On a native site the owner chooses when to update, from More → Version, on the machine, or from their own timer or agent. -[Try the 0.x beta](native-beta.md) is the tester's guide. The installer puts -the `ftw` command on `PATH`: +[Install and update FTW](native-beta.md) is the guide for everyone. The +installer puts the `ftw` command on `PATH`: ```bash ftw status # version, published release, last update, health diff --git a/docs/setup-guide/update-sv.md b/docs/setup-guide/update-sv.md index 4e1c7a46e..379a0c6e2 100644 --- a/docs/setup-guide/update-sv.md +++ b/docs/setup-guide/update-sv.md @@ -1,22 +1,31 @@ # Byt till nya FTW och håll det uppdaterat -[English](../native-beta.md). +**Första stabila versionen av nya serien är `v0.140.1`.** FTW 2.x och 3.x får +inga fler uppdateringar. [English](../native-beta.md). -**FTW 2.x och 3.x får inga fler uppdateringar. All fortsatt utveckling går -till den nya 0.x-serien. Vill du ha de senaste funktionerna och rättningarna -är det dags att byta nu. Installera inte 3.x-beta, och uppdatera inte en äldre -installation till 3.x som ett steg på vägen.** +## Kort svar -Den nya serien börjar med `v0.131.0-beta.1`. Det lägre versionsnumret är -avsiktligt. Äldre 0.x-versioner, till och med 0.130.x, hör till den gamla -serien. `beta` är kanalen inom en serie; ett kanalbyte flyttar inte en gammal -installation till den nya serien. - -Du kan börja använda nya FTW nu, med nya inställningar och egen datalagring. -Den guidade flytten som tar med gamla inställningar och historik är ännu inte -klar. Behöver du föra över dessa data innan du byter, ta hjälp med just din -installation. Kopiera inte gamla databaser till den nya installationen på egen -hand. +| Du kör | Gör så här | +|---|---| +| Nya FTW 0.x, native | Öppna **More → Version → Update FTW** i webbsidan, eller kör `ftw update` på boxen. Inget mer. | +| Nya FTW 0.x i Docker | Sätt `FTW_VERSION=v0.140.1` i `.env` och kör `docker compose up -d --build`. [Detaljer](#docker-från-det-nya-releasepaketet) | +| Inget FTW än, på 64-bitars Linux eller ett nytt Pi-kort | [Installera](#installera-på-det-nya-kortet-eller-en-tom-linux-maskin) med den stabila taggen. | +| Gamla FTW 2.x, 3.x eller den gamla Pi-imagen | Går inte att uppdatera på plats. Sätt upp nya FTW på ett andra SD-kort eller en annan maskin och behåll den gamla. [Steg](#byt-på-raspberry-pi-med-ett-nytt-sd-kort) | +| Home Assistant-appen | Ingen ny app än. Kör nya FTW på en annan Linux-maskin och koppla Home Assistant via MQTT. [Steg](#välj-en-väg) | +| Windows eller macOS | Stöds inte. Använd en Raspberry Pi eller en annan 64-bitars Linux-maskin. | + +Låt boxen ha ström och tryck inte Restart medan uppdateringen pågår. Den tar +ungefär en minut. Vill du tillbaka, kör `ftw rollback`. + +Nya serien börjar med tom data. Flytten av gamla inställningar, historik, +identitet och mål är inte klar än. Kopiera inte gamla databaser till en ny +installation; behöver du gamla data flyttade, ta hjälp med just din +installation. + +Resten av sidan har detaljerna. Den nya serien börjar med `v0.131.0-beta.1`. +Äldre 0.x-versioner, till och med 0.130.x, hör till den gamla serien. `beta` i +en gammal installation flyttar den inte till nya serien, och 3.x-beta är inget +steg på vägen. ## Välj en väg @@ -166,17 +175,19 @@ kortet, gå tillbaka till kortbytet ovan. `--fresh-host` betyder att ingen FTW-installation eller dess data finns här, även om den är stoppad. 1. Öppna [Releases](https://github.com/srcfl/ftw/releases) på din vanliga dator. - Välj en publicerad **ny 0.x-beta** med Linux-paket och SHA-256-fil för din - maskin. Använd inte `releases/latest`; den pekar på gamla 2.x. + Välj den senaste **stabila** taggen, `v0.140.1` eller senare utan `-beta`. + Välj en beta bara om du provar nya byggen. Releasen ska ha Linux-paket och + SHA-256-fil för din maskin. Använd inte `releases/latest`; den pekar på + gamla 2.x. 2. Kopiera taggen från releasens rubrik. Skriv inte av den för hand. Byt bara - ut `v0.X.Y-beta.N` i blocket nedan mot taggen du kopierade. + ut `v0.X.Y` i blocket nedan mot taggen du kopierade. 3. Klistra in **hela blocket, inklusive `(` och `)`**, i SSH på nya kortet. Det stannar vid första felet och hämtar skriptet till en tillfällig fil. ```bash ( set -eu - tag=v0.X.Y-beta.N + tag=v0.X.Y if [[ ! "$tag" =~ ^v0\.([0-9]+)\.[0-9]+(-beta\.[0-9]+)?$ ]] || (( 10#${BASH_REMATCH[1]} < 131 )); then echo "STOP: copy an exact published new 0.x tag from Releases." >&2 exit 1 @@ -200,13 +211,16 @@ Kör på FTW-maskinen: ```bash ftw status -ftw update --channel beta +ftw update ftw status journalctl -u ftw --since "10 minutes ago" --no-pager ``` -`--channel beta` väljer beta och försöker uppdatera. När rätt kanal redan är -sparad räcker `ftw update` nästa gång. Du kan också välja +`ftw update` följer kanalen du valt med `--channel`. Har du aldrig valt följer +den det boxen kör: en stabil version följer stable, en beta följer beta. Beta +erbjuder också en nyare stable, så en betabox går över till stable när en +sådan kommer. Vill du stanna på beta efter det, kör `ftw update --channel beta`; +vill du lämna beta, kör `ftw update --channel stable`. Du kan också välja **More → Version → Update FTW** i native-webbsidan. Knappen använder samma Core-API och launcher som kommandot. Den visar hämtade byte, klara steg och resultatet efter omstart. Behåll strömmen på. Att stänga eller ladda om sidan diff --git a/scripts/test_install_docs.py b/scripts/test_install_docs.py index 7481266a8..ce0268a5c 100644 --- a/scripts/test_install_docs.py +++ b/scripts/test_install_docs.py @@ -14,7 +14,7 @@ def recipe(path, marker): blocks = re.findall(r'```bash\n(.*?)\n```', path.read_text(), re.S) - matches = [block for block in blocks if marker in block and 'tag=v0.X.Y-beta.N' in block] + matches = [block for block in blocks if marker in block and 'tag=v0.X.Y\n' in block] assert len(matches) == 1, (path, marker, len(matches)) return matches[0] @@ -49,7 +49,7 @@ def stub(self, name, body): path.chmod(0o755) def run_recipe(self, marker, failure='', tag='v0.138.2-beta.1'): - block = recipe(EN, marker).replace('v0.X.Y-beta.N', tag) + block = recipe(EN, marker).replace('tag=v0.X.Y\n', f'tag={tag}\n') # Change only the destination, never the user's HOME or real Docker state. if marker == 'compose up': self.assertEqual(block.count('"$HOME/ftw-local"'), 1) @@ -65,7 +65,7 @@ def test_translations_use_the_same_native_commands(self): def test_rejects_placeholder_old_line_and_mistyped_tag_before_work(self): for marker in ('--fresh-host', 'compose up'): - for tag in ('v0.X.Y-beta.N', 'v3.8.0-beta.1', 'v0.130.0', 'v0.0.138-beta.1'): + for tag in ('v0.X.Y', 'v0.X.Y-beta.N', 'v3.8.0-beta.1', 'v0.130.0', 'v0.0.138-beta.1'): with self.subTest(marker=marker, tag=tag): result, calls = self.run_recipe(marker, tag=tag) self.assertNotEqual(result.returncode, 0) @@ -82,11 +82,15 @@ def test_native_download_failure_does_not_run_stale_installer(self): self.assertFalse(Path(download).exists()) def test_native_success_runs_download_and_removes_temp_file(self): - result, calls = self.run_recipe('--fresh-host') - self.assertEqual(result.returncode, 0, result.stderr) - self.assertIn('INSTALL\n', calls) - download = shlex.split(calls.splitlines()[0])[-1] - self.assertFalse(Path(download).exists()) + for tag in ('v0.140.1', 'v0.138.2-beta.1'): + with self.subTest(tag=tag): + self.log.write_text('') + result, calls = self.run_recipe('--fresh-host', tag=tag) + self.assertEqual(result.returncode, 0, result.stderr) + self.assertIn('INSTALL\n', calls) + self.assertIn(f'/srcfl/ftw/{tag}/scripts/install.sh', calls) + download = shlex.split(calls.splitlines()[0])[-1] + self.assertFalse(Path(download).exists()) def test_failed_docker_download_leaves_no_project_and_allows_retry(self): for failure in ('download', 'dockerfile'): From c35caaefd0e80924be9c425ba14e4c2e3f1585c4 Mon Sep 17 00:00:00 2001 From: Fredrik Ahlgren Date: Sat, 10 Oct 2026 18:47:07 +0200 Subject: [PATCH 02/29] docs: prepare the guide for native stable 0.140.4 Signed-off-by: Fredrik Ahlgren --- docs/native-beta.md | 12 ++++++------ docs/self-update.md | 2 +- docs/setup-guide/update-sv.md | 10 +++++----- scripts/test_install_docs.py | 2 +- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/docs/native-beta.md b/docs/native-beta.md index 87202e3be..c1d9f4103 100644 --- a/docs/native-beta.md +++ b/docs/native-beta.md @@ -1,6 +1,6 @@ # Install and update FTW -**The first stable release of the new line is `v0.140.1`.** FTW 2.x and 3.x +**The first stable release of the new line is `v0.140.4`.** FTW 2.x and 3.x get no more updates. [Svenska](setup-guide/update-sv.md). ## Quick answer @@ -8,14 +8,14 @@ get no more updates. [Svenska](setup-guide/update-sv.md). | You run | Do this | |---|---| | New FTW 0.x, native | Open **More → Version → Update FTW** in the web UI, or run `ftw update` on the box. Nothing else. | -| New FTW 0.x in Docker | Set `FTW_VERSION=v0.140.1` in `.env` and run `docker compose up -d --build`. [Details](#update-new-docker) | +| New FTW 0.x in Docker | Set `FTW_VERSION=v0.140.4` in `.env` and run `docker compose up -d --build`. [Details](#update-new-docker) | | No FTW yet, on 64-bit Linux or a new Pi card | [Install](#install) with the stable tag. | | Old FTW 2.x, 3.x or the old Pi image | No update in place. Set up new FTW on a second SD card or host and keep the old one. [Steps](#coming-from-an-older-ftw) | | Home Assistant app | No new app yet. Run new FTW on another Linux host and connect Home Assistant over MQTT. [Steps](#coming-from-an-older-ftw) | | Windows or macOS | Not supported. Use a Raspberry Pi or another 64-bit Linux machine. | -While an update runs, keep the box powered and do not press Restart. It takes -about a minute. To go back, run `ftw rollback`. +While an update runs, keep the box powered and do not press Restart. Wait for +the update to finish. To go back, run `ftw rollback`. The new line starts with empty data. Moving old settings, history, identity and goals is not ready yet. Do not copy old databases into a new install; @@ -184,7 +184,7 @@ return to [the second-card steps](#raspberry-pi-use-a-second-sd-card) first. This section does not update or migrate an old installation. Use the newest stable tag from [Releases](https://github.com/srcfl/ftw/releases), -`v0.140.1` or later with no `-beta` in it. Choose a beta only if you test new +`v0.140.4` or later with no `-beta` in it. Choose a beta only if you test new builds. Check that the release includes the Linux package for your architecture and its SHA-256 file. Do not use `releases/latest`: it still points to the retired 2.x line. Copy the tag from the release title; do not @@ -240,7 +240,7 @@ closing or reloading the page does not cancel or repeat the update. ftw status # version, releases, last update, disk, health ftw update # install the next release on the saved channel ftw rollback # return to the previous release -ftw backup # make a verified backup in /var/lib/ftw/backups +ftw backup # make a verified full backup; prints its path ftw support # write the redacted support file for a report journalctl -u ftw -n 100 # logs sudo systemctl restart ftw # restart diff --git a/docs/self-update.md b/docs/self-update.md index d50878e03..e7e8057d2 100644 --- a/docs/self-update.md +++ b/docs/self-update.md @@ -1,7 +1,7 @@ # Updates and release channels [ADR 0007](adr/0007-self-updating-binary.md) defines the move to a native -Core. `v0.131.0-beta.1` is the first published native beta and `v0.140.1` +Core. `v0.131.0-beta.1` is the first published native beta and `v0.140.4` the first native stable. Guided migration for an existing old box has not shipped. diff --git a/docs/setup-guide/update-sv.md b/docs/setup-guide/update-sv.md index 379a0c6e2..4e3f1c911 100644 --- a/docs/setup-guide/update-sv.md +++ b/docs/setup-guide/update-sv.md @@ -1,6 +1,6 @@ # Byt till nya FTW och håll det uppdaterat -**Första stabila versionen av nya serien är `v0.140.1`.** FTW 2.x och 3.x får +**Första stabila versionen av nya serien är `v0.140.4`.** FTW 2.x och 3.x får inga fler uppdateringar. [English](../native-beta.md). ## Kort svar @@ -8,14 +8,14 @@ inga fler uppdateringar. [English](../native-beta.md). | Du kör | Gör så här | |---|---| | Nya FTW 0.x, native | Öppna **More → Version → Update FTW** i webbsidan, eller kör `ftw update` på boxen. Inget mer. | -| Nya FTW 0.x i Docker | Sätt `FTW_VERSION=v0.140.1` i `.env` och kör `docker compose up -d --build`. [Detaljer](#docker-från-det-nya-releasepaketet) | +| Nya FTW 0.x i Docker | Sätt `FTW_VERSION=v0.140.4` i `.env` och kör `docker compose up -d --build`. [Detaljer](#docker-från-det-nya-releasepaketet) | | Inget FTW än, på 64-bitars Linux eller ett nytt Pi-kort | [Installera](#installera-på-det-nya-kortet-eller-en-tom-linux-maskin) med den stabila taggen. | | Gamla FTW 2.x, 3.x eller den gamla Pi-imagen | Går inte att uppdatera på plats. Sätt upp nya FTW på ett andra SD-kort eller en annan maskin och behåll den gamla. [Steg](#byt-på-raspberry-pi-med-ett-nytt-sd-kort) | | Home Assistant-appen | Ingen ny app än. Kör nya FTW på en annan Linux-maskin och koppla Home Assistant via MQTT. [Steg](#välj-en-väg) | | Windows eller macOS | Stöds inte. Använd en Raspberry Pi eller en annan 64-bitars Linux-maskin. | -Låt boxen ha ström och tryck inte Restart medan uppdateringen pågår. Den tar -ungefär en minut. Vill du tillbaka, kör `ftw rollback`. +Låt boxen ha ström och tryck inte Restart medan uppdateringen pågår. Vänta tills +uppdateringen är klar. Vill du tillbaka, kör `ftw rollback`. Nya serien börjar med tom data. Flytten av gamla inställningar, historik, identitet och mål är inte klar än. Kopiera inte gamla databaser till en ny @@ -175,7 +175,7 @@ kortet, gå tillbaka till kortbytet ovan. `--fresh-host` betyder att ingen FTW-installation eller dess data finns här, även om den är stoppad. 1. Öppna [Releases](https://github.com/srcfl/ftw/releases) på din vanliga dator. - Välj den senaste **stabila** taggen, `v0.140.1` eller senare utan `-beta`. + Välj den senaste **stabila** taggen, `v0.140.4` eller senare utan `-beta`. Välj en beta bara om du provar nya byggen. Releasen ska ha Linux-paket och SHA-256-fil för din maskin. Använd inte `releases/latest`; den pekar på gamla 2.x. diff --git a/scripts/test_install_docs.py b/scripts/test_install_docs.py index ce0268a5c..7846996c1 100644 --- a/scripts/test_install_docs.py +++ b/scripts/test_install_docs.py @@ -82,7 +82,7 @@ def test_native_download_failure_does_not_run_stale_installer(self): self.assertFalse(Path(download).exists()) def test_native_success_runs_download_and_removes_temp_file(self): - for tag in ('v0.140.1', 'v0.138.2-beta.1'): + for tag in ('v0.140.4', 'v0.138.2-beta.1'): with self.subTest(tag=tag): self.log.write_text('') result, calls = self.run_recipe('--fresh-host', tag=tag) From a60396e0f9470a3a38abff63b43d3d49b1eb790e Mon Sep 17 00:00:00 2001 From: Fredrik Ahlgren Date: Sun, 11 Oct 2026 19:52:41 +0200 Subject: [PATCH 03/29] docs: verify Docker recovery before restarting Core --- docs/backup-and-restore.md | 5 +- docs/native-beta.md | 92 +++++++++++++++++++++++++++++------ docs/self-update.md | 2 +- docs/setup-guide/update-sv.md | 85 ++++++++++++++++++++++++++++++-- scripts/test_install_docs.py | 73 ++++++++++++++++++++++++++- 5 files changed, 235 insertions(+), 22 deletions(-) diff --git a/docs/backup-and-restore.md b/docs/backup-and-restore.md index 6d936d762..bae7d0a58 100644 --- a/docs/backup-and-restore.md +++ b/docs/backup-and-restore.md @@ -79,8 +79,9 @@ in the CLI environment if the site requires LAN auth. Set `state.backup_dir` to a mounted external directory to keep Core's own copies off the data disk; FTW must be able to write it. -In Docker 0.x, stop FTW and archive the whole data directory, as in -[Docker](native-beta.md#docker). +In Docker 0.x, use the release image's offline `ftw-backup` helper to create +the verified archive on another disk. See +[Back up and restore new Docker](native-beta.md#back-up-and-restore-new-docker). On older Docker installs (1.x–3.x), open **FTW Update Center → Full backups**, choose **Create full backup**, then **Download** and save the `.ftwbak` file diff --git a/docs/native-beta.md b/docs/native-beta.md index c1d9f4103..ad11f79ba 100644 --- a/docs/native-beta.md +++ b/docs/native-beta.md @@ -1,6 +1,6 @@ # Install and update FTW -**The first stable release of the new line is `v0.140.4`.** FTW 2.x and 3.x +**The first stable release of the new line is `v0.140.5`.** FTW 2.x and 3.x get no more updates. [Svenska](setup-guide/update-sv.md). ## Quick answer @@ -8,19 +8,27 @@ get no more updates. [Svenska](setup-guide/update-sv.md). | You run | Do this | |---|---| | New FTW 0.x, native | Open **More → Version → Update FTW** in the web UI, or run `ftw update` on the box. Nothing else. | -| New FTW 0.x in Docker | Set `FTW_VERSION=v0.140.4` in `.env` and run `docker compose up -d --build`. [Details](#update-new-docker) | +| New FTW 0.x in Docker | Set `FTW_VERSION=v0.140.5` in `.env` and run `docker compose up -d --build`. [Details](#update-new-docker) | | No FTW yet, on 64-bit Linux or a new Pi card | [Install](#install) with the stable tag. | | Old FTW 2.x, 3.x or the old Pi image | No update in place. Set up new FTW on a second SD card or host and keep the old one. [Steps](#coming-from-an-older-ftw) | | Home Assistant app | No new app yet. Run new FTW on another Linux host and connect Home Assistant over MQTT. [Steps](#coming-from-an-older-ftw) | | Windows or macOS | Not supported. Use a Raspberry Pi or another 64-bit Linux machine. | While an update runs, keep the box powered and do not press Restart. Wait for -the update to finish. To go back, run `ftw rollback`. +the update to finish. On native, `ftw rollback` returns to the previous +compatible release. For Docker, follow [Update new Docker](#update-new-docker). The new line starts with empty data. Moving old settings, history, identity and goals is not ready yet. Do not copy old databases into a new install; if you need the old data moved, ask for help with your exact installation. +Storage conversion is one part of that move. See +[history conversion](history-conversion.md) for SQLite/Parquet and DuckDB, +and [the native pilot](self-update.md#pilot-an-older-native-systemd-site) +for its supported service layout. Neither is a general migration for Docker, +Pi images or Home Assistant. Preserve the active config and its credentials, +not just the masked config shown by the API. + The rest of this page has the details, for people and agents. The owner runs the host; FTW supplies the commands. Native systemd and Docker on 64-bit Linux use the same release package. The new line starts at `v0.131.0-beta.1`; older @@ -184,7 +192,7 @@ return to [the second-card steps](#raspberry-pi-use-a-second-sd-card) first. This section does not update or migrate an old installation. Use the newest stable tag from [Releases](https://github.com/srcfl/ftw/releases), -`v0.140.4` or later with no `-beta` in it. Choose a beta only if you test new +`v0.140.5` or later with no `-beta` in it. Choose a beta only if you test new builds. Check that the release includes the Linux package for your architecture and its SHA-256 file. Do not use `releases/latest`: it still points to the retired 2.x line. Copy the tag from the release title; do not @@ -464,20 +472,76 @@ image: `docker image ls ftw-local` lists them, and `docker image rm ftw-local:` frees the space of one you no longer need. -Back up and restore the whole data directory while FTW is stopped: +### Back up and restore new Docker + +Use the `ftw-backup` tool in the same release image. It verifies a portable +`.ftwbak` archive and retains replaced data during restore. These commands +apply to the new Docker project above; they do not migrate an older install. +Run them from `~/ftw-local`. Only the `ftw` service stops. + +Mount another disk first and replace `/media/usb/ftw-backups` with a dedicated +directory on that disk. The container runs as UID 100, GID 101. The backup +block creates that directory with those owners and private permissions: ```bash -docker compose stop -sudo tar -czf /media/usb/ftw/ftw-data-$(date +%F).tar.gz data -docker compose start - -# restore -docker compose stop -sudo mv data data.before-restore-$(date +%F-%H%M) -sudo tar -xzf /media/usb/ftw/ftw-data-.tar.gz -docker compose start +( + set -eu + backup_dir=/media/usb/ftw-backups + sudo install -d -o 100 -g 101 -m 0700 "$backup_dir" + docker compose stop ftw + docker compose run --rm --no-deps --entrypoint /app/ftw-backup \ + --volume "$backup_dir:/backup:z" ftw \ + create -state /app/data/state.db -data /app/data -output /backup -progress + docker compose start ftw +) ``` +The final JSON names the verified archive under `/backup`; the file is in +`backup_dir` on the host. Keep the printed name. A backup error stops the +block and leaves FTW stopped. Resolve it before restarting; do not treat a +partial file as a backup. + +To restore, use the exact `.ftwbak` name and a compatible release image: + +```bash +( + set -eu + backup_dir=/media/usb/ftw-backups + archive=ftw-full-backup-YYYYMMDDTHHMMSS.ftwbak + test -f "$backup_dir/$archive" + docker compose stop ftw + docker compose run --rm --no-deps --entrypoint /app/ftw-backup \ + --volume "$backup_dir:/backup:ro,z" ftw \ + restore -archive "/backup/$archive" -data /app/data -yes + docker compose start ftw +) +``` + +Restore verifies and extracts before replacing data. Any helper error stops +the block before Core starts. Earlier data stays under the printed +`/app/data/.ftw-pre-restore-…` path. Keep it until you have checked config, +identity, old and new history, goals, fresh device readings and planning. +Wait for healthy status in `docker compose ps`, then run +`docker compose exec ftw ftw status`. + +To return to the retained data, replace `safety` with that printed container +path. Use the compatible image for those data: + +```bash +( + set -eu + safety=/app/data/.ftw-pre-restore-YYYYMMDDTHHMMSS + docker compose stop ftw + docker compose run --rm --no-deps --entrypoint /app/ftw-backup ftw \ + revert -data /app/data -safety "$safety" -yes + docker compose start ftw +) +``` + +These helpers accept `.ftwbak`, not an old raw `.tar.gz`. Keep raw archives +and the matching old installation for recovery; do not rename them to +`.ftwbak`. See [full backup and restore](backup-and-restore.md). + To remove it, run `docker compose down`, remove the `ftw-local` images and delete `~/ftw-local`. diff --git a/docs/self-update.md b/docs/self-update.md index e7e8057d2..9748238b7 100644 --- a/docs/self-update.md +++ b/docs/self-update.md @@ -1,7 +1,7 @@ # Updates and release channels [ADR 0007](adr/0007-self-updating-binary.md) defines the move to a native -Core. `v0.131.0-beta.1` is the first published native beta and `v0.140.4` +Core. `v0.131.0-beta.1` is the first published native beta and `v0.140.5` the first native stable. Guided migration for an existing old box has not shipped. diff --git a/docs/setup-guide/update-sv.md b/docs/setup-guide/update-sv.md index 4e3f1c911..ede28b151 100644 --- a/docs/setup-guide/update-sv.md +++ b/docs/setup-guide/update-sv.md @@ -1,6 +1,6 @@ # Byt till nya FTW och håll det uppdaterat -**Första stabila versionen av nya serien är `v0.140.4`.** FTW 2.x och 3.x får +**Första stabila versionen av nya serien är `v0.140.5`.** FTW 2.x och 3.x får inga fler uppdateringar. [English](../native-beta.md). ## Kort svar @@ -8,20 +8,28 @@ inga fler uppdateringar. [English](../native-beta.md). | Du kör | Gör så här | |---|---| | Nya FTW 0.x, native | Öppna **More → Version → Update FTW** i webbsidan, eller kör `ftw update` på boxen. Inget mer. | -| Nya FTW 0.x i Docker | Sätt `FTW_VERSION=v0.140.4` i `.env` och kör `docker compose up -d --build`. [Detaljer](#docker-från-det-nya-releasepaketet) | +| Nya FTW 0.x i Docker | Sätt `FTW_VERSION=v0.140.5` i `.env` och kör `docker compose up -d --build`. [Detaljer](#docker-från-det-nya-releasepaketet) | | Inget FTW än, på 64-bitars Linux eller ett nytt Pi-kort | [Installera](#installera-på-det-nya-kortet-eller-en-tom-linux-maskin) med den stabila taggen. | | Gamla FTW 2.x, 3.x eller den gamla Pi-imagen | Går inte att uppdatera på plats. Sätt upp nya FTW på ett andra SD-kort eller en annan maskin och behåll den gamla. [Steg](#byt-på-raspberry-pi-med-ett-nytt-sd-kort) | | Home Assistant-appen | Ingen ny app än. Kör nya FTW på en annan Linux-maskin och koppla Home Assistant via MQTT. [Steg](#välj-en-väg) | | Windows eller macOS | Stöds inte. Använd en Raspberry Pi eller en annan 64-bitars Linux-maskin. | Låt boxen ha ström och tryck inte Restart medan uppdateringen pågår. Vänta tills -uppdateringen är klar. Vill du tillbaka, kör `ftw rollback`. +uppdateringen är klar. På native återgår `ftw rollback` till föregående +kompatibla release. För Docker, följ [Docker-steget](#docker-från-det-nya-releasepaketet). Nya serien börjar med tom data. Flytten av gamla inställningar, historik, identitet och mål är inte klar än. Kopiera inte gamla databaser till en ny installation; behöver du gamla data flyttade, ta hjälp med just din installation. +Lagringskonvertering är en del av flytten. Läs +[historikkonvertering](../history-conversion.md) för SQLite/Parquet och DuckDB +och [native-piloten](../self-update.md#pilot-an-older-native-systemd-site) +för dess stödda tjänstelayout. De ger ingen allmän flytt för Docker, Pi-images +eller Home Assistant. Behåll aktiv config och dess hemligheter; API:t visar +maskerade värden och ger ingen full export av dem. + Resten av sidan har detaljerna. Den nya serien börjar med `v0.131.0-beta.1`. Äldre 0.x-versioner, till och med 0.130.x, hör till den gamla serien. `beta` i en gammal installation flyttar den inte till nya serien, och 3.x-beta är inget @@ -175,7 +183,7 @@ kortet, gå tillbaka till kortbytet ovan. `--fresh-host` betyder att ingen FTW-installation eller dess data finns här, även om den är stoppad. 1. Öppna [Releases](https://github.com/srcfl/ftw/releases) på din vanliga dator. - Välj den senaste **stabila** taggen, `v0.140.4` eller senare utan `-beta`. + Välj den senaste **stabila** taggen, `v0.140.5` eller senare utan `-beta`. Välj en beta bara om du provar nya byggen. Releasen ska ha Linux-paket och SHA-256-fil för din maskin. Använd inte `releases/latest`; den pekar på gamla 2.x. @@ -270,6 +278,75 @@ inte den här Docker-installationen. Återgång sker genom att välja föregåen kompatibla `FTW_VERSION` och köra Compose igen. Docker har ingen automatisk återgång till föregående version. +### Backup och restore för nya Docker + +Använd `ftw-backup` från samma release-image. Verktyget verifierar ett +portabelt `.ftwbak`-arkiv och behåller tidigare data vid restore. Stegen gäller +det nya Compose-projektet, inte flytt av en äldre installation. Kör från +`~/ftw-local`. Bara tjänsten `ftw` stoppas. + +Montera en annan disk först. Byt `/media/usb/ftw-backups` till en särskild +backupkatalog där. Containern använder UID 100 och GID 101; blocket skapar +katalogen med dessa ägare och privata rättigheter: + +```bash +( + set -eu + backup_dir=/media/usb/ftw-backups + sudo install -d -o 100 -g 101 -m 0700 "$backup_dir" + docker compose stop ftw + docker compose run --rm --no-deps --entrypoint /app/ftw-backup \ + --volume "$backup_dir:/backup:z" ftw \ + create -state /app/data/state.db -data /app/data -output /backup -progress + docker compose start ftw +) +``` + +Slutlig JSON anger det verifierade arkivets namn under `/backup`. Filen finns +i `backup_dir` på värden. Spara namnet. Vid fel stannar blocket och FTW förblir +stoppad. Lös felet innan du startar igen; en ofärdig fil är ingen backup. + +För restore: ange exakt `.ftwbak`-namn och använd en kompatibel release-image: + +```bash +( + set -eu + backup_dir=/media/usb/ftw-backups + archive=ftw-full-backup-YYYYMMDDTHHMMSS.ftwbak + test -f "$backup_dir/$archive" + docker compose stop ftw + docker compose run --rm --no-deps --entrypoint /app/ftw-backup \ + --volume "$backup_dir:/backup:ro,z" ftw \ + restore -archive "/backup/$archive" -data /app/data -yes + docker compose start ftw +) +``` + +Verktyget verifierar och packar upp innan data ersätts. Ett fel stoppar blocket +innan Core startar. Tidigare data finns kvar i den utskrivna sökvägen +`/app/data/.ftw-pre-restore-…`. Behåll dem tills config, identitet, gammal och ny +historik, mål, färska mätvärden och plan har kontrollerats. Vänta på frisk +status i `docker compose ps` och kör sedan +`docker compose exec ftw ftw status`. + +För att återgå till sparade data: sätt `safety` till den utskrivna sökvägen i +containern. Använd en image som kan läsa dessa data: + +```bash +( + set -eu + safety=/app/data/.ftw-pre-restore-YYYYMMDDTHHMMSS + docker compose stop ftw + docker compose run --rm --no-deps --entrypoint /app/ftw-backup ftw \ + revert -data /app/data -safety "$safety" -yes + docker compose start ftw +) +``` + +Verktyget läser `.ftwbak`, inte äldre råa `.tar.gz`-arkiv. Behåll sådana arkiv +och den matchande gamla installationen för återställning. Att döpa om filen +gör den inte kompatibel. Läs [full backup och restore](../backup-and-restore.md). + ## För agenter som hjälper till - Välj en väg. Native och Docker är alternativ, inte steg efter varandra. diff --git a/scripts/test_install_docs.py b/scripts/test_install_docs.py index 7846996c1..c6cb9b656 100644 --- a/scripts/test_install_docs.py +++ b/scripts/test_install_docs.py @@ -19,6 +19,13 @@ def recipe(path, marker): return matches[0] +def recovery_recipe(path, marker): + blocks = re.findall(r'```bash\n(.*?)\n```', path.read_text(), re.S) + matches = [block for block in blocks if marker in block and 'docker compose run' in block] + assert len(matches) == 1, (path, marker, len(matches)) + return matches[0] + + class InstallDocsTest(unittest.TestCase): def setUp(self): self.tmp = tempfile.TemporaryDirectory(prefix='ftw-install-docs-') @@ -82,7 +89,7 @@ def test_native_download_failure_does_not_run_stale_installer(self): self.assertFalse(Path(download).exists()) def test_native_success_runs_download_and_removes_temp_file(self): - for tag in ('v0.140.4', 'v0.138.2-beta.1'): + for tag in ('v0.140.5', 'v0.138.2-beta.1'): with self.subTest(tag=tag): self.log.write_text('') result, calls = self.run_recipe('--fresh-host', tag=tag) @@ -137,6 +144,70 @@ def test_docker_success_writes_ignore_before_build(self): self.assertEqual(result.returncode, 0, result.stderr) self.assertIn('docker compose up -d --build', calls) + def run_recovery(self, marker, failure='', archive_exists=True): + backup_dir = self.work / 'usb-backups' + backup_dir.mkdir(exist_ok=True) + archive = backup_dir / 'ftw-full-backup-YYYYMMDDTHHMMSS.ftwbak' + if archive_exists: + archive.write_text('test archive; helper is stubbed\n') + self.stub('install', 'echo "install $*" >> "$FTW_TEST_LOG"') + self.stub('docker', '''echo "docker $*" >> "$FTW_TEST_LOG" +if [ "$FTW_TEST_FAIL" = stop ] && [ "$1 ${2:-}" = 'compose stop' ]; then exit 1; fi +case " $* " in + *' create '*) [ "$FTW_TEST_FAIL" != create ] || exit 1 ;; + *' restore '*) [ "$FTW_TEST_FAIL" != restore ] || exit 1 ;; + *' revert '*) [ "$FTW_TEST_FAIL" != revert ] || exit 1 ;; +esac''') + block = recovery_recipe(EN, marker).replace( + 'backup_dir=/media/usb/ftw-backups', 'backup_dir=' + shlex.quote(str(backup_dir))) + self.env['FTW_TEST_FAIL'] = failure + result = subprocess.run(['bash', '-c', block], cwd=self.work, env=self.env, + capture_output=True, text=True) + calls = self.log.read_text() if self.log.exists() else '' + return result, calls + + def test_recovery_translations_use_the_same_commands(self): + for marker in ('create -state /app/data/state.db', 'restore -archive', 'revert -data'): + self.assertEqual(recovery_recipe(EN, marker), recovery_recipe(SV, marker)) + + def test_recovery_helper_failure_never_restarts_core(self): + for action, marker in (('create', 'create -state /app/data/state.db'), + ('restore', 'restore -archive'), ('revert', 'revert -data')): + with self.subTest(action=action): + self.log.write_text('') + result, calls = self.run_recovery(marker, action) + self.assertNotEqual(result.returncode, 0) + self.assertIn('docker compose stop ftw\n', calls) + self.assertIn('--entrypoint /app/ftw-backup', calls) + self.assertNotIn('docker compose start', calls) + + def test_failed_stop_does_not_run_recovery_or_start_core(self): + for marker in ('create -state /app/data/state.db', 'restore -archive', 'revert -data'): + with self.subTest(marker=marker): + self.log.write_text('') + result, calls = self.run_recovery(marker, 'stop') + self.assertNotEqual(result.returncode, 0) + self.assertNotIn('docker compose run', calls) + self.assertNotIn('docker compose start', calls) + + def test_missing_restore_archive_stops_before_touching_core(self): + result, calls = self.run_recovery('restore -archive', archive_exists=False) + self.assertNotEqual(result.returncode, 0) + self.assertEqual(calls, '') + + def test_recovery_success_starts_only_ftw_after_helper(self): + for marker in ('create -state /app/data/state.db', 'restore -archive', 'revert -data'): + with self.subTest(marker=marker): + self.log.write_text('') + result, calls = self.run_recovery(marker) + self.assertEqual(result.returncode, 0, result.stderr) + docker_calls = [call for call in calls.splitlines() if call.startswith('docker ')] + self.assertEqual(docker_calls[0], 'docker compose stop ftw') + self.assertIn('compose run --rm --no-deps --entrypoint /app/ftw-backup', docker_calls[1]) + self.assertEqual(docker_calls[2], 'docker compose start ftw') + if marker == 'restore -archive': + self.assertIn(':/backup:ro,z', docker_calls[1]) + if __name__ == '__main__': unittest.main() From bc21d11627cc196d5266949d8c75e9ebcdf1c5d4 Mon Sep 17 00:00:00 2001 From: Fredrik Ahlgren Date: Mon, 12 Oct 2026 02:33:25 +0200 Subject: [PATCH 04/29] docs: preserve settings and history in the stable switch guide --- docs/migration.md | 161 ++++++++++++++++++++++++++++++++++ docs/native-beta.md | 51 ++++++----- docs/setup-guide/update-sv.md | 46 +++++----- scripts/test_install_docs.py | 38 +++++++- 4 files changed, 248 insertions(+), 48 deletions(-) create mode 100644 docs/migration.md diff --git a/docs/migration.md b/docs/migration.md new file mode 100644 index 000000000..569527532 --- /dev/null +++ b/docs/migration.md @@ -0,0 +1,161 @@ +# Move FTW with your data + +Keep settings, history, identity, credentials, drivers and stored goals when +moving to the new line. Use a full backup and a separate target copy. Keep +the source install and an off-host backup until the target and the return +path have passed their checks. [Svenska](#svenska). + +This draft targets `v0.140.10`, which has not shipped as stable. Its published +beta is `v0.140.10-beta.1`. Data-copy tests do not establish that every old +installation can switch safely. The remaining paths below need work before +the guide can ship with stable. + +## Start from the installation you have + +| Source | Export and import | +|---|---| +| New 0.x native or Docker | Keep the existing data. Follow the [normal update](native-beta.md), including a verified full backup. | +| Old 0.x, 1.x, 2.x or SQLite-based 3.x | Export a full `.ftwbak`, or make a stopped copy of the entire data directory. Restore that backup on the separate target before its first configured start. | +| A DuckDB beta | Preserve the DuckDB file, hot SQLite, cold archives and settings together. Run [the exact target's offline converter](history-conversion.md) on the copied data before Core opens them. | +| Home Assistant app | Download a backup that includes FTW. Keep its password or encryption key. Its FTW component contains `/data`; it must be extracted and checked before making a full FTW backup. The complete Supervisor route is still being qualified. | +| Only a backup remains | Identify its format and source version from its metadata. Use the checked full-backup route, or the matching old image on a separate recovery copy. | +| Custom paths, external files or another host platform | Inventory the actual mounts, config seed, databases, archives, keys, drivers and start rules first. Resolve external paths before activation. | + +Record the actual source version, data path, config path and startup owner. +The old ready-made Pi image uses Docker. A source running a 32-bit OS can +export a stopped copy to a 64-bit Linux target; it cannot run the new binary. +These source/platform combinations still need their own installation tests. + +Active SQLite settings take precedence over an old YAML seed. The config API +masks secrets and is not a full export. Include environment files and service +or Compose definitions needed to explain the source's paths and credentials. +Preserve shared MQTT and other services used by the equipment. + +## Export a complete source copy + +Use the source version's full-backup UI or helper when it has one. Verify the +finished archive and copy it off the source host. A verified server copy does +not establish that the downloaded file has the same bytes. + +For a source without a helper, stop Core and preserve its whole data tree, +including SQLite WAL files, keys, drivers and required archives. On a +separate 64-bit Linux copy, the target's `ftw-backup create` can open legacy +SQLite read-only without upgrading it. Pass `-core-version` with the verified +**source** version and `-config` if the config seed has another name. Keep +external files and their path mapping explicit; the helper requires its +config seed inside the data tree. + +Do not start an old Core merely to inspect the migration copy. Preserve the +original bytes and use the full-backup inspector or converter. When a format +or source is unknown, keep the copy and resolve that case before starting it. + +## Restore a full backup on a new native target + +Prepare a new Linux host or Pi card with [the exact release package](native-beta.md#install). +The installer starts an empty setup service. Stop and disable it before +import, so it cannot start configured Core during an unfinished move. + +Copy the verified full backup to `/var/tmp/ftw-move.ftwbak`. Use the exact tag +installed on this target in place of `v0.X.Y`. The following block verifies, +restores and fixes ownership. It leaves Core stopped: + +```bash +( + set -eu + tag=v0.X.Y + archive=/var/tmp/ftw-move.ftwbak + helper=/opt/ftw/releases/$tag/ftw-backup + sudo test -x "$helper" + sudo systemctl disable --now ftw + sudo "$helper" verify -archive "$archive" + sudo "$helper" restore -archive "$archive" -data /var/lib/ftw -yes + sudo chown -R ftw:ftw /var/lib/ftw +) +``` + +Restore checks the archive before replacing data and prints the retained +previous-data directory. Keep that path. It maps archive-internal config +paths to `/var/lib/ftw`, while keeping other stored settings. A directory move +with unresolved external paths stops before activation. Do not remove the +path check to make a restore pass. + +For DuckDB, complete the offline conversion now, using the matching converter +package and all copied sources. Keep Core stopped until it succeeds. A file +that changed during conversion stops resume; keep the original and follow +the converter's diagnosis. + +For a new Docker target, use its separate Compose project and the +[verified restore recipe](native-beta.md#update-new-docker). Keep Core +stopped through any conversion. Do not attach new Core to the source's live +data volume. + +## Switch control and verify + +1. Stop old Core and its updater. Disable the confirmed old systemd, Compose, + timer or custom startup path. In Home Assistant, also disable **Start on + boot** and **Watchdog**. Keep needed MQTT running. +2. Confirm that the old process has stopped. A port error or one visible + dashboard does not establish that only one Core runs. +3. Start the prepared target. On native, run + `sudo systemctl enable --now ftw`. Use the saved API port; migration keeps + a custom port too. +4. Check the actual running version and binary, saved settings and credentials, + key identity, goals, representative historical periods, archive exports, + fresh device readings and new history writes. Check the plan and actual + equipment feedback before accepting control. +5. At a safe time, reboot the target and check again that old Core stays off, + exactly one Core runs, the imported data remain and new writes continue. + +If a check fails, stop new Core, preserve its data and diagnose. Return with +the matching old version and its saved data, with new Core stopped. Restore +only the source start rules recorded before the move. Keep data collected on +the target; returning does not merge those readings into old Core. + +## What the copy tests cover + +The published `.10` packages have passed representative SQLite/config copies +from 2.3.2 and 3.8, and DuckDB copies from 3.2.0-beta.1 and 3.4.2-beta.4. +The tests check settings, credentials, goals, identity, historical data, +two starts, new writes, backup/restore and matching old return. DuckDB tests +include retained long-format Parquet and resumable conversion. Earlier +0.130.4 and 1.15.0 copies were tested with `.8`; they still need current-target +qualification. + +Supervisor-format tests cover plain, compressed and encrypted version 2/3 +components using the published 3.8 HA image and `.10`. They do not cover a +complete Supervisor job, every community app, managed-driver link layout or +HA entity continuity. An isolated Linux systemd test does not establish a +physical Pi cutover or a power-loss recovery. + +Large archives on Pi/SD, external layouts, cross-platform and 32-bit sources, +complete Supervisor control, activation interruption and physical cutover +remain release requirements. Unknown formats keep their source data and +require a checked import path. + +## Svenska + +Ta med dina inställningar och data. Börja med en full backup av gamla FTW +och behåll den gamla installationen. Kontrollera filen efter kopiering till +en annan disk eller dator. Använd en separat värd eller ett nytt Pi-kort som mål. + +1. Identifiera gamla versionen, dataformatet och de faktiska filvägarna. + Aktiva SQLite-inställningar gäller före gammal YAML. Maskerad API-config + saknar hemligheter och räcker inte som backup. +2. Exportera allt som behövs: data, config, lösenord, nycklar, mål, + drivrutiner och arkiv. Home Assistant-backup behöver sin nyckel och en + kontrollerad läsare för FTW-komponenten. +3. Installera exakt målversion på den separata Linuxmaskinen. Stoppa och + stäng av nya tjänstens autostart före import. Använd blocket ovan för en + verifierad `.ftwbak`; det lämnar Core stoppad. +4. Har källan DuckDB, kör målversionens konverterare på kopian innan Core + startar. Vid ett fel: behåll båda kopiorna och lös felet. +5. Stoppa gamla Core och updater samt deras autostart. Stäng också av Home + Assistants **Start on boot** och **Watchdog**. Behåll nödvändig MQTT. +6. Starta nya Core. Kontrollera config, mål, identitet, gamla tidsperioder, + arkiv, färska enhetsvärden, plan och nya skrivningar. Upprepa efter en + planerad omstart och kontrollera att gamla Core fortfarande är avstängd. + +Vid återgång: stoppa nya Core först och använd rätt gammal version med dess +sparade data. Behåll också nya data. Guidens provade datafall är avgränsade; +hela flytten från Supervisor, egna layoutar och olika värdplattformar behöver +fortfarande egna prov före stable. diff --git a/docs/native-beta.md b/docs/native-beta.md index ad11f79ba..8a579f086 100644 --- a/docs/native-beta.md +++ b/docs/native-beta.md @@ -1,33 +1,34 @@ # Install and update FTW -**The first stable release of the new line is `v0.140.5`.** FTW 2.x and 3.x -get no more updates. [Svenska](setup-guide/update-sv.md). +**This draft targets `v0.140.10`; stable has not been published yet.** FTW +2.x and 3.x get no more updates. [Svenska](setup-guide/update-sv.md). ## Quick answer | You run | Do this | |---|---| | New FTW 0.x, native | Open **More → Version → Update FTW** in the web UI, or run `ftw update` on the box. Nothing else. | -| New FTW 0.x in Docker | Set `FTW_VERSION=v0.140.5` in `.env` and run `docker compose up -d --build`. [Details](#update-new-docker) | +| New FTW 0.x in Docker | Set `FTW_VERSION=v0.140.10` in `.env` and run `docker compose up -d --build`. [Details](#update-new-docker) | | No FTW yet, on 64-bit Linux or a new Pi card | [Install](#install) with the stable tag. | -| Old FTW 2.x, 3.x or the old Pi image | No update in place. Set up new FTW on a second SD card or host and keep the old one. [Steps](#coming-from-an-older-ftw) | -| Home Assistant app | No new app yet. Run new FTW on another Linux host and connect Home Assistant over MQTT. [Steps](#coming-from-an-older-ftw) | +| Old FTW 2.x, 3.x or the old Pi image | Move data and config through a full backup to a second SD card or host. [Steps](#coming-from-an-older-ftw) | +| Home Assistant app | Keep the app backup and move to another Linux host; keep Home Assistant on MQTT. [Steps](#coming-from-an-older-ftw) | | Windows or macOS | Not supported. Use a Raspberry Pi or another 64-bit Linux machine. | While an update runs, keep the box powered and do not press Restart. Wait for the update to finish. On native, `ftw rollback` returns to the previous compatible release. For Docker, follow [Update new Docker](#update-new-docker). -The new line starts with empty data. Moving old settings, history, identity -and goals is not ready yet. Do not copy old databases into a new install; -if you need the old data moved, ask for help with your exact installation. +**Keep your settings, history, identity and goals when you move.** Follow +[Move with your data](migration.md) to choose the source format, export a full +backup, import a separate copy and check the result before switching control. +A new site uses setup; an existing site uses its saved settings. Keep the old +installation and an off-host backup for return. -Storage conversion is one part of that move. See -[history conversion](history-conversion.md) for SQLite/Parquet and DuckDB, -and [the native pilot](self-update.md#pilot-an-older-native-systemd-site) -for its supported service layout. Neither is a general migration for Docker, -Pi images or Home Assistant. Preserve the active config and its credentials, -not just the masked config shown by the API. +The migration guide names the data cases tested with the published beta and +the work still needed for other layouts. An import error is a stop point: +keep both copies and resolve it before starting Core. The masked config API +is not a full settings export. DuckDB uses the exact target's +[history converter](history-conversion.md); it needs no intermediate release. The rest of this page has the details, for people and agents. The owner runs the host; FTW supplies the commands. Native systemd and Docker on 64-bit Linux @@ -116,10 +117,10 @@ running Core; inspect containers and their restart rules. A service called ## Coming from an older FTW Move directly to the new line using one of the paths below. Keep the old -installation and its data for recovery; the new setup does not import them. -Before switching, save device addresses, goals and schedules, and make a -verified full backup using the tools your installed version supports. Keep -that backup off the host. Not every old version has the same backup UI. +installation and its data for recovery. Use [Move with your data](migration.md) +for a verified full backup and an import into the separate target. Keep the +backup off the host. Check saved settings, credentials, goals and historical +periods on that target before it takes control. Not every old version has the same backup UI. Calendar support is gone: use loadpoint targets and ready-by schedules. **Only one Core may control the equipment.** An old Core can keep controlling @@ -144,7 +145,8 @@ new Core, and stop new Core before returning to the old install. control the same equipment. If the old card supplied MQTT, arrange a broker for the new setup. The old card's broker does not move with FTW. 6. **In SSH on the new card:** follow [Install](#install), then open - `http://:8080/setup` and set up the site again. + [import the saved data](migration.md#restore-a-full-backup-on-a-new-native-target) + before the new Core takes control. The saved API port may differ from 8080. 7. Follow [Verify the switch](#verify-the-switch). To return, shut down and put the old card back. Also stop any new FTW you ran @@ -169,10 +171,11 @@ because the native installer refused the old card. 4. Check systemd, timers and custom scripts that could recreate or start old Core or its updater at boot. Disable only the confirmed old start path. Docker's container restart policy is only one possible start path. -5. Follow [Docker](#docker) in a new directory with separate empty data, - normally `~/ftw-local`. If that directory already exists, inspect it first; - do not overwrite an earlier test or attach the old data directory. -6. Set up the site and follow [Verify the switch](#verify-the-switch). +5. Prepare [Docker](#docker) in a new directory, normally `~/ftw-local`. Keep + new Core stopped until [the copied data are imported](migration.md). Inspect + an existing target directory before using it. +6. Check the imported settings and data, then follow + [Verify the switch](#verify-the-switch). To return, stop the new project first, then start the saved old project with its original files and version pin. Restore only the start rules you disabled. @@ -192,7 +195,7 @@ return to [the second-card steps](#raspberry-pi-use-a-second-sd-card) first. This section does not update or migrate an old installation. Use the newest stable tag from [Releases](https://github.com/srcfl/ftw/releases), -`v0.140.5` or later with no `-beta` in it. Choose a beta only if you test new +`v0.140.10` or later with no `-beta` in it. Choose a beta only if you test new builds. Check that the release includes the Linux package for your architecture and its SHA-256 file. Do not use `releases/latest`: it still points to the retired 2.x line. Copy the tag from the release title; do not diff --git a/docs/setup-guide/update-sv.md b/docs/setup-guide/update-sv.md index ede28b151..0ffebc75b 100644 --- a/docs/setup-guide/update-sv.md +++ b/docs/setup-guide/update-sv.md @@ -1,16 +1,16 @@ # Byt till nya FTW och håll det uppdaterat -**Första stabila versionen av nya serien är `v0.140.5`.** FTW 2.x och 3.x får -inga fler uppdateringar. [English](../native-beta.md). +**Detta utkast gäller `v0.140.10`; stable är ännu inte publicerad.** FTW +2.x och 3.x får inga fler uppdateringar. [English](../native-beta.md). ## Kort svar | Du kör | Gör så här | |---|---| | Nya FTW 0.x, native | Öppna **More → Version → Update FTW** i webbsidan, eller kör `ftw update` på boxen. Inget mer. | -| Nya FTW 0.x i Docker | Sätt `FTW_VERSION=v0.140.5` i `.env` och kör `docker compose up -d --build`. [Detaljer](#docker-från-det-nya-releasepaketet) | +| Nya FTW 0.x i Docker | Sätt `FTW_VERSION=v0.140.10` i `.env` och kör `docker compose up -d --build`. [Detaljer](#docker-från-det-nya-releasepaketet) | | Inget FTW än, på 64-bitars Linux eller ett nytt Pi-kort | [Installera](#installera-på-det-nya-kortet-eller-en-tom-linux-maskin) med den stabila taggen. | -| Gamla FTW 2.x, 3.x eller den gamla Pi-imagen | Går inte att uppdatera på plats. Sätt upp nya FTW på ett andra SD-kort eller en annan maskin och behåll den gamla. [Steg](#byt-på-raspberry-pi-med-ett-nytt-sd-kort) | +| Gamla FTW 2.x, 3.x eller den gamla Pi-imagen | Flytta data och config med en full backup till ett andra SD-kort eller en annan maskin. [Steg](#byt-på-raspberry-pi-med-ett-nytt-sd-kort) | | Home Assistant-appen | Ingen ny app än. Kör nya FTW på en annan Linux-maskin och koppla Home Assistant via MQTT. [Steg](#välj-en-väg) | | Windows eller macOS | Stöds inte. Använd en Raspberry Pi eller en annan 64-bitars Linux-maskin. | @@ -18,19 +18,18 @@ Låt boxen ha ström och tryck inte Restart medan uppdateringen pågår. Vänta uppdateringen är klar. På native återgår `ftw rollback` till föregående kompatibla release. För Docker, följ [Docker-steget](#docker-från-det-nya-releasepaketet). -Nya serien börjar med tom data. Flytten av gamla inställningar, historik, -identitet och mål är inte klar än. Kopiera inte gamla databaser till en ny -installation; behöver du gamla data flyttade, ta hjälp med just din -installation. +**Ta med inställningar, historik, identitet och mål.** Börja med +[Flytta med din data](../migration.md#svenska). Ta en full backup, importera +på en separat kopia och kontrollera resultatet innan nya FTW tar över. +Behåll gamla installationen och en backup utanför maskinen för återgång. +En befintlig anläggning använder sina sparade inställningar. -Lagringskonvertering är en del av flytten. Läs -[historikkonvertering](../history-conversion.md) för SQLite/Parquet och DuckDB -och [native-piloten](../self-update.md#pilot-an-older-native-systemd-site) -för dess stödda tjänstelayout. De ger ingen allmän flytt för Docker, Pi-images -eller Home Assistant. Behåll aktiv config och dess hemligheter; API:t visar -maskerade värden och ger ingen full export av dem. +Guiden anger provade datafall och kvarvarande arbete för andra layoutar. +Vid ett importfel: behåll båda kopiorna och lös felet före start. Maskerad +API-config är ingen full export. DuckDB använder +[målversionens konverterare](../history-conversion.md). -Resten av sidan har detaljerna. Den nya serien börjar med `v0.131.0-beta.1`. +Den nya serien börjar med `v0.131.0-beta.1`. Äldre 0.x-versioner, till och med 0.130.x, hör till den gamla serien. `beta` i en gammal installation flyttar den inte till nya serien, och 3.x-beta är inget steg på vägen. @@ -125,10 +124,10 @@ den igen vid omboot. som kan styra samma utrustning. Ordna MQTT om utrustningen behöver det. En broker på gamla kortet följer inte med. 6. **I SSH på nya kortet:** följ [Installera på det nya kortet](#installera-på-det-nya-kortet-eller-en-tom-linux-maskin) - nedan. Öppna sedan `http://:8080/setup` och ställ in anläggningen. - Historik, inlärning och gamla inställningar ligger kvar på gamla kortet; - de följer inte automatiskt med. Använd mål och ready-by-scheman i stället - för gamla kalenderhändelser. + nedan. [Importera din backup](../migration.md#restore-a-full-backup-on-a-new-native-target) + innan nya Core tar över. Kontrollera sparade mål och inställningar. Den + sparade API-porten kan skilja sig från 8080. Använd mål och ready-by-scheman + för tidigare kalenderhändelser. 7. Kontrollera rätt version, friska enheter, färska mätvärden och aktuell plan. Starta sedan om Pi:n när anläggningen kan tåla avbrottet och kontrollera samma saker igen. @@ -144,8 +143,8 @@ du kan identifiera och stoppa gamla Core och updater, hantera deras startregler och bevara MQTT. Välj annars nytt kort eller be om hjälp. En nekad native-installation på gamla kortet är inte ett skäl att fortsätta med Docker. -Den nya Docker-installationen använder en egen katalog och egen data. -Den flyttar inte gamla data. +Den nya Docker-installationen använder en egen katalog. +[Importera en verifierad kopia](../migration.md#svenska) av dina data där. 1. Identifiera det gamla Compose-projektet, dess Core, updater, datakataloger och startregler. Vanliga kataloger är `/opt/ftw`, `~/ftw` och @@ -163,7 +162,8 @@ Den flyttar inte gamla data. Använd en ny katalog, normalt `~/ftw-local`, och en tom datakatalog. Återanvänd inte den gamla datakatalogen eller en redan befintlig testkatalog utan att först kontrollera vad den innehåller. -6. Ställ in anläggningen och kontrollera version, enheter, mätvärden och plan. +6. Importera din backup med nya Core stoppad. Kontrollera sparade inställningar, + historik, version, enheter, mätvärden och plan innan den tar över. Kontrollera att bara en Core körs och styr utrustningen. Upprepa kontrollen efter en planerad omboot. @@ -183,7 +183,7 @@ kortet, gå tillbaka till kortbytet ovan. `--fresh-host` betyder att ingen FTW-installation eller dess data finns här, även om den är stoppad. 1. Öppna [Releases](https://github.com/srcfl/ftw/releases) på din vanliga dator. - Välj den senaste **stabila** taggen, `v0.140.5` eller senare utan `-beta`. + Välj den senaste **stabila** taggen, `v0.140.10` eller senare utan `-beta`. Välj en beta bara om du provar nya byggen. Releasen ska ha Linux-paket och SHA-256-fil för din maskin. Använd inte `releases/latest`; den pekar på gamla 2.x. diff --git a/scripts/test_install_docs.py b/scripts/test_install_docs.py index c6cb9b656..489b518e4 100644 --- a/scripts/test_install_docs.py +++ b/scripts/test_install_docs.py @@ -67,6 +67,42 @@ def run_recipe(self, marker, failure='', tag='v0.138.2-beta.1'): calls = self.log.read_text() if self.log.exists() else '' return result, calls + def test_migration_restore_stops_on_failure_and_leaves_core_off(self): + blocks = re.findall(r'```bash\n(.*?)\n```', + (ROOT / 'docs/migration.md').read_text(), re.S) + block = next(b for b in blocks if 'helper=/opt/ftw/releases/' in b) + release = self.work / 'releases' / 'v0.140.10' + release.mkdir(parents=True) + helper = release / 'ftw-backup' + helper.write_text('#!/bin/bash\nset -eu\necho "helper $*" >> "$FTW_TEST_LOG"\n' + '[ "$FTW_TEST_FAIL" != "$1" ]\n') + helper.chmod(0o755) + self.stub('systemctl', 'echo "systemctl $*" >> "$FTW_TEST_LOG"') + self.stub('chown', 'echo "chown $*" >> "$FTW_TEST_LOG"') + block = block.replace('tag=v0.X.Y', 'tag=v0.140.10') + block = block.replace('/opt/ftw/releases', str(self.work / 'releases')) + block = block.replace('/var/lib/ftw', str(self.work / 'target')) + for failure in ('verify', 'restore', ''): + with self.subTest(failure=failure): + self.log.write_text('') + self.env['FTW_TEST_FAIL'] = failure + result = subprocess.run(['bash', '-c', block], env=self.env, + cwd=self.work, capture_output=True, text=True) + calls = self.log.read_text() + self.assertIn('systemctl disable --now ftw', calls) + self.assertNotIn('systemctl start', calls) + self.assertNotIn('systemctl enable', calls) + if failure: + self.assertNotEqual(result.returncode, 0) + self.assertNotIn('chown', calls) + if failure == 'verify': + self.assertNotIn('helper restore', calls) + else: + self.assertEqual(result.returncode, 0, result.stderr) + self.assertIn('helper verify', calls) + self.assertIn('helper restore', calls) + self.assertIn('chown -R ftw:ftw', calls) + def test_translations_use_the_same_native_commands(self): self.assertEqual(recipe(EN, '--fresh-host'), recipe(SV, '--fresh-host')) @@ -89,7 +125,7 @@ def test_native_download_failure_does_not_run_stale_installer(self): self.assertFalse(Path(download).exists()) def test_native_success_runs_download_and_removes_temp_file(self): - for tag in ('v0.140.5', 'v0.138.2-beta.1'): + for tag in ('v0.140.10', 'v0.138.2-beta.1'): with self.subTest(tag=tag): self.log.write_text('') result, calls = self.run_recipe('--fresh-host', tag=tag) From 9f68a1d9780dff286b047b92a7ff5c987bc24a2d Mon Sep 17 00:00:00 2001 From: Fredrik Ahlgren Date: Mon, 12 Oct 2026 03:21:35 +0200 Subject: [PATCH 05/29] docs: target the managed-driver migration beta --- docs/migration.md | 4 ++-- docs/native-beta.md | 6 +++--- docs/setup-guide/update-sv.md | 6 +++--- scripts/test_install_docs.py | 6 +++--- 4 files changed, 11 insertions(+), 11 deletions(-) diff --git a/docs/migration.md b/docs/migration.md index 569527532..ed60434ba 100644 --- a/docs/migration.md +++ b/docs/migration.md @@ -5,8 +5,8 @@ moving to the new line. Use a full backup and a separate target copy. Keep the source install and an off-host backup until the target and the return path have passed their checks. [Svenska](#svenska). -This draft targets `v0.140.10`, which has not shipped as stable. Its published -beta is `v0.140.10-beta.1`. Data-copy tests do not establish that every old +This draft targets `v0.140.11`, which has not shipped as stable. Its published +beta is `v0.140.11-beta.1`. Data-copy tests do not establish that every old installation can switch safely. The remaining paths below need work before the guide can ship with stable. diff --git a/docs/native-beta.md b/docs/native-beta.md index 8a579f086..03a407166 100644 --- a/docs/native-beta.md +++ b/docs/native-beta.md @@ -1,6 +1,6 @@ # Install and update FTW -**This draft targets `v0.140.10`; stable has not been published yet.** FTW +**This draft targets `v0.140.11`; stable has not been published yet.** FTW 2.x and 3.x get no more updates. [Svenska](setup-guide/update-sv.md). ## Quick answer @@ -8,7 +8,7 @@ | You run | Do this | |---|---| | New FTW 0.x, native | Open **More → Version → Update FTW** in the web UI, or run `ftw update` on the box. Nothing else. | -| New FTW 0.x in Docker | Set `FTW_VERSION=v0.140.10` in `.env` and run `docker compose up -d --build`. [Details](#update-new-docker) | +| New FTW 0.x in Docker | Set `FTW_VERSION=v0.140.11` in `.env` and run `docker compose up -d --build`. [Details](#update-new-docker) | | No FTW yet, on 64-bit Linux or a new Pi card | [Install](#install) with the stable tag. | | Old FTW 2.x, 3.x or the old Pi image | Move data and config through a full backup to a second SD card or host. [Steps](#coming-from-an-older-ftw) | | Home Assistant app | Keep the app backup and move to another Linux host; keep Home Assistant on MQTT. [Steps](#coming-from-an-older-ftw) | @@ -195,7 +195,7 @@ return to [the second-card steps](#raspberry-pi-use-a-second-sd-card) first. This section does not update or migrate an old installation. Use the newest stable tag from [Releases](https://github.com/srcfl/ftw/releases), -`v0.140.10` or later with no `-beta` in it. Choose a beta only if you test new +`v0.140.11` or later with no `-beta` in it. Choose a beta only if you test new builds. Check that the release includes the Linux package for your architecture and its SHA-256 file. Do not use `releases/latest`: it still points to the retired 2.x line. Copy the tag from the release title; do not diff --git a/docs/setup-guide/update-sv.md b/docs/setup-guide/update-sv.md index 0ffebc75b..7c8c44d47 100644 --- a/docs/setup-guide/update-sv.md +++ b/docs/setup-guide/update-sv.md @@ -1,6 +1,6 @@ # Byt till nya FTW och håll det uppdaterat -**Detta utkast gäller `v0.140.10`; stable är ännu inte publicerad.** FTW +**Detta utkast gäller `v0.140.11`; stable är ännu inte publicerad.** FTW 2.x och 3.x får inga fler uppdateringar. [English](../native-beta.md). ## Kort svar @@ -8,7 +8,7 @@ | Du kör | Gör så här | |---|---| | Nya FTW 0.x, native | Öppna **More → Version → Update FTW** i webbsidan, eller kör `ftw update` på boxen. Inget mer. | -| Nya FTW 0.x i Docker | Sätt `FTW_VERSION=v0.140.10` i `.env` och kör `docker compose up -d --build`. [Detaljer](#docker-från-det-nya-releasepaketet) | +| Nya FTW 0.x i Docker | Sätt `FTW_VERSION=v0.140.11` i `.env` och kör `docker compose up -d --build`. [Detaljer](#docker-från-det-nya-releasepaketet) | | Inget FTW än, på 64-bitars Linux eller ett nytt Pi-kort | [Installera](#installera-på-det-nya-kortet-eller-en-tom-linux-maskin) med den stabila taggen. | | Gamla FTW 2.x, 3.x eller den gamla Pi-imagen | Flytta data och config med en full backup till ett andra SD-kort eller en annan maskin. [Steg](#byt-på-raspberry-pi-med-ett-nytt-sd-kort) | | Home Assistant-appen | Ingen ny app än. Kör nya FTW på en annan Linux-maskin och koppla Home Assistant via MQTT. [Steg](#välj-en-väg) | @@ -183,7 +183,7 @@ kortet, gå tillbaka till kortbytet ovan. `--fresh-host` betyder att ingen FTW-installation eller dess data finns här, även om den är stoppad. 1. Öppna [Releases](https://github.com/srcfl/ftw/releases) på din vanliga dator. - Välj den senaste **stabila** taggen, `v0.140.10` eller senare utan `-beta`. + Välj den senaste **stabila** taggen, `v0.140.11` eller senare utan `-beta`. Välj en beta bara om du provar nya byggen. Releasen ska ha Linux-paket och SHA-256-fil för din maskin. Använd inte `releases/latest`; den pekar på gamla 2.x. diff --git a/scripts/test_install_docs.py b/scripts/test_install_docs.py index 489b518e4..eca064588 100644 --- a/scripts/test_install_docs.py +++ b/scripts/test_install_docs.py @@ -71,7 +71,7 @@ def test_migration_restore_stops_on_failure_and_leaves_core_off(self): blocks = re.findall(r'```bash\n(.*?)\n```', (ROOT / 'docs/migration.md').read_text(), re.S) block = next(b for b in blocks if 'helper=/opt/ftw/releases/' in b) - release = self.work / 'releases' / 'v0.140.10' + release = self.work / 'releases' / 'v0.140.11' release.mkdir(parents=True) helper = release / 'ftw-backup' helper.write_text('#!/bin/bash\nset -eu\necho "helper $*" >> "$FTW_TEST_LOG"\n' @@ -79,7 +79,7 @@ def test_migration_restore_stops_on_failure_and_leaves_core_off(self): helper.chmod(0o755) self.stub('systemctl', 'echo "systemctl $*" >> "$FTW_TEST_LOG"') self.stub('chown', 'echo "chown $*" >> "$FTW_TEST_LOG"') - block = block.replace('tag=v0.X.Y', 'tag=v0.140.10') + block = block.replace('tag=v0.X.Y', 'tag=v0.140.11') block = block.replace('/opt/ftw/releases', str(self.work / 'releases')) block = block.replace('/var/lib/ftw', str(self.work / 'target')) for failure in ('verify', 'restore', ''): @@ -125,7 +125,7 @@ def test_native_download_failure_does_not_run_stale_installer(self): self.assertFalse(Path(download).exists()) def test_native_success_runs_download_and_removes_temp_file(self): - for tag in ('v0.140.10', 'v0.138.2-beta.1'): + for tag in ('v0.140.11', 'v0.138.2-beta.1'): with self.subTest(tag=tag): self.log.write_text('') result, calls = self.run_recipe('--fresh-host', tag=tag) From b9d8f37aa56f9b233fe4e81ac8df2863f45e76a9 Mon Sep 17 00:00:00 2001 From: Fredrik Ahlgren Date: Mon, 12 Oct 2026 05:09:32 +0200 Subject: [PATCH 06/29] docs(migration): link checked HA exporter and current copy scope --- docs/migration.md | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff --git a/docs/migration.md b/docs/migration.md index ed60434ba..13885c7df 100644 --- a/docs/migration.md +++ b/docs/migration.md @@ -17,7 +17,7 @@ the guide can ship with stable. | New 0.x native or Docker | Keep the existing data. Follow the [normal update](native-beta.md), including a verified full backup. | | Old 0.x, 1.x, 2.x or SQLite-based 3.x | Export a full `.ftwbak`, or make a stopped copy of the entire data directory. Restore that backup on the separate target before its first configured start. | | A DuckDB beta | Preserve the DuckDB file, hot SQLite, cold archives and settings together. Run [the exact target's offline converter](history-conversion.md) on the copied data before Core opens them. | -| Home Assistant app | Download a backup that includes FTW. Keep its password or encryption key. Its FTW component contains `/data`; it must be extracted and checked before making a full FTW backup. The complete Supervisor route is still being qualified. | +| Home Assistant app | Download a backup that includes FTW and keep its key. Use the [offline HA exporter](https://github.com/srcfl/ftw/releases/tag/ha-export-v1-beta.1) to check and copy its FTW component, then make a full FTW backup at the old `/data` root. The complete Supervisor route is still being qualified. | | Only a backup remains | Identify its format and source version from its metadata. Use the checked full-backup route, or the matching old image on a separate recovery copy. | | Custom paths, external files or another host platform | Inventory the actual mounts, config seed, databases, archives, keys, drivers and start rules first. Resolve external paths before activation. | @@ -49,6 +49,15 @@ Do not start an old Core merely to inspect the migration copy. Preserve the original bytes and use the full-backup inspector or converter. When a format or source is unknown, keep the copy and resolve that case before starting it. +For a Home Assistant backup, follow the exporter's included README. It needs +Linux and Python 3.11 or later, checks plain and protected v2/v3 components, +and keeps checked internal driver links. It refuses outside links and unknown +layouts. The extracted copy must be writable when the FTW helper opens old +SQLite; WAL/SHM sidecars may be needed. Keep the original backup unchanged. +Use the printed source version in `ftw-backup create -core-version`, and mount +the extracted data at `/data` when making the full backup. That preserves the +source root for verified relocation; a host path is not a replacement for it. + ## Restore a full backup on a new native target Prepare a new Linux host or Pi card with [the exact release package](native-beta.md#install). @@ -113,8 +122,9 @@ the target; returning does not merge those readings into old Core. ## What the copy tests cover -The published `.10` packages have passed representative SQLite/config copies -from 2.3.2 and 3.8, and DuckDB copies from 3.2.0-beta.1 and 3.4.2-beta.4. +The published `.11` packages have passed representative SQLite/config copies +from 2.3.2 and 3.8, and DuckDB copies from 3.2.0-beta.1. The 3.4.2-beta.4 +DuckDB proof used `.10` and still needs current-target qualification. The tests check settings, credentials, goals, identity, historical data, two starts, new writes, backup/restore and matching old return. DuckDB tests include retained long-format Parquet and resumable conversion. Earlier @@ -122,9 +132,10 @@ include retained long-format Parquet and resumable conversion. Earlier qualification. Supervisor-format tests cover plain, compressed and encrypted version 2/3 -components using the published 3.8 HA image and `.10`. They do not cover a -complete Supervisor job, every community app, managed-driver link layout or -HA entity continuity. An isolated Linux systemd test does not establish a +components using the published 3.8 HA image. The offline exporter and `.11` +copy tests also cover synthetic managed-driver choices and internal links. +They do not cover a complete Supervisor job, every community app, a signed +driver-channel move or HA entity continuity. An isolated Linux systemd test does not establish a physical Pi cutover or a power-loss recovery. Large archives on Pi/SD, external layouts, cross-platform and 32-bit sources, @@ -142,8 +153,9 @@ en annan disk eller dator. Använd en separat värd eller ett nytt Pi-kort som m Aktiva SQLite-inställningar gäller före gammal YAML. Maskerad API-config saknar hemligheter och räcker inte som backup. 2. Exportera allt som behövs: data, config, lösenord, nycklar, mål, - drivrutiner och arkiv. Home Assistant-backup behöver sin nyckel och en - kontrollerad läsare för FTW-komponenten. + drivrutiner och arkiv. Home Assistant-backup behöver sin nyckel. Använd + den länkade exportören för FTW-komponenten och följ dess README för full + backup med den gamla roten `/data`. 3. Installera exakt målversion på den separata Linuxmaskinen. Stoppa och stäng av nya tjänstens autostart före import. Använd blocket ovan för en verifierad `.ftwbak`; det lämnar Core stoppad. From f67595a5a22e907e243d144227194066856a2f3e Mon Sep 17 00:00:00 2001 From: Fredrik Ahlgren Date: Mon, 12 Oct 2026 08:25:42 +0200 Subject: [PATCH 07/29] docs: retain all copies when migration is interrupted --- docs/backup-and-restore.md | 9 +++++++++ docs/migration.md | 30 +++++++++++++++++++++++++++--- docs/native-beta.md | 6 +++--- docs/setup-guide/update-sv.md | 6 +++--- 4 files changed, 42 insertions(+), 9 deletions(-) diff --git a/docs/backup-and-restore.md b/docs/backup-and-restore.md index bae7d0a58..f863f06fe 100644 --- a/docs/backup-and-restore.md +++ b/docs/backup-and-restore.md @@ -169,6 +169,15 @@ Pass `-config` to `create` when the seed has a name other than `/config.yaml`. The config seed must be inside the data directory. + +From `v0.141.0-beta.1`, the helper records and checks a complete previous file +list before revert. An interrupted move or an older safety point without that +record stops before another import or revert can certify a partial directory. +Keep Core stopped and retain all directories. Restore a verified full backup +to a separate target; do not remove the check or discard newer readings. +A returned `safety_complete: false` refers to the retained rejected target, +which must not be reactivated. See [the migration guide](migration.md#if-import-or-return-stops). + ## Svenska – kortversion att skicka till en användare 1. Sätt i ett USB-minne eller anslut en annan disk till datorn där FTW körs. diff --git a/docs/migration.md b/docs/migration.md index 13885c7df..104ea4aff 100644 --- a/docs/migration.md +++ b/docs/migration.md @@ -5,8 +5,8 @@ moving to the new line. Use a full backup and a separate target copy. Keep the source install and an off-host backup until the target and the return path have passed their checks. [Svenska](#svenska). -This draft targets `v0.140.11`, which has not shipped as stable. Its published -beta is `v0.140.11-beta.1`. Data-copy tests do not establish that every old +This draft targets `v0.141.0`, which has not shipped as stable. Its next +beta is `v0.141.0-beta.1`; package qualification is pending. Data-copy tests do not establish that every old installation can switch safely. The remaining paths below need work before the guide can ship with stable. @@ -98,6 +98,23 @@ For a new Docker target, use its separate Compose project and the stopped through any conversion. Do not attach new Core to the source's live data volume. +## If import or return stops + +Keep both Core processes and their autostart off. Retain the full backup and +all active, staging and safety directories. Do not delete a hidden directory +or bypass a check to make the command succeed. + +The new helper checks a restore point's complete file list before reverting. +It refuses a partial point, an older point without that record, or a retry +that would treat a partly moved active directory as complete. Recover the +verified full backup into a separate directory instead; retain the current +files too, including readings written after that backup. + +If recovery returns `safety_complete: false`, the previous complete data have +returned, but the retained rejected target is partial. Keep it for inspection; +do not start Core from it or try to switch back to it. Check the recovered +installation and its start rules before enabling control. + ## Switch control and verify 1. Stop old Core and its updater. Disable the confirmed old systemd, Compose, @@ -122,7 +139,7 @@ the target; returning does not merge those readings into old Core. ## What the copy tests cover -The published `.11` packages have passed representative SQLite/config copies +The published `v0.140.11-beta.1` packages have passed representative SQLite/config copies from 2.3.2 and 3.8, and DuckDB copies from 3.2.0-beta.1. The 3.4.2-beta.4 DuckDB proof used `.10` and still needs current-target qualification. The tests check settings, credentials, goals, identity, historical data, @@ -167,6 +184,13 @@ en annan disk eller dator. Använd en separat värd eller ett nytt Pi-kort som m arkiv, färska enhetsvärden, plan och nya skrivningar. Upprepa efter en planerad omstart och kontrollera att gamla Core fortfarande är avstängd. +Vid ett avbrott eller fel: håll båda Core och deras autostart avstängda. +Behåll backupen och alla data-, staging- och återställningskataloger. En +ofullständig eller äldre återställningspunkt utan kvitto ska inte tvingas +igång. Återställ fullbackupen till en separat katalog och behåll också data +som skrevs efter backupen. `safety_complete: false` betyder att den sparade +avvisade målkopian är ofullständig; använd den inte för en ny start. + Vid återgång: stoppa nya Core först och använd rätt gammal version med dess sparade data. Behåll också nya data. Guidens provade datafall är avgränsade; hela flytten från Supervisor, egna layoutar och olika värdplattformar behöver diff --git a/docs/native-beta.md b/docs/native-beta.md index 03a407166..dfbae0c03 100644 --- a/docs/native-beta.md +++ b/docs/native-beta.md @@ -1,6 +1,6 @@ # Install and update FTW -**This draft targets `v0.140.11`; stable has not been published yet.** FTW +**This draft targets `v0.141.0`; stable has not been published yet.** FTW 2.x and 3.x get no more updates. [Svenska](setup-guide/update-sv.md). ## Quick answer @@ -8,7 +8,7 @@ | You run | Do this | |---|---| | New FTW 0.x, native | Open **More → Version → Update FTW** in the web UI, or run `ftw update` on the box. Nothing else. | -| New FTW 0.x in Docker | Set `FTW_VERSION=v0.140.11` in `.env` and run `docker compose up -d --build`. [Details](#update-new-docker) | +| New FTW 0.x in Docker | Set `FTW_VERSION=v0.141.0` in `.env` and run `docker compose up -d --build`. [Details](#update-new-docker) | | No FTW yet, on 64-bit Linux or a new Pi card | [Install](#install) with the stable tag. | | Old FTW 2.x, 3.x or the old Pi image | Move data and config through a full backup to a second SD card or host. [Steps](#coming-from-an-older-ftw) | | Home Assistant app | Keep the app backup and move to another Linux host; keep Home Assistant on MQTT. [Steps](#coming-from-an-older-ftw) | @@ -195,7 +195,7 @@ return to [the second-card steps](#raspberry-pi-use-a-second-sd-card) first. This section does not update or migrate an old installation. Use the newest stable tag from [Releases](https://github.com/srcfl/ftw/releases), -`v0.140.11` or later with no `-beta` in it. Choose a beta only if you test new +`v0.141.0` or later with no `-beta` in it. Choose a beta only if you test new builds. Check that the release includes the Linux package for your architecture and its SHA-256 file. Do not use `releases/latest`: it still points to the retired 2.x line. Copy the tag from the release title; do not diff --git a/docs/setup-guide/update-sv.md b/docs/setup-guide/update-sv.md index 7c8c44d47..730471bfb 100644 --- a/docs/setup-guide/update-sv.md +++ b/docs/setup-guide/update-sv.md @@ -1,6 +1,6 @@ # Byt till nya FTW och håll det uppdaterat -**Detta utkast gäller `v0.140.11`; stable är ännu inte publicerad.** FTW +**Detta utkast gäller `v0.141.0`; stable är ännu inte publicerad.** FTW 2.x och 3.x får inga fler uppdateringar. [English](../native-beta.md). ## Kort svar @@ -8,7 +8,7 @@ | Du kör | Gör så här | |---|---| | Nya FTW 0.x, native | Öppna **More → Version → Update FTW** i webbsidan, eller kör `ftw update` på boxen. Inget mer. | -| Nya FTW 0.x i Docker | Sätt `FTW_VERSION=v0.140.11` i `.env` och kör `docker compose up -d --build`. [Detaljer](#docker-från-det-nya-releasepaketet) | +| Nya FTW 0.x i Docker | Sätt `FTW_VERSION=v0.141.0` i `.env` och kör `docker compose up -d --build`. [Detaljer](#docker-från-det-nya-releasepaketet) | | Inget FTW än, på 64-bitars Linux eller ett nytt Pi-kort | [Installera](#installera-på-det-nya-kortet-eller-en-tom-linux-maskin) med den stabila taggen. | | Gamla FTW 2.x, 3.x eller den gamla Pi-imagen | Flytta data och config med en full backup till ett andra SD-kort eller en annan maskin. [Steg](#byt-på-raspberry-pi-med-ett-nytt-sd-kort) | | Home Assistant-appen | Ingen ny app än. Kör nya FTW på en annan Linux-maskin och koppla Home Assistant via MQTT. [Steg](#välj-en-väg) | @@ -183,7 +183,7 @@ kortet, gå tillbaka till kortbytet ovan. `--fresh-host` betyder att ingen FTW-installation eller dess data finns här, även om den är stoppad. 1. Öppna [Releases](https://github.com/srcfl/ftw/releases) på din vanliga dator. - Välj den senaste **stabila** taggen, `v0.140.11` eller senare utan `-beta`. + Välj den senaste **stabila** taggen, `v0.141.0` eller senare utan `-beta`. Välj en beta bara om du provar nya byggen. Releasen ska ha Linux-paket och SHA-256-fil för din maskin. Använd inte `releases/latest`; den pekar på gamla 2.x. From a6ee340d0c64478c77edef112a50d01a568ea1ba Mon Sep 17 00:00:00 2001 From: Fredrik Ahlgren Date: Mon, 12 Oct 2026 08:49:40 +0200 Subject: [PATCH 08/29] docs: record published migration copy checks --- docs/migration.md | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/docs/migration.md b/docs/migration.md index 104ea4aff..5f27cbd8e 100644 --- a/docs/migration.md +++ b/docs/migration.md @@ -5,8 +5,8 @@ moving to the new line. Use a full backup and a separate target copy. Keep the source install and an off-host backup until the target and the return path have passed their checks. [Svenska](#svenska). -This draft targets `v0.141.0`, which has not shipped as stable. Its next -beta is `v0.141.0-beta.1`; package qualification is pending. Data-copy tests do not establish that every old +This draft targets `v0.141.0`, which has not shipped as stable. The published +beta is `v0.141.0-beta.1`. Data-copy tests do not establish that every old installation can switch safely. The remaining paths below need work before the guide can ship with stable. @@ -140,7 +140,8 @@ the target; returning does not merge those readings into old Core. ## What the copy tests cover The published `v0.140.11-beta.1` packages have passed representative SQLite/config copies -from 2.3.2 and 3.8, and DuckDB copies from 3.2.0-beta.1. The 3.4.2-beta.4 +from 2.3.2 and 3.8. The published `v0.141.0-beta.1` Core and converter pair +passed DuckDB copies from 3.2.0-beta.1. The 3.4.2-beta.4 DuckDB proof used `.10` and still needs current-target qualification. The tests check settings, credentials, goals, identity, historical data, two starts, new writes, backup/restore and matching old return. DuckDB tests @@ -149,14 +150,21 @@ include retained long-format Parquet and resumable conversion. Earlier qualification. Supervisor-format tests cover plain, compressed and encrypted version 2/3 -components using the published 3.8 HA image. The offline exporter and `.11` +components using the published 3.8 HA image. The offline exporter and `v0.141.0-beta.1` copy tests also cover synthetic managed-driver choices and internal links. They do not cover a complete Supervisor job, every community app, a signed driver-channel move or HA entity continuity. An isolated Linux systemd test does not establish a physical Pi cutover or a power-loss recovery. +The published `v0.141.0-beta.1` Linux ARM64 backup helper also passed process +crash tests during preservation, activation, return and a later extraction. +The tests check that incomplete copies cannot replace active data, all old +and new files remain, and a complete backup can restore on a separate target. +These tests use synthetic files and do not prove recovery from physical +power loss or an interrupted installation change. + Large archives on Pi/SD, external layouts, cross-platform and 32-bit sources, -complete Supervisor control, activation interruption and physical cutover +complete Supervisor control, interrupted installation changes and physical cutover remain release requirements. Unknown formats keep their source data and require a checked import path. From fe3f5c7053934359447f4055ad68272a7aa362f7 Mon Sep 17 00:00:00 2001 From: Fredrik Ahlgren Date: Mon, 12 Oct 2026 11:17:59 +0200 Subject: [PATCH 09/29] docs: record verified two-host native migration scope --- docs/migration.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/docs/migration.md b/docs/migration.md index 5f27cbd8e..62bf1aa63 100644 --- a/docs/migration.md +++ b/docs/migration.md @@ -156,6 +156,15 @@ They do not cover a complete Supervisor job, every community app, a signed driver-channel move or HA entity continuity. An isolated Linux systemd test does not establish a physical Pi cutover or a power-loss recovery. +A separate two-host Linux ARM64 test moved a synthetic 3.8 custom systemd +source to a fresh `v0.141.0-beta.1` native target. The exact published old +helper created the full backup. Both hosts restarted with only the selected +Core enabled. The checks retained the source's exact chart rows and stored +hours, settings, credentials, goals and keys, verified new writes, and +returned to the matching old binary while keeping the target data. The +installer ran on the fresh target; this does not qualify an in-place +install, every custom service, physical equipment or a Pi power cycle. + The published `v0.141.0-beta.1` Linux ARM64 backup helper also passed process crash tests during preservation, activation, return and a later extraction. The tests check that incomplete copies cannot replace active data, all old From db73c91693fb1f08a03ef6df70d29308877dfa15 Mon Sep 17 00:00:00 2001 From: Fredrik Ahlgren Date: Mon, 12 Oct 2026 12:13:37 +0200 Subject: [PATCH 10/29] docs: keep shared MQTT running during Docker migration --- docs/migration.md | 9 +++++++++ docs/native-beta.md | 16 ++++++++++++---- docs/setup-guide/update-sv.md | 17 ++++++++++++----- 3 files changed, 33 insertions(+), 9 deletions(-) diff --git a/docs/migration.md b/docs/migration.md index 62bf1aa63..8187f4e60 100644 --- a/docs/migration.md +++ b/docs/migration.md @@ -165,6 +165,15 @@ returned to the matching old binary while keeping the target data. The installer ran on the fresh target; this does not qualify an in-place install, every custom service, physical equipment or a Pi power cycle. +The published 2.3.2 Docker image also passed a move to `v0.141.0-beta.1` +using two Compose projects and separate named data volumes. A synthetic +MQTT meter and an independent subscriber used the same broker throughout +backup, two target starts and return to old Core. The checks retained exact +old chart rows, settings, credentials, goals, identity and Lua files, and +verified new writes. The broker and subscriber kept their process start +times. The test checked saved Compose and container restart policies; it +did not reboot Docker or the host, run the old updater, or control equipment. + The published `v0.141.0-beta.1` Linux ARM64 backup helper also passed process crash tests during preservation, activation, return and a later extraction. The tests check that incomplete copies cannot replace active data, all old diff --git a/docs/native-beta.md b/docs/native-beta.md index dfbae0c03..2bc9a57a5 100644 --- a/docs/native-beta.md +++ b/docs/native-beta.md @@ -164,13 +164,21 @@ because the native installer refused the old card. `~/forty-two-watts`; use the path found on this host. Save its Compose files and `.env` with the backup so recovery uses the same old version. 2. Check whether that project also supplies Mosquitto or another needed - service. Arrange continued MQTT before stopping the whole project. -3. Stop the old project with its actual files and project name. For a standard - project, run `docker compose down` from its directory (with `sudo` if - required). Do not add `-v`, delete data, or stop Docker as a whole. + service. Keep those services running. Use `docker compose config --services` + with the source's actual files and project name to identify them. +3. Stop only the confirmed Core and updater services. For a Core service named + `ftw`, run `docker compose stop ftw`, then + `docker update --restart=no "$(docker compose ps -aq ftw)"`. Repeat for an + updater if one exists. Set `restart: "no"` for those services in the saved + source Compose files too. Check that their containers are stopped and their + restart policies are `no`. Do not run `docker compose down` while that + project still supplies needed MQTT. Do not add `-v` or delete data. 4. Check systemd, timers and custom scripts that could recreate or start old Core or its updater at boot. Disable only the confirmed old start path. Docker's container restart policy is only one possible start path. + When keeping the broker, name its service in later Compose commands. + `docker compose up -d` for the whole old project starts old Core again, + even with `restart: "no"`. 5. Prepare [Docker](#docker) in a new directory, normally `~/ftw-local`. Keep new Core stopped until [the copied data are imported](migration.md). Inspect an existing target directory before using it. diff --git a/docs/setup-guide/update-sv.md b/docs/setup-guide/update-sv.md index 730471bfb..d8a1dcd68 100644 --- a/docs/setup-guide/update-sv.md +++ b/docs/setup-guide/update-sv.md @@ -152,12 +152,19 @@ Den nya Docker-installationen använder en egen katalog. 2. Ta en full backup och spara den utanför maskinen. Behåll också Compose-filer, overrides och `.env`, så att du kan återställa rätt gamla version. 3. Kontrollera om projektet även kör Mosquitto eller andra tjänster som - utrustningen behöver. Ordna fortsatt MQTT innan du stoppar hela projektet. -4. Stoppa den gamla installationen med dess riktiga Compose-filer och - projektnamn. Ett vanligt projekt kan stoppas med `docker compose down` - från rätt katalog. Använd inte `-v` och radera inga datakataloger. + utrustningen behöver. Behåll dem igång. Identifiera tjänsterna med + `docker compose config --services`, projektets riktiga filer och projektnamn. +4. Stoppa bara gamla Core och updater. Heter Core-tjänsten `ftw`, kör + `docker compose stop ftw`, sedan + `docker update --restart=no "$(docker compose ps -aq ftw)"`. Gör samma sak + för updater om den finns. Sätt också `restart: "no"` för dessa tjänster i + gamla Compose-filerna. Kontrollera att containrarna är stoppade och har + restart policy `no`. Kör inte `docker compose down` om projektet fortfarande + ger utrustningen MQTT. Använd inte `-v` och radera inga datakataloger. Kontrollera även systemd, timers och egna skript som kan skapa eller starta - den igen. Stäng inte av Docker som helhet. + den igen. Ange brokerns tjänstenamn i senare Compose-kommandon: + `docker compose up -d` för hela gamla projektet startar gamla Core igen, + även med `restart: "no"`. Stäng inte av Docker som helhet. 5. Följ [Docker-guiden för nya FTW](https://github.com/srcfl/ftw/blob/master/docs/native-beta.md#docker). Använd en ny katalog, normalt `~/ftw-local`, och en tom datakatalog. Återanvänd inte den gamla datakatalogen eller en redan befintlig testkatalog From e934b39f0c5d7505a43014714858589d10128e52 Mon Sep 17 00:00:00 2001 From: Fredrik Ahlgren Date: Mon, 12 Oct 2026 13:04:43 +0200 Subject: [PATCH 11/29] docs: qualify Linux migration across CPU architectures --- docs/migration.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/docs/migration.md b/docs/migration.md index 8187f4e60..44d1abb69 100644 --- a/docs/migration.md +++ b/docs/migration.md @@ -174,6 +174,14 @@ verified new writes. The broker and subscriber kept their process start times. The test checked saved Compose and container restart policies; it did not reboot Docker or the host, run the old updater, or control equipment. +A separate test moved the published 2.3.2 AMD64 Docker image to the published +`v0.141.0-beta.1` ARM64 Core and helper. All 29 checks passed, including two +target starts, new writes and return to old Core with data, settings, +credentials, goals, identity and shared MQTT retained. Both binary architectures +were checked. The AMD64 source ran through emulation on Apple Silicon. +This covers the tested Linux Docker copy across CPU architectures; it does +not qualify 32-bit sources or native macOS/Windows paths. + The published `v0.141.0-beta.1` Linux ARM64 backup helper also passed process crash tests during preservation, activation, return and a later extraction. The tests check that incomplete copies cannot replace active data, all old From e965060b51c4dc3378150bae9472fa35e057017e Mon Sep 17 00:00:00 2001 From: Fredrik Ahlgren Date: Mon, 12 Oct 2026 15:00:00 +0200 Subject: [PATCH 12/29] docs: qualify legacy copies against current beta --- docs/migration.md | 28 +++++++++++++++++++--------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/docs/migration.md b/docs/migration.md index 44d1abb69..80d4d62c3 100644 --- a/docs/migration.md +++ b/docs/migration.md @@ -139,15 +139,25 @@ the target; returning does not merge those readings into old Core. ## What the copy tests cover -The published `v0.140.11-beta.1` packages have passed representative SQLite/config copies -from 2.3.2 and 3.8. The published `v0.141.0-beta.1` Core and converter pair -passed DuckDB copies from 3.2.0-beta.1. The 3.4.2-beta.4 -DuckDB proof used `.10` and still needs current-target qualification. -The tests check settings, credentials, goals, identity, historical data, -two starts, new writes, backup/restore and matching old return. DuckDB tests -include retained long-format Parquet and resumable conversion. Earlier -0.130.4 and 1.15.0 copies were tested with `.8`; they still need current-target -qualification. +The published `v0.141.0-beta.1` packages have passed representative +SQLite/settings copies from 0.130.4, 1.15.0, 2.3.2 and 3.8.0-beta.1. +The matching Core and converter pair also passed DuckDB copies from +3.2.0-beta.1 and 3.4.2-beta.4. Each test uses the published old binary or +image and synthetic data. The checks retain exact old chart rows, settings, +credentials, goals and identity over two target starts, new writes and +return to the matching old Core. + +Those four SQLite sources also passed full-backup restore to both the same +data path and a new path with the published target helper. Two synthetic +Parquet rows in the old 2.x long format retain their bytes and JSON/CSV +exports over two target starts. Stored settings, credentials, goals, +identity and new writes remain, and revert returns the previous target. +These small cases do not cover every older cold format or external file. + +DuckDB tests include hot SQLite, imported or retained long-format Parquet, +500,000 extra raw values, interrupted conversion and resume, generation +checks and portable backup/restore/revert. These copies do not qualify every +old schema, archive format, platform or complete installation change. Supervisor-format tests cover plain, compressed and encrypted version 2/3 components using the published 3.8 HA image. The offline exporter and `v0.141.0-beta.1` From 1736deab5ac84de367f9b4dfc0a18cbdd776b71c Mon Sep 17 00:00:00 2001 From: Fredrik Ahlgren Date: Mon, 12 Oct 2026 16:28:21 +0200 Subject: [PATCH 13/29] docs: qualify the native migration pilot --- docs/migration.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/docs/migration.md b/docs/migration.md index 80d4d62c3..bc0593f80 100644 --- a/docs/migration.md +++ b/docs/migration.md @@ -175,6 +175,16 @@ returned to the matching old binary while keeping the target data. The installer ran on the fresh target; this does not qualify an in-place install, every custom service, physical equipment or a Pi power cycle. +A separate same-host test used the [native pilot](self-update.md#pilot-an-older-native-systemd-site) +with a synthetic 3.8 systemd source: `/opt/ftw/ftw`, the `ftw` user and a +data bind. The corrected operator CLI and published `v0.141.0-beta.1` +package passed 24 checks. Charts, stored hours, settings, credentials, +goals, identity and new writes survived the switch and a machine restart +with one Core. Return to the matching old Core passed another restart, +and both off-host backups remain. This covers that Linux pilot layout; +it does not qualify every native install or physical power loss. The +normal fresh-host installer still refuses an existing installation. + The published 2.3.2 Docker image also passed a move to `v0.141.0-beta.1` using two Compose projects and separate named data volumes. A synthetic MQTT meter and an independent subscriber used the same broker throughout From eac8d3474ea1b8e8415639aed18676efd13e2d4c Mon Sep 17 00:00:00 2001 From: Fredrik Ahlgren Date: Mon, 12 Oct 2026 16:59:45 +0200 Subject: [PATCH 14/29] docs: pin the verified pilot operator script --- docs/self-update.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/self-update.md b/docs/self-update.md index 9748238b7..c086418a8 100644 --- a/docs/self-update.md +++ b/docs/self-update.md @@ -44,11 +44,13 @@ exact 0.x tags. Publication never installs a release on a site by itself. ### Pilot: an older native systemd site This is not the user migration path. `migrate-native` in the -[operator CLI](../scripts/ftwctl.py) moves an older **direct native systemd** +[operator CLI](https://github.com/srcfl/ftw/blob/af22b488cbda7945d78d30a915fa81b71fe8f1ce/scripts/ftwctl.py) moves an older **direct native systemd** site, one whose unit runs `/opt/ftw/ftw` as the `ftw` user, onto 0.x release slots. The owner's home box was moved with it. It stages the release under a separate root, `/opt/ftw-native` by default, and switches the unit with a -drop-in, so such a box keeps a different layout from a fresh install. Run it +drop-in, so such a box keeps a different layout from a fresh install. Use +the linked script revision on the operator computer; older release checkouts +can reject a valid backup timestamp on older Python. Run it on another computer, through an SSH tunnel to the box's API: ```bash From 81bfb9ec00dc1357708499bd848ac8005cd43e7e Mon Sep 17 00:00:00 2001 From: Fredrik Ahlgren Date: Mon, 12 Oct 2026 17:39:44 +0200 Subject: [PATCH 15/29] docs: qualify current managed drivers and million-row archive copies --- docs/migration.md | 18 ++++++++++++++++-- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/docs/migration.md b/docs/migration.md index bc0593f80..f98119fc9 100644 --- a/docs/migration.md +++ b/docs/migration.md @@ -154,6 +154,14 @@ exports over two target starts. Stored settings, credentials, goals, identity and new writes remain, and revert returns the previous target. These small cases do not cover every older cold format or external file. +A separate 2.3.2 archive test passed 37 checks with 1,036,800 synthetic +Parquet values in ten daily files and twelve series. Restore to the same +and a new root retained exact hourly counts, sums, minimums, maximums and last timestamps +over two starts. JSON/CSV exports, settings, goals, identity, new writes, +revert and raw exports from the matching old Core passed. The compressed +files total about 9 MiB; this tests row count on Linux ARM64 in Docker, +not a large disk footprint, Pi/SD performance or physical power loss. + DuckDB tests include hot SQLite, imported or retained long-format Parquet, 500,000 extra raw values, interrupted conversion and resume, generation checks and portable backup/restore/revert. These copies do not qualify every @@ -163,8 +171,14 @@ Supervisor-format tests cover plain, compressed and encrypted version 2/3 components using the published 3.8 HA image. The offline exporter and `v0.141.0-beta.1` copy tests also cover synthetic managed-driver choices and internal links. They do not cover a complete Supervisor job, every community app, a signed -driver-channel move or HA entity continuity. An isolated Linux systemd test does not establish a -physical Pi cutover or a power-loss recovery. +driver-channel move or HA entity continuity. An isolated Linux systemd test +does not establish a physical Pi cutover or a power-loss recovery. + +Four separate managed-driver copy tests also passed with the published +`v0.141.0-beta.1` helper and Core. Current and older default manifests, +same and new data roots, two starts and revert keep the selected driver +active and preserve its previous-version path. These checks use synthetic +records and valid file hashes; they do not prove a signed-channel install. A separate two-host Linux ARM64 test moved a synthetic 3.8 custom systemd source to a fresh `v0.141.0-beta.1` native target. The exact published old From 0b5784d0ac552ef64c3aa9936146ce1b84c10b04 Mon Sep 17 00:00:00 2001 From: Fredrik Ahlgren Date: Mon, 12 Oct 2026 20:45:45 +0200 Subject: [PATCH 16/29] docs: track the published partial-history beta Signed-off-by: Fredrik Ahlgren --- docs/migration.md | 13 +++++++++++-- docs/native-beta.md | 6 +++--- docs/setup-guide/update-sv.md | 6 +++--- 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/docs/migration.md b/docs/migration.md index f98119fc9..2e316568e 100644 --- a/docs/migration.md +++ b/docs/migration.md @@ -5,8 +5,8 @@ moving to the new line. Use a full backup and a separate target copy. Keep the source install and an off-host backup until the target and the return path have passed their checks. [Svenska](#svenska). -This draft targets `v0.141.0`, which has not shipped as stable. The published -beta is `v0.141.0-beta.1`. Data-copy tests do not establish that every old +This draft targets `v0.141.2`, which has not shipped as stable. The published +beta is `v0.141.2-beta.1`. Data-copy tests do not establish that every old installation can switch safely. The remaining paths below need work before the guide can ship with stable. @@ -139,6 +139,15 @@ the target; returning does not merge those readings into old Core. ## What the copy tests cover +The published `v0.141.2-beta.1` Core and helper preserve partial history in +a full backup. Small synthetic meter/battery cases passed two starts, +portable restore and return: a working meter keeps recording while the +battery is offline, and missing flows and totals stay unknown. A balance +warning also leaves measured flows in the record. The browser shows the +gap and warning, then new values after recovery. These checks do not qualify +the older installation routes below against this newer beta; their actual +tested target remains `v0.141.0-beta.1`. + The published `v0.141.0-beta.1` packages have passed representative SQLite/settings copies from 0.130.4, 1.15.0, 2.3.2 and 3.8.0-beta.1. The matching Core and converter pair also passed DuckDB copies from diff --git a/docs/native-beta.md b/docs/native-beta.md index 2bc9a57a5..55345ef17 100644 --- a/docs/native-beta.md +++ b/docs/native-beta.md @@ -1,6 +1,6 @@ # Install and update FTW -**This draft targets `v0.141.0`; stable has not been published yet.** FTW +**This draft targets `v0.141.2`; stable has not been published yet.** FTW 2.x and 3.x get no more updates. [Svenska](setup-guide/update-sv.md). ## Quick answer @@ -8,7 +8,7 @@ | You run | Do this | |---|---| | New FTW 0.x, native | Open **More → Version → Update FTW** in the web UI, or run `ftw update` on the box. Nothing else. | -| New FTW 0.x in Docker | Set `FTW_VERSION=v0.141.0` in `.env` and run `docker compose up -d --build`. [Details](#update-new-docker) | +| New FTW 0.x in Docker | Set `FTW_VERSION=v0.141.2` in `.env` and run `docker compose up -d --build`. [Details](#update-new-docker) | | No FTW yet, on 64-bit Linux or a new Pi card | [Install](#install) with the stable tag. | | Old FTW 2.x, 3.x or the old Pi image | Move data and config through a full backup to a second SD card or host. [Steps](#coming-from-an-older-ftw) | | Home Assistant app | Keep the app backup and move to another Linux host; keep Home Assistant on MQTT. [Steps](#coming-from-an-older-ftw) | @@ -203,7 +203,7 @@ return to [the second-card steps](#raspberry-pi-use-a-second-sd-card) first. This section does not update or migrate an old installation. Use the newest stable tag from [Releases](https://github.com/srcfl/ftw/releases), -`v0.141.0` or later with no `-beta` in it. Choose a beta only if you test new +`v0.141.2` or later with no `-beta` in it. Choose a beta only if you test new builds. Check that the release includes the Linux package for your architecture and its SHA-256 file. Do not use `releases/latest`: it still points to the retired 2.x line. Copy the tag from the release title; do not diff --git a/docs/setup-guide/update-sv.md b/docs/setup-guide/update-sv.md index d8a1dcd68..5d4995683 100644 --- a/docs/setup-guide/update-sv.md +++ b/docs/setup-guide/update-sv.md @@ -1,6 +1,6 @@ # Byt till nya FTW och håll det uppdaterat -**Detta utkast gäller `v0.141.0`; stable är ännu inte publicerad.** FTW +**Detta utkast gäller `v0.141.2`; stable är ännu inte publicerad.** FTW 2.x och 3.x får inga fler uppdateringar. [English](../native-beta.md). ## Kort svar @@ -8,7 +8,7 @@ | Du kör | Gör så här | |---|---| | Nya FTW 0.x, native | Öppna **More → Version → Update FTW** i webbsidan, eller kör `ftw update` på boxen. Inget mer. | -| Nya FTW 0.x i Docker | Sätt `FTW_VERSION=v0.141.0` i `.env` och kör `docker compose up -d --build`. [Detaljer](#docker-från-det-nya-releasepaketet) | +| Nya FTW 0.x i Docker | Sätt `FTW_VERSION=v0.141.2` i `.env` och kör `docker compose up -d --build`. [Detaljer](#docker-från-det-nya-releasepaketet) | | Inget FTW än, på 64-bitars Linux eller ett nytt Pi-kort | [Installera](#installera-på-det-nya-kortet-eller-en-tom-linux-maskin) med den stabila taggen. | | Gamla FTW 2.x, 3.x eller den gamla Pi-imagen | Flytta data och config med en full backup till ett andra SD-kort eller en annan maskin. [Steg](#byt-på-raspberry-pi-med-ett-nytt-sd-kort) | | Home Assistant-appen | Ingen ny app än. Kör nya FTW på en annan Linux-maskin och koppla Home Assistant via MQTT. [Steg](#välj-en-väg) | @@ -190,7 +190,7 @@ kortet, gå tillbaka till kortbytet ovan. `--fresh-host` betyder att ingen FTW-installation eller dess data finns här, även om den är stoppad. 1. Öppna [Releases](https://github.com/srcfl/ftw/releases) på din vanliga dator. - Välj den senaste **stabila** taggen, `v0.141.0` eller senare utan `-beta`. + Välj den senaste **stabila** taggen, `v0.141.2` eller senare utan `-beta`. Välj en beta bara om du provar nya byggen. Releasen ska ha Linux-paket och SHA-256-fil för din maskin. Använd inte `releases/latest`; den pekar på gamla 2.x. From 152fb19a4106013285997e0f9bc9430d2caae2cc Mon Sep 17 00:00:00 2001 From: Fredrik Ahlgren Date: Mon, 12 Oct 2026 22:42:01 +0200 Subject: [PATCH 17/29] docs: target 0.141.3 and state Supervisor return limits --- docs/migration.md | 20 ++++++++++++++++++-- docs/native-beta.md | 6 +++--- docs/setup-guide/update-sv.md | 6 +++--- 3 files changed, 24 insertions(+), 8 deletions(-) diff --git a/docs/migration.md b/docs/migration.md index 2e316568e..821b00515 100644 --- a/docs/migration.md +++ b/docs/migration.md @@ -5,8 +5,8 @@ moving to the new line. Use a full backup and a separate target copy. Keep the source install and an off-host backup until the target and the return path have passed their checks. [Svenska](#svenska). -This draft targets `v0.141.2`, which has not shipped as stable. The published -beta is `v0.141.2-beta.1`. Data-copy tests do not establish that every old +This draft targets `v0.141.3`, which has not shipped as stable. The published +beta is `v0.141.3-beta.1`. Data-copy tests do not establish that every old installation can switch safely. The remaining paths below need work before the guide can ship with stable. @@ -148,6 +148,22 @@ gap and warning, then new values after recovery. These checks do not qualify the older installation routes below against this newer beta; their actual tested target remains `v0.141.0-beta.1`. +The published `v0.141.3-beta.1` helper also exports the older split SQLite +history, whose schema has none of the six newer partial/quality tables. +It refuses an incomplete set. Actual plain and protected Supervisor full +backups from a synthetic published HA 3.8 source passed export, portable +restore, two starts per route and revert with the published 0.141.3 packages. +Old charts, stored hours, config, credentials, goals, identity and managed +driver choices remained. The trial used the official unsupported Supervisor +devcontainer, not a supported HAOS host or real equipment. + +The full Supervisor return job restored files, but the old app failed to +start because its private files had the wrong owner. A bounded owner repair +on that test instance restored the matching old version and its data. +Automatic Supervisor return and HA entity continuity remain unqualified. +Keep the original app and its data; do not treat a completed backup job as +proof that the app can return without help. + The published `v0.141.0-beta.1` packages have passed representative SQLite/settings copies from 0.130.4, 1.15.0, 2.3.2 and 3.8.0-beta.1. The matching Core and converter pair also passed DuckDB copies from diff --git a/docs/native-beta.md b/docs/native-beta.md index 55345ef17..f0d77cac0 100644 --- a/docs/native-beta.md +++ b/docs/native-beta.md @@ -1,6 +1,6 @@ # Install and update FTW -**This draft targets `v0.141.2`; stable has not been published yet.** FTW +**This draft targets `v0.141.3`; stable has not been published yet.** FTW 2.x and 3.x get no more updates. [Svenska](setup-guide/update-sv.md). ## Quick answer @@ -8,7 +8,7 @@ | You run | Do this | |---|---| | New FTW 0.x, native | Open **More → Version → Update FTW** in the web UI, or run `ftw update` on the box. Nothing else. | -| New FTW 0.x in Docker | Set `FTW_VERSION=v0.141.2` in `.env` and run `docker compose up -d --build`. [Details](#update-new-docker) | +| New FTW 0.x in Docker | Set `FTW_VERSION=v0.141.3` in `.env` and run `docker compose up -d --build`. [Details](#update-new-docker) | | No FTW yet, on 64-bit Linux or a new Pi card | [Install](#install) with the stable tag. | | Old FTW 2.x, 3.x or the old Pi image | Move data and config through a full backup to a second SD card or host. [Steps](#coming-from-an-older-ftw) | | Home Assistant app | Keep the app backup and move to another Linux host; keep Home Assistant on MQTT. [Steps](#coming-from-an-older-ftw) | @@ -203,7 +203,7 @@ return to [the second-card steps](#raspberry-pi-use-a-second-sd-card) first. This section does not update or migrate an old installation. Use the newest stable tag from [Releases](https://github.com/srcfl/ftw/releases), -`v0.141.2` or later with no `-beta` in it. Choose a beta only if you test new +`v0.141.3` or later with no `-beta` in it. Choose a beta only if you test new builds. Check that the release includes the Linux package for your architecture and its SHA-256 file. Do not use `releases/latest`: it still points to the retired 2.x line. Copy the tag from the release title; do not diff --git a/docs/setup-guide/update-sv.md b/docs/setup-guide/update-sv.md index 5d4995683..1f0e747e0 100644 --- a/docs/setup-guide/update-sv.md +++ b/docs/setup-guide/update-sv.md @@ -1,6 +1,6 @@ # Byt till nya FTW och håll det uppdaterat -**Detta utkast gäller `v0.141.2`; stable är ännu inte publicerad.** FTW +**Detta utkast gäller `v0.141.3`; stable är ännu inte publicerad.** FTW 2.x och 3.x får inga fler uppdateringar. [English](../native-beta.md). ## Kort svar @@ -8,7 +8,7 @@ | Du kör | Gör så här | |---|---| | Nya FTW 0.x, native | Öppna **More → Version → Update FTW** i webbsidan, eller kör `ftw update` på boxen. Inget mer. | -| Nya FTW 0.x i Docker | Sätt `FTW_VERSION=v0.141.2` i `.env` och kör `docker compose up -d --build`. [Detaljer](#docker-från-det-nya-releasepaketet) | +| Nya FTW 0.x i Docker | Sätt `FTW_VERSION=v0.141.3` i `.env` och kör `docker compose up -d --build`. [Detaljer](#docker-från-det-nya-releasepaketet) | | Inget FTW än, på 64-bitars Linux eller ett nytt Pi-kort | [Installera](#installera-på-det-nya-kortet-eller-en-tom-linux-maskin) med den stabila taggen. | | Gamla FTW 2.x, 3.x eller den gamla Pi-imagen | Flytta data och config med en full backup till ett andra SD-kort eller en annan maskin. [Steg](#byt-på-raspberry-pi-med-ett-nytt-sd-kort) | | Home Assistant-appen | Ingen ny app än. Kör nya FTW på en annan Linux-maskin och koppla Home Assistant via MQTT. [Steg](#välj-en-väg) | @@ -190,7 +190,7 @@ kortet, gå tillbaka till kortbytet ovan. `--fresh-host` betyder att ingen FTW-installation eller dess data finns här, även om den är stoppad. 1. Öppna [Releases](https://github.com/srcfl/ftw/releases) på din vanliga dator. - Välj den senaste **stabila** taggen, `v0.141.2` eller senare utan `-beta`. + Välj den senaste **stabila** taggen, `v0.141.3` eller senare utan `-beta`. Välj en beta bara om du provar nya byggen. Releasen ska ha Linux-paket och SHA-256-fil för din maskin. Använd inte `releases/latest`; den pekar på gamla 2.x. From 1f5d832823045daa1e22a942175ad7ff2e788cf6 Mon Sep 17 00:00:00 2001 From: Fredrik Ahlgren Date: Tue, 13 Oct 2026 00:13:47 +0200 Subject: [PATCH 18/29] docs: link verified Supervisor owner recovery route --- docs/migration.md | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/docs/migration.md b/docs/migration.md index 821b00515..cc56d8950 100644 --- a/docs/migration.md +++ b/docs/migration.md @@ -158,8 +158,18 @@ driver choices remained. The trial used the official unsupported Supervisor devcontainer, not a supported HAOS host or real equipment. The full Supervisor return job restored files, but the old app failed to -start because its private files had the wrong owner. A bounded owner repair -on that test instance restored the matching old version and its data. +start because its private files had the wrong owner. The separate +[owner recovery command](https://github.com/srcfl/home-assistant-addons/blob/main/docs/restore-data-owner.md) +now provides a checked route for that failure. Run it in the stopped app's +matching image with only its verified data mounted. It preserves bytes, +private file modes and internal links, and stops on external or broken links, +hard links or extra mounts. Keep Start on boot and Watchdog off; record the +image and data path before Supervisor removes the stopped container. + +A complete protected return job on that separate test instance passed the +command, old Core start, retained chart rows and two archive hours, then a +final stop. Its source was the same published HA 3.8 image. This command +does not publish or update the retired app line. Automatic Supervisor return and HA entity continuity remain unqualified. Keep the original app and its data; do not treat a completed backup job as proof that the app can return without help. From a026385709c7638f5da702cbce4e447f6bad871a Mon Sep 17 00:00:00 2001 From: Fredrik Ahlgren Date: Tue, 13 Oct 2026 00:59:16 +0200 Subject: [PATCH 19/29] docs: track published 0.141.4 diagnostic beta --- docs/migration.md | 11 +++++++++-- docs/native-beta.md | 6 +++--- docs/setup-guide/update-sv.md | 6 +++--- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/docs/migration.md b/docs/migration.md index cc56d8950..e16ce6eda 100644 --- a/docs/migration.md +++ b/docs/migration.md @@ -5,8 +5,8 @@ moving to the new line. Use a full backup and a separate target copy. Keep the source install and an off-host backup until the target and the return path have passed their checks. [Svenska](#svenska). -This draft targets `v0.141.3`, which has not shipped as stable. The published -beta is `v0.141.3-beta.1`. Data-copy tests do not establish that every old +This draft targets `v0.141.4`, which has not shipped as stable. The published +beta is `v0.141.4-beta.1`. Data-copy tests do not establish that every old installation can switch safely. The remaining paths below need work before the guide can ship with stable. @@ -139,6 +139,13 @@ the target; returning does not merge those readings into old Core. ## What the copy tests cover +The published `v0.141.4-beta.1` Core passed healthy, offline and invalid +balance cases over two starts each on separate synthetic Linux copies. +Known meter values remain in history while missing flows and totals stay +unknown. It also records the time spent in forecast connection, query, scan +and decode phases when a read fails. The timeout cause remains unproven. +These checks do not qualify the older migration routes against this beta. + The published `v0.141.2-beta.1` Core and helper preserve partial history in a full backup. Small synthetic meter/battery cases passed two starts, portable restore and return: a working meter keeps recording while the diff --git a/docs/native-beta.md b/docs/native-beta.md index f0d77cac0..1794fa9d2 100644 --- a/docs/native-beta.md +++ b/docs/native-beta.md @@ -1,6 +1,6 @@ # Install and update FTW -**This draft targets `v0.141.3`; stable has not been published yet.** FTW +**This draft targets `v0.141.4`; stable has not been published yet.** FTW 2.x and 3.x get no more updates. [Svenska](setup-guide/update-sv.md). ## Quick answer @@ -8,7 +8,7 @@ | You run | Do this | |---|---| | New FTW 0.x, native | Open **More → Version → Update FTW** in the web UI, or run `ftw update` on the box. Nothing else. | -| New FTW 0.x in Docker | Set `FTW_VERSION=v0.141.3` in `.env` and run `docker compose up -d --build`. [Details](#update-new-docker) | +| New FTW 0.x in Docker | Set `FTW_VERSION=v0.141.4` in `.env` and run `docker compose up -d --build`. [Details](#update-new-docker) | | No FTW yet, on 64-bit Linux or a new Pi card | [Install](#install) with the stable tag. | | Old FTW 2.x, 3.x or the old Pi image | Move data and config through a full backup to a second SD card or host. [Steps](#coming-from-an-older-ftw) | | Home Assistant app | Keep the app backup and move to another Linux host; keep Home Assistant on MQTT. [Steps](#coming-from-an-older-ftw) | @@ -203,7 +203,7 @@ return to [the second-card steps](#raspberry-pi-use-a-second-sd-card) first. This section does not update or migrate an old installation. Use the newest stable tag from [Releases](https://github.com/srcfl/ftw/releases), -`v0.141.3` or later with no `-beta` in it. Choose a beta only if you test new +`v0.141.4` or later with no `-beta` in it. Choose a beta only if you test new builds. Check that the release includes the Linux package for your architecture and its SHA-256 file. Do not use `releases/latest`: it still points to the retired 2.x line. Copy the tag from the release title; do not diff --git a/docs/setup-guide/update-sv.md b/docs/setup-guide/update-sv.md index 1f0e747e0..87a87419a 100644 --- a/docs/setup-guide/update-sv.md +++ b/docs/setup-guide/update-sv.md @@ -1,6 +1,6 @@ # Byt till nya FTW och håll det uppdaterat -**Detta utkast gäller `v0.141.3`; stable är ännu inte publicerad.** FTW +**Detta utkast gäller `v0.141.4`; stable är ännu inte publicerad.** FTW 2.x och 3.x får inga fler uppdateringar. [English](../native-beta.md). ## Kort svar @@ -8,7 +8,7 @@ | Du kör | Gör så här | |---|---| | Nya FTW 0.x, native | Öppna **More → Version → Update FTW** i webbsidan, eller kör `ftw update` på boxen. Inget mer. | -| Nya FTW 0.x i Docker | Sätt `FTW_VERSION=v0.141.3` i `.env` och kör `docker compose up -d --build`. [Detaljer](#docker-från-det-nya-releasepaketet) | +| Nya FTW 0.x i Docker | Sätt `FTW_VERSION=v0.141.4` i `.env` och kör `docker compose up -d --build`. [Detaljer](#docker-från-det-nya-releasepaketet) | | Inget FTW än, på 64-bitars Linux eller ett nytt Pi-kort | [Installera](#installera-på-det-nya-kortet-eller-en-tom-linux-maskin) med den stabila taggen. | | Gamla FTW 2.x, 3.x eller den gamla Pi-imagen | Flytta data och config med en full backup till ett andra SD-kort eller en annan maskin. [Steg](#byt-på-raspberry-pi-med-ett-nytt-sd-kort) | | Home Assistant-appen | Ingen ny app än. Kör nya FTW på en annan Linux-maskin och koppla Home Assistant via MQTT. [Steg](#välj-en-väg) | @@ -190,7 +190,7 @@ kortet, gå tillbaka till kortbytet ovan. `--fresh-host` betyder att ingen FTW-installation eller dess data finns här, även om den är stoppad. 1. Öppna [Releases](https://github.com/srcfl/ftw/releases) på din vanliga dator. - Välj den senaste **stabila** taggen, `v0.141.3` eller senare utan `-beta`. + Välj den senaste **stabila** taggen, `v0.141.4` eller senare utan `-beta`. Välj en beta bara om du provar nya byggen. Releasen ska ha Linux-paket och SHA-256-fil för din maskin. Använd inte `releases/latest`; den pekar på gamla 2.x. From e5f8160f312b80a0725da52a048312d2f7e732b7 Mon Sep 17 00:00:00 2001 From: Fredrik Ahlgren Date: Tue, 13 Oct 2026 02:33:26 +0200 Subject: [PATCH 20/29] docs: record supported HAOS backup and manual return proof --- docs/migration.md | 23 +++++++++++++++++++++-- 1 file changed, 21 insertions(+), 2 deletions(-) diff --git a/docs/migration.md b/docs/migration.md index e16ce6eda..c57592186 100644 --- a/docs/migration.md +++ b/docs/migration.md @@ -144,7 +144,26 @@ balance cases over two starts each on separate synthetic Linux copies. Known meter values remain in history while missing flows and totals stay unknown. It also records the time spent in forecast connection, query, scan and decode phases when a read fails. The timeout cause remains unproven. -These checks do not qualify the older migration routes against this beta. +These checks alone do not qualify the older migration routes against this beta. + +A separate protected full backup and full return passed on a separate HAOS 18.3 +ARM64 VM, with Supervisor 2026.09.3 reporting supported and healthy. Its +published HA 3.8 FTW source used synthetic data. Export and full FTW backup +with the exact published `v0.141.4-beta.1` Core/helper passed two target +starts, new writes and revert on a separate Linux ARM64 data copy. Old +chart rows, two archive hours, settings, credentials, goals and identity +remained. The checks verify root relocation and the older planner and SoC +field mappings rather than requiring those fields to keep their old form. +Native installation and physical cutover need separate proof. + +The protected HAOS return restored a synthetic template sensor's entity ID, +unique ID and state, and both HA and FTW test files. Old FTW still needed +the owner recovery command below before it could start. That command kept +all 61 checked files' bytes and modes and both internal links. The matching +old Core then returned with its chart rows and two archive hours. The VM +and FTW test targets are stopped; their backups and data remain. +This does not qualify FTW MQTT discovery or entity continuity, every +community app, real equipment or power-loss recovery. The published `v0.141.2-beta.1` Core and helper preserve partial history in a full backup. Small synthetic meter/battery cases passed two starts, @@ -177,7 +196,7 @@ A complete protected return job on that separate test instance passed the command, old Core start, retained chart rows and two archive hours, then a final stop. Its source was the same published HA 3.8 image. This command does not publish or update the retired app line. -Automatic Supervisor return and HA entity continuity remain unqualified. +Automatic Supervisor return and FTW HA entity continuity remain unqualified. Keep the original app and its data; do not treat a completed backup job as proof that the app can return without help. From 8b4193caa6f9166a583912fcc9cd2768302ac05b Mon Sep 17 00:00:00 2001 From: Fredrik Ahlgren Date: Tue, 13 Oct 2026 03:18:03 +0200 Subject: [PATCH 21/29] docs: record HAOS MQTT migration and reboot proof --- docs/migration.md | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/docs/migration.md b/docs/migration.md index c57592186..6d75f5fbb 100644 --- a/docs/migration.md +++ b/docs/migration.md @@ -162,8 +162,24 @@ the owner recovery command below before it could start. That command kept all 61 checked files' bytes and modes and both internal links. The matching old Core then returned with its chart rows and two archive hours. The VM and FTW test targets are stopped; their backups and data remain. -This does not qualify FTW MQTT discovery or entity continuity, every -community app, real equipment or power-loss recovery. +This template check does not test FTW MQTT entities, every community app, +real equipment or power-loss recovery. + +A separate MQTT move on that own HAOS VM kept the same broker running while +only the selected FTW Core ran. The published HA 3.8 source and exact +`v0.141.4-beta.1` target kept all 44 recorded MQTT entity IDs, unique IDs +and device links through two target starts and matching old return. The same +grid sensor reported 700 W, then the target's new synthetic 800 W, then the +old source's 700 W. Old chart rows and both stored hours remained; new ticks +had no failed or rejected writes. Both full backups remain off the VM. + +The checks compare credentials and identity without exporting their values. +They verify the old Balanced forecast margin's move to the current Balanced +style, alongside the root, planner and SoC mappings. A guest OS reboot with +the old app's Start on boot, Watchdog and auto-update off started neither +old Core nor the removed target. This covers one synthetic MQTT setup and a +Docker data target on HAOS. It does not qualify every entity or command, +community layout, native installer, real device or power-loss case. The published `v0.141.2-beta.1` Core and helper preserve partial history in a full backup. Small synthetic meter/battery cases passed two starts, @@ -196,7 +212,8 @@ A complete protected return job on that separate test instance passed the command, old Core start, retained chart rows and two archive hours, then a final stop. Its source was the same published HA 3.8 image. This command does not publish or update the retired app line. -Automatic Supervisor return and FTW HA entity continuity remain unqualified. +Automatic Supervisor return remains unqualified. This older devcontainer +check did not test FTW MQTT entities. Keep the original app and its data; do not treat a completed backup job as proof that the app can return without help. From 1179840302fb928fac396baffe24eed0547d40a9 Mon Sep 17 00:00:00 2001 From: Fredrik Ahlgren Date: Tue, 13 Oct 2026 04:21:28 +0200 Subject: [PATCH 22/29] docs: record verified external copy migration scope --- docs/migration.md | 28 +++++++++++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/docs/migration.md b/docs/migration.md index 6d75f5fbb..49cf6d4fc 100644 --- a/docs/migration.md +++ b/docs/migration.md @@ -45,6 +45,15 @@ SQLite read-only without upgrading it. Pass `-core-version` with the verified external files and their path mapping explicit; the helper requires its config seed inside the data tree. +For an external layout, keep the stopped source and its config seed intact. +Use a second writable copy to collect the database, required archives, keys +and driver files inside one data tree. Map each known file path in that +copy's active SQLite config and YAML seed; keep all other settings and +credentials. If the source has no stored config, keep YAML as its source +until Core imports it. Do not add a `config_database` reference to a database +that has no stored config. Verify the resulting full backup and restore it +on a separate target. An unresolved external path must stop the move. + Do not start an old Core merely to inspect the migration copy. Preserve the original bytes and use the full-backup inspector or converter. When a format or source is unknown, keep the copy and resolve that case before starting it. @@ -294,6 +303,18 @@ were checked. The AMD64 source ran through emulation on Apple Silicon. This covers the tested Linux Docker copy across CPU architectures; it does not qualify 32-bit sources or native macOS/Windows paths. +One external Linux layout from published 2.3.2 also passed 36 checks with +the published `v0.141.4-beta.1` ARM64 Core and helper. Its database used a +subdirectory, while the config seed, driver files and Parquet archive used +other paths. The helper refused an external config seed and stopped a move +with unresolved paths before replacing target data. A separate copy with +explicit path mappings retained 25 old chart rows, two Parquet values, +settings, credentials, goals, keys and driver files over two target starts +and return to old Core. The check compared every old config field, with +explicit mappings for paths, old planner choice and units. Revert kept new +target data. This covers that stopped-copy layout, not every external mount, +an installer change, physical equipment or power loss. + The published `v0.141.0-beta.1` Linux ARM64 backup helper also passed process crash tests during preservation, activation, return and a later extraction. The tests check that incomplete copies cannot replace active data, all old @@ -301,7 +322,7 @@ and new files remain, and a complete backup can restore on a separate target. These tests use synthetic files and do not prove recovery from physical power loss or an interrupted installation change. -Large archives on Pi/SD, external layouts, cross-platform and 32-bit sources, +Large archives on Pi/SD, other external layouts, cross-platform and 32-bit sources, complete Supervisor control, interrupted installation changes and physical cutover remain release requirements. Unknown formats keep their source data and require a checked import path. @@ -319,6 +340,11 @@ en annan disk eller dator. Använd en separat värd eller ett nytt Pi-kort som m drivrutiner och arkiv. Home Assistant-backup behöver sin nyckel. Använd den länkade exportören för FTW-komponenten och följ dess README för full backup med den gamla roten `/data`. + Ligger filer på externa sökvägar: behåll den stoppade källan och samla + filerna i en extra skrivbar kopia. Mappa bara kända sökvägar i kopians + aktiva SQLite-config och YAML-seed. Behåll övriga inställningar. Lägg + inte till `config_database` om databasen saknar lagrad config. Olösta + externa sökvägar ska stoppa flytten före aktivering. 3. Installera exakt målversion på den separata Linuxmaskinen. Stoppa och stäng av nya tjänstens autostart före import. Använd blocket ovan för en verifierad `.ftwbak`; det lämnar Core stoppad. From 2876c76e6920b3aff18a85216460821d5e28e9bf Mon Sep 17 00:00:00 2001 From: Fredrik Ahlgren Date: Tue, 13 Oct 2026 05:40:51 +0200 Subject: [PATCH 23/29] docs: record Docker cutover and reboot proof limits --- docs/migration.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/docs/migration.md b/docs/migration.md index 49cf6d4fc..e1c6dda7b 100644 --- a/docs/migration.md +++ b/docs/migration.md @@ -295,6 +295,23 @@ verified new writes. The broker and subscriber kept their process start times. The test checked saved Compose and container restart policies; it did not reboot Docker or the host, run the old updater, or control equipment. +A later ARM64 Docker test passed 62 checks from the published 2.3.2 Core +and updater to the exact published `v0.141.4-beta.1` Core/helper. The old +updater answered on its Unix socket. Separate data trees and saved Compose +and container policies kept old Core and updater off while the beta target +continued writing after a verified Docker daemon restart and guest OS +reboot. Shared MQTT recovered with fresh synthetic readings. Both target +starts and old return retained the exact 25 source chart rows, two Parquet +values, settings, credentials, goals and identity. Full backups are verified +off the VM, including the final stopped target data; revert keeps new data. + +The test used an own QEMU/HVF HAOS guest as a Docker host. Supervisor marked +standalone images as `unsupported/software`; its normal check returned to +supported and healthy after cleanup. This does not qualify a standalone FTW +Docker installation as a supported HAOS app, every host startup unit, +old updater jobs, the optional old optimizer, physical equipment or power +loss. The test VM is shut down and all proof containers are removed. + A separate test moved the published 2.3.2 AMD64 Docker image to the published `v0.141.0-beta.1` ARM64 Core and helper. All 29 checks passed, including two target starts, new writes and return to old Core with data, settings, From b5198d2d90c1c2b23900986f11108ebecaef624f Mon Sep 17 00:00:00 2001 From: Fredrik Ahlgren Date: Tue, 13 Oct 2026 08:45:29 +0200 Subject: [PATCH 24/29] docs: target verified 0.141.5 beta and retain earlier proof scopes --- docs/migration.md | 13 ++++++++++--- docs/native-beta.md | 6 +++--- 2 files changed, 13 insertions(+), 6 deletions(-) diff --git a/docs/migration.md b/docs/migration.md index e1c6dda7b..5fc42b78d 100644 --- a/docs/migration.md +++ b/docs/migration.md @@ -5,8 +5,8 @@ moving to the new line. Use a full backup and a separate target copy. Keep the source install and an off-host backup until the target and the return path have passed their checks. [Svenska](#svenska). -This draft targets `v0.141.4`, which has not shipped as stable. The published -beta is `v0.141.4-beta.1`. Data-copy tests do not establish that every old +This draft targets `v0.141.5`, which has not shipped as stable. The published +beta is `v0.141.5-beta.1`. Data-copy tests do not establish that every old installation can switch safely. The remaining paths below need work before the guide can ship with stable. @@ -148,13 +148,20 @@ the target; returning does not merge those readings into old Core. ## What the copy tests cover -The published `v0.141.4-beta.1` Core passed healthy, offline and invalid +The published `v0.141.5-beta.1` Core passed healthy, offline and invalid balance cases over two starts each on separate synthetic Linux copies. Known meter values remain in history while missing flows and totals stay unknown. It also records the time spent in forecast connection, query, scan and decode phases when a read fails. The timeout cause remains unproven. These checks alone do not qualify the older migration routes against this beta. +The published `v0.141.5-beta.1` helper also passed full backup, verification, +portable restore and revert on separate copies of published HA 3.8 split +SQLite and current partial/quality history. Historical rows, settings and +identity remained after explicit data-root and restore-generation mappings. +Revert kept new target writes in its safety directory. These are data-copy +checks; the HAOS, MQTT and installation tests below retain their own versions. + A separate protected full backup and full return passed on a separate HAOS 18.3 ARM64 VM, with Supervisor 2026.09.3 reporting supported and healthy. Its published HA 3.8 FTW source used synthetic data. Export and full FTW backup diff --git a/docs/native-beta.md b/docs/native-beta.md index 1794fa9d2..4e7c4606f 100644 --- a/docs/native-beta.md +++ b/docs/native-beta.md @@ -1,6 +1,6 @@ # Install and update FTW -**This draft targets `v0.141.4`; stable has not been published yet.** FTW +**This draft targets `v0.141.5`; stable has not been published yet.** FTW 2.x and 3.x get no more updates. [Svenska](setup-guide/update-sv.md). ## Quick answer @@ -8,7 +8,7 @@ | You run | Do this | |---|---| | New FTW 0.x, native | Open **More → Version → Update FTW** in the web UI, or run `ftw update` on the box. Nothing else. | -| New FTW 0.x in Docker | Set `FTW_VERSION=v0.141.4` in `.env` and run `docker compose up -d --build`. [Details](#update-new-docker) | +| New FTW 0.x in Docker | Set `FTW_VERSION=v0.141.5` in `.env` and run `docker compose up -d --build`. [Details](#update-new-docker) | | No FTW yet, on 64-bit Linux or a new Pi card | [Install](#install) with the stable tag. | | Old FTW 2.x, 3.x or the old Pi image | Move data and config through a full backup to a second SD card or host. [Steps](#coming-from-an-older-ftw) | | Home Assistant app | Keep the app backup and move to another Linux host; keep Home Assistant on MQTT. [Steps](#coming-from-an-older-ftw) | @@ -203,7 +203,7 @@ return to [the second-card steps](#raspberry-pi-use-a-second-sd-card) first. This section does not update or migrate an old installation. Use the newest stable tag from [Releases](https://github.com/srcfl/ftw/releases), -`v0.141.4` or later with no `-beta` in it. Choose a beta only if you test new +`v0.141.5` or later with no `-beta` in it. Choose a beta only if you test new builds. Check that the release includes the Linux package for your architecture and its SHA-256 file. Do not use `releases/latest`: it still points to the retired 2.x line. Copy the tag from the release title; do not From 46e91ac511d1d4896d355ee9866a1a54797dbc5e Mon Sep 17 00:00:00 2001 From: Fredrik Ahlgren Date: Tue, 13 Oct 2026 13:42:36 +0200 Subject: [PATCH 25/29] docs: qualify 0.142 copies and Cloud restore identity Signed-off-by: Fredrik Ahlgren --- docs/backup-and-restore.md | 6 ++++++ docs/migration.md | 31 +++++++++++++++++++++++++++---- docs/native-beta.md | 6 +++--- docs/setup-guide/update-sv.md | 6 +++--- 4 files changed, 39 insertions(+), 10 deletions(-) diff --git a/docs/backup-and-restore.md b/docs/backup-and-restore.md index f863f06fe..38d338f97 100644 --- a/docs/backup-and-restore.md +++ b/docs/backup-and-restore.md @@ -56,6 +56,12 @@ consistent copy of `cache.db`: savings history is costed from its past prices, and a price provider sends only today and tomorrow. Managed-driver links that point inside the persistent directory become relative links in the archive, so restore can move the data to another directory or machine. + +The archive also leaves out `cloud.key` and `cloud.key.tmp`. Pairing and +WebPush keys remain. After a full restore, FTW Cloud stays off until the +owner grants it again under a new home ID. Local control and stored goals +remain available. + Backup never follows these links to copy a host file; verification rejects link chains that escape the data directory or form a cycle. diff --git a/docs/migration.md b/docs/migration.md index 5fc42b78d..94328f29a 100644 --- a/docs/migration.md +++ b/docs/migration.md @@ -5,8 +5,8 @@ moving to the new line. Use a full backup and a separate target copy. Keep the source install and an off-host backup until the target and the return path have passed their checks. [Svenska](#svenska). -This draft targets `v0.141.5`, which has not shipped as stable. The published -beta is `v0.141.5-beta.1`. Data-copy tests do not establish that every old +This draft targets `v0.142.0`, which has not shipped as stable. The published +beta is `v0.142.0-beta.1`. Data-copy tests do not establish that every old installation can switch safely. The remaining paths below need work before the guide can ship with stable. @@ -31,6 +31,11 @@ masks secrets and is not a full export. Include environment files and service or Compose definitions needed to explain the source's paths and credentials. Preserve shared MQTT and other services used by the equipment. +FTW Cloud needs a new owner grant after a full-backup restore. The backup +keeps pairing and WebPush keys but leaves out `cloud.key` and its temporary +file. A restored Cloud grant reads as off until the owner turns Cloud on +again under a new home ID. Local operation and stored goals remain. + ## Export a complete source copy Use the source version's full-backup UI or helper when it has one. Verify the @@ -148,20 +153,35 @@ the target; returning does not merge those readings into old Core. ## What the copy tests cover -The published `v0.141.5-beta.1` Core passed healthy, offline and invalid +The published `v0.142.0-beta.1` Core passed healthy, offline and invalid balance cases over two starts each on separate synthetic Linux copies. Known meter values remain in history while missing flows and totals stay unknown. It also records the time spent in forecast connection, query, scan and decode phases when a read fails. The timeout cause remains unproven. These checks alone do not qualify the older migration routes against this beta. -The published `v0.141.5-beta.1` helper also passed full backup, verification, +The published `v0.142.0-beta.1` helper also passed full backup, verification, portable restore and revert on separate copies of published HA 3.8 split SQLite and current partial/quality history. Historical rows, settings and identity remained after explicit data-root and restore-generation mappings. Revert kept new target writes in its safety directory. These are data-copy checks; the HAOS, MQTT and installation tests below retain their own versions. +The same published Core and helper passed a separate Cloud restore check +without network access. Core created a local grant on the source copy. A +verified full backup omitted the Cloud key, and two restored starts kept +Cloud off. A new explicit grant used a different home ID. Source keys and +modes, pairing identity and WebPush identity remained. This tests local +restore behavior, not a connection to the Cloud service. + +The published `v0.142.0-beta.1` Core, helper and converter also passed 30 +checks from published `v3.2.0-beta.1` with retained Parquet and 500,000 extra +synthetic DuckDB rows. A process kill interrupted the copy before publication; +resume checked the source, and a changed source stopped it. Two target +starts and two portable-restore starts kept history, goals, settings and +identity. Return and revert retained both copies. This does not qualify +an installation change, Pi/SD performance or physical power loss. + A separate protected full backup and full return passed on a separate HAOS 18.3 ARM64 VM, with Supervisor 2026.09.3 reporting supported and healthy. Its published HA 3.8 FTW source used synthetic data. Export and full FTW backup @@ -364,6 +384,9 @@ en annan disk eller dator. Använd en separat värd eller ett nytt Pi-kort som m drivrutiner och arkiv. Home Assistant-backup behöver sin nyckel. Använd den länkade exportören för FTW-komponenten och följ dess README för full backup med den gamla roten `/data`. + FTW Cloud kräver ett nytt godkännande efter full återställning. Backupen + utelämnar Cloud-nyckeln; återställd Cloud är avstängd tills ägaren slår på + den igen med ett nytt home-ID. Pairing, WebPush och sparade mål består. Ligger filer på externa sökvägar: behåll den stoppade källan och samla filerna i en extra skrivbar kopia. Mappa bara kända sökvägar i kopians aktiva SQLite-config och YAML-seed. Behåll övriga inställningar. Lägg diff --git a/docs/native-beta.md b/docs/native-beta.md index 4e7c4606f..d7754658f 100644 --- a/docs/native-beta.md +++ b/docs/native-beta.md @@ -1,6 +1,6 @@ # Install and update FTW -**This draft targets `v0.141.5`; stable has not been published yet.** FTW +**This draft targets `v0.142.0`; stable has not been published yet.** FTW 2.x and 3.x get no more updates. [Svenska](setup-guide/update-sv.md). ## Quick answer @@ -8,7 +8,7 @@ | You run | Do this | |---|---| | New FTW 0.x, native | Open **More → Version → Update FTW** in the web UI, or run `ftw update` on the box. Nothing else. | -| New FTW 0.x in Docker | Set `FTW_VERSION=v0.141.5` in `.env` and run `docker compose up -d --build`. [Details](#update-new-docker) | +| New FTW 0.x in Docker | Set `FTW_VERSION=v0.142.0` in `.env` and run `docker compose up -d --build`. [Details](#update-new-docker) | | No FTW yet, on 64-bit Linux or a new Pi card | [Install](#install) with the stable tag. | | Old FTW 2.x, 3.x or the old Pi image | Move data and config through a full backup to a second SD card or host. [Steps](#coming-from-an-older-ftw) | | Home Assistant app | Keep the app backup and move to another Linux host; keep Home Assistant on MQTT. [Steps](#coming-from-an-older-ftw) | @@ -203,7 +203,7 @@ return to [the second-card steps](#raspberry-pi-use-a-second-sd-card) first. This section does not update or migrate an old installation. Use the newest stable tag from [Releases](https://github.com/srcfl/ftw/releases), -`v0.141.5` or later with no `-beta` in it. Choose a beta only if you test new +`v0.142.0` or later with no `-beta` in it. Choose a beta only if you test new builds. Check that the release includes the Linux package for your architecture and its SHA-256 file. Do not use `releases/latest`: it still points to the retired 2.x line. Copy the tag from the release title; do not diff --git a/docs/setup-guide/update-sv.md b/docs/setup-guide/update-sv.md index 87a87419a..459dd65ea 100644 --- a/docs/setup-guide/update-sv.md +++ b/docs/setup-guide/update-sv.md @@ -1,6 +1,6 @@ # Byt till nya FTW och håll det uppdaterat -**Detta utkast gäller `v0.141.4`; stable är ännu inte publicerad.** FTW +**Detta utkast gäller `v0.142.0`; stable är ännu inte publicerad.** FTW 2.x och 3.x får inga fler uppdateringar. [English](../native-beta.md). ## Kort svar @@ -8,7 +8,7 @@ | Du kör | Gör så här | |---|---| | Nya FTW 0.x, native | Öppna **More → Version → Update FTW** i webbsidan, eller kör `ftw update` på boxen. Inget mer. | -| Nya FTW 0.x i Docker | Sätt `FTW_VERSION=v0.141.4` i `.env` och kör `docker compose up -d --build`. [Detaljer](#docker-från-det-nya-releasepaketet) | +| Nya FTW 0.x i Docker | Sätt `FTW_VERSION=v0.142.0` i `.env` och kör `docker compose up -d --build`. [Detaljer](#docker-från-det-nya-releasepaketet) | | Inget FTW än, på 64-bitars Linux eller ett nytt Pi-kort | [Installera](#installera-på-det-nya-kortet-eller-en-tom-linux-maskin) med den stabila taggen. | | Gamla FTW 2.x, 3.x eller den gamla Pi-imagen | Flytta data och config med en full backup till ett andra SD-kort eller en annan maskin. [Steg](#byt-på-raspberry-pi-med-ett-nytt-sd-kort) | | Home Assistant-appen | Ingen ny app än. Kör nya FTW på en annan Linux-maskin och koppla Home Assistant via MQTT. [Steg](#välj-en-väg) | @@ -190,7 +190,7 @@ kortet, gå tillbaka till kortbytet ovan. `--fresh-host` betyder att ingen FTW-installation eller dess data finns här, även om den är stoppad. 1. Öppna [Releases](https://github.com/srcfl/ftw/releases) på din vanliga dator. - Välj den senaste **stabila** taggen, `v0.141.4` eller senare utan `-beta`. + Välj den senaste **stabila** taggen, `v0.142.0` eller senare utan `-beta`. Välj en beta bara om du provar nya byggen. Releasen ska ha Linux-paket och SHA-256-fil för din maskin. Använd inte `releases/latest`; den pekar på gamla 2.x. From d809d91775b8355b9972ca149d73e97abbd253f8 Mon Sep 17 00:00:00 2001 From: Fredrik Ahlgren Date: Tue, 13 Oct 2026 14:41:40 +0200 Subject: [PATCH 26/29] docs: record published native migration and autostart proof Signed-off-by: Fredrik Ahlgren --- docs/migration.md | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/docs/migration.md b/docs/migration.md index 94328f29a..d39bda498 100644 --- a/docs/migration.md +++ b/docs/migration.md @@ -294,6 +294,23 @@ same and new data roots, two starts and revert keep the selected driver active and preserve its previous-version path. These checks use synthetic records and valid file hashes; they do not prove a signed-channel install. +A later two-host test passed 39 checks from the published 3.8 Core and +helper to the published `v0.142.0-beta.1` native package. The unchanged +installer refused the source's existing `ftw` account and installed on a +fresh Debian 13 ARM64 target. Full backup transfer, two target starts and +matching old return retained 24 exact chart rows, two stored hours, settings, +credentials, goals and keys. The check compared every selected old config +field after explicit path, planner, SoC and forecast-margin mappings. +The source data stayed intact and new target writes had no errors. + +Real systemd rules kept only the selected Core running after both test +machines restarted, including after return. Both stopped full backups were +verified off the guest, and both machines ended stopped with data retained. +These OrbStack machine restarts test Linux service startup, not a physical +Pi power cycle. The source has no Parquet files; this test does not add +Parquet coverage, every custom layout, in-place installation or equipment +control. + A separate two-host Linux ARM64 test moved a synthetic 3.8 custom systemd source to a fresh `v0.141.0-beta.1` native target. The exact published old helper created the full backup. Both hosts restarted with only the selected From 2b604e7287fb5173be6948e91699be8c267aa6ff Mon Sep 17 00:00:00 2001 From: Fredrik Ahlgren Date: Tue, 13 Oct 2026 15:47:08 +0200 Subject: [PATCH 27/29] docs: qualify current beta migration and restore paths Signed-off-by: Fredrik Ahlgren --- docs/migration.md | 15 ++++++++------- docs/native-beta.md | 6 +++--- docs/setup-guide/update-sv.md | 6 +++--- 3 files changed, 14 insertions(+), 13 deletions(-) diff --git a/docs/migration.md b/docs/migration.md index d39bda498..b87dac08f 100644 --- a/docs/migration.md +++ b/docs/migration.md @@ -5,8 +5,8 @@ moving to the new line. Use a full backup and a separate target copy. Keep the source install and an off-host backup until the target and the return path have passed their checks. [Svenska](#svenska). -This draft targets `v0.142.0`, which has not shipped as stable. The published -beta is `v0.142.0-beta.1`. Data-copy tests do not establish that every old +This draft targets `v0.142.1`, which has not shipped as stable. The published +beta is `v0.142.1-beta.1`. Data-copy tests do not establish that every old installation can switch safely. The remaining paths below need work before the guide can ship with stable. @@ -153,14 +153,15 @@ the target; returning does not merge those readings into old Core. ## What the copy tests cover -The published `v0.142.0-beta.1` Core passed healthy, offline and invalid +The published `v0.142.1-beta.1` Core passed healthy, offline and invalid balance cases over two starts each on separate synthetic Linux copies. Known meter values remain in history while missing flows and totals stay -unknown. It also records the time spent in forecast connection, query, scan +unknown. Energy today shows measured subtotals with a gap mark; the full +range remains unknown when measurements are incomplete. It also records the time spent in forecast connection, query, scan and decode phases when a read fails. The timeout cause remains unproven. These checks alone do not qualify the older migration routes against this beta. -The published `v0.142.0-beta.1` helper also passed full backup, verification, +The published `v0.142.1-beta.1` helper also passed full backup, verification, portable restore and revert on separate copies of published HA 3.8 split SQLite and current partial/quality history. Historical rows, settings and identity remained after explicit data-root and restore-generation mappings. @@ -174,7 +175,7 @@ Cloud off. A new explicit grant used a different home ID. Source keys and modes, pairing identity and WebPush identity remained. This tests local restore behavior, not a connection to the Cloud service. -The published `v0.142.0-beta.1` Core, helper and converter also passed 30 +The published `v0.142.1-beta.1` Core, helper and converter also passed 30 checks from published `v3.2.0-beta.1` with retained Parquet and 500,000 extra synthetic DuckDB rows. A process kill interrupted the copy before publication; resume checked the source, and a changed source stopped it. Two target @@ -295,7 +296,7 @@ active and preserve its previous-version path. These checks use synthetic records and valid file hashes; they do not prove a signed-channel install. A later two-host test passed 39 checks from the published 3.8 Core and -helper to the published `v0.142.0-beta.1` native package. The unchanged +helper to the published `v0.142.1-beta.1` native package. The unchanged installer refused the source's existing `ftw` account and installed on a fresh Debian 13 ARM64 target. Full backup transfer, two target starts and matching old return retained 24 exact chart rows, two stored hours, settings, diff --git a/docs/native-beta.md b/docs/native-beta.md index d7754658f..95dac4228 100644 --- a/docs/native-beta.md +++ b/docs/native-beta.md @@ -1,6 +1,6 @@ # Install and update FTW -**This draft targets `v0.142.0`; stable has not been published yet.** FTW +**This draft targets `v0.142.1`; stable has not been published yet.** FTW 2.x and 3.x get no more updates. [Svenska](setup-guide/update-sv.md). ## Quick answer @@ -8,7 +8,7 @@ | You run | Do this | |---|---| | New FTW 0.x, native | Open **More → Version → Update FTW** in the web UI, or run `ftw update` on the box. Nothing else. | -| New FTW 0.x in Docker | Set `FTW_VERSION=v0.142.0` in `.env` and run `docker compose up -d --build`. [Details](#update-new-docker) | +| New FTW 0.x in Docker | Set `FTW_VERSION=v0.142.1` in `.env` and run `docker compose up -d --build`. [Details](#update-new-docker) | | No FTW yet, on 64-bit Linux or a new Pi card | [Install](#install) with the stable tag. | | Old FTW 2.x, 3.x or the old Pi image | Move data and config through a full backup to a second SD card or host. [Steps](#coming-from-an-older-ftw) | | Home Assistant app | Keep the app backup and move to another Linux host; keep Home Assistant on MQTT. [Steps](#coming-from-an-older-ftw) | @@ -203,7 +203,7 @@ return to [the second-card steps](#raspberry-pi-use-a-second-sd-card) first. This section does not update or migrate an old installation. Use the newest stable tag from [Releases](https://github.com/srcfl/ftw/releases), -`v0.142.0` or later with no `-beta` in it. Choose a beta only if you test new +`v0.142.1` or later with no `-beta` in it. Choose a beta only if you test new builds. Check that the release includes the Linux package for your architecture and its SHA-256 file. Do not use `releases/latest`: it still points to the retired 2.x line. Copy the tag from the release title; do not diff --git a/docs/setup-guide/update-sv.md b/docs/setup-guide/update-sv.md index 459dd65ea..0c28f0a51 100644 --- a/docs/setup-guide/update-sv.md +++ b/docs/setup-guide/update-sv.md @@ -1,6 +1,6 @@ # Byt till nya FTW och håll det uppdaterat -**Detta utkast gäller `v0.142.0`; stable är ännu inte publicerad.** FTW +**Detta utkast gäller `v0.142.1`; stable är ännu inte publicerad.** FTW 2.x och 3.x får inga fler uppdateringar. [English](../native-beta.md). ## Kort svar @@ -8,7 +8,7 @@ | Du kör | Gör så här | |---|---| | Nya FTW 0.x, native | Öppna **More → Version → Update FTW** i webbsidan, eller kör `ftw update` på boxen. Inget mer. | -| Nya FTW 0.x i Docker | Sätt `FTW_VERSION=v0.142.0` i `.env` och kör `docker compose up -d --build`. [Detaljer](#docker-från-det-nya-releasepaketet) | +| Nya FTW 0.x i Docker | Sätt `FTW_VERSION=v0.142.1` i `.env` och kör `docker compose up -d --build`. [Detaljer](#docker-från-det-nya-releasepaketet) | | Inget FTW än, på 64-bitars Linux eller ett nytt Pi-kort | [Installera](#installera-på-det-nya-kortet-eller-en-tom-linux-maskin) med den stabila taggen. | | Gamla FTW 2.x, 3.x eller den gamla Pi-imagen | Flytta data och config med en full backup till ett andra SD-kort eller en annan maskin. [Steg](#byt-på-raspberry-pi-med-ett-nytt-sd-kort) | | Home Assistant-appen | Ingen ny app än. Kör nya FTW på en annan Linux-maskin och koppla Home Assistant via MQTT. [Steg](#välj-en-väg) | @@ -190,7 +190,7 @@ kortet, gå tillbaka till kortbytet ovan. `--fresh-host` betyder att ingen FTW-installation eller dess data finns här, även om den är stoppad. 1. Öppna [Releases](https://github.com/srcfl/ftw/releases) på din vanliga dator. - Välj den senaste **stabila** taggen, `v0.142.0` eller senare utan `-beta`. + Välj den senaste **stabila** taggen, `v0.142.1` eller senare utan `-beta`. Välj en beta bara om du provar nya byggen. Releasen ska ha Linux-paket och SHA-256-fil för din maskin. Använd inte `releases/latest`; den pekar på gamla 2.x. From ac43a6a113e874d47e2a2eff7a3f81ab45022f65 Mon Sep 17 00:00:00 2001 From: Fredrik Ahlgren Date: Tue, 13 Oct 2026 16:28:25 +0200 Subject: [PATCH 28/29] docs: qualify the custom Linux 32-bit copy path --- docs/migration.md | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/docs/migration.md b/docs/migration.md index b87dac08f..ad7d81aaa 100644 --- a/docs/migration.md +++ b/docs/migration.md @@ -365,6 +365,20 @@ were checked. The AMD64 source ran through emulation on Apple Silicon. This covers the tested Linux Docker copy across CPU architectures; it does not qualify 32-bit sources or native macOS/Windows paths. +A separate test passed 42 checks from one custom Linux 386 build of the +unchanged 2.3.2 source to the published `v0.142.1-beta.1` ARM64 Core and +helper. The ELF32 source ran under QEMU user emulation and wrote current +history with millisecond timestamps. A verified full backup from a stopped, +writable export copy kept the source unchanged. Two ARM64 starts retained +25 exact old chart rows, two Parquet values, stored goals and credentials, +identity and all old YAML config fields after checked path, planner, SoC +and PV-unit mappings. New writes had no errors or rejected ticks. Return +to the matching 32-bit build and revert passed; the old source, backups +and new target database remain. All test containers are stopped. +This is a data-copy check for that custom build. It is not a published +32-bit package, an ARMv7/Pi test, a 32-bit OS, an installer change, reboot +or physical power-loss proof. + One external Linux layout from published 2.3.2 also passed 36 checks with the published `v0.141.4-beta.1` ARM64 Core and helper. Its database used a subdirectory, while the config seed, driver files and Parquet archive used @@ -384,7 +398,7 @@ and new files remain, and a complete backup can restore on a separate target. These tests use synthetic files and do not prove recovery from physical power loss or an interrupted installation change. -Large archives on Pi/SD, other external layouts, cross-platform and 32-bit sources, +Large archives on Pi/SD, other external layouts, cross-platform and other 32-bit sources, complete Supervisor control, interrupted installation changes and physical cutover remain release requirements. Unknown formats keep their source data and require a checked import path. From 2ef6520277411b487fa50ae25c7b4841602655a1 Mon Sep 17 00:00:00 2001 From: Fredrik Ahlgren Date: Tue, 13 Oct 2026 18:26:46 +0200 Subject: [PATCH 29/29] docs: qualify native macOS copy and note beta backup cancellation --- docs/backup-and-restore.md | 5 +++++ docs/migration.md | 14 ++++++++++++++ 2 files changed, 19 insertions(+) diff --git a/docs/backup-and-restore.md b/docs/backup-and-restore.md index 38d338f97..b0c5a31b9 100644 --- a/docs/backup-and-restore.md +++ b/docs/backup-and-restore.md @@ -51,6 +51,11 @@ disk. Keeping a copy somewhere else is the owner's step: point `--output-dir` at another disk, or copy the file off the machine. Keep at least one older known-good copy. +In `v0.142.1-beta.1`, Ctrl-C can stop the CLI while Core keeps making the +live backup. Check `/api/backups` for its phase and wait for completion +before starting an update. [The cancellation fix](https://github.com/srcfl/ftw/pull/1615) +is not included in that beta. + The archive leaves out other backups and old rollback points. It carries a consistent copy of `cache.db`: savings history is costed from its past prices, and a price provider sends only today and tomorrow. Managed-driver diff --git a/docs/migration.md b/docs/migration.md index ad7d81aaa..c0468deca 100644 --- a/docs/migration.md +++ b/docs/migration.md @@ -379,6 +379,20 @@ This is a data-copy check for that custom build. It is not a published 32-bit package, an ARMv7/Pi test, a 32-bit OS, an installer change, reboot or physical power-loss proof. +A native macOS ARM64 copy test passed 45 checks from an own Mach-O build +of the unchanged 2.3.2 source to the published `v0.142.1-beta.1` Linux +ARM64 Core and helper. The macOS process wrote new SQLite rows with all +network access denied; its source HTTP API was blocked too. A separate, +stopped Linux export copy kept the original macOS data unchanged. Two Linux +starts retained 25 exact old chart rows, two Parquet values, stored goals +and credentials, identity and all old YAML config fields after checked +path, planner, SoC and PV-unit mappings. New writes, native macOS return +and revert passed. Backup bytes were checked outside the export container, +on the same physical Mac. All source and target processes are stopped. +This covers that custom data-copy layout. It is not a published macOS +package, source API or installer test, Windows migration, a backup on a +separate physical host, equipment or power-loss proof. + One external Linux layout from published 2.3.2 also passed 36 checks with the published `v0.141.4-beta.1` ARM64 Core and helper. Its database used a subdirectory, while the config seed, driver files and Parquet archive used