@blokcert/node-red-contrib-ocpp
v1.8.0
Published
Node-RED nodes for OCPP (Open Charge Point Protocol) message handling via Redis Streams
Downloads
1,309
Maintainers
Readme
@blokcert/node-red-contrib-ocpp
Node-RED nodes for OCPP (Open Charge Point Protocol) message handling via Redis Streams.
Features
- OCPP 1.6 & 2.0.1 Support - Handle both protocol versions with unified message format
- Redis Streams Integration - Consumer groups for scalable message processing
- Automatic Normalization - Convert between OCPP versions transparently
- Unified Actions - Single handler for both OCPP versions (TransactionStarted, TransactionEnded, etc.)
- Unified Commands - Single command name for CSMS → Station operations (RemoteStart, GetConfig, etc.)
- CSMS Commands - Send remote commands to charging stations with automatic version detection
Installation
cd ~/.node-red
npm install /path/to/node-red-contrib-ocppOr from npm (when published):
npm install @blokcert/node-red-contrib-ocppNodes
ocpp-config
Configuration node for Redis connection settings. Shared by other OCPP nodes.
ocpp in
Receives OCPP messages from charging stations via Redis Streams.
Features:
- Consumer group support for load balancing
- Optional payload normalization (OCPP 1.6/2.0.1 → unified format)
- Filter by action type or response type
- Auto-acknowledge messages
- Unified Action routing - Use
msg.ocpp.unifiedActionto route both OCPP versions with a single handler
Filter Options:
- Empty: Receive all messages (CALL requests + responses)
- Action name (e.g.,
BootNotification): Only CALL requests with this action _CallResult: Only CALLRESULT responses_CallError: Only CALLERROR responses_Response: Both CALLRESULT and CALLERROR responses
Output:
{
payload: { /* Normalized OCPP message payload */ },
ocpp: {
messageId: "abc123",
action: "StartTransaction", // Original OCPP action
unifiedAction: "TransactionStarted", // Unified action for routing
messageType: "call", // "call", "result", or "error"
ocppMessageType: 2, // 2=CALL, 3=CALLRESULT, 4=CALLERROR
version: "1.6",
tenant: "operator1",
deviceId: "charger001",
identity: "operator1:charger001",
timestamp: 1699999999999,
streamId: "1699999999999-0"
}
}ocpp out
Sends OCPP responses back to charging stations.
Features:
- Automatic denormalization (unified → OCPP version)
- Error response support
- Auto-acknowledge inbound message
Input:
// Normal response
msg.payload = {
status: "Accepted",
currentTime: new Date().toISOString(),
interval: 300
};
// Error response
msg.ocpp.error = true;
msg.ocpp.errorCode = "NotImplemented";
msg.ocpp.errorDescription = "Action not supported";ocpp command
Sends CSMS-initiated commands to charging stations and receives responses.
Features:
- Unified Commands - Use a single command name for both OCPP versions
- Automatic Version Detection - Reads device OCPP version from Redis connection registry
- Timeout handling with error output
Unified Commands:
| Unified Command | OCPP 1.6 | OCPP 2.0.1 | Description |
|-----------------|----------|------------|-------------|
| RemoteStart | RemoteStartTransaction | RequestStartTransaction | Start charging remotely |
| RemoteStop | RemoteStopTransaction | RequestStopTransaction | Stop charging remotely |
| GetConfig | GetConfiguration | GetVariables | Get device configuration |
| SetConfig | ChangeConfiguration | SetVariables | Set device configuration |
| GetLog | GetDiagnostics | GetLog | Get diagnostics/log |
| Trigger | TriggerMessage | TriggerMessage | Request status update |
| Reset | Reset | Reset | Reboot the charging station |
| Unlock | UnlockConnector | UnlockConnector | Unlock a connector |
| Availability | ChangeAvailability | ChangeAvailability | Set connector availability |
| ClearCache | ClearCache | ClearCache | Clear authorization cache |
| Reserve | ReserveNow | ReserveNow | Reserve a connector |
| CancelReserve | CancelReservation | CancelReservation | Cancel a reservation |
Also supports version-specific commands:
- All native OCPP 1.6 and 2.0.1 commands can be sent directly
Response Message:
{
payload: { /* device response payload */ },
ocpp: {
messageId: "abc123",
action: "GetConfiguration", // Version-specific action sent
command: "GetConfig", // Original unified command
version: "1.6", // Device OCPP version
tenant: "operator1",
deviceId: "charger001",
identity: "operator1:charger001",
response: true,
error: false,
sentAt: 1699999999999,
receivedAt: 1699999999150,
latency: 150
}
}Unified Action Mapping (CS → CSMS)
Use msg.ocpp.unifiedAction to route messages from both OCPP versions with a single handler.
| Unified Action | OCPP 1.6 | OCPP 2.0.1 |
|----------------|----------|------------|
| TransactionStarted | StartTransaction | TransactionEvent (eventType: Started) |
| TransactionEnded | StopTransaction | TransactionEvent (eventType: Ended) |
| TransactionUpdated | MeterValues (with transactionId) | TransactionEvent (eventType: Updated) |
| MeterValues | MeterValues (without transactionId) | MeterValues |
| LogStatus | DiagnosticsStatusNotification | LogStatusNotification |
Actions that remain the same in both versions:
- BootNotification, Heartbeat, StatusNotification, Authorize
- DataTransfer, FirmwareStatusNotification
- SecurityEventNotification, NotifyEvent, NotifyReport (2.0.1 only)
Unified Command Mapping (CSMS → CS)
Use unified command names to send commands to devices regardless of their OCPP version.
RemoteStart
msg.ocpp = {
tenant: "operator1",
deviceId: "charger001",
command: "RemoteStart" // Automatically converts to version-specific action
};
msg.payload = {
idToken: "RFID12345",
connectorId: 1 // or evseId for 2.0.1
};GetConfig
msg.ocpp = {
tenant: "operator1",
deviceId: "charger001",
command: "GetConfig"
};
msg.payload = {
keys: ["HeartbeatInterval", "ConnectionTimeOut"] // Optional, empty = get all
};SetConfig
msg.ocpp = {
tenant: "operator1",
deviceId: "charger001",
command: "SetConfig"
};
msg.payload = {
key: "HeartbeatInterval",
value: 300
};GetLog
msg.ocpp = {
tenant: "operator1",
deviceId: "charger001",
command: "GetLog"
};
msg.payload = {
location: "ftp://logs.example.com/upload",
logType: "DiagnosticsLog", // 2.0.1: "DiagnosticsLog" or "SecurityLog"
retries: 3,
retryInterval: 60,
oldestTimestamp: "2024-01-01T00:00:00Z",
latestTimestamp: "2024-01-02T00:00:00Z"
};Trigger
msg.ocpp = {
tenant: "operator1",
deviceId: "charger001",
command: "Trigger"
};
msg.payload = {
requestedMessage: "StatusNotification",
connectorId: 1 // Optional, converts to evse for 2.0.1
};
// Auto-converts to:
// 1.6: { requestedMessage: "StatusNotification", connectorId: 1 }
// 2.0.1: { requestedMessage: "StatusNotification", evse: { id: 1 } }Reset
msg.ocpp = {
tenant: "operator1",
deviceId: "charger001",
command: "Reset"
};
msg.payload = {
type: "Soft", // "Soft" or "Hard"
evseId: 1 // Optional, 2.0.1 only
};
// Auto-converts type values:
// 1.6: { type: "Soft" }
// 2.0.1: { type: "OnIdle", evseId: 1 } (Soft→OnIdle, Hard→Immediate)Availability
msg.ocpp = {
tenant: "operator1",
deviceId: "charger001",
command: "Availability"
};
msg.payload = {
available: false, // true=Operative, false=Inoperative
connectorId: 1
};
// Auto-converts to:
// 1.6: { connectorId: 1, type: "Inoperative" }
// 2.0.1: { operationalStatus: "Inoperative", evse: { id: 1 } }Reserve
msg.ocpp = {
tenant: "operator1",
deviceId: "charger001",
command: "Reserve"
};
msg.payload = {
reservationId: 123,
idTag: "RFID12345", // Converts to idToken object for 2.0.1
expiryDate: "2024-12-31T23:59:59Z",
connectorId: 1 // Optional
};
// Auto-converts to:
// 1.6: { connectorId: 1, expiryDate: "...", idTag: "RFID12345", reservationId: 123 }
// 2.0.1: { id: 123, expiryDateTime: "...", idToken: { idToken: "RFID12345", type: "ISO14443" }, evseId: 1 }Message Normalization
The nodes automatically normalize OCPP messages to a unified format, allowing you to handle both OCPP 1.6 and 2.0.1 with the same logic.
BootNotification
| OCPP 1.6 | OCPP 2.0.1 | Unified | |----------|------------|---------| | chargePointVendor | chargingStation.vendorName | vendor | | chargePointModel | chargingStation.model | model | | chargePointSerialNumber | chargingStation.serialNumber | serialNumber | | firmwareVersion | chargingStation.firmwareVersion | firmwareVersion |
StatusNotification
| OCPP 1.6 | OCPP 2.0.1 | Unified | |----------|------------|---------| | connectorId | evseId + connectorId | evseId, connectorId | | status | connectorStatus | status | | errorCode | (not in 2.0.1) | errorCode |
Transaction Events (Unified Format)
Both StartTransaction (1.6) and TransactionEvent:Started (2.0.1) normalize to:
{
idToken: "RFID12345",
idTokenType: "ISO14443",
evseId: 1,
connectorId: 1,
meterStart: 1000,
timestamp: "2024-01-01T10:00:00Z",
triggerReason: "Authorized"
}LogStatus (Unified Format)
Both DiagnosticsStatusNotification (1.6) and LogStatusNotification (2.0.1) normalize to:
{
status: "Uploading",
requestId: 123, // null for 1.6
type: "Diagnostics" // "Diagnostics" for 1.6, "Log" for 2.0.1
}Example Flow
[ocpp in] → [switch by unifiedAction] → [TransactionStarted handler] → [ocpp out]
→ [TransactionEnded handler] → [ocpp out]
→ [TransactionUpdated handler] → [ocpp out]
→ [LogStatus handler] → [ocpp out]
→ [default handler] → [ocpp out]Switch Node Configuration
Route by msg.ocpp.unifiedAction:
- TransactionStarted
- TransactionEnded
- TransactionUpdated
- LogStatus
- BootNotification
- Heartbeat
- StatusNotification
- (etc.)
Redis Data Structures
| Key | Type | Description |
|-----|------|-------------|
| ws:inbound | Stream | Messages from devices (consumer group: biz-workers) |
| ws:out:{tenant}:{deviceId} | Stream | Messages to specific device |
| ws:conn:{tenant}:{deviceId} | Hash | Connection registry (includes OCPP version) |
| ws:pending:{tenant}:{deviceId} | Hash | Pending command tracking |
Requirements
- Node-RED >= 2.0.0
- Node.js >= 18.0.0
- Redis >= 6.0 (for Streams support)
Changelog
See CHANGELOG.md for version history.
License
MIT
Related
- OCPP WebSocket Server - The WebSocket server that works with these nodes
