Skip to content

v0.0.22

Choose a tag to compare

@chris1howell chris1howell released this 30 Aug 14:42
· 5 commits to OpenEVSE9 since this release

Stuck-relay recovery support

Client-library support for the controller-side stuck-relay auto-recovery
feature (open_evse firmware 9.3.0, dev @ 5b3a755). OpenEVSE9 @
2c7c3f3, library.json 0.0.22.

Background

Firmware 9.3.0 added an automatic recovery attempt for a welded/stuck main
contactor: when EVSE_STATE_STUCK_RELAY is entered with no EV connected,
the controller cycles the relay (3 rounds of 5 on/off toggles, each shorter
than the last) instead of going straight to an unrecoverable hard fault.
It also added $FK to run that same cycle manually, and extended $GL
(relay health) with a cumulative attempt counter. Full firmware-side
derivation: open_evse/docs/stuck_relay_recovery.md.

This release wires both into the client API.

getRelayHealth() - new field

The callback signature gained a 10th parameter,
uint32_t stuck_relay_recovery_count:

OpenEVSE.getRelayHealth([](int ret, uint8_t life_remaining_pct,
                            uint32_t cold_open_count, uint32_t elec_damage_x1e6,
                            uint32_t transit_baseline_ms, bool transit_drift_warning,
                            uint32_t thermal_index_x100, uint32_t thermal_baseline_x100,
                            uint8_t thermal_warning_level,
                            uint32_t stuck_relay_recovery_count)
{
  if (ret == RAPI_RESPONSE_OK) {
    Serial.printf("Recovery attempts: %u\n", stuck_relay_recovery_count);
  }
});

Backward compatible on the wire: against a pre-9.3.0 controller, $GL
still only returns 8 fields, and stuck_relay_recovery_count reads back
0 rather than the call failing.

runStuckRelayRecovery() - new method

void OpenEVSEClass::runStuckRelayRecovery(std::function<void(int ret)> callback);

Sends $FK to run the recovery cycle on demand - the same routine the
controller runs automatically. The controller NAKs it if an EV is
connected (unsafe to cycle the relay under load).

Uses an explicit 35 second RapiSender timeout, not the library
default (RAPI_TIMEOUT_MS, 500ms). The controller call itself is blocking
and can legitimately take up to ~30s (3 rounds x 5 toggles x up to 2s
on+off, plus zero-cross/transit overhead) before it responds - the default
timeout would give up long before that.

Doesn't itself report whether the relay came free; check getStatus()
(state) or getRelayHealth() (the recovery counter, or re-poll relay
status) afterward.

resetRelayHealth() - behavior change, no API change

$FH now also clears the recovery counter server-side, alongside the
existing damage-accumulator and baseline resets. No client-side change
needed - just documented.

Requirements

Same D9-protocol gate (isD9Supported()) as the other linco-work
extensions, and firmware 9.3.0+ / ADVPWR for runStuckRelayRecovery() and
the recovery counter specifically (older/non-ADVPWR controllers NAK $FK
with RAPI_RESPONSE_FEATURE_NOT_SUPPORTED and report the counter as 0).

Verification

Compiled by temporarily pointing openevse_esp32_firmware's lib_deps at
this checkout (symlink://) and building openevse_wifi_v1. The library
itself compiled clean; the only error was the expected one - that repo's
evse_monitor.cpp still has the old 9-argument getRelayHealth() lambda.