ocpp-ws-io 소개: Node.js용 타입 안전 OCPP 생태계 ⚡

발행: (2026년 3월 8일 AM 12:09 GMT+9)
10 분 소요
원문: Dev.to

Source: Dev.to

Introducing ocpp-ws-io: 타입‑세이프 OCPP 에코시스템 for Node.js ⚡

Rohit Tiwari

개요

EV(전기차) 충전 산업을 위한 소프트웨어를 만든 적이 있다면, Open Charge Point Protocol (OCPP) 가 충전소와 중앙 시스템(CSMS) 간 통신을 위한 확고한 표준이라는 것을 알 것입니다.

하지만 확장 가능하고 신뢰성 있으며 보안이 보장된 OCPP‑호환 시스템을 구축하는 것은 악명 높게 어렵습니다. 개발자들은 종종 페이로드 형태를 추측하고, JSON 스키마를 수동으로 검증하며, 복잡한 WebSocket 프레이밍을 구현하고, 연결 끊김을 처리하는 데 어려움을 겪습니다.

그래서 저는 ocpp-ws-io 를 만들었습니다 — TypeScript로 처음부터 구축한 타입 안전하고 프로덕션 준비된 OCPP WebSocket RPC 클라이언트 및 서버 생태계로, Node.js용입니다.

🚀 왜 또 다른 OCPP 라이브러리가 필요할까요?

  • 🎯 End‑to‑End Type Safety: OCPP 1.6, 2.0.1, 2.1 모든 메서드를 포괄하는 완전 자동 생성 TypeScript 타입을 제공합니다. BootNotification 페이로드가 어떻게 생겼는지 추측할 필요가 없습니다.
  • 📐 Strict Schema Validation: 비즈니스 로직이 메시지를 처리하기 전에 내장된 JSON‑schema 검증을 수행하는 선택적 엄격 모드.
  • 🛜 Router Built‑In: 모듈화되고 깔끔한 코드를 위한 Express/Hono 스타일 라우터를 제공하여 관리가 용이합니다.
  • 🔒 Comprehensive Security: OCA Security Profiles 0–3 (Plain WS, Basic Auth, TLS + Basic Auth, Mutual TLS)을 바로 사용할 수 있습니다.
  • 🚦 DDoS Protection & Rate Limiting: 스테이션 및 메서드별 소켓 레이어 토큰 버킷 레이트 리밋을 제공합니다.
  • 🔁 Resilience: 지수 백오프 자동 재연결, Redis 상태 동기화, 그리고 Idempotency Keys를 통해 재시도 시 정확히 한 번만 메시지가 전달되도록 보장합니다.
  • 🧩 Framework‑Agnostic: 독립적으로 사용하거나 Express, Fastify, NestJS, 혹은 커스텀 HTTP 서버에 손쉽게 연결할 수 있습니다.
  • 📡 Built for Scale: 멀티 인스턴스 배포를 위한 Redis 어댑터와 Streams를 이용한 내구성 있는 메시지 전달을 지원합니다.

💻 코드가 말보다 크게 말한다

서버 (CSMS)

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

const server = new OCPPServer({
  protocols: ["ocpp1.6", "ocpp2.0.1"],
  logging: { prettify: true, exchangeLog: true, level: "info" }, // Powered by voltlog-io!
});

// Authenticate incoming connections
server.auth((ctx) => {
  console.log(`Connection attempt from ${ctx.handshake.identity}`);
  ctx.accept({ session: { authorized: true } });
});

server.on("client", (client) => {
  console.log(`${client.identity} connected via ${client.protocol}`);

  // Type‑safe RPC handler
  client.handle("ocpp1.6", "BootNotification", ({ params }) => ({
    status: "Accepted",
    currentTime: new Date().toISOString(),
    interval: 300,
  }));
});

await server.listen(3000);
console.log("⚡ OCPP Server running on port 3000");

클라이언트 (충전소 시뮬레이터)

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

const client = new OCPPClient({
  endpoint: "ws://localhost:3000/api/v1/chargers",
  identity: "CP001",
  protocols: ["ocpp1.6"],
  securityProfile: SecurityProfile.NONE,
});

// Handle commands from the central system
client.handle("Reset", ({ params }) => {
  console.log("CSMS requested a Reset of type:", params.type);
  return { status: "Accepted" };
});

await client.connect();

// Send an RPC request and await the result!
const response = await client.call("ocpp1.6", "BootNotification", {
  chargePointVendor: "VendorX",
  chargePointModel: "ModelY",
});

console.log("Central System response status:", response.status); // Type‑checked!

🛜 Express‑Style 라우팅 및 미들웨어

ocpp-ws-io의 눈에 띄는 기능 중 하나는 강력한 라우팅 및 미들웨어 시스템으로, Express나 Hono와 똑같은 느낌을 주도록 설계되었습니다. 이를 통해 모듈식이고 깔끔하며 관리가 쉬운 CSMS 아키텍처를 구축할 수 있습니다.

HTTP Upgrade 요청(연결 단계)과 들어오고 나가는 OCPP RPC 메시지(메시지 단계)를 가로챌 수 있습니다.

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

const server = new OCPPServer({ protocols: ["ocpp1.6"] });

// 1️⃣ Connection middleware: block bad IPs or rate‑limit before WebSockets even open!
const rateLimiter = defineMiddleware(async (ctx, next) => {
  if (isRateLimited(ctx.handshake.remoteAddress)) {
    ctx.reject(429, "Too Many Requests"); // Instantly drops the connection
  } else {
    await next();
  }
});

server.use(rateLimiter);

// 2️⃣ Create dynamic routes with wildcard parameter extraction
const chargerRoute = server.route("/api/v1/chargers/:id");

chargerRoute.on("client", (client) => {
  console.log(`Charger connected at endpoint: ${client.handshake.pathname}`);

  // 3️⃣ Message middleware: log processing times for every single RPC call
  client.use(async (ctx, next) => {
    const start = Date.now();
    await next();
    console.log(`[${ctx.action}] took ${Date.now() - start}ms`);
  });

  client.handle("BootNotification", ({ params }) => ({
    status: "Accepted",
    currentTime: new Date().toISOString(),
    interval: 300,
  }));
});

await server.listen(3000);

보다 고급 라우팅 시나리오에 대해서는 문서를 참고하세요: https://ocpp-ws-io.rohittiwari.me/docs/routing

🪵 일류 구조화 로깅 (voltlog-io)

고성능 WebSocket 환경은 표준 console.log으로 디버깅하기가 악몽과 같습니다. 그래서 ocpp-ws-iovoltlog‑io 로 구동되는 내장 구조화 JSON 로깅을 포함합니다.

단일 설정 토글만으로 다음을 얻을 수 있습니다:

  • 프로덕션용으로 매우 빠른 JSON 로깅.
  • 로컬 개발을 위한 지연 시간 메트릭이 포함된 아름답고 색상으로 구분된 출력 (prettify: true).

Exchange Logs (exchangeLog: true)는 모든 인바운드 ([IN]) 및 아웃바운드 ([OUT]) OCPP 명령을 완벽하게 추적합니다.

⚡ CP-101  →  BootNotification  [OUT]
✅ CP-101  ←  BootNotification  [IN]   { latencyMs: 45 }

🌐 브라우저 클라이언트

충전기나 프록시와 직접 통신하는 웹 UI, CSMS 대시보드, 혹은 테스트 인터페이스를 구축해야 하나요? 우리는 또한 Browser Client (ocpp-ws-io/browser)를 제공하는데, 이는 의존성이 전혀 없으며 vanilla JS, React, Vue, Svelte 어디서든 완벽히 실행됩니다. 서버에서 제공하는 엄격한 타입 안전성이 브라우저에서도 그대로 사용 가능합니다!

🛠️ ocpp-ws-cli 생태계

Install from npm

훌륭한 개발자 도구가 없는 라이브러리는 전쟁의 절반에 불과합니다. 핵심 ocpp-ws-io 패키지와 함께 ocpp-ws-cli 를 출시했으며, 이는 OCPP 개발자를 위한 궁극적인 CLI입니다.

npx ocpp-ws-cli 로 즉시 사용할 수 있는 이 툴킷은 백엔드를 구축하고 테스트하는 방식을 완전히 바꿔줍니다:

  • 🎮 ocpp simulate – 가상 충전소와 인터랙티브 터미널 UI (부팅 시퀀스, 하트비트, 실시간 전압/전류/전력, 플러그인, RFID, 오류 상태).
  • 📡 ocpp mock – 프런트엔드 개발을 위한 더미 MeterValues, StatusNotification, Heartbeat 데이터를 스트리밍하는 SSE 모크 서버.
  • 🚄 ocpp bench – 백분위수 메트릭과 실시간 대시보드를 제공하는 처리량 및 지연 시간 벤치마크 엔진.
  • 💣 ocpp load-test – 수천 개의 동시 충전소 연결을 시뮬레이션하는 분산 부하 엔진.
  • 👾 ocpp fuzz – 잘못된 JSON 페이로드를 CSMS에 대량 전송하여 strict‑mode 처리를 테스트하는 프로토콜 혼돈 엔진.
  • 🔐 ocpp certs – OCA Profile 2 & 3 테스트를 위한 4096‑비트 루트 CA와 서명된 서버/클라이언트 .pem 인증서를 자동 생성.
  • 🗂️ ocpp audit – 자동화된 테스트를 실행하고 마크다운 로드맵(audit‑report.md)을 생성하는 보안 마법사.
  • 📝 ocpp generate – 맞춤형 .json 스키마를 .d.ts 선언 라이브러리로 변환하여 100 % 타입 안전성을 제공.
  • 🧪 ocpp test – 모듈화된 OCTT 준수 테스트 스위트를 서버에 직접 실행.

🌟 참여하기

전기차 인프라 생태계가 빠르게 성장하고 있으며, 견고한 오픈‑소스 도구가 그 성장의 핵심이 될 것입니다. 다음 큰 CSMS 플랫폼을 구축하든, 전기차 충전 앱을 만들든, 혹은 단순히 업계에 대해 배우고 있든, ocpp-ws-io 를 한 번 사용해 보세요!

우리는 피드백, 이슈, 풀 리퀘스트를 적극적으로 기다리고 있습니다. 아래 댓글에 여러분의 의견을 알려 주세요. 즐거운 충전 되세요! ⚡🚗

0 조회
Back to Blog

관련 글

더 보기 »