Files
OCTOPUS_TWIN-Demo/CLAUDE.md
wsh 91c1337d6a feat: PropertyWindow Network 탭 및 Twin Agent Auto 프로세스 추가
PropertyWindow에 Network 탭 시스템을 추가하고, Twin Agent의 자동 네트워크 설정 기능을 구현했습니다.

주요 기능:
- PropertyWindow 탭 시스템 (PropertyTab, PropertyTabView)
- Network 탭 추가 (Server Type별 동적 설정)
- Button PropertyType 추가 (ButtonProperty, ButtonPropertyUI)
- Label PropertyType 추가 (LabelProperty, LabelPropertyUI)
- Entity Processor 패턴 (IEntityProcessor, TwinAgentAutoProcessor)
- PropertyItem 이벤트 시스템 (ValueChanged, IsVisibleChanged, ValueChangedObject)
- 동적 가시성 제어 (Server Type, Connection Type 변경 시)
- 진행 상태 애니메이션 (타이핑 효과, 점 애니메이션, 완료 시 초록색)

Server Type 구성:
- Twin Agent: Auto 버튼 + 자동 진행 (Read Entity → Connection)
- Octopus Hub: Connection Type (MQTT/API), Topics, URI, Period
- Octopus AI: Agent Type, URI

기술 구현:
- PropertyItem 양방향 바인딩
- Entity 프로세서 컨테이너 패턴
- UniTask 비동기 진행 (1~3초 무작위 대기)
- 실시간 UI 갱신 (ValueChangedObject 이벤트)

Co-Authored-By: Claude Sonnet 4.5 (1M context) <noreply@anthropic.com>
2026-02-08 20:53:26 +09:00

15 KiB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

프로젝트 개요

2026년 2월 11일 OCTOPUS DAY 전시회를 위한 디지털 트윈 시연 프로젝트입니다.

  • Unity 버전: 6000.2.12f1 (Unity 6.0.2)
  • 언어: C# (.NET 6.0+)
  • 주요 기술: MQTT IoT 통신, 실시간 센서 데이터 시각화, 3D 디지털 트윈

개발 환경

이 프로젝트는 Unity Editor에서 실행됩니다:

  • Unity Hub를 통해 Unity 6000.2.12f1 설치 필요
  • IDE: JetBrains Rider 또는 Visual Studio
  • Windows 빌드 타겟 (기본값: FullScreen 1920x1080@60fps)

런타임 설정 파일

Assets/StreamingAssets/ 폴더의 JSON 파일들은 런타임에 로드되며 코드 수정 없이 설정을 변경할 수 있습니다:

  • MQTTConfig.json: MQTT 브로커 호스트/포트 설정
  • FactoryAppConfig.json: 현대위아 시연 설정 (API 엔드포인트, 프레임레이트)
  • AppConfig.json: 기본 앱 설정 (언어, 윈도우 크기)

아키텍처

멀티 테넌트 구조

3개의 독립적인 시연 모듈이 있으며, 각각 자체 Scene과 Manager를 가집니다:

  1. ChunilENG (Assets/Scripts/ChunilENG/)

    • 한전기술 전력 IoT 시연
    • 실시간 온도계 데이터 (MQTT 구독: DVI/HOT/+)
    • 주요 Manager: DataManager, ViewManager, MachineInfoItemManager
  2. KEPCO (Assets/Scripts/KEPCO/)

    • 한전 전력 감시 시연
    • 센서/시설 3D 시각화
    • 주요 Manager: FacilityManager, SensorManager, ColorPalette
  3. HyundaiWIA (Assets/Scripts/HyundaiWIA/)

    • 현대위아 스마트팩토리 시연
    • 설비 이상 감지 시나리오 (AnomalyScenario)
    • Dashboard: AMR, COBOT, ASRS, Lifter, Storage

초기화 흐름

OctopusTwinAppMain (App 진입점, Singleton)
  ↓ Initialized 이벤트
{Scene}Main (예: ChunilENGSceneMain, Singleton)
  ↓ async Init()
Building/Facility 초기화
  ↓ await LoadManager<T>()
Manager 로드 (DataManager, UIManager, ViewManager 등)
  ↓ SetupDataSetting()
MQTT 연결 및 이벤트 바인딩

모든 Manager는 Manager 베이스 클래스를 상속하며 async UniTask Init() 메서드를 구현합니다.

핵심 디자인 패턴

  1. Singleton 패턴

    • SingletonApp<T>: 앱 전역 진입점 (OctopusTwinAppMain)
    • SingletonScene<T>: Scene별 관리자 (ChunilENGSceneMain, KEPCOSceneMain 등)
  2. Command 패턴

    • 71개의 ICommand 구현체
    • CameraCommand, DataCommand, ObjectCommand, UICommand 등
    • UI 이벤트와 비즈니스 로직 분리
  3. 이벤트 기반 통신

    // MQTT → DataManager → UI 체인
    mqttManager.onThermostatData += dataManager.SetThermostatDataList;
    dataManager.onSetThermostatData += ui.SetData;
    

MQTT 통신

구현 위치

  • 핵심 클래스: Assets/Scripts/ChunilENG/Managements/MQTT.cs
  • 라이브러리: Best MQTT v3.0.4 (TCP 또는 WebSocket)

연결 구조

// 브로커 연결
host: "106.247.236.204"
port: "8901"
topics: "DVI/HOT/+"  // 와일드카드 구독

// 이벤트 핸들러
OnConnected  OnMessage (JSON 파싱)  콜백 실행

데이터 흐름

IoT 센서
  ↓ MQTT Publish (JSON 페이로드)
MQTT.cs OnMessage()
  ↓ JsonConvert.DeserializeObject<ThermostatData>()
DataManager.SetThermostatDataList()
  ↓ onSetThermostatData 이벤트
UI 업데이트 (ThermostatControlPanel)

비동기 처리

프로젝트 전체에서 UniTask (Cysharp)를 사용합니다 (212회 사용):

  • Scene 초기화: await building.Init()
  • Manager 로딩: await LoadManager<T>()
  • 데이터 로드: await UniTask.CompletedTask

주의: async void는 이벤트 핸들러에서만 사용하고, 일반 메서드는 async UniTask 사용.

3D 객체 계층

Scene
├── Building (GameObject)
│   ├── Facility (컴포넌트)
│   │   └── Sensor (Tag_Machine으로 필터링)
│   └── Floor (층별 관리)
├── Canvas
│   ├── PopupCanvas (동적 팝업)
│   ├── StaticCanvas (고정 UI)
│   └── TopMenuPanel
└── Camera
    └── OrbitalController (3D 카메라 제어)

객체 초기화 패턴: Building → Floor → Machine/Thermostat/Facility → Sensor (모두 async Init)

리소스 구조

  • JSON 데이터: Assets/Resources/Data/{ChunilENG|KEPCO|HyundaiWIA}/
    • MachineData.json, Facility.json, SensorColorData.json 등
  • Prefab: Assets/Resources/ (각 Scene Main Prefab)
  • UI: Assets/Resources/UI/

JSON은 Resources.Load<TextAsset>(path).text로 로드하고 Newtonsoft.Json으로 역직렬화합니다.

주요 외부 패키지

  • com.tivadar.best.http v3.0.16 (HTTP/2 지원)
  • com.tivadar.best.mqtt v3.0.4 (MQTT 프로토콜)
  • com.tivadar.best.websockets v3.0.7 (WebSocket)
  • com.cysharp.unitask (async/await)
  • com.unity.nuget.newtonsoft-json v3.2.2 (JSON 처리)
  • com.unity.render-pipelines.universal v17.2.0 (URP)

Scene 정보

Scene 용도
Demo.unity 종합 데모
Demo_Home.unity 프로젝트 선택 화면
Demo_시연.unity 한전기술 시연 (MQTT 실시간 데이터)
HyundaiWIA.unity 현대위아 스마트팩토리 시연

코드 작성 시 주의사항

  1. Manager 추가 시:

    • Manager 베이스 클래스 상속
    • async UniTask Init() 오버라이드
    • {Scene}Main.csLoadManager<T>() 호출 추가
  2. Command 추가 시:

    • ICommand 인터페이스 구현
    • Execute() 메서드에 로직 작성
    • 적절한 폴더에 배치 (CameraCommand, DataCommand 등)
  3. MQTT 토픽 추가 시:

    • MQTT.cssubscriptionTopics 배열에 추가
    • 해당 토픽의 콜백 함수 등록 (thermostatTopicTable 등)
    • 데이터 구조체 정의 ([Serializable] 특성 필요)
  4. UI 이벤트 바인딩:

    • SetupDataSetting() 메서드에서 이벤트 체인 구성
    • Manager → UI 순서로 연결

UI 시스템

Canvas 계층 구조

프로젝트는 3단계 Canvas 아키텍처를 사용합니다:

Level 1: StaticCanvas (항상 표시)
├── LeftSidePanel (도구 모음)
├── TopMenuPanel (메뉴)
└── BottomToolbar (카메라 버튼, ChunilENG만)

Level 2: PopupCanvas (동적 Panel)
├── TotalProgressPanel (종합 현황)
├── MachineDashBoard (기계 대시보드)
├── FloorControlPanel (층 조절)
└── SettingPanel (설정)

Level 3: LocalPopupManager (개별 Popup)
└── PopupBase 상속 (ToastPopup 등)

기본 클래스

  • UICanvas: 모든 Canvas의 베이스

    • LoadPanel<T>(): Panel 로드
    • GetPanel<T>(): Panel 획득
    • OpenPanel<T>(): Panel 열기
    • CanvasPanelOpenMode: None (다중), Single (단일)
  • UIPanel: 모든 Panel의 베이스

    • async UniTask Init(): 비동기 초기화
    • Open(): Panel 활성화
    • Close(): Panel 비활성화
    • GetElement<T>(name): 자식 컴포넌트 검색
  • PopupBase: 모든 Popup의 베이스

    • 자동 PopupBlocker 연동
    • ClosePopup(): 팝업 닫기
  • UIManager: Canvas 관리자

    • LoadCanvas<T>(): Canvas 로드
    • GetCanvas<T>(): Canvas 획득

프로젝트별 주요 UI

ChunilENG (생산 관리)

  • MachineDashBoard: 기계 상세 정보
  • TotalProgressPanel: 종합 진행현황 (자동 순환)
  • ThermostatControlPanel: MQTT 온도계 제어
  • 특징: IColorChangeBehaviour 색상 변경

KEPCO (전력 감시)

  • FacilityAndSensorTypeTogglePanel: 설비/센서 목록
  • TotalProgressPanel: MTR/GIS 구분 표시
  • 특징: ScriptableAnimation (Echo, Scaling 등)

HyundaiWIA (스마트팩토리)

  • AnomalyScenario: 이상 시나리오 관리자
  • EquipmentTabController: 설비 탭 (AMR, COBOT, Lifter, Storage)
  • 특징: 단계별 팝업 시나리오

Panel/Popup 생명주기

// Panel 생명주기
1. LoadPanel<T>()  Panel 검색/생성
2. await Init()  자식 컴포넌트 캐싱
3. Open()  gameObject.SetActive(true)
4. Close()  gameObject.SetActive(false)

// Popup 생명주기
1. OnEnable()  PopupBlocker.Show()
2. 사용자 상호작용
3. ClosePopup()  gameObject.SetActive(false)
4. OnDisable()  PopupBlocker.Hide()

데이터 바인딩 패턴

// 1. 직접 바인딩
MachineDashBoard.SetDetailDashBoardData(data, machine);

// 2. Content 기반 바인딩
ProgressContent.SetProductionStatusItem(completeInfoList);

// 3. 동적 생성 바인딩
var content = Instantiate(FacilitiesContent, parent);
content.SetProductionStatusItem(group.Panels, group.Type);

UI 추가 가이드

  1. Canvas 추가:

    • UICanvas 상속
    • {Project}UIManager.Init()에서 LoadCanvas<T>() 호출
  2. Panel 추가:

    • UIPanel 상속
    • async UniTask Init() 구현 (GetElement로 자식 캐싱)
    • Canvas의 Init()에서 LoadPanel<T>() 호출
  3. Popup 추가:

    • PopupBase 상속
    • OnEnable/OnDisable에서 PopupBlocker 자동 처리
    • ClosePopup() 메서드로 닫기
  4. 데이터 표시:

    • SetData() 또는 Set{DataType}() 메서드 구현
    • 이벤트 구독: dataManager.onSetData += panel.SetData
  5. 애니메이션:

    • ChunilENG: Panel_Effect, IColorChangeBehaviour
    • KEPCO: ScriptableAnimation (Animation_Scaling 등)
    • HyundaiWIA: DOTween (RectTransform.DOAnchorPos)

공통 UI 컴포넌트

  • PopupBlocker: 전역 팝업 배경 차단 (Singleton)
  • ToastPopup: 자동 닫힘 알림 (displayDuration)
  • UILoading: 로딩 화면 (Progress Bar, Fade)
  • LanguageController: 언어 전환
  • BottomToolbar: 카메라 이동 버튼

표준 UI 패턴

Panel 열기 (권장)

var uiManager = ChunilENGSceneMain.Instance.GetManager<ChunilENGUIManager>();
uiManager.GetCanvas<PopupCanvas>().OpenPanel<MachineDashBoard>(CanvasPanelOpenMode.Single);

데이터와 함께 Panel 열기

var uiManager = ChunilENGSceneMain.Instance.GetManager<ChunilENGUIManager>();
var panel = uiManager.GetCanvas<PopupCanvas>().GetPanel<MachineDashBoard>();
panel.SetDetailDashBoardData(data, machine);
uiManager.GetCanvas<PopupCanvas>().OpenPanel<MachineDashBoard>(CanvasPanelOpenMode.Single);

Panel 닫기

var panel = uiManager.GetCanvas<PopupCanvas>().GetPanel<MachineDashBoard>();
panel.Close();

Command 패턴 (UI 열기)

public class OpenMachineDashBoardCommand : ICommand
{
    public void Execute(object? parameter = null)
    {
        var uiManager = ChunilENGSceneMain.Instance.GetManager<ChunilENGUIManager>();
        uiManager.GetCanvas<PopupCanvas>().OpenPanel<MachineDashBoard>(CanvasPanelOpenMode.Single);
    }
}

이벤트 구독

// SetupDataSetting 패턴
mqttManager.onThermostatData += dataManager.SetThermostatDataList;
dataManager.onSetThermostatData += panel.SetData;

Panel 초기화

public override async UniTask Init()
{
    // GetElement로 UI 요소 캐싱
    MachineName = GetElement<TextMeshProUGUI>(nameof(MachineName));
    Button_Close = GetElement<Button>(nameof(Button_Close));

    // 이벤트 리스너 등록
    Button_Close.onClick.AddListener(Close);

    await UniTask.CompletedTask;
}

3D 오브젝트 상호작용

오브젝트 계층 구조

Building
├── Floor (층별 관리)
│   ├── Facility (설비, KEPCO)
│   │   └── Sensor (센서)
│   ├── Machine (기계, ChunilENG)
│   └── Thermostat (온도계, ChunilENG)

주요 오브젝트 클래스

Building

  • GetMachines() / GetThermostats(): 오브젝트 리스트 반환
  • SetFloor(index): 층 변경 및 가시성 제어
  • Init(): 모든 자식 오브젝트 비동기 초기화

Facility / Machine

  • centerPos: 메시 중심 좌표 (카메라 포커싱용)
  • originScale: 원본 스케일
  • Init(): centerPos, 컴포넌트 초기화
  • focusDistance/Azimuth/Elevation: 카메라 설정값 (Machine)

Sensor

  • SetSensorState(state): 상태 변경 및 색상 업데이트
  • Active() / Inactive(): 센서 활성화/비활성화
  • Hovering(): 호버 상태 동기화, Outline 활성화
  • outline: Outline 컴포넌트 (외곽선 효과)

마우스 상호작용

MachineClickManager (ChunilENG)

  • Raycast 기반 3D 오브젝트 클릭 감지
  • 이벤트: onLeftClickMachine, onLeftClickArea

UI 아이콘 클릭 (KEPCO)

  • UI_FacilityIcon / UI_SensorIcon이 IPointerClickHandler 구현
  • OnPointerClick(): SelectedObjectCommand 실행
  • OnPointerEnter/Exit(): 호버 효과 (상태 변경, Outline)

Command 패턴

SelectedObjectCommand

  • Execute(): ViewManager.SetTargetPosToMachine() 호출
  • 설비/센서 타입 판별 후 카메라 포커싱

SelectedMachineCommand

  • Machine 오브젝트로 카메라 포커싱

OpenFacilityInfoPanel

  • 설비 정보 패널 열기

카메라 제어

OrbitalController

  • 궤도형 카메라 제어 (Orbital Pattern)
  • SetTargetPos(Vector3): 타겟 위치 설정
  • AnimateToState(): DoTween 기반 부드러운 이동
  • SetViewMode(ViewMode): PerspectiveView / TopView 전환
  • 입력: 좌클릭(Pan), 우클릭(Orbit), 휠(Zoom)

오브젝트 검색

Tag 기반 검색

  • Tag_Machine: Unity VisualScripting 태그로 머신/설비 마킹
  • FindObjectsByType<Tag_Machine>(): 태그된 오브젝트 검색

타입별 필터링

  • FacilityManager: 설비타입 필터링 ("GIS", "주변압기")
  • SensorManager: SensorType별 그룹화 (PD, CB, DGA 등)
  • Dictionary 기반 빠른 검색 (name/code → 오브젝트)

시각적 효과

선택/하이라이트

  • Outline: 호버 시 외곽선 표시
  • Color 변경: MaterialPropertyBlock으로 상태별 색상
  • Animation: ScriptableAnimation (Echo, Scaling)

상태별 색상 (KEPCO)

  • ColorPalette에서 SensorState별 색상 관리
  • Normal(녹색), Interest(청록), Care(노랑), Anomaly(주황), Danger(빨강)

오브젝트 추가 가이드

  1. 새 오브젝트 타입 추가:

    • Building/Facility/Machine 중 적절한 클래스 상속
    • async UniTask Init() 구현
    • centerPos, originScale 초기화
  2. 클릭 이벤트 추가:

    • ICommand 구현체 생성 (SelectedXXXCommand)
    • MachineClickManager 또는 IPointerClickHandler 사용
  3. 오브젝트 검색:

    • Tag_Machine 태그 추가
    • Manager에서 FindObjectsByType으로 검색
    • Dictionary에 등록 (이름/코드 → 오브젝트)
  4. 시각적 효과:

    • Outline 컴포넌트 추가
    • MaterialPropertyBlock으로 색상 변경
    • ScriptableAnimation 활용

성능 최적화

  • 타겟 프레임레이트: 60fps (FactoryAppConfig.json)
  • LOD 사용: Sensor_LOD.cs (Level of Detail)
  • DOTween 애니메이션: ScriptableAnimationManager로 최적화
  • URP 렌더링: 경량화된 Universal Render Pipeline

디버깅

  • 로그: Unity Console 창 확인
  • MQTT 연결 상태: MQTT.csOnStateChange 이벤트 로그
  • Manager 초기화: 각 Manager의 isInit 플래그 확인
  • JSON 파싱 에러: Newtonsoft.Json의 예외 메시지 확인

알려진 제약사항

  • WebGL 빌드 시 MQTT는 WebSocket 모드로만 작동 (TCP 불가)
  • MQTT QoS Level 3 사용 (정확히 1회 배달)
  • 현재 중앙 MQTT 수신 시스템(DataRepository)은 주석 처리됨 (각 Scene별로 독립 연결)