제8장: 구현 및 인증

弘益人間 (홍익인간) - 널리 인간을 이롭게 하라

8.1 구현 로드맵

WIA-ROB-011의 네 단계는 앞 단계를 기반으로 다음 단계가 쌓이는 구조이므로, 구현도 같은 순서로 진행하는 것이 자연스럽다. 제3장의 준수 수준과 연결하면 다음과 같다.

순서구현 대상달성 준수 수준참조 장
0현황 분석: 기존 데이터·API와 명세의 차이 파악-제3장
11단계 JSON-LD 데이터 형식과 유효성 검증기본제4장
22단계 REST·WebSocket API, 인증, 속도 제한표준제5장
33단계 MQTT, TLS 1.3, mDNS, OTA고급(일부)제6장
44단계 스마트 홈·로봇군·클라우드 통합고급제7장
5적합성 시험과 인증 신청-이 장

각 단계에 걸리는 기간은 기존 제품의 구조와 팀 규모에 따라 크게 달라지므로 이 책에서는 제시하지 않는다.

8.2 개발 환경

WIA가 제공하는 출발점은 WIA-Official GitHub 조직의 공개 저장소(wia-standards-public)의 cleaning-robot 디렉터리다.

경로내용
spec/PHASE-1~4 명세 문서
api/typescript/TypeScript SDK 골격(WiaCleaningRobot 클래스, 1단계 타입 정의)
cli/요청/응답 계약을 보여 주는 POSIX 셸 클라이언트
simulator/브라우저 기반 시뮬레이터
git clone https://github.com/WIA-Official/wia-standards-public.git
cd wia-standards-public/cleaning-robot/api/typescript

이 밖에 JSON Schema 검증기, MQTT 브로커, TLS 1.3을 지원하는 HTTP 서버 등 일반적인 개발 도구가 필요하다. 명세는 특정 라이브러리를 요구하지 않는다.

8.3 데이터 모델 구현

1단계 형식을 코드로 옮길 때는 명세의 열거값과 단위를 타입 수준에서 강제하는 것이 좋다. 다음은 RobotState의 일부를 TypeScript로 표현한 예다.

type RobotMode = 'idle' | 'cleaning' | 'charging' | 'returning' | 'error';
type CleaningMode = 'auto' | 'spot' | 'edge' | 'zigzag' | 'spiral';

interface RobotState {
  '@context': 'https://wiastandards.com/rob-011/v1';
  '@type': 'RobotState';
  timestamp: string;              // ISO 8601, 시간대 포함
  battery: { percentage: number; voltage: number; current: number;
             temperature: number; health: number; cycleCount: number };
  pose: { x: number; y: number; theta: number; floor: number; confidence: number };
  mode: RobotMode;
  cleaningMode: CleaningMode;
  suctionPower: number;           // 0-100
  [extension: `x_${string}`]: unknown;   // 제조사 확장 필드
}

function toWiaState(internal: InternalState): RobotState {
  return {
    '@context': 'https://wiastandards.com/rob-011/v1',
    '@type': 'RobotState',
    timestamp: new Date().toISOString(),
    battery: { ...internal.battery },
    pose: { x: internal.xMm / 1000, y: internal.yMm / 1000,   // mm → m (SI 단위)
            theta: internal.headingDeg * Math.PI / 180,        // 도 → 라디안
            floor: internal.floor, confidence: internal.locConfidence },
    mode: internal.mode,
    cleaningMode: internal.cleaningMode,
    suctionPower: internal.suction
  };
}

예시의 toWiaState처럼 기존 내부 형식을 표준 형식으로 바꾸는 변환 계층을 두면, 로봇 펌웨어 내부 구조를 크게 바꾸지 않고도 1단계를 준수할 수 있다. 제3장 3.4절의 "로봇 추상화 계층"이 바로 이 역할을 한다.

8.4 API 서버 구현

다음은 Node.js의 Express 프레임워크로 2단계의 청소 시작 엔드포인트를 구현한 예다. 경로, 오류 형식, 속도 제한은 모두 제5장의 명세를 따른다.

import express from 'express';
import rateLimit from 'express-rate-limit';

const app = express();
const api = express.Router();

api.use(rateLimit({ windowMs: 60_000, limit: 100 }));   // IP당 분당 100회, 초과 시 429
api.use(requireBearerJwt);                               // Authorization: Bearer {token}

function wiaError(res: express.Response, status: number, code: string, message: string) {
  return res.status(status).json({
    error: { code, message, details: {}, timestamp: new Date().toISOString() }
  });
}

api.post('/robot/clean', express.json(), async (req, res) => {
  if (robot.mode === 'cleaning') return wiaError(res, 409, 'ROBOT_BUSY', 'Robot is currently cleaning');
  if (robot.battery.percentage < 15) return wiaError(res, 409, 'LOW_BATTERY', 'Battery too low for operation');

  const { mode = 'auto', rooms, powerLevel } = req.body;
  const session = await robot.startCleaning({ mode, rooms, powerLevel });
  res.json({ sessionId: session.id, status: 'started', estimatedDuration: session.estimate });
});

app.use('/api/v1', api);

예시에서 HTTP 상태 코드(409)와 배터리 기준값(15%)은 구현자가 정하는 값으로, 명세가 규정한 것이 아니다. 명세가 규정하는 것은 오류 코드 이름과 오류 응답 형식, 그리고 속도 제한 초과 시의 HTTP 429다.

8.5 WebSocket 서버 구현

import { WebSocketServer, WebSocket } from 'ws';

const wss = new WebSocketServer({ server: httpsServer, path: '/ws' });
const subscriptions = new Map<WebSocket, Set<string>>();

wss.on('connection', (ws) => {
  subscriptions.set(ws, new Set());
  ws.on('message', (raw) => {
    const msg = JSON.parse(raw.toString());
    if (msg.type === 'subscribe')   subscriptions.get(ws)!.add(msg.channel);
    if (msg.type === 'unsubscribe') subscriptions.get(ws)!.delete(msg.channel);
  });
  ws.on('close', () => subscriptions.delete(ws));
});

function publish(channel: 'status' | 'sensors' | 'map' | 'logs', data: object): void {
  const frame = JSON.stringify({ type: 'event', channel, timestamp: new Date().toISOString(), data });
  for (const [ws, channels] of subscriptions) {
    if (channels.has(channel)) ws.send(frame);
  }
}

명세의 WebSocket 속도 제한(초당 10개 메시지)은 클라이언트가 보내는 메시지에 적용해야 하며, 로봇이 보내는 이벤트도 구독 요청의 interval을 존중해 과도하게 보내지 않도록 한다.

8.6 통신 계층과 보안 구현

8.7 테스트 전략

단위 테스트

변환 계층이 명세의 유효성 규칙(ISO 8601 시각, SI 단위, UUID v4, 열거값 일치, 필수 필드 비-null)을 지키는지 검사한다.

test('pose는 미터와 라디안으로 변환된다', () => {
  const s = toWiaState(sampleInternal({ xMm: 2500, headingDeg: 90 }));
  expect(s.pose.x).toBe(2.5);
  expect(s.pose.theta).toBeCloseTo(1.5708, 4);
  expect(s.timestamp).toMatch(/Z$|[+-]\d\d:\d\d$/);   // 시간대 포함
});

테스트 벡터

명세와 함께 공개되는 테스트 벡터는 요청·응답 쌍의 표준 집합이다. Tier 2 이상을 주장하려면 모든 테스트 벡터를 요청 직렬화와 응답 역직렬화 양방향으로 통과하고, 어떤 벡터를 시험했는지 밝힌 서명된 보고서를 공개해야 한다. 테스트 벡터는 명세 문서와 별도로 버전이 관리된다.

통합 테스트

실제 로봇 또는 시뮬레이터를 대상으로 인증 → 청소 시작 → WebSocket 상태 수신 → 정지 → 이력 조회의 전체 흐름을 시험하고, 속도 제한 초과 시 HTTP 429가 반환되는지, TLS 1.2 연결이 거부되는지도 확인한다.

8.8 인증 절차

4단계 명세가 정한 인증 절차는 다섯 단계다(제3장 3.8절).

  1. 신청서 제출: 대상 제품과 구현 범위를 밝혀 신청한다.
  2. 자동화 테스트(2~3일): API 엔드포인트 적합성, 데이터 형식 유효성, 성능 벤치마크 등을 자동으로 검증한다.
  3. 수동 검토(1주): 보안 감사를 포함해 자동화 테스트로 확인하기 어려운 항목을 검토한다.
  4. 통합 테스트(1주): 다른 시스템과의 상호운용성을 시험한다.
  5. 인증 부여: 모든 과정을 통과하면 인증이 부여된다.

인증 후에는 매년 보안 감사를 받아야 한다(3단계 명세 10.2절). 또한 적합성 등급(Tier)에 따라 감사 주기가 정해져 있다. Tier 1은 연 1회 자체 검토, Tier 2는 24개월마다, Tier 3은 12개월마다 감사를 받는다. 등급은 OpenAPI의 info.x-wia-tier 확장 필드와 공개 인증 페이지에 밝히고, 등급이 내려가면 30일 이내에 WIA 레지스트리에 보고한다.

비용과 유효 기간: WIA는 이 책을 쓰는 시점에 인증 수수료, 시험 항목 수, 인증 유효 기간, 갱신 비용을 명세에 공개하지 않았다. 이러한 조건은 인증을 신청할 때 WIA에 직접 확인해야 한다.

8.9 자체 점검 체크리스트

1단계: 데이터 형식

2단계: API

3단계: 통신 프로토콜

4단계: 통합

8.10 운영과 유지보수

8.11 리소스

명세 부속서 D는 스키마 버전 관리 정책, 개인정보 보호형 집계, 다국어 오류 메시지 목록, 장기 보존, 지속가능성 공시를 향후 검토 과제로 든다. 이 과제들에는 확정된 일정이 없으며, 공개 논의를 거쳐 규범으로 승격될 수 있다.

마무리

WIA-ROB-011은 청소 로봇이 제조사와 플랫폼의 경계를 넘어 함께 일하도록 하는 공통 언어다. 데이터 형식에서 시작해 API, 통신 프로토콜, 시스템 통합으로 한 단계씩 나아가면, 기존 제품도 무리 없이 표준을 받아들일 수 있다. 이것이 弘益人間, 곧 청소 자동화의 혜택을 더 많은 사람에게 넓히는 길이다.

핵심 요약

최종 복습 문제

  1. 네 단계의 구현 순서와 각 단계가 대응하는 준수 수준을 설명하라.
  2. 변환 계층(로봇 추상화 계층)은 기존 제품의 표준 준수를 어떻게 돕는가?
  3. 2단계 API 서버에서 명세가 규정하는 것과 구현자가 정하는 것을 구분하라.
  4. Tier 2 이상을 주장하려면 테스트 벡터에 대해 무엇을 해야 하는가?
  5. 명세의 5단계 인증 절차를 설명하라.
  6. 적합성 등급별 감사 주기를 설명하라.
  7. 주 버전이 바뀔 때 WIA 참조 구현의 병행 지원 기간은 얼마인가?

📐 시뮬레이터 패널 2