Two related fixes for v0.1.3:
1. _read_power_w() reads each power sensor's unit_of_measurement and
converts kW to W. Before this, sensors reporting in kW (Tesla
integration's leomobile_charger_power = "1" kW) were treated as raw
watts, causing the leftover calculation to undercount by ~1000×.
In practice the algorithm sent the EV charge rate that matched
"what's exporting NOW" instead of "what's available if EV pulled
everything" — leaving ~1 kW of solar exported instead of routed to
the car.
2. round() → math.ceil() on the amp computation. Trade-off: up to
~VOLTAGE watts of grid import per tick, in exchange for zero solar
export. Maximizes PV self-consumption, accepts small grid cost as
rounding noise.
Tests added: kW conversion round-trip; ceil rounds up partial amps.
All 57 pass.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
The hardcoded 16A ceiling was too high for a 14A circuit breaker.
Lowered the constant; tests updated accordingly. Making MAX_AMPS
configurable per install is a v0.1.3 follow-up — for now, anyone with
a different circuit rating will need to fork and edit the constant.
If the EV's service rejected a write (e.g. Tesla integration raising
'Command was unsuccessful: is_charging' when we redundantly call
switch.turn_on while charging already running), the exception used to
propagate up through _async_update_data, killing the whole coordinator
update and putting the integration into setup_retry indefinitely.
Wrap service calls in a _safe_service_call helper that catches and
logs at WARNING; the coordinator still returns a valid Decision so
entities populate. The next tick reconciles naturally.
The gate-reset condition was matching Mode.OFF (sub_mode=DISABLED,
write_action=NONE) and clearing last_desired_amps each tick, causing
the next tick to re-issue switch.turn_off. Disambiguate by checking
desired_amps is None — only the true gate-closure path returns None.
Also removes now-unused SubMode import from coordinator.py.
Adds ConfigFlow with async_step_user, three validators (missing grid signal,
mutual exclusivity, EV draw plausibility), strings.json + translations/en.json,
and three passing tests. Adds enable_custom_integrations autouse fixture to
conftest.py to allow HA to discover the custom integration during tests.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Add _build_snapshot and helper methods (_read_float, _read_bool,
_read_at_home, _read_sun_state, _read_net_grid) to EVSolarChargerCoordinator
so it can assemble a full Snapshot from live HA entity states.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Pure function resolving sub-mode from time-of-day and sun state; 9
parametrized test cases covering all boundary conditions.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>