Repository navigation
Conversation
…4.1) A tester's trace (srcfl/ftw#1763, 23 Oct 2026) showed FTW ordering 15 A and the charger reading back 15 A, while Easee's circuit allocation (observations 70-72) and the current it signalled to the car (114) fell to 12, 14 and 13 A. FTW said "Not following". Read 70-72 and 114. Emit current_limit_a, the signalled current, while the car charges and it is more than half an amp below the order the charger holds (48), and only when it answers that order: recorded at or after it, or unchanged for 30 s since. Emit current_limited_by = "load_balancer" only when the allocation is below the order too and no higher than the signalled current. ReasonForNoCurrent is not used as a cause. Reason labels follow Easee's table (from #172). Port the REST ordering check from #183: while a car is connected, a reply whose power time goes back, conflicts at one instant or cannot be read is not used. Times compare as instants across offsets. The order starts again on disconnect or after 30 s of replies that go back, so a stamp from the future cannot hold the driver silent. Co-authored-by: Segran <goran@andersson-stehag.se> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Fredrik Ahlgren <fredrik@sourceful-labs.com>
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 3e0af590a2
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| end | ||
| -- A three-phase car gets the lowest phase's share. A one-phase car | ||
| -- uses one phase, which the driver does not know, so the highest. | ||
| local allocated_a = (phases == 1) and high or (n == 3 and low or nil) |
There was a problem hiding this comment.
Require complete phase allocations before attributing a one-phase limit
For a one-phase charger, if any phase allocation is missing or rejected by answering() because its timestamp predates the order, high only covers the remaining phases. Since the driver does not know which phase the car uses, that partial maximum cannot establish that its allocation explains the pilot limit. For example, with a 15 A order, a 12 A pilot, and only L1's 10 A allocation accepted, this emits current_limited_by = "load_balancer" even though the car could use L2 with a 15 A allocation and be limited for another reason. Require all three allocations before using their maximum, or identify the active phase; otherwise leave the cause nil.
Useful? React with 👍 / 👎.
- An unreadable power time no longer silences the driver for good: after 30 s of such replies they are used as they come, as before, until a readable time arrives. - A late "disconnected" reply is held to the same order as any other. - A failed poll ends a run of held-back replies, so a rejection before an outage does not count toward the 30 s. - A held-back reply does not drop the session proof, which cost one of Easee's ten session checks an hour each time. - Report a limit only while the charger reads back FTW's last order; do not name the load balancer when the charger's own static limit explains the pilot; a phase with no allocation is not one in use. - Tests for each, all failing on the previous commit, plus the one-phase highest-allocation rule, a finished car, a pilot recorded in the same second as the order, and an impossible first date. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Fredrik Ahlgren <fredrik@sourceful-labs.com>
- A failed poll no longer restarts the 30 s count; a gap of more than 30 s between held-back replies does. Occasional HTTP errors among unreadable replies kept the driver silent. - Skip dropping the session proof only on a poll whose reply was held back, not whenever the count is running. - A one-phase charger with no allocation on any phase does not name the load balancer. - Tests: both cases, and no limit before FTW's first order. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Fredrik Ahlgren <fredrik@sourceful-labs.com>
When Easee lets the car take the order again, the car needs a few seconds to draw it and the cloud to report that. Core then saw no limit and a car still below the order, and said "Not following" until the new draw arrived. Keep the last limit for up to 20 s while the car charges below the order. Test fails without it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Fredrik Ahlgren <fredrik@sourceful-labs.com>
Problem
Göran (@segran2) traced an Easee Home on 23 October 2026 with every FTW driver POST logged (srcfl/ftw#1763). FTW ordered 15 A and the charger read back 15 A (observation 48). Easee's circuit allocation (observations 70–72) and the current it signalled to the car (114, the pilot) were 12 A at the start, then 14 A and 13 A while the home battery charged. The car took 8.2–8.9 kW instead of 10.4 kW. FTW sent no lower order, yet it said "Not following". ReasonForNoCurrent (96) read 77, "limited by charger max current", with a time older than the cuts.
Change
easee_cloud 1.4.0 → 1.4.1. This takes the work in #172 and #183 onto 1.4.0 and its SignalR stream (#192).
current_limit_a: the signalled current, while the car charges, the charger reads back FTW's last order (48 equals the last write), and the signalled current is more than half an amp below it. A value counts only when it answers that order: Easee recorded it at or after the order, or the order has stood 30 s. Easee records a value when it changes, so an unchanged pilot keeps an older time.current_limited_by = "load_balancer"only when the allocation is below the order too and no higher than the signalled current, so it explains the limit, and the charger's own static limit (device_limit_a) does not. A three-phase charger uses the lowest allocation of the phases in use (a phase with none is not in use); a one-phase charger the highest, since the driver does not know its phase, and never an allocation of 0. Otherwise the cause stays nil.spec/host-api-profile.jsonand to the control feedback section ofdocs/WRITING-A-DRIVER.md. Add Easee's enumeration page toupstream_docs.Tests
Each new test failed on
mainfirst:test_easee_cloud_allocated_limit.lua(new): Göran's trace at 12, 15, 14 and 13 A; a limit without a shown cause (allocation at the order, missing, above the pilot, old reason 29, reason 77); lowest and highest phase; at or within half an amp of the order, not charging, zero pilot, no readback of the order; an older pilot right after a raise, counted at 30 s and not at 29 s, and a pilot recorded after the order counted at once; pushed allocation and pilot on the stream. Onmain:start at 12 A: got nil/nil, want 12/load_balancer.test_easee_cloud_observation_order.lua: fix(easee_cloud): reject out-of-order power observations #183's cases unchanged, then the additions: an impossible first date, unreadable times used after 30 s, a late disconnected reply, a disconnect restarting the order, a good reply or a failed poll ending a run, and held-back replies costing no session check. Onmain:older cloud zero replaced a newer power observation. The additions fail on 3e0af59, before the review fixes.test_easee_cloud_start_boost.luacases 18–19 and the stamped session fixtures (from fix(easee_cloud): reject out-of-order power observations #183). Onmain:invalid first observation enabled boost.test_easee_cloud_allocated_limit.luaalso covers, after the review: a readback still at the old order, the charger's own 10 A limit, unused phases, a one-phase charger whose phase is unknown, a finished car and a pilot recorded in the same second as the order.make test-driver ID=easee_cloud: 43 passed, 15 skipped.make check: 4991 passed, 936 skipped.Not yet run against Easee's servers or on hardware. Göran's trace is the evidence for 70–72 and 114; the 30 s settle time and the half-amp margin are judgement.
Pairing
srcfl/ftw#1537 reads
current_limit_aandcurrent_limited_byand says "Easee limits the charger to 12 A (its load balancing)". After this merges, a separate FTW PR movesdrivers/BUNDLED_SOURCE.jsonto the merge commit. #172 and #183 can close once this lands; I have not closed them.Co-authored-by: Segran goran@andersson-stehag.se
🤖 Generated with Claude Code