2단계 명세(PHASE-2-API, v1.0.0)는 청소 로봇을 제어하고 모니터링하기 위한 RESTful HTTP API와 WebSocket 인터페이스를 정의한다. 명세는 모든 엔드포인트가 인증과 요청 속도 제한(rate limiting)을 구현해야 한다(MUST)고 규정한다. API가 주고받는 데이터는 제4장의 1단계 형식(RobotState, OccupancyGrid, CleaningSession 등)을 그대로 사용한다.
API는 로봇 자체(또는 로봇을 대리하는 게이트웨이)가 제공하며, 기본 URL은 다음과 같다. 기본 포트는 8080이다.
http://{robot_ip}:{port}/api/v1
API 버전은 URL 경로(/api/v1/)에 표시하며, 호환성을 깨는 변경이 생기면 새 버전 번호를 부여해야 한다. 명세 예시의 기본 URL은 http로 적혀 있지만, 3단계는 모든 네트워크 통신에 TLS 1.3을 요구하므로 실제 배치에서는 HTTPS를 사용해야 한다(제6장 참조).
클라이언트는 POST /auth/token에 사용자 이름과 비밀번호를 보내 JWT 접근 토큰과 갱신 토큰을 받는다. 접근 토큰의 유효 시간은 expires_in(초)으로 알려 주며, 명세 예시는 3600초(1시간)다.
POST /auth/token
Content-Type: application/json
{
"username": "string",
"password": "string"
}
Response:
{
"access_token": "JWT token",
"refresh_token": "string",
"expires_in": 3600
}
이후 모든 요청은 Authorization 헤더에 Bearer 토큰을 실어 보낸다.
Authorization: Bearer {access_token}
3단계 명세는 인증 방식으로 JWT(권장), OAuth 2.0, 단순 통합용 API 키를 허용한다. 서드파티 서비스가 사용자를 대신해 로봇에 접근할 때는 OAuth 2.0(RFC 6749)이 적합하다.
명세 4절이 정의하는 핵심 엔드포인트는 다음과 같다. 모든 경로는 기본 URL(/api/v1) 아래에 붙는다.
| 메서드 | 경로 | 기능 |
|---|---|---|
| GET | /robot/status | 로봇 상태 조회 |
| POST | /robot/clean | 청소 시작 |
| POST | /robot/stop | 청소 정지 |
| POST | /robot/dock | 도크 복귀 |
| GET | /robot/map?floor={floor_number} | 지도 조회 |
| PUT | /robot/map/rooms/{room_id} | 방 정보 수정 |
| GET | /robot/history?limit=10&offset=0 | 청소 이력 조회 |
| POST | /robot/schedule | 청소 일정 등록 |
GET /robot/status
Response:
{
"robotId": "string",
"state": "RobotState object",
"uptime": "integer (seconds)",
"lastUpdate": "ISO8601 datetime"
}
응답의 state는 제4장의 RobotState 문서다.
POST /robot/clean
Content-Type: application/json
{
"mode": "auto|spot|edge|custom",
"rooms": ["room_id1", "room_id2"],
"powerLevel": 0-100,
"waterLevel": 0-100
}
Response:
{
"sessionId": "UUID",
"status": "started",
"estimatedDuration": "integer (seconds)"
}
응답의 sessionId는 이 청소 작업에 해당하는 CleaningSession의 식별자다. 특정 방만 청소하려면 rooms에 지도의 방 ID를 넣는다.
POST /robot/stop
Response: { "status": "stopped", "sessionId": "UUID", "areaCleaned": "float (m²)" }
POST /robot/dock
Response: { "status": "returning", "distance": "float (meters)", "estimatedTime": "integer (seconds)" }
GET /robot/map?floor={floor_number}
Response: { "map": "OccupancyGrid object", "lastUpdated": "ISO8601 datetime" }
PUT /robot/map/rooms/{room_id}
Content-Type: application/json
{
"name": "Living Room",
"surfaceType": "hardwood",
"cleaningPriority": 1-10
}
Response: { "status": "updated", "room": "Room object" }
GET /robot/history?limit=10&offset=0
Response: { "sessions": ["CleaningSession", "array"], "total": "integer", "hasMore": "boolean" }
POST /robot/schedule
Content-Type: application/json
{
"enabled": true,
"schedule": [
{ "day": "monday|tuesday|...", "time": "HH:MM", "mode": "auto", "rooms": ["array (optional)"] }
]
}
Response: { "scheduleId": "UUID", "status": "created" }
실시간 상태 변화는 WebSocket으로 받는다. 연결 주소는 ws://{robot_ip}:{port}/ws이며, 실제 배치에서는 TLS를 적용한 WSS를 사용한다. 모든 메시지는 종류(type)와 채널(channel)을 가진다.
{
"type": "subscribe|unsubscribe|command|event",
"channel": "status|sensors|map|logs",
"data": {}
}
클라이언트가 상태 채널을 1000ms 간격으로 구독하면, 로봇은 event 메시지로 변화를 알린다.
// 구독 요청
{ "type": "subscribe", "channel": "status", "interval": 1000 }
// 실시간 이벤트
{
"type": "event",
"channel": "status",
"timestamp": "ISO8601",
"data": { "battery": 75, "position": {"x": 2.5, "y": 3.1}, "mode": "cleaning" }
}
오류 응답은 다음 형식을 따른다.
{
"error": {
"code": "ERROR_CODE",
"message": "Human readable message",
"details": {},
"timestamp": "ISO8601 datetime"
}
}
| 오류 코드 | 의미 |
|---|---|
ROBOT_BUSY | 로봇이 이미 청소 중이다 |
LOW_BATTERY | 배터리가 부족해 작업할 수 없다 |
INVALID_COMMAND | 명령 매개변수가 올바르지 않다 |
NOT_CONNECTED | 로봇이 네트워크에 연결되어 있지 않다 |
SENSOR_ERROR | 센서 이상이 감지되었다 |
NAVIGATION_ERROR | 주행할 수 없다 |
DOCK_NOT_FOUND | 충전 도크를 찾을 수 없다 |
명세 부속서 B는 HTTP API 오류 표현의 국제 표준으로 RFC 9457(Problem Details)을 참조 표준으로 열거한다. 위 오류 형식과 RFC 9457 형식을 어떻게 대응시킬지는 구현체가 문서화해 두는 것이 좋다.
목록을 돌려주는 모든 엔드포인트는 표준 페이지 나누기 매개변수를 지원한다.
GET /robot/history?limit=20&offset=40&sort=startTime&order=desc - limit: 페이지당 항목 수 (기본 10, 최대 100) - offset: 건너뛸 항목 수 - sort: 정렬 기준 필드 - order: asc 또는 desc
명세는 필터 예시로 GET /robot/history?mode=auto&minDuration=300, GET /robot/map/rooms?surfaceType=carpet, GET /robot/events?level=error&category=navigation을 든다.
POST /robot/batch는 여러 요청을 한 번에 보내고, 요청 순서대로 결과 배열을 돌려받는다.
POST /robot/batch
{
"operations": [
{ "method": "POST", "path": "/robot/clean", "body": {"mode": "spot"} },
{ "method": "PUT", "path": "/robot/config", "body": {"language": "ko"} }
]
}
Response:
{ "results": [ {"status": 200, "data": {}}, {"status": 200, "data": {}} ] }
| 엔드포인트 | 기능 |
|---|---|
GET /robot/metrics | CPU·메모리 사용률, 온도, 네트워크 송수신량, 가동 시간 |
POST /robot/control/joystick | 원격 수동 조작(선속도 m/s, 각속도 rad/s) |
GET /robot/camera/stream | MJPEG 카메라 스트림 |
GET /robot/map/export?format=png|svg|json | 지도 내보내기 |
카메라 스트림과 원격 조작은 사생활과 안전에 직접 영향을 주므로, 인증된 사용자에게만 허용하고 사용 중임을 사용자가 알 수 있게 하는 것이 바람직하다.
WIA 공개 저장소(cleaning-robot/api/typescript)의 TypeScript SDK 골격은 위 엔드포인트를 감싼 WiaCleaningRobot 클래스를 제공한다. 이 SDK는 공개 패키지 저장소에 배포되어 있지 않으므로 저장소에서 직접 받아 사용한다(제3장 3.9절 참조).
import { WiaCleaningRobot } from 'wia-rob-011';
const robot = new WiaCleaningRobot({
host: '192.168.1.100',
token: 'your_token_here'
});
await robot.connect(); // GET /health
const status = await robot.getStatus(); // GET /robot/status
await robot.startCleaning({ mode: 'auto' }); // POST /robot/clean
http://{robot_ip}:{port}/api/v1, 기본 포트는 8080이며 실제 배치에는 HTTPS를 쓴다POST /auth/token으로 JWT를 받아 Bearer 헤더로 보낸다/robot/status, /robot/clean, /robot/stop, /robot/dock, /robot/map, /robot/history, /robot/schedule이다/ws에서 status·sensors·map·logs 채널을 구독한다error.code와 일곱 가지 표준 오류 코드로 표현한다POST /robot/clean 본문을 작성하라.