All paths are relative to
http://<device-ip>/api/v1. LAN-only. No authentication.
Returns the full current state of the sump pump monitor — run state, active alerts, protection mode, lockout info, learning progress, and cumulative stats.
200 OK{
"pump_running": false,
"current_run_s": 0,
"current_power_w": 0.0,
"alerts": [],
"protection_mode": "active",
"protection_auto_disabled": false,
"lockout_active": false,
"lockout_remaining_s": 0,
"lockout_retries_used": 0,
"lockout_alert": null,
"run_count_total": 87,
"runs_last_24h": 7,
"total_runtime_s": 2958,
"last_outage_s": 0,
"last_run_end_ms": 1708300000000,
"last_run_dur_s": 34,
"last_run_avg_w": 762.4,
"last_run_peak_w": 812.0,
"idle_w": 0.0,
"active_w": 780.0,
"on_threshold_w": 234.0,
"inter_run_gap_mean": 21600.0,
"alert_enable_mask": 7,
"relay_cut_mask": 1,
"inactivity_alert_min": 7200,
"anomaly_lockout_min": 10,
"lockout_max_retries": 3,
"rhythm_hex": "000000010001000200010000...",
"rhythm_head": 142,
"rhythm_last_bin_ms": 1708300200000
}
| Field | Type | Description |
|---|---|---|
pump_running | boolean | true if pump is currently detected as ON |
current_run_s | integer | Seconds into current run (0 if idle) |
current_power_w | float | Instantaneous power reading (watts) |
alerts | string[] | Currently active alert keys, e.g. ["power_anomaly_low", "long_run"]. Empty if none. |
protection_mode | string | Current protection mode: learning, active, or suspended |
protection_auto_disabled | boolean | true if any relay-cut flag was system-disabled due to exhausted retries |
lockout_active | boolean | true if relay is currently held OPEN during a lockout period |
lockout_remaining_s | integer | Seconds remaining in current lockout (0 if not in lockout) |
lockout_retries_used | integer | How many relay trips have occurred for the current alert type |
lockout_alert | string | null | Alert key that triggered the current lockout, or null |
last_run_end_ms | integer | null | Epoch ms of last completed run, or null if no runs since boot |
last_run_dur_s | integer | Duration of last completed run in seconds |
last_run_avg_w | float | Average power during last completed run |
last_run_peak_w | float | Peak power during last completed run |
last_outage_s | integer | Duration of last detected power outage in seconds (0 if none) |
run_count_total | integer | Cumulative lifetime run count (persisted in NVS) |
runs_last_24h | integer | Precise pump run count in the rolling 24h window |
total_runtime_s | integer | Cumulative lifetime runtime in seconds |
idle_w | float | Learned idle power in watts |
active_w | float | Learned active power in watts |
on_threshold_w | float | Current ON detection threshold in watts |
inter_run_gap_mean | float | null | Mean seconds between consecutive pump runs. null if fewer than 2 runs. |
alert_enable_mask | integer | Current alert-enable bitmap (0–31). Default 7. |
relay_cut_mask | integer | Current relay-cut bitmap (0–7). |
inactivity_alert_min | integer | Minutes without a cycle before Expected Run alert fires. Default 7200. |
anomaly_lockout_min | integer | Minutes relay stays OPEN after anomaly. Default 10. |
lockout_max_retries | integer | Auto-release attempts before protection disables. Default 3. |
rhythm_hex | string | 288-char hex string — rolling 24h activity bins |
rhythm_head | integer | Index (0–287) of the current bin |
rhythm_last_bin_ms | integer | Epoch ms when the current head bin was last advanced |
| Mode | Description |
|---|---|
learning | Insufficient baseline data — only power outage fires |
active | Wattage and runtime baselines met — all alerts enabled |
suspended | Was active, inactivity alert fired — reverts to learning until next cycle |
| Key | Display name | Description |
|---|---|---|
power_anomaly_low | Low Power | Possible dry run |
power_anomaly_high | High Power | Possible blockage |
long_run | Excessive Run | Run exceeds 2× learned mean duration |
frequent_cycling | Short Cycling | Cycles in rolling 60-min window exceed 2× mean hourly rate |
inactivity | Expected Run | No pump cycle for inactivity_alert_min minutes |
Returns detailed stats and power waveform for the last completed pump cycle.
200 OK{
"start_ms": 1708299965000,
"end_ms": 1708300000000,
"dur_s": 34,
"avg_w": 762.4,
"peak_w": 812.0,
"std_w": 18.7,
"sample_count": 34,
"samples": [210.5, 810.2, 795.0, 780.1, 770.3, 762.8, ...]
}
| Field | Type | Description |
|---|---|---|
start_ms | integer | null | Epoch ms when pump turned ON |
end_ms | integer | null | Epoch ms when pump turned OFF |
dur_s | integer | Cycle duration in seconds |
avg_w | float | Mean power during cycle |
peak_w | float | Peak power observed |
std_w | float | Standard deviation of power |
sample_count | integer | Number of valid entries in samples[] (0–60) |
samples | float[] | Power readings at ~1 Hz (first 60 seconds of run) |
samples[]captures the first 60 seconds. For shorter runs, this is the complete waveform. Data is NVS-persisted — survives reboot, overwritten by the next completed cycle.
Returns all current configuration parameters.
200 OK{
"inactivity_alert_min": 7200,
"anomaly_lockout_min": 10,
"lockout_max_retries": 3,
"alert_enable_mask": 7,
"relay_cut_mask": 1
}
| Field | Type | Default | Range | Description |
|---|---|---|---|---|
inactivity_alert_min | integer | 7200 | 1–43200 | Minutes without a cycle before Expected Run alert. 7200 = 5 days. |
anomaly_lockout_min | integer | 10 | 1–480 | Minutes relay stays OPEN after anomaly. |
lockout_max_retries | integer | 3 | 1–10 | Auto-release attempts before protection permanently disables. |
alert_enable_mask | integer | 7 | 0–31 | Bitmap. Bit 0=low power, 1=high power, 2=long run, 3=freq cycling, 4=inactivity. |
relay_cut_mask | integer | 1 | 0–7 | Bitmap. Only bits 0–2 meaningful (low power, high power, long run). |
Update configuration. Accepts a partial JSON body — only fields present are changed. Persisted to NVS immediately.
// Change lockout timing
{ "anomaly_lockout_min": 15, "lockout_max_retries": 5 }
// Enable high-power relay cut (bits 0+1)
{ "relay_cut_mask": 3 }
// Enable frequent cycling alert (bits 0–3)
{ "alert_enable_mask": 15 }
// Set inactivity alert to 3 days
{ "inactivity_alert_min": 4320 }
| Field | Rule |
|---|---|
inactivity_alert_min | Integer, 1–43200 |
anomaly_lockout_min | Integer, 1–480 |
lockout_max_retries | Integer, 1–10 |
alert_enable_mask | Integer, 0–31 |
relay_cut_mask | Integer, 0–7 |
200 OKFull config object (same as GET).
| Status | Body | Condition |
|---|---|---|
| 400 | "Empty body" | No request body |
| 400 | "Invalid JSON" | Body is not valid JSON |
| 400 | "<field> must be <min>–<max>" | Numeric field out of range |
| 400 | "<field> must be a number" | Non-numeric value |
Returns the alert event ring buffer — up to 32 most recent events, ordered oldest first.
200 OK[
{
"event": "alert_fired",
"alert": "power_anomaly_low",
"timestamp_ms": 1738886400000,
"run_dur_s": 12,
"power_w": 520.0,
"relay_cut": true
},
{
"event": "alert_cleared",
"alert": "power_anomaly_low",
"timestamp_ms": 1738886420000,
"duration_s": 20
},
{
"event": "power_outage",
"timestamp_ms": 1738800000000,
"outage_s": 3600
},
{
"event": "mode_change",
"timestamp_ms": 1739145600000,
"from": "learning",
"to": "active"
},
{
"event": "device_boot",
"timestamp_ms": 1739318400000,
"reason": "power_on"
}
]
| Event | Description | Extra fields |
|---|---|---|
alert_fired | Active alert added | alert, relay_cut, power_w, run_dur_s |
alert_cleared | Active alert removed | alert, duration_s |
power_outage | Boot gap > 2 min detected | outage_s |
protection_auto_disabled | Max retries exhausted | alert |
mode_change | Protection mode transition | from, to |
lockout_reset | User reset lockout | — |
device_boot | Device booted | reason |
Normal pump runs do NOT appear in this ring. Pump activity is captured by the rhythm ring in
/sump/status.
Clear any active lockout, re-enable any system-disabled protection flags, and reset the retry counter.
200 OK{ "status": "lockout_reset" }
| State | Reset to |
|---|---|
lockout_active | false — relay closes immediately |
lockout_retries_used | 0 |
protection_auto_disabled | false |
| System-disabled cut flags | Restored to true in NVS |
Reset all cumulative statistics, clear alert history, clear rhythm ring, and reset all learned baselines. Device re-enters learning mode.
200 OK{ "status": "stats_reset" }
| Data | Reset to |
|---|---|
| Run count, runtime | 0 |
| Welford trackers (4×) | Zeroed |
| Bimodal EMA (idle_w, active_w) | 0.0 |
| Rhythm ring (288 bins) | All zeros |
| Alert history ring (32 slots) | Empty |
| Protection mode | learning |
| Lockout state | Cleared |
Returns learning / baseline convergence data: Welford CV values, per-metric readiness flags, inter-run gap stats, and the bimodal power baselines.
200 OK{
"mode": "learning",
"cycle_count": 9,
"wattage_mean": 762.4,
"wattage_cv": 8.2,
"wattage_ready": true,
"runtime_mean": 34.0,
"runtime_cv": 46.1,
"runtime_ready": false,
"cycle_rate_mean": 7.2,
"cycle_rate_cv": 45.0,
"cycle_rate_ready": false,
"inter_run_gap_mean": 420.0,
"inter_run_gap_cv": 32.5,
"inter_run_gap_ready": true,
"idle_w": 0.0,
"active_w": 780.0
}
| Field | Type | Description |
|---|---|---|
mode | string | Protection mode: learning, active, suspended |
cycle_count | integer | Total valid pump cycles observed |
wattage_mean | float | Welford mean peak power per cycle (W) |
wattage_cv | float | Wattage CV (%). Threshold: < 15% |
wattage_ready | boolean | true if below threshold |
runtime_mean | float | Mean run duration (seconds) |
runtime_cv | float | Runtime CV (%). Threshold: < 40% |
runtime_ready | boolean | true if below threshold |
cycle_rate_mean | float | Mean cycles per hour |
cycle_rate_cv | float | Cycle rate CV (%) |
cycle_rate_ready | boolean | Always true (informational) |
inter_run_gap_mean | float | Mean gap between runs (seconds) |
inter_run_gap_cv | float | Inter-run gap CV (%) |
inter_run_gap_ready | boolean | true if ≥ 2 runs observed |
idle_w | float | Learned idle power baseline (W) |
active_w | float | Learned active power baseline (W) |
| Metric | CV threshold | Required for ACTIVE |
|---|---|---|
| Wattage | < 15% | Yes |
| Runtime | < 40% | Yes |
| Cycle rate | — | No (informational) |
| Inter-run gap | — | No (informational) |
Transitions learning → active when both wattage_ready and runtime_ready are true and ≥ 5 cycles recorded.
application/json.application/json.text/plain.timestamp_ms fields are wall-clock UTC epoch milliseconds. The device obtains time via SNTP after WiFi connects.