Local-first home energy coordination.
FTW is an open-source local energy runtime for solar, batteries, grid and EV charging. Its core runs as a single Go binary on a Raspberry Pi or Linux host, coordinates devices through Lua drivers, and keeps the control loop local. The optional full mathematical optimizer uses Python/CVXPY; official containers include that runtime and native installs fall back safely to the Go planner when it is unavailable.
FTW is maintained by Sourceful Labs AB and project contributors. It is a self-hosted open-source project, not a hosted Sourceful service; the local control path does not depend on Sourceful cloud services.
Upgrading an existing Forty Two Watts installation? Follow the step-by-step legacy upgrade guide in Swedish and English. Its migration command moves older Docker Compose and local-development layouts to the official Sourceful images while preserving the existing service, directory, configuration, history, and device data.
The project is active and runs on real hardware, but API and config fields
can still change before a stable 1.0 release. Version numbers come from
git tags and package.json; use the GitHub releases page for the latest
published build.
- Self-consumption: batteries discharge to cover household load, charge from PV surplus, and keep the site meter near the configured target.
- MPC planning: a 48-hour planner uses spot prices, weather, PV, load, and battery state to choose charge, discharge, hold, or export targets.
- EV and V2X awareness: EV charging is treated as load, and V2X chargers can emit bidirectional vehicle power without confusing stationary batteries.
- Calendar planning (CalDAV): add events in your normal calendar app and
FTW turns them into planner intents — Away / Vacation conserves battery,
Charge car 80% sets an EV departure deadline — and publishes charging
windows + EVSE usage history back to a calendar you can subscribe to. FTW
hosts CalDAV itself, in-process, via
emersion/go-webdav— no extra container, recurring events supported, and it works as a Home Assistant add-on. Seedocs/caldav-integration.md. - Multi-device control: multiple meters, inverters, batteries, PV-only devices, and chargers can run side by side.
- Local operation: the control loop does not depend on a cloud service. Prices, weather, notifications, and cloud drivers degrade independently.
Drivers are plain Lua files under drivers/. The in-app catalog
is generated from each driver's DRIVER metadata block, and
docs/driver-catalog.md mirrors that metadata for
humans. The driver list should not be maintained as a number in this README.
Current bundled driver families include:
| Category | Examples |
|---|---|
| Hybrid inverters | Sungrow, Ferroamp, Solis, Huawei, Deye, SMA, Fronius, GoodWe, Growatt, Sofar, Victron, Kostal |
| PV and meters | SolarEdge, SMA PV, Pixii PV, Eastron SDM630, Fronius Smart Meter, Tibber Pulse, Zuidwijk P1, Sourceful Zap |
| Batteries | Ferroamp, Pixii, sonnen, hybrid inverter batteries |
| EV and V2X | Easee, CTEK Chargestorm, Tesla Vehicle, Ferroamp DC2 V2X, Ambibox V2X |
Adding a new device starts with
docs/writing-a-driver.md.
Recommended: point Raspberry Pi Imager at the FTW image repository (App Options → Content Repository → Use custom file):
https://github.com/srcfl/ftw/releases/download/rpi-installer/os_list.json
Then pick FTW, set your hostname / SSH user / Wi-Fi in the
customisation panel, and write — Imager downloads the image for you. Boot the
Pi and open http://ftw.local/.
You can instead download the latest dated .img.xz from the dedicated
rpi-installer release
and flash it directly, but that skips the customisation panel (default
credentials, Wi-Fi via the ftw-setup captive portal) — not recommended.
Full walkthrough: docs/rpi-image.md.
On Raspberry Pi OS, Debian, or Ubuntu:
curl -fsSL https://raw.githubusercontent.com/srcfl/ftw/master/scripts/install.sh | bashThen open http://<your-pi>:8080/setup.
If you run Home Assistant OS or HA Supervised, install the add-on from
erikarenhill/ha-addon-forty-two-watts.
Prerequisites: Go 1.26+, a Linux/Raspberry Pi target, and at least one supported device or simulator.
git clone https://github.com/srcfl/ftw
cd ftw
make dev # simulators + app at http://localhost:8080
make test # unit + integration tests
make build-arm64 # cross-compile for Raspberry PiThe first make dev copies the tracked simulator template to the gitignored
config.local.yaml, starts both simulators, and opens the app on port 8080.
For real hardware, copy config.example.yaml to config.yaml and fill in your
device capabilities instead.
config.yaml
|
v
Lua drivers: Modbus / MQTT / HTTP / WebSocket / raw TCP
|
v
Telemetry store: latest readings, driver health, metric queue
|
v
Control loop: PI, dispatch splitting, slew, fuse guard, watchdog
|
v
MPC planner + PV/load/price twins + SQLite state
|
v
HTTP API, dashboard, Home Assistant bridge, notifications
All power values above the driver boundary use the same site convention:
positive W means energy flowing into the site across the grid-meter
boundary. Read docs/site-convention.md before
touching power math.
Transition status: local control is unaffected, but the new Sourceful relay/TURN endpoints are not yet declared operational. Treat remote access as unavailable unless the deployment runbook has been completed and verified; this infrastructure cutover is tracked separately from the repository migration.
Remote access is opt-in and still keeps the home site local-first. Enable it
from the local dashboard under Settings -> Access, save, and restart when
prompted. The Pi then registers an opaque, high-entropy site_id with the
public relay and publishes only the minimal information needed for a browser to
find that Pi.
Once that infrastructure has been provisioned and verified, the public
home.fortytwowatts.com route works in three layers:
- The relay serves a small loader and owner-access pages from the
ftw-relay-web.tar.gzrelease asset. - After a browser unlocks its encrypted local directory, static dashboard files are fetched from the selected Pi through the relay route.
- Owner API calls, login, status, prices, history, plans, settings, and control commands go over the strict WebRTC DataChannel to the Pi.
The relay is therefore only a blind router and bootstrap host. It does not
store the dashboard app bundle, does not terminate owner sessions, does not
receive ftw_owner cookies, and does not inspect passkeys or owner data.
Passkeys, remembered browser keys, and active sessions are managed locally in
the Access tab, where they can also be revoked.
First setup is a one-time bootstrap: the local Access screen shows a QR/link and PIN only before the first passkey exists, and only after the relay has accepted the live setup invitation. After one passkey is enrolled, add or revoke access from Settings -> Access while signed in.
Relay operators should install the relay bootstrap bundle from each release,
not copy the Pi dashboard web/ directory to the relay. Deployment details:
docs/relay-deploy.md.
Get started
docs/rpi-image.md- SD-card image and captive portaldocs/setup-guide/- alternative generic Raspberry Pi OS + Docker setupdocs/configuration.md- YAML config referencedocs/driver-catalog.md- bundled Lua drivers
Run it
docs/operations.md- deploy, backup, logs, recoverydocs/self-update.md- Docker updater sidecarMIGRATION.md- former-name compatibility and upgrade notesdocs/ha-integration.md- MQTT autodiscoverydocs/caldav-integration.md- calendar planner constraints (CalDAV)docs/safety.md- watchdog, clamps, fuse guard
Understand it
docs/architecture.md- system map and data flowdocs/site-convention.md- sign conventiondocs/ml-models.md- PV, load, and price twinsdocs/mpc-planner.md- planner strategy detailsdocs/battery-models.md- ARX/RLS battery modelsdocs/api.md- HTTP API reference
Build with it
docs/writing-a-driver.md- Lua driver guidedocs/host-api.md-host.*Lua capability referencedocs/testing-drivers-live.md- live driver testingdocs/testing.md- repo test guidedocs/development.md- local development loop
Historical plans and early TODOs live under docs/archive/
when they are kept for context.
make test
make e2e
make dev
make ci
make build-arm64Releases are driven by Changesets and GitHub Actions:
- Add a
.changeset/*.mdentry for each user-visible change. - Merge the feature PR to
master. - The
releaseworkflow opens or updates the "Version Packages" PR. - Merge that Version PR to bump
package.json, updateCHANGELOG.md, create thevX.Y.Ztag, and publish the GitHub Release. - The
release-assetsworkflow builds and uploads Linux/Windows binaries,ftw-relaybinaries, Docker images, andftw-relay-web.tar.gz.
The Raspberry Pi installer image has its own monthly/on-change workflow and
permanent rpi-installer channel. It pulls the current stable containers on
first boot, so application patch releases do not rebuild the base OS image.
Do not hand-edit CHANGELOG.md or manually bump package.json; pending
release notes live in .changeset/*.md.
- Discord: discord.gg/25xcBzQaux
- Issues: github.com/srcfl/ftw/issues
Licensed under the Apache License, Version 2.0 — see LICENSE and
NOTICE. Project naming guidance lives in TRADEMARKS.md.
Contributions are accepted under the same license via the
Developer Certificate of Origin (commit with git commit -s).
Prior to the adoption of Apache-2.0, the project was offered under the MIT License. See
NOTICEfor details.
