EV-03: car charger seam + Alfen HA driver, Settings group, read-only Car card, car out of the house profile, two-writer detector.
Read only. Nothing in this change writes to the charger (test_ev03.py part 1 proves it and greps for callers of the write methods). Default ev_charger: off changes nothing (part 3).
Options ev_charger, ev_current_entity, ev_max_a, ev_phases: schema, defaults, translations EN/NL, Settings group "Car charger", Simple view, validator, SAFETY-28 census, live station-limit check, read-only probe (/config/charger and the notes on the settings page)
Car card on Home, unreachable row and one notification after 5 minutes, two-writer info row, MQTT sensors goodwe_car_power, goodwe_car_state, goodwe_car_today_kwh
House tile and house profile exclude the car; a car reading older than stale_input_s leaves House with no figure and the profile sample out
tools/chargersim.py charger model and fake HA; DOCS "Car charger"; CHANGELOG line
Deviations are listed in reports/EV-03-dev-report.md.
EV-03: car charger seam + Alfen HA driver, Settings group, read-only Car card, car out of the house profile, two-writer detector.
Read only. Nothing in this change writes to the charger (test_ev03.py part 1 proves it and greps for callers of the write methods). Default `ev_charger: off` changes nothing (part 3).
- `app/chargers.py`: `ChargerDriver`, `AlfenHaDriver`, `UnavailableCharger`, `ChargerReading`, `CarTracker`
- Options `ev_charger`, `ev_current_entity`, `ev_max_a`, `ev_phases`: schema, defaults, translations EN/NL, Settings group "Car charger", Simple view, validator, SAFETY-28 census, live station-limit check, read-only probe (`/config/charger` and the notes on the settings page)
- Car card on Home, unreachable row and one notification after 5 minutes, two-writer info row, MQTT sensors `goodwe_car_power`, `goodwe_car_state`, `goodwe_car_today_kwh`
- House tile and house profile exclude the car; a car reading older than `stale_input_s` leaves House with no figure and the profile sample out
- `tools/chargersim.py` charger model and fake HA; DOCS "Car charger"; CHANGELOG line
Deviations are listed in reports/EV-03-dev-report.md.
🤖 Generated with [Claude Code](https://claude.ai/code)
https://claude.ai/code/session_01Bdqr7PiaHcBnzPituu2yTC
Read-only: nothing in this change writes to the charger.
- app/chargers.py: ChargerDriver, AlfenHaDriver, UnavailableCharger, ChargerReading, CarTracker
- options ev_charger/ev_current_entity/ev_max_a/ev_phases (default off), Settings group, validator, census
- Car card on Home, unreachable row and notification, two-writer info row, MQTT sensors
- car out of the House tile and the house profile
- tools/chargersim.py charger model, test_ev03.py
Co-Authored-By: Claude <noreply@anthropic.com>
test_pv.py part 6 says only the PV reader's named modules may mention its
material, so chargers.py no longer imports pv.py.
Co-Authored-By: Claude <noreply@anthropic.com>
- CarTracker.car_w returns None when the current reading carries no power
(power entity unavailable or in a non-power unit); it can no longer raise
into the control cycle, /status or the MQTT values.
- mode3 E and F are the card state "fault" (EN and NL).
- chargersim gains fault().
Co-Authored-By: Claude <noreply@anthropic.com>
Review of EV-03 at 678ea13: not merged, one Medium finding goes back to the dev
Head reviewed: 678ea138952e14a4aeffdb8a9fd40d7ba4fd8e19 (base release/1.06bf3759). CI run 1673 checks / unit (pull_request) is green on this head.
Medium (behaviour, back to the dev)
M1. If the power entity is missing, the charger is accepted, but House and the house profile never get a reading again.
app/chargers.py:83: REQUIRED = ("current", "readback", "state"). If only the power entity is missing (for example, disabled in HA or reported in a unit other than W), the probe passes (ok=True) and the charger is used.
app/chargers.py:535: last_ok is set only when power_w is not None. So fresh() never becomes True, car_w() stays None, and car_term() returns (0.0, True) on every cycle (app/ctl_inputs.py:129).
Result: the House tile shows "No reading" for good (app/homeview.py:87), and every house-profile sample is None (app/ctl_trade.py:399). After PROFILE_DAYS (7 days) the profile is empty, estimator() returns None, and the batteries' night plan falls back to having no plan. Nothing on screen explains it: the card shows "Charging" with no figure, there is no amber row, and the Settings note for a missing power entity is only "info" (app/validate.py:2035).
Reproduced with SimCharger and the power entity removed: probe ok True, available True, status "charging", fresh False, car_w None, held over 30 cycles.
Fix (dev's choice): either add power to the entities whose absence refuses the charger (then the card says "Charger not set up", one amber row, and House and the profile behave as before), or show a row when the charger answers but has had no power reading for longer than stale_input_s. Either way, add a test: power missing means House and the profile are not starved without a word.
Low (the dev can fold these into the same round)
L1. app/ui_text/nl.json:90: help_off "De add-on laat de laadpaal ongemoeid." The design and this card's own Why lines (nl.json:264-265) say "met rust". Use one word for one thing.
L2. app/ui_text/nl.json:258: chip fault "Laadpaal storing" is not correct Dutch. Use "Laadpaalstoring" or "Laadpaal in storing".
Checks that passed
No charger writes: the write methods have no caller in app/ (my own grep and AST scan agree with the dev's). The only new service calls are persistent_notification create/dismiss. MQTT has sensors only, no command topics. /config/charger reads the cached entity list. The settings save only reads limits().
With the default off nothing changes: UnavailableCharger, no read in the gather, car_term = (0, False), the same House and profile sample, no rows, no car sensors (optional_keys), census entity "", validator []. Test part 3 covers this.
Census and validator: an inverter entity, including one in the inverter list, named as the charger is refused. A missing setpoint, read-back or state entity refuses the charger only. ev_max_a above the station limit is refused at save and at run time. The census clash refuses the add-on and the save, as SAFETY-28 does for two inverters on one entity. The design's "refuses the charger, not the add-on" is about entities that are not found. Accepted.
The rule for a stale car reading (15 s, then House "No reading" and the moment left out of the profile) is safe. HouseProfile.add(None) drops the moment. An hour still counts with 60 samples. Missing hours fall back to medians over other days or to the base. An outage of more than 7 days in a row ends in the existing no-profile fallback (no day plan), not in a wrong plan, and the amber row plus the notification make the outage visible. I know of no simpler rule that is also honest (a car may be charging while the charger is unreachable). Note M1 above, which leaves the reading stale forever.
Unreachable: the row comes at 30 s, the WARNING line on the change only, and one notification after 5 min that is dismissed on recovery, following the same pattern as check_price_gap.
Two-writer detector: it does not fire at start-up, on a meter tick, after a gap where the charger was unavailable, or when one read-back comes back empty. It fires when the setpoint or the read-back changes.
Today kWh: tested for a meter reset (counted from its new zero), the change of day (local Brussels date), a restart on the same day (kept), and a restart on the next day (back to 0).
Strings, EN and NL: the deviations ("Something else changes the charger", one-sentence notification body, Why lines split) follow STYLE.md. Apart from L1 and L2 the strings are fine.
Existing tests that were edited (test_translations, test_settings, test_selfconfig): each edit only adds the new group or route. None is weaker.
CI 1673 is green.
Verdict: changes requested (M1). Not merged.
## Review of EV-03 at 678ea13: not merged, one Medium finding goes back to the dev
Head reviewed: `678ea138952e14a4aeffdb8a9fd40d7ba4fd8e19` (base `release/1.0` 6bf3759). CI run 1673 `checks / unit (pull_request)` is green on this head.
### Medium (behaviour, back to the dev)
**M1. If the power entity is missing, the charger is accepted, but House and the house profile never get a reading again.**
- `app/chargers.py:83`: `REQUIRED = ("current", "readback", "state")`. If only the power entity is missing (for example, disabled in HA or reported in a unit other than W), the probe passes (`ok=True`) and the charger is used.
- `app/chargers.py:535`: `last_ok` is set only when `power_w` is not None. So `fresh()` never becomes True, `car_w()` stays None, and `car_term()` returns `(0.0, True)` on every cycle (`app/ctl_inputs.py:129`).
- Result: the House tile shows "No reading" for good (`app/homeview.py:87`), and every house-profile sample is None (`app/ctl_trade.py:399`). After `PROFILE_DAYS` (7 days) the profile is empty, `estimator()` returns None, and the batteries' night plan falls back to having no plan. Nothing on screen explains it: the card shows "Charging" with no figure, there is no amber row, and the Settings note for a missing power entity is only "info" (`app/validate.py:2035`).
- Reproduced with `SimCharger` and the power entity removed: probe ok True, available True, status "charging", fresh False, car_w None, held over 30 cycles.
- Fix (dev's choice): either add `power` to the entities whose absence refuses the charger (then the card says "Charger not set up", one amber row, and House and the profile behave as before), or show a row when the charger answers but has had no power reading for longer than `stale_input_s`. Either way, add a test: power missing means House and the profile are not starved without a word.
### Low (the dev can fold these into the same round)
- L1. `app/ui_text/nl.json:90`: `help_off` "De add-on laat de laadpaal ongemoeid." The design and this card's own Why lines (`nl.json:264-265`) say "met rust". Use one word for one thing.
- L2. `app/ui_text/nl.json:258`: chip `fault` "Laadpaal storing" is not correct Dutch. Use "Laadpaalstoring" or "Laadpaal in storing".
### Checks that passed
1. No charger writes: the write methods have no caller in `app/` (my own grep and AST scan agree with the dev's). The only new service calls are persistent_notification create/dismiss. MQTT has sensors only, no command topics. `/config/charger` reads the cached entity list. The settings save only reads `limits()`.
2. With the default `off` nothing changes: `UnavailableCharger`, no read in the gather, `car_term` = (0, False), the same House and profile sample, no rows, no car sensors (`optional_keys`), census entity "", validator `[]`. Test part 3 covers this.
3. Census and validator: an inverter entity, including one in the inverter list, named as the charger is refused. A missing setpoint, read-back or state entity refuses the charger only. `ev_max_a` above the station limit is refused at save and at run time. The census clash refuses the add-on and the save, as SAFETY-28 does for two inverters on one entity. The design's "refuses the charger, not the add-on" is about entities that are not found. Accepted.
4. The rule for a stale car reading (15 s, then House "No reading" and the moment left out of the profile) is safe. `HouseProfile.add(None)` drops the moment. An hour still counts with 60 samples. Missing hours fall back to medians over other days or to the base. An outage of more than 7 days in a row ends in the existing no-profile fallback (no day plan), not in a wrong plan, and the amber row plus the notification make the outage visible. I know of no simpler rule that is also honest (a car may be charging while the charger is unreachable). Note M1 above, which leaves the reading stale forever.
5. Unreachable: the row comes at 30 s, the WARNING line on the change only, and one notification after 5 min that is dismissed on recovery, following the same pattern as `check_price_gap`.
6. Two-writer detector: it does not fire at start-up, on a meter tick, after a gap where the charger was unavailable, or when one read-back comes back empty. It fires when the setpoint or the read-back changes.
7. Today kWh: tested for a meter reset (counted from its new zero), the change of day (local Brussels date), a restart on the same day (kept), and a restart on the next day (back to 0).
8. Strings, EN and NL: the deviations ("Something else changes the charger", one-sentence notification body, Why lines split) follow STYLE.md. Apart from L1 and L2 the strings are fine.
9. Existing tests that were edited (`test_translations`, `test_settings`, `test_selfconfig`): each edit only adds the new group or route. None is weaker.
10. CI 1673 is green.
Verdict: **changes requested** (M1). Not merged.
A charger with no usable power entity is refused as "not set up", like a
missing setpoint, read-back or state entity, so House and the house profile
behave as with no charger. An entity that is merely unavailable at probe time
is still the unreachable path. NL: help text "met rust", chip "Laadpaalstoring".
Co-Authored-By: Claude <noreply@anthropic.com>
Re-review round 3 at 918d44a: not merged, one Medium finding goes back to the dev
Head reviewed: 918d44ab336d7d08636d23cbcdf928cc2fdd2daf (base release/1.06bf3759, unchanged). CI run 1675 checks / unit (pull_request) is green on this head.
Medium (behaviour, back to the dev)
M2. The M1 hole is still open on one path: the power entity is unavailable when the probe runs, then comes back with a wrong unit.
The probe counts an unavailable power entity as found, which is right. Later, reading_from_states only checks that the power entity has some state (app/chargers.py:222). If it comes back as 12 V, or with no unit, the reading counts as available, but _watts returns None.
last_ok then never moves (chargers.py:552), and car_term() returns unknown for good. The House tile shows "No reading" for good, and every profile sample is None.
bad_since stays None, so there is no row and no notification. The card shows "Charging". This is the same silent, permanent state as M1.
The same happens when a user changes the power sensor's display unit in HA while the add-on runs: HA offers mW and MW for power, and these are no longer accepted.
Reproduced through the controller (my probe: power unavailable for 3 cycles, then 400 cycles):
unit V: refused None, available True, state charging, House None, sample None, no charger row.
no unit: the same.
never comes back: "Charger not reachable", amber row, notification. Visible, so fine.
back in W: House 6100, sample 5600. Fine.
Fix (dev's choice): a power entity that answers but cannot be believed should go down a visible path. Two simple options: count it as "gone" in reading_from_states, so after 30 s the unreachable path gives a row and a notification; or judge the unit on the first reading that is available and refuse the charger then, as the probe does. Add a test for "unavailable at probe, then V".
Low (fold into the same round)
L3. test_ev03.py:984: the round 2 check no longer asserts reading.available (res["avail"] is now only power_w is None). For the wrong-unit case, keep an explicit assert that the reading is available with no power, so the available-without-power path stays proven. The M2 fix will change exactly this path, so the test should say which behaviour it expects.
Checks
M1 is closed for a power entity that is missing or in the wrong unit when the probe runs: the charger is refused as "not set up", there is one amber row, and House and the profile sample equal the no-charger run (test part 11; I re-ran it in my own probe).
A power entity that is unavailable when the probe runs, then:
never comes back: the unreachable path is visible. OK.
comes back in a wrong unit, or with no unit: this is the silent hole, M2.
The changed round 2 test: the wrong-unit case still sends the code down the available-without-power path, but the assertion that it does was dropped (L3).
"Charger not set up" for a refused charger is a WARNING plus an amber row, not a refusal of the save. That is consistent with how the add-on already treats a missing required entity (accepted in round 1). Fine.
The rest of 678ea13..918d44a is sound: L1 ("met rust") and L2 ("Laadpaalstoring") are fixed, and the Settings notes are now warnings for required entities. Still no charger writes (grep: no caller of the write methods, and no new set_number or service call).
Verdict: changes requested (M2). Not merged.
## Re-review round 3 at 918d44a: not merged, one Medium finding goes back to the dev
Head reviewed: `918d44ab336d7d08636d23cbcdf928cc2fdd2daf` (base `release/1.0` 6bf3759, unchanged). CI run 1675 `checks / unit (pull_request)` is green on this head.
### Medium (behaviour, back to the dev)
**M2. The M1 hole is still open on one path: the power entity is unavailable when the probe runs, then comes back with a wrong unit.**
- The probe counts an unavailable power entity as found, which is right. Later, `reading_from_states` only checks that the power entity has some state (`app/chargers.py:222`). If it comes back as `12 V`, or with no unit, the reading counts as available, but `_watts` returns None.
- `last_ok` then never moves (`chargers.py:552`), and `car_term()` returns unknown for good. The House tile shows "No reading" for good, and every profile sample is None.
- `bad_since` stays None, so there is no row and no notification. The card shows "Charging". This is the same silent, permanent state as M1.
- The same happens when a user changes the power sensor's display unit in HA while the add-on runs: HA offers mW and MW for power, and these are no longer accepted.
- Reproduced through the controller (my probe: power unavailable for 3 cycles, then 400 cycles):
- unit V: refused None, available True, state charging, House None, sample None, no charger row.
- no unit: the same.
- never comes back: "Charger not reachable", amber row, notification. Visible, so fine.
- back in W: House 6100, sample 5600. Fine.
- Fix (dev's choice): a power entity that answers but cannot be believed should go down a visible path. Two simple options: count it as "gone" in `reading_from_states`, so after 30 s the unreachable path gives a row and a notification; or judge the unit on the first reading that is available and refuse the charger then, as the probe does. Add a test for "unavailable at probe, then V".
### Low (fold into the same round)
- L3. `test_ev03.py:984`: the round 2 check no longer asserts `reading.available` (`res["avail"]` is now only `power_w is None`). For the wrong-unit case, keep an explicit assert that the reading is available with no power, so the available-without-power path stays proven. The M2 fix will change exactly this path, so the test should say which behaviour it expects.
### Checks
1. M1 is closed for a power entity that is missing or in the wrong unit when the probe runs: the charger is refused as "not set up", there is one amber row, and House and the profile sample equal the no-charger run (test part 11; I re-ran it in my own probe).
2. A power entity that is unavailable when the probe runs, then:
- never comes back: the unreachable path is visible. OK.
- comes back in a wrong unit, or with no unit: this is the silent hole, **M2**.
3. The changed round 2 test: the wrong-unit case still sends the code down the available-without-power path, but the assertion that it does was dropped (**L3**).
4. "Charger not set up" for a refused charger is a WARNING plus an amber row, not a refusal of the save. That is consistent with how the add-on already treats a missing required entity (accepted in round 1). Fine.
5. The rest of 678ea13..918d44a is sound: L1 ("met rust") and L2 ("Laadpaalstoring") are fixed, and the Settings notes are now warnings for required entities. Still no charger writes (grep: no caller of the write methods, and no new `set_number` or service call).
Verdict: **changes requested** (M2). Not merged.
- every HA power unit is accepted and converted (mW, W, kW, MW), in the probe
and in the reading
- a power entity that answers in another unit, with no unit, or not as a
number makes the reading unavailable: after 30 s it is "Charger not
reachable" (amber row, WARNING, notification after 5 min), with a Why that
names the cause (EN and NL)
Co-Authored-By: Claude <noreply@anthropic.com>
POWER_UNITS is now derived from _W_PER, so the start-up probe and the
reading cannot drift apart. No behaviour change.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Re-review round 4 at af7e96e: right, merged after one Low fix
Head reviewed: af7e96e5e5f5d72c19d989c033ac0fa07243db2e, then my fix commit d7b42980927c31773bda65a926078906c1f82ebf (base release/1.06bf3759, unchanged). CI run 1677 is green on af7e96e.
Checks
M2 is closed. My probe2 (power entity unavailable for 3 cycles while the add-on starts, then 400 cycles in each case) now gives:
back in V, or back with no unit: the reading is unavailable, then "Charger not reachable" with the amber row and the notification, and the Why names the unit. Nothing is silent any more.
never comes back: the same visible path.
back in W: Charging, House 6100 W, profile sample 5600 W.
The dev's test part 12 also covers recovery, a unit changed from W to V while the add-on runs, and one notification after 5 min. No silent path is left. A reading now counts as available only when _watts() gives a number, so an available reading always moves last_ok. The only paths that leave the car's power unknown are unavailable readings: a read error, a 5 s timeout, a check of the entities at start-up that does not finish, or the login sensor off. All of them reach the unreachable row after 30 s. The one other gap is the first cycle before the first read.
The unit conversion is exact (mW 0.001, W 1, kW 1000, MW 1e6; tests use 6 900 000 mW, 0.0069 MW and 6.9 kW). The probe used its own POWER_UNITS tuple beside _W_PER: two lists with the same content. Fixed myself (Low) in d7b4298: POWER_UNITS = tuple(_W_PER), one table. No behaviour change. test_ev03, test_pv, test_messages, test_ui_text and test_defaults_pin pass locally.
L3 is fixed. The round 2 check now asserts the expected behaviour explicitly: the reading is unavailable, with cause "power unit" or "no answer from power". The seam checks for a missing or wrong unit now assert not available and the cause. The switch to named_absence.nth follows TEST-26. Nothing is weaker.
The rest of the diff is sound. The new Why strings are in EN and NL. Still no charger writes: the write methods have no caller in app/, and there is no new number write or service call.
Verdict: right. Merging into release/1.0, pinned to d7b4298 after CI run 1679 checks / unit (pull_request) went green on it.
## Re-review round 4 at af7e96e: right, merged after one Low fix
Head reviewed: `af7e96e5e5f5d72c19d989c033ac0fa07243db2e`, then my fix commit `d7b42980927c31773bda65a926078906c1f82ebf` (base `release/1.0` 6bf3759, unchanged). CI run 1677 is green on af7e96e.
### Checks
1. **M2 is closed.** My probe2 (power entity unavailable for 3 cycles while the add-on starts, then 400 cycles in each case) now gives:
- back in V, or back with no unit: the reading is unavailable, then "Charger not reachable" with the amber row and the notification, and the Why names the unit. Nothing is silent any more.
- never comes back: the same visible path.
- back in W: Charging, House 6100 W, profile sample 5600 W.
The dev's test part 12 also covers recovery, a unit changed from W to V while the add-on runs, and one notification after 5 min. No silent path is left. A reading now counts as available only when `_watts()` gives a number, so an available reading always moves `last_ok`. The only paths that leave the car's power unknown are unavailable readings: a read error, a 5 s timeout, a check of the entities at start-up that does not finish, or the login sensor off. All of them reach the unreachable row after 30 s. The one other gap is the first cycle before the first read.
2. **The unit conversion is exact** (mW 0.001, W 1, kW 1000, MW 1e6; tests use 6 900 000 mW, 0.0069 MW and 6.9 kW). The probe used its own `POWER_UNITS` tuple beside `_W_PER`: two lists with the same content. **Fixed myself (Low)** in d7b4298: `POWER_UNITS = tuple(_W_PER)`, one table. No behaviour change. test_ev03, test_pv, test_messages, test_ui_text and test_defaults_pin pass locally.
3. **L3 is fixed.** The round 2 check now asserts the expected behaviour explicitly: the reading is unavailable, with cause "power unit" or "no answer from power". The seam checks for a missing or wrong unit now assert `not available` and the cause. The switch to `named_absence.nth` follows TEST-26. Nothing is weaker.
4. **The rest of the diff is sound.** The new Why strings are in EN and NL. Still no charger writes: the write methods have no caller in `app/`, and there is no new number write or service call.
Verdict: **right**. Merging into `release/1.0`, pinned to d7b4298 after CI run 1679 `checks / unit (pull_request)` went green on it.
admin
merged commit 7513fd9439 into release/1.02026-11-15 16:32:51 +01:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
EV-03: car charger seam + Alfen HA driver, Settings group, read-only Car card, car out of the house profile, two-writer detector.
Read only. Nothing in this change writes to the charger (test_ev03.py part 1 proves it and greps for callers of the write methods). Default
ev_charger: offchanges nothing (part 3).app/chargers.py:ChargerDriver,AlfenHaDriver,UnavailableCharger,ChargerReading,CarTrackerev_charger,ev_current_entity,ev_max_a,ev_phases: schema, defaults, translations EN/NL, Settings group "Car charger", Simple view, validator, SAFETY-28 census, live station-limit check, read-only probe (/config/chargerand the notes on the settings page)goodwe_car_power,goodwe_car_state,goodwe_car_today_kwhstale_input_sleaves House with no figure and the profile sample outtools/chargersim.pycharger model and fake HA; DOCS "Car charger"; CHANGELOG lineDeviations are listed in reports/EV-03-dev-report.md.
🤖 Generated with Claude Code
https://claude.ai/code/session_01Bdqr7PiaHcBnzPituu2yTC
Review of EV-03 at
678ea13: not merged, one Medium finding goes back to the devHead reviewed:
678ea138952e14a4aeffdb8a9fd40d7ba4fd8e19(baserelease/1.06bf3759). CI run 1673checks / unit (pull_request)is green on this head.Medium (behaviour, back to the dev)
M1. If the power entity is missing, the charger is accepted, but House and the house profile never get a reading again.
app/chargers.py:83:REQUIRED = ("current", "readback", "state"). If only the power entity is missing (for example, disabled in HA or reported in a unit other than W), the probe passes (ok=True) and the charger is used.app/chargers.py:535:last_okis set only whenpower_wis not None. Sofresh()never becomes True,car_w()stays None, andcar_term()returns(0.0, True)on every cycle (app/ctl_inputs.py:129).app/homeview.py:87), and every house-profile sample is None (app/ctl_trade.py:399). AfterPROFILE_DAYS(7 days) the profile is empty,estimator()returns None, and the batteries' night plan falls back to having no plan. Nothing on screen explains it: the card shows "Charging" with no figure, there is no amber row, and the Settings note for a missing power entity is only "info" (app/validate.py:2035).SimChargerand the power entity removed: probe ok True, available True, status "charging", fresh False, car_w None, held over 30 cycles.powerto the entities whose absence refuses the charger (then the card says "Charger not set up", one amber row, and House and the profile behave as before), or show a row when the charger answers but has had no power reading for longer thanstale_input_s. Either way, add a test: power missing means House and the profile are not starved without a word.Low (the dev can fold these into the same round)
app/ui_text/nl.json:90:help_off"De add-on laat de laadpaal ongemoeid." The design and this card's own Why lines (nl.json:264-265) say "met rust". Use one word for one thing.app/ui_text/nl.json:258: chipfault"Laadpaal storing" is not correct Dutch. Use "Laadpaalstoring" or "Laadpaal in storing".Checks that passed
app/(my own grep and AST scan agree with the dev's). The only new service calls are persistent_notification create/dismiss. MQTT has sensors only, no command topics./config/chargerreads the cached entity list. The settings save only readslimits().offnothing changes:UnavailableCharger, no read in the gather,car_term= (0, False), the same House and profile sample, no rows, no car sensors (optional_keys), census entity "", validator[]. Test part 3 covers this.ev_max_aabove the station limit is refused at save and at run time. The census clash refuses the add-on and the save, as SAFETY-28 does for two inverters on one entity. The design's "refuses the charger, not the add-on" is about entities that are not found. Accepted.HouseProfile.add(None)drops the moment. An hour still counts with 60 samples. Missing hours fall back to medians over other days or to the base. An outage of more than 7 days in a row ends in the existing no-profile fallback (no day plan), not in a wrong plan, and the amber row plus the notification make the outage visible. I know of no simpler rule that is also honest (a car may be charging while the charger is unreachable). Note M1 above, which leaves the reading stale forever.check_price_gap.test_translations,test_settings,test_selfconfig): each edit only adds the new group or route. None is weaker.Verdict: changes requested (M1). Not merged.
Re-review round 3 at
918d44a: not merged, one Medium finding goes back to the devHead reviewed:
918d44ab336d7d08636d23cbcdf928cc2fdd2daf(baserelease/1.06bf3759, unchanged). CI run 1675checks / unit (pull_request)is green on this head.Medium (behaviour, back to the dev)
M2. The M1 hole is still open on one path: the power entity is unavailable when the probe runs, then comes back with a wrong unit.
reading_from_statesonly checks that the power entity has some state (app/chargers.py:222). If it comes back as12 V, or with no unit, the reading counts as available, but_wattsreturns None.last_okthen never moves (chargers.py:552), andcar_term()returns unknown for good. The House tile shows "No reading" for good, and every profile sample is None.bad_sincestays None, so there is no row and no notification. The card shows "Charging". This is the same silent, permanent state as M1.reading_from_states, so after 30 s the unreachable path gives a row and a notification; or judge the unit on the first reading that is available and refuse the charger then, as the probe does. Add a test for "unavailable at probe, then V".Low (fold into the same round)
test_ev03.py:984: the round 2 check no longer assertsreading.available(res["avail"]is now onlypower_w is None). For the wrong-unit case, keep an explicit assert that the reading is available with no power, so the available-without-power path stays proven. The M2 fix will change exactly this path, so the test should say which behaviour it expects.Checks
set_numberor service call).Verdict: changes requested (M2). Not merged.
Re-review round 4 at
af7e96e: right, merged after one Low fixHead reviewed:
af7e96e5e5f5d72c19d989c033ac0fa07243db2e, then my fix commitd7b42980927c31773bda65a926078906c1f82ebf(baserelease/1.06bf3759, unchanged). CI run 1677 is green onaf7e96e.Checks
M2 is closed. My probe2 (power entity unavailable for 3 cycles while the add-on starts, then 400 cycles in each case) now gives:
The dev's test part 12 also covers recovery, a unit changed from W to V while the add-on runs, and one notification after 5 min. No silent path is left. A reading now counts as available only when
_watts()gives a number, so an available reading always moveslast_ok. The only paths that leave the car's power unknown are unavailable readings: a read error, a 5 s timeout, a check of the entities at start-up that does not finish, or the login sensor off. All of them reach the unreachable row after 30 s. The one other gap is the first cycle before the first read.The unit conversion is exact (mW 0.001, W 1, kW 1000, MW 1e6; tests use 6 900 000 mW, 0.0069 MW and 6.9 kW). The probe used its own
POWER_UNITStuple beside_W_PER: two lists with the same content. Fixed myself (Low) ind7b4298:POWER_UNITS = tuple(_W_PER), one table. No behaviour change. test_ev03, test_pv, test_messages, test_ui_text and test_defaults_pin pass locally.L3 is fixed. The round 2 check now asserts the expected behaviour explicitly: the reading is unavailable, with cause "power unit" or "no answer from power". The seam checks for a missing or wrong unit now assert
not availableand the cause. The switch tonamed_absence.nthfollows TEST-26. Nothing is weaker.The rest of the diff is sound. The new Why strings are in EN and NL. Still no charger writes: the write methods have no caller in
app/, and there is no new number write or service call.Verdict: right. Merging into
release/1.0, pinned tod7b4298after CI run 1679checks / unit (pull_request)went green on it.