OCPP WS IO

Browser Client

Use BrowserOCPPClient in browser environments — React, Vue, Next.js, and more.

BrowserOCPPClient is a lightweight OCPP WebSocket RPC client designed for browser environments. It enables building charge point simulators, testing dashboards, and debugging tools directly in the browser — using the same typed API as OCPPClient.

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

[!IMPORTANT] The browser client is designed for testing and simulating charge points — it does not support all OCPP features. Missing: Security Profiles (0–3), Strict Mode (schema validation), TLS/mTLS configuration, WebSocket Ping/Pong, and custom HTTP headers. For production charge point communication, use OCPPClient in a Node.js environment.

Limitations vs OCPPClient

OCPPClient depends on Node.js modules (ws, node:crypto, node:events, node:net) — it can't run in the browser. BrowserOCPPClient replaces these with browser-native APIs, but this comes with trade-offs:

FeatureOCPPClientBrowserOCPPClient
WebSocketws (Node.js)Native browser WebSocket
Eventsnode:eventsCustom lightweight EventEmitter
ID Generation@paralleldrive/cuid2@paralleldrive/cuid2
Security Profiles0–3 (TLS, mTLS, certs)N/A (handled by browser/TLS)
Custom Headers✅ via ws❌ browser limitation
Ping/Pong❌ browser limitation
Type Safety✅ Full✅ Full (same generated types)
Reconnection
Strict Mode

Quick Start

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

const client = new BrowserOCPPClient({
  endpoint: "wss://csms.example.com/ocpp",
  identity: "CP001",
  protocols: ["ocpp1.6"],
});

// Register a handler — params are auto-typed for OCPP 1.6 Reset
client.handle("Reset", ({ params }) => {
  console.log("Reset type:", params.type);
  return { status: "Accepted" };
});

// Connect and send a BootNotification
await client.connect();

const response = await client.call("ocpp1.6", "BootNotification", {
  chargePointVendor: "VendorX",
  chargePointModel: "ModelY",
});

console.log("Status:", response.status); // typed: "Accepted" | "Pending" | "Rejected"

Configuration

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 consecutive bad messages
respondWithDetailedErrorsbooleanfalseInclude error details in RPC error responses

Connection Lifecycle

Connection States

BrowserOCPPClient.CONNECTING; // 0
BrowserOCPPClient.OPEN; // 1
BrowserOCPPClient.CLOSING; // 2
BrowserOCPPClient.CLOSED; // 3

// Check current state
if (client.state === BrowserOCPPClient.OPEN) {
  await client.call("Heartbeat", {});
}

Properties

PropertyTypeDescription
client.identitystringCharging station identity
client.protocolstring | undefinedNegotiated OCPP subprotocol
client.stateConnectionStateCurrent connection state

Making Calls

// Version-aware call — fully typed params and response
const result = await client.call("ocpp1.6", "BootNotification", {
  chargePointVendor: "VendorX",
  chargePointModel: "ModelY",
});
result.status; // typed: "Accepted" | "Pending" | "Rejected"

// OCPP 2.0.1 — different shape, still fully typed
const result201 = await client.call("ocpp2.0.1", "BootNotification", {
  chargingStation: { model: "ModelX", vendorName: "VendorY" },
  reason: "PowerUp",
});

// Default protocol call (uses the client's type parameter P)
const res = await client.call("Heartbeat", {});

// Explicit response type (for custom/vendor methods)
const custom = await client.call<{ result: string }>("VendorAction", {
  data: "hello",
});

Call Options

// Timeout
const res = await client.call(
  "Reset",
  { type: "Soft" },
  {
    timeoutMs: 5000,
  },
);

// AbortSignal
const controller = new AbortController();
const res2 = await client.call(
  "Heartbeat",
  {},
  {
    signal: controller.signal,
  },
);

// Cancel the call
controller.abort();

Handling Incoming Calls

Register handlers for incoming server-to-client calls. The API is identical to OCPPClient.handle().

// Version-specific handler — only triggers for ocpp1.6
client.handle("ocpp1.6", "Reset", ({ params }) => {
  params.type; // typed: "Hard" | "Soft" (OCPP 1.6 shape)
  return { status: "Accepted" };
});

// Generic handler — triggers for any negotiated protocol
client.handle("Reset", ({ params, protocol }) => {
  console.log(`Reset via ${protocol}:`, params.type);
  return { status: "Accepted" };
});

// Wildcard handler — catches all unhandled methods
client.handle((method, { params }) => {
  console.log(`Unhandled method: ${method}`);
  return {};
});

Handler Priority

When a call arrives, handlers are checked in this order:

  1. Version-specific handler (e.g., "ocpp1.6:Reset")
  2. Generic handler (e.g., "Reset")
  3. Wildcard handler

NOREPLY

Return NOREPLY from a handler to suppress the automatic response:

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

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

Removing Handlers

client.removeHandler("Reset"); // remove generic
client.removeHandler("ocpp1.6", "Reset"); // remove version-specific
client.removeHandler(); // remove wildcard
client.removeAllHandlers(); // remove all

Events

client.on("open", (event) => {
  /* WebSocket connected */
});

client.on("close", ({ code, reason }) => {
  /* WebSocket disconnected */
});

client.on("error", (error) => {
  /* Connection or WebSocket error */
});

client.on("connecting", ({ url }) => {
  /* Attempting connection */
});

client.on("reconnect", ({ attempt, delay }) => {
  /* Scheduled reconnection */
});

client.on("message", (message) => {
  /* Any parsed OCPP message */
});

client.on("call", (call) => {
  /* Incoming OCPP Call */
});

client.on("callResult", (result) => {
  /* Received CallResult */
});

client.on("callError", (error) => {
  /* Received CallError */
});

client.on("badMessage", ({ message, error }) => {
  /* Malformed message received */
});

Reconnection

BrowserOCPPClient supports automatic reconnection with exponential backoff, identical to OCPPClient:

const client = new BrowserOCPPClient({
  identity: "CP001",
  endpoint: "wss://csms.example.com/ocpp",
  protocols: ["ocpp1.6"],
  reconnect: true, // default: true
  maxReconnects: 10, // default: Infinity
  backoffMin: 1000, // default: 1000ms
  backoffMax: 30000, // default: 30000ms
});

client.on("reconnect", ({ attempt, delay }) => {
  console.log(`Reconnect attempt ${attempt} in ${delay}ms`);
});

client.on("close", ({ code, reason }) => {
  console.log(`Disconnected: ${code} ${reason}`);
});

Toggle Reconnection at Runtime

// Disable reconnection
client.reconfigure({ reconnect: false });

// Re-enable with different settings
client.reconfigure({
  reconnect: true,
  maxReconnects: 5,
  backoffMin: 2000,
});

Closing the Connection

// Graceful close (waits for pending calls)
await client.close();

// Custom close code and reason
await client.close({ code: 1000, reason: "User navigated away" });

// Force close (immediately terminates)
await client.close({ force: true });

// Wait for in-flight calls to complete first
await client.close({ awaitPending: true });

Framework Integration

React

import { useEffect, useRef, useState } from "react";
import { BrowserOCPPClient } from "ocpp-ws-io/browser";

function useOCPP(identity: string, endpoint: string) {
  const clientRef = useRef<BrowserOCPPClient | null>(null);
  const [connected, setConnected] = useState(false);

  useEffect(() => {
    const client = new BrowserOCPPClient({
      identity,
      endpoint,
      protocols: ["ocpp1.6"],
    });

    client.on("open", () => setConnected(true));
    client.on("close", () => setConnected(false));

    client.connect();
    clientRef.current = client;

    return () => { client.close(); };
  }, [identity, endpoint]);

  return { client: clientRef.current, connected };
}

// Usage
function ChargingStation() {
  const { client, connected } = useOCPP("CP001", "wss://csms.example.com/ocpp");

  const sendBoot = async () => {
    if (!client) return;
    const res = await client.call("BootNotification", {
      chargePointVendor: "VendorX",
      chargePointModel: "ModelY",
    });
    console.log("Boot:", res.status);
  };

  return (
    <div>
      <p>Status: {connected ? "Connected" : "Disconnected"}</p>
      <button onClick={sendBoot} disabled={!connected}>Send Boot</button>
    </div>
  );
}

Next.js (Client Component)

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

// ✅ Works in client components — no Node.js dependencies
const client = new BrowserOCPPClient({
  identity: "CP001",
  endpoint: "wss://csms.example.com/ocpp",
  protocols: ["ocpp1.6"],
});

Note: OCPPClient from "ocpp-ws-io" cannot be imported in client components — it requires Node.js modules. Use BrowserOCPPClient from "ocpp-ws-io/browser" instead.

Vue

import { ref, onMounted, onUnmounted } from "vue";
import { BrowserOCPPClient } from "ocpp-ws-io/browser";

export function useOCPP(identity: string, endpoint: string) {
  const client = ref<BrowserOCPPClient | null>(null);
  const connected = ref(false);

  onMounted(() => {
    const c = new BrowserOCPPClient({
      identity,
      endpoint,
      protocols: ["ocpp1.6"],
    });

    c.on("open", () => (connected.value = true));
    c.on("close", () => (connected.value = false));

    c.connect();
    client.value = c;
  });

  onUnmounted(() => {
    client.value?.close();
  });

  return { client, connected };
}

Browser Exports

All exports available from the ocpp-ws-io/browser subpath:

import {
  // Client
  BrowserOCPPClient,

  // Error classes
  RPCGenericError,
  RPCNotImplementedError,
  RPCNotSupportedError,
  RPCInternalError,
  RPCProtocolError,
  RPCSecurityError,
  RPCFormatViolationError,
  RPCFormationViolationError,
  RPCPropertyConstraintViolationError,
  RPCOccurrenceConstraintViolationError,
  RPCTypeConstraintViolationError,
  RPCMessageTypeNotSupportedError,
  RPCFrameworkError,
  TimeoutError,

  // Utilities
  createRPCError,
  getErrorPlainObject,

  // Constants
  ConnectionState,
  MessageType,
  NOREPLY,
} from "ocpp-ws-io/browser";

All types from the main package (OCPPProtocol, AllMethodNames, OCPPRequestType, OCPPResponseType, etc.) are re-exported for full type safety.

On this page