Advanced integration
Local HTTP and MQTT integration for custom clients, broker-based flows and charger automation.
Advanced integration
The integration documentation gathered into one dedicated guide page.
Scope
The charger exposes two local integration mechanisms:
- A local HTTP server on port
80 - An MQTT client that connects from the charger to your broker
The HTTP API is the easiest place to start. MQTT is better when you want a broker-centric integration with telemetry pushed out automatically and commands delivered through topics.
Base URL and authentication
Use the charger's local hostname or IP address:
http://nofos-<id>.local/http://<charger-ip>/
Examples in this guide use:
http://<charger-ip>/
If web credentials have been configured, the local HTTP server requires HTTP authentication for both API requests and static pages. When the charger is running in AP-only mode, authentication is not enforced.
The local HTTP handlers also send permissive CORS headers:
Access-Control-Allow-Origin: *Access-Control-Allow-Headers: *Access-Control-Allow-Methods: *
Integration-first HTTP endpoints
These are the endpoints most useful for a custom integration.
GET /status
Returns the charger's current live state as JSON.
Typical fields include:
- Network and connectivity:
mode,wifi_client_connected,eth_connected,net_connected,ipaddress - Service state:
mqtt_connected,nofos_connected - Runtime metrics:
free_heap,largest_free_block,min_free_heap - EVSE telemetry:
amp,amp1,amp2,amp3,voltage,v1,v2,v3,pilot,wh,state,temp1,temp4,srssi - Counters:
elapsed,wattsec,watthour,gfcicount,nogndcount,stuckcount - Time:
time,offset - OTA/debug state:
ota_update,comm_sent,comm_success,rapi_connected
Example:
curl http://<charger-ip>/status
/status field reference
Fields are included from multiple subsystems. Some optional fields are only present when the related subsystem has valid data.
mode: active network mode. One ofWired,STA,AP, orSTA+AP.wifi_client_connected:1when the station interface is connected, otherwise0.eth_connected:1when Ethernet is connected, otherwise0.net_connected:1when any active network path is connected, otherwise0.ipaddress: current local IP address as a string.mqtt_connected:1when the local MQTT client is connected to its broker, otherwise0.free_heap: current free heap in bytes.largest_free_block: current largest free contiguous heap block in bytes.min_free_heap: minimum free heap seen since boot in bytes.comm_sent: number of RAPI commands sent to the EVSE controller.comm_success: number of successful RAPI exchanges with the EVSE controller.rapi_connected:1when the gateway considers the EVSE controller connected, otherwise0.nofos_connected:1when the nofos MQTT path is connected, otherwise0.amp: measured phase-1 current in amps.amp1: same value asamp.amp2: measured phase-2 current in amps.amp3: measured phase-3 current in amps.voltage: measured phase-1 voltage.pilot: current advertised pilot current in amps.wh: accumulated energy in watt-hours.v1: measured phase-1 voltage.v2: measured phase-2 voltage.v3: measured phase-3 voltage.temp1: external temperature value, orfalseif the sensor is not valid.temp4: optional MCP9808 temperature value, orfalseif unavailable. Only present when that sensor support is compiled in.state: current EVSE state code.freeram: free heap in bytes from the EVSE telemetry block.srssi: Wi-Fi RSSI in dBm.elapsed: charging-session elapsed time in seconds.wattsec: session energy in watt-seconds.watthour: accumulated energy total in watt-hours.gfcicount: GFCI trip counter.nogndcount: no-ground trip counter.stuckcount: stuck-relay trip counter.charge_rate: current charge-rate value in amps.ota_update:1while a firmware OTA update is running, otherwise0.time: current UTC timestamp formatted as ISO 8601, for example2026-03-10T12:34:56Z.offset: current UTC offset string fromstrftime("%z").crash_seq: sequence number of the most recent stored crash log record.boot_count: total boot count recorded in crash log storage.reset_reason: numeric ESP reset reason code for the last reboot.reset_reason_str: string form ofreset_reason, for examplepoweron,software,panic, orbrownout.prev_uptime_ms: last heartbeat uptime from the previous boot, in milliseconds.prev_free_heap: last recorded free heap from the previous boot, in bytes.prev_largest_free_block: last recorded largest free block from the previous boot, in bytes.prev_min_free_heap: last recorded minimum free heap from the previous boot, in bytes.prev_unix_time: last recorded Unix time from the previous boot.crash_recorded_unix_time: Unix time when the current crash log record was stored.
GET /config
Returns the current configuration as JSON.
This includes both general settings and supported option lists such as:
mqtt_supported_protocolshttp_supported_protocolsnofos_network_profiles
The response is intended for machine consumption. Secret values are hidden in the serialized output.
Example:
curl http://<charger-ip>/config
/config field reference
GET /config returns:
- Controller and gateway metadata added by
handleConfigGet() - Static capability lists
- Serialized persistent configuration fields from
app_config.cpp
Some secret fields may be blank or redacted in the response because the endpoint is serialized with secret-hiding enabled.
Controller and gateway metadata
firmware: EVSE controller firmware string reported over RAPI.protocol: EVSE controller RAPI protocol version string.espflash: flash chip size in bytes.identifier: long device identifier.version: gateway firmware version string.diodet: diode-check enabled flag from the EVSE controller.gfcit: GFCI self-test enabled flag from the EVSE controller.groundt: ground-check enabled flag from the EVSE controller.relayt: stuck-relay-check enabled flag from the EVSE controller.ventt: vent-check enabled flag from the EVSE controller.tempt: temperature-check enabled flag from the EVSE controller.service: active service level as reported by the controller.scale: current-sensor scale value from$GA.offset: current-sensor offset value from$GA.amplimit: current ampacity-related limit value read from token 2 of$GC. In the upstream OpenEVSE comments this token is the hardware max current.
Capability lists
mqtt_supported_protocols: array of supported MQTT transport strings. Currently["mqtt","mqtts"].http_supported_protocols: array of supported HTTP transport strings. Currently["http","https"].nofos_network_profiles: array of supported nofos network profile labels. Currently["Disabled","GSM only","GSM with fallback to WiFi","WiFi only","WiFI with fallback to GSM"].
Persistent configuration fields
ssid: configured Wi-Fi SSID.pass: configured Wi-Fi password. Secret field.www_username: HTTP authentication username for the local web server.www_password: HTTP authentication password. Secret field.hostname: configured device hostname.sntp_hostname: configured SNTP server hostname.time_zone: configured POSIX or extended timezone string.mqtt_server: MQTT broker hostname or IP.mqtt_port: MQTT broker port.mqtt_topic: MQTT base topic used for telemetry and commands.mqtt_user: MQTT username.mqtt_pass: MQTT password. Secret field.mqtt_vrms: external MQTT topic used as line voltage input.mqtt_announce_topic: retained announce topic used for connect/disconnect presence payloads.nofos_network_profile: selected nofos network profile ID.flags: raw bitfield storing multiple service and behavior flags.mqtt_enabled:truewhen the local MQTT client is enabled.mqtt_reject_unauthorized:truewhen MQTT TLS certificate validation is enforced.sntp_enabled:truewhen SNTP time sync is enabled.pause_uses_disabled:truewhen pause operations use$FDinstead of$FS.mqtt_protocol: MQTT transport string. Currentlymqttormqtts.
POST /config
Updates configuration with a JSON body.
This is the preferred write interface for custom integrations because it supports partial updates and exposes more settings than the older form endpoints.
Common fields:
- HTTP auth:
www_username,www_password - MQTT:
mqtt_enabled,mqtt_protocol,mqtt_server,mqtt_port,mqtt_topic,mqtt_user,mqtt_pass,mqtt_reject_unauthorized,mqtt_vrms,mqtt_announce_topic - Charge behavior:
pause_uses_disabled - Time/network:
sntp_enabled,time_zone,hostname,sntp_hostname,nofos_network_profile
Example: enable MQTT
curl -X POST http://<charger-ip>/config \
-H "Content-Type: application/json" \
-d '{
"mqtt_enabled": true,
"mqtt_protocol": "mqtt",
"mqtt_server": "192.168.1.10",
"mqtt_port": 1883,
"mqtt_topic": "charger/nofos-1234",
"mqtt_user": "mqtt-user",
"mqtt_pass": "mqtt-pass",
"mqtt_reject_unauthorized": true
}'
Responses:
200with{"msg":"done"}on success400with{"msg":"Could not parse JSON"}on invalid JSON
GET /r and GET /rapi
Sends a RAPI command to the EVSE controller.
Use query parameters:
rapi: the command to sendjson: optional;1,true, or present with no value returns JSON instead of HTML
Example:
curl "http://<charger-ip>/r?json=1&rapi=\$GS"
Successful JSON response:
{"cmd":"$GS","ret":"$OK ..."}
Error JSON response:
{"cmd":"$GS","error":"RAPI_RESPONSE_TIMEOUT"}
Use this endpoint for low-level EVSE commands when a higher-level config field does not exist.
GET /crashlog
Returns recent crash history as JSON.
Optional query parameter:
count: number of events to return,1to10
Example:
curl "http://<charger-ip>/crashlog?count=5"
GET /scan
Returns visible Wi-Fi networks as JSON.
POST /apoff
Turns the access point off shortly after the request returns.
GET /reset
Resets stored configuration and reboots.
GET /restart
Reboots without wiping configuration.
GET /debug
Returns the buffered debug console as plain text.
GET /evse
Returns the buffered EVSE serial console as plain text.
Recommended HTTP usage pattern
For an external integration, the practical pattern is:
- Read
GET /statusfor live state - Read
GET /configonce at startup if your client needs capability discovery - Write
POST /configfor supported settings - Use
GET /r?json=1&rapi=...only for controller commands that are not represented in/config
RAPI command reference for GET /r and GET /rapi
GET /r and GET /rapi forward a raw RAPI command string to the OpenEVSE controller. The firmware does not hardcode an allowlist in the HTTP handler; it passes through whatever you supply. The list below documents the RAPI commands that are explicitly used, wrapped, or special-cased inside this repository.
Where a command is only inferred from usage and the repository does not include the upstream protocol description, that is called out explicitly.
Query and status commands
$GV: get EVSE firmware version and RAPI protocol version.$GS: get EVSE status. Used to read current state and elapsed session time.$GT: get controller RTC time.$GG: get charging current and voltage.$GP: get temperature readings.$GU: get energy usage counters.$GF: get fault counters.$GE: get EVSE settings, including pilot current and flags.$GC: get current-capacity information, including minimum, pilot, configured max, and hardware max.$GD: get the delay timer schedule. This firmware also emulates$GDin the HTTP handler when the underlying controller returns$NK.$GA: get current-sensor calibration values. Inference from code: token 1 is the current scale and token 2 is the current offset.
Configuration and control commands
$SC <amps> [V|M]: set current capacity.Vsets a volatile current limit.Mstores a maximum limit in EEPROM. Without a suffix, the firmware treats it as a compatibility fallback for older controllers.$SV <millivolts>: set voltage used for power calculations.$S1 <yy> <mm> <dd> <hh> <mm> <ss>: set controller RTC time.$ST <start_hour> <start_minute> <end_hour> <end_minute>: set the delay timer.$FE: enable charging / wake the EVSE.$FS: put the EVSE into sleep mode.$FD: disable the EVSE.$FR: restart the EVSE controller.$FF <feature> <0|1>: enable or disable a controller feature.0disables the feature and1enables it. Supported feature IDs documented in this repo areB,D,E,F,G,R,T, andV.$F0 <0|1>: disable or enable LCD display updates.$FB <color>: set LCD backlight color.$FP <x> <y> <text>: draw text on the LCD.$SY <interval> <current>: enable heartbeat supervision.$SY: send a heartbeat pulse.$SY 165: acknowledge a missed heartbeat pulse.$F1: emulate a front-panel button press.$S4 0|1: toggle controller lock state. Inference fromnofos_mqtt.cpp:1locks,0unlocks.$SB: clear the hard amperage limit stored in controller EEPROM. This is explicitly described innofos_mqtt.cppas "Wipe hard amperage limit in EEPROM."
Practical examples
Get controller version:
curl "http://<charger-ip>/r?json=1&rapi=\$GV"
Get current EVSE state:
curl "http://<charger-ip>/r?json=1&rapi=\$GS"
Get current-capacity information:
curl "http://<charger-ip>/r?json=1&rapi=\$GC"
Set the current limit to 13 A:
curl "http://<charger-ip>/r?json=1&rapi=\$SC%2013"
Disable the EVSE:
curl "http://<charger-ip>/r?json=1&rapi=\$FD"
Restart the EVSE controller:
curl "http://<charger-ip>/r?json=1&rapi=\$FR"
MQTT overview
The charger is an MQTT client. It does not run a broker locally. You point it at your own broker and it will:
- Connect to the broker
- Publish charger state and events
- Subscribe to selected command and telemetry topics
Supported protocols:
mqttmqtts
MQTT setup
The preferred setup path is POST /config.
Minimum configuration:
{
"mqtt_enabled": true,
"mqtt_protocol": "mqtt",
"mqtt_server": "192.168.1.10",
"mqtt_port": 1883,
"mqtt_topic": "charger/nofos-1234",
"mqtt_user": "mqtt-user",
"mqtt_pass": "mqtt-pass",
"mqtt_reject_unauthorized": true
}
Notes:
mqtt_reject_unauthorized=trueenforces certificate validation formqtts- The legacy
POST /savemqttendpoint cannot setmqtt_vrmsormqtt_announce_topic - After saving MQTT config, the firmware restarts the MQTT connection automatically
MQTT topics used by the charger
Assume:
mqtt_topic = charger/nofos-1234mqtt_announce_topic = openevse/announce/abcd
Outbound topics published by the charger
Announcement topic
On connect, the charger publishes a retained JSON payload to mqtt_announce_topic:
{
"state": "connected",
"id": "<device-id>",
"name": "<hostname>",
"mqtt": "charger/nofos-1234",
"http": "http://<charger-ip>/"
}
The charger also sets a retained last-will message on the same topic:
{
"state": "disconnected",
"id": "<device-id>",
"name": "<hostname>"
}
Telemetry and event topics
For each JSON field in an emitted event document, the firmware publishes one MQTT message to:
<mqtt_topic>/<field>
Examples:
charger/nofos-1234/ampcharger/nofos-1234/voltagecharger/nofos-1234/statecharger/nofos-1234/pilotcharger/nofos-1234/wh
The main periodic publish happens every 30 seconds and includes the standard live EVSE fields such as:
amp,amp1,amp2,amp3voltage,v1,v2,v3pilotwhstatefreeramsrssi
Additional event-driven fields may also be published, including:
charge_rateavailable_currentsmoothed_available_current
Inbound topics subscribed to by the charger
RAPI command input
The charger subscribes to:
<mqtt_topic>/rapi/in/#
To send a RAPI command, publish to a topic that ends with the command name beginning with $.
Examples:
charger/nofos-1234/rapi/in/$GS
charger/nofos-1234/rapi/in/$SC
If the command needs an argument, put the argument in the payload.
Example: set charge current to 13 A
Topic:
charger/nofos-1234/rapi/in/$SC
Payload:
13
The charger publishes the RAPI response to:
<mqtt_topic>/rapi/out
MQTT examples
Subscribe to everything for one charger:
mosquitto_sub -h 192.168.1.10 -u mqtt-user -P mqtt-pass -t 'charger/nofos-1234/#'
Request EVSE state with RAPI:
mosquitto_pub -h 192.168.1.10 -u mqtt-user -P mqtt-pass \
-t 'charger/nofos-1234/rapi/in/$GS'
Then read the response:
mosquitto_sub -h 192.168.1.10 -u mqtt-user -P mqtt-pass \
-t 'charger/nofos-1234/rapi/out'
Set current limit to 13 A:
mosquitto_pub -h 192.168.1.10 -u mqtt-user -P mqtt-pass \
-t 'charger/nofos-1234/rapi/in/$SC' \
-m '13'
Recommended MQTT usage pattern
For most broker-based integrations:
- Configure MQTT through
POST /config - Read the retained payload on
mqtt_announce_topicto discover the charger - Subscribe to
<mqtt_topic>/# - Use
<mqtt_topic>/rapi/in/$...when you need a controller command path through the broker
Practical recommendation
If you are building a new integration from scratch:
- Prefer HTTP for configuration and direct querying
- Prefer MQTT for pushed telemetry, event streams, and broker-driven automations
- Use
POST /configinstead of the older/save...endpoints whenever possible