-
Notifications
You must be signed in to change notification settings - Fork 7
Expand file tree
/
Copy pathdocker-compose.yml
More file actions
182 lines (167 loc) · 8.35 KB
/
Copy pathdocker-compose.yml
File metadata and controls
182 lines (167 loc) · 8.35 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
# FTW — Home Energy Management System (Linux)
#
# Pulls the pre-built multi-arch image (linux/amd64 + linux/arm64) from
# GitHub Container Registry. No local build needed.
#
# Start: docker compose up -d
# Logs: docker compose logs -f
# Upgrade: docker compose pull && docker compose up -d
# Stop: docker compose down
#
# PLATFORM: This file uses `network_mode: host`, a Linux-kernel feature.
# It is the right file for a Raspberry Pi, an Ubuntu/Debian server, a
# NUC, or a Linux VM. On macOS (e.g. a Mac mini) host networking binds to
# the Docker Desktop VM, not to the Mac, so the dashboard is unreachable
# and discovery breaks silently — use docker-compose.macos.yml instead.
# Use docker-compose.macos.yml on Docker Desktop for Mac.
#
# Persistent state — config.yaml, state.db, battery models, cold/
# Parquet files — lives in ./data and survives image upgrades. The
# directory must be owned by uid 100 / gid 101 so the container's ftw
# user can write to it. If you set this up manually (instead of via
# scripts/install.sh), run:
#
# mkdir -p ./data && sudo chown -R 100:101 ./data
#
# In-app updates: the `ftw-updater` sidecar below is what the "Update" /
# "Restart" buttons in the web UI signal to pull a new image + recreate
# the main service. See docs/self-update.md. Remove the sidecar service
# (and the update-ipc volume) if you prefer to run upgrades by hand —
# the UI buttons will surface a non-2xx error (typically 502) and the
# version-check banner keeps working as a notify-only indicator.
name: ${COMPOSE_PROJECT_NAME:-ftw}
services:
ftw:
# Tag is variable so the ftw-updater sidecar can pin to a specific
# release on `update`. Manual `docker compose up -d` (no env set)
# falls through to :latest. See docs/self-update.md.
image: ghcr.io/srcfl/ftw:${FTW_IMAGE_TAG:-latest}
container_name: ftw
restart: unless-stopped
environment:
# Turns on the in-app self-update feature (version-check banner +
# Update/Restart buttons). Only meaningful alongside the ftw-updater
# sidecar below; native / OS-image deploys leave this unset so the
# UI hides the feature entirely. See docs/self-update.md.
FTW_SELFUPDATE_ENABLED: "1"
# Optional Bearer token for API mutations addressed through a public or
# fully-qualified hostname. Keep it in .env so updater-driven recreates
# retain it. Local LAN addresses continue to work without a token.
FTW_API_TOKEN: ${FTW_API_TOKEN:-}
# Prefer the independently versioned optimizer sidecar. During the
# migration window core falls back to its bundled Python worker, then
# to the Go DP planner, if this socket is unavailable or incompatible.
FTW_OPTIMIZER_TRANSPORT: ${FTW_OPTIMIZER_TRANSPORT:-auto}
FTW_OPTIMIZER_SOCKET: /run/ftw-optimizer/optimizer.sock
# Host networking is required for:
# - Modbus TCP to inverters / meters on the LAN
# - MQTT brokers on the LAN (no port forwarding)
# - mDNS-based drivers (e.g. Sourceful Zap at zap.local)
#
# If you don't have any local hardware (e.g. you're just evaluating
# the UI) you can drop this line and add `ports: ["8080:8080"]`
# instead, at the cost of losing mDNS/broadcast driver discovery.
network_mode: host
volumes:
- ./data:/app/data
# Shared volume with the updater — the main app reads state.json from
# here to render update progress in the UI; it never writes to it.
- update-ipc:/run/ftw-update
- optimizer-ipc:/run/ftw-optimizer
ftw-optimizer:
image: ghcr.io/srcfl/ftw-optimizer:${FTW_OPTIMIZER_IMAGE_TAG:-latest}
container_name: ftw-optimizer
restart: unless-stopped
network_mode: none
environment:
FTW_OPTIMIZER_SOCKET: /run/ftw-optimizer/optimizer.sock
volumes:
- optimizer-ipc:/run/ftw-optimizer
ftw-updater:
# Normally follows :latest. The separate variable is only needed for
# bootstrapping a beta pair before the installed stable updater
# understands that prerelease's immutable tag.
image: ghcr.io/srcfl/ftw-updater:${FTW_UPDATER_IMAGE_TAG:-latest}
container_name: ftw-updater
restart: unless-stopped
# No network — the sidecar reaches the host daemon over its Unix
# socket and the main app reaches it over a Unix socket inside
# update-ipc. Nothing needs to leave this container.
network_mode: none
environment:
# Point the sidecar's internal `docker compose -f <path>` at the
# same absolute host path the user invoked compose with. This
# matters because the host daemon — not the sidecar — interprets
# the bind paths in the file, so they must be real host paths.
FTW_UPDATER_COMPOSE: ${PWD:-.}/docker-compose.yml
FTW_UPDATER_MAIN_SERVICE: ftw
# Without this the sidecar's internal compose would derive its
# project name from the -f file's parent dir and create a parallel
# set of containers/volumes instead of recreating the real ones.
# Defaults to `ftw` (matches the layout in
# operations.md); override at launch time if your deploy dir is
# named differently:
# COMPOSE_PROJECT_NAME=myhome docker compose up -d
COMPOSE_PROJECT_NAME: ${COMPOSE_PROJECT_NAME:-ftw}
volumes:
# The Docker socket is the ONE privileged resource the sidecar
# touches. Needed so it can `docker compose pull` + recreate the
# main service. If you want to harden this further, put
# tecnativa/docker-socket-proxy in front and swap the bind.
- /var/run/docker.sock:/var/run/docker.sock
# Bind the WHOLE project directory at its host path, read-only.
# Rationale: when the sidecar runs `docker compose up -d`, compose
# asks the host daemon to resolve `./data:/app/data` — which the
# daemon reads as an ABSOLUTE HOST PATH. If the path inside the
# sidecar doesn't match the host, the daemon binds a phantom
# directory and the recreated main container boots with empty
# state. ${PWD} comes from the shell at `docker compose up` time,
# which is the invocation flow documented in operations.md.
- ${PWD:-.}:${PWD:-.}:ro
# Shared with the main container so the update status survives the
# main app being recreated (volume contents outlive the container
# lifecycle of individual services that mount the same volume).
- update-ipc:/run/ftw-update
# ---------------------------------------------------------------------
# MQTT broker (Eclipse Mosquitto)
#
# Lets on-LAN devices — notably the Pixii PowerShaper's MQTT uplink —
# publish telemetry into FTW without us having to poll them
# over Modbus. The main app reaches the broker at localhost:1883 because
# it runs with host networking; the Pixii (and any other LAN device)
# reaches it at <host-ip>:1883.
#
# Config lives in ./mosquitto/config/mosquitto.conf (anonymous access,
# persistent queues). Remove this service block if you don't need an
# embedded broker — FTW drivers can just as well dial out
# to a broker somewhere else on the LAN.
# ---------------------------------------------------------------------
mosquitto:
image: eclipse-mosquitto:2
container_name: ftw-mosquitto
restart: unless-stopped
ports:
- "1883:1883"
volumes:
- ./mosquitto/config:/mosquitto/config:ro
- mosquitto-data:/mosquitto/data
# ---------------------------------------------------------------------
# Calendar (CalDAV) planner constraints (#498)
#
# No service here: FTW hosts its OWN in-process, pure-Go CalDAV server
# (emersion/go-webdav, MIT) inside the main container — there is no sidecar to
# run. With `caldav.enabled: true`, point a CalDAV account in your phone or
# desktop calendar app at http://<host-ip>:5232/<user>/energy/ and create
# events to drive the planner:
# - "Away" / "Vacation" → conserve battery while you're out.
# - "Charge car 80%" → have the EV ready by the event's start time.
# FTW also writes read-only "EVSE history" and "plan" calendars you subscribe
# to. Credentials are auto-managed and shown (with a QR) in Settings →
# Calendar. LAN-ONLY by design; nothing forwards port 5232 to the internet
# unless the operator does so separately.
# See docs/caldav-integration.md.
# ---------------------------------------------------------------------
volumes:
update-ipc:
optimizer-ipc:
mosquitto-data: