OCPP-RS
Rust protocol library for the Open Charge Point Protocol (OCPP).
Supports OCPP 1.6 (JSON) and OCPP 2.1 (additive / 2.0.1-compatible schemas).
Documentation · Changelog · Guides
Features
- Full OCPP 1.6 and 2.1 message payloads + OCPP-J parse/serialize
- CallResult typing via
PendingCalls/ action-name correlation (no untagged guessing) - Typed RPC framework error codes; MessageId length ≤ 36
- Optional Part 3 schema bounds (
schema_validate) and device-model catalogs #![no_std]+alloc— zerostdin library code (global allocator required on baremetal)- Inspired by mobilityhouse/ocpp; 2.1 layout inspired by rust-ocpp
Install
[]
= "0.4"
# Optional:
# features = ["schema_validate", "device_model_catalog", "datetime_serialize_rfc3339"]
| Feature | Purpose |
|---|---|
schema_validate |
Enforce Part 3 / 1.6 string/array/numeric bounds after parse |
device_model_catalog |
Standard 2.1 component/variable name tables |
datetime_serialize_rfc3339 |
Emit RFC3339 millis instead of %.3fZ |
MSRV: 1.85 (edition 2024).
Upgrading from 0.2.x: guides/migration-0.4.md.
no_std / firmware
[]
= { = "0.4", = false }
# plus your allocator / #[global_allocator]
|
OCPP 1.6 CallResult
CALLRESULT has no action on the wire. Blind parse yields CallResultRaw. Correlate with PendingCalls:
use ;
use TypedMessage;
use PendingCalls;
use TypedCallResult;
let mut pending = new;
let _wire = pending.send_call?;
let typed = pending.deserialize_typed?;
assert!;
- Sticky sessions or Redis
messageId → action name+resolve_with_action_name - Datetime: RFC3339 parse; serialize defaults to
%.3fZ— guides/datetime-features.md - Details:
v16::pending, migration guide
OCPP 2.1
Same correlation model under v21::pending. Framing types 2–6 (CALL, CALLRESULT, CALLERROR, CALLRESULTERROR, SEND).
use ;
use HeartbeatRequest;
use TypedMessage;
use PendingCalls;
use TypedCallResult;
let mut pending = new;
let call = new;
assert_eq!;
let _wire = pending.send_call?;
let typed = pending.deserialize_typed?;
assert!;
2.0.1 subprotocol gating: guides/ocpp-2.0.1.md.
Load-balanced resolve
use resolve_with_action_name;
use ;
let CallResult = deserialize_to_message? else ;
let typed = resolve_with_action_name?;
Example (1.6 CALL)
use ;
use Action;
let incoming_text = r#"[2, "19223201", "BootNotification", {"chargePointVendor":"VendorX","chargePointModel":"SingleSocketCharger"}]"#;
let incoming_message = deserialize_to_message?;
if let Call = incoming_message
Out of scope
This is a protocol wire crate, not a full stack:
- No SOAP / HTTP binding for 1.6
- No WebSocket, TLS, or Security Profile handshake
- No Charge Point / CSMS state machines or OCA Part 6 runner
Contributing
Add or update tests with behavior changes. Fuzz (optional, nightly):
License: MIT.