Local-first home energy coordination.
FTW is a local-first home energy management system (EMS). It coordinates solar, batteries, grid power, EV charging and thermal assets on a Raspberry Pi or Linux host. The safety-critical runtime is one Go binary, hardware integrations are sandboxed Lua drivers, and a compiled Energyplan worker handles long-horizon planning.
The control path stays on the local network. Cloud price, weather and device integrations degrade independently; they are not required for safe local operation.
FTW should make mixed equipment simple to live with: useful first-day planning, reliable daily charging, fast and honest live feedback, and structured access for agents. The default experience should need few choices while keeping expert controls and Lua drivers available.
VISION.md is the product direction set by Fredrik. docs/roadmap.md lists the outcomes and proof needed. These include goals that have not shipped; the capability list below is separate.
Sourceful Energy maintains FTW Community under AGPL-3.0-only with the Energyplan combination permission. Contributions are welcome, preferably starting with issues. Share a short Markdown proposal or a focused fix with relevant test evidence. See CONTRIBUTING.md. Community help is best effort; SUPPORT.md describes separate commercial services.
Join the FTW Discord for questions and community discussions.
FTW has three explicit modules:
- Core owns configuration, telemetry, state, safety, dispatch, API and UI.
- Drivers translate vendor protocols and power signs in isolated Lua VMs.
- Optimizer proposes plans over a versioned contract; core validates every result and keeps a Go fallback.
Drivers and the optimizer can evolve without moving safety authority out of Core. A new module needs a concrete reason and must reduce the complexity of the whole product. See docs/architecture.md.
- self-consumption, peak shaving and explicit grid targets;
- multi-battery allocation with fuse, SoC, slew and stale-data protection;
- price-, weather-, PV- and load-aware planning;
- EV charging, V2X and thermal planning;
- local web UI, with history and configuration in SQLite;
- Home Assistant MQTT discovery;
- hot-reloadable, independently released Lua drivers;
- a built-in OCPP 1.6J + 2.0.1 server, so OCPP chargers connect with no driver.
The local catalog is generated from DRIVER metadata. The public
srcfl/device-drivers repo is the
editable source and FTW's default signed driver channel.
This repository holds no driver source. drivers/*.lua is gitignored and
fetched from that repository at the commit pinned in
drivers/BUNDLED_SOURCE.json:
make driversThe files still ship: they are the release's own drivers and what normally
runs. Startup is deliberately local — a gateway boots and runs without the
network, so a remote refresh must never block it — and the image, the release
tarballs and the tests all read drivers/. They are simply fetched rather than committed, which is
why a driver cannot be edited here at all. There is no file to open a pull
request against; fix it upstream and move the pin. CI fails if one is
committed.
Moving the pin is a driver release. make driver-versions-across-pin compares
the drivers at the old pin against the drivers at the new one and fails when a
file changed without its DRIVER version moving — the signed channel refuses to
publish changed bytes under a version it already published, and a gateway
offered the same version twice cannot tell them apart.
The pin needs watching in both directions. Every pull request runs
--check, which catches a driver edited here. A daily job runs --behind,
which catches the opposite: the pin left in place while a fix lands upstream.
It opens one issue and keeps it up to date, and stays quiet unless a bundled
driver actually changed.
2.x and 3.x will receive no further updates. New releases use the new 0.x line. Switch now to follow the latest fixes and features; do not install 3.x beta or use it as an intermediate upgrade.
Start with Install and update FTW (Svenska). It covers old Docker images, Raspberry Pi SD-card images, 1.x/2.x/3.x, older native sites, new native and Docker installs, Home Assistant, backup, and recovery.
The new line starts at v0.131.0-beta.1; old 0.x releases up to 0.130.x are
also retired. A lower version number or a saved beta channel does not tell
you which install path you have. Identify it before running commands.
Old FTW on a Raspberry Pi? Use a second SD card. Keep the old card, prepare the new one and swap cards before running install commands. Follow the card-by-card steps. Do not try Docker next if the native installer refuses the old card.
Use a fresh 64-bit Raspberry Pi OS, Debian or Ubuntu host for native systemd. Docker on the same Linux host is a separate, advanced option: identify and stop old Core and its updater, and preserve any MQTT service first. The guided migration of settings and history is not ready; preserve the old data and get help if those data must move before you switch. Only one Core may control the equipment, including after reboot.
Give the FTW host a DHCP reservation in the router so device connections keep
working. Open http://<host>:8080/setup after installation. The optional
FTW webapp connects through an encrypted
session and blind relay; relay loss does not stop local control.
The existing Home Assistant app is on the retired 3.x line. It does not follow new 0.x releases. Do not install that beta to get current FTW. Run new FTW on a separate Linux host and use the MQTT integration with Home Assistant.
Follow the switch guide, including backup and stopping the old app's Core, Start on boot and Watchdog. Supervisor still owns recovery of the old app; its update controls do not migrate to 0.x. Report old app or Supervisor faults in its issue tracker, and Core faults in this repository.
Requirements are Go and Node.js. Python 3 verifies release artifacts during development; no Python interpreter or service runs the planner.
git clone https://github.com/srcfl/ftw.git
cd ftw
make devUseful checks:
make test # Go tests
npm test # web
make verify # fast test, compose, vet and build checks
make e2e # simulator-backed full stack
make ci # e2e, builds and browser smokeSee docs/development.md for the small set of development workflows.
config.example.yaml and the validation types in
go/internal/config are the configuration reference. Copy the example for a native development setup:
cp config.local.example.yaml config.local.yamlPower values above a driver use one convention: positive means into the site, negative means out. Drivers alone translate vendor conventions. Read docs/site-convention.md before editing power math or writing a driver.
Drivers are plain Lua files and need no compilation. A driver declares its catalog metadata, lifecycle and required capabilities in one file. The Go host provides capability-scoped Modbus, MQTT, serial, HTTP, WebSocket and TCP access.
Which devices are covered, and on what evidence, is published as a searchable
catalog: Device driver catalog.
It is generated from srcfl/device-drivers on every push to that repository's
main, so the versions, tested models and per-target status it shows are the
ones FTW installs. Listing is not an install claim: the page states which
drivers have been confirmed against physical hardware and which have not.
Start with docs/writing-a-driver.md. Send shared
driver changes to srcfl/device-drivers. That repo publishes one signed,
content-addressed asset per driver and version. FTW downloads only the chosen
driver, which can update or roll back without a new FTW core release. Device
Support may consume the same public source later for other products or a higher
support level.
EV chargers that speak OCPP are the exception: they need no driver. FTW runs an OCPP Central System (1.6J and 2.0.1), so the charger connects and registers itself. See docs/ocpp.md.
There are two channels:
- beta receives every merged change in the next beta, aiming for one a week;
- stable promotes the exact commit already published and tested as beta.
There is no edge channel. Beta is the shared playground: run it on a real
site and report what you find as an issue naming the beta version you saw it
on. An issue marked release-blocker stops that line from promoting. A beta
promotes to stable after a week on the home box and at least one other real
site with no open release-blocker.
Changesets produce versions and changelog entries; the native release
workflow builds the checksummed Linux packages that the installer, ftw update and the Docker files use. The repository owner cuts every release.
Details for operators are in docs/self-update.md; the
maintainer rules are in the Releases section of AGENTS.md.
The repository deliberately keeps prose small. Code, types, tests and driver metadata are the detailed reference.
- Architecture
- Product roadmap
- Power sign convention
- Safety invariants
- Operations and recovery
- Full backup and safe restore
- Writing a driver
- Device driver catalog — every supported device and the evidence behind it
- OCPP chargers (no driver needed)
- Self-update and release channels
- Status of old Docker upgrades
- Home Assistant
Other files under docs/ are focused installation or
external-integration guides.
Read CONTRIBUTING.md. User-visible changes need a Changeset.
AGPL-3.0-only with the Energyplan combination permission — see LICENSE and LICENSING.md. Energyplan binaries have separate household-use terms; commercial use of those binaries needs a Sourceful agreement. Earlier versions retain their earlier licenses.