- FeedforwardSupervisor: PvTag() ToUpperInvariant + empty FeedTag 가드 - FeedforwardConfigStore: 모든 ToLowerInvariant() 제거 - FeedRampAdvisorService: ToLowerInvariant 제거 + StringComparison.OrdinalIgnoreCase - SimOverrideStore: ToLowerInvariant 제거 - Hc900RealtimeService: HealthCheck SERVING 판정, mapping 없는 태그 대소문자 유지 - PidExtractorService: ToLowerInvariant → OrdinalIgnoreCase 비교 - Hc900Entities: 주석 업데이트 (대문자 표준) - load_state_labels.py: 소문자 변환 금지, controller_id 파라미터 추가 - Hc900Controllers: 대소문자 무시 정렬 - write.js: .MODE → AutoManState/RemLocSPState/SP_SelectState/TuneSetState - setup.js/html: 중복 함수 제거, C5 컨트롤러 placeholder
102 lines
5.0 KiB
JavaScript
102 lines
5.0 KiB
JavaScript
/* ─────────────────────────────────────────────────────────────
|
|
15 HC900 Write
|
|
───────────────────────────────────────────────────────────── */
|
|
async function writeLoadControllers() {
|
|
const d = await api('GET', '/api/gateway/status');
|
|
const sel = document.getElementById('w-ctrl');
|
|
sel.innerHTML = '';
|
|
const controllers = d.controllers || {};
|
|
const entries = Object.entries(controllers);
|
|
if (entries.length === 0) {
|
|
const opt = document.createElement('option');
|
|
opt.value = 'HC1'; opt.textContent = 'HC1';
|
|
sel.appendChild(opt);
|
|
return;
|
|
}
|
|
entries.forEach(([id, connected]) => {
|
|
const opt = document.createElement('option');
|
|
opt.value = id; opt.textContent = `${id} — ${connected ? 'Connected' : 'Disconnected'}`;
|
|
sel.appendChild(opt);
|
|
});
|
|
}
|
|
|
|
async function wrWriteTag() {
|
|
const controllerId = document.getElementById('w-ctrl').value || 'HC1';
|
|
const tagName = document.getElementById('wr-nodeid').value.trim();
|
|
const value = parseFloat(document.getElementById('wr-value').value);
|
|
if (!tagName) return log('wr-log', [{ c: 'err', t: '❌ 태그명을 입력하세요.' }]);
|
|
if (isNaN(value)) return log('wr-log', [{ c: 'err', t: '❌ 유효한 숫자를 입력하세요.' }]);
|
|
|
|
try {
|
|
const d = await api('POST', '/api/gateway/write', { controllerId, tagName, value });
|
|
log('wr-log', [
|
|
{ c: d.success ? 'ok' : 'err', t: (d.success ? '✅ ' : '❌ ') + 'Write ' + esc(tagName) + ' = ' + value + (d.error ? ' → ' + esc(d.error) : '') },
|
|
]);
|
|
} catch (e) {
|
|
log('wr-log', [{ c: 'err', t: '❌ ' + e.message }]);
|
|
}
|
|
}
|
|
|
|
async function wrSetMode() {
|
|
const controllerId = document.getElementById('w-ctrl').value || 'HC1';
|
|
const tagName = document.getElementById('wr-mode-nodeid').value.trim();
|
|
const mode = document.getElementById('wr-mode').value;
|
|
if (!tagName) return log('wr-log', [{ c: 'err', t: '❌ 태그명을 입력하세요.' }]);
|
|
|
|
// 모드별 R/W 태그 매핑 (register-map의 .MD(읽기전용)이 아님)
|
|
// Auto/Manual → AutoManState, LSP/RSP → RemLocSPState, SP1/SP2 → SP_SelectState, Tune → TuneSetState
|
|
const modeMap = { '0': 'AutoManState', '1': 'AutoManState', '2': 'RemLocSPState', '3': 'SP_SelectState', '4': 'TuneSetState' };
|
|
const valueMap = { '0': 0, '1': 1, '2': 1, '3': 1, '4': 1 }; // Auto=1, RSP=1, RSP/LSP=1, Tune=1
|
|
const modeTag = modeMap[mode] ?? 'AutoManState';
|
|
const writeValue = mode === '0' ? 0 : 1; // 0=Manual/LSP, 1=Auto/RSP
|
|
|
|
try {
|
|
const d = await api('POST', '/api/gateway/write', { controllerId, tagName: tagName + '.' + modeTag, value: writeValue });
|
|
log('wr-log', [
|
|
{ c: d.success ? 'ok' : 'err', t: (d.success ? '✅ ' : '❌ ') + 'Mode ' + esc(tagName) + ' → ' + mode + ' (' + modeTag + ')' + (d.error ? ' → ' + esc(d.error) : '') },
|
|
]);
|
|
} catch (e) {
|
|
log('wr-log', [{ c: 'err', t: '❌ ' + e.message }]);
|
|
}
|
|
}
|
|
|
|
async function wrControlOp() {
|
|
const controllerId = document.getElementById('w-ctrl').value || 'HC1';
|
|
const tagName = document.getElementById('wr-ctrl-tag').value.trim();
|
|
const opValue = parseFloat(document.getElementById('wr-ctrl-op').value);
|
|
const restoreAuto = document.getElementById('wr-ctrl-restore').checked;
|
|
if (!tagName) return log('wr-log', [{ c: 'err', t: '❌ 태그명을 입력하세요.' }]);
|
|
if (isNaN(opValue)) return log('wr-log', [{ c: 'err', t: '❌ 유효한 OP 값을 입력하세요.' }]);
|
|
|
|
try {
|
|
const d = await api('POST', '/api/gateway/write', { controllerId, tagName, value: opValue });
|
|
log('wr-log', [
|
|
{ c: d.success ? 'ok' : 'err', t: (d.success ? '✅ ' : '❌ ') + '통합 제어 ' + esc(tagName) + ' OP=' + opValue + (d.error ? ' — ' + esc(d.error) : '') },
|
|
]);
|
|
} catch (e) {
|
|
log('wr-log', [{ c: 'err', t: '❌ ' + e.message }]);
|
|
}
|
|
}
|
|
|
|
async function wrReadTag() {
|
|
const tagName = document.getElementById('wr-read-nodeid').value.trim().toLowerCase();
|
|
if (!tagName) return;
|
|
|
|
try {
|
|
const pts = await api('GET', '/api/realtime/points');
|
|
const point = pts.find(p => (p.TagName || '').toLowerCase() === tagName);
|
|
const box = document.getElementById('wr-read-result');
|
|
if (point) {
|
|
box.innerHTML = `
|
|
<div class="kv"><span class="kk">Tag Name</span><span class="kv2">${esc(point.TagName)}</span></div>
|
|
<div class="kv"><span class="kk">Value</span><span class="kv2 ok">${esc(point.LiveValue)}</span></div>
|
|
<div class="kv"><span class="kk">Timestamp</span><span class="kv2">${point.Timestamp ? new Date(point.Timestamp).toLocaleString('ko-KR') : '-'}</span></div>
|
|
`;
|
|
} else {
|
|
box.innerHTML = `<div class="kv"><span class="kk">Error</span><span class="kv2 err">태그를 찾을 수 없음</span></div>`;
|
|
}
|
|
} catch (e) {
|
|
document.getElementById('wr-read-result').innerHTML = `<div class="kv"><span class="kk">Error</span><span class="kv2 err">${esc(e.message)}</span></div>`;
|
|
}
|
|
}
|