Skip to content

Releases: zany92/tesla-loadpilot

v1.4.0 - Law ceiling capped on the measured TWC3 reaction curve

Choose a tag to compare

@zany92 zany92 released this 31 Aug 20:57

What changed

law_emax_default moves from 1.0 A to 0.9 A, and law_gain_default from 0.75 back to 0.5.

Why the ceiling moved

PVi1 published a measured reaction curve of the TWC3 to fixed, stepped reported values on firmware 26.26.1:

Excess above L Measured wallbox reaction
+0.9 A gentle reduction over tens of seconds
+1.0 A reduction after ~20 s, inconsistent under dynamic load
+1.1 A rapid reduction, full stop in about 3 s

That curve independently corroborates the dead-band hysteresis measured on my own pilot, where the wallbox only engages at about L+0.85 from rest. Two separate instrumentations, the same threshold.

The published value carries a permanent +/-0.05 A dither, so a ceiling of 1.0 let the law peak at L+1.05: inside the inconsistent band, and 0.05 A away from the band that stops the charge outright. At 0.9 the peak is L+0.95, which still breaks the dead band while keeping 0.15 A of margin below the stop threshold.

The ceiling now deliberately equals escalation_kick_a, so the continuous law and the stage-2 anti-hysteresis kick target the same measured point. Stage 2 still bypasses the clamp by design, so its authority is unchanged.

Why the gain moved back

Both 0.5 and 0.75 are field validated, but 0.75 was measured pumping the regulation, 6 to 13 A swings, on a pilot whose house load was near constant: the loop was chasing its own echo. 0.5 holds the same equilibrium without pumping, and still sits on the measured distrust floor, which must never be crossed downward.

Upgrading

Both values are runtime knobs (Law Max Excursion, Law Echo Gain), so an existing install can adopt the change immediately without reflashing. Note that both carry restore_value: false by design: the law always boots on its shipped default, so a reflash is what makes the new values survive a reboot.

The pure test mirror and the 80 golden cases are updated and pass. The goldens pin their parameters explicitly, so traces recorded on the earlier defaults remain valid.

Credit to PVi1 for the measurement that motivated this.

Tesla LoadPilot 1.3.1

Choose a tag to compare

@zany92 zany92 released this 18 Aug 15:21

Tooling and consistency release.

  • CI now validates the ESPHome schema of all four reference configs and
    really compiles three of them (three-phase charger, single-phase
    charger, single-phase meter) with a warm platformio cache. The
    packet_transport duplicated-sensor question of the single-phase
    provider is settled: it compiles and links.
  • Golden law tests: a pure Python mirror of the publication law (both
    variants, escalations, dither, glitch firewall, fail-safe) replayed
    against seven segments of the real 17-18 Aug traces. 80 pytest cases
    run on every push; mutating a measured constant breaks the locks.
  • The shipped default echo gain moves to 0.75 (PVi1's value, bench
    vindicated in 1.2.0); golden replays explicitly pin the 0.5-era
    constants of the recorded traces.
  • Docs: spike-damper and episode-grouped announcement patterns, RS485
    field note, validated firmwares 26.18 + 26.26.1.

Tesla LoadPilot 1.3.0

Choose a tag to compare

@zany92 zany92 released this 18 Aug 14:27

Tesla LoadPilot 1.3.0

The integration learns the control patterns that were prototyped and
field-validated on the pilot site. Everything is strictly opt-in: an
existing entry keeps byte-identical behavior until you enable a feature.

Charge cap (number.loadpilot_charge_cap)

A user-set ceiling in amps (0 = automatic). The coordinator runs a 10 s
control tick that steers the node's bias channel: target = worst-phase
headroom + vehicle current - cap, raised immediately, released at most
0.5 A per tick (the asymmetry that killed the 11-16 A limit cycle), with
an anti-hysteresis kick when the vehicle idles above the cap while the
published value sits in the dead band. Field-validated on the pilot
(13 A target held at 13.2 A steady). Requires mapping a vehicle-current
entity (new field in advanced mapping); without it the number stays
unavailable and nothing runs.

Automatic budget trim (option, default off)

When the cap is 0, an IDLE / ARMED / KICKING / COOLDOWN state machine
detects the parked-above-budget condition (negative headroom held 3 min,
published in the dead band, bias at 0) and applies a transient 2 A kick,
releasing it only if the bias is still its own. Layered under the
firmware stage-2 escalation of core 1.2.0: the integration acts at
3 min, the firmware backstops at 4 min with no Home Assistant needed.

Law settings enforcement (options, default off)

Optional gain / max-excursion (and site-mapped drag) values that the
integration re-applies when the node reboots or comes back: this closes
the real gap where a reflash silently resets the law numbers to their
initial values (lived on the pilot: the tail fell back to 0 after a
flash). A Repair is raised if an enforced knob has no resolvable target
entity. Note: the generic core ships law variant A; the decaying-tail
knob is a site-specific override with no generic default.

Meter distrust detector (binary_sensor.loadpilot_meter_distrust)

A PROBLEM binary sensor plus a pedagogical Repair when the published
value stays in the pull zone for 120 s while the vehicle keeps drawing:
the signature of the charger silently distrusting the meter (BEHAVIOR
section 4). Thresholds derive from the new max-conductor option.
Disabled without a vehicle-current mapping (a published-only variant is
structurally false-positive prone; the 17 Aug false alert is now a
regression test).

Engineering

The decision logic lives in a pure module (control.py, injected clock,
no Home Assistant imports) covered by 36 pytest cases anchored on the
real traces of 17-18 Aug, and the CI now runs them on every push.

Tesla LoadPilot 1.2.0

Choose a tag to compare

@zany92 zany92 released this 18 Aug 13:26

Firmware core: stage-2 escalation (anti-hysteresis kick).

After four minutes of sustained constraint the charger-side node now
publishes at least L + 0.9 A (substitution escalation_kick_a), breaking
the dead-band hysteresis documented in BEHAVIOR section 12. The pilot
then follows the published value down to L, which is the exact budget
equilibrium, and the episode leaves the constraint (one kick per
episode). Budget convergence no longer depends on Home Assistant.

Also raised the recommended echo gain to 0.75 (PVi1's original value,
quantitatively vindicated on the pilot bench: the engagement gap
shrinks from about 1.7 A to 1.1 A; the measured distrust floor remains
around 0.5, never go below it).

Deployed and flashed on the pilot site on 18 Aug 2026. Integration code
unchanged.

Tesla LoadPilot 1.1.1

Choose a tag to compare

@zany92 zany92 released this 18 Aug 11:47

Tesla LoadPilot 1.1.1

Documentation and field-data release. No code change in the integration
or the firmware packages; the version bump ships the knowledge gained
on the pilot site on 18 Aug 2026.

Firmware 26.26.1 revalidated

Tesla started rolling out wall connector firmware 26.26.1 overnight.
The pilot site updated under supervision and revalidated the whole
behavior model in a real charge session: the commissioned emulated
meter survives the update, and every measured behavior (echo
correlation, dead band, pull, pause, autonomous resume) is identical
to 26.18, including a real 115 percent house-spike stress test with a
clean floor stop and resume. Details and raw traces: BEHAVIOR section
12 and data/traces/ (both languages).

Behavior model refined: the dead band is a hysteresis

From rest the pilot engages at about L + 0.85 published; once pulling
it follows down to published = L and holds there. Consequence for any
external bias controller: raise fast, release slowly, kick through the
threshold when the vehicle idles above target. Documented in BEHAVIOR
(EN and FR) and applied to the manual-limit pattern in the roadmap.

Manual cap pattern field-tuned

The 13 A manual cap was exercised on a live charge: a fast symmetric
loop produced an 11-16 A limit cycle; the shipped pattern (immediate
raise, 0.5 A per 10 s decay, anti-hysteresis kick, 5 s local vitals
source) held 13.2 A steady. TESTPLAN record A16.

New runbook signature

"charging failed" right after a pause with a calm house: a pause bias
posted while no charge is running can survive every release path and
silently block session starts. Signature, remedy and the permanent
"empty pause" exemption deployed on the pilot are documented in
RUNBOOK_INCIDENTS (EN and FR).

Tesla LoadPilot 1.1.0

Choose a tag to compare

@zany92 zany92 released this 18 Aug 10:43

Tesla LoadPilot 1.1.0

Changes since 1.0.1. One SemVer tag still covers the whole repository:
the HACS integration and the ESPHome firmware packages ship in lockstep.

Theme: single-phase support, end to end and clearly labelled
THEORETICAL
(meter provider, examples, preset, services, dashboards,
documentation), plus fully bilingual documentation.

Nothing changes for existing three-phase installations. The charger-node
firmware is unchanged character for character: esphome/packages/twc-core.yaml,
esphome/packages/providers/teleinfo-fr.yaml, the board packs and the
three-phase examples have a null git diff against 1.0.1, so the pilot-site
binaries need no reflash. The UDP measurement contract (port 18511, the six
lky_* broadcast ids) is untouched. The only behaviour change in the whole
release is the loadpilot.pause ceiling described below, and it only
affects single-phase entries.

Single-phase support (THEORETICAL - never bench-validated)

Scope: European 230 V single-phase, one logical CT. US split-phase (240 V,
two CTs) is a third topology and remains out of scope.

The packages already sketched single-phase (phase_count: "1" substitution
in the core, phase choice in the config flow, L1-only mirror). What was
missing to make it usable ships in this release:

  • Single-phase TIC provider
    esphome/packages/providers/teleinfo-fr-mono.yaml (new file; the
    three-phase provider is byte-identical). A single-phase Linky never emits
    the indexed labels the three-phase provider reads (SINSTS1/2/3), so with
    the old provider the UDP feed would never become fresh and the charger
    node would sit in fail-safe forever. The single-phase provider reads
    SINSTS (no index) plus URMS1 and computes sub-amp current as
    SINSTS/URMS1; phases B/C are published at 0, slaved to the TIC
    watchdog
    (0 only while phase A is alive, NAN on all six quantities on
    failure). Constant zeros independent of phase A's health would keep the
    feed judged fresh forever with a dead TIC - the exact resurrection of QA
    pitfall M3. CONTRACTS.md section 2 is clarified accordingly (a
    clarification of the existing rule, not an ABI change).
  • Single-phase meter example
    esphome/examples/meter-teleinfo-mono-olimex-poe.yaml (same Olimex
    board as the three-phase reference), and a completed charger example
    charger-mono-exemple.yaml: bias_max_a: "32", an electrically
    coherent 45 A service breaker for the 9 kVA example, pointers to the
    single-phase provider and to the commissioning ladder (shadow mode
    first, RAW as short as possible).
  • 3 kVA preset (mono_3, 15 A) in the config flow: the single-phase
    series now covers the full Enedis catalogue, 3/6/9/12/15/18/24 kVA.
    Three-phase presets are unchanged value by value.
  • Bias up to 32 A on single-phase entries: a single-phase TWC Gen 3
    draws up to 32 A on its one phase, and a full pause requires a bias at
    least equal to the vehicle current. loadpilot.set_bias now accepts up
    to 32 A on a single-phase entry and still refuses anything above 16 A on
    a three-phase one (the value is validated against every targeted entry
    before being written to any). At the fixed firmware ramp, a full 32 A
    pause takes about 160 s; the Charge Stop switch remains the immediate
    lever.
  • Single-phase dashboards: dashboards/loadpilot-overview-mono.yaml
    and dashboards/loadpilot_card-mono.yaml (L2/L3 rows removed).
  • Documentation: single-phase annexes in docs/en/BEHAVIOR.md
    section 11 and docs/fr/40_LOI_DE_COMMANDE.md section 11 (what is
    structurally invariant versus which numbers are three-phase calibration
    NOT transferred), single-phase commissioning inserts in both INSTALL
    guides, a single-phase provider row in
    docs/fr/15_FOURNISSEURS_MESURE.md, and "Single-phase or three-phase"
    configuration paragraphs in both READMEs.

Why "theoretical": no single-phase bench was available at design time.
The control-law constants (dead band, ~20 A.s cut integral, latencies,
slopes, vehicle minimum) are three-phase measurements, and the set of CT
registers a wallbox commissioned single-phase actually reads is unknown.
The bench campaign is declared OPEN as TESTPLAN cases C14-C20
(CT registers read, ct_total acceptance, control-law constants, 32 A
plausibility scale, real single-phase TIC, 32 A bias pause, fail-safe and
Meter Absent). Single-phase support stays theoretical until that campaign
runs; do not trust it on a real installation before then.

Fixed: loadpilot.pause used a hard-coded 16 A ceiling

loadpilot.pause now writes the per-installation bias ceiling (16 A
three-phase, 32 A single-phase) instead of a hard-coded 16 A. On a 32 A
single-phase charge, a 16 A bias would only have slowed the vehicle down,
never paused it. This is the only behaviour change of the release and it
only affects single-phase entries: on a three-phase entry the service
writes 16 A exactly as before.

Documentation is now fully bilingual

  • INSTALL and TESTPLAN translated into English (docs/en/).
  • BEHAVIOR and RUNBOOK_INCIDENTS translated into French (docs/fr/).
  • Cross-links are wired language to language: English pages link docs/en/,
    French pages link docs/fr/.

Upgrade notes

  • No config-flow migration: existing entries reload as they are. The only
    visible difference on a three-phase entry is one more option (mono_3)
    in the preset dropdown.
  • Charger-node firmware: byte-identical, no reflash needed, no new
    required substitution (phase_count still defaults to "3").
  • The set_bias service selector now shows 0-32 A; three-phase entries
    still reject anything above 16 A at call time.

This project is not affiliated with, endorsed by, or sponsored by
Tesla, Inc.

Tesla LoadPilot 1.0.1

Choose a tag to compare

@zany92 zany92 released this 18 Aug 07:19

Packaging release for the HACS default-store submission.

  • Brand icons now shipped inside the integration (custom_components/loadpilot/brand/), per the Home Assistant 2026.3 mechanism.
  • LICENSE is now the pure MIT text so GitHub and HACS detect the SPDX id; the PVi1/Klangen82 attribution moved to NOTICE.md.
  • README (EN and FR): step-by-step Installation section, variant B closed-loop verdict, MIT lineage.
  • CI: HACS validation and hassfest both green with no ignored checks.

Functional behavior is unchanged from 1.0.0.

Tesla LoadPilot 1.0.0

Choose a tag to compare

@zany92 zany92 released this 17 Aug 21:46

Tesla LoadPilot 1.0.0

First tagged release. One SemVer tag covers the whole repository: the HACS
integration and the ESPHome firmware packages ship in lockstep and both
report version 1.0.0.

Tesla LoadPilot is local, cloud-free charging power regulation for the
Tesla Wall Connector Gen 3: an ESP32 emulates the discontinued Neurio meter
on the wallbox's RS485 bus and feeds it real per-phase measurements taken at
the utility meter, so the wallbox's own load management modulates the
vehicle without ever tripping.

Status: first public release. Validated on a single pilot site (France,
three-phase 15 kVA, Linky meter, TWC firmware 26.18). The repository is
private; nothing is published to HACS or home-assistant/brands yet.

Firmware (ESPHome packages)

  • Co-variant worst-phase law (v2): the published signal always echoes
    real load variations, even in constraint, via bounded compression above
    the Max Conductor Limit (knobs Law Echo Gain 0.5, Law Max Excursion
    1.0 A). This removes the "frozen published value" failure mode that
    latched the wallbox's distrust state. Validated in closed loop on the
    pilot site on 17 Aug 2026 (load steps absorbed, autonomous session
    recovery, zero contactor events). Design: docs/fr/DESIGN_LOI_COVARIANTE.md.
  • Variant B (release drag): the asymmetric-release design that removes
    the exit yo-yo is fully specified with an inert-by-default kill switch
    (drag depth 0 restores the exact v2 law). It is delivered as design only
    in this release and is not part of the generic firmware packages. Design:
    docs/fr/DESIGN_VARIANTE_B.md.
  • TIC watchdog (meter provider): without it, a dead TIC hat on a live
    ESP32 rebroadcasts frozen values forever and no fallback engages (proven
    by ESPHome source reading, QA finding M3). The watchdog (tic_timeout_ms,
    default 15 s) invalidates the six broadcast quantities to NAN, which
    cascades to fail-safe on the charger node.
  • Anti-glitch plausibility firewall: measurement input filter on the
    charger node. R1: physical floor with the contactor closed (a service
    meter can never read below the wallbox's own draw). R2: sudden drops
    above 5 A must be confirmed by a second sample. Rises always pass
    immediately (the transient error is on the safe side). Design:
    docs/fr/DESIGN_ANTI_GLITCH.md.
  • Direct STOP: the Charge Stop switch immediately publishes the stop
    order (limit plus nudge, dithered). Never restored at boot: a deliberate
    stop cannot silently survive a reboot.
  • Meter-absent test switch: Meter Absent (test) silences the Modbus
    server at runtime (hot slave-address change) to exercise the wallbox's
    documented "loss of meter" 6 A fallback. Shipped OFF, never restored at
    boot. Design: docs/fr/DESIGN_METER_ABSENT.md.
  • Escalation stop (120 s at zero headroom publishes limit + 0.1 A,
    dithered), bias target with firmware-side ramp, fail-safe publication of
    the main breaker value with source priority UDP > HA mirror > fail-safe,
    all carried over from the production-validated reference block.

Integration (custom_components/loadpilot)

  • Config flow, 5 steps: meter profile, node names (existence checked),
    electrical parameters (installation type, France kVA presets, contract
    limit, buffer, with budget_too_small and tri_limit_suspicious
    validations), HA mirror mapping, confirmation summary. Options flow for
    later adjustments.
  • Entity mapping layer: entity_overrides (opt-in "advanced mapping"
    options step) remaps any tracked charger-node entity to an arbitrary
    entity_id; fail-safe detection depends only on the six essential
    measurements.
  • 5 derived sensors: regulation state (enum), per-phase headroom (3),
    worst phase. Contractual entity ids pinned in English
    (sensor.loadpilot_state, sensor.loadpilot_headroom_l1/l2/l3,
    sensor.loadpilot_worst_phase).
  • 3 services: loadpilot.set_bias, loadpilot.pause,
    loadpilot.resume.
  • Repairs: firmware/integration version skew, fail-safe source active,
    charger node missing from the entity registry.
  • Diagnostics export for support bundles.
  • Full EN/FR translations (identical key trees).

Known limitations

  • Entity ids on translated instances: recent Home Assistant releases
    (observed on 2026.8) ignore suggested_object_id, so the derived sensors
    can be created with translated object ids on a non-English instance (for
    example sensor.loadpilot_etat instead of sensor.loadpilot_state).
    Workaround: rename the five entities to the contractual ids listed above
    (Settings > Devices and services > Entities). The dashboards and docs
    assume the English ids.
  • Pilot node requires mapping: the pilot site's charger node predates
    the generic package naming, so the advanced entity mapping step is
    required there. Fresh installs that follow twc-core.yaml naming do not
    need it.
  • Variant B is not closed-loop tested: design only, see above. The exit
    yo-yo of the v2 law is a known, bounded behaviour until then.
  • Distrust layer is partially inferred: the wallbox's latched distrust
    state is characterised from field episodes and community corroboration,
    with statements labelled MEASURED / INFERRED / REPORTED in
    docs/en/BEHAVIOR.md section 4. Expect refinements at the next episode.
  • Physical fault-injection tests remain: the TIC watchdog was proven by
    source reading; the physical unplug test (TESTPLAN case C6, QA finding
    M3) and the meter-absent 6 A fallback test have not been run yet.
  • Calibration is tied to TWC firmware 26.18: a wallbox firmware update
    requires re-calibration of the measured law.

Documentation

  • docs/en/BEHAVIOR.md: the measured behaviour model of the TWC Gen 3 load
    management (English), including the distrust state (section 4).
  • docs/en/RUNBOOK_INCIDENTS.md: operator runbook for incidents.
  • docs/fr/TESTPLAN.md: acceptance and fault-injection test plan.
  • docs/fr/INSTALL.md: step-by-step installation guide (French).

Credits and license

Founding prior art: PVi1/esphome-twc-control
(Neurio emulation concept, Modbus register structure, escalation stop
technique). Licensing conversation in progress; nothing derived is
published. Neurio identity block constants from LucaTNT's register-map
gist. No license is granted yet (see LICENSE.placeholder); all rights
reserved until the attribution agreement is settled.

This project is not affiliated with, endorsed by, or sponsored by
Tesla, Inc.