For advanced users

Advanced integration

Local HTTP and MQTT integration for custom clients, broker-based flows and charger automation.

HTTP API MQTT RAPI
01

Advanced integration

The integration documentation gathered into one dedicated guide page.

For advanced users: This document describes the local integration surfaces exposed by the charger firmware for power users who want to build their own client or automation.

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 of Wired, STA, AP, or STA+AP.
  • wifi_client_connected: 1 when the station interface is connected, otherwise 0.
  • eth_connected: 1 when Ethernet is connected, otherwise 0.
  • net_connected: 1 when any active network path is connected, otherwise 0.
  • ipaddress: current local IP address as a string.
  • mqtt_connected: 1 when the local MQTT client is connected to its broker, otherwise 0.
  • 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: 1 when the gateway considers the EVSE controller connected, otherwise 0.
  • nofos_connected: 1 when the nofos MQTT path is connected, otherwise 0.
  • amp: measured phase-1 current in amps.
  • amp1: same value as amp.
  • 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, or false if the sensor is not valid.
  • temp4: optional MCP9808 temperature value, or false if 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: 1 while a firmware OTA update is running, otherwise 0.
  • time: current UTC timestamp formatted as ISO 8601, for example 2026-03-10T12:34:56Z.
  • offset: current UTC offset string from strftime("%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 of reset_reason, for example poweron, software, panic, or brownout.
  • 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_protocols
  • http_supported_protocols
  • nofos_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: true when the local MQTT client is enabled.
  • mqtt_reject_unauthorized: true when MQTT TLS certificate validation is enforced.
  • sntp_enabled: true when SNTP time sync is enabled.
  • pause_uses_disabled: true when pause operations use $FD instead of $FS.
  • mqtt_protocol: MQTT transport string. Currently mqtt or mqtts.

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:

  • 200 with {"msg":"done"} on success
  • 400 with {"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 send
  • json: 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, 1 to 10

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:

  1. Read GET /status for live state
  2. Read GET /config once at startup if your client needs capability discovery
  3. Write POST /config for supported settings
  4. 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 $GD in 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. V sets a volatile current limit. M stores 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. 0 disables the feature and 1 enables it. Supported feature IDs documented in this repo are B, D, E, F, G, R, T, and V.
  • $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 from nofos_mqtt.cpp: 1 locks, 0 unlocks.
  • $SB: clear the hard amperage limit stored in controller EEPROM. This is explicitly described in nofos_mqtt.cpp as "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:

  • mqtt
  • mqtts

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=true enforces certificate validation for mqtts
  • The legacy POST /savemqtt endpoint cannot set mqtt_vrms or mqtt_announce_topic
  • After saving MQTT config, the firmware restarts the MQTT connection automatically

MQTT topics used by the charger

Assume:

  • mqtt_topic = charger/nofos-1234
  • mqtt_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/amp
  • charger/nofos-1234/voltage
  • charger/nofos-1234/state
  • charger/nofos-1234/pilot
  • charger/nofos-1234/wh

The main periodic publish happens every 30 seconds and includes the standard live EVSE fields such as:

  • amp, amp1, amp2, amp3
  • voltage, v1, v2, v3
  • pilot
  • wh
  • state
  • freeram
  • srssi

Additional event-driven fields may also be published, including:

  • charge_rate
  • available_current
  • smoothed_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:

  1. Configure MQTT through POST /config
  2. Read the retained payload on mqtt_announce_topic to discover the charger
  3. Subscribe to <mqtt_topic>/#
  4. 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 /config instead of the older /save... endpoints whenever possible