feat(report): 운전모드에 펌프 가동(RUN/STOP) 반영 + /live 최신 window만
- 펌프 게이트: 펌프 정지(state STOP/TRIP/FAULT) → 잔류 유량과 무관하게 idle.
펌프 가동(L-RUN=1/R-RUN=5) → 흐름 기반(normal/cleaning/drawdown). DetectModeAsync 통합.
인디케이터 펌프 = Report:Pumps:{col} 또는 제품펌프 P-{제품번호} 유도. realtime_table 현재 상태로 판정.
- /live: DISTINCT ON (column_id,kpi) 최신 window_start만 반환 — 과거 날짜 잔여 행이
stale state로 표시되던 버그 수정.
검증: C-6111 펌프RUN→normal, C-6211 펌프STOP→idle(잔류유량 12.8 있어도). 펌프 상태값
5=R-RUN/1=L-RUN/0=L-STOP (tag_metadata state 라벨 확정). /live 컬럼당 state 단일.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -33,9 +33,11 @@ public class ReportController : ControllerBase
|
||||
var conn = _db.Database.GetDbConnection();
|
||||
if (conn.State != ConnectionState.Open) await conn.OpenAsync(ct);
|
||||
await using var cmd = conn.CreateCommand();
|
||||
cmd.CommandText = @"SELECT column_id, kpi, value, unit, state, excluded_min, status, window_start, updated_at
|
||||
// (column_id,kpi)별 최신 window_start만 — 과거 날짜 잔여 행으로 인한 stale 표시 방지
|
||||
cmd.CommandText = @"SELECT DISTINCT ON (column_id, kpi)
|
||||
column_id, kpi, value, unit, state, excluded_min, status, window_start, updated_at
|
||||
FROM hc900.live_kpi" + (column == null ? "" : " WHERE column_id=@col") +
|
||||
" ORDER BY column_id, kpi";
|
||||
" ORDER BY column_id, kpi, window_start DESC";
|
||||
if (column != null) { var p = cmd.CreateParameter(); p.ParameterName = "@col"; p.Value = column; cmd.Parameters.Add(p); }
|
||||
var items = new List<object>();
|
||||
await using var rd = await cmd.ExecuteReaderAsync(ct);
|
||||
|
||||
@@ -91,6 +91,10 @@
|
||||
"C-9111": "C-10111",
|
||||
"C-10111": "C-9111"
|
||||
},
|
||||
"Pumps": {
|
||||
"C-6111": [ "P-6102", "P-6118" ],
|
||||
"C-6211": [ "P-6201", "P-6218" ]
|
||||
},
|
||||
"Historian": {
|
||||
"Enabled": true,
|
||||
"IntervalSeconds": 1,
|
||||
|
||||
@@ -157,13 +157,26 @@ CREATE TABLE IF NOT EXISTS hc900.kpi_alert (
|
||||
feed = rd.IsDBNull(2) ? null : rd.GetDouble(2);
|
||||
}
|
||||
}
|
||||
if (prod is null && feed is null) return ("no_data", feed);
|
||||
// 펌프 가동 여부(realtime_table 현재 상태) — 정지면 잔류 흐름과 무관하게 idle.
|
||||
var pumps = _map.PumpTags(col);
|
||||
bool pumpKnown = pumps.Count > 0, pumpRunning = false;
|
||||
if (pumpKnown)
|
||||
{
|
||||
await using var pq = conn.CreateCommand();
|
||||
pq.CommandText = "SELECT count(*) FROM hc900.realtime_table WHERE tagname = ANY(@p) AND livevalue IN ('1','5','L-RUN','R-RUN')";
|
||||
var pp = pq.CreateParameter(); pp.ParameterName = "@p"; pp.Value = pumps.ToArray(); pq.Parameters.Add(pp);
|
||||
pumpRunning = Convert.ToInt64(await pq.ExecuteScalarAsync(ct)) > 0;
|
||||
}
|
||||
|
||||
if (prod is null && feed is null && !pumpRunning) return ("no_data", feed);
|
||||
bool fLow = (feed ?? 0) < cl.FeedMin, pLow = (prod ?? 0) < cl.ProductMin, vHigh = vac.HasValue && vac > cl.VacMax;
|
||||
string mode = (fLow && pLow) ? "idle" // 아무것도 안 흐름 = 진짜 미가동
|
||||
: vHigh ? "cleaning" // 진공 깨짐 = 세정/비운전
|
||||
: (fLow) ? "drawdown" // feed≈0 + product 흐름 = 인벤토리 인출
|
||||
: (pLow) ? "cleaning" // feed 흐름 + product≈0 = 세정/startup
|
||||
: "normal"; // 둘 다 흐름 + 진공 정상
|
||||
string mode =
|
||||
(pumpKnown && !pumpRunning) ? "idle" // ★펌프 정지 = 셧다운(흐름 잔류 무관)
|
||||
: (fLow && pLow) ? (pumpRunning ? "normal" : "idle") // 펌프 도는데 흐름↓ = 가동(저율/startup)
|
||||
: vHigh ? "cleaning"
|
||||
: (fLow) ? "drawdown"
|
||||
: (pLow) ? "cleaning"
|
||||
: "normal";
|
||||
return (mode, feed);
|
||||
}
|
||||
|
||||
|
||||
@@ -73,6 +73,18 @@ public sealed class ReportColumnMap
|
||||
/// <summary>컬럼간 이송 라인 상대 컬럼(있으면). 예: C-9111↔C-10111. 없으면 null(=순수 인벤토리 인출).</summary>
|
||||
public string? TransferPartner(string column) => _config[$"Report:Transfer:{column}"];
|
||||
|
||||
/// <summary>가동 판정용 펌프 상태태그(.PV). Report:Pumps:{col} 우선, 없으면 제품펌프 P-{제품번호} 유도.</summary>
|
||||
public IReadOnlyList<string> PumpTags(string column)
|
||||
{
|
||||
var configured = _config.GetSection($"Report:Pumps:{column}").Get<string[]>();
|
||||
if (configured is { Length: > 0 })
|
||||
return configured.Select(t => t.Contains('.') ? t : t + ".PV").ToList();
|
||||
var prod = _config[$"SteamAdvisor:Columns:{column}:Product"]; // 예: FICQ-6118.PV
|
||||
if (string.IsNullOrWhiteSpace(prod)) return Array.Empty<string>();
|
||||
var num = StripAttr(prod!).Split('-').Last(); // 6118
|
||||
return new[] { $"P-{num}.PV" }; // 제품펌프
|
||||
}
|
||||
|
||||
/// <summary>동특성 대상 루프(하부온도 TICA-*A): PV vs OP(스팀밸브). 밸브 stiction/hunting 진단용.</summary>
|
||||
public bool TryResolveDynamics(string column, out string? pvTag, out string? opTag)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user