분리후 첫 Crawling 성공 모델
This commit is contained in:
140
OpcPksPlatform/Services/OpcUaCollector.cs
Normal file
140
OpcPksPlatform/Services/OpcUaCollector.cs
Normal file
@@ -0,0 +1,140 @@
|
||||
using Npgsql;
|
||||
using Opc.Ua;
|
||||
using Opc.Ua.Client;
|
||||
using OpcPks.Core.Services; // OpcSessionManager 참조
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace OpcPks.Collector.Services
|
||||
{
|
||||
public class OpcUaCollector
|
||||
{
|
||||
private readonly OpcSessionManager _sessionManager;
|
||||
private ISession _session;
|
||||
private Subscription _subscription;
|
||||
private readonly string _dbConnString = "Host=localhost;Username=postgres;Password=postgres;Database=opcdb";
|
||||
|
||||
public OpcUaCollector(OpcSessionManager sessionManager)
|
||||
{
|
||||
_sessionManager = sessionManager;
|
||||
}
|
||||
|
||||
public async Task StartCollection()
|
||||
{
|
||||
try
|
||||
{
|
||||
// 1. 공통 세션 관리자로부터 하니웰 세션 가져오기
|
||||
_session = await _sessionManager.GetSessionAsync();
|
||||
|
||||
// 2. DB(tag_master)에서 엔지니어가 등록한 감시 대상 노드 리스트 조회
|
||||
var nodesToMonitor = await GetNodesFromMaster();
|
||||
|
||||
if (nodesToMonitor.Count == 0)
|
||||
{
|
||||
Console.WriteLine("⚠️ 감시 대상으로 등록된 태그가 없습니다.");
|
||||
return;
|
||||
}
|
||||
|
||||
// 3. Subscription 생성 (1초 주기 감시)
|
||||
_subscription = new Subscription(_session.DefaultSubscription) { PublishingInterval = 1000 };
|
||||
|
||||
foreach (var nodeId in nodesToMonitor)
|
||||
{
|
||||
var item = new MonitoredItem(_subscription.DefaultItem)
|
||||
{
|
||||
DisplayName = nodeId,
|
||||
StartNodeId = nodeId
|
||||
};
|
||||
|
||||
// 중요: 값이 변했을 때만 실행될 이벤트 핸들러 등록
|
||||
item.Notification += OnDataChangeReceived;
|
||||
_subscription.AddItem(item);
|
||||
}
|
||||
|
||||
_session.AddSubscription(_subscription);
|
||||
_subscription.Create();
|
||||
|
||||
Console.WriteLine($"🚀 수집 엔진 가동 중: {nodesToMonitor.Count}개의 태그 감시 시작.");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"❌ 수집 시작 중 오류 발생: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDataChangeReceived(MonitoredItem item, MonitoredItemNotificationEventArgs e)
|
||||
{
|
||||
foreach (var value in item.DequeueValues())
|
||||
{
|
||||
// 하니웰에서 값이 변경되어 통보(COV)가 오면 DB 업데이트 수행
|
||||
UpdateLiveDb(item.StartNodeId.ToString(), value.Value?.ToString() ?? "NULL", value.StatusCode.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateLiveDb(string nodeId, string val, string quality)
|
||||
{
|
||||
try
|
||||
{
|
||||
using var conn = new NpgsqlConnection(_dbConnString);
|
||||
// IS DISTINCT FROM: 실제 값이 다를 때만 쓰기(Write)를 수행하여 SSD 부하 감소
|
||||
var sql = @"
|
||||
UPDATE tag_live_data
|
||||
SET live_value = @val, quality = @q, last_updated = NOW()
|
||||
WHERE full_node_id = @id AND live_value IS DISTINCT FROM @val";
|
||||
|
||||
using var cmd = new NpgsqlCommand(sql, conn);
|
||||
cmd.Parameters.AddWithValue("id", nodeId);
|
||||
cmd.Parameters.AddWithValue("val", val);
|
||||
cmd.Parameters.AddWithValue("q", quality);
|
||||
|
||||
conn.Open();
|
||||
int affectedRows = cmd.ExecuteNonQuery();
|
||||
|
||||
if (affectedRows > 0)
|
||||
{
|
||||
Console.WriteLine($"[변경수집] {nodeId} -> {val} ({quality})");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"❌ DB 업데이트 오류: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<List<string>> GetNodesFromMaster()
|
||||
{
|
||||
var nodes = new List<string>();
|
||||
try
|
||||
{
|
||||
using var conn = new NpgsqlConnection(_dbConnString);
|
||||
await conn.OpenAsync();
|
||||
|
||||
// tag_master에서 활성화된(is_active) 태그들만 가져옴
|
||||
var sql = "SELECT full_node_id FROM tag_master WHERE is_active = TRUE";
|
||||
using var cmd = new NpgsqlCommand(sql, conn);
|
||||
using var reader = await cmd.ExecuteReaderAsync();
|
||||
|
||||
while (await reader.ReadAsync())
|
||||
{
|
||||
nodes.Add(reader.GetString(0));
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Console.WriteLine($"❌ 마스터 노드 조회 실패: {ex.Message}");
|
||||
}
|
||||
return nodes;
|
||||
}
|
||||
|
||||
public async Task StopCollection()
|
||||
{
|
||||
if (_subscription != null)
|
||||
{
|
||||
_subscription.Delete(true);
|
||||
}
|
||||
Console.WriteLine("⏹️ 수집 엔진 정지.");
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user