Skip to content

Configuration portal HTTP API

This page documents the HTTP form fields accepted by the on-device WiFi configuration portal so that companion apps, provisioning scripts, and Home Assistant flows can integrate without reading firmware source.

The portal is implemented on top of h2zero's WiFiManager fork and the field declarations live in main/main.cpp (see setup_wifimanager).

Endpoint

POST http://<portal-ip>/wifisave
Content-Type: application/x-www-form-urlencoded

When the portal is active (no saved credentials, or trigger pressed at boot) the device exposes a soft-AP — see Portal for SSID/password rules.

Form fields

FieldTypeSource declarationPersisted?
sSSIDWiFiManager built-inyes
pWiFi PSKWiFiManager built-inyes
serverMQTT host (≤ 64)custom_mqtt_serveryes, if non-empty
portMQTT portcustom_mqtt_portyes, if non-empty
userMQTT usernamecustom_mqtt_useryes, if non-empty
passMQTT passwordcustom_mqtt_passyes, if non-empty and value differs from the compile-time MQTT_PASS sentinel
secure0 / 1custom_mqtt_secureyes (always)
validate0 / 1custom_validate_certyes (always)
certPEM (≤ 4096 B)custom_mqtt_certyes, if length > MIN_CERT_LENGTH
ota_certPEM (≤ 4096 B)custom_ota_server_certyes, if length > MIN_CERT_LENGTH
client_certPEMcustom_client_cert (signed-client builds only)yes, if length > MIN_CERT_LENGTH
client_keyPEMcustom_client_key (signed-client builds only)yes, if length > MIN_CERT_LENGTH
topicMQTT base topiccustom_mqtt_topicyes, if non-empty (trailing / added if missing)
nameGateway namecustom_gateway_nameyes, if non-empty
otaOTA / WebUI passwordcustom_ota_passyes, if non-empty

Empty-field semantics

Empty server / port / user / topic / name / ota values are ignored rather than persisted. This means a partial POST (e.g. WiFi-only) preserves any pre-flashed defaults instead of clearing them. To intentionally clear a field, this portal API does not currently support it — re-flash with new build defaults or use the WebUI.

The pass field combines the empty-check with a sentinel guard: the firmware persists the form value only when it is non-empty and differs from the compile-time MQTT_PASS sentinel. The sentinel branch prevents an unmodified form (which echoes back the default) from overwriting a stored password; the non-empty branch prevents a partial POST from wiping it.

Response and AP teardown

After processing the POST, WiFiManager returns a small success page and then tears down the soft-AP to attempt joining the configured station network. The teardown happens quickly enough that the TCP socket may be reset before the HTTP response is fully flushed to the client. Companion apps should:

  • Treat a connection reset immediately after the POST as a likely-success signal, not a failure.
  • Verify provisioning by checking for the device on the target network or for its first MQTT LWT message rather than relying on the HTTP response.

Example

bash
curl -X POST \
  --data-urlencode 's=my-ssid' \
  --data-urlencode 'p=my-psk' \
  --data-urlencode 'server=192.168.1.10' \
  --data-urlencode 'port=1883' \
  --data-urlencode 'name=kitchen-omg' \
  --data-urlencode 'ota=mySecret123' \
  --data-urlencode 'topic=home/' \
  http://192.168.4.1/wifisave