openapi: 3.0.3 info: title: OpenEVSE WiFi API description: | The API for the OpenEVSE WiFi module ## Authentication Authentication is only enforced when an admin password is configured. With no password set (or while the device is in AP-only provisioning mode) every operation is open and none of the credentials below are needed. When a password is set, every operation except `/login`, `/logout` and `/emoncms/describe` requires **one** of: * **HTTP Basic** credentials (`Authorization` header) - intended for machine clients such as scripts and integrations. If the username is left blank in the configuration a default admin user is used. * A **session cookie** (`oevse_session`) obtained from [`POST /login`](#tag/Authentication) - intended for the browser UI. Sessions last 6 hours, or 30 days if `remember` was requested. Over plain HTTP, Basic credentials and the session cookie are sent without transport encryption. Use HTTPS, which the device serves once a certificate is configured, to protect them in transit. ### Authentication failures | Status | Meaning | |---|---| | `401` | No valid credentials were supplied. Clients that send `X-Requested-With: OpenEVSE` get a JSON body `{"msg":"auth"}`; any other client gets a `WWW-Authenticate` Basic challenge so browsers prompt for credentials. | | `429` | A *wrong* Basic password, or a failed `/login`, was presented while the brute-force throttle is active (`{"msg":"locked"}`). Correct credentials are never throttled, and the counter decays on its own. Requests with no credentials at all still get `401`. | | `403` | CSRF guard: a state-changing (non-`GET`) request authenticated by session cookie must also send `X-Requested-With: OpenEVSE`. Basic-auth clients are unaffected. A few `GET` endpoints also require this header and are documented on the operation. | version: '1.0' contact: email: jeremy@bigjungle.net name: Jeremy Poulter url: 'https://github.com/jeremypoulter/' license: name: Apache 2.0 url: 'http://www.apache.org/licenses/LICENSE-2.0.html' servers: - url: '{server}' variables: server: default: 'http://openevse.local' - url: 'http://localhost:8080' security: - {} - BasicAuth: [] - SessionCookie: [] paths: /status: get: operationId: getStatus summary: Get the EVSE status description: | The status endpoint can be called to get the status of the EVSE. While it is posible to poll this endpoint, the recomendatoin is to retrieve the initial state then use the [/ws](#statusUpdates) responses: '200': description: OK content: application/json: schema: $ref: ./models/Status.yaml examples: EVSE Status: value: mode: STA wifi_client_connected: 1 eth_connected: 0 net_connected: 1 srssi: -73 ipaddress: 192.168.1.43 emoncms_connected: 1 packets_sent: 22307 packets_success: 22290 mqtt_connected: 1 free_heap: 203268 comm_sent: 335139 comm_success: 335139 rapi_connected: 1 amp: 0 pilot: 32 max_current: 32 temp1: 282 temp2: -2560 temp3: -2560 state: 254 elapsed: 3473 session_energy: 25034 total_energy: 998 total_day: 23 total_week: 68 total_month: 126 total_year: 998 gfcicount: 0 nogndcount: 0 stuckcount: 0 divertmode: 1 solar: 390 grid_ie: 0 charge_rate: 7 divert_update: 0 ota_update: 0 time: '2020-05-12T17:53:48Z' offset: '+0000' tags: - Status post: operationId: postStatus summary: Update external data to EVSE status description: | The status endpoint can be called to post external data that should be updated by MQTT If MQTT is not an option, all external data needed can be updated from an HTTP POST request to /status endpoint. responses: '200': description: OK content: application/json: schema: type: object properties: voltage: type: integer description: live voltage in V shaper_live_pwr: type: integer description: total household live power in W solar: type: integer description: divert solar production in W grid_ie: type: integer description: divert grid -import/+export in W battery_level: type: integer description: vehicle soc in % battery_range: type: integer description: vehicle range time_to_full_charge: type: integer description: vehicle charge ETA x-examples: EVSE Status: voltage: 220 shaper_live_pwr: 3400 solar: 3000 grid_ie: 3000 battery_level: 85 battery_range: 230 time_to_full_charge: 1590 examples: EVSE Status: value: voltage: 220 shaper_live_pwr: 3400 solar: 3000 grid_ie: 3000 battery_level: 85 battery_range: 230 time_to_full_charge: 1590 tags: - Status /ws: get: operationId: statusUpdates summary: EVSE status updates description: | As the state changes on the EVSE a websocket frame will be sent over the socket. The frame will contain a JSON document conntaining only the updated state. responses: '200': description: OK content: application/json: schema: $ref: ./models/Status.yaml '400': description: Error tags: - Status /config: get: operationId: getConfig summary: Get the EVSE configuration description: | Retrieve the current WiFi and EVSE module configuration tags: - Config responses: '200': description: OK content: application/json: schema: $ref: ./models/Config.yaml examples: {} post: description: | Update the EVSE configuration operationId: updateConfig responses: '200': $ref: '#/components/responses/UpdateSuccessful' '400': $ref: '#/components/responses/BadRequest' requestBody: content: application/json: schema: $ref: ./models/Config.yaml examples: Update EmonCMS setting: value: emoncms_enabled: true emoncms_server: 'http://emoncms.org' emoncms_node: openevse-a7d4 emoncms_apikey: emoncmskey emoncms_fingerprint: '' Configure Solar divert: value: divert_type: 0 divert_enabled: true divert_attack_smoothing_time: 8 divert_decay_smoothing_time: 300 divert_min_charge_time: 20 Set normal charging mode: value: charge_mode: fast Set Eco mode: value: charge_mode: eco Configure Tesla credentials: value: tesla_enabled: true tesla_access_token: qts-1234....... tesla_refresh_token: abcd....... tesla_created_at: 1623358948 tesla_expires_in: 3888000 Select Tesla vehicle: value: tesla_vehicle_id: '2238974987235987' summary: Update the EVSE configuration tags: - Config /override: description: Manual override can be used to override a charging timer or to immediately start a charge if the EVSE is in sleeping state. get: responses: '200': description: Manual overide is active content: application/json: schema: $ref: ./models/Properties.yaml '404': $ref: '#/components/responses/NotFound' operationId: getManualOverride tags: - Manual Override summary: Get the Manual Override status description: Returns the current state of the manual override. post: description: | Set the manual override requestBody: content: application/json: schema: $ref: ./models/Properties.yaml examples: Force stop of charging: value: state: disabled example-1: value: state: active charge_current: 0 max_current: 0 auto_release: true responses: '200': description: OK content: application/json: schema: $ref: '#/components/schemas/Message' operationId: setManualOverride tags: - Manual Override summary: Set the manual override patch: description: Toggle the manual override responses: '200': description: OK operationId: toggleManualOverride tags: - Manual Override summary: Toggle the manual Override delete: description: Clears the manual override responses: '200': description: OK operationId: clearManualOverride tags: - Manual Override summary: Clear the manual override /claims: get: description: | List all claims made by EVSE clients. The response will be an array of EVSE claims. responses: '200': description: OK content: application/json: schema: type: array items: $ref: ./models/Claim.yaml operationId: listClaims tags: - Claims summary: List EVSE claims '/claims/{client}': get: description: | Get the claim information for a specific client. The response will be an EVSE claim. responses: '200': description: OK content: application/json: schema: $ref: ./models/Properties.yaml '404': $ref: '#/components/responses/NotFound' parameters: [] operationId: getClaim tags: - Claims summary: Get EVSE claim information post: description: Make/Update a claim requestBody: content: application/json: schema: $ref: ./models/Properties.yaml responses: '200': description: OK content: application/json: schema: $ref: '#/components/schemas/Message' '400': $ref: '#/components/responses/BadRequest' operationId: setClaim summary: Make/Update an EVSE claim tags: - Claims delete: description: Release a claim responses: '200': description: OK content: application/json: schema: $ref: '#/components/schemas/Message' '404': $ref: '#/components/responses/NotFound' operationId: releaseClaim summary: Release an EVSE claim tags: - Claims parameters: - schema: type: integer name: client in: path required: true description: 'The client ID, defined by [OpenEVSE](https://github.com/OpenEVSE/openevse_esp32_firmware/blob/master/src/evse_man.h#L28)' /schedule: get: summary: List schedule events description: This will get a complete list of events in the schedule responses: '200': description: List of the schedule events content: application/json: schema: type: array items: $ref: '#/components/schemas/ScheduleEvent' '400': $ref: '#/components/responses/BadRequest' operationId: listSchedule tags: - Schedule post: operationId: updateSchedule description: Perform multiple event updates responses: '201': description: item created '400': description: 'invalid input, object invalid' '409': description: an existing item already exists requestBody: content: application/json: schema: type: array items: $ref: '#/components/schemas/ScheduleEvent' examples: Single event: value: - id: 1 state: active time: '14:15:22Z' days: - monday Daily Timer: value: - id: 1 state: active days: - monday - tuesday - wednesday - thursday - friday - saturday - sunday time: '07:00:00' - id: 2 state: disabled days: - monday - tuesday - wednesday - thursday - friday - saturday - sunday time: '10:00:00' description: Inventory item to add tags: - Schedule summary: Batch update schedule '/schedule/{id}': parameters: - in: path name: id required: true schema: type: integer description: Numeric ID of the event get: summary: Get event details description: | This will get the details of a specific event in the schedule. The response will be the EVSE state to set for that event. responses: '200': description: OK content: application/json: schema: $ref: ./models/EvseState.yaml operationId: getScheduleEvent tags: - Schedule post: description: | Update the details of a specific event in the schedule. responses: '200': $ref: '#/components/responses/UpdateSuccessful' requestBody: content: application/json: schema: $ref: ./models/EvseState.yaml description: '' operationId: setScheduleEvent tags: - Schedule summary: Update event details delete: description: | Remove a specific event from the schedule. responses: '200': description: OK content: application/json: schema: $ref: '#/components/schemas/Message' examples: {} operationId: removeScheduleEvent tags: - Schedule summary: Remove event /schedule/plan: get: summary: Get planned events and state description: This will return the planned events by day and also the current state of the scheduler responses: '200': description: List of planed events content: application/json: schema: type: object properties: current_day: $ref: '#/components/schemas/Day' operationId: getSchedulePlan tags: - Schedule /logs: get: summary: Get event block information tags: - Event Log responses: '200': description: OK content: application/json: schema: type: object properties: min: type: integer max: type: integer operationId: getEventBlockInfo description: 'Retrieve the start and end indexes of the log event blocks. Each log event block contains ' parameters: [] parameters: [] '/logs/{index}': get: summary: Get log block events tags: - Event Log responses: '200': description: OK content: application/json: schema: type: array items: $ref: '#/components/schemas/LogEvent' '404': $ref: '#/components/responses/NotFound' operationId: getEventBlock description: | Retrieve the log events for a specific block. The block index range is returned by the /logs endpoint. parameters: - schema: type: integer name: index in: path required: true /logs/export: get: summary: Export session history as CSV tags: - Event Log responses: '200': description: OK content: text/csv: schema: type: string '401': $ref: '#/components/responses/Unauthorized' '429': $ref: '#/components/responses/TooManyRequests' operationId: exportEventLogCsv description: >- Stream every stored log entry as a CSV file (Time, Type, State, Energy (kWh), Elapsed (min), RFID Tag, User Name, Temperature (C)), one row per event. The RFID Tag and User Name columns are blank for sessions without RFID authentication. parameters: [] /rfid/users: get: summary: List RFID user names tags: - RFID responses: '200': description: OK content: application/json: schema: type: object additionalProperties: type: string description: Map of RFID tag UID to the assigned user name. operationId: getRfidUsers description: Retrieve the UID → user name mapping used to attribute sessions in History and the CSV export. parameters: [] post: summary: Set an RFID user name tags: - RFID requestBody: content: application/json: schema: type: object required: - rfid properties: rfid: type: string name: type: string responses: '200': description: OK content: application/json: schema: $ref: '#/components/schemas/Message' '400': $ref: '#/components/responses/BadRequest' operationId: setRfidUser description: >- Assign a user name to an RFID tag UID. Sending an empty name removes the mapping. delete: summary: Remove an RFID user name tags: - RFID parameters: - schema: type: string name: rfid in: query required: true responses: '200': description: OK content: application/json: schema: $ref: '#/components/schemas/Message' '400': $ref: '#/components/responses/BadRequest' operationId: removeRfidUser description: Remove the user name mapping for an RFID tag UID. parameters: [] /login: post: operationId: login summary: Log in and obtain a session cookie description: | Checks the admin credentials and, on success, sets the `oevse_session` cookie (`HttpOnly`, `SameSite=Strict`). Only needed for browser-style clients; machine clients can use HTTP Basic on every request instead. This operation is reachable without authentication. Wrong credentials count towards the same brute-force throttle as a wrong Basic password. tags: - Authentication security: [] requestBody: required: true content: application/json: schema: type: object required: - user - pass properties: user: type: string pass: type: string remember: type: boolean description: Issue a 30 day cookie instead of a 6 hour one now: type: integer description: >- Client time in epoch seconds. Only used to bootstrap the device clock when it has none, so the cookie can be dated. responses: '200': description: Logged in; `Set-Cookie` carries the session headers: Set-Cookie: schema: type: string content: application/json: schema: $ref: '#/components/schemas/Message' '400': $ref: '#/components/responses/BadRequest' '401': description: Wrong username or password content: application/json: schema: $ref: '#/components/schemas/Message' examples: Invalid: value: msg: invalid '429': $ref: '#/components/responses/TooManyRequests' '503': description: >- A session cannot be issued yet (`clock`: the device has no valid time and the client did not supply one; `not ready`: no signing secret). Use HTTP Basic instead. content: application/json: schema: $ref: '#/components/schemas/Message' /logout: post: operationId: logout summary: Clear the session cookie description: Always succeeds and does not require authentication. tags: - Authentication security: [] responses: '200': description: Cookie cleared content: application/json: schema: $ref: '#/components/schemas/Message' /restart: post: summary: restart gateway or evse modules description: restart wifi gateway or openevse module operationId: restart tags: - Restart requestBody: content: application/json: schema: type: object properties: device: type: string description: gateway|evse responses: '200': description: Restart successfull content: application/json: schema: type: object properties: msg: type: string description: restart gateway|evse /limit: get: summary: Get charge limit description: 'This will return the limit type, value and auto_release (true|false) defined if there''s one' responses: '200': description: Limit properties content: application/json: schema: $ref: ./models/Limit.yaml '404': description: No limit content: application/json: schema: type: object properties: msg: type: string description: No limit operationId: limit_get tags: - Limit post: summary: Set charge limit description: 'This will set the limit type, value and auto_release (true|false)' responses: '200': description: Limit set content: application/json: schema: type: object properties: msg: type: string description: created '500': description: Failed to parse data content: application/json: schema: type: object properties: msg: type: string description: Failed to parse JSON requestBody: content: application/json: schema: $ref: ./models/Limit.yaml operationId: limit_set tags: - Limit delete: summary: Get charge limit description: This will clear current limit responses: '200': description: Clear Limit ok content: application/json: schema: type: object properties: msg: type: string description: Deleted '404': description: No limit content: application/json: schema: type: object properties: msg: type: string description: No limit to clear '500': description: Failed to clear limit content: application/json: schema: type: object properties: msg: type: string description: Failed to clear limit operationId: limit_clear tags: - Limit /loadsharing/peers: get: summary: List discovered and configured peers description: | Return the set of peers that are discovered (mDNS) and/or configured as members of the load sharing group. responses: '200': description: OK content: application/json: schema: type: array items: $ref: '#/components/schemas/LoadSharingPeer' operationId: listLoadSharingPeers tags: - Load Sharing post: summary: Add a peer to the load sharing group description: | Add a new peer to the load sharing group. The peer must be specified as a hostname or IP address (the value must contain `.` or `:`). On success the controller performs reciprocal peer-list sync on the remote unless `reciprocal` is false. Config push to the new member is handled separately by the peer poller after the WebSocket connection is established. requestBody: content: application/json: schema: type: object required: - host properties: host: type: string description: Hostname or IP address of the peer to add example: openevse-2.local reciprocal: type: boolean default: true description: | When true (default), add this device to the remote peer's group list. Set false when handling a reciprocal sync from the remote. responses: '200': description: Peer added or already in group content: application/json: schema: $ref: '#/components/schemas/Message' examples: Added: value: msg: done Already in group: value: msg: already in group '400': description: Invalid request content: application/json: schema: $ref: '#/components/schemas/Message' examples: Invalid JSON: value: msg: Invalid JSON Missing host: value: msg: Missing required 'host' parameter Empty host: value: msg: Host cannot be empty Local device: value: msg: Cannot add local device as peer Invalid host format: value: msg: Invalid host format - must contain domain or IP operationId: addLoadSharingPeer tags: - Load Sharing '/loadsharing/peers/{host}': put: summary: Change the priority of a peer description: >- Only allowed on the group leader; members answer `403`. parameters: - in: path name: host required: true schema: type: string description: Hostname or IP address of the peer requestBody: required: true content: application/json: schema: type: object required: - priority properties: priority: type: integer responses: '200': $ref: '#/components/responses/UpdateSuccessful' '400': $ref: '#/components/responses/BadRequest' '403': description: Load sharing configuration is read-only on members content: application/json: schema: $ref: '#/components/schemas/Message' '404': description: Peer not found content: application/json: schema: $ref: '#/components/schemas/Message' operationId: updateLoadSharingPeer tags: - Load Sharing delete: summary: Remove a peer from the load sharing group description: | Remove a peer from the load sharing group. On success the controller performs reciprocal removal on the remote unless `reciprocal=false`. The controller also pushes a reset config to the removed member when applicable. parameters: - in: path name: host required: true schema: type: string description: Hostname or IP address of the peer to remove - in: query name: reciprocal required: false schema: type: boolean default: true description: | When true (default), remove this device from the remote peer's group list. Set false when handling a reciprocal sync from the remote. responses: '200': $ref: '#/components/responses/UpdateSuccessful' '400': description: Cannot remove local device content: application/json: schema: $ref: '#/components/schemas/Message' examples: Local device: value: msg: Cannot remove local device from group '404': description: Peer not found content: application/json: schema: $ref: '#/components/schemas/Message' examples: Peer not found: value: msg: Peer not found operationId: removeLoadSharingPeer tags: - Load Sharing /loadsharing/status: get: summary: Get load sharing runtime status description: | Return runtime status for load sharing, including online/offline peers and the most recent computed allocations. responses: '200': description: OK content: application/json: schema: $ref: '#/components/schemas/LoadSharingStatus' operationId: getLoadSharingStatus tags: - Load Sharing /loadsharing/discover: post: summary: Trigger peer discovery description: | Trigger an mDNS discovery scan for other OpenEVSE devices. responses: '200': description: OK content: application/json: schema: $ref: '#/components/schemas/Message' operationId: discoverLoadSharingPeers tags: - Load Sharing /boost: get: summary: Get the active boost description: > Returns the active boost (type, value, remaining, started), or an empty object when no boost is active. The idle 200+{} response doubles as the capability probe: older firmware has no clean 404 for this path, so clients should treat any non-200-JSON response as unsupported rather than relying on a 404. responses: '200': description: Active boost, or {} when idle content: application/json: schema: type: object properties: type: type: string enum: [time, energy, soc, range] value: type: integer description: > time: seconds (NOT minutes, unlike /limit); energy: Wh added since activation; soc: absolute percent; range: absolute distance remaining: type: integer description: Remaining amount in the dimension's unit (ceil) started: type: string format: date-time operationId: boost_get tags: - Boost post: summary: Arm (or replace) a boost description: > Boost charges NOW - an Active claim at priority 200 (above Divert and the Scheduler, below Manual and Limit) - until the target is reached, then releases so the previous controller resumes. Re-POSTing while a boost is active replaces it with a fresh activation snapshot. Time values clamp to 604800 seconds (7 days). Energy value is a Wh delta from the moment of activation; soc/range values are absolute targets and require a vehicle data source (422 otherwise). A soc/range target that is ALREADY met arms as a no-op: 201, no claim is taken, and GET /boost still returns {}. The MQTT /boost event topic publishes the boolean boost + boost_version on every change; boost_reason ("reached", "cancelled" or "replaced") appears only on end events (boost false) and never on an active one, so a replace emits the end event first and then the fresh arm event. The retained /boost state topic carries this same serialized object ({} when idle) - the retained remaining is a snapshot at arm/end, not a live countdown. responses: '201': description: Boost armed content: application/json: schema: type: object properties: msg: type: string description: created '400': description: Malformed body, unknown type, or zero value content: application/json: schema: type: object properties: msg: type: string description: Failed to parse JSON '422': description: soc/range boost without a vehicle data source content: application/json: schema: type: object properties: msg: type: string description: No vehicle data available requestBody: required: true content: application/json: schema: type: object required: [type, value] properties: type: type: string enum: [time, energy, soc, range] value: type: integer minimum: 1 operationId: boost_set tags: - Boost delete: summary: Cancel the active boost description: This will clear the active boost, if any responses: '200': description: Boost cancelled content: application/json: schema: type: object properties: msg: type: string description: Deleted '404': description: No boost active content: application/json: schema: type: object properties: msg: type: string description: No boost to clear operationId: boost_clear tags: - Boost /notifications: get: summary: Get the advisory list description: > Returns every currently active advisory, acknowledged entries included - a muted advisory is still listed, marked acked, so the GUI can render it as muted rather than have it vanish. Advisories are non-fault conditions the user should know about (a safety check switched off, a fault that has already cleared, thermal state, relay wear); anything stopping the EVSE charging right now is a fault, not an advisory, and is reported through the state fields instead. first_seen and last_seen are epoch seconds, or 0 when the gateway's clock had not synced at the moment the reading was taken. responses: '200': description: The advisory list content: application/json: schema: type: object properties: count: type: integer description: > Number of UNMUTED advisories - what a badge should show. The notifications array may be longer. max_severity: type: string enum: [info, warning, critical] description: Highest severity among the unmuted advisories notifications: type: array items: type: object properties: id: type: string description: > Stable dotted id, e.g. safety.ground_check. The only thing a UI keys on; titles and detail text are looked up from it. category: type: string enum: [safety, fault, wear, thermal] severity: type: string enum: [info, warning, critical] sticky: type: boolean description: > true when acknowledging mutes the advisory rather than dismissing it - it stays listed, and keeps its settings-page marker, until the condition clears. acked: type: boolean first_seen: type: integer description: Epoch seconds, 0 if unknown (clock not synced) last_seen: type: integer description: Epoch seconds, 0 if unknown (clock not synced) operationId: notifications_get tags: - Notifications /notifications/ack: post: summary: Acknowledge one advisory description: > Acknowledges the advisory named by id. A non-sticky advisory is dismissed until its token changes - the token is the underlying counter, so a later GFI trip raises it again. A sticky advisory is muted instead: it stays in the list marked acked and keeps its settings-page marker, but stops driving the LCD's amber border and advisory line. The acknowledgement survives a reboot; it is voided by any movement in the token, by any EVSE settings change for safety.* advisories, and by a firmware update. The id may be sent either on the query string (POST /notifications/ack?id=safety.ground_check, no body) or as an application/x-www-form-urlencoded body. requestBody: required: false content: application/x-www-form-urlencoded: schema: type: object properties: id: type: string description: > The advisory id. May instead be given as the `id` query parameter. parameters: - name: id in: query required: false description: > The advisory id, e.g. safety.ground_check. Required unless the same name is sent in a form-encoded body. schema: type: string responses: '200': description: Acknowledged content: text/plain: schema: type: string '400': description: No id given, in either the query string or the body content: text/plain: schema: type: string '403': description: > GET used without the X-Requested-With: OpenEVSE header, or a cookie-authenticated request without it (CSRF guard) content: text/plain: schema: type: string '404': description: No advisory with that id is currently active content: text/plain: schema: type: string operationId: notifications_ack tags: - Notifications /emeter: delete: summary: Reset Energy Meter description: This will clear the Energy Meter requestBody: content: application/json: schema: type: object properties: hard: type: integer description: 0|1 Enable hard reset ( reset total_counter & total_switches) import: type: integer description: 0|1 Import OpenEvse module total kwh. responses: '200': description: Reset counter ok content: application/json: schema: type: object properties: msg: type: string description: Reset done '500': description: Failed to reset counter content: application/json: schema: type: object properties: msg: type: string description: Reset failed operationId: energymeter-reset tags: - Energy Meter /tesla/vehicles: get: summary: Get Tesla vehicle list tags: - Tesla responses: '200': description: OK content: application/json: schema: description: '' type: object x-examples: example-1: count: 3 vehicles: - id: '1492932278133304' name: AwesomeSAUCE - id: '1492931610165415' name: Herbie - id: '1492930973960452' name: 'Life, the Universe, and Everything' properties: count: type: number vehicles: type: array uniqueItems: true items: type: object additionalProperties: false properties: id: type: string minLength: 1 name: type: string minLength: 1 required: - id - name required: - count - vehicles examples: example-1: value: count: 1 vehicles: - id: '2238974987235987' name: My Tesla operationId: get-tesla-vehicles description: Once the Tesla account credentials have been configured via the `/config` API this endpoint will return a list of vehicles associated with the account. The ID of the vehicle to use for SoC/Range can then be set using `tesla_vehicle_id` on the `/config` endpoint. /time: get: summary: Get the time tags: - Time responses: '200': description: OK content: application/json: schema: type: object properties: time: type: string x-stoplight: id: 6q0laeyxt5u85 description: The time in UTC according to the OpenEVSE. format: date-time offset: type: string x-stoplight: id: u5zngl88caktf pattern: '^[+-][0-9]{4}$' local_time: type: string x-stoplight: id: 7h1cpgfjj5j9j format: date-time uptime: type: integer description: EVSE gateway uptime, in seconds required: - time - offset - local_time - uptime operationId: get-time description: Gets the time set on the OpenEVSE post: summary: Set the time tags: - Time responses: '200': description: OK content: application/json: schema: type: object x-examples: Example 1: sntp_enabled: false time_zone: 'GMT0BST,M3.5.0/1,M10.5.0' time: '2018-08-10T14:30:00Z' properties: sntp_enabled: type: boolean description: | Set to `true` to enable receiving time updates via NTP, `false` will disable NTP updates. default: false time_zone: type: string description: The time zone to use on the OpenEVSE. This has the format `|`. The `location name` is not used by the EVSE and is largely to for the UI to provide a human readable version of the timezone and differentiate between locations that use the same time zone. default: UTC0 time: type: string description: If `sntp_enabled` is false this is the time to set. Must be in UTC. format: date-time '400': $ref: '#/components/responses/BadRequest' operationId: post-time description: Set the time and associated config options. If not setting the time the `/config` endpoint can be used. /certificates: get: summary: Get a list of certificates description: | Returns a list of certificates that have been uploaded to the OpenEVSE. The certificates are used to authenticate the OpenEVSE to the MQTT broker, provide a secure web interface or as additional root CA certificates. operationId: listCertificates tags: - Certificates responses: '200': description: OK content: application/json: schema: type: object properties: certificates: type: array items: $ref: './models/Certificate.yaml' post: summary: Upload a certificate description: | Upload a certificate to the OpenEVSE. The certificate can be used to authenticate the OpenEVSE to the MQTT broker, provide a secure web interface or as additional root CA certificates. operationId: uploadCertificate tags: - Certificates requestBody: content: application/json: schema: $ref: './models/Certificate.yaml' responses: '200': $ref: '#/components/responses/UpdateSuccessful' '400': $ref: '#/components/responses/BadRequest' '/certificates/{id}': get: summary: Get a certificate description: | Returns a certificate that has been uploaded to the OpenEVSE. The certificate is used to authenticate the OpenEVSE to the MQTT broker, provide a secure web interface or as additional root CA certificates. operationId: getCertificate tags: - Certificates parameters: - in: path name: id required: true schema: type: string responses: '200': description: OK content: application/json: schema: $ref: './models/Certificate.yaml' '400': $ref: '#/components/responses/BadRequest' '404': $ref: '#/components/responses/NotFound' delete: summary: Delete a certificate description: | Delete a certificate that has been uploaded to the OpenEVSE. The certificate is used to authenticate the OpenEVSE to the MQTT broker, provide a secure web interface or as additional root CA certificates. operationId: deleteCertificate tags: - Certificates parameters: - in: path name: id required: true schema: type: string responses: '200': $ref: '#/components/responses/UpdateSuccessful' '400': $ref: '#/components/responses/BadRequest' '404': $ref: '#/components/responses/NotFound' '500': description: Certificate removal failed because storage or trust-bundle preparation failed. content: application/json: schema: $ref: '#/components/schemas/Message' example: msg: Could not remove certificate /reset: get: operationId: factoryReset summary: Factory reset and reboot the gateway description: | Erases the stored configuration and reboots the WiFi module. Also accepts `POST`. A `GET` must send `X-Requested-With: OpenEVSE`, see [Authentication](#section/Authentication). tags: - System responses: '200': description: Reset accepted, the device is rebooting content: text/plain: schema: type: string example: '1' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '429': $ref: '#/components/responses/TooManyRequests' /apoff: get: operationId: accessPointOff summary: Turn the WiFi access point off description: | Switches off the access point after one second. Also accepts `POST`. A `GET` must send `X-Requested-With: OpenEVSE`. tags: - Network responses: '200': description: OK content: text/plain: schema: type: string example: Turning AP Off '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '429': $ref: '#/components/responses/TooManyRequests' /scan: get: operationId: scanWifi summary: Scan for WiFi networks description: >- Starts a scan and returns the networks found. Returns an empty array if the scan could not be started. tags: - Network responses: '200': description: OK content: application/json: schema: type: array items: type: object properties: rssi: type: integer description: Signal strength in dBm ssid: type: string bssid: type: string channel: type: integer secure: type: integer description: Encryption type, `0` for an open network '401': $ref: '#/components/responses/Unauthorized' '429': $ref: '#/components/responses/TooManyRequests' /divertmode: get: operationId: setDivertMode summary: Set the solar divert mode description: | Changes the divert mode. Also accepts `POST`. A `GET` must send `X-Requested-With: OpenEVSE`. tags: - Status parameters: - in: query name: divertmode required: true schema: type: integer enum: - 1 - 2 description: '`1` Normal (default), `2` Eco' responses: '200': description: OK content: text/plain: schema: type: string example: Divert Mode changed '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '429': $ref: '#/components/responses/TooManyRequests' /shaper: get: operationId: setCurrentShaper summary: Enable or disable the current shaper description: | Also accepts `POST`. A `GET` must send `X-Requested-With: OpenEVSE`. tags: - Status parameters: - in: query name: shaper required: true schema: type: integer enum: - 0 - 1 description: '`1` enables the shaper, any other value disables it' responses: '200': description: OK content: text/plain: schema: type: string example: Current Shaper state changed '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '429': $ref: '#/components/responses/TooManyRequests' /rfid/add: get: operationId: rfidAddTag summary: Wait for an RFID badge to be presented description: | Puts the RFID reader into learn mode; the tag id is reported over the websocket once a badge is scanned. Also accepts `POST`. A `GET` must send `X-Requested-With: OpenEVSE`. tags: - RFID responses: '200': description: Waiting for a badge content: application/json: schema: $ref: '#/components/schemas/Message' examples: Waiting: value: msg: Waiting for badge '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '429': $ref: '#/components/responses/TooManyRequests' /settime: post: operationId: setTimeLegacy summary: Set the time (legacy alias of POST /time) description: | Same as `POST /time`. Accepts either a JSON body or a form-encoded body (`tz`, `ntp`, `time`). Kept for older clients; new code should use [`/time`](#tag/Time). tags: - Time responses: '200': description: OK '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '429': $ref: '#/components/responses/TooManyRequests' /teslaveh: get: operationId: getTeslaVehiclesLegacy summary: List Tesla vehicles (legacy alias of /tesla/vehicles) description: Returns the same data as [`/tesla/vehicles`](#operation/get-tesla-vehicles). tags: - Tesla responses: '200': description: OK content: application/json: schema: type: object properties: count: type: integer vehicles: type: array items: type: object properties: id: type: string name: type: string '401': $ref: '#/components/responses/Unauthorized' '429': $ref: '#/components/responses/TooManyRequests' /rapi: get: operationId: rapi summary: Send a RAPI command to the EVSE controller description: | Sends an arbitrary RAPI command and returns the controller's reply. `/r` is an alias. Without the `rapi` parameter it returns an HTML test page (or an empty body when `json=1`). Because a RAPI command can change anything on the controller, a `GET` with `rapi` must send `X-Requested-With: OpenEVSE`; `POST` is also accepted. Some commands are blocked by the firmware. tags: - RAPI parameters: - in: query name: rapi required: false schema: type: string example: $GS description: The RAPI command, including the leading `$` - in: query name: json required: false schema: type: integer enum: - 0 - 1 description: '`1` for a JSON reply rather than an HTML one' responses: '200': description: >- The controller answered (`$OK` or `$NK`). With `json=1` the body is `{"cmd": ..., "ret": ...}` where `ret` is the raw reply. content: application/json: schema: type: object properties: cmd: type: string ret: type: string text/html: schema: type: string '400': description: >- The command is blocked by the firmware. With `json=1` the body is `{"cmd": ..., "error": ...}`. '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '429': $ref: '#/components/responses/TooManyRequests' '500': description: >- The command failed (timeout, queue full, ...). With `json=1` the body is `{"cmd": ..., "error": ...}`. /emoncms/describe: get: operationId: emoncmsDescribe summary: Device discovery for emoncms description: >- Returns the string `openevse` so the device can be found by [emoncms/find](https://github.com/emoncms/find). This is the only operation that never requires authentication and it allows any CORS origin. tags: - System security: [] responses: '200': description: OK content: text/plain: schema: type: string example: openevse /mqtt: get: operationId: getMqttStatus summary: Get the MQTT connection status description: Connection state of the MQTT client, including the last error. tags: - MQTT responses: '200': description: OK content: application/json: schema: type: object properties: mqtt_connected: type: integer enum: - 0 - 1 mqtt_status: type: string mqtt_broker_ip: type: string description: Only present once known mqtt_broker_version: type: string description: Only present once known mqtt_connected_since: type: integer description: Epoch seconds, only present while connected mqtt_last_rx: type: integer description: Epoch seconds of the last MQTT broker traffic, sent or received mqtt_error: type: string description: Error category, empty when there is no failure mqtt_error_detail: type: string '401': $ref: '#/components/responses/Unauthorized' '429': $ref: '#/components/responses/TooManyRequests' post: operationId: restartMqtt summary: Restart the MQTT connection description: Drops and re-establishes the connection to the broker. tags: - MQTT responses: '200': $ref: '#/components/responses/UpdateSuccessful' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '429': $ref: '#/components/responses/TooManyRequests' /relay/reset: get: operationId: resetRelayHealth summary: Reset the relay contact-life estimate description: | Use after a physical relay replacement so wear from the old relay is not carried over. Requires the controller's relay health feature. Also accepts `POST`. A `GET` must send `X-Requested-With: OpenEVSE`. tags: - Relay responses: '200': $ref: '#/components/responses/UpdateSuccessful' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '429': $ref: '#/components/responses/TooManyRequests' '500': description: The controller rejected the command content: application/json: schema: $ref: '#/components/schemas/Message' examples: Error: value: msg: error /relay/recovery: get: operationId: runRelayRecovery summary: Run the stuck-relay recovery cycle description: | Requires controller firmware 9.3.0+. The controller rejects the command if an EV is connected. The response is deferred until the cycle finishes, which can take up to about 30 seconds. Also accepts `POST`. A `GET` must send `X-Requested-With: OpenEVSE`. tags: - Relay responses: '200': $ref: '#/components/responses/UpdateSuccessful' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '429': $ref: '#/components/responses/TooManyRequests' '500': description: The controller rejected the command, for example an EV is connected content: application/json: schema: $ref: '#/components/schemas/Message' examples: Error: value: msg: error /cabletemp: get: operationId: getCableTemperatures summary: Get the cable thermistor readings and configuration description: | Four logical sources: `ev1`/`ev2` on the EV cable and `in1`/`in2` on the input cable. Requires controller firmware 9.4.0+. The live readings are also included in `/status`. tags: - Cable Temperature responses: '200': description: OK content: application/json: schema: type: object properties: supported: type: boolean enabled: type: boolean sources: type: array items: type: object properties: source: type: integer minimum: 0 maximum: 3 name: type: string enum: - ev1 - ev2 - in1 - in2 pin: type: integer minimum: 0 maximum: 2 status: type: integer description: '`0` ok, `1` not installed or unassigned, `2` open circuit, `3` shorted' temperature: type: number description: Omitted when there is no reading, so it is never confused with 0 C r25: type: integer beta: type: integer offset_c10: type: integer panic_c10: type: integer '401': $ref: '#/components/responses/Unauthorized' '429': $ref: '#/components/responses/TooManyRequests' post: operationId: setCableTemperatureSource summary: Assign a pin and optionally set the thermistor parameters description: | Omitting the calibration fields reassigns the pin only. `r25`, `beta`, `offset_c10` and `panic_c10` must be supplied together. Ranges are enforced by the controller. Assigning a source to pin `1` (PP_READ) makes the controller turn PP auto-ampacity off. tags: - Cable Temperature requestBody: required: true content: application/json: schema: type: object required: - source - pin properties: source: type: integer minimum: 0 maximum: 3 pin: type: integer minimum: 0 maximum: 2 r25: type: integer beta: type: integer offset_c10: type: integer panic_c10: type: integer responses: '200': $ref: '#/components/responses/UpdateSuccessful' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '429': $ref: '#/components/responses/TooManyRequests' '500': description: The controller rejected the values content: application/json: schema: $ref: '#/components/schemas/Message' /claims/target: get: operationId: getClaimsTarget summary: Get the resolved target state description: >- The properties that are currently in effect after all [claims](#tag/Claims) have been resolved, and which client holds each one. tags: - Claims responses: '200': description: OK content: application/json: schema: type: object properties: properties: type: object description: The effective properties claims: type: object description: The client id that owns each of `state`, `charge_current` and `max_current` '401': $ref: '#/components/responses/Unauthorized' '429': $ref: '#/components/responses/TooManyRequests' /energy/raw: get: operationId: getEnergyRaw summary: Raw energy log samples description: | Recent samples at the logging interval. Builds with the time series database return the last three hours, wrapped as `{"samples": [...]}`; `before` pages back one window at a time. tags: - Energy parameters: - in: query name: max schema: type: integer description: Return at most this many samples - in: query name: before schema: type: integer description: Epoch seconds. Return the window immediately before this time responses: '200': description: OK content: application/json: schema: type: object properties: samples: type: array items: type: object properties: ts: type: integer description: Epoch seconds a: type: number description: Current (A) t: type: number description: Temperature (C) e: type: number description: Session energy s: type: integer description: State of charge, `-1` when unknown v: type: number description: Voltage (V), time series builds only p: type: number description: Power (W), time series builds only pilot: type: number description: Pilot current (A), time series builds only '401': $ref: '#/components/responses/Unauthorized' '429': $ref: '#/components/responses/TooManyRequests' /energy/daily: get: operationId: getEnergyDaily summary: Daily energy totals description: | Time series builds take `days` (1-365, default 30). Other builds take `year` and `quarter` (`1`-`4`). tags: - Energy parameters: - in: query name: days schema: type: integer minimum: 1 maximum: 365 default: 30 - in: query name: year schema: type: integer minimum: 2020 maximum: 2100 - in: query name: quarter schema: type: integer minimum: 1 maximum: 4 responses: '200': description: OK content: application/json: schema: type: object properties: daily: type: array items: $ref: '#/components/schemas/EnergyBucketDate' '401': $ref: '#/components/responses/Unauthorized' '429': $ref: '#/components/responses/TooManyRequests' /energy/weekly: get: operationId: getEnergyWeekly summary: Weekly energy totals description: Only available in builds with the time series database. tags: - Energy parameters: - in: query name: weeks schema: type: integer minimum: 1 maximum: 104 default: 12 responses: '200': description: OK content: application/json: schema: type: object properties: weekly: type: array items: $ref: '#/components/schemas/EnergyBucketDate' '401': $ref: '#/components/responses/Unauthorized' '429': $ref: '#/components/responses/TooManyRequests' /energy/monthly: get: operationId: getEnergyMonthly summary: Monthly energy totals description: Totals per month for one year, defaulting to the current year. tags: - Energy parameters: - in: query name: year schema: type: integer minimum: 2020 maximum: 2100 responses: '200': description: OK content: application/json: schema: type: object properties: monthly: type: array items: type: object properties: mo: type: string description: Month pk: type: number description: Peak temperature (C) mn: type: number description: Minimum temperature (C) en: type: number description: Energy (kWh) '401': $ref: '#/components/responses/Unauthorized' '429': $ref: '#/components/responses/TooManyRequests' /energy/annual: get: operationId: getEnergyAnnual summary: Annual energy totals description: Totals per year. tags: - Energy responses: '200': description: OK content: application/json: schema: type: object properties: annual: type: array items: type: object properties: yr: type: integer pk: type: number description: Peak temperature (C) mn: type: number description: Minimum temperature (C) en: type: number description: Energy (kWh) '401': $ref: '#/components/responses/Unauthorized' '429': $ref: '#/components/responses/TooManyRequests' /update: post: operationId: updateFirmware summary: Update the firmware description: | Either upload the firmware image as a multipart form, or send a JSON body naming a URL for the device to fetch it from (answered with `{"msg": "started"}`; progress is reported over `/ws`). `GET` is not supported and returns `405`. tags: - Firmware Update requestBody: content: multipart/form-data: schema: type: object properties: firmware: type: string format: binary description: The firmware image; the part name is not significant application/json: schema: type: object properties: url: type: string description: Location of the firmware image to fetch responses: '200': $ref: '#/components/responses/UpdateSuccessful' '400': $ref: '#/components/responses/BadRequest' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '405': description: Only `POST` is accepted '429': $ref: '#/components/responses/TooManyRequests' '500': description: The update failed /migrate/status: get: operationId: getMigrateStatus summary: Flash migration progress and diagnostics description: >- State of an in-place 16MB repartition. Progress is also pushed over `/ws`. On builds without migration support it returns `{"active": false}`. tags: - Diagnostics responses: '200': description: OK content: application/json: schema: type: object properties: active: type: boolean state: type: string enum: - idle - manifest - app - migrator conn_open: type: boolean awaiting: type: boolean body_complete: type: boolean has_redirect: type: boolean has_pending: type: boolean dl_pos: type: integer dl_total: type: integer app_off: type: integer failed: type: boolean fail_code: type: integer fail_where: type: string free_heap: type: integer '401': $ref: '#/components/responses/Unauthorized' '429': $ref: '#/components/responses/TooManyRequests' /migrate/coredump: get: operationId: getMigrateCoredump summary: Summary of the last panic, as seen by the migrator description: Decoded summary of the last panic, read by the flash migration code. tags: - Diagnostics responses: '200': description: >- `task`, `pc`, `bt` and `corrupted` when a core dump exists, otherwise `coredump` set to `none` (or `n/a` on unsupported builds). content: application/json: schema: type: object '401': $ref: '#/components/responses/Unauthorized' '429': $ref: '#/components/responses/TooManyRequests' /migrate/expand16mb: post: operationId: expandTo16mb summary: Repartition a 16MB module that was flashed with the 4MB layout description: Starts the migration; progress is available from `/migrate/status` and `/ws`. tags: - Diagnostics requestBody: content: application/json: schema: type: object properties: url: type: string description: Release manifest to use instead of the default dry_run: type: boolean default: false responses: '200': description: Migration started content: application/json: schema: $ref: '#/components/schemas/Message' examples: Started: value: msg: started '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '405': description: Only `POST` is accepted '409': description: A migration is already in progress '412': description: This device is not eligible for the migration '429': $ref: '#/components/responses/TooManyRequests' '500': description: The migration could not be started /debug: get: operationId: getDebugLog summary: Buffered debug log description: The recent debug output of the WiFi module. Allows any CORS origin. tags: - Diagnostics responses: '200': description: OK content: text/plain: schema: type: string '401': $ref: '#/components/responses/Unauthorized' '429': $ref: '#/components/responses/TooManyRequests' /debug/console: get: operationId: debugConsole summary: Live debug console description: >- WebSocket that streams the debug output as text frames. The upgrade request is authenticated like any other. tags: - Diagnostics responses: '101': description: Switching protocols '401': $ref: '#/components/responses/Unauthorized' /debug/crash: get: operationId: getCrashSummary summary: Decoded summary of the last panic description: >- A core dump survives a reboot in flash. `present` is `false` when there is none. The remaining keys depend on the CPU architecture. tags: - Diagnostics responses: '200': description: OK content: application/json: schema: type: object properties: present: type: boolean size: type: integer addr: type: integer valid: type: boolean task: type: string pc: type: string '401': $ref: '#/components/responses/Unauthorized' '429': $ref: '#/components/responses/TooManyRequests' delete: operationId: clearCrashSummary summary: Clear the stored core dump description: Clears the stored core dump so the next panic is unambiguous. tags: - Diagnostics responses: '200': description: Erased content: application/json: schema: $ref: '#/components/schemas/Message' examples: Erased: value: msg: erased '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '429': $ref: '#/components/responses/TooManyRequests' '500': description: The core dump could not be erased /debug/crash/raw: get: operationId: getCrashImage summary: Download the raw core dump description: >- For use with `esp-coredump`. Unlike other operations this one always answers an unauthenticated request with a `WWW-Authenticate` Basic challenge (never the JSON `401`), and is not subject to the throttle. tags: - Diagnostics responses: '200': description: OK content: application/octet-stream: schema: type: string format: binary '401': description: Credentials are required, answered with a `WWW-Authenticate` challenge '404': description: There is no core dump content: application/json: schema: $ref: '#/components/schemas/Message' /debug/crash/report: get: operationId: getCrashReport summary: The crash report, in the form the broker accepts description: | Part of the crash report upload: the browser fetches this and POSTs it to the broker itself, so the charger needs no internet access. Only present in builds with crash upload enabled. The report carries the reporter id and a hash of the delete key, so a reporter identity must exist first, see `/debug/crash/identity`. tags: - Diagnostics responses: '200': description: The report, exactly as the broker takes it content: application/json: schema: type: object '401': $ref: '#/components/responses/Unauthorized' '404': description: There is no stored crash dump content: application/json: schema: $ref: '#/components/schemas/Message' '409': description: No reporter identity has been stored yet content: application/json: schema: $ref: '#/components/schemas/Message' '429': $ref: '#/components/responses/TooManyRequests' '500': description: The report is too large to build content: application/json: schema: $ref: '#/components/schemas/Message' /debug/crash/identity: get: operationId: getCrashIdentity summary: The reporter identity and broker URL description: | Only present in builds with crash upload enabled. Every method on this route is for the web app only: it must send `X-Requested-With: OpenEVSE` even with no password set, because the delete key is what erases this charger's reports. The delete key is only returned when `key=1` is requested. tags: - Diagnostics parameters: - in: query name: key required: false schema: type: integer enum: - 1 description: Also return the delete key responses: '200': description: OK content: application/json: schema: type: object properties: reporter_id: type: string nullable: true description: Null when no identity has been stored delete_key: type: string description: Only present when `key=1` was requested broker: type: string description: URL of the crash report broker '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '429': $ref: '#/components/responses/TooManyRequests' post: operationId: storeCrashIdentity summary: Store the reporter identity generated by the browser description: Only present in builds with crash upload enabled. tags: - Diagnostics requestBody: required: true content: application/json: schema: type: object required: - reporter_id - delete_key properties: reporter_id: type: string delete_key: type: string responses: '200': description: Stored, or the same identity was already stored content: application/json: schema: $ref: '#/components/schemas/Message' examples: Stored: value: msg: stored '400': description: Invalid JSON, reporter id or delete key content: application/json: schema: $ref: '#/components/schemas/Message' '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '409': description: A different identity is already stored content: application/json: schema: $ref: '#/components/schemas/Message' '429': $ref: '#/components/responses/TooManyRequests' '500': description: The identity could not be stored content: application/json: schema: $ref: '#/components/schemas/Message' delete: operationId: forgetCrashIdentity summary: Forget the reporter identity description: >- Only present in builds with crash upload enabled. Call this once the reports have been erased at the broker. tags: - Diagnostics responses: '200': description: Forgotten content: application/json: schema: $ref: '#/components/schemas/Message' examples: Forgotten: value: msg: forgotten '401': $ref: '#/components/responses/Unauthorized' '403': $ref: '#/components/responses/Forbidden' '429': $ref: '#/components/responses/TooManyRequests' '500': description: The identity could not be removed content: application/json: schema: $ref: '#/components/schemas/Message' /evse: get: operationId: getEvseSerialLog summary: Buffered serial traffic with the EVSE controller description: Allows any CORS origin. tags: - Diagnostics responses: '200': description: OK content: text/plain: schema: type: string '401': $ref: '#/components/responses/Unauthorized' '429': $ref: '#/components/responses/TooManyRequests' /evse/console: get: operationId: evseConsole summary: Live EVSE serial console description: >- WebSocket that streams the serial traffic to and from the EVSE controller as text frames. The upgrade request is authenticated like any other. tags: - Diagnostics responses: '101': description: Switching protocols '401': $ref: '#/components/responses/Unauthorized' /installer/verify: post: description: | Check the installer password. Requires `X-Requested-With: OpenEVSE` and a JSON body. Wrong passwords are throttled; a locked-out client gets 429 with `retry_after` seconds. requestBody: required: true content: application/json: schema: type: object required: [password] properties: password: type: string responses: '200': description: Password accepted content: application/json: schema: type: object properties: msg: type: string example: ok '400': description: Body is not valid JSON '403': description: Missing CSRF header, or wrong password '405': description: Not a POST request '429': description: Locked out after too many failures operationId: verifyInstaller tags: - Installer summary: Verify the installer password /installer/password: post: description: | Change the installer password. Requires the current password. The new password must be 8 to 32 printable ASCII characters. requestBody: required: true content: application/json: schema: type: object required: [current, new] properties: current: type: string new: type: string responses: '200': description: Password changed content: application/json: schema: type: object properties: msg: type: string example: changed '400': description: New password is missing its length or characters '403': description: Missing CSRF header, or wrong current password '429': description: Locked out after too many failures '500': description: Password could not be stored operationId: changeInstallerPassword tags: - Installer summary: Change the installer password /installer/maxcurrent: post: description: | Set the hardware maximum current. The controller accepts this only once, so the reply confirms the command was sent; re-read `/config` to see whether `max_current_hard` took the new value. Amps must lie between the minimum current and the lower of the hardware maximum and the installer limit, and can only come down in practice. requestBody: required: true content: application/json: schema: type: object required: [password, amps] properties: password: type: string amps: type: integer responses: '200': description: Command sent to the controller content: application/json: schema: type: object properties: msg: type: string example: sent requested: type: integer previous: type: integer '400': description: Amps out of range (the body gives the allowed min and max), or bad JSON '403': description: Missing CSRF header, or wrong password '429': description: Locked out after too many failures operationId: setInstallerMaxCurrent tags: - Installer summary: Set the hardware maximum current components: securitySchemes: BasicAuth: type: http scheme: basic description: >- Admin username and password, sent on every request. Over plain HTTP they are not encrypted; use HTTPS to protect them in transit. SessionCookie: type: apiKey in: cookie name: oevse_session description: >- Session cookie issued by `POST /login`. State-changing requests that use it must also send `X-Requested-With: OpenEVSE`. schemas: EnergyBucketDate: type: object properties: dt: type: string format: date description: First day of the bucket pk: type: number description: Peak temperature (C) mn: type: number description: Minimum temperature (C) en: type: number description: Energy (Wh) Message: title: Informational message type: object properties: msg: type: string description: The message Day: type: string enum: - monday - tuesday - wednesday - thursday - friday - saturday - sunday x-examples: {} ScheduleEvent: type: object properties: id: type: integer example: 1 state: $ref: ./models/EvseState.yaml time: type: string format: time days: type: array uniqueItems: true items: $ref: '#/components/schemas/Day' required: - state - time - days title: '' LogEvent: title: LogEvent type: object x-examples: example-1: value: time: '2021-08-24T14:15:22Z' type: information managerState: active evseState: 1 evseFlags: 123 pilotState: 2 changed: - pilot pilot: 32 energy: 1234.5 elapsed: 123456 temperature: 35.4 tempuratureMax: 50.4 divertMode: 1 properties: time: type: string format: date-time readOnly: true type: type: string enum: - information - notification - warning managerState: $ref: ./models/EvseState.yaml evseState: type: integer minimum: 0 maximum: 255 evseFlags: type: integer format: int32 pilotState: description: >- J1772 pilot state at the time of the event. 255 for entries written before this field was recorded. type: integer minimum: 0 maximum: 255 changed: description: >- Which fields differ from the previous entry, i.e. why this entry exists. "flags" covers only the meaningful evseFlags bits: the session-timing and previous-EV-connected bookkeeping bits are recorded in evseFlags but never create an entry of their own. "boot" means there was no previous entry to compare against; "periodic" means nothing visible changed and the entry is the periodic sample of an unchanging state; "notification" means the advisory id differs from the previous entry's. Empty for entries written before this field was recorded. The pilot state is never listed: it is recorded, but a change in it alone does not create an entry. type: array items: type: string enum: - boot - type - manager - state - flags - pilot - divert - shaper - periodic - notification pilot: type: integer format: int32 minimum: 0 energy: type: number format: double minimum: 0 elapsed: type: integer format: int32 minimum: 0 temperature: type: number format: double tempuratureMax: type: number format: double divertMode: type: integer format: int32 minimum: 1 maximum: 2 exclusiveMaximum: false rfidTag: description: >- RFID tag UID authenticated for this session, when RFID was used. Absent for entries with no RFID authentication or written before this field was recorded. type: string notification: description: >- For a "notification" entry, the advisory id that was raised (e.g. safety.ground_check). Empty for every other entry type and for entries written before this field existed. A row is written on the raise edge only, at most once per advisory id per boot. type: string LoadSharingPeerStatus: type: object description: Minimal peer status snapshot used for load sharing decisions. properties: amp: type: number format: double description: Measured current (amps). voltage: type: number format: double description: Measured voltage (volts). pilot: type: number format: double description: Current pilot setpoint (amps). vehicle: type: integer description: 1 if vehicle connected, else 0. state: type: integer description: EVSE state code. min_current: type: number format: double description: EVSE minimum current (amps). max_current: type: number format: double description: EVSE configured maximum current (amps). priority: type: integer description: Node-local load sharing priority; lower values win under scarcity. LoadSharingPeer: type: object description: A discovered or configured peer. properties: id: type: string description: Stable device id. name: type: string description: mDNS instance/hostname if available. host: type: string description: Hostname or IP address used to reach the peer. ip: type: string description: Current resolved IP address. version: type: string description: Firmware version if available. online: type: boolean joined: type: boolean description: True if this peer is joined to the load sharing group (manually configured). last_seen: type: integer description: Seconds since boot when the peer was last seen (millis/1000). status: $ref: '#/components/schemas/LoadSharingPeerStatus' LoadSharingAllocation: type: object description: Per-member current allocation result. properties: id: type: string description: Member id. target_current: type: number format: double minimum: 0 description: Allocated current (amps). reason: type: string enum: - idle - equal_share - connected_min - min_subset - insufficient - offline - failsafe_disabled description: Why this allocation was computed. required: - target_current LoadSharingStatus: type: object description: Runtime status for local load sharing. properties: enabled: type: boolean group_id: type: string computed_at: type: string format: date-time failsafe_active: type: boolean online_count: type: integer offline_count: type: integer peers: type: array items: $ref: '#/components/schemas/LoadSharingPeer' allocations: type: array items: $ref: '#/components/schemas/LoadSharingAllocation' responses: UpdateSuccessful: description: Update successful content: application/json: schema: $ref: '#/components/schemas/Message' examples: Success message: value: msg: done NotFound: description: Example response content: application/json: schema: $ref: '#/components/schemas/Message' examples: Not found: value: msg: Not found Unauthorized: description: >- Authentication is required and no valid credentials were supplied. Requests with `X-Requested-With: OpenEVSE` get a JSON body; others get a `WWW-Authenticate` Basic challenge. content: application/json: schema: $ref: '#/components/schemas/Message' examples: Auth required: value: msg: auth TooManyRequests: description: >- A wrong password was presented while the brute-force throttle is active. Correct credentials are never throttled. content: application/json: schema: $ref: '#/components/schemas/Message' examples: Locked: value: msg: locked Forbidden: description: >- Rejected by the CSRF guard. A state-changing request authenticated by session cookie, or a `GET` to an operation that changes state, is missing `X-Requested-With: OpenEVSE`. Session-cookie requests get the JSON body; `GET` actuators get plain text. content: application/json: schema: $ref: '#/components/schemas/Message' examples: CSRF: value: msg: csrf text/plain: schema: type: string example: 'Forbidden: use POST or the app' BadRequest: description: Example response content: application/json: schema: $ref: '#/components/schemas/Message' examples: Bad JSON: value: msg: Could not parse JSON parameters: {} tags: - name: Authentication - name: Claims - name: Config - name: Event Log - name: Manual Override - name: Schedule - name: Status - name: Tesla - name: Limit - name: Boost - name: Notifications - name: Energy Meter - name: Time - name: Restart - name: Certificates - name: Load Sharing - name: RFID - name: Cable Temperature - name: Diagnostics - name: Energy - name: Firmware Update - name: MQTT - name: Network - name: RAPI - name: Relay - name: System - name: Installer