Dank Unterstützung von @Tom-HA ist es mir gelungen, Toorox Foresight HA als eigenständigen Docker Container, und nicht als HA-Addon (bzw. App) auf einem Intel-NUC unter Ubuntu zu nutzen. Ich verwende die HA-Version für Docker, weil bei mir die “supervised version” unter HAOS in einer virtuellen Maschine auf dem NuC instabil war. Es kam immer wieder zur Korruption der HA home-assistant_v2.db kam. Das ist nun Geschichte.
Wer sich für docker interessiert, kann zum Beispiel hier https://www.youtube.com/playlist?list=PL3o767Uczze7VyWBHumFZPSzMRNbtgl-l die Grundlagen erlernen. Wie man HA als docker container intallieren kann, ist z. B. hier gut erklärt: https://www.youtube.com/watch?v=S-itdbqwj4I&t=6s
Umgebung:
Ich verwende auf dem NUC Ubuntu 24.04.4 LTS. Unter “/opt” habe ich eine einzige “docker-compose.yaml” für die Konfiguration aller Container. Dort sind auch die Unterverzeichnisse für alle “exposed directories” der Container angelegt.
Docker Image erzeugen:
Zunächst ist die aktuelle SW-Version https://github.com/Zara-Toorox/TFS-HA-SFML-Transformer-AI/archive/refs/tags/V28.0.0.tar.gz herunter zu laden und in einem Verzeichnis nach Wunsch zu entpacken.
Dann in das Verzeichnis toorox_foresight_ha wechseln. Um das Image zu bauen, muss das dort gespeicherte “Dockerfile” angepasst werden, da es eigentlich für die HAOS-Umgebung geschrieben ist. Die erste Zeile enthält ARG BUILD_FROM. Ich habe sie auf ARG BUILD_FROM=ubuntugeändert.
Dann in diesem Verzeichnis
docker build -t toorox_foresight_ha .
ausführen. Der Build sollte beginnen. Auf dem NUC hat er ~200 sec gedauert. Das Image ist dann im Docker System bekannt und kann per docker compose geladen werden.
Hier mein Eintrag für toorox_foresight_ha in der docker-compose.yaml:
toorox-foresight:
image: toorox_foresight_ha:latest
container_name: toorox-foresight
restart: unless-stopped
ports:
- "8780:8780"
volumes:
- /opt/homeassistant/config:/config
environment:
- TFS_TIMEZONE_STR=Europe/Berlin
- TFS_LATITUDE=52.000000
- TFS_LONGITUDE=9.000000
- TFS_STATE_DIR=/config/toorox_foresight_ha
Da diese TFS-Version als HA-Addon gedacht ist, muss sie auf das “config”-Verzeichnis von HA zugreifen können, um dort die SFML-Datenbank direkt verwenden zu können. Deshalb wird /config auf das config-Verzeichnis des HA-Containers gemapped. Nachfolgend werden die 4 TFS_xxx Umgebungsvariablen definiert, da diese Daten von TFS als Container nicht von HA abgerufen werden können. Für LAT und LON natürlich den eigenen Standort eintragen :).
Der HA-Container muss im “network: host” Mode laufen, wie hier von ZARA erläutert: SFML: Feedback und Problemberichte zum aktuellen Release - #828 von Tom-HA
Meine Config für HA im docker-compose.yaml sieht so aus:
homeassistant:
container_name: homeassistant
image: "ghcr.io/home-assistant/home-assistant:stable"
volumes:
- /opt/homeassistant/config:/config
- /etc/localtime:/etc/localtime:ro
restart: unless-stopped
privileged: true
network_mode: host
Damit funktioniert funktioniert der Zugriff des SFML auf das TFS.
Nun kann der TFS-Container gestartet werden. Dazu im Verzeichnis, wo die docker-compose.yaml liegt, dies Kommando ausführen:
docker compose up -d toorox-foresight .
Das Log vom Start des Containers kann man sich so anschauen:
docker logs toorox-foresight
Oder aber über portainer im GUI …
Hier das Log vom erstmaligen Start des TFS im Docker Container:
INFO: Started server process [7]
INFO: Waiting for application startup.
2026-06-17T07:44:11.944891Z [info ] tfs_bootstrap codename=Phoenix state_dir=/config/toorox_foresight_ha version=28.0.0
2026-06-17T07:44:11.962563Z [info ] state_db_apply_migration description='Initial schema — forecasts, weights, baseline cache, training history' version=1
2026-06-17T07:44:11.964997Z [info ] state_db_schema_ready version=1
2026-06-17T07:44:11.965230Z [info ] state_db_connected path=/config/toorox_foresight_ha/tfs.db
2026-06-17T07:44:11.986666Z [info ] runtime_context_resolved latitude=52.2857943 location_source=settings longitude=9.28650475 panel_group_source=sfml panel_groups=3
2026-06-17T07:44:11.987237Z [info ] weather_blender_initialized rows=0
2026-06-17T07:44:12.642271Z [info ] base_model_loaded path=/app/models/base/TFS-V2_pretrain_best.safetensors.enc
2026-06-17T07:44:12.642587Z [info ] lora_not_applied instance=default status=missing_refinetune_pending
2026-06-17T07:44:12.646666Z [info ] startup_notification adapter_path=/config/toorox_foresight_ha/lora/lora_default.safetensors adapter_status=missing_refinetune_pending base_model_hash=9f032a4b93da1794 base_model_path=/app/models/base/TFS-V2_pretrain_best.safetensors.enc codename=Phoenix panel_groups=3 version=28.0.0
2026-06-17T07:44:12.649007Z [info ] forecast_job_registered kind=fixed spec=00:30
/usr/local/lib/python3.12/site-packages/tzlocal/unix.py:203: UserWarning: Can not find any timezone configuration, defaulting to UTC.
warnings.warn("Can not find any timezone configuration, defaulting to UTC.")
2026-06-17T07:44:12.732257Z [info ] forecast_job_registered kind=solar_dynamic next_run_local=2026-06-18T04:15:33.419256+02:00 next_run_utc=2026-06-18T02:15:33.419256+00:00 spec=sunrise-45
2026-06-17T07:44:12.732622Z [info ] finetune_job_registered at=00:00 timezone=Europe/Berlin
2026-06-17T07:44:12.733531Z [info ] scheduler_started timezone=Europe/Berlin
2026-06-17T07:44:12.733777Z [info ] startup_refinetune_queued adapter_status=missing_refinetune_pending base_hash_adapter=None base_hash_current=9f032a4b93da1794 requested_at=2026-06-17T07:44:12.733749+00:00
2026-06-17T07:44:12.733906Z [info ] startup_notification_refinetune reason=queued status=queued
INFO: Application startup complete.
INFO: Uvicorn running on http://0.0.0.0:8780 (Press CTRL+C to quit)
2026-06-17T07:44:12.763783Z [info ] weather_learning_done end_date=2026-06-16 samples=336 start_date=2026-06-02 status=success weights=32
2026-06-17T07:44:12.858340Z [info ] finetune_dataset_building actuals_count=1047 degradation_count=1440 end_date=2026-06-16 groups=3 max_samples=200 start_date=2026-04-17 step_hours=6 weather_count=1094
2026-06-17T07:44:44.633154Z [info ] finetune_dataset_progress offset=10/200 samples=10
2026-06-17T07:45:16.377015Z [info ] finetune_dataset_progress offset=20/200 samples=20
2026-06-17T07:45:48.065688Z [info ] finetune_dataset_progress offset=30/200 samples=30
2026-06-17T07:46:19.881185Z [info ] finetune_dataset_progress offset=40/200 samples=40
2026-06-17T07:46:51.580685Z [info ] finetune_dataset_progress offset=50/200 samples=50
2026-06-17T07:47:23.268277Z [info ] finetune_dataset_progress offset=60/200 samples=60
2026-06-17T07:47:55.042982Z [info ] finetune_dataset_progress offset=70/200 samples=70
2026-06-17T07:48:26.851659Z [info ] finetune_dataset_progress offset=80/200 samples=80
2026-06-17T07:48:58.564071Z [info ] finetune_dataset_progress offset=90/200 samples=90
2026-06-17T07:49:30.221736Z [info ] finetune_dataset_progress offset=100/200 samples=100
2026-06-17T07:50:01.887314Z [info ] finetune_dataset_progress offset=110/200 samples=110
2026-06-17T07:50:33.700380Z [info ] finetune_dataset_progress offset=120/200 samples=120
2026-06-17T07:51:05.370001Z [info ] finetune_dataset_progress offset=130/200 samples=130
2026-06-17T07:51:36.949277Z [info ] finetune_dataset_progress offset=140/200 samples=140
2026-06-17T07:52:08.693085Z [info ] finetune_dataset_progress offset=150/200 samples=150
2026-06-17T07:52:40.302139Z [info ] finetune_dataset_progress offset=160/200 samples=160
2026-06-17T07:53:11.985587Z [info ] finetune_dataset_progress offset=170/200 samples=170
2026-06-17T07:53:43.697992Z [info ] finetune_dataset_progress offset=180/200 samples=180
2026-06-17T07:54:15.330408Z [info ] finetune_dataset_progress offset=190/200 samples=190
2026-06-17T07:54:46.946381Z [info ] finetune_dataset_progress offset=200/200 samples=200
2026-06-17T07:54:46.946527Z [info ] finetune_dataset_complete total_samples=200 valid_ratio=200/200
2026-06-17T07:54:46.947126Z [info ] finetune_dataset_ready end_date=2026-06-16 samples=200
2026-06-17T07:54:47.552942Z [info ] finetune_training_start device=cpu lora_rank=8 max_epochs=20 samples=200 train_size=160 val_size=40
2026-06-17T07:55:38.294876Z [info ] finetune_epoch best_val=n/a elapsed=50.7s epoch=1/20 train_loss=0.15800 val_loss=0.15458
2026-06-17T07:56:27.383703Z [info ] finetune_epoch best_val=0.15458 elapsed=99.8s epoch=2/20 train_loss=0.15417 val_loss=0.14842
2026-06-17T07:57:16.471221Z [info ] finetune_epoch best_val=0.14842 elapsed=148.9s epoch=3/20 train_loss=0.14777 val_loss=0.13952
2026-06-17T07:58:05.521378Z [info ] finetune_epoch best_val=0.13952 elapsed=198.0s epoch=4/20 train_loss=0.13910 val_loss=0.12804
2026-06-17T07:58:55.279989Z [info ] finetune_epoch best_val=0.12804 elapsed=247.7s epoch=5/20 train_loss=0.12810 val_loss=0.11587
2026-06-17T07:59:44.730056Z [info ] finetune_epoch best_val=0.11587 elapsed=297.2s epoch=6/20 train_loss=0.11643 val_loss=0.10263
2026-06-17T08:00:34.336773Z [info ] finetune_epoch best_val=0.10263 elapsed=346.8s epoch=7/20 train_loss=0.10227 val_loss=0.08260
2026-06-17T08:00:38.513437Z [info ] weather_fetch_complete hours=72 sources=['open_meteo', 'brightsky']
2026-06-17T08:00:42.429376Z [info ] forecast_complete groups=3 horizon=72h lora=missing_refinetune_pending p10=154.2kWh p50=164.2kWh p90=175.1kWh
2026-06-17T08:01:27.035547Z [info ] finetune_epoch best_val=0.08260 elapsed=399.5s epoch=8/20 train_loss=0.06465 val_loss=0.05967
2026-06-17T08:02:16.730426Z [info ] finetune_epoch best_val=0.05967 elapsed=449.2s epoch=9/20 train_loss=0.05129 val_loss=0.04781
2026-06-17T08:03:06.052188Z [info ] finetune_epoch best_val=0.04781 elapsed=498.5s epoch=10/20 train_loss=0.04803 val_loss=0.04719
2026-06-17T08:03:55.440468Z [info ] finetune_epoch best_val=0.04719 elapsed=547.9s epoch=11/20 train_loss=0.04633 val_loss=0.04512
2026-06-17T08:04:44.729002Z [info ] finetune_epoch best_val=0.04512 elapsed=597.2s epoch=12/20 train_loss=0.04531 val_loss=0.04495
2026-06-17T08:05:34.217445Z [info ] finetune_epoch best_val=0.04495 elapsed=646.7s epoch=13/20 train_loss=0.04451 val_loss=0.04373
2026-06-17T08:06:23.420460Z [info ] finetune_epoch best_val=0.04373 elapsed=695.9s epoch=14/20 train_loss=0.04406 val_loss=0.04311
2026-06-17T08:07:12.676224Z [info ] finetune_epoch best_val=0.04311 elapsed=745.1s epoch=15/20 train_loss=0.04362 val_loss=0.04327
2026-06-17T08:08:01.790034Z [info ] finetune_epoch best_val=0.04311 elapsed=794.2s epoch=16/20 train_loss=0.04338 val_loss=0.04272
WARNING: Invalid HTTP request received.
WARNING: Invalid HTTP request received.
2026-06-17T08:08:51.006854Z [info ] finetune_epoch best_val=0.04272 elapsed=843.5s epoch=17/20 train_loss=0.04320 val_loss=0.04289
2026-06-17T08:09:40.256852Z [info ] finetune_epoch best_val=0.04272 elapsed=892.7s epoch=18/20 train_loss=0.04304 val_loss=0.04228
2026-06-17T08:10:29.473011Z [info ] finetune_epoch best_val=0.04228 elapsed=941.9s epoch=19/20 train_loss=0.04297 val_loss=0.04245
2026-06-17T08:11:18.747963Z [info ] finetune_epoch best_val=0.04228 elapsed=991.2s epoch=20/20 train_loss=0.04284 val_loss=0.04244
2026-06-17T08:11:18.778233Z [info ] finetune_complete adapter=/config/toorox_foresight_ha/lora/lora_default.safetensors elapsed=991.2s epochs=20 val_loss=0.04228
2026-06-17T08:11:18.799635Z [info ] correction_learning_done epochs=20 latest_learning_date=2026-06-16 samples=200 status=success val_loss=0.04228
2026-06-17T08:11:19.161034Z [info ] base_model_loaded path=/app/models/base/TFS-V2_pretrain_best.safetensors.enc
2026-06-17T08:11:21.219226Z [info ] lora_applied instance=default val_loss=0.042282
2026-06-17T08:11:21.229127Z [info ] lora_reloaded_after_finetune status=active
2026-06-17T08:11:21.229713Z [info ] learning_job_complete correction_status=success status=completed weather_status=success
Die Uhrzeiten sind in UTC angegeben. Die gesamte Initialisierung hat bei also von 9:44 Uhr bis 10:11 Uhr gedauert, also ~27 Minuten.
Inzwischen sind 2 weitere Meldungen im Log aufgelaufen, die zeigen, dass TFS funktioniert:
2026-06-17T14:01:04.181225Z [info ] weather_fetch_complete hours=72 sources=['open_meteo', 'brightsky']
2026-06-17T14:01:06.645498Z [info ] forecast_complete groups=3 horizon=72h lora=active p10=154.4kWh p50=281.4kWh p90=287.6kWh
Viel Spaß beim Nachmachen und nochmal herzlichen Dank an @Tom-HA für seine Software!