Summary
teslemetry.py never sends optimization_strategy when it pushes the ToU tariff, so the Powerwall's Time-Based Control stays in Balanced mode. In Balanced, TBC discharges only to offset house load and never exports stored energy to the grid — no matter how high the synthetic ON_PEAK sell price in the boost window is.
Net effect: Predbat reports Exporting, every device command succeeds, and the battery exports nothing. Planned exports have never executed on this site.
The defect
set_tariff (teslemetry.py, ~line 1155):
return await self._apply_command(
"tariff",
signature,
lambda: self._command("time_of_use_settings", {"tou_settings": {"tariff_content_v2": tariff}}),
force=force,
)
The Fleet API tou_settings object accepts optimization_strategy: economics | balanced. We set the tariff but never set the dial that decides whether the Powerwall acts on it commercially. Whatever the customer's Tesla app happens to hold, stands.
Per Tesla's own description of Balanced: "once peak rates kick in, the Powerwall will start discharging to offset what your house is consuming." Offset load — not export. economics ("Cost Saving") is the strategy that will export for price.
Evidence
Real site, Powerwall 2 (13.5 kWh), Intelligent Octopus Go import (6.9p / 28.56p), Octopus Outgoing Fixed export (flat 12p).
1. The control path is correct. Entering an export window, all four commands landed successfully:
22:05:41 POST grid_import_export 200 -> battery_ok, grid charging off
22:05:41 POST operation 200 Code 200 -> autonomous
21:53:36 POST time_of_use_settings 200 Code 201 -> boosted tariff
(backup reserve deduped, device already at 4%)
22:05:58 record_status Exporting target 56%-4%
2. The tariff itself is correct. Rebuilt locally with the site's real rates — the boost lands exactly on the window, on the right day-of-week:
=== SELL side === rates: {"SUPER_OFF_PEAK": 0.12, "ON_PEAK": 0.58}
SUPER_OFF_PEAK day 3-3 00:00 -> 07:25
ON_PEAK day 3-3 07:25 -> 09:30
SUPER_OFF_PEAK day 3-3 09:30 -> 00:00
=== BUY side === rates: {"SUPER_OFF_PEAK": 0.07, "OFF_PEAK": 0.29, "ON_PEAK": 0.58}
ON_PEAK day 3-3 07:25 -> 09:30
3. The Powerwall just load-follows. Through the whole 80-minute Exporting target 56%->4% window, battery_power tracked load_power to the watt and grid stayed at zero:
22:41:54 soc=53.6% batt= 440 solar=0 load= 440 grid= 0
22:45:55 soc=53.2% batt= 500 solar=0 load= 500 grid= 0
22:51:57 soc=52.8% batt= 570 solar=0 load= 570 grid= 0
23:12:04 soc=51.4% batt= 2140 solar=0 load= 2140 grid= 0
23:24:08 soc=50.4% batt= 500 solar=0 load= 500 grid= 0
SoC drifted 53.6% -> 50.0% on house load alone, against a 4% target.
4. Charging works instantly, which rules out a broken command channel. The moment the plan flipped to Charging at 23:26, the next sample obeyed:
23:28:09 soc=50.0% batt=-3640 load= 658 grid= 4298
5. Same story with a full battery. A second window (07:25-09:30, armed at 08:59:56) held battery_power at exactly 0 W for all 30 minutes while 5-7 kW of solar exported freely:
09:01:22 soc=100.0% batt=0 solar=5614 load=327 grid=-5287
09:15:27 soc=100.0% batt=0 solar=5739 load=250 grid=-5489
09:29:31 soc=100.0% batt=0 solar=6981 load=336 grid=-6645
Suggested fix
{"tou_settings": {"optimization_strategy": "economics", "tariff_content_v2": tariff}}
Notes for whoever picks this up:
- Include the strategy in the
_apply_command dedupe signature so changing it forces a re-push.
- Worth asserting on every tariff push rather than once at boot — the customer's Tesla app can set it back to Balanced at any time, and there is no read endpoint to detect that drift (
site_info does not expose optimization_strategy).
- Probably belongs behind the same read-only gate as the rest of
sync_tariff.
Secondary issue (separate, lower priority)
Tesla clamps buy up to sell when buy < sell at any given time. On a flat-export tariff this bites overnight: buy SUPER_OFF_PEAK 0.07 vs sell 0.12, so the Powerwall models cheap IOG import as 12p and its own charge decisions are distorted. Not the cause of the export failure, but worth a look once export works.
Caveat
optimization_strategy is not exposed on any read endpoint, so the current device value could not be read back directly. The diagnosis rests on the field never being sent plus the behavioural signature (battery == load, grid == 0) matching documented Balanced behaviour exactly. Setting economics and observing a window is the confirming test.
Environment
- Predbat v8.48.8
- Tesla Backup Gateway 2 + 1x Powerwall 2, firmware 26.18.3
- Teslemetry API,
teslemetry_automatic (TESLA inverter type)
- Not a regression — this site ran Read-Only until recently, so the component's export path had never actually been exercised.
Summary
teslemetry.pynever sendsoptimization_strategywhen it pushes the ToU tariff, so the Powerwall's Time-Based Control stays in Balanced mode. In Balanced, TBC discharges only to offset house load and never exports stored energy to the grid — no matter how high the syntheticON_PEAKsell price in the boost window is.Net effect: Predbat reports
Exporting, every device command succeeds, and the battery exports nothing. Planned exports have never executed on this site.The defect
set_tariff(teslemetry.py, ~line 1155):The Fleet API
tou_settingsobject acceptsoptimization_strategy: economics | balanced. We set the tariff but never set the dial that decides whether the Powerwall acts on it commercially. Whatever the customer's Tesla app happens to hold, stands.Per Tesla's own description of Balanced: "once peak rates kick in, the Powerwall will start discharging to offset what your house is consuming." Offset load — not export.
economics("Cost Saving") is the strategy that will export for price.Evidence
Real site, Powerwall 2 (13.5 kWh), Intelligent Octopus Go import (6.9p / 28.56p), Octopus Outgoing Fixed export (flat 12p).
1. The control path is correct. Entering an export window, all four commands landed successfully:
2. The tariff itself is correct. Rebuilt locally with the site's real rates — the boost lands exactly on the window, on the right day-of-week:
3. The Powerwall just load-follows. Through the whole 80-minute
Exporting target 56%->4%window,battery_powertrackedload_powerto the watt and grid stayed at zero:SoC drifted 53.6% -> 50.0% on house load alone, against a 4% target.
4. Charging works instantly, which rules out a broken command channel. The moment the plan flipped to Charging at 23:26, the next sample obeyed:
5. Same story with a full battery. A second window (07:25-09:30, armed at 08:59:56) held
battery_powerat exactly 0 W for all 30 minutes while 5-7 kW of solar exported freely:Suggested fix
{"tou_settings": {"optimization_strategy": "economics", "tariff_content_v2": tariff}}Notes for whoever picks this up:
_apply_commanddedupe signature so changing it forces a re-push.site_infodoes not exposeoptimization_strategy).sync_tariff.Secondary issue (separate, lower priority)
Tesla clamps buy up to sell when buy < sell at any given time. On a flat-export tariff this bites overnight: buy
SUPER_OFF_PEAK0.07 vs sell 0.12, so the Powerwall models cheap IOG import as 12p and its own charge decisions are distorted. Not the cause of the export failure, but worth a look once export works.Caveat
optimization_strategyis not exposed on any read endpoint, so the current device value could not be read back directly. The diagnosis rests on the field never being sent plus the behavioural signature (battery == load, grid == 0) matching documented Balanced behaviour exactly. Settingeconomicsand observing a window is the confirming test.Environment
teslemetry_automatic(TESLA inverter type)