Skip to content

Fix Work Mode select/switch bit conflicts; rename discharge slots - #31

Merged
fboundy merged 1 commit into
mainfrom
patch
Jul 4, 2026
Merged

fboundy merged 1 commit into
mainfrom
patch

Conversation

@fboundy

@fboundy fboundy commented Jul 4, 2026

Copy link
Copy Markdown
Owner

Summary

Fixes the reported "Mode - Timed Charge bounces off" interaction between the mode switches and the Work Mode select, plus the mislabelled discharge entities.

Work Mode select (register 43110) — the option definitions were internally broken:

  • Every option listed its own bit in conflicts_with (clear bit 0, then immediately re-set it).
  • No plain mode cleared the TOU bit (1), so selecting "Self-Use" while in "Self-Use + TOU" computed new == current, wrote nothing, and the select could never turn TOU off.
  • Cross-mode transitions left stale mode bits set, producing multi-mode combos the firmware rejects/normalises — the next poll publishes the firmware's corrected value and the control visibly bounces off.

Each option now clears exactly the incompatible other mode bits per the official Appendix 8 map; "+ TOU" variants keep bit 1 via requires.

Mode - Timed Charge switch (bit 1) — had no conflicts_with. Toggling it from Off-Grid (2) or Peak Shaving (11) force-sets the fallback Self-Use bit, which those modes forbid → firmware rejects → bounce. Now conflicts_with [2, 11].

Select state push — async_select_option's bit-position branch never pushed entity state after a write (the on_value branch did); fixed.

Discharge renames — the six discharge slots were labelled "Timed Charge … 7-12"; now "Timed Discharge … 1-6" (enable switches on 43707 bits 6-11, start/end times, SOC/current/voltage numbers). Names only — unique_ids are register/bit-derived, so no registry migration and the sensor-drift suite passes unchanged.

Test plan

  • tests/test_solis_select_entity.py: parametrised round-trip — every Work Mode option applied from six different starting mode states must resolve back to itself; plain modes clear TOU
  • tests/test_switch_conflicts_requires.py: toggling Timed Charge from Peak Shaving (real definitions) writes Self-Use+TOU with bit 11 cleared
  • tests/test_ac_coupling.py: discharge name assertions
  • Full suite: 347 passed
  • ruff check / ruff format --check clean

Live verification on the real inverter to follow (restart HA, confirm Timed Charge stays on, then timed charge/discharge tests on both protocols).

The Work Mode select options each conflicted with their own bit, never
cleared the Timed Charge bit, and left stale mode bits from the
previous mode - so plain modes couldn't turn TOU off and cross-mode
transitions could write invalid combos the firmware rejects, which
reads back as controls bouncing off on the next poll. Each option now
clears exactly the other mode bits it is incompatible with per the
official Appendix 8 map.

Mode - Timed Charge gains conflicts_with [2, 11]: toggling it from
Off-Grid or Peak Shaving force-sets the fallback Self-Use bit, which
those modes forbid - the firmware rejected the combo and the switch
bounced off.

The select's bit-position branch now pushes its state after a write
(the on_value branch already did).

Also renames the six discharge slots that were mislabelled as
"Timed Charge ... 7-12" to "Timed Discharge ... 1-6" (enable switches,
start/end times, SOC/current/voltage numbers). Names only; unique_ids
are register-derived so nothing migrates.
@github-actions

github-actions Bot commented Jul 4, 2026

Copy link
Copy Markdown
Contributor

Failed to generate code suggestions for PR

@fboundy
fboundy merged commit ebc29c2 into main Jul 4, 2026
6 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant