OpenEVSE Developers Guide

July 7, 2026 · View on GitHub

This guide describes the MQTT API implemented by the OpenEVSE WiFi gateway firmware (ESP32, v4.x and later). It covers device discovery, the topics the charging station publishes, the command topics it subscribes to, RAPI passthrough over MQTT, and the integration topics used for solar PV divert, current shaping and vehicle data.

The companion HTTP API is documented in the OpenEVSE WiFi API reference (api.yml). The MQTT command topics accept the same JSON payloads as the equivalent HTTP endpoints, so the two APIs can be used interchangeably.

Prerequisites

  • OpenEVSE / EmonEVSE charging station with the ESP32 WiFi gateway (firmware v4.x or later)
  • Gateway connected to a network (WiFi station mode or wired Ethernet)
  • An MQTT broker reachable from the gateway, e.g. Mosquitto, emonPi, or a cloud broker such as AWS IoT Core
  • Plain MQTT (default port 1883) and MQTT over TLS (MQTTS, default port 8883) are both supported

The examples in this guide use the mosquitto command line clients (mosquitto_pub / mosquitto_sub).

MQTT setup

Using the web interface:

  1. Browse to the IP address or hostname of the OpenEVSE gateway (e.g. http://openevse-xxxx.local)
  2. Open the Services tab
  3. Tick Enable MQTT
  4. Enter the broker hostname or IP address, and port
  5. (Optional) Enter the broker username and password
  6. (Optional) Change the base-topic OpenEVSE publishes to (default: the device hostname, e.g. openevse-7b2c)
  7. Save; the status should change to Connected: Yes within a few seconds

MQTT can also be configured programmatically via the HTTP API (POST /config) or, once connected, via the <base-topic>/config/set MQTT topic. The relevant configuration keys are listed in MQTT configuration reference.

Note: The MQTT settings are pre-populated with the OpenEnergyMonitor emonPi default MQTT credentials. If you are posting to an emonPi broker and want the data to appear in Emoncms, use emon/<name> as the base-topic.

Connection behaviour

PropertyBehaviour
Client IDThe device hostname (openevse-xxxx by default)
Protocolmqtt (plain TCP) or mqtts (TLS), selected by the mqtt_protocol config key
AuthenticationOptional username/password (mqtt_user / mqtt_pass)
TLS server verificationEnabled by default; can be disabled with mqtt_reject_unauthorized: false (not recommended)
TLS client certificateOptional; upload a certificate/key via the HTTP certificates API and reference it with mqtt_certificate_id
ReconnectAutomatic, attempted every 5 seconds while the network is up and MQTT is enabled
Last Will & TestamentRetained disconnected message on the announce topic (see below)

On (re)connection the firmware publishes a retained announce message, subscribes to all of its command topics, and re-publishes its full retained state (config, claim, override, schedule, limit).

Device discovery and Last Will (announce topic)

At startup the following message is published retained to the announce topic, openevse/announce/xxxx by default, where xxxx is the last 4 characters of the device ID (configurable via mqtt_announce_topic):

{
  "state": "connected",
  "id": "c44f330dxxad",
  "name": "openevse-7b2c",
  "mqtt": "openevse-7b2c",
  "http": "http://192.168.1.43/"
}
  • id — the unique device ID
  • name — the device hostname
  • mqtt — the base-topic this device publishes to (use this to find its status topics)
  • http — the URL of the device's HTTP API / web interface

To discover all OpenEVSE devices on a broker, subscribe with a wildcard:

mosquitto_sub -h broker.local -t 'openevse/announce/#' -v

The same topic is registered as the connection's Last Will & Testament. If the device disconnects ungracefully the broker publishes (retained):

{"state": "disconnected", "id": "c44f330dxxad", "name": "openevse-7b2c"}

Because both messages are retained, the announce topic always reflects the device's last known connection state and can be used as an availability topic.

Published topics — status values

Status values are published as individual sub-topics of the base-topic, one value per topic:

<base-topic>/<name> <value>

Publishing is event driven: values are published when the gateway polls the EVSE controller and the data changes (typically every few seconds while charging), not on a fixed 30 second timer. Messages are published non-retained by default; set the mqtt_retained config key to true to publish these status values with the retained flag.

Electrical and sensor values

TopicDescription
<base>/ampMeasured charge current in milliamps
<base>/voltageVoltage in volts (measured, or configured/MQTT-supplied value)
<base>/powerCharge power in watts
<base>/frequencyAC line frequency in 100ths of Hz, e.g. 5000 = 50.00 Hz (only on controllers that measure it)
<base>/pilotPilot current advertised to the vehicle, in amps
<base>/max_currentEffective maximum charge current in amps (after claims/limits)
<base>/tempPrimary temperature reading in 10ths of °C (e.g. 247 = 24.7 °C), false if not valid
<base>/temp_maxHighest of the available temperature sensors, 10ths of °C
<base>/temp1<base>/temp3Individual temperature sensors (DS3232, MCP9808, TMP007), 10ths of °C, false if not fitted
<base>/srssiWiFi signal strength (RSSI, dBm)
<base>/freeramFree heap memory of the gateway, bytes

Charge state

TopicDescription
<base>/stateNumeric EVSE state (see table below)
<base>/statusEVSE service state as a string: active or disabled
<base>/flagsEVSE controller flags bitmask
<base>/vehicle1 if a vehicle is connected, 0 otherwise
<base>/colourCurrent LCD/LED colour code
<base>/manual_override1 if a manual override is active, 0 otherwise
<base>/evse_connected1 if the gateway has serial communication with the EVSE controller
<base>/divertmodeDivert mode: 1 = normal, 2 = eco (solar divert)
<base>/rfid_authLast authenticated RFID tag (only when RFID is enabled)

EVSE state values (<base>/state) follow the OpenEVSE controller states:

ValueState
0Starting
1Not connected (ready)
2Vehicle connected
3Charging
4–11Error states (vent required, diode check failed, GFCI fault, no earth ground, stuck relay, GFCI self-test failed, over temperature, over current)
254Sleeping
255Disabled

Session and energy values

TopicDescription
<base>/session_elapsedElapsed time of the current charge session, seconds
<base>/session_energyEnergy delivered in the current session, Wh
<base>/total_energyLifetime total energy, kWh
<base>/total_dayEnergy today, kWh
<base>/total_weekEnergy this week, kWh
<base>/total_monthEnergy this month, kWh
<base>/total_yearEnergy this year, kWh
<base>/total_switchesTotal number of relay switch cycles
<base>/time / <base>/local_timeCurrent time (UTC / local, ISO 8601)
<base>/offsetTimezone offset
<base>/uptimeGateway uptime, seconds

Deprecated (will be removed in a future release — use the session_*/total_* topics instead): <base>/elapsed (seconds), <base>/wattsec (session energy in watt-seconds), <base>/watthour (total energy in Wh).

Vehicle and home battery values

When vehicle or home-battery data is fed into the gateway (via MQTT input topics, HTTP or Tesla API), it is re-published on:

TopicDescription
<base>/battery_levelVehicle state of charge, %
<base>/battery_rangeVehicle range (km or miles, per mqtt_vehicle_range_miles)
<base>/time_to_full_chargeVehicle time to full charge, seconds
<base>/vehicle_charge_limitVehicle charge limit, %
<base>/home_battery_socHome/storage battery state of charge, %
<base>/home_battery_powerHome/storage battery power, W

Solar divert and current shaper values

When divert mode is enabled, divert status is published on <base>/grid_ie or <base>/solar (echo of the last received input value), plus <base>/charge_rate, <base>/available_current, <base>/smoothed_available_current, <base>/divert_active, <base>/trigger_current and <base>/min_charge_end as the divert algorithm updates. When the current shaper is enabled its status is published on <base>/shaper (0/1), <base>/shaper_live_pwr, <base>/shaper_smoothed_live_pwr, <base>/shaper_max_pwr and <base>/shaper_cur.

Published topics — retained JSON state

In addition to the individual status values, the firmware maintains a set of retained JSON documents (always retained, regardless of mqtt_retained). Each is re-published whenever the underlying state changes — including changes made via the HTTP API or web UI — so subscribing to these topics gives you the current state immediately plus live updates:

TopicContent
<base>/configFull device configuration as a JSON object (secrets such as passwords are redacted)
<base>/config_versionConfiguration version counter
<base>/claimThe current MQTT-service claim, or {"state":"null"} when none
<base>/overrideThe current manual override, or {"state":"null"} when none
<base>/scheduleThe charge scheduler configuration
<base>/limitThe active charge limit, or an empty/none limit when not set

Command topics (subscribed by OpenEVSE)

All commands are sub-topics of the base-topic. JSON payloads use exactly the same schemas as the HTTP API — the linked reference documentation applies to both.

TopicPayloadAction
<base>/override/setJSON override propertiesSet/update the manual override
<base>/override/settoggleToggle the manual override (acts like pressing the button)
<base>/override/setclearClear the manual override
<base>/claim/setJSON claim propertiesMake/update the MQTT service claim (same priority as the HTTP client claim)
<base>/claim/setreleaseRelease the MQTT service claim
<base>/schedule/setJSON schedule eventsSet/update scheduled charge events
<base>/schedule/clearevent id (integer)Remove one schedule event
<base>/limit/setJSON limit propertiesSet a session limit (type: time, energy, soc or range)
<base>/limit/setclearClear the session limit
<base>/config/setJSON config object (any subset of config keys)Update device configuration
<base>/divertmode/set1 or 2Set divert mode: 1 = normal, 2 = eco
<base>/shaper/set0 or 1Temporarily disable (0) / enable (1) the current shaper (does not survive a reboot)
<base>/restart{"device":"gateway"} or {"device":"evse"}Restart the WiFi gateway or the EVSE controller
<base>/rapi/in/$CC …see RAPI over MQTTSend a raw RAPI command to the EVSE controller

Notes:

  • After each command the corresponding retained state topic (<base>/override, <base>/claim, <base>/schedule, <base>/limit, <base>/config) is re-published, which serves as the acknowledgement.
  • Claim and override properties can be set incrementally: a JSON payload containing only some fields updates just those fields. To remove a single property, send "clear" as its value, e.g. {"charge_current": "clear"}.
  • Property values follow the Properties schema: state (active/disabled), charge_current (A), max_current (A), auto_release (bool).

RAPI over MQTT

RAPI is the low-level serial command protocol of the OpenEVSE controller. The gateway forwards RAPI commands received over MQTT to the controller and publishes the response.

Important: Prefer the higher-level topics above (claim, override, limit, …) where they exist — they cooperate with the gateway's claims system, whereas raw RAPI commands bypass it. See docs/rapi.md for details and the full command reference; the complete command list lives in rapi_proc.h in the OpenEVSE controller firmware. Some potentially unsafe commands are blocked by the gateway.

Request:

<base-topic>/rapi/in/$<command> [payload = parameters]

The command is taken from the topic (everything from the $); if the message payload is non-empty it is appended as the command's parameters.

Response — the raw RAPI response string (e.g. $OK 32 $0001^{2}$2) is published to:

<base-topic>/rapi/out

Examples (base-topic openevse-7b2c):

# Watch for responses
mosquitto_sub -h broker.local -t 'openevse-7b2c/rapi/out'

# Get the current charge current setting ($GC = get current capacity)
mosquitto_pub -h broker.local -t 'openevse-7b2c/rapi/in/$GC' -n

# Set charge current to 13 A ($SC), parameters in the payload
mosquitto_pub -h broker.local -t 'openevse-7b2c/rapi/in/$SC' -m '13'

Responses are published to the single shared rapi/out topic in the order the commands complete; there is no per-request correlation ID, so serialise your requests if you need to match responses to commands.

Integration input topics (topics you publish, OpenEVSE consumes)

These are your topics — full topic paths configured in the OpenEVSE settings (they are not under the base-topic). The gateway subscribes to them and consumes the values. All payloads are plain numbers.

Config keyPayloadUsed for
mqtt_solarSolar PV generation, watts (positive)Solar divert (when divert_type = solar)
mqtt_grid_ieGrid import/export, watts; positive = importing, negative = exportingSolar divert (when divert_type = grid import/export)
mqtt_live_pwrSite live power, wattsCurrent shaper (may be the same topic as mqtt_grid_ie)
mqtt_vrmsAC voltage, voltsVoltage used for power/energy calculation
mqtt_vehicle_socVehicle state of charge, %Vehicle status / SoC limits
mqtt_vehicle_rangeVehicle range (km, or miles if mqtt_vehicle_range_miles)Vehicle status / range limits
mqtt_vehicle_etaTime to full charge, secondsVehicle status
mqtt_vehicle_charge_limitVehicle charge limit, %Vehicle status
mqtt_home_battery_socHome battery state of charge, %Display only
mqtt_home_battery_powerHome battery power, WDisplay only

Notes:

  • Divert topics are only subscribed when divert is enabled (divert_enabled: true) and the matching divert_type is selected; the shaper topic requires current_shaper_enabled: true.
  • Vehicle topics are only acted on when vehicle_data_src is set to 2 (MQTT). (0 = none, 1 = Tesla API, 2 = MQTT, 3 = HTTP.)
  • Solar divert example: a house exporting 1077 W to the grid should publish -1077 to the grid I/E topic (or 1077 plus house load to the solar topic). OpenEVSE then adjusts the charge rate to consume the surplus. See the divert simulator for the algorithm details.

MQTT configuration reference

All keys below can be set via the web UI, POST /config (HTTP) or <base>/config/set (MQTT), and are visible in the retained <base>/config topic. See models/Config.yaml for the full config schema.

KeyTypeDefaultDescription
mqtt_enabledboolfalseEnable the MQTT service
mqtt_protocolstringmqttmqtt or mqtts (TLS). Read-only companion mqtt_supported_protocols lists ["mqtt","mqtts"]
mqtt_serverstringemonpiBroker hostname or IP
mqtt_portint1883Broker port (typically 8883 for MQTTS)
mqtt_userstringemonpiUsername (empty for anonymous)
mqtt_passstringemonpimqtt2016Password (write-only; redacted in config output)
mqtt_topicstringhostnameBase-topic for all publish/subscribe topics
mqtt_announce_topicstringopenevse/announce/<id>Discovery/LWT topic
mqtt_retainedboolfalsePublish status values with the retained flag
mqtt_reject_unauthorizedbooltrueVerify the broker's TLS certificate (MQTTS)
mqtt_certificate_idstring""ID of a client certificate/key pair for mutual TLS (see the HTTP certificates API)
mqtt_solarstring""Solar generation input topic
mqtt_grid_iestringemon/emonpi/power1Grid import/export input topic
mqtt_vrmsstringemon/emonpi/vrmsVoltage input topic
mqtt_live_pwrstring""Live power input topic for the current shaper
mqtt_vehicle_socstring""Vehicle SoC input topic
mqtt_vehicle_rangestring""Vehicle range input topic
mqtt_vehicle_etastring""Vehicle time-to-full-charge input topic
mqtt_vehicle_charge_limitstring""Vehicle charge limit input topic
mqtt_vehicle_range_milesboolfalseInterpret/display vehicle range in miles
mqtt_home_battery_socstring""Home battery SoC input topic
mqtt_home_battery_powerstring""Home battery power input topic
vehicle_data_srcint0Vehicle data source: 0 none, 1 Tesla, 2 MQTT, 3 HTTP

Worked examples

All examples assume broker broker.local and base-topic openevse-7b2c. Add -u <user> -P <pass> as needed.

Watch everything the device publishes:

mosquitto_sub -h broker.local -t 'openevse-7b2c/#' -v

Start charging now (manual override):

mosquitto_pub -h broker.local -t 'openevse-7b2c/override/set' -m '{"state":"active"}'

Stop/pause charging:

mosquitto_pub -h broker.local -t 'openevse-7b2c/override/set' -m '{"state":"disabled"}'

Charge at 16 A while the override is active:

mosquitto_pub -h broker.local -t 'openevse-7b2c/override/set' -m '{"state":"active","charge_current":16}'

Clear the override (return to normal/scheduled behaviour):

mosquitto_pub -h broker.local -t 'openevse-7b2c/override/set' -m 'clear'

Limit this session to 10 kWh, then auto-release:

mosquitto_pub -h broker.local -t 'openevse-7b2c/limit/set' \
  -m '{"type":"energy","value":10000,"auto_release":true}'

Cap the current via a service claim (cooperates with other services rather than overriding them):

mosquitto_pub -h broker.local -t 'openevse-7b2c/claim/set' -m '{"max_current":20}'
# ...later
mosquitto_pub -h broker.local -t 'openevse-7b2c/claim/set' -m 'release'

Schedule charging between 07:00 and 10:00 every day:

mosquitto_pub -h broker.local -t 'openevse-7b2c/schedule/set' -m '[
  {"id":1,"state":"active","time":"07:00:00","days":["monday","tuesday","wednesday","thursday","friday","saturday","sunday"]},
  {"id":2,"state":"disabled","time":"10:00:00","days":["monday","tuesday","wednesday","thursday","friday","saturday","sunday"]}]'

Feed grid import/export data for solar divert (from your energy monitor, every few seconds):

mosquitto_pub -h broker.local -t 'emon/emonpi/power1' -m '-1077'   # exporting 1077 W

Switch divert to eco mode:

mosquitto_pub -h broker.local -t 'openevse-7b2c/divertmode/set' -m '2'

Restart the gateway:

mosquitto_pub -h broker.local -t 'openevse-7b2c/restart' -m '{"device":"gateway"}'

Connecting to cloud IoT services

For TLS brokers select the mqtts protocol and port 8883 (or as required by the service). If the service uses client-certificate authentication, upload the certificate and private key via the HTTP certificates API and set mqtt_certificate_id.

AWS IoT Core

Example policy for AWS IoT Core:

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "iot:Connect",
      "Resource": "arn:aws:iot:eu-west-2:489072314047:client/openevse-*"
    },
    {
      "Effect": "Allow",
      "Action": "iot:Subscribe",
      "Resource": "arn:aws:iot:eu-west-2:489072314047:topicfilter/openevse/*"
    },
    {
      "Effect": "Allow",
      "Action": [
        "iot:Receive",
        "iot:Publish",
        "iot:RetainPublish"
      ],
      "Resource": "arn:aws:iot:eu-west-2:489072314047:topic/openevse/*"
    }
  ]
}

Home Assistant

The firmware does not publish Home Assistant MQTT auto-discovery messages. For Home Assistant, use the native OpenEVSE integration (HTTP based), or define MQTT sensors/switches manually against the topics documented in this guide. The retained announce topic works well as an MQTT availability topic.

Additional resources

License

This document is part of the OpenEVSE project and is released under the Creative Commons Attribution-ShareAlike (CC BY-SA) license. The OpenEVSE firmware source code is released under the GNU General Public License v3.