본문으로 건너뛰기

Robotics OTA API

로봇 장비의 원격 펌웨어/소프트웨어 업데이트(OTA, Over-The-Air)를 관리하는 REST API 엔드포인트입니다.

개요

Robotics OTA API는 제조 현장의 로봇 장비에 대한 안전한 원격 업데이트를 제공합니다. A/B 파티션 기반 롤백 지원, 링 배포(Canary, Gradual Rollout), 업데이트 상태 모니터링 기능을 포함합니다.

Base URL: /api/v1/ota

네임스페이스: Caffeine.Robotics.OTA.Controllers 어셈블리: Caffeine.Robotics.OTA.dll .NET 버전: .NET 10.0


인증

현재 OTA API는 공개 엔드포인트입니다. 프로덕션 환경에서는 JWT Bearer 토큰 인증을 권장합니다.

Authorization: Bearer <token>

엔드포인트 요약

메서드경로설명
GET/api/v1/ota/status현재 업데이트 상태 조회
POST/api/v1/ota/update/{deviceId}업데이트 트리거 (비동기)

상세 엔드포인트

GET /api/v1/ota/status

현재 OTA 업데이트 진행 상태를 조회합니다.

요청:

GET /api/v1/ota/status

응답 (200 OK - Idle 상태):

{
"state": "Idle"
}

응답 (200 OK - Downloading 상태):

{
"state": "Downloading"
}

UpdateState 값:

설명
Idle유휴 상태 (업데이트 없음)
Checking업데이트 확인 중
Downloading패키지 다운로드 중
Downloaded다운로드 완료
Installing설치 중
Installed설치 완료
Rebooting재부팅 대기 중
Verifying설치 후 검증 중
Complete업데이트 완료
Failed업데이트 실패
RolledBack롤백됨

POST /api/v1/ota/update/{deviceId}

특정 장비에 대한 OTA 업데이트를 트리거합니다. 업데이트는 비동기로 실행되며, 클라이언트는 /status 엔드포인트를 폴링하여 진행 상태를 확인해야 합니다.

요청:

POST /api/v1/ota/update/robot-arm-001
Content-Type: application/json

{
"packageId": "firmware-v2.5.0",
"version": "2.5.0",
"checksum": "sha256:a1b2c3d4e5f6...",
"sizeBytes": 52428800
}

경로 파라미터:

파라미터타입필수설명
deviceIdstring대상 장비 ID

요청 필드:

필드타입필수설명
packageIdstring업데이트 패키지 고유 식별자
versionstring업데이트 버전 (Semantic Versioning)
checksumstring패키지 체크섬 (무결성 검증용)
sizeByteslong패키지 크기 (바이트)

응답 (202 Accepted - 업데이트 시작):

{
"status": "Update initiated"
}

응답 헤더:

HTTP/1.1 202 Accepted
Content-Type: application/json

응답 (409 Conflict - 이미 업데이트 진행 중):

{
"type": "https://tools.ietf.org/html/rfc9110#section-15.5.10",
"title": "Conflict",
"status": 409,
"detail": "Update already in progress"
}

업데이트 워크플로우

OTA 업데이트는 다음 단계로 진행됩니다:

상태 전이 설명

  1. Checking: 업데이트 가능 여부 확인 (배터리, 디스크 공간, 네트워크)
  2. Downloading: 패키지 다운로드 중 (체크섬 검증 포함)
  3. Downloaded: 다운로드 완료, 설치 대기
  4. Installing: A/B 파티션에 설치 중
  5. Installed: 설치 완료, 재부팅 대기
  6. Rebooting: 재부팅 진행 중 (클라이언트는 연결 끊김 예상)
  7. Verifying: 재부팅 후 Health Check 실행
  8. Complete: 업데이트 성공적으로 완료
  9. Failed: 업데이트 실패 (재시도 가능)
  10. RolledBack: 검증 실패로 이전 버전으로 자동 롤백

DTO 정의

UpdateInfo

public record UpdateInfo(
string PackageId,
string Version,
string Checksum,
long SizeBytes
);

UpdateState (열거형)

public enum UpdateState
{
Idle,
Checking,
Downloading,
Downloaded,
Installing,
Installed,
Rebooting,
Verifying,
Complete,
Failed,
RolledBack
}

에러 코드

HTTP 상태설명대응 방법
200성공-
202업데이트 시작됨 (비동기 처리)/status를 폴링하여 진행 상태 확인
400잘못된 요청 (필수 필드 누락, 잘못된 체크섬 형식)요청 본문 확인
401인증 실패 (JWT 토큰 없음/만료)토큰 갱신
404장비 없음장비 ID 확인
409이미 업데이트 진행 중현재 업데이트 완료 후 재시도
500서버 내부 오류로그 확인

사용 예제

C# (HttpClient)

using System.Net.Http.Json;
using Caffeine.Robotics.OTA.Abstractions;

var client = new HttpClient
{
BaseAddress = new Uri("http://localhost:5200")
};

// 현재 상태 조회
var status = await client.GetFromJsonAsync<UpdateState>("/api/v1/ota/status");
Console.WriteLine($"Current State: {status}");

// 업데이트 트리거
var updateInfo = new UpdateInfo(
PackageId: "firmware-v2.5.0",
Version: "2.5.0",
Checksum: "sha256:a1b2c3d4e5f6...",
SizeBytes: 52428800
);

var response = await client.PostAsJsonAsync("/api/v1/ota/update/robot-arm-001", updateInfo);

if (response.StatusCode == System.Net.HttpStatusCode.Accepted)
{
Console.WriteLine("Update initiated. Polling status...");

// 상태 폴링 (5초 간격)
while (true)
{
await Task.Delay(5000);
var currentState = await client.GetFromJsonAsync<UpdateState>("/api/v1/ota/status");
Console.WriteLine($"State: {currentState}");

if (currentState == UpdateState.Complete)
{
Console.WriteLine("Update completed successfully!");
break;
}
else if (currentState == UpdateState.Failed || currentState == UpdateState.RolledBack)
{
Console.WriteLine($"Update failed: {currentState}");
break;
}
}
}
else if (response.StatusCode == System.Net.HttpStatusCode.Conflict)
{
Console.WriteLine("Update already in progress.");
}

curl

# 현재 상태 조회
curl http://localhost:5200/api/v1/ota/status

# 업데이트 트리거
curl -X POST http://localhost:5200/api/v1/ota/update/robot-arm-001 \
-H "Content-Type: application/json" \
-d '{
"packageId": "firmware-v2.5.0",
"version": "2.5.0",
"checksum": "sha256:a1b2c3d4e5f6...",
"sizeBytes": 52428800
}'

# 상태 폴링 (watch 사용)
watch -n 5 'curl -s http://localhost:5200/api/v1/ota/status | jq'

PowerShell

$baseUrl = "http://localhost:5200"

# 현재 상태 조회
$status = Invoke-RestMethod -Uri "$baseUrl/api/v1/ota/status"
Write-Host "Current State: $status"

# 업데이트 트리거
$updateInfo = @{
packageId = "firmware-v2.5.0"
version = "2.5.0"
checksum = "sha256:a1b2c3d4e5f6..."
sizeBytes = 52428800
} | ConvertTo-Json

$response = Invoke-WebRequest -Uri "$baseUrl/api/v1/ota/update/robot-arm-001" `
-Method Post -Body $updateInfo -ContentType "application/json"

if ($response.StatusCode -eq 202) {
Write-Host "Update initiated. Polling status..."

# 상태 폴링 (5초 간격)
while ($true) {
Start-Sleep -Seconds 5
$currentState = Invoke-RestMethod -Uri "$baseUrl/api/v1/ota/status"
Write-Host "State: $currentState"

if ($currentState -eq "Complete") {
Write-Host "Update completed successfully!"
break
}
elseif ($currentState -in @("Failed", "RolledBack")) {
Write-Host "Update failed: $currentState"
break
}
}
}

A/B 파티션 롤백 메커니즘

OTA 업데이트는 A/B 파티션 구조를 사용하여 안전성을 보장합니다:

파티션 구조

┌─────────────┐
│ Partition A │ ← 현재 실행 중인 버전
├─────────────┤
│ Partition B │ ← 업데이트 설치 대상
└─────────────┘

업데이트 프로세스

  1. 다운로드: 새 버전을 비활성 파티션(B)에 다운로드
  2. 설치: 파티션 B에 설치 및 검증
  3. 부트 플래그 전환: 다음 재부팅 시 파티션 B에서 부팅하도록 설정
  4. 재부팅: 장비 재시작
  5. Health Check: 재부팅 후 시스템 정상 동작 확인
  6. 롤백 (선택적): Health Check 실패 시 파티션 A로 자동 롤백

롤백 조건

다음 상황에서 자동 롤백이 발생합니다:

  • Health Check 실패 (예: 네트워크 연결 불가, 중요 서비스 미실행)
  • 재부팅 후 30초 이내 정상 응답 없음
  • 수동 롤백 트리거 (긴급 상황)

링 배포 (Ring Deployment)

대규모 함대(fleet)에 대한 단계적 업데이트를 지원합니다:

배포 링 단계

  1. Canary Ring (금사조 배포): 1~5대의 테스트 장비에 먼저 배포
  2. Beta Ring: 10~20% 장비에 배포
  3. Production Ring: 전체 장비에 배포

사용 예시

// Canary Ring 배포 (단계 1)
var canaryDevices = new[] { "robot-arm-001", "agv-002" };
foreach (var deviceId in canaryDevices)
{
await client.PostAsJsonAsync($"/api/v1/ota/update/{deviceId}", updateInfo);
}

// 24시간 대기 후 성공 확인
await Task.Delay(TimeSpan.FromHours(24));

// Beta Ring 배포 (단계 2)
var betaDevices = await GetBetaRingDevices(); // 10~20% 선택
foreach (var deviceId in betaDevices)
{
await client.PostAsJsonAsync($"/api/v1/ota/update/{deviceId}", updateInfo);
}

// 일주일 대기 후 전체 배포 (단계 3)
await Task.Delay(TimeSpan.FromDays(7));
var allDevices = await GetAllProductionDevices();
foreach (var deviceId in allDevices)
{
await client.PostAsJsonAsync($"/api/v1/ota/update/{deviceId}", updateInfo);
}

모니터링 및 로깅

업데이트 진행 중 다음 이벤트가 로깅됩니다:

  • 업데이트 시작 시각 및 대상 장비
  • 다운로드 진행률 (선택적)
  • 설치 성공/실패
  • Health Check 결과
  • 롤백 발생 여부 및 사유

로그 확인:

# Serilog 로그 파일
tail -f logs/robotics-ota-.log

# OpenTelemetry (Prometheus exporter)
curl http://localhost:9090/metrics | grep ota_update

Swagger UI

개발 환경에서 Swagger UI를 통해 API를 테스트할 수 있습니다:

http://localhost:5200/swagger

관련 문서


보안 고려사항

패키지 무결성

  • 모든 패키지는 SHA-256 체크섬으로 검증됩니다.
  • 체크섬 불일치 시 설치가 중단되고 Failed 상태로 전환됩니다.

전송 암호화

  • 프로덕션 환경에서는 반드시 HTTPS 사용을 권장합니다.
  • 패키지 다운로드 시 TLS 1.2 이상 사용 필수

인증 및 권한

  • OTA 업데이트 트리거는 관리자 권한 필요
  • JWT 토큰에 ota:update 권한 클레임 필수 (권장)

네임스페이스: Caffeine.Robotics.OTA.Controllers DTO 네임스페이스: Caffeine.Robotics.OTA.Abstractions 어셈블리: Caffeine.Robotics.OTA.dll .NET 플랫폼: .NET 10.0