OCPP StatusNotification: The Charger State Machine

StatusNotification carries every connector state change. The state machine, the transitions that matter, and what operational dashboards depend on.

StatusNotification is the message that keeps the CSMS’s view of each charger in sync with reality. Every state change on every connector fires one. The CSMS uses them to drive operational dashboards, monitoring, alerts, and session-start eligibility. If you are new to the protocol, start with what is OCPP for the overall message model, or the full session message flow to see where StatusNotification sits in a live session.

It is a small message and an operationally critical one. This article covers the state machine it represents, the transitions that matter, and the issues that come up in production.

The basic structure (OCPP 1.6)

{
  "connectorId": 1,
  "errorCode": "NoError",
  "status": "Charging",
  "timestamp": "2026-06-27T14:30:00Z",
  "info": null,
  "vendorId": null,
  "vendorErrorCode": null
}

The fields:

  • connectorId. Which connector. 0 means the whole charger, and 1 upward is per-connector.
  • errorCode. Current fault state, or NoError if there is no fault.
  • status. The operational state.
  • timestamp. When the state changed, which is not the same as when the message arrived.
  • info. Optional human-readable detail.
  • vendorId and vendorErrorCode. Vendor-specific error context.

The status states (OCPP 1.6)

Connector status can be:

  • Available. Ready for a user.
  • Preparing. The user is plugging in or preparing to start a session.
  • Charging. Actively delivering energy.
  • SuspendedEVSE. Paused by the EVSE, for instance a smart-charging throttle or a grid command.
  • SuspendedEV. Paused by the vehicle, usually battery management or temperature.
  • Finishing. The session is ending and the user is about to unplug.
  • Reserved. Held for a specific user via ReserveNow.
  • Unavailable. Administratively disabled, or not operational for a non-fault reason.
  • Faulted. A fault is preventing operation. Read it together with errorCode for detail.

The state machine

A normal session moves through states like this:

Available
    ↓ (user plugs in cable)
Preparing
    ↓ (authorization complete, vehicle handshake done)
Charging
    ↓ (rate changes, smart charging, temperature)
SuspendedEVSE / SuspendedEV (may oscillate during session)
    ↓ (session ends)
Finishing
    ↓ (user unplugs)
Available

The same flow as a state diagram:

stateDiagram-v2
    [*] --> Available
    Available --> Preparing: cable in
    Available --> Reserved: ReserveNow
    Reserved --> Preparing: user arrives
    Reserved --> Available: expired
    Preparing --> Charging: auth done
    Charging --> SuspendedEVSE: EVSE pause
    Charging --> SuspendedEV: EV pause
    SuspendedEVSE --> Charging: resume
    SuspendedEV --> Charging: resume
    Charging --> Finishing: session ends
    Finishing --> Available: unplug
    Charging --> Faulted: fault
    Faulted --> Available: cleared

A session can move to Faulted from any point, and a reservation creates the Available to Reserved transition.

Not every implementation fires StatusNotification on every internal state change. Most fire on:

  • Available to and from Preparing
  • Preparing to Charging
  • Charging to and from the Suspended states
  • Any transition into Finishing
  • Any transition involving Faulted, Reserved, or Unavailable

Some chargers under-report, which leaves you unable to track session state precisely. Others over-report and flood the CSMS during state-machine oscillation. Both are worth knowing about your specific hardware before you build alerting on top of it.

OCPP 2.0.1: device-model based status

OCPP 2.0.1 reports through the device model, so status comes from variables on EVSE and Connector components.

A change in OperationalStatus on EVSE 1 triggers a StatusNotificationRequest:

{
  "evseId": 1,
  "connectorId": 1,
  "connectorStatus": "Occupied",
  "timestamp": "2026-06-27T14:30:00Z"
}

The states in 2.0.1 are a smaller set:

  • Available, as in 1.6.
  • Occupied, meaning connected to a vehicle, which absorbs several distinct 1.6 states.
  • Reserved, as in 1.6.
  • Unavailable, as in 1.6.
  • Faulted, as in 1.6.

Finer detail moves into additional variables, such as chargingState within the transaction and the availability state on the component. The 2.0.1 model gives a richer picture, at the cost of CSMS-side work to map variable changes onto something a human can read on a dashboard.

Common transition patterns

A few real-world sequences and what each tells you.

Normal session

Available → Preparing → Charging → Finishing → Available

The happy path. User plugs in, charges, unplugs, possibly with a few Charging and SuspendedEV oscillations as the battery’s BMS throttles.

Reserved session (fulfilled)

Available → Reserved → Preparing → Charging → Finishing → Available

The user reserved the charger, arrived, plugged in, and charged. Reserved to Preparing is the reservation being fulfilled.

Reserved session (no-show)

Available → Reserved → Available

The reservation expired without anyone arriving, and the charger auto-released it.

Faulted session

Available → Preparing → Charging → Faulted → Available

A fault occurred mid-session and ended it. Once the fault cleared, or someone reset the charger, it returned to Available.

Faulted on plug-in

Available → Preparing → Faulted → Available

The user plugged in and the charger detected a fault, most often ConnectorLockFailure or EVCommunicationError, so the session never started. These fault codes are covered in common OCPP errors explained.

Long pause

Available → Preparing → Charging → SuspendedEVSE [for 30 min] → Charging → Finishing → Available

The session was paused by the EVSE for a long stretch, most likely demand-response curtailment or a smart-charging schedule. The driver may not have noticed. The vehicle certainly did.

Why StatusNotification matters

The CSMS leans on StatusNotification for a lot:

Operational dashboard. Where are all my chargers and what state is each one in?

Availability for reservations. Reserving a Faulted or Unavailable charger makes nobody happy.

Alert generation. A transition into Faulted should reach an operations queue.

Per-station fault history. A connector that keeps going Faulted is a maintenance ticket, not a mystery.

Session lifecycle reconstruction. When billing or audit asks what happened during a session, the StatusNotification trail is the evidence.

Customer app integration. Drivers see “charging” or “session ended” based on this data, which means a missed transition becomes a support call.

Without StatusNotification, the CSMS is blind to almost everything happening at the charger between transaction messages.

Common implementation issues

Missing transitions

The charger does not send StatusNotification on every transition, so the CSMS misses state changes and shows the wrong state for stretches at a time.

Mitigation: use TriggerMessage (coming soon) to request a fresh StatusNotification periodically, and detect missing transitions by gap analysis. A healthy Heartbeat also tells you whether a silent connector is offline or simply not transitioning.

Late transitions

StatusNotification fires after a delay from network or processing latency, so the dashboard shows stale state.

Mitigation: display the timestamp next to the state and accept some lag rather than pretending it is not there.

Out-of-order transitions

Messages arrive out of order and the CSMS treats the older state as current.

Mitigation: order by the embedded timestamp rather than arrival time, and reject states older than the one already processed.

Stuck in a transitional state

A charger sits in Preparing or Finishing for hours because of a state-machine bug.

Mitigation: alert on state durations exceeding expected ranges, then investigate.

Phantom Reserved state

A reservation was cancelled but the charger still shows Reserved, because the CancelReservation never arrived.

Mitigation: reconcile reservation state whenever the charger reconnects.

Faulted with no real fault

The charger reports Faulted but everything looks fine on inspection. Sensor drift or a firmware bug.

Mitigation: alert on Faulted, escalate if it persists, and suppress known false positives only with a documented reason and an expiry date on the suppression.

State flapping

A connector oscillates rapidly between states, usually from poor cellular coverage, a contact issue, or a firmware bug.

Mitigation: detect the flap pattern itself and alert on it, rather than alerting on each transition.

What the CSMS should do

Persist every state change. Keep an audit log of transitions per connector.

Display current state with the time of the last transition. State without a timestamp invites people to trust stale data.

Compute durations. “This connector has been in this state for X minutes” is what surfaces stuck transitions.

Alert on anomalies. Faulted, long-duration transitional states, and flapping.

Cross-reference with sessions. If your transaction view says Charging and the connector says Available, one of them is lying and you need to know which.

Handle out-of-order events by timestamp, not arrival order.

Reconcile on reconnect. Trigger fresh StatusNotifications when a charger comes back, rather than assuming your last known state survived the outage.

What the charger should do

Send StatusNotification on every meaningful transition. Do not skip one because it was brief.

Timestamp at the moment of transition, not at the moment of transmission.

Distinguish Faulted clearly. Do not conflate it with Unavailable or Preparing, because they lead to completely different operational responses.

Enforce Reserved properly. Move to Reserved when ReserveNow is accepted, and back to Available on cancellation or expiry.

Do not flap on transient conditions. A 100ms sensor blip should not produce a burst of state notifications.

Use vendor extensions sparingly. The standard states cover almost everything, and every extension is something a CSMS has to be taught.

The honest summary

StatusNotification is the lifeblood of OCPP operational visibility. The state machine is well defined; implementation quality is where it varies.

The failure worth internalising is the quiet one. A charger that never sends a transition does not throw an error, and a CSMS that misses one does not either. What happens instead is that your dashboard is confidently wrong, and stays wrong until a driver phones to say the charger they can see is free is showing as occupied. Almost every “why does the dashboard not match reality” investigation ends up in this layer, which is why gap detection and periodic reconciliation earn their cost long before your fleet gets large.

Quick check

Q1. When does a charger fire StatusNotification?
Q2. What does connectorId 0 report?
Q3. Two StatusNotifications arrive out of order due to a network issue. How should the CSMS decide which state is current?
Q4. How is connector status represented in OCPP 2.0.1?
Q5. A connector is stuck in Preparing for hours. What is the right CSMS response?

Frequently asked questions

How often does StatusNotification fire?

On every connector state change, not on a fixed interval. So once when a user plugs in (Available to Preparing), once when charging begins (Preparing to Charging), once when charging completes (Charging to Finishing), and once when the user unplugs (Finishing to Available), plus any faults or other state changes along the way.

What is the connectorId for the whole charger?

connectorId = 0. StatusNotification with connectorId 0 reports the state of the entire charger rather than a specific connector. It is used for charger-level faults that affect every connector.

Does OCPP 2.0.1 still use StatusNotification?

Yes, but with more structure. The 2.0.1 version reports through the device model, using OperationalStatus and AvailabilityState variables on the relevant components such as EVSE and Connector. The functional equivalent is the same and the structure is cleaner.

What does Reserved status mean?

A connector has an active reservation, so users other than the reservation holder cannot start sessions on it. The reservation lifecycle is managed via the ReserveNow and CancelReservation messages.

Found this useful? Share it.