Skip to content

HTTP API

Two auth mechanisms — pick whichever fits the caller:

  • Session cookiePOST /login with password=<web-password> returns a Set-Cookie you reuse. Browsers do this automatically.
  • Bearer tokenAuthorization: Bearer <token> header on every request. Generate the token on Settings → Home Assistant → API token; only the hash is kept on the device.

Responses are JSON unless noted. Errors use a consistent shape:

{ "ok": false, "error": "human-readable reason" }

The on-device page /config/api is the live, hand-maintained inventory — open it on your own HeatSync for the same list (54+ endpoints currently). This page mirrors it grouped by purpose.

MethodPathNotes
POST/loginForm-encoded password=…. Returns 302 + cookie.
GET/logoutClears the session cookie.
GET/api/auth/tokenStatus of the long-lived bearer token (created? when?).
POST/api/auth/tokenGenerate a new bearer token; returns the plaintext (shown once, stored hashed).
DELETE/api/auth/tokenRevoke the current token.
MethodPathDescription
GET/api/statusTop-level health — WiFi, MQTT, bus stats, writes counter, BLE inject status.
GET/api/livePer-device snapshot — every value HeatSync has decoded. Drives the dashboard and the HACS integration’s main poll.
GET/api/systemChip info, uptime, reset reason, heap stats.
GET/api/diagnoseBundle of /api/system + /api/status + sniffer head + events. Used by the “Copy snapshot” button and HA’s “Download diagnostics”.
GET/api/eventsLast ~80 events from the in-RAM ring (boot, OTAs, faults, warnings).
GET/api/events/persistedPersistent events that survive reboots (boot count, last error, etc.).
GET/api/busList of NASA addresses seen on the bus.
GET/api/sniffer/recentAll unique (source, msgNo) tuples with last/previous value + change count. Cap 256, chunked-streamed.
POST/api/sniffer/resetZero the sniffer’s change counters.
GET/api/ble/sensorsBLE thermometers seen + paired (empty when BLE compile-disabled).
POST/api/ble/pairPair a sensor by MAC (form mac=…&name=…).
POST/api/ble/unpairUnpair (form mac=…).

These power the home page widgets and the HACS integration’s daily totals.

MethodPathDescription
GET/api/cost/statusToday’s running totals — todayPence, peakKwh, offPeakKwh, per-mode kWh split, current rateNowPence + bucket (peak/offPeak). Reset at midnight.
GET/api/energy/dailyPer-day historical totals (kwhElec, kwhThermal, cycles, outdoorAvg). One entry per past day; rolls forward at midnight.
GET/api/carbon/statusCurrent gCO₂/kWh from carbonintensity.org.uk for the configured region, plus the 48-slot half-hour forecast.
POST/api/carbon/configForm: enabled, postcode, or resolve=1 to derive postcode from saved weather lat/lon.
GET/api/weatherCurrent weather state + 48 h hourly forecast (Open-Meteo).
POST/api/weather/configSave lat/lon (and optional place label).
GET/api/weather/geocode?q=<postcode-or-city>Resolve a place name to lat/lon.
GET/api/octopus/statusStored Octopus credentials state + last lookup result (API key masked).
POST/api/octopus/lookupFire the Octopus account + tariff lookup. Form: apiKey, account (both optional — falls back to persisted).
POST/api/octopus/applyApply the most recent successful lookup’s windows to tariffWindows[].
MethodPathDescription
GET/api/dhw-schedule/statusCurrent DHW schedule decision — mode (0–3), enabled, off-peak flag, status string, reheat-minutes estimate, computed Efficiency/Combo window epochs.
GET/api/schedule/heatingWeekly heating schedule blocks.
POST/api/schedule/heatingReplace the weekly heating schedule.
GET/api/dhw-modelCylinder-learning state — volume estimate, standing loss, last-reheat duration, cycle count.
GET/api/load-comp/statusLoad-compensation state — current offset, computed error and slope terms.
MethodPathDescription
GET/api/configAll persisted settings (passwords, API keys never returned).
POST/api/configForm-encoded; only the keys present are updated. Triggers MQTT re-setup when touched.

Notable fields: deviceName, zoneLabel, mqttHost, mqttPort, mqttUser, mqttPass, mqttTopicPrefix, haDiscoveryPrefix, haEnabled, writesEnabled, roomTempInject, glycolPercent, dhwSchedEnabled, dhwSchedMode (0=Tariff, 1=Carbon, 2=Efficiency, 3=Combo), dhwSchedFullTarget, dhwSchedMidTarget, dhwSchedHardLimit, dhwTankVolumeL, tariffWindows[], tariffPeakPence, tariffOffPeakPence, loadComp*, heatNightOffset, awayActive, awaySetbackC, boost*, preferredBssid.

Control — writes (require bus writes enabled)

Section titled “Control — writes (require bus writes enabled)”

All return { "ok": true } on success, or 400 { ok: false, error: ... }.

MethodPathBody / queryDescription
POST/api/control/dhw-targetvalue=<30..65>Set DHW setpoint °C.
POST/api/control/dhw-power`on=10`
POST/api/control/dhw-mode`mode=ecostandard
POST/api/control/dhw-boost(none)One-shot +5 °C for 1 h.
POST/api/control/heating-mode`mode=offheat
POST/api/control/heating-targetvalue=<float>Set room/zone target.
POST/api/control/heating-boost(none)One-shot +1 °C for 1 h.
POST/api/control/water-law-offsetvalue=<-5..+5>±5 °C heating-curve dial.
POST/api/control/heating-curveForm: curveType, wl1FlowMax, wl1FlowMin, wl2FlowMax, wl2FlowMin, ambMax, ambMinWrite the heating curve shape.
POST/api/control/flow-targetvalue=<15..65>Direct flow-temp override (fixed-flow installs).
POST/api/control/fan-mode`mode=autolow
POST/api/control/quiet-mode`on=10`
POST/api/control/legionellaForm: enabled, day, hour, targetC, durationMinAnti-legionella schedule.
POST/api/control/away`on=10`
MethodPathDescription
GET/api/wifi/scanScan visible WiFi APs (BSSID + RSSI + channel).
POST/api/wifi/selectPin to a specific BSSID (form bssid=AA:BB:...). Empty = auto-pick strongest matching SSID.
POST/api/wifi/roamForce-evaluate auto-roam now, bypassing the 5-min cool-down.
GET/api/net/probeDNS + TCP + TLS connectivity probe with explicit mbedTLS error codes. Diagnostic.
MethodPathDescription
GET/api/baselineBaseline-capture state — active, progress, computed delta.
POST/api/baseline/startBegin a baseline capture (~10 min idle measurement).
POST/api/baseline/cancelAbort an in-progress capture.
MethodPathDescription
POST/api/fsv/pollKick off a polling cycle — sends a NASA Read request for each known FSV register in rotation, one every 250 ms.
GET/api/fsv/status{ active, index, total, elapsedMs }.
POST/api/fsv/probeOne-shot Read for a specific register with caller-spoofed source class (diagnostic). Query: target=<hex>, source=<hex>.
MethodPathDescription
GET/api/heat-loss/stateSummary of the analyser’s current estimate.
GET/api/heat-loss/binsPer-outdoor-temperature-bin samples.
GET/api/heat-loss/eventsRecent cool-down events used as samples.
POST/api/heat-loss/resetWipe the accumulated samples.
MethodPathDescription
GET/api/update/statusCurrent version, latest release, install-in-progress flag.
POST/api/update/checkFetch the manifest from GitHub Pages right now.
POST/api/update/installBegin downloading + flashing the latest release. Device reboots when done.
POST/api/update/configForm: autoCheck, autoCheckIntervalH.
GET/update(Legacy upload page — used by ./build.sh ota-http.)
POST/updateMultipart upload of samsung_controller.ino.bin. Cookie auth.

The first-boot onboarding wizard at /wizard.

MethodPathDescription
POST/api/wizard/mqtt-testTry connecting to the entered MQTT broker.
GET/api/wizard/ha-checkConfirm HA’s homeassistant/status was seen.
POST/api/wizard/namesSave device + zone labels.
POST/api/wizard/completeMark onboarding done, redirect to dashboard.

All authenticated; redirect to /login if no session — except ?demo=1 which serves the page with the demo JS shim for screenshots / docs.

/ (dashboard), /heating, /hot-water, /schedule, /diagnostics, /sniffer, /faults, /insights, /wizard, /config, /config/device, /config/energy, /config/home-assistant, /config/data-sources, /config/api, /config/sensors, /config/device-info, /config/firmware.

PathPurpose
/loginLogin form.
/style.cssShared stylesheet.
/icons.svgLucide icon sprite.
/heatsync.jsDemo-mode shim used by ?demo=1 for screenshots.
/favicon.svg / /favicon.icoSVG mark.