Skip to content

Make the remedy work, and stop blocking weekly schedules - #278

Merged
CharlesGillanders merged 4 commits into
CharlesGillanders:mainfrom
Poshy163:fix/unblock-b4-writes
Sep 4, 2026
Merged

CharlesGillanders merged 4 commits into
CharlesGillanders:mainfrom
Poshy163:fix/unblock-b4-writes

Conversation

@Poshy163

@Poshy163 Poshy163 commented Aug 25, 2026 •

Copy link
Copy Markdown
Collaborator

Fixes the schedule-control path behind #267 without treating AlphaESS's write-only enable flags as an inverter working-mode endpoint.

What changed

  • Scheduled Charging and Scheduled Discharging remain ordinary staged edits. Apply sends the complete pair atomically; Discard removes them.
  • Confirmed enable intent is persisted separately from the displayed draft, so restarting Home Assistant cannot promote an unapplied switch change.
  • Duration buttons and immediate services use only their own arguments plus the last confirmed pair. They cannot consume unrelated staged values, and a successful immediate write rebases untouched draft fields.
  • Removed the inferred Time Based Control lockout. OpenAPI does not expose the app-selected working mode, so a recorded 0/0 pair no longer disables schedule controls.
  • Renamed the diagnostic to Recorded Schedule Flags Enabled, while preserving its existing unique ID so the entity is renamed in place.
  • A periodic POST rejected with 6017 keeps the last readable schedule for diagnostics and Discard, while correctly disabling further writes.
  • A new period in a weekly schedule inherits the weekdays of its existing sibling. With no sibling to copy, the write is still refused.
  • Power controls now accept whole-watt values such as 14000 W instead of forcing 14001 W.
  • Diagnostics separate an atomic completed-poll schedule snapshot from the current schedule_live draft/apply state.
  • Currency symbols are normalized consistently; ambiguous symbols prefer Home Assistant's configured currency.

The periodic Reset button remains unavailable because AlphaESS rejects a replacement with empty charge/discharge period lists.

Three blockers from a b4 diagnostics download on CharlesGillanders#267, all of which the new
schedule section made visible at once: enable_intent null, a switch staged, no
write ever attempted, and a weekly schedule underneath.

The remedy could not be carried out. Every refused write said to set the two
switches, but moving a switch only staged it, and the record the write consults
was written on a successful write - which could not happen. Worse, the staged
flag made the mode indicator read active, so the switch took the staging path
rather than the immediate one, and the loop closed. Staging a flag now records
it: it is the user's answer either way, and it is a local record rather than a
call. Discard puts the previous answer back, so it is still an edit like any
other.

Adding a period to a weekly schedule was refused outright on the grounds that
the two-slot entities cannot choose weekdays. The newer app writes "every day"
as a weekly schedule covering all seven, so that refusal blocks most systems on
the new backend. A new period now runs on the same days as the period it is
added alongside, which is visible in the app and changeable there; with no
sibling to copy, it is still refused.

The power boxes had a minimum of 1 and a step of 100, so they only accepted
1, 101, 201 and so on - which is why a user asking for 14000 W sent 14001. The
step is now 1. The minimum stays 1: a 1 W period is a documented way to force
grid-charge mode.
AlphaESS has started answering moneyType with the symbol rather than an ISO
code - "€" where it used to send "EUR". Home Assistant's monetary device class
only accepts a code, so the symbol had to be resolved before it reached a unit.

The mapping already existed in the sensor platform, so the monetary units were
never wrong, but two things around it were. The Currency Code sensor reports
whatever the API sent, so it now reads "€" - a symbol, from a sensor named for
a code, and the same value goes into the diagnostics download. The parser now
resolves it once, so both report a code.

The other is a symbol that names more than one currency. "$" resolved to USD
whatever the owner's currency, which is wrong for every AUD, NZD and CAD system
- a good share of them - and "¥" resolved to JPY for a Chinese one. An
ambiguous symbol now resolves to the currency Home Assistant is configured for
when that is one of the candidates, and to the most common otherwise. An
unrecognised value still falls back rather than being guessed at.

The mapping moves to its own module so the parser and the sensor platform share
one answer, and it gains 元 and Kč on the way through.
@Poshy163
Poshy163 marked this pull request as ready for review September 4, 2026 10:22
Two things a UK/EU report on CharlesGillanders#267 still could not do from Home Assistant.

The first is show what the API actually returned. The diagnostics download
carries the parsed entity view, so every question that needed a response body
ended with a tester signing requests by hand. The single API gate now keeps
the last answer from every endpoint per system - the request it answered, or
the return code or exception it failed with - and a new export_raw_snapshot
action hands them over as a response, together with the parsed data, the
schedule state and the coordinator's pacing. Nothing is requested from
AlphaESS. Serials are replaced by inverter_N / ev_charger_N wherever they
appear, inside response bodies and entity IDs alike, with the same numbering
as the diagnostics download; credentials, the register key, wifi details and
the dongle serial are redacted by key, and bind/unbind calls never have their
arguments retained. The local dongle read bypasses the gate, so each of its
three call sites records itself.

The second is write anything on a fresh install. Those systems read
gridChargeCycle/ctrDisCycle back as 0/0 whatever the app shows, so Home
Assistant has no record of the pair until both switches have been applied
once, and until then every one-sided write - a service call from an
automation, a duration button - is refused. That refusal is right by default:
sending a guess would choose the inverter's working mode. It is now a choice.
An option in the integration's settings, off by default, sends 1 for any flag
Home Assistant has no record of. It never overrides a switch or a service's
own value, the pair is recorded as soon as AlphaESS accepts the write, and the
log says when the assumption was used. The refusal names the option.

README documents both, along with two things the thread established that it
did not say: a discharge window does not force export, and a 200 on the write
is not a read-back confirmation.
@Poshy163

Poshy163 commented Sep 4, 2026

Copy link
Copy Markdown
Collaborator Author

@CharlesGillanders bump, going to use this as another beta

@CharlesGillanders
CharlesGillanders self-requested a review September 4, 2026 15:24
@CharlesGillanders
CharlesGillanders merged commit d0494ff into CharlesGillanders:main Sep 4, 2026
3 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.

2 participants