-
Notifications
You must be signed in to change notification settings - Fork 8
Expand file tree
/
Copy pathconfig.example.yaml
More file actions
252 lines (237 loc) · 9.87 KB
/
Copy pathconfig.example.yaml
File metadata and controls
252 lines (237 loc) · 9.87 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
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
# FTW config example
# Copy to config.yaml and edit for your site.
site:
name: "Home"
control_interval_s: 2 # 2 s matches Ferroamp ehub ~1 Hz; drop to 1 for snappier response
grid_target_w: 0 # 0 = self-consumption
grid_tolerance_w: 42 # deadband (The Answer)
watchdog_timeout_s: 60
smoothing_alpha: 0.3
slew_rate_w: 3000 # W per cycle. Both Ferroamp and Sungrow ramp internally — this is a soft ceiling, not the primary protection
# slew_enabled: false # disable the external slew limiter entirely and trust the inverter's internal ramp control (experimental)
min_dispatch_interval_s: 2 # debounce; keep == control_interval_s
fuse:
max_amps: 16
phases: 3
voltage: 230
# ----------------------------------------------------------------------
# Drivers — Lua scripts with per-driver capabilities.
# Capabilities are the ONLY way the sandbox talks to the outside world.
# A driver with only mqtt capability can't touch modbus, and vice versa.
# ----------------------------------------------------------------------
drivers:
- name: ferroamp
lua: drivers/ferroamp.lua
is_site_meter: true # exactly one driver must have this
battery_capacity_wh: 15200
capabilities:
mqtt:
host: 192.168.1.153
port: 1883
username: extapi
password: ferroampExtApi
- name: sungrow
lua: drivers/sungrow.lua
battery_capacity_wh: 9600
capabilities:
modbus:
host: 192.168.1.10
port: 502
unit_id: 1
# Pixii PowerShaper. When troubleshooting mode is enabled in Settings,
# Pixii also exposes calibration/control status and setpoint readback metrics.
# - name: pixii
# lua: drivers/pixii.lua
# is_site_meter: true
# battery_capacity_wh: 20000
# observe_only: true # retailer VPP controls actuation — FTW reads only
# capabilities:
# modbus:
# host: 192.168.1.50
# port: 502
# unit_id: 1
# V2X chargers are modeled separately from stationary batteries.
# They emit signed v2x_charger.w telemetry:
# +W = vehicle charging, -W = vehicle discharging into the site/grid.
# Manual test setpoints can be sent with POST /api/v2x/command.
#
# - name: ferroamp_dc2
# lua: drivers/ferroamp_dc2_v2x.lua
# capabilities:
# mqtt:
# host: 192.168.1.70
# port: 1883
# username: dc2
# password: dc2mqtt!
#
# - name: ambibox
# lua: drivers/ambibox_v2x.lua
# capabilities:
# mqtt:
# host: sid-os.local
# port: 1883
# Sourceful Zap — official local-API integration. Zap can be the site meter
# and can aggregate every PV, battery and V2X DER attached to the gateway.
# The driver is telemetry-only: battery_telemetry_only admits battery data
# without making Zap a dispatch target. Zap firmware has semantic local
# command routes, but its REST path currently lacks expiring leases and a
# hardware-execution acknowledgement. FTW control therefore still uses the
# native inverter/charger driver; see docs/sourceful-zap.md.
#
# - name: sourceful-zap
# lua: drivers/zap.lua
# is_site_meter: true
# battery_telemetry_only: true
# capabilities:
# http:
# allowed_hosts: ["zap.local"] # use the LAN IP if mDNS is unavailable
# config:
# host: zap.local
# # meter_serial: p1m-... # optional; P1 is auto-selected
# # disable_pv: true # if a native driver already emits PV
# # disable_battery: true # if a native driver emits the battery
# # disable_v2x: true # if a native V2X driver is configured
# NIBE S-series heat pump — read-only telemetry over the on-prem Local
# REST API (HTTPS + Basic auth). The pump presents a SELF-SIGNED cert, so
# pin it: tls_pin_sha256 is the cert SHA-256 fingerprint (the
# "fingeravtryck" shown in the myUplink app, or from `openssl s_client
# -connect <ip>:8443 | openssl x509 -fingerprint -sha256`). The host then
# trusts exactly that one cert — never a blanket insecure-skip-verify.
# Read-only by default: the driver issues no writes at all. (The pump-side
# write gate is the installer's read-only/read-write choice for the Local
# REST API, menu 7.5.15 — NOT "aid mode", which is a compressor-off fault
# state unrelated to API permissions.) One opt-in write path exists — the
# pump's native Solar PV surplus feed (srcfl/ftw#537, developed in
# srcfl/device-drivers). It needs BOTH the host capabilities.http.allow_write
# grant below AND write.solar_pv: true in the driver config; leave either off
# and the driver stays read-only.
# - name: nibe
# lua: drivers/nibe_local.lua
# config:
# host: 192.168.1.180
# port: 8443
# username: <local-api-username>
# password: <local-api-password>
# # write: # opt-in Solar PV feed (off unless present)
# # solar_pv: true
# # max_w: 9000 # REQUIRED clamp ceiling (site PV nameplate, W)
# capabilities:
# http:
# allowed_hosts: ["192.168.1.180:8443"]
# tls_pin_sha256: "<64-hex-char certificate fingerprint>"
# # allow_write: true # host gate for host.http_patch; default off
api:
port: 8080
# Home Assistant MQTT bridge (optional)
homeassistant:
enabled: false
broker: 192.168.1.1
port: 1883
username: homeems
password: homeems
publish_interval_s: 5
# Calendar-based planner constraints (#498). FTW hosts its OWN in-process,
# pure-Go CalDAV server (emersion/go-webdav, MIT — no sidecar, works in a
# single container incl. a Home Assistant add-on; objects persist in state.db)
# and turns the events you add into planner intents: "Away"/"Vacation" → away
# load profile; "Charge car 80%" → EV target SoC by the event time. It also
# writes EVSE usage-history and forward-looking plan calendars you subscribe
# to. Recurring events are expanded server-side. Opt-in + fail-soft; the
# password is stored in state.db. See docs/caldav-integration.md.
caldav:
enabled: false
# listen: ":5232" # bind address for the in-process CalDAV server
url: http://localhost:5232
username: ftw
# manage_credentials (default true): FTW generates the password and the
# in-process server authenticates against it, then shows it (with a QR) in
# Settings → Calendar. Set false to set `password` here by hand.
manage_credentials: true
password: ""
calendar_path: /ftw/energy/
poll_interval_s: 300
ev_default_target_soc_pct: 80
# ev_loadpoint_id: "" # defaults to the first configured loadpoint
# away_keywords: [away, vacation, holiday]
# ev_keywords: [ev, car, charge]
evse_history: true # write a calendar event per EV charge session
history_path: /ftw/history/
publish_plan: true # publish upcoming charge/discharge windows (read-only)
plan_path: /ftw/plan/
# plan_publish_interval_s: 900 # how often the plan calendar is reconciled
# Persistent state (SQLite)
state:
path: state.db
# backup_dir: backups # use an absolute mounted path for off-device backups
# Home Link is opt-in. It opens only an outbound TLS connection and exposes
# four read-only views after a local passkey is enrolled.
home_link:
enabled: false
# Independently distributed Lua drivers. The signed stable catalog is refreshed
# by default, but refresh never downloads, activates, or restarts a driver.
# Add `device_repository: { enabled: false }` to opt out. The expanded form is:
# device_repository:
# enabled: true
# refresh_interval_h: 24
# repositories:
# - id: ftw-official
# name: FTW device drivers
# format: ftw.manifest/v1
# manifest_url: https://github.com/srcfl/device-drivers/releases/download/drivers-stable/manifest.json
# enabled: true
# trusted_keys:
# ftw-drivers-2026-01: MX+j27UBkyM099hTyJlmMLK9qlTTDUJsaK/vH12fFKc=
# Test the public beta channel on one site before stable promotion:
# device_repository:
# enabled: true
# refresh_interval_h: 24
# repositories:
# - id: ftw-device-drivers-beta
# name: FTW device drivers beta
# format: ftw.manifest/v1
# manifest_url: https://github.com/srcfl/device-drivers/releases/download/drivers-beta/manifest.json
# enabled: true
# trusted_keys:
# ftw-drivers-2026-01: MX+j27UBkyM099hTyJlmMLK9qlTTDUJsaK/vH12fFKc=
# Refresh only updates the signed catalog. Install and activation stay explicit.
# Mathematical MPC optimizer. Official Compose runs it as the independently
# updatable ftw-optimizer service; native installs can point optimizer_command
# at their venv's Python executable.
# planner:
# enabled: true
# engine: python
# mode: passive_arbitrage
# horizon_hours: 48
# interval_min: 15
# soc_min_pct: 10
# soc_max_pct: 95
# optimizer_solver: HIGHS
# optimizer_formulation: auto
# optimizer_transport: process # process | auto | unix; official Compose sets unix
# optimizer_socket: /run/ftw-optimizer/optimizer.sock
# optimizer_timeout_s: 30
# optimizer_idle_timeout_s: 120 # release Python/CVXPY memory between planning bursts
# optimizer_mip_rel_gap: 0.005
# optimizer_cvar_weight: 0.15
# optimizer_cvar_alpha: 0.90
# optimizer_recourse_shadow: false # diagnostic only; never controls dispatch
# optimizer_recourse_non_anticipative_slots: 1
# optimizer_challenger_policy: multistage # recourse | multistage
# optimizer_multistage:
# scenario_limit: 12
# branch_interval_slots: 4
# branch_horizon_slots: 48
# max_branching: 2
# near_horizon_slots: 16
# mid_horizon_slots: 96
# mid_block_slots: 2
# far_block_slots: 4
# service_cvar_weight: 1.0
# service_cvar_alpha: 0.95
# economic_cvar_weight: 0
# economic_cvar_alpha: 0.90
# decomposition_threshold: 20
# decomposition_method: auto # auto | extensive | progressive_hedging
# ph_max_iterations: 8
# ph_rho: 50
# ph_tolerance_w: 5