This document describes the HTTP endpoints exposed by the firmware webserver.
- Base URL:
http://<device-ip> - API prefix:
/api - Content types:
- JSON for status/system endpoints
- Plain text for control endpoints
multipart/form-datafor firmware upload
Returns device and runtime information.
- Method:
GET - Query parameters: none
- Status:
200 OK - Content-Type:
application/json - Body example:
{
"system": {
"firmwareVersion": 1,
"cpuFrequency": "240 MHz",
"ip": "192.168.1.123",
"wifiStrength": -58,
"uptimeSeconds": 98012,
"upSince": "27h 13m 32s",
"currentDateTime": "-"
}
}Note:
currentDateTimeis not yet implemented and always returns"-".upSinceis the elapsed uptime formatted as"Xh MMm SSs".
Returns boiler status values used by the UI.
- Method:
GET - Query parameters: none
- Status:
200 OK - Content-Type:
application/json - Body example:
{
"power": 1320,
"measuredPowerSource": "energy_meter",
"heatingPercentage": 60,
"temperature": 65.0,
"total": 12.345,
"rssi": -50
}measuredPowerSource is one of "energy_meter", "pulse", or "estimate" (heuristic fallback).
Sets heating level percentage.
- Method:
GET - Query parameter:
percentage(optional): integer, clamped to0..100
Example:
GET /api/heat?percentage=60
- Status:
200 OK - Content-Type:
text/plain - Body:
OK
Triggers an immediate reboot.
- Method:
GET - Query parameters: none
- Status:
200 OK - Content-Type:
text/plain - Body:
Restart ESP
Triggers factory reset callback, responds OK, then reboots.
- Method:
GET - Query parameters: none
- Status:
200 OK - Content-Type:
text/plain - Body:
OK
Uploads new firmware image and, on success, reboots into the new partition.
- Method:
POST - Content-Type:
multipart/form-data - Payload: firmware
.binfile (commonly sent in form fieldupdateby UI)
- Status:
200 OK - Content-Type:
text/plain - Body:
OKon successful OTA and boot partition switch (device then reboots)FAILon OTA failure
Single response combining system, status, sensors, control, output, and calibration (same field shapes as the individual endpoints below where applicable). Used by the web UI Status tab.
JSON: valid (bool), celsius (number, when valid).
JSON: valid (bool), everValid (bool), pollFailCount (number), pulseFallbackAvoidedCount (number); when valid: totalKwh, activeKw, voltageV, currentA.
JSON: valid (bool); when valid: totalPulses, estimatedWatts.
JSON: analog0to10V (requestedVoltage, dacMillivolt), ssr (heatingPercent, tonUs, toffUs, phaseHigh, gpioHigh, dutyCyclePercent).
Set heating setpoint. Body: application/json with either percentage or heatingPercent, or watts / heatingWatts (converted using the calibration curve when available, otherwise the 22 W/% heuristic).
Response 200 JSON: heatingPercentage, wattageControlEnabled, estimatedHeatingWattsFromPercent. 400 if neither watts nor percentage is provided.
Returns the current calibration data and the state of an active calibration run.
- Status:
200 OK - Content-Type:
application/json - Body example:
{
"calibrated": true,
"points": [
{ "percent": 0, "watts": 0, "fromMeasurement": false },
{ "percent": 1, "watts": 22, "fromMeasurement": true }
],
"run": {
"state": "idle",
"step": 0,
"currentPercent": 0,
"lastSampleWatts": 0
}
}run.state is one of "idle", "running", or "done". An optional run.error string is included when an error occurred.
Starts an automated calibration run.
200 OK—{"ok": true}on success409 Conflict—{"ok": false, "error": "busy"}if already running
Requests a stop of an active calibration run.
200 OK—{"ok": true}on success409 Conflict—{"ok": false, "error": "not_running"}if not running
Clears all stored calibration data.
200 OK—{"ok": true}on success409 Conflict—{"ok": false, "error": "busy"}if a calibration run is in progress
Sets the target heating wattage. Rate-limited to one request per 4.5 seconds.
- Method:
POST - Content-Type:
application/json - Body:
{"watts": 1500}(also accepts"heatingWatts")
200 OK:
{
"requestedWatts": 1500,
"targetHeatingWatts": 1500,
"wattageControlEnabled": true,
"heatingPercentage": 68
}400 Bad Request—{"error": "watts required"}if the field is missing429 Too Many Requests—{"error": "rate_limited", "retryAfterSeconds": 3}withRetry-Afterheader
GET /serves the main web UI (gzipped HTML)GET /logo.svgserves the logo asset (gzipped SVG)
- Endpoint list is based on currently registered handlers in firmware (
main/Webserver/Webserver.cpp). - A
/otaroute appears in the web UI source as documentation text but is not currently registered by the firmware webserver.