ocpp-client 0.4.0

OCPP Client Implementation. Use this library to implement an OCPP charge point
Documentation
# ๐Ÿ”Œ OCPP Client

> **A lightweight, embedded-friendly Rust OCPP communication framework for building real charge points and CSMS integrations.**

[![Rust](https://img.shields.io/badge/rust-stable-orange.svg)](https://www.rust-lang.org/)
[![License](https://img.shields.io/badge/license-MIT%20%2F%20Apache--2.0-blue.svg)](#license)
[![Crates.io](https://img.shields.io/crates/v/ocpp-client)](https://crates.io/crates/ocpp-client)
[![Documentation](https://docs.rs/ocpp-client/badge.svg)](https://docs.rs/ocpp-client)
[![.github/workflows/ci.yaml](https://github.com/flowionab/ocpp-client/actions/workflows/ci.yaml/badge.svg)](https://github.com/flowionab/ocpp-client/actions/workflows/ci.yaml)
[![no_std](https://img.shields.io/badge/no__std-compatible-brightgreen.svg)](#features)

---

## ๐Ÿš€ Overview

**OCPP Client** is the communication layer of the **Flowion Rust OCPP ecosystem**, providing the networking and transport foundation required to build OCPP-enabled charge points and backend integrations.

The library handles the complexities of establishing and managing OCPP connections, including:

* Connection lifecycle management
* Transport handling
* Message routing
* Communication reliability

OCPP message types and protocol definitions are provided by [`ocpp-types`](https://github.com/flowionab/ocpp-types), while OCPP Client focuses on the communication layer required to exchange messages between charge points and Charge Station Management Systems (CSMS).

Designed for both cloud/server environments and resource-constrained embedded systems, OCPP Client speaks WebSocket out of the box and compiles for `no_std` + `alloc` targets. An `embassy-net`-based transport and an STM32 board scaffold ship alongside it as **experimental** crates - see [Supported Transports](#-supported-transports).

The library currently supports **OCPP 1.6J**, **OCPP 2.0.1**, and **OCPP 2.1**.

---

## โœจ Features

* ๐Ÿฆ€ Native Rust implementation
* ๐Ÿ”Œ OCPP communication layer
* โšก OCPP **1.6J support**
* ๐Ÿš€ OCPP **2.0.1 support**
* โšก OCPP **2.1 support**
* ๐ŸŒ WebSocket transport
* ๐Ÿ”’ Secure WebSocket (WSS)
* ๐Ÿ”‹ `embassy-net` transport for embedded targets (experimental)
* ๐Ÿ”„ Connection lifecycle management
* ๐Ÿ’“ Scheduled WebSocket keepalive with dead-peer detection
* ๐Ÿ“จ Message routing
* ๐Ÿงฉ Transport abstraction
* ๐Ÿชถ Lightweight runtime
* ๐Ÿ’พ `no_std` support for embedded environments
* ๐Ÿ–ฅ๏ธ `std` support enabled by default for desktop and server applications

---

## ๐Ÿ”Œ Supported Protocols

| Protocol   | Status         | Actions wired up |
| ---------- | -------------- | ---------------- |
| OCPP 1.6J  | โœ… Supported    | all 39           |
| OCPP 2.0.1 | โœ… Supported    | all 64           |
| OCPP 2.1   | โœ… Supported    | all 91           |

1.6's 39 includes the eleven actions from the security whitepaper (`SignCertificate`, `GetLog`,
`SignedUpdateFirmware` and friends), wired up in **0.4.0** when `ocpp-types` first defined them.

Every action defined by [`ocpp-types`](https://crates.io/crates/ocpp-types) for each version has a
`send_*`/`on_*` method - `tests/action_coverage.rs` fails the build otherwise, so the table can't
drift. If a method you expect is missing, check [CHANGELOG.md](CHANGELOG.md) before filing an
issue: five actions were only wired up in **0.2.1**, so a 0.2.0 build is missing
`SecurityEventNotification` (2.0.1) and `TriggerMessage`, `SetDisplayMessage`, `GetDERControl`,
`SetDERControl`, `UpdateDynamicSchedule` (2.1).

---

## ๐ŸŒ Supported Transports

| Transport                                   | Status            |
| ------------------------------------------- | ----------------- |
| WebSocket                                    | โœ… Supported       |
| Secure WebSocket (WSS), incl. mutual TLS     | โœ… Supported       |
| `embassy-net` (embedded, `no_std` + `alloc`) | ๐Ÿงช Experimental   |

The embedded transport (`crates/ocpp-transport-embassy-net`) and the NUCLEO-H723ZG firmware
scaffold (`crates/ocpp-board-stm32h723-nucleo`) compile and fully link against the real
`thumbv7em-none-eabihf` target in CI, but **neither has been run against real hardware or a real
CSMS**, and the embedded transport has no TLS. Treat them as a starting point for a board bring-up
rather than a supported deployment path. Each crate's README states its exact status.

---

## โš™๏ธ Feature Flags

OCPP Client supports both standard Rust environments and embedded systems.

By default, the `std` feature is enabled:

```toml
[dependencies]
ocpp-client = "0.x"
```

For embedded targets or `no_std` environments:

```toml
[dependencies]
ocpp-client = { version = "0.x", default-features = false }
```

This lets the same OCPP communication core compile for resource-constrained devices as well as server-side applications. Embedded users supply their own `Executor`/`Timer` implementations (e.g. backed by `embassy-executor`/`embassy-time`) and a `critical-section` backend for their target.

The optional `chrono` feature adds `From`/`Into` between `ocpp_types::OcppTimestamp` - the type every `dateTime` field uses - and `chrono::DateTime`, for applications that already keep time in chrono. It is interop only; chrono never reaches the wire.

---

## ๐Ÿ—๏ธ Architecture

OCPP Client separates protocol definitions from communication.

```text
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚          Your Application                  โ”‚
โ”‚          Charge Point / CSMS Logic         โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                       โ”‚
                       โ”‚
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚              ocpp-charge-point             โ”‚
โ”‚                                            โ”‚
โ”‚  Complete charge point firmware framework  โ”‚
โ”‚  Add hardware bindings and deploy          โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                       โ”‚
                       โ”‚
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚              ocpp-client                   โ”‚
โ”‚                                            โ”‚
โ”‚  OCPP communication runtime                โ”‚
โ”‚  Transport abstraction                     โ”‚
โ”‚  WebSocket / embedded transports           โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
                       โ”‚
                       โ”‚
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚               ocpp-types                   โ”‚
โ”‚                                            โ”‚
โ”‚  OCPP message types                        โ”‚
โ”‚  Protocol models                            โ”‚
โ”‚  Serialization                              โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
```

---

## ๐ŸŒ Flowion OCPP Ecosystem

OCPP Client is designed as a modular building block within the **Flowion Rust OCPP ecosystem**.

Each project has a focused responsibility, allowing developers to choose the right level of abstraction for their application.

---

### ๐Ÿ“ฆ ocpp-types

**OCPP protocol definitions and data models**

[`ocpp-types`](https://github.com/flowionab/ocpp-types) provides the foundation for working with OCPP messages in Rust.

It contains:

* OCPP message types
* Protocol models
* Serialization and deserialization
* Version-specific protocol definitions

OCPP Client builds on top of `ocpp-types` to provide communication capabilities.

---

### ๐Ÿ”Œ ocpp-client

**OCPP communication and transport layer**

This repository provides the runtime required to connect OCPP-enabled systems.

It handles:

* Connection management
* Transport abstraction
* Message routing
* WebSocket communication
* Embedded-compatible transports
* `no_std` environments

It is designed to run in both:

* ๐Ÿ–ฅ๏ธ Server environments
* ๐Ÿ”‹ Embedded charge point environments

---

### โšก ocpp-charge-point

**Complete charge point firmware framework**

[`ocpp-charge-point`](https://github.com/flowionab/ocpp-charge-point) provides a complete framework for building OCPP-enabled charge point firmware.

The goal is to make developing custom charging hardware as simple as implementing the required hardware bindings.

Developers provide hardware-specific implementations such as:

* GPIO control
* Contactor control
* Metering interfaces
* Connector handling
* LEDs and user interfaces
* Hardware drivers

while the framework handles:

* Charge point state management
* OCPP communication
* Charging workflows
* Backend communication
* Protocol integration

This allows manufacturers and developers to build custom OCPP-compatible chargers without implementing the complete protocol stack from scratch.

---

## ๐ŸŽฏ Use Cases

OCPP Client can be used for:

* ๐Ÿš— Building EV charge point firmware
* ๐Ÿญ Developing OCPP-enabled hardware
* ๐Ÿ–ฅ๏ธ Building CSMS integrations
* ๐Ÿงช Testing OCPP implementations
* ๐Ÿ”‹ Connecting embedded devices to charging platforms
* โšก Creating custom charging solutions
* ๐Ÿค– Automated integration testing

---

## ๐Ÿ“ฆ Installation

Add the dependency to your `Cargo.toml`:

```toml
[dependencies]
ocpp-client = "0.x"
```

---

## ๐Ÿš€ Quick Example

```rust
use ocpp_client::connect_1_6;
use ocpp_client::ocpp_types::v16::HeartbeatRequest;

#[tokio::main]
async fn main() {
    // `None` takes the defaults: 5s request timeout, automatic reconnect, and keepalive
    // pinging every 60s.
    let client = connect_1_6("wss://example.com/ocpp", None).await.unwrap();

    let response = client.send_heartbeat(HeartbeatRequest {}).await.unwrap();
    println!("CSMS time: {}", response.current_time);
}
```

Use `connect_2_0_1`/`connect_2_1` for those versions, or `connect` to negotiate whichever version
the server picks.

### Vendor extensions (`customData`)

2.0.1 and 2.1 hang an optional `customData` object on nearly every message. The `send_*`/`on_*`
methods use the specification's own shape - a bare `vendorId` - which is all most deployments
need. To carry your own, name the type on the action marker and go through `call`/`on`:

```rust,ignore
#[derive(serde::Serialize, serde::Deserialize)]
struct AcmeExtension {
    #[serde(rename = "vendorId")]
    vendor_id: String,
    #[serde(rename = "siteId")]
    site_id: u32,
}

let response = client.call::<Reset<AcmeExtension>>(request).await?;
```

`NoCustomData` is the other end of the trade: it accepts whatever a peer sends and discards it,
costing one byte per node instead of the field's full width - worth naming on an MCU.

---

## ๐Ÿ’“ Keepalive & `WebSocketPingInterval`

By default a client pings the CSMS every 60 seconds and, after two unanswered pings, drops the
connection and redials. Without this a half-open link - a dropped NAT entry, a mobile connection
that vanished without a FIN - is undetectable: the socket accepts writes and nothing ever comes
back, and reconnect can't help because nothing reports the connection as closed.

```rust
use ocpp_client::{ConnectOptions, KeepaliveBehavior, KeepalivePolicy, connect_1_6};
use std::time::Duration;

let options = ConnectOptions {
    keepalive: KeepaliveBehavior::Enabled(KeepalivePolicy {
        interval: Duration::from_secs(30),
        timeout: None,          // fall back to the client's request timeout
        max_missed: 2,
    }),
    ..Default::default()
};
let client = connect_1_6("wss://example.com/ocpp", Some(options)).await?;
```

Set `keepalive: KeepaliveBehavior::Disabled` if the CSMS pings the charge point instead, or if the
deployment forbids unsolicited traffic.

This crate does not implement a device model, but it owns the ping timer, so it exposes the value
for the layer that does:

| OCPP | Variable / key | Read | Write |
| ---- | -------------- | ---- | ----- |
| 2.0.1 / 2.1 | `OCPPCommCtrlr.WebSocketPingInterval` (`GetVariables`/`SetVariables`) | `client.ping_interval()` | `client.set_ping_interval(..)` |
| 1.6 (security whitepaper) | `WebSocketPingInterval` (`GetConfiguration`/`ChangeConfiguration`) | `client.ping_interval()` | `client.set_ping_interval(..)` |

Both are non-`async`, so a `GetVariables` handler can call them directly. `None` maps to the
spec's `0` (disabled) in both directions, writes take effect immediately rather than after the
current interval finishes, and a write can enable pinging on a client that started with keepalive
disabled.

---

## ๐Ÿงช Testing

OCPP Client is designed for:

* Integration testing
* Charge point development
* Embedded testing
* CSMS validation
* Automated test environments

It can be combined with simulators and real charging hardware to validate complete OCPP workflows.

---

## ๐Ÿ›ฃ๏ธ Roadmap

Planned improvements:

* ๐Ÿ”Œ Additional embedded transports
* ๐Ÿ“š More examples
* ๐Ÿงช Expanded integration tests
* ๐Ÿ”ง Improved developer tooling

---

## ๐Ÿค Contributing

Contributions are welcome!

You can help by:

* ๐Ÿ› Reporting issues
* ๐Ÿ’ก Suggesting improvements
* ๐Ÿ“ Improving documentation
* ๐Ÿ”ง Submitting pull requests

---

## ๐Ÿ“„ License

OCPP Client is dual licensed:

* MIT License
* Apache License 2.0

You may choose either license.

---

## ๐Ÿข About Flowion

**OCPP Client** is developed by **Flowion AB** as part of our effort to make EV charging development more accessible through modern, open-source tooling.

Flowion builds software solutions for electric vehicle charging using open standards such as **OCPP**, helping developers and businesses build reliable and scalable charging infrastructure.

---

## โญ Support the Project

If you find this library useful:

* โญ Star the repository
* ๐Ÿ› Report issues
* ๐Ÿ’ก Suggest improvements
* ๐Ÿค Contribute

Together we can make EV charging development easier and more accessible.