ocpp-client 0.2.2

OCPP Client Implementation. Use this library to implement an OCPP charge point
Documentation
[workspace]
members = ["crates/*"]
# ocpp-client itself (this manifest) is the workspace root and an implicit member - no need to
# list it. crates/* holds satellite crates that build on ocpp-client's public traits, starting
# with ocpp-transport-embassy-net and ocpp-board-stm32h723-nucleo (see
# PRODUCTION_READINESS.md item 6). Kept as workspace members rather than folded into this
# crate's own Cargo.toml because they pull in embedded-only dependencies (embassy-*) that most
# consumers of ocpp-client itself don't want.
#
# default-members is just this root package: neither satellite crate belongs in a plain
# `cargo build`/`test` run here. ocpp-board-stm32h723-nucleo depends on `cortex-m`'s inline
# `asm!`, which only compiles for a real ARM target, so it would fail outright targeting the
# host. ocpp-transport-embassy-net *does* build for the host, but including it as a default
# member made any `cargo <cmd> --features <name>` at the root ambiguous whenever <name> wasn't a
# feature on every default member (e.g. `--features test`, `--features ocpp_1_6` - both
# ocpp-client-only features) - Cargo can't tell which package you meant. Build/check/clippy the
# satellite crates explicitly with `-p <crate>` (see .github/workflows/ci.yaml's `embedded` job
# and each crate's README).
default-members = ["."]

[package]
edition = '2024'
name = "ocpp-client"
version = "0.2.2"
description = "OCPP Client Implementation. Use this library to implement an OCPP charge point"
repository = "https://github.com/flowionab/ocpp-client"
license = "MIT OR Apache-2.0"
authors = ["Joatin Granlund <joatin@granlund.io>"]
keywords = ["OCPP", "ChargePoint", "Client", "ocpp16", "ocpp201"]

[features]
default = ["std", "tokio-runtime", "websocket", "ocpp_1_6", "ocpp_2_0_1", "ocpp_2_1"]
# Pulls in std/alloc-only support. Forwards to critical-section's `std` backend (gates the
# mutex implementation src/sync.rs's `CriticalSectionRawMutex` uses under the hood) and
# tracing's `std` feature (thread-local span/event dispatch instead of tracing's no_std
# global-only dispatch). `ocpp-types` needs no forwarding here - its own `alloc` feature is
# unconditionally enabled below regardless of this crate's `std` status, since even the
# no_std+alloc build wants plain `alloc::String`/`Vec` for spec-unbounded fields rather than
# const-generic-sized `heapless` collections (see MIGRATION_OCPP_TYPES.md). Disable `std` for
# no_std + alloc targets (embedded); the engine itself (src/client.rs) has no unconditional
# std/tokio dependency left - see the `Executor`/`Timer` traits in src/runtime.rs. Embedded
# users must supply their own `Executor`/`Timer` impls plus a `critical-section` backend for
# their target (via `critical_section::set_impl!`), and their own `tracing::Subscriber` (e.g. a
# `defmt`/RTT-backed one) if they want the log output.
std = ["critical-section/std", "tracing/std"]
# tokio-backed `Executor`/`Timer` impls (`TokioExecutor`/`TokioTimer`). Implies `std`.
tokio-runtime = ["std", "dep:tokio"]
# WebSocket transport. tokio-tungstenite inherently needs a tokio runtime, so this implies
# `tokio-runtime`.
websocket = ["tokio-runtime", "dep:tokio-tungstenite", "dep:futures", "dep:url", "dep:rustls", "dep:base64"]
# `ocpp-types` has no per-version cargo features (v16/v201/v21 always compile in), so these
# just gate this crate's own src/ocpp_{1_6,2_0_1,2_1}/ modules.
ocpp_1_6 = []
ocpp_2_0_1 = []
ocpp_2_1 = []
test = []

[dependencies]
# Strongly typed, no_std+no_alloc-by-default OCPP message types generated from the official
# JSON schemas - see MIGRATION_OCPP_TYPES.md for why this replaced the rust-ocpp fork.
ocpp-types = { version = "0.1.3", default-features = false, features = ["serde", "alloc"] }
serde = { version = "1", default-features = false, features = ["derive", "alloc"] }
serde_json = { version = "1", default-features = false, features = ["alloc"] }
uuid = { version = "1", default-features = false, features = ["v4"] }

# no_std+alloc-friendly Mutex/Signal primitives backing src/sync.rs - used unconditionally by
# the engine regardless of the `std`/`tokio-runtime` features.
embassy-sync = { version = "0.8", default-features = false }
critical-section = { version = "1" }

# Only needed for the tokio-backed `Executor`/`Timer` impls (`tokio-runtime` feature) and the
# WebSocket transport, which needs a tokio runtime regardless.
tokio = { version = "1", features = ["sync", "rt", "time"], optional = true }

tokio-tungstenite = { version = "0.28", features = ["rustls-tls-webpki-roots"], optional = true }
futures = { version = "0.3", optional = true }
url = { version = "2.5", optional = true }
rustls = { version = "0.23", optional = true }
base64 = { version = "0.22", optional = true }
tracing = { version = "0.1.44", default-features = false }

[dev-dependencies]
tokio = { version = "1", features = ["full"] }
chrono = { version = "^0.4", default-features = false, features = ["now"] }
rcgen = { version = "0.14.8", default-features = false, features = ["aws_lc_rs", "pem"] }
tokio-rustls = "0.26"
tracing-test = { version = "0.2.6", features = ["no-env-filter"] }
criterion = { version = "0.5", features = ["async_tokio"] }

[[bench]]
name = "call_roundtrip"
harness = false