OCPP WS IOocpp-ws-io
Core WebSocket RPC

API Reference

Detailed API reference for OCPPClient and OCPPServer.

OCPPClient

import { OCPPClient } from "ocpp-ws-io";

Constructor

const client = new OCPPClient(options: ClientOptions);

ClientOptions

OptionTypeDefaultDescription
identitystringrequiredCharging station ID
endpointstringrequiredWebSocket URL (ws:// or wss://)
protocolsstring[][]OCPP subprotocols to negotiate
securityProfileSecurityProfileNONESecurity profile (0–3)
passwordstring | BufferPassword for Basic Auth (Profile 1 & 2)
tlsTLSOptionsTLS/SSL options (Profile 2 & 3)
headersRecord<string, string>Additional WebSocket headers
queryRecord<string, string>Additional URL query parameters
reconnectbooleantrueAuto-reconnect on disconnect
maxReconnectsnumberInfinityMax reconnection attempts
pingIntervalMsnumber30000Includes ±25% randomized jitter
strictModeboolean | string[]falseEnable/restrict schema validation
strictModeMethodsstring[]Restrict validation to specific methods
loggingLoggingConfig{}Configuration for structured logging.
offlineQueuebooleanfalseQueue calls while disconnected, flush on reconnect.
offlineQueueMaxSizenumber100Max offline queue size before oldest are dropped.
compressionboolean | CompressionOptionsfalseEnable WebSocket permessage-deflate compression.

LoggingConfig

OptionTypeDefaultDescription
enabledbooleantrueEnable or disable all logging.
levelstring'info'Minimum log level (trace, debug, info, warn, error, fatal).
prettifybooleanfalseUse prettyTransport for human-readable output (colors, icons).
exchangeLogbooleanfalseLog all OCPP messages with direction (IN/OUT) and metadata.
loggerLoggerLikeundefinedCustom logger instance (e.g., Pino) to replace the default logger.
handlerfunctionundefinedCustom voltlog-io transport function (entry) => void | Promise<void>
showMetadatabooleantrueShow trailing metadata object in logs.
showSourceMetabooleantrueShow source context (component, identity).
prettifySourcebooleanfalseCompact source tag [OCPPServer/CP-1].
prettifyMetadatabooleanfalseFormat metadata as key=value pairs.

Methods

connect()

Connect to the OCPP server.

await client.connect();

call(protocol?, method, params, options?)

Make an RPC call. Throws a TimeoutError or protocol-level Error if the request fails. Make an RPC call. Throws a TimeoutError or protocol-level Error if the request fails.

  • protocol: Optional. e.g., "ocpp1.6". If omitted, generic type inference is used.
  • method: The OCPP method name (e.g., "BootNotification").
  • params: The request payload.
  • options: { timeoutMs?: number, retries?: number, idempotencyKey?: string }
// With manual idempotency key to prevent double execution on reconnections
const result = await client.call("ocpp1.6", "BootNotification", { ... }, { idempotencyKey: "unique-boot-123" });

safeCall(protocol?, method, params, options?)

Exactly like call(), except it catches all errors and returns the response payload on success, or undefined on error rather than throwing. Useful for fire-and-forget or localized error handling without breaking loops.

const result = await client.safeCall(
  "ocpp1.6",
  "ClearCache",
  {},
  { timeoutMs: 15000 },
);

if (result === undefined) {
  client.logger.warn("Station failed to clear cache", { error });
}

handle(protocol?, method, handler)

Register an RPC handler.

  • protocol: Optional. If provided, handler only triggers for this protocol version.
  • method: The OCPP method name.
  • handler: (context) => Response | Promise<Response>
// Version specific
client.handle("ocpp1.6", "Reset", ({ params }) => { ... });

// Generic
client.handle("Reset", ({ params }) => { ... });

// Catch-all
client.handle((method, { params }) => { ... });

close(options?)

Close the connection gracefully or forcefully.

By default, calling close() will wait for all pending RPC requests to complete before terminating the socket to prevent interrupting in-flight operations.

// Graceful close (waits for pending calls, sends 1000 code)
await client.close({ code: 1000, reason: "Normal Closure" });

// Forceful immediate drop (useful during DDoS or severe errors)
await client.close({ force: true });

// Graceful WS close, but skips waiting for pending asynchronous RPC calls
await client.close({ awaitPending: false });

Properties

logger

A fully initialized voltlog-io instance localized to this client. Automatically includes the client identity and component: "OCPPClient" in the context of every log message.

client.logger.info("Initializing updates", { pendingFiles: 4 });

OCPPServer

import { OCPPServer } from "ocpp-ws-io";

Constructor

const server = new OCPPServer(options?: ServerOptions);

ServerOptions

OptionTypeDefaultDescription
protocolsstring[][]Accepted OCPP subprotocols
securityProfileSecurityProfileNONESecurity profile
handshakeTimeoutMsnumber30000Timeout for WebSocket handshake (ms)
tlsTLSOptionsTLS options (Profile 2 & 3)
loggingLoggingConfig{}Configuration for structured logging.
sessionTtlMsnumber7200000Garbage collection inactivity timeout
rateLimitRateLimitOptionsToken bucket socket & method limiter
healthEndpointbooleanfalseExpose HTTP /health and /metrics
maxPayloadBytesnumber65536Max WebSocket frame size in bytes. Rejects oversized messages at the transport layer before any parsing. Prevents OOM from malicious payloads.
workerThreadsboolean | objectfalseEnable worker thread pool for JSON parsing. true = auto pool size, { poolSize, maxQueueSize } for fine-tuning.
compressionboolean | CompressionOptionsfalseEnable WebSocket permessage-deflate compression. true = sensible defaults (threshold: 1024, level: 6).

CompressionOptions

OptionTypeDefaultDescription
thresholdnumber1024Minimum payload size (bytes) to compress.
levelnumber6zlib compression level (1=fastest, 9=smallest).
memLevelnumber8zlib memory level (1–9).
serverNoContextTakeoverbooleantrueDon't retain server deflate context (saves ~120KB/conn).
clientNoContextTakeoverbooleantrueDon't retain client deflate context.

RateLimitOptions

OptionTypeDefaultDescription
limitnumberMax messages allowed globally per window
windowMsnumberTime window in milliseconds
onLimitExceeded"ignore" | "disconnect" | function"ignore"Action to execute when limit is breached
methodsRecord<string, { limit; windowMs }>Deep method-wise limits (e.g. Heartbeat)

CORSOptions

OptionTypeDefaultDescription
allowedOriginsstring[]Origins allowed to connect via WebSocket
allowedIPsstring[]Exact IPv4/v6 or CIDR IP ranges (e.g. /24)
allowedSchemes("ws" | "wss")[]Restrict connections to specific protocols

Methods

listen(port, host?, options?)

Start listening on a port. Returns the http.Server instance.

auth(handler)

Attach authentication logic.

server.auth((ctx) => {
  // ctx.handshake has .identity, .pathname, .headers, etc.
  ctx.accept({ session: { ... } }); // Attach session data to client
});

cors(options)

Apply CORS rules directly to the server or router levels. This protects endpoints from unauthorized WebSocket hijacking or public IP access.

server.cors({
  allowedOrigins: ["https://dashboard.example.com"],
  allowedIPs: ["192.168.1.0/24", "10.0.0.5"],
  allowedSchemes: ["wss"],
});

on("client", handler)

Listen for new connections.

server.on("client", (client) => {
  // client is an OCPPServerClient (extends OCPPClient)
  console.log(client.session); // Access session data
});

updateTLS(options)

Hot-reload TLS certificates on all active HTTPS servers without dropping connections. Only valid when using SecurityProfile.TLS_BASIC_AUTH or TLS_CLIENT_CERT.

server.updateTLS({
  cert: fs.readFileSync("./certs/server.crt"),
  key: fs.readFileSync("./certs/server.key"),
});

See TLS Certificate Hot-Reload for full details.

on("securityEvent", handler)

Emitted for every security-relevant action. Useful for SIEM, alerting, and audit logging.

server.on("securityEvent", (event) => {
  // event.type: "AUTH_FAILED" | "CONNECTION_RATE_LIMIT" | "UPGRADE_ABORTED"
  siem.log(event);
});

See Security Event Monitoring for full details.

sendToClient(identity, protocol?, method, params, options?)

Helper method to dispatch an outgoing RPC call to a specific connected client by its identity. Throws an error if the station is not connected. Matches the client.call() signature and supports timeoutMs in the options argument.

const result = await server.sendToClient(
  "CP-001",
  "ocpp1.6",
  "Reset",
  {
    type: "Soft",
  },
  { timeoutMs: 10000 },
);

safeSendToClient(identity, protocol?, method, params, options?)

Exactly like sendToClient(), but catches errors (and disconnected station errors), returning the response payload on success, or undefined on error. Highly recommended for bulk operations across your cluster where individual failures shouldn't throw exceptions.

const result = await server.safeSendToClient(
  "CP-001",
  "ocpp1.6",
  "UpdateFirmware",
  { location: "..." },
  { timeoutMs: 30000 },
);

if (result !== undefined) {
  console.log("Firmware update accepted");
}

broadcastBatch(identities, method, params, options?)

Broadcast an identical RPC call to many stations concurrently. For clustered architectures, unicast commands are grouped and dispatched in pipeline batches via the adapter's streams, reducing per-message TCP round-trip overhead.

const targets = ["CP-001", "CP-002", "CP-003", ...thousands];

await server.broadcastBatch(targets, "Reset", { type: "Hard" });

stats()

Returns instantaneous observability metrics about the server's local node status. This is deeply integrated with standard Node.js internals to supply immediate health checks for Prometheus and Loki collection.

const telemetry = server.stats();

console.log(`Active Managed Sessions: ${telemetry.activeSessions}`);
console.log(`Active Raw WebSockets: ${telemetry.webSockets?.total}`);
console.log(
  `Pending Network Flushes: ${telemetry.webSockets?.bufferedAmount} bytes`,
);
console.log(`Memory Used: ${telemetry.memoryUsage.heapUsed} bytes`);
console.log(`Uptime: ${telemetry.uptimeSeconds}s`);
console.log(`PID: ${telemetry.pid}`);

adapterMetrics()

Fetches deep backend observability from the underlying clustering adapter. When using the RedisAdapter, this returns the consumerLag (pending unread stream messages) specific to this node, enabling DevOps to perform accurate horizontal capacity auto-scaling.

const metrics = await server.adapterMetrics();
console.log("Redis Backlog:", metrics?.redisConsumerLag?.pendingMessages);

Properties

logger

An initialized voltlog-io logger isolated to the Server context (via component: "OCPPServer"). Automatically utilized by the internal router and exchange logs.

server.logger.warn("Unrecognized protocol attempted", { requested: "ocpp1.5" });

Protocol Constants

NOREPLY

Return NOREPLY from a handler to suppress the automatic response. This is useful for asynchronous processing where you might send a response later manually, or for specific OCPP flows.

import { NOREPLY } from "ocpp-ws-io";

client.handle("StatusNotification", ({ params }) => {
  // Process the notification but don't send a response immediately
  return NOREPLY;
});

BrowserOCPPClient

import { BrowserOCPPClient } from "ocpp-ws-io/browser";

A browser-compatible OCPP client with the same typed API as OCPPClient. Uses the native browser WebSocket API — no Node.js dependencies.

See Browser Client for the full guide with examples. See Browser Client for the full guide with examples.

Constructor

const client = new BrowserOCPPClient(options: BrowserClientOptions);

BrowserClientOptions

OptionTypeDefaultDescription
identitystringrequiredCharging station ID
endpointstringrequiredWebSocket URL (ws:// or wss://)
protocolsstring[][]OCPP subprotocols to negotiate
queryRecord<string, string>Additional URL query parameters
reconnectbooleantrueAuto-reconnect on disconnect
maxReconnectsnumberInfinityMax reconnection attempts
backoffMinnumber1000Initial reconnect delay (ms)
backoffMaxnumber30000Maximum reconnect delay (ms)
callTimeoutMsnumber30000Default RPC call timeout (ms)
callConcurrencynumber1Max concurrent outbound calls
maxBadMessagesnumberInfinityClose after N bad messages
respondWithDetailedErrorsbooleanfalseInclude error details in responses
loggingLoggingConfig{}Configuration for structured logging.
OptionTypeDefaultDescription
:--------------------------:-----------------------:---------:------------------------------------
identitystringrequiredCharging station ID
endpointstringrequiredWebSocket URL (ws:// or wss://)
protocolsstring[][]OCPP subprotocols to negotiate
queryRecord<string, string>Additional URL query parameters
reconnectbooleantrueAuto-reconnect on disconnect
maxReconnectsnumberInfinityMax reconnection attempts
backoffMinnumber1000Initial reconnect delay (ms)
backoffMaxnumber30000Maximum reconnect delay (ms)
callTimeoutMsnumber30000Default RPC call timeout (ms)
callConcurrencynumber1Max concurrent outbound calls
maxBadMessagesnumberInfinityClose after N bad messages
respondWithDetailedErrorsbooleanfalseInclude error details in responses
loggingLoggingConfig{}Configuration for structured logging.

Methods

All methods match OCPPClient:

await client.connect();

// Version-aware typed call
const result = await client.call("ocpp1.6", "BootNotification", { ... });
const { success } = await client.safeCall("ocpp1.6", "Heartbeat", {});
const { success } = await client.safeCall("ocpp1.6", "Heartbeat", {});

// Register handlers (version-specific, generic, wildcard)
client.handle("ocpp1.6", "Reset", ({ params }) => { ... });
client.handle("Reset", ({ params }) => { ... });
client.handle((method, { params }) => { ... });

// Close
await client.close();
await client.close({ force: true });
await client.close({ awaitPending: true });

// Runtime reconfiguration
client.reconfigure({ callTimeoutMs: 10000 });

// Handler removal
client.removeHandler("Reset");
client.removeHandler("ocpp1.6", "Reset");
client.removeAllHandlers();

// Raw message
client.sendRaw(JSON.stringify([2, "uuid", "Heartbeat", {}]));

Properties

logger

A fully initialized logger specific to the browser console. Works with browser contexts.

client.logger.info("Retrying connection...");

Properties

logger

A fully initialized logger specific to the browser console. Works with browser contexts.

client.logger.info("Retrying connection...");

Events

client.on("open", (event) => {
  /* connected */
});
client.on("close", ({ code, reason }) => {
  /* disconnected */
});
client.on("error", (error) => {
  /* error */
});
client.on("connecting", ({ url }) => {
  /* attempting */
});
client.on("reconnect", ({ attempt, delay }) => {
  /* reconnecting */
});
client.on("message", (message) => {
  /* OCPP message */
});
client.on("call", (call) => {
  /* incoming call */
});
client.on("callResult", (result) => {
  /* result received */
});
client.on("callError", (error) => {
  /* error received */
});
client.on("badMessage", ({ message, error }) => {
  /* malformed */
});

Error Classes

All error classes are exported for instanceof checks:

import {
  // Base errors
  TimeoutError, // Call timeout
  UnexpectedHttpResponse, // Non-101 upgrade response
  WebsocketUpgradeError, // WebSocket upgrade failure

  // RPC errors (OCPP-J spec Section 4.3)
  RPCGenericError,
  RPCNotImplementedError,
  RPCNotSupportedError,
  RPCInternalError,
  RPCProtocolError,
  RPCSecurityError,
  RPCFormationViolationError,
  RPCPropertyConstraintViolationError,
  RPCOccurrenceConstraintViolationError,
  RPCTypeConstraintViolationError,
  RPCGenericTransportError,
} from "ocpp-ws-io";

On this page