시뮬레이션 환경 구성 가이드
실제 제조 장비 없이도 Caffeine 플랫폼의 모든 기능을 테스트할 수 있습니다. 이 가이드를 따라하면 가상 장비에서 실시간 센서 데이터를 생성하고, Admin 대시보드에서 모니터링할 수 있습니다.
📋 사전 요구사항
시작하기 전에 아래 항목을 준비하세요:
| 항목 | 필수 | 확인 방법 |
|---|---|---|
| .NET 10 SDK | O | dotnet --version → 10.x.x |
| Docker Desktop | △ (Docker 방식만) | docker --version |
| MQTT 브로커 | O | Docker 또는 로컬 설치 |
Docker만 있으면 MQTT 브로커를 한 줄로 실행할 수 있습니다:
docker run -d --name mqtt -p 1883:1883 eclipse-mosquitto:2
🏗️ 시뮬레이션 아키텍처
Caffeine 시뮬레이션은 3개의 계층으로 구성됩니다:
| 컴포넌트 | 역할 | 언제 사용? |
|---|---|---|
| Caffeine.Simulator | MQTT로 대량 센서 데이터 발행 | 부하 테스트, 대규모 시뮬레이션 |
| VirtualMemoryDriver | Bridge.Host 내장 가상 드라이버 | 개발 중 빠른 테스트 |
| PlcSimulator | MC(SLMP) + XGT TCP 가상 PLC | PLC 드라이버 프로토콜 검증 |
| SimulatorApp | PlcSimulator + 웹 GUI (Blazor) | 멀티 PLC 관리, 메모리 편집, 데모 |
| MesHostSimulator | SECS/GEM MES 호스트 시뮬레이션 | 반도체/디스플레이 장비 연동 테스트 |
cafe 명령어를 사용하려면 CLI를 먼저 설치하세요:
dotnet tool install -g NEXCODE.Caffeine.Cli
cafe --version
이미 설치된 경우 업데이트: dotnet tool update -g NEXCODE.Caffeine.Cli
🚀 방법 1: Admin UI에서 시뮬레이션 (가장 쉬움)
가장 간단한 방법입니다. Admin 대시보드에서 버튼 클릭만으로 시뮬레이션을 시작할 수 있습니다.
Step 1: Caffeine 서비스 시작
cafe setup 위자드에서 app 프로파일을 선택하면 인프라(MQTT, Redis)와 Engine, Admin이 한 번에 시작됩니다:
# 배포 파일 추출 (최초 1회)
cafe setup extract
# 위자드 실행
cafe setup
# 프로파일 선택: app
cafe setup status로 모든 서비스가 정상 실행 중인지 확인하세요.
Step 2: 시뮬레이션 페이지 접속
브라우저에서 http://localhost:5233/simulation 에 접속합니다.

Step 5: 파라미터 설정
| 파라미터 | 초보자 권장값 | 설명 |
|---|---|---|
| 디바이스 수 | 10 | 프로세스당 가상 장비 개수 |
| 프로세스 수 | 1 | 병렬 시뮬레이터 프로세스 |
| 목표 RPS | 100 | 초당 전송할 이벤트 수 |
| 시나리오 | Normal | 데이터 패턴 (아래 참조) |
| 배치 크기 | 10 | 한 번에 전송할 메시지 수 |
Step 6: 시작 & 모니터링
시작 버튼을 클릭하면:
- 왼쪽 패널에 실행 중인 프로세스 수, 총 RPS, 경과 시간이 표시됩니다
- 홈 대시보드 (
/)에서 Ingestion Traffic 그래프가 실시간 업데이트됩니다 - 중지 버튼으로 언제든 시뮬레이션을 멈출 수 있습니다

Admin이 Engine과 분리 실행되는 경우(임베드 모드) 대시보드에 "Disconnected"가 표시될 수 있습니다. 이 경우 Engine 컨테이너가 실행 중인지 cafe setup status로 확인하고, Admin의 환경 변수 ApiSettings__EngineUrl을 Engine 주소로 설정하세요.
총 디바이스 = 디바이스 수 × 프로세스 수 총 RPS = 목표 RPS × 프로세스 수
예: 디바이스 50 × 프로세스 4 = 200개 장비, 1000 RPS × 4 = 4,000 이벤트/초
🔧 방법 2: CLI 직접 실행
Admin 없이 시뮬레이터만 독립 실행하는 방법입니다. 자동화 스크립트나 CI/CD에 유용합니다.
Step 1: 시뮬레이터 실행
Caffeine CLI의 demo simulator 명령으로 Docker 기반 시뮬레이터를 실행합니다:
cafe demo simulator \
--host localhost \
--device-count 10 \
--scenario Normal
Step 2: 환경 변수로 세밀한 제어
Docker 시뮬레이터 컨테이너에 환경 변수를 전달하여 세밀하게 제어할 수 있습니다:
# Docker로 직접 실행 (환경 변수 지정)
docker run --rm \
-e MQTT_HOST=localhost \
-e MQTT_PORT=1883 \
-e DEVICE_ID=TestDevice \
-e DEVICE_COUNT=10 \
-e SCENARIO=Normal \
-e TARGET_RPS=100 \
-e BATCH_SIZE=10 \
--network host \
nexcode/caffeine-simulator:latest
환경 변수 레퍼런스
| 변수 | 기본값 | 설명 |
|---|---|---|
MQTT_HOST | localhost | MQTT 브로커 주소 |
MQTT_PORT | 1883 | MQTT 포트 |
DEVICE_ID | Simulated-Eqp | 장치 ID 프리픽스 (뒤에 번호 자동 부여) |
DEVICE_COUNT | 1 | 시뮬레이션할 장치 수 |
SCENARIO | Normal | 시나리오 타입 |
TARGET_RPS | 1 | 초당 목표 이벤트 수 |
BATCH_SIZE | 1 | 배치당 메시지 수 |
실행 확인
콘솔에 아래와 같은 통계가 5초마다 출력됩니다:
##################################################
🚀 Starting Engine [Devices: 10, Scenario: Normal, Total RPS: 100, Batch: 10]
✅ All 10 devices registered and online.
[Stats] RPS: 100 (Target: 100), Total Batches: 50
[Stats] RPS: 100 (Target: 100), Total Batches: 100
[Stats] RPS: 100 (Target: 100), Total Batches: 150
- RPS: 실제 초당 전송 수 (Target에 가까울수록 정상)
- Total Batches: 누적 배치 전송 수
🐳 방법 3: Docker Compose (전체 스택)
모든 인프라를 한 번에 실행하는 방법입니다.
Step 1: 환경 파일 준비
cd deploy
cp .env.example .env # 필요 시 편집
Step 2: 프로파일 선택 후 실행
# 최소 인프라 (Redis + MQTT)
docker compose --profile minimal up -d
# 표준 (+ InfluxDB + Kafka)
docker compose --profile standard up -d
# 전체 (+ TypeDB + Grafana + Prometheus)
docker compose --profile full up -d
# 전체 + Caffeine 앱
docker compose --profile app up -d
Step 3: 시뮬레이터 로그 확인
docker logs -f caffeine-simulator-01
프로파일 구성
| 프로파일 | 서비스 | 용도 |
|---|---|---|
minimal | Redis, MQTT | 개발 중 빠른 테스트 |
standard | + InfluxDB, Kafka | 시계열 데이터 저장 테스트 |
full | + TypeDB, Grafana, Prometheus | 전체 관측성 확인 |
app | + Engine, Admin, Simulator | 데모, 통합 테스트 |
🎭 시나리오 가이드
시뮬레이터는 4가지 데이터 패턴을 지원합니다:
| 시나리오 | 데이터 패턴 | 용도 |
|---|---|---|
| Normal | 정상 범위 내 랜덤 변동 | 기본 동작 확인, 대시보드 테스트 |
| Overheat | 온도가 점진적으로 상승 | 알람 트리거 테스트, 임계값 검증 |
| PressureDrop | 압력이 급격히 하락 | 이상 감지 AI 테스트 |
| RandomSpike | 간헐적 비정상 스파이크 | 노이즈 필터링, 알람 해제 테스트 |
- 처음 시작할 때: Normal로 기본 동작 확인
- 알람 기능 테스트: Overheat (온도 알람 트리거)
- AI 예측 테스트: PressureDrop (이상 패턴 학습)
- 운영 안정성 테스트: RandomSpike (간헐적 장애 대응)
시나리오별 데이터 범위
| 시나리오 | 온도 (°C) | 압력 (hPa) | 특성 |
|---|---|---|---|
| Normal | 20 ~ 30 | 1000 ~ 1020 | 균일 분포, 정상 범위 |
| Overheat | 80 ~ 120 | 1000 ~ 1020 | 온도만 위험 수준 |
| PressureDrop | 20 ~ 30 | 600 ~ 800 | 압력만 저압 이상 |
| RandomSpike | 20 | 1000 | 15% 확률 동시 스파이크 |
런타임 시나리오 전환 (MQTT 명령)
시뮬레이터를 재시작하지 않고 실행 중에 시나리오를 변경할 수 있습니다. Engine의 Demo API가 MQTT 명령 토픽으로 변경 요청을 전달합니다.
POST /api/v1/demo/scenario
Content-Type: application/json
Authorization: Bearer <token>
{ "scenario": "Overheat" }
시뮬레이터는 caffeine/demo/command MQTT 토픽을 구독하며, ChangeScenario 명령을 수신하면 즉시 데이터 생성 패턴을 전환합니다.
Admin의 Demo Stage 페이지(/demo-stage)에서 시나리오 버튼을 클릭하면 위 API를 자동 호출합니다. 자세한 내용은 Demo Stage 시연 가이드를 참고하세요.
📊 규모별 설정 예시
소규모 (개발 중 빠른 테스트)
디바이스: 10, 프로세스: 1, RPS: 100, 배치: 10
→ 총 10개 장비, 100 이벤트/초
중규모 (기능 검증)
디바이스: 100, 프로세스: 10, RPS: 1000, 배치: 50
→ 총 1,000개 장비, 10,000 이벤트/초
대규모 (스트레스 테스트)
디바이스: 500, 프로세스: 20, RPS: 5000, 배치: 100
→ 총 10,000개 장비, 100,000 이벤트/초
- 충분한 메모리(16GB+)와 CPU 코어(8+) 확보
- MQTT 브로커의
max_connections설정 확인 - InfluxDB의 디스크 공간 여유 확인
🔌 Bridge.Host 내장 시뮬레이션
Bridge.Host는 VirtualMemoryDriver를 기본 탑재하여, MQTT 없이도 장비 데이터를 생성합니다.
실행
Bridge.Host는 Docker 이미지 또는 cafe setup (app 프로파일)로 실행합니다:
# Docker로 직접 실행
docker run -d --name bridge-host \
-p 5100:5100 \
-v ./driver_settings.json:/app/driver_settings.json \
nexcode/caffeine-bridge-host:latest
# 또는 cafe setup으로 전체 스택 실행
cafe setup # 프로파일: app
설정 확인 (driver_settings.json)
{
"Drivers": [
{
"Id": "Edge-Machine-01",
"Type": "Simulation",
"Port": 0,
"Settings": {
"size": 4096,
"interval": 100
}
}
]
}
Type: "Simulation"— VirtualMemoryDriver 자동 로드interval: 100— 100ms마다 데이터 업데이트- 다중 드라이버 지원:
Drivers배열에 여러 드라이버를 정의할 수 있습니다
VirtualMemoryDriver 데이터 생성 패턴
Simulation 드라이버는 100ms 주기로 가상 메모리에 값을 생성합니다:
| 태그 | 메모리 주소 | 데이터 타입 | 패턴 | 범위 |
|---|---|---|---|---|
| AliveBit | 0 | Bool | 1초 주기 토글 (0/1) | 0 또는 1 |
| Temperature | 104 | Float | sin 파형 (6.3초 주기) | 30 ~ 70 |
| Pressure | 108 | Float | cos 파형 (Temperature와 90도 위상차) | 50.5 ~ 150.5 |
Simulation 드라이버 최초 실행 시, 위 3개 태그가 자동으로 등록됩니다. Edge UI의 태그 관리 탭에서 추가/수정/삭제할 수 있습니다.
Bridge.Host Edge UI (v2)
http://localhost:5100 에 접속하면 Edge 전용 웹 UI를 사용할 수 있습니다. 설비 벤더사 엔지니어가 현장에서 Engine 없이 Edge 단독으로 설비 설정과 검증을 완료할 수 있습니다.
기본 계정: admin / admin (최초 접속 시 비밀번호 설정)
| 탭 | 기능 |
|---|---|
| 모니터링 | 드라이버 상태, 실시간 태그 값 (1초 폴링), 오프라인 버퍼 게이지 |
| 설비 정보 | 설비명, 카테고리, 위치 설정 |
| 드라이버 | 드라이버 유형/IP/포트 설정 |
| 태그 관리 | 태그 CRUD + CSV 가져오기/내보내기 |
| AAS | AAS 서브모델 설정, 장비 템플릿 자동 입력, IRDI 검색, 설정 Export/Import |
| 감사 로그 | 작업 이력 (액션 필터 + 검색) |
다크 모드: 헤더의 ☀️/🌙 버튼으로 전환 (야간 작업 시 유용)
모니터링 탭
Engine에 바인딩하면 모니터링 탭에서 실시간 태그 값을 확인할 수 있습니다:
- 드라이버 상태 카드: 드라이버 유형, 상태(Running/Uninitialized), Engine 연결 여부, 전송 성공/실패 카운터
- 오프라인 버퍼 게이지: Engine 연결 해제 시 자동 버퍼링 건수와 용량 표시 (재연결 시 FIFO 전송)
- 실시간 태그 테이블: 태그별 현재값, 갱신 시간, LIVE/STALE 상태
AAS 편의 기능
설비 벤더사 엔지니어가 AAS(Asset Administration Shell) 모델을 빠르게 등록할 수 있도록 다음 편의 기능을 제공합니다:
- 장비 템플릿: Pump, Motor, Conveyor, CNC, Robot, PLC 중 선택하면 서브모델 + IRDI 매핑이 자동 입력됩니다
- IRDI 검색: IRDI 입력 필드 옆 🔍 버튼으로 50개 항목의 내장 카탈로그에서 검색
- IRDI 형식 검증:
0173-1#XX-XXXXX#NNN형식이 아니면 경고 표시 - 설정 Export/Import: 동일 모델의 여러 설비에 AAS 설정을 JSON 파일로 복제
데이터 흐름 (Engine 바인딩 후)
Engine이 Bridge를 바인딩하면 다음 순서로 데이터가 흐릅니다:
1. Engine → Bridge POST /api/bridge/bind (바인딩 요청)
2. Bridge → Engine: manifest 응답 (태그 목록 + DriverId)
3. Engine: TagManager에 태그 등록 + ScanPlan 생성
4. Engine → Bridge: gRPC ScanPlan 전송 (SmartIOScheduler 업데이트)
5. Bridge: 드라이버 읽기 시작 → gRPC StreamIo → Engine
6. Engine: IngestionDispatcher → TagManager 값 업데이트
7. Admin: gRPC MonitoringStream으로 실시간 태그 값 수신
🔌 방법 4: PLC 프로토콜 시뮬레이터
Caffeine.Tools.PlcSimulator는 실제 PLC 장비 없이 MC(SLMP) 프로토콜과 XGT(FEnet) 프로토콜을 TCP로 제공하는 가상 PLC입니다. Mitsubishi PLC 드라이버나 LS(LG) XGT 드라이버를 개발·테스트할 때 사용합니다.
언제 사용하나?
| 시뮬레이터 | 프로토콜 | 용도 |
|---|---|---|
| Caffeine.Simulator | MQTT | 대량 센서 데이터 부하 테스트 |
| VirtualMemoryDriver | gRPC (Bridge 내장) | 개발 중 빠른 테스트 |
| PlcSimulator | MC/SLMP + XGT TCP | PLC 드라이버 프로토콜 검증 |
실행
# 기본 실행 (MC: 5007, XGT: 2004)
dotnet run --project tools/Caffeine.Tools.PlcSimulator/
# 커스텀 포트
dotnet run --project tools/Caffeine.Tools.PlcSimulator/ -- --mc-port 5008 --xgt-port 2005
# 시뮬레이션 간격 변경 (기본 100ms)
dotnet run --project tools/Caffeine.Tools.PlcSimulator/ -- --interval 50
# 서버 전용 모드 (자동 값 생성 없이 읽기/쓰기만)
dotnet run --project tools/Caffeine.Tools.PlcSimulator/ -- --no-sim
CLI 인수
| 인수 | 타입 | 기본값 | 설명 |
|---|---|---|---|
--mc-port | int | 5007 | MC(SLMP) 프로토콜 TCP 포트 |
--xgt-port | int | 2004 | XGT FEnet 프로토콜 TCP 포트 |
--interval | int | 100 | 시뮬레이션 값 갱신 주기 (ms) |
--no-sim | bool | false | 시뮬레이션 엔진 비활성화 |
시뮬레이션 데이터
시뮬레이션 엔진이 활성화되면 아래 주소에 자동으로 값이 생성됩니다:
| 디바이스 주소 | 타입 | 패턴 | 설명 |
|---|---|---|---|
| D100-D101 | Int32 | 사인파 | 50000 +/- 20000 범위의 주기적 변동 |
| D102 | UInt16 | 카운터 | 0~65535 순환 증가 |
| D103 | UInt16 | 사인파 | 50 +/- 30 범위 (온도 시뮬레이션) |
| M0 | Bit | 토글 | 1초 주기 ON/OFF (Alive 신호) |
| Y0 | Bit | 조건부 | 카운터 짝수일 때 ON |
지원 디바이스 코드 (MC/SLMP)
| 디바이스 | 코드 | 타입 | 용도 |
|---|---|---|---|
| D | 0xA8 | 워드 | 데이터 레지스터 |
| W | 0xB4 | 워드 | 링크 레지스터 |
| R | 0xAF | 워드 | 파일 레지스터 |
| ZR | 0xB0 | 워드 | 확장 파일 레지스터 |
| M | 0x90 | 비트 | 내부 릴레이 |
| X | 0x9C | 비트 | 입력 디바이스 |
| Y | 0x9D | 비트 | 출력 디바이스 |
XGT 주소 형식
XGT 프로토콜은 %DW100, %MW50, %PW10 형식의 변수 주소를 사용합니다. 디바이스 타입(D, M, P 등) + 워드/비트 접미사(W, B) + 번호로 구성됩니다.
Caffeine 드라이버와 연동
PlcSimulator를 실행한 뒤 Bridge.Host의 driver_settings.json에서 PLC 드라이버를 설정하면 실제 장비와 동일하게 통신할 수 있습니다:
{
"Drivers": [
{
"Id": "Virtual-PLC-01",
"Type": "MitsubishiMc",
"IpAddress": "127.0.0.1",
"Port": 5007,
"Settings": {
"scanInterval": 100
}
}
]
}
PlcSimulator와 VirtualMemoryDriver를 동시에 사용할 수 있습니다. PlcSimulator는 PLC 프로토콜 수준의 검증에, VirtualMemoryDriver는 Bridge 내부 동작 검증에 각각 적합합니다.
🖥️ 방법 5: Simulator Hub GUI (올인원)
Caffeine.Tools.SimulatorApp은 PLC 시뮬레이터를 웹 UI로 관리하는 Blazor Server 앱입니다. CLI 없이 브라우저에서 가상 PLC를 추가·편집·모니터링할 수 있어, QA 팀이나 고객 데모에 적합합니다.
언제 사용하나?
| 시뮬레이터 | 인터페이스 | 용도 |
|---|---|---|
| PlcSimulator CLI | 터미널 | 자동화, CI/CD, 빠른 단일 PLC |
| SimulatorApp GUI | 웹 브라우저 | 멀티 PLC 관리, 메모리 편집, 데모 |
실행
dotnet run --project tools/Caffeine.Tools.SimulatorApp/
브라우저에서 http://localhost:5050 에 접속합니다.
주요 화면
대시보드
처음 실행하면 빈 대시보드가 표시됩니다. "PLC 추가" 버튼으로 가상 PLC를 생성합니다.

PLC 추가 다이얼로그에서 프로토콜(MC/XGT), 포트, 메모리 크기, 시뮬레이션 설정을 지정합니다.

PLC가 추가되면 카드로 표시됩니다. 녹색 점은 Running, D100/D101 값이 실시간 미리보기됩니다.

- 시작/정지: 카드의 재생/일시정지 버튼으로 개별 제어
- 포트 중복 검사: 같은 포트를 사용하는 PLC 추가 시 에러 메시지 표시
메모리 편집기
카드를 클릭하면 해당 PLC의 메모리를 직접 편집할 수 있습니다.

| 열 | 내용 |
|---|---|
| Address | 디바이스 코드 + 주소 번호 |
| Hex | 16진수 값 (인라인 편집 가능) |
| Decimal | 10진수 값 |
| Float | IEEE 754 32비트 부동소수 해석 |
| ASCII | ASCII 문자 변환 |
- 키보드 지원: Enter로 편집 시작/확정, Escape로 취소, Tab으로 셀 이동
- 시뮬레이션 토글: 우측 상단 체크박스로 자동 값 생성 ON/OFF 전환
- 디바이스 코드 탭: D, W, R, ZR(워드), M, X, Y(비트) 코드별 표시
실시간 모니터링
SVG 스파클라인 차트로 선택한 메모리 주소의 값 변화를 실시간 추적합니다.

- Watch 목록: PLC + 디바이스 + 주소를 선택하여 여러 값을 동시 모니터링
- 폴링 주기: 100ms / 200ms / 500ms / 1000ms 중 선택
- Min/Max 표시: 각 Watch 항목의 범위 자동 계산
설정 영속화
앱 종료 후 재시작해도 이전 PLC 설정이 자동 복원됩니다. 설정은 실행 디렉토리의 simulator_config.json에 저장됩니다.
Caffeine 드라이버와 연동
SimulatorApp에서 PLC를 추가하면 PlcSimulator CLI와 동일한 MC/XGT TCP 서버가 시작됩니다. Bridge.Host의 driver_settings.json에서 해당 포트로 연결하면 실제 장비와 동일하게 통신합니다.
현재 Blazor Server로 동작하지만, 동일 Blazor 컴포넌트를 MAUI Blazor Hybrid로 변환하면 데스크톱 네이티브 앱으로도 사용 가능합니다.
📚 다음 단계
- 벤치마크 테스트 가이드 — 시뮬레이션 환경에서 성능 측정하기
- 드라이버 개발 가이드 — 실제 장비 드라이버 개발
- 배포 가이드 — Docker로 프로덕션 배포