OPC DB server Project First Commit
This commit is contained in:
137
.Notebook/BRIN 설명.md
Normal file
137
.Notebook/BRIN 설명.md
Normal file
@@ -0,0 +1,137 @@
|
||||
1️⃣ BRIN 인덱스란?
|
||||
|
||||
Block Range INdex 의 약자
|
||||
|
||||
대용량 테이블에서 연속적인 값(순차적/시간적)에 최적화
|
||||
|
||||
일반 B-Tree 인덱스보다 작고 빠르게 생성 가능
|
||||
|
||||
하지만 랜덤값 검색에는 적합하지 않음
|
||||
|
||||
💡 요약:
|
||||
|
||||
특징 설명
|
||||
장점 작은 크기, 빠른 생성, 디스크 절약
|
||||
단점 랜덤/불규칙 값 검색 느림
|
||||
사용 예 날짜, 시퀀스, ID 등 순차적 값 컬럼
|
||||
2️⃣ BRIN 인덱스 생성 기본 문법
|
||||
CREATE INDEX index_name
|
||||
ON table_name USING brin (column_name);
|
||||
|
||||
|
||||
예제:
|
||||
|
||||
CREATE INDEX brin_test_table_age
|
||||
ON test_table USING brin (age);
|
||||
|
||||
|
||||
test_table의 age 컬럼에 BRIN 인덱스 생성
|
||||
|
||||
대량 데이터에서 범위 검색할 때 효율적
|
||||
|
||||
3️⃣ BRIN 인덱스 옵션
|
||||
CREATE INDEX brin_test_table_age
|
||||
ON test_table USING brin (age)
|
||||
WITH (pages_per_range = 32);
|
||||
|
||||
|
||||
pages_per_range → 한 인덱스 범위에 몇 페이지를 묶을지 설정 (기본값 128)
|
||||
|
||||
범위를 작게 하면 검색 정확도 ↑, 인덱스 크기 ↑
|
||||
|
||||
범위를 크게 하면 인덱스 작고 빠름, 정확도 ↓
|
||||
|
||||
4️⃣ 사용 예제
|
||||
범위 검색
|
||||
-- age가 30 이상 40 이하인 데이터 검색
|
||||
SELECT * FROM test_table
|
||||
WHERE age BETWEEN 30 AND 40;
|
||||
|
||||
|
||||
BRIN 인덱스를 생성하면 범위 검색이 빨라짐
|
||||
|
||||
작은 테이블에서는 체감 안 될 수 있음 → 수십만~수백만 행 이상에서 효과적
|
||||
|
||||
복합 컬럼 BRIN 인덱스
|
||||
CREATE INDEX brin_test_table_name_age
|
||||
ON test_table USING brin (name, age);
|
||||
|
||||
|
||||
여러 컬럼 순서대로 범위 기반 검색 가능
|
||||
|
||||
💡 Tip
|
||||
|
||||
BRIN 인덱스는 연속적인 값에서 진가
|
||||
|
||||
순차적 시퀀스, 타임스탬프 컬럼에 주로 사용
|
||||
|
||||
랜덤/고르게 분포된 값 → B-Tree 인덱스가 더 적합
|
||||
===========================================================================
|
||||
|
||||
1️⃣ TimescaleDB란?
|
||||
|
||||
PostgreSQL 기반 시계열(Time-Series) 데이터베이스 확장
|
||||
|
||||
하이퍼테이블(Hypertable) 구조로 자동 파티셔닝
|
||||
|
||||
시계열 데이터 삽입, 조회, 집계 최적화
|
||||
|
||||
2️⃣ BRIN + TimescaleDB의 조합
|
||||
|
||||
TimescaleDB는 내부적으로 하이퍼테이블 파티셔닝
|
||||
|
||||
시계열 데이터는 시간 컬럼 기준으로 연속적이기 때문에
|
||||
|
||||
BRIN 인덱스와 궁합이 매우 좋음
|
||||
|
||||
💡 특징:
|
||||
|
||||
특징 설명
|
||||
인덱스 크기 BRIN → 매우 작음
|
||||
삽입 속도 TimescaleDB → 초당 수십만~수백만 레코드 처리 가능
|
||||
조회 효율 시간 범위 쿼리 → BRIN + 하이퍼테이블 최적화
|
||||
3️⃣ 기본 사용법
|
||||
1) TimescaleDB 설치 후 extension 활성화
|
||||
-- PostgreSQL에서
|
||||
CREATE EXTENSION IF NOT EXISTS timescaledb;
|
||||
|
||||
2) 테이블을 하이퍼테이블로 변환
|
||||
CREATE TABLE sensor_data (
|
||||
time TIMESTAMPTZ NOT NULL,
|
||||
device_id INT NOT NULL,
|
||||
temperature DOUBLE PRECISION NOT NULL
|
||||
);
|
||||
|
||||
-- 하이퍼테이블로 변환 (시간 컬럼: time)
|
||||
SELECT create_hypertable('sensor_data', 'time');
|
||||
|
||||
3) BRIN 인덱스 생성
|
||||
-- 시간 기준 BRIN 인덱스
|
||||
CREATE INDEX brin_sensor_time
|
||||
ON sensor_data USING brin (time);
|
||||
|
||||
-- 필요시 device_id 추가 가능
|
||||
CREATE INDEX brin_sensor_device_time
|
||||
ON sensor_data USING brin (device_id, time);
|
||||
|
||||
|
||||
시간 컬럼 순차적 → BRIN 범위 검색에 최적화
|
||||
|
||||
작은 인덱스로 수십억 행도 검색 가능
|
||||
|
||||
4️⃣ 범위 조회 예제
|
||||
-- 특정 시간 범위 데이터 조회
|
||||
SELECT *
|
||||
FROM sensor_data
|
||||
WHERE time BETWEEN '2026-02-01 00:00:00' AND '2026-02-02 00:00:00';
|
||||
|
||||
|
||||
BRIN 인덱스 덕분에 빠른 범위 스캔 가능
|
||||
|
||||
🔹 정리
|
||||
|
||||
TimescaleDB = 시계열 최적화 + 자동 파티셔닝
|
||||
|
||||
BRIN 인덱스 = 연속적 시간 컬럼에 최적화된 작은 범위 인덱스
|
||||
|
||||
조합 = 대용량 시계열 데이터 + 낮은 디스크 사용 + 빠른 범위 쿼리
|
||||
60
.Notebook/Nuget에 OPC UA 라이브러리설치.md
Normal file
60
.Notebook/Nuget에 OPC UA 라이브러리설치.md
Normal file
@@ -0,0 +1,60 @@
|
||||
1️⃣ 프로젝트 폴더에서 NuGet 설치
|
||||
|
||||
터미널에서 프로젝트 디렉토리로 이동:
|
||||
|
||||
cd ~/projects/DbTest
|
||||
|
||||
|
||||
패키지 설치:
|
||||
|
||||
dotnet add package OPCFoundation.NetStandard.Opc.Ua
|
||||
|
||||
|
||||
이 명령어가 NuGet에서 라이브러리 다운로드 + 프로젝트에 추가까지 해줌
|
||||
|
||||
설치 후 출력 메시지에 Successfully added 확인
|
||||
|
||||
2️⃣ 설치 확인
|
||||
dotnet list package
|
||||
|
||||
|
||||
출력 예시:
|
||||
|
||||
Project 'DbTest' has the following package references
|
||||
[net8.0]:
|
||||
Top-level Package Requested Resolved
|
||||
> OPCFoundation.NetStandard.Opc.Ua 1.4.365 1.4.365
|
||||
|
||||
3️⃣ 테스트 코드
|
||||
|
||||
설치 완료 후 간단한 OPC UA 연결 테스트 작성 가능:
|
||||
|
||||
using Opc.Ua;
|
||||
using Opc.Ua.Client;
|
||||
using Opc.Ua.Configuration;
|
||||
|
||||
class Program
|
||||
{
|
||||
static async Task Main()
|
||||
{
|
||||
var config = new ApplicationConfiguration
|
||||
{
|
||||
ApplicationName = "ExperionClient",
|
||||
ApplicationType = ApplicationType.Client,
|
||||
SecurityConfiguration = new SecurityConfiguration
|
||||
{
|
||||
ApplicationCertificate = new CertificateIdentifier()
|
||||
},
|
||||
ClientConfiguration = new ClientConfiguration()
|
||||
};
|
||||
await config.Validate(ApplicationType.Client);
|
||||
|
||||
var endpointURL = "opc.tcp://<EXPERION_IP>:4840";
|
||||
var selectedEndpoint = CoreClientUtils.SelectEndpoint(endpointURL, useSecurity: false);
|
||||
var session = await Session.Create(config,
|
||||
new ConfiguredEndpoint(null, selectedEndpoint, EndpointConfiguration.Create(config)),
|
||||
false, "", 60000, null, null);
|
||||
|
||||
Console.WriteLine("Experion OPC UA 연결 성공!");
|
||||
}
|
||||
}
|
||||
400
.Notebook/OpcTest program by claude.md
Normal file
400
.Notebook/OpcTest program by claude.md
Normal file
@@ -0,0 +1,400 @@
|
||||
Experion 서버 연결 테스트 코드를 작성해드리겠습니다!
|
||||
🚀 빠른 테스트 프로젝트 생성
|
||||
bashcd ~/projects
|
||||
mkdir OpcConnectionTest
|
||||
cd OpcConnectionTest
|
||||
|
||||
# 콘솔 프로젝트 생성
|
||||
dotnet new console
|
||||
|
||||
# .NET 8.0 고정
|
||||
dotnet new globaljson --sdk-version 8.0.123 --force
|
||||
|
||||
# OPC UA 패키지 설치
|
||||
dotnet add package OPCFoundation.NetStandard.Opc.Ua
|
||||
dotnet add package OPCFoundation.NetStandard.Opc.Ua.Client
|
||||
|
||||
📝 Program.cs
|
||||
csharpusing Opc.Ua;
|
||||
using Opc.Ua.Client;
|
||||
using Opc.Ua.Configuration;
|
||||
|
||||
namespace OpcConnectionTest
|
||||
{
|
||||
class Program
|
||||
{
|
||||
static async Task Main(string[] args)
|
||||
{
|
||||
Console.WriteLine("=== Experion OPC UA Connection Test ===\n");
|
||||
|
||||
// Experion 서버 정보 (VMware 환경)
|
||||
string primaryEndpoint = "opc.tcp://192.168.xxx.xxx:4840"; // Primary 서버 IP
|
||||
string secondaryEndpoint = "opc.tcp://192.168.xxx.xxx:4840"; // Secondary 서버 IP (있다면)
|
||||
|
||||
Console.WriteLine($"Primary Server: {primaryEndpoint}");
|
||||
Console.WriteLine($"Secondary Server: {secondaryEndpoint}\n");
|
||||
|
||||
try
|
||||
{
|
||||
// 1. Application Configuration 생성
|
||||
var config = new ApplicationConfiguration()
|
||||
{
|
||||
ApplicationName = "OPC UA Test Client",
|
||||
ApplicationType = ApplicationType.Client,
|
||||
ApplicationUri = "urn:localhost:OpcUaTestClient",
|
||||
|
||||
SecurityConfiguration = new SecurityConfiguration
|
||||
{
|
||||
ApplicationCertificate = new CertificateIdentifier
|
||||
{
|
||||
StoreType = "Directory",
|
||||
StorePath = "OPC Foundation/CertificateStores/MachineDefault"
|
||||
},
|
||||
AutoAcceptUntrustedCertificates = true, // 테스트용
|
||||
RejectSHA1SignedCertificates = false
|
||||
},
|
||||
|
||||
TransportConfigurations = new TransportConfigurationCollection(),
|
||||
TransportQuotas = new TransportQuotas { OperationTimeout = 15000 },
|
||||
|
||||
ClientConfiguration = new ClientConfiguration { DefaultSessionTimeout = 60000 },
|
||||
|
||||
TraceConfiguration = new TraceConfiguration
|
||||
{
|
||||
OutputFilePath = "OpcUaTest.log",
|
||||
TraceMasks = 0 // 로그 레벨 (0: 없음, 1: Error, 511: 전부)
|
||||
}
|
||||
};
|
||||
|
||||
await config.Validate(ApplicationType.Client);
|
||||
|
||||
// 2. Primary 서버 검색
|
||||
Console.WriteLine("Step 1: Discovering Primary Server...");
|
||||
var endpoints = await DiscoverEndpoints(primaryEndpoint);
|
||||
|
||||
if (endpoints == null || endpoints.Count == 0)
|
||||
{
|
||||
Console.WriteLine("❌ No endpoints found on Primary server!");
|
||||
return;
|
||||
}
|
||||
|
||||
Console.WriteLine($"✅ Found {endpoints.Count} endpoint(s)");
|
||||
foreach (var ep in endpoints)
|
||||
{
|
||||
Console.WriteLine($" - {ep.EndpointUrl} ({ep.SecurityMode})");
|
||||
}
|
||||
|
||||
// 3. Primary 서버 연결
|
||||
Console.WriteLine("\nStep 2: Connecting to Primary Server...");
|
||||
var session = await CreateSession(config, endpoints[0]);
|
||||
|
||||
if (session == null)
|
||||
{
|
||||
Console.WriteLine("❌ Failed to create session!");
|
||||
return;
|
||||
}
|
||||
|
||||
Console.WriteLine($"✅ Connected! Session ID: {session.SessionId}");
|
||||
|
||||
// 4. 서버 정보 읽기
|
||||
Console.WriteLine("\nStep 3: Reading Server Information...");
|
||||
await ReadServerInfo(session);
|
||||
|
||||
// 5. Redundancy 정보 읽기 (Experion Redundant 확인)
|
||||
Console.WriteLine("\nStep 4: Checking Redundancy Support...");
|
||||
await CheckRedundancy(session);
|
||||
|
||||
// 6. 샘플 태그 읽기 (있다면)
|
||||
Console.WriteLine("\nStep 5: Reading Sample Tags...");
|
||||
await ReadSampleTags(session);
|
||||
|
||||
// 7. 연결 종료
|
||||
Console.WriteLine("\nStep 6: Closing connection...");
|
||||
session.Close();
|
||||
Console.WriteLine("✅ Connection closed successfully!");
|
||||
|
||||
// Secondary 서버도 테스트 (선택)
|
||||
if (!string.IsNullOrEmpty(secondaryEndpoint) && secondaryEndpoint != primaryEndpoint)
|
||||
{
|
||||
Console.WriteLine("\n\n=== Testing Secondary Server ===");
|
||||
await TestSecondaryServer(config, secondaryEndpoint);
|
||||
}
|
||||
|
||||
Console.WriteLine("\n✅ All tests completed!");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"\n❌ Error: {ex.Message}");
|
||||
Console.WriteLine($"Stack: {ex.StackTrace}");
|
||||
}
|
||||
|
||||
Console.WriteLine("\nPress any key to exit...");
|
||||
Console.ReadKey();
|
||||
}
|
||||
|
||||
// Endpoint 검색
|
||||
static async Task<EndpointDescriptionCollection> DiscoverEndpoints(string serverUrl)
|
||||
{
|
||||
try
|
||||
{
|
||||
var endpointConfiguration = EndpointConfiguration.Create();
|
||||
endpointConfiguration.OperationTimeout = 10000;
|
||||
|
||||
using (var client = DiscoveryClient.Create(new Uri(serverUrl), endpointConfiguration))
|
||||
{
|
||||
var endpoints = await client.GetEndpointsAsync(null);
|
||||
return endpoints;
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Discovery failed: {ex.Message}");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// 세션 생성
|
||||
static async Task<ISession> CreateSession(ApplicationConfiguration config, EndpointDescription endpoint)
|
||||
{
|
||||
try
|
||||
{
|
||||
var endpointConfiguration = EndpointConfiguration.Create(config);
|
||||
var configuredEndpoint = new ConfiguredEndpoint(null, endpoint, endpointConfiguration);
|
||||
|
||||
var session = await Session.Create(
|
||||
config,
|
||||
configuredEndpoint,
|
||||
false,
|
||||
config.ApplicationName,
|
||||
60000,
|
||||
new UserIdentity(new AnonymousIdentityToken()), // 익명 인증
|
||||
null
|
||||
);
|
||||
|
||||
return session;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Session creation failed: {ex.Message}");
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
// 서버 정보 읽기
|
||||
static async Task ReadServerInfo(ISession session)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Server Status 노드 읽기
|
||||
var nodeId = new NodeId(Objects.Server_ServerStatus);
|
||||
var value = await Task.Run(() => session.ReadValue(nodeId));
|
||||
|
||||
Console.WriteLine($"Server Status: {value.Value}");
|
||||
|
||||
// Server State 읽기
|
||||
var stateNodeId = new NodeId(Variables.Server_ServerStatus_State);
|
||||
var stateValue = await Task.Run(() => session.ReadValue(stateNodeId));
|
||||
Console.WriteLine($"Server State: {stateValue.Value}");
|
||||
|
||||
// Current Time 읽기
|
||||
var timeNodeId = new NodeId(Variables.Server_ServerStatus_CurrentTime);
|
||||
var timeValue = await Task.Run(() => session.ReadValue(timeNodeId));
|
||||
Console.WriteLine($"Server Current Time: {timeValue.Value}");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Failed to read server info: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
// Redundancy 지원 확인
|
||||
static async Task CheckRedundancy(ISession session)
|
||||
{
|
||||
try
|
||||
{
|
||||
// ServiceLevel 읽기 (Primary: 200+, Secondary: <200)
|
||||
var serviceLevelNode = new NodeId(Variables.Server_ServiceLevel);
|
||||
var serviceLevel = await Task.Run(() => session.ReadValue(serviceLevelNode));
|
||||
|
||||
byte level = Convert.ToByte(serviceLevel.Value);
|
||||
Console.WriteLine($"Service Level: {level}");
|
||||
|
||||
if (level >= 200)
|
||||
{
|
||||
Console.WriteLine("✅ This is PRIMARY server");
|
||||
}
|
||||
else if (level > 0)
|
||||
{
|
||||
Console.WriteLine("⚠️ This is SECONDARY server");
|
||||
}
|
||||
else
|
||||
{
|
||||
Console.WriteLine("ℹ️ Standalone server (no redundancy)");
|
||||
}
|
||||
|
||||
// ServerRedundancy 노드 확인
|
||||
var redundancyNode = new NodeId(Objects.Server_ServerRedundancy);
|
||||
var redundancyValue = await Task.Run(() => session.ReadValue(redundancyNode));
|
||||
Console.WriteLine($"Redundancy Support: {redundancyValue.StatusCode}");
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Redundancy check failed: {ex.Message}");
|
||||
Console.WriteLine("ℹ️ Server may not support redundancy");
|
||||
}
|
||||
}
|
||||
|
||||
// 샘플 태그 읽기
|
||||
static async Task ReadSampleTags(ISession session)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Browse root folder
|
||||
var browser = new Browser(session)
|
||||
{
|
||||
BrowseDirection = BrowseDirection.Forward,
|
||||
ReferenceTypeId = ReferenceTypeIds.HierarchicalReferences,
|
||||
IncludeSubtypes = true,
|
||||
NodeClassMask = (int)NodeClass.Variable | (int)NodeClass.Object,
|
||||
ResultMask = (uint)BrowseResultMask.All
|
||||
};
|
||||
|
||||
// Objects 폴더 탐색
|
||||
var references = browser.Browse(ObjectIds.ObjectsFolder);
|
||||
|
||||
Console.WriteLine($"Found {references.Count} nodes in Objects folder:");
|
||||
int count = 0;
|
||||
foreach (var reference in references)
|
||||
{
|
||||
Console.WriteLine($" - {reference.DisplayName} ({reference.NodeClass})");
|
||||
|
||||
if (++count >= 10) // 처음 10개만 표시
|
||||
{
|
||||
Console.WriteLine(" ... (more)");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 특정 태그가 있다면 읽기 (NodeId를 알고 있을 때)
|
||||
// var tagNodeId = new NodeId("ns=2;s=YourTagName");
|
||||
// var tagValue = await Task.Run(() => session.ReadValue(tagNodeId));
|
||||
// Console.WriteLine($"Tag Value: {tagValue.Value}");
|
||||
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Tag reading failed: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
// Secondary 서버 테스트
|
||||
static async Task TestSecondaryServer(ApplicationConfiguration config, string serverUrl)
|
||||
{
|
||||
try
|
||||
{
|
||||
var endpoints = await DiscoverEndpoints(serverUrl);
|
||||
|
||||
if (endpoints == null || endpoints.Count == 0)
|
||||
{
|
||||
Console.WriteLine("❌ Secondary server not reachable");
|
||||
return;
|
||||
}
|
||||
|
||||
Console.WriteLine($"✅ Secondary server found with {endpoints.Count} endpoint(s)");
|
||||
|
||||
var session = await CreateSession(config, endpoints[0]);
|
||||
if (session != null)
|
||||
{
|
||||
Console.WriteLine("✅ Secondary server connection successful!");
|
||||
|
||||
// ServiceLevel 확인
|
||||
var serviceLevelNode = new NodeId(Variables.Server_ServiceLevel);
|
||||
var serviceLevel = await Task.Run(() => session.ReadValue(serviceLevelNode));
|
||||
Console.WriteLine($"Secondary Service Level: {serviceLevel.Value}");
|
||||
|
||||
session.Close();
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"Secondary test failed: {ex.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
⚙️ 설정 수정 포인트
|
||||
Line 15-16: Experion 서버 IP 주소 변경
|
||||
csharpstring primaryEndpoint = "opc.tcp://192.168.1.10:4840"; // ← 실제 IP
|
||||
string secondaryEndpoint = "opc.tcp://192.168.1.11:4840"; // ← 실제 IP
|
||||
|
||||
🚀 실행
|
||||
bashcd ~/projects/OpcConnectionTest
|
||||
|
||||
# 빌드
|
||||
dotnet build
|
||||
|
||||
# 실행
|
||||
dotnet run
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 📊 예상 출력
|
||||
```
|
||||
=== Experion OPC UA Connection Test ===
|
||||
|
||||
Primary Server: opc.tcp://192.168.1.10:4840
|
||||
Secondary Server: opc.tcp://192.168.1.11:4840
|
||||
|
||||
Step 1: Discovering Primary Server...
|
||||
✅ Found 2 endpoint(s)
|
||||
- opc.tcp://192.168.1.10:4840 (SignAndEncrypt)
|
||||
- opc.tcp://192.168.1.10:4840 (None)
|
||||
|
||||
Step 2: Connecting to Primary Server...
|
||||
✅ Connected! Session ID: ns=1;i=123456
|
||||
|
||||
Step 3: Reading Server Information...
|
||||
Server State: Running
|
||||
Server Current Time: 2026-02-08 15:30:45
|
||||
|
||||
Step 4: Checking Redundancy Support...
|
||||
Service Level: 255
|
||||
✅ This is PRIMARY server
|
||||
Redundancy Support: Good
|
||||
|
||||
Step 5: Reading Sample Tags...
|
||||
Found 15 nodes in Objects folder:
|
||||
- Server (Object)
|
||||
- DeviceSet (Object)
|
||||
- ...
|
||||
|
||||
Step 6: Closing connection...
|
||||
✅ Connection closed successfully!
|
||||
|
||||
✅ All tests completed!
|
||||
|
||||
🔧 문제 해결
|
||||
1. "Connection refused" 에러
|
||||
bash# 방화벽 확인
|
||||
sudo ufw status
|
||||
sudo ufw allow 4840/tcp
|
||||
|
||||
# Experion 서버 ping 확인
|
||||
ping 192.168.1.10
|
||||
2. "Certificate validation failed"
|
||||
csharp// Line 25에서 이미 설정됨
|
||||
AutoAcceptUntrustedCertificates = true
|
||||
3. IP 주소 확인
|
||||
bash# VMware에서 Experion 서버 IP 확인
|
||||
# Windows 개발 PC에서
|
||||
ping experion-server-name
|
||||
|
||||
📝 다음 단계
|
||||
연결 성공하면:
|
||||
|
||||
✅ Tag 목록 가져오기
|
||||
✅ Tag 구독 (Subscription) 테스트
|
||||
✅ 실시간 데이터 수신 테스트
|
||||
1
.Notebook/ubuntu 서버 기본명령어.md
Normal file
1
.Notebook/ubuntu 서버 기본명령어.md
Normal file
@@ -0,0 +1 @@
|
||||
셧다운 : sudo shutdown now
|
||||
174
.Notebook/설치패키지 체크 by claude.md
Normal file
174
.Notebook/설치패키지 체크 by claude.md
Normal file
@@ -0,0 +1,174 @@
|
||||
현재 설치 상태 요약
|
||||
✅ 이미 설치된 것들
|
||||
1. 개발 환경
|
||||
✓ .NET SDK 8.0.123
|
||||
✓ .NET SDK 10.0 (aspnetcore-runtime-10.0)
|
||||
✓ dotnet-sdk-8.0
|
||||
2. 데이터베이스
|
||||
✓ PostgreSQL 16.11
|
||||
✓ TimescaleDB 2.25.0
|
||||
✓ postgresql-client-16
|
||||
3. 시스템 도구
|
||||
✓ Git 2.43.0
|
||||
✓ curl, wget
|
||||
✓ vim, nano
|
||||
✓ htop (시스템 모니터링)
|
||||
✓ tmux (터미널 멀티플렉서)
|
||||
|
||||
🔧 추가로 설치해야 할 것들
|
||||
1. OPC UA 라이브러리 (NuGet)
|
||||
bashcd ~/projects/OpcUaMinimal
|
||||
dotnet add package OPCFoundation.NetStandard.Opc.Ua --version 1.5.374.126
|
||||
dotnet add package OPCFoundation.NetStandard.Opc.Ua.Client --version 1.5.374.126
|
||||
또는 더 간단한 라이브러리:
|
||||
bashdotnet add package Technosoftware.OpcUaNetStandardLibrary --version 7.0.0
|
||||
2. Entity Framework Core (PostgreSQL)
|
||||
bashdotnet add package Npgsql.EntityFrameworkCore.PostgreSQL --version 8.0.23
|
||||
dotnet add package Microsoft.EntityFrameworkCore.Design --version 8.0.23
|
||||
dotnet add package Microsoft.EntityFrameworkCore.Tools --version 8.0.23
|
||||
3. SignalR (실시간 통신)
|
||||
bashdotnet add package Microsoft.AspNetCore.SignalR.Client --version 8.0.23
|
||||
4. 기타 필수 라이브러리
|
||||
bash# Logging
|
||||
dotnet add package Serilog.AspNetCore --version 8.0.3
|
||||
dotnet add package Serilog.Sinks.File --version 6.0.0
|
||||
dotnet add package Serilog.Sinks.PostgreSQL --version 3.2.0
|
||||
|
||||
# Configuration
|
||||
dotnet add package Microsoft.Extensions.Configuration.Json
|
||||
dotnet add package Microsoft.Extensions.Options.ConfigurationExtensions
|
||||
|
||||
# Background Service
|
||||
dotnet add package Microsoft.Extensions.Hosting
|
||||
dotnet add package Microsoft.Extensions.Hosting.Systemd
|
||||
5. 시스템 서비스 관련 (Linux에서 필요)
|
||||
bash# systemd 개발 헤더 (이미 설치됨)
|
||||
✓ systemd-dev
|
||||
|
||||
# 추가 필요한 것
|
||||
sudo apt update
|
||||
sudo apt install -y build-essential
|
||||
|
||||
📁 프로젝트 구조 생성
|
||||
bashcd ~/projects
|
||||
mkdir -p OpcClientSystem
|
||||
cd OpcClientSystem
|
||||
|
||||
# 1. Core 프로젝트
|
||||
dotnet new classlib -n Domain -o 01_Core/Domain
|
||||
dotnet new classlib -n Application -o 01_Core/Application
|
||||
|
||||
# 2. Infrastructure 프로젝트
|
||||
dotnet new classlib -n Infrastructure -o 02_Infrastructure
|
||||
|
||||
# 3. OPC Client Service
|
||||
dotnet new worker -n OpcDataCollector.Service -o 03_Service
|
||||
|
||||
# 4. Web API
|
||||
dotnet new webapi -n IndustrialAutomation.API -o 04_WebAPI
|
||||
|
||||
# 5. Blazor Web (선택)
|
||||
dotnet new blazor -n IndustrialAutomation.Web -o 05_Web
|
||||
|
||||
# Solution 파일 생성
|
||||
dotnet new sln -n OpcClientSystem
|
||||
|
||||
# 프로젝트들을 Solution에 추가
|
||||
dotnet sln add 01_Core/Domain/Domain.csproj
|
||||
dotnet sln add 01_Core/Application/Application.csproj
|
||||
dotnet sln add 02_Infrastructure/Infrastructure.csproj
|
||||
dotnet sln add 03_Service/OpcDataCollector.Service/OpcDataCollector.Service.csproj
|
||||
dotnet sln add 04_WebAPI/IndustrialAutomation.API/IndustrialAutomation.API.csproj
|
||||
|
||||
🗄️ PostgreSQL 설정
|
||||
DB 생성 (아직 안 했다면)
|
||||
bashsudo -u postgres psql
|
||||
|
||||
# PostgreSQL 프롬프트에서
|
||||
CREATE DATABASE scada;
|
||||
CREATE USER opcuser WITH PASSWORD 'your_password';
|
||||
GRANT ALL PRIVILEGES ON DATABASE scada TO opcuser;
|
||||
|
||||
# TimescaleDB 확장 활성화
|
||||
\c scada
|
||||
CREATE EXTENSION IF NOT EXISTS timescaledb;
|
||||
|
||||
\q
|
||||
연결 테스트
|
||||
bashpsql -h localhost -U opcuser -d scada
|
||||
# 비밀번호 입력 후 연결 확인
|
||||
|
||||
🔐 환경 변수 설정
|
||||
bash# ~/.bashrc 또는 ~/.profile에 추가
|
||||
echo 'export ConnectionStrings__DefaultConnection="Host=localhost;Database=scada;Username=opcuser;Password=your_password"' >> ~/.bashrc
|
||||
source ~/.bashrc
|
||||
|
||||
🚀 개발 시작 체크리스트
|
||||
✅ 완료된 것
|
||||
|
||||
Ubuntu Server 24.04 설치
|
||||
PostgreSQL 16 설치
|
||||
TimescaleDB 설치
|
||||
.NET SDK 8.0 설치
|
||||
Git 설치
|
||||
VSCode Remote SSH 연결
|
||||
|
||||
📝 해야 할 것
|
||||
|
||||
OPC UA NuGet 패키지 설치
|
||||
EF Core PostgreSQL 패키지 설치
|
||||
프로젝트 구조 생성
|
||||
Database 스키마 생성
|
||||
OPC Client 기본 연결 테스트
|
||||
Experion 서버 연결 확인
|
||||
|
||||
|
||||
🎯 다음 단계 제안
|
||||
bash# 1. 간단한 테스트 프로젝트부터 시작
|
||||
cd ~/projects
|
||||
dotnet new console -n OpcTest
|
||||
cd OpcTest
|
||||
|
||||
# 2. OPC UA 패키지 설치
|
||||
dotnet add package OPCFoundation.NetStandard.Opc.Ua.Client
|
||||
|
||||
# 3. Experion 연결 테스트 코드 작성
|
||||
# (다음 메시지에서 샘플 코드 제공 가능)
|
||||
|
||||
# 4. 테스트 실행
|
||||
dotnet run
|
||||
필요한 것이 더 있으면 말씀해주세요!
|
||||
|
||||
OPC UA 연결 테스트 코드?
|
||||
DB 스키마 생성 스크립트?
|
||||
전체 프로젝트 템플릿 코드?
|
||||
nuget 이미 설치했는데?오전 10:01아! 죄송합니다. NuGet은 .NET SDK에 포함되어 있으니 이미 사용 가능합니다.
|
||||
제가 말한 건 NuGet 패키지 관리자가 아니라 NuGet 패키지(라이브러리) 설치를 의미한 거였습니다.
|
||||
정리하면:
|
||||
✅ 이미 있는 것 (설치 완료)
|
||||
✓ NuGet (패키지 관리자) - .NET SDK에 포함
|
||||
✓ .NET SDK 8.0
|
||||
✓ PostgreSQL 16
|
||||
✓ TimescaleDB
|
||||
📦 해야 할 것 (프로젝트에 라이브러리 추가)
|
||||
프로젝트를 만든 후에:
|
||||
bashcd ~/projects/OpcUaMinimal # 또는 새 프로젝트 경로
|
||||
|
||||
# 이런 명령어들로 라이브러리 추가
|
||||
dotnet add package OPCFoundation.NetStandard.Opc.Ua.Client
|
||||
dotnet add package Npgsql.EntityFrameworkCore.PostgreSQL
|
||||
NuGet 자체는 설치할 필요 없고,
|
||||
NuGet을 통해 라이브러리들을 추가하면 됩니다!
|
||||
|
||||
🚀 바로 시작할 수 있는 것
|
||||
bashcd ~/projects/OpcUaMinimal
|
||||
|
||||
# OPC UA 라이브러리 추가
|
||||
dotnet add package OPCFoundation.NetStandard.Opc.Ua.Client
|
||||
|
||||
# PostgreSQL 라이브러리 추가
|
||||
dotnet add package Npgsql.EntityFrameworkCore.PostgreSQL
|
||||
|
||||
# 설치 확인
|
||||
dotnet list package
|
||||
이제 Experion 서버 연결 테스트 코드가 필요하신가요?
|
||||
Reference in New Issue
Block a user