Skip to content

Fox Cloud: support Feed-in First (freeze export) via the work-mode setting #5022

Closed

Description

@chalfontchubby

(Claude wrote this issue, posted under my account.)

Split out of #5015, which turned off support_feedin_first for FoxCloud because the Cloud path never selects the mode. This issue tracks actually adding it.

Background

The Fox hardware does have a Feed-in First work mode, and Predbat already uses it on the modbus path: templates/fox.yaml ships a discharge_freeze_service stanza that selects "Feed-in First" on select.foxess_work_mode, published by the FoxESS HA integration.

The Cloud path has no equivalent. templates/fox_cloud.yaml contains no *_service stanzas at all, so during a freeze export slot adjust_export_immediate(..., freeze=True) calls call_service_template("discharge_freeze_service", ...), finds nothing configured, falls back to discharge_stop_service (also unset), and the freeze becomes a no-op. The inverter stays in Self Use.

Same hardware, different control surface.

What makes this look implementable

The Cloud component already publishes a writable work-mode select:

  • automatic_config wires inverter_mode to select.{prefix}_fox_{device}_setting_workmode (fox.py:2221)
  • that entity carries enumList: OPTIONS_WORK_MODE, which includes "Feedin" (fox.py:44, fox.py:57)
  • writes route select_event → write_setting_from_event → set_device_setting, a real Fox API write (fox.py:1994-2005)

So a discharge_freeze_service stanza in fox_cloud.yaml pointing at that select is plausibly most of the work — structurally the same as the modbus template, just a different entity id.

The catch

adjust_inverter_mode writes to that same inverter_mode entity and hardcodes SelfUse for any has_fox_inverter_mode inverter:

if self.inv_has_fox_inverter_mode:
    # For fox we only use selfuse as the rest is done by schedule
    new_inverter_mode = "SelfUse"

(inverter.py:2443-2444, added in #2659, Sept 2025.)

A service call setting Feedin would be reverted to SelfUse on the next cycle — the two would fight. So the template stanza alone is not sufficient; the hardcode needs to learn that freeze export is a legitimate third state. That comment's premise ("the rest is done by schedule") holds for Cloud but not for modbus, which is why one brand-named flag spanning both control paths leaves this gap.

Also worth checking whether the scheduler writer (apply_battery_schedule, which rewrites the schedule each cycle and only emits ForceCharge/ForceDischarge) would interfere.

Caveats

  • The Fox Cloud integration - Freeze Export planned but has no effect #5015 reporter notes that ~200W still flows into the battery even under Feed-in Priority on their inverter, so this will not be an exact SoC hold even when working.
  • write_setting_from_event only writes when the value actually changed, so ordering between the service call and adjust_inverter_mode matters.
  • Needs validation on real Fox Cloud hardware — the enum lists say Feedin is accepted, but that is not proof the API takes it in this context.

Once this works, support_feedin_first can go back to True for FoxCloud in config.py.

Related

Activity

  1. springfall2008 commented on Sep 9, 2026

    @springfall2008
    Owner

    Automated first-pass triage — a maintainer will review before any action is taken.

    Classification: enhancement (labels enhancement/fox already applied — no change).

    Investigation against main (d48cb223, v8.55.1-9-gd48cb223) — every code pointer in the issue verifies:

    • templates/fox.yaml does ship discharge_freeze_service selecting "Feed-in First" on select.foxess_work_mode; templates/fox_cloud.yaml has no *_service stanzas at all, so the Cloud freeze falls through call_service_template and no-ops.
    • OPTIONS_WORK_MODE includes Feedin (fox.py:44) and automatic_config wires inverter_mode to select.{prefix}_fox_{device}_setting_workmode (fox.py:2221), with writes routed select_event → write_setting_from_event → set_device_setting and a write-only-on-change guard (fox.py:~1995) — so the proposed template stanza is indeed structurally the same as the modbus one.
    • The adjust_inverter_mode hardcode is real and live: if self.inv_has_fox_inverter_mode: new_inverter_mode = "SelfUse" (inverter.py:2442-2444) — a Feedin write would be reverted on the next execute cycle, so the template stanza alone is not sufficient, as the issue states.
    • The freeze fallback chain confirmed at inverter.py:3049-3055: explicit freeze=True → discharge_freeze_service, falling back to discharge_stop_service; with neither configured for FoxCloud neither fires and the inverter stays in Self Use. This is exactly the Fox Cloud integration - Freeze Export planned but has no effect #5015 symptom.

    One correction: the issue states #5015 "turned off" support_feedin_first for FoxCloud. It did not — no commit has. support_feedin_first: True has been set for FoxESS and FoxCloud since commit 3ed9151e (24 Aug, the #4207 modelling change), and #5015 itself is still open. That state is the sharper version of the problem: the flag being True means prediction.py's freeze branch models PV recapture as charging the battery, while the Cloud execute path still cannot select Feed-in — so the plan shows a working freeze that execution never delivers. The enhancement remains as described; only the flag premise is backwards.

    No regression test was run — this is a feature request, not a behavioural claim against an existing test module. The implementation questions it raises (ordering vs adjust_inverter_mode, and whether apply_battery_schedule re-emitting ForceCharge/ForceDischarge fights the mode write) are for the PR that implements this and will need real-hardware validation, as the issue already flags.

  2. chalfontchubby commented on Sep 10, 2026

    @chalfontchubby
    CollaboratorAuthor

    5015 can close then if you are happy

  3. added a commit that references this issue on Sep 10, 2026
    0488339
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    BOT_TRIAGEDHas been through the triage botenhancementNew feature or requestfox

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions