feat: Add real-time IO/interlock updates, HW status display, and history page

- Implement real-time IO value updates via IOValueChanged event
- Add interlock toggle and real-time interlock change events
- Fix ToggleLight to check return value of DIO.SetRoomLight
- Add HW status display in Footer matching WinForms HWState
- Implement GetHWStatus API and 250ms broadcast interval
- Create HistoryPage React component for work history viewing
- Add GetHistoryData API for database queries
- Add date range selection, search, filter, and CSV export
- Add History button in Header navigation
- Add PickerMoveDialog component for manage operations
- Fix DataSet column names (idx, PRNATTACH, PRNVALID, qtymax)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
2025-11-27 00:14:47 +09:00
parent bb67d04d90
commit 3bd35ad852
19 changed files with 2917 additions and 81 deletions

View File

@@ -6,6 +6,7 @@ using System.IO;
using System.Linq;
using System.Collections.Generic;
using AR;
using System.Threading.Tasks;
namespace Project.WebUI
{
@@ -1145,7 +1146,14 @@ namespace Project.WebUI
}
var cur = DIO.GetIOOutput(AR.eDOName.ROOMLIGHT);
DIO.SetRoomLight(!cur, true);
var success = DIO.SetRoomLight(!cur, true);
if (success == false)
{
var response = new { success = false, message = "Failed to control room light" };
return JsonConvert.SerializeObject(response);
}
PUB.log.Add($"User Request: Room Light {(!cur ? "ON" : "OFF")}", false);
var response2 = new { success = true, message = $"Light turned {(!cur ? "ON" : "OFF")}" };
return JsonConvert.SerializeObject(response2);
@@ -1173,7 +1181,7 @@ namespace Project.WebUI
var selectedPrinter = printer.ToLower() == "left" ? PUB.PrinterL : PUB.PrinterR;
// Create ZPL
string zpl = selectedPrinter.makeZPL_210908(new AR.Class.Reel
string zpl = selectedPrinter.makeZPL_210908(new Class.Reel
{
SID = sid,
venderLot = venderLot,
@@ -1290,10 +1298,11 @@ namespace Project.WebUI
return JsonConvert.SerializeObject(response);
}
// The manage dialog (fPickerMove) cannot be opened from web UI
// This would require implementing a separate picker management page
// Set flag to indicate picker move dialog is open
PUB.flag.set(eVarBool.FG_MOVE_PICKER, true, "PICKERMOVE_WEB");
PUB.log.Add("User Request: Manage (Web UI)", false);
var response2 = new { success = false, message = "Manage is not available in Web UI. Please use the main program." };
var response2 = new { success = true, message = "Manage dialog opened" };
return JsonConvert.SerializeObject(response2);
}
catch (Exception ex)
@@ -1304,6 +1313,29 @@ namespace Project.WebUI
}
}
public string CloseManage()
{
try
{
// Clear the flag
PUB.flag.set(eVarBool.FG_MOVE_PICKER, false, "PICKERMOVE_WEB");
// Check if auto-init is needed: home not set AND picker is in center position
bool shouldAutoInit = PUB.mot.HasHomeSetOff == true && DIO.GetIOInput(eDIName.PICKER_SAFE);
PUB.log.Add($"User Request: Close Manage (Web UI), shouldAutoInit={shouldAutoInit}", false);
var response = new { shouldAutoInit = shouldAutoInit };
return JsonConvert.SerializeObject(response);
}
catch (Exception ex)
{
Console.WriteLine($"[ERROR] Failed to close manage: {ex.Message}");
var response = new { shouldAutoInit = false };
return JsonConvert.SerializeObject(response);
}
}
public string OpenManual()
{
try
@@ -1433,5 +1465,837 @@ namespace Project.WebUI
return JsonConvert.SerializeObject(response);
}
}
// ===== PICKER MOVE METHODS =====
private static bool _manPosL = false;
private static bool _manPosR = false;
public string GetPickerStatus()
{
try
{
// X축 피커 이동 가능 여부 체크
bool xEnabled = false;
if (PUB.mot.IsHomeSet((int)eAxis.PZ_PICK) == false)
{
if (PUB.mot.IsOrg((int)eAxis.PZ_PICK) || PUB.mot.IsLimitN((int)eAxis.PZ_PICK))
xEnabled = true;
}
else
{
var PosZ = MOT.GetPZPos(ePZLoc.READY);
var OffZ = MOT.getPositionOffset(PosZ);
xEnabled = OffZ < 1;
}
var doorsafef = DIO.isSaftyDoorF();
var managementEnabled = PUB.mot.HasHomeSetOff == false && doorsafef == true;
var status = new
{
xEnabled = xEnabled,
zEnabled = xEnabled, // Z jog uses same condition
pickerSafe = DIO.GetIOInput(eDIName.PICKER_SAFE),
managementEnabled = managementEnabled,
manPosL = _manPosL,
manPosR = _manPosR
};
return JsonConvert.SerializeObject(status);
}
catch (Exception ex)
{
Console.WriteLine($"[ERROR] Failed to get picker status: {ex.Message}");
return JsonConvert.SerializeObject(new { xEnabled = false, zEnabled = false, pickerSafe = false, managementEnabled = false, manPosL = false, manPosR = false });
}
}
private bool CheckPickerSafety(out string errorMessage)
{
errorMessage = null;
if (DIO.isSaftyDoorF() == false)
{
errorMessage = "Front door is open";
return false;
}
if (PUB.mot.HasHomeSetOff)
{
errorMessage = "Motion home operation is not completed";
return false;
}
return true;
}
private bool CheckZAxisReady(out string errorMessage)
{
errorMessage = null;
var z = MOT.GetPZPos(ePZLoc.READY);
var zpos = MOT.getPositionOffset(z);
if (zpos >= 0.5)
{
errorMessage = "Raise the Z axis and try again";
return false;
}
return true;
}
public string PickerMoveLeft()
{
try
{
if (!CheckPickerSafety(out string safetyError))
return JsonConvert.SerializeObject(new { success = false, message = safetyError });
if (!CheckZAxisReady(out string zError))
return JsonConvert.SerializeObject(new { success = false, message = zError });
var m1 = MOT.GetLMPos(eLMLoc.READY);
if (MOT.getPositionMatch(m1) == false)
return JsonConvert.SerializeObject(new { success = false, message = "Printer attachment is not in ready position.\nCannot move as collision may occur" });
var p1 = MOT.GetPXPos(ePXLoc.PICKOFFL);
MOT.Move(eAxis.PX_PICK, p1.Position, 250, p1.Acc, false, false, false);
return JsonConvert.SerializeObject(new { success = true, message = "Moving to left position" });
}
catch (Exception ex)
{
return JsonConvert.SerializeObject(new { success = false, message = ex.Message });
}
}
public string PickerMoveLeftWait()
{
try
{
if (!CheckPickerSafety(out string safetyError))
return JsonConvert.SerializeObject(new { success = false, message = safetyError });
if (!CheckZAxisReady(out string zError))
return JsonConvert.SerializeObject(new { success = false, message = zError });
var m1 = MOT.GetLMPos(eLMLoc.READY);
if (MOT.getPositionMatch(m1) == false)
return JsonConvert.SerializeObject(new { success = false, message = "Printer attachment is not in ready position.\nCannot move as collision may occur" });
var p1 = MOT.GetPXPos(ePXLoc.READYL);
MOT.Move(eAxis.PX_PICK, p1.Position, 250, p1.Acc, false, false, false);
return JsonConvert.SerializeObject(new { success = true, message = "Moving to left wait position" });
}
catch (Exception ex)
{
return JsonConvert.SerializeObject(new { success = false, message = ex.Message });
}
}
public string PickerMoveCenter()
{
try
{
if (!CheckPickerSafety(out string safetyError))
return JsonConvert.SerializeObject(new { success = false, message = safetyError });
if (!CheckZAxisReady(out string zError))
return JsonConvert.SerializeObject(new { success = false, message = zError });
var p1 = MOT.GetPXPos(ePXLoc.PICKON);
MOT.Move(eAxis.PX_PICK, p1.Position, 250, p1.Acc, false, false, false);
return JsonConvert.SerializeObject(new { success = true, message = "Moving to center position" });
}
catch (Exception ex)
{
return JsonConvert.SerializeObject(new { success = false, message = ex.Message });
}
}
public string PickerMoveRightWait()
{
try
{
if (!CheckPickerSafety(out string safetyError))
return JsonConvert.SerializeObject(new { success = false, message = safetyError });
if (!CheckZAxisReady(out string zError))
return JsonConvert.SerializeObject(new { success = false, message = zError });
var m1 = MOT.GetRMPos(eRMLoc.READY);
if (MOT.getPositionMatch(m1) == false)
return JsonConvert.SerializeObject(new { success = false, message = "Printer attachment is not in ready position.\nCannot move as collision may occur" });
var p1 = MOT.GetPXPos(ePXLoc.READYR);
MOT.Move(eAxis.PX_PICK, p1.Position, 250, p1.Acc, false, false, false);
return JsonConvert.SerializeObject(new { success = true, message = "Moving to right wait position" });
}
catch (Exception ex)
{
return JsonConvert.SerializeObject(new { success = false, message = ex.Message });
}
}
public string PickerMoveRight()
{
try
{
if (!CheckPickerSafety(out string safetyError))
return JsonConvert.SerializeObject(new { success = false, message = safetyError });
if (!CheckZAxisReady(out string zError))
return JsonConvert.SerializeObject(new { success = false, message = zError });
var m1 = MOT.GetRMPos(eRMLoc.READY);
if (MOT.getPositionMatch(m1) == false)
return JsonConvert.SerializeObject(new { success = false, message = "Printer attachment is not in ready position.\nCannot move as collision may occur" });
var p1 = MOT.GetPXPos(ePXLoc.PICKOFFR);
MOT.Move(eAxis.PX_PICK, p1.Position, 250, p1.Acc, false, false, false);
return JsonConvert.SerializeObject(new { success = true, message = "Moving to right position" });
}
catch (Exception ex)
{
return JsonConvert.SerializeObject(new { success = false, message = ex.Message });
}
}
public string PickerJogStart(string direction)
{
try
{
switch (direction)
{
case "up":
PUB.mot.JOG((int)eAxis.PZ_PICK, arDev.MOT.MOTION_DIRECTION.Negative, AR.SETTING.Data.JOG_Speed, AR.SETTING.Data.JOG_Acc);
break;
case "down":
PUB.mot.JOG((int)eAxis.PZ_PICK, arDev.MOT.MOTION_DIRECTION.Positive, AR.SETTING.Data.JOG_Speed, AR.SETTING.Data.JOG_Acc);
break;
case "left":
PUB.mot.JOG((int)eAxis.PX_PICK, arDev.MOT.MOTION_DIRECTION.Negative, AR.SETTING.Data.JOG_Speed, AR.SETTING.Data.JOG_Acc);
break;
case "right":
PUB.mot.JOG((int)eAxis.PX_PICK, arDev.MOT.MOTION_DIRECTION.Positive, AR.SETTING.Data.JOG_Speed, AR.SETTING.Data.JOG_Acc);
break;
}
return JsonConvert.SerializeObject(new { success = true, message = $"Jog {direction} started" });
}
catch (Exception ex)
{
return JsonConvert.SerializeObject(new { success = false, message = ex.Message });
}
}
public string PickerJogStop()
{
try
{
PUB.mot.MoveStop("pmove_web", (short)eAxis.PX_PICK);
PUB.mot.MoveStop("pmove_web", (short)eAxis.PZ_PICK);
return JsonConvert.SerializeObject(new { success = true, message = "Jog stopped" });
}
catch (Exception ex)
{
return JsonConvert.SerializeObject(new { success = false, message = ex.Message });
}
}
public string PickerStop()
{
try
{
PUB.mot.MoveStop("pmove_web", (int)eAxis.PX_PICK);
return JsonConvert.SerializeObject(new { success = true, message = "Picker stopped" });
}
catch (Exception ex)
{
return JsonConvert.SerializeObject(new { success = false, message = ex.Message });
}
}
public string CancelVisionValidation(string side)
{
try
{
if (side == "left")
{
PUB.flag.set(eVarBool.FG_PRC_VISIONL, false, "CANCEL_WEB");
PUB.flag.set(eVarBool.FG_PORTL_ITEMON, false, "CANCEL_WEB");
PUB.log.Add($"LEFT-QR verification cancelled JGUID={PUB.Result.ItemDataL.guid}");
}
else
{
PUB.flag.set(eVarBool.FG_PRC_VISIONR, false, "CANCEL_WEB");
PUB.flag.set(eVarBool.FG_PORTR_ITEMON, false, "CANCEL_WEB");
PUB.log.Add($"RIGHT-QR verification cancelled JGUID={PUB.Result.ItemDataR.guid}");
}
return JsonConvert.SerializeObject(new { success = true, message = $"{side.ToUpper()}-QR verification cancelled" });
}
catch (Exception ex)
{
return JsonConvert.SerializeObject(new { success = false, message = ex.Message });
}
}
public string PickerManagePosition(string side)
{
try
{
if (PUB.sm.Step != eSMStep.IDLE)
return JsonConvert.SerializeObject(new { success = false, message = "Available only in standby state" });
var Xpos = DIO.GetIOInput(eDIName.PICKER_SAFE);
if (Xpos == false)
return JsonConvert.SerializeObject(new { success = false, message = "Available only when picker is in center position" });
int vidx = side == "left" ? 0 : 2;
Task.Run(() =>
{
DateTime dt;
if (vidx == 0)
{
while (DIO.GetIOInput(eDIName.L_CYLUP) == false)
{
var dorlt = DIO.checkDigitalO(eDOName.L_CYLDN, new TimeSpan(1), false);
if (dorlt == eNormalResult.False)
System.Threading.Thread.Sleep(100);
else if (dorlt == eNormalResult.Error)
{
PUB.log.AddE("l_cylup check error");
return;
}
}
var zPos = MOT.GetLZPos(eLZLoc.READY).Clone();
zPos.Speed = 100;
MOT.Move(zPos);
dt = DateTime.Now;
while (MOT.getPositionMatch(zPos) == false)
{
if ((DateTime.Now - dt).TotalSeconds > 30) break;
System.Threading.Thread.Sleep(10);
}
var mPos = MOT.GetLMPos(eLMLoc.PRINTL07).Clone();
mPos.Speed = 100;
MOT.Move(mPos);
dt = DateTime.Now;
while (MOT.getPositionMatch(mPos) == false)
{
if ((DateTime.Now - dt).TotalSeconds > 30) break;
System.Threading.Thread.Sleep(10);
}
var zPos2 = MOT.GetLZPos(eLZLoc.PICKOFF);
var tPos = (zPos2.Position / 2f);
MOT.Move(eAxis.PL_UPDN, tPos, 100, zPos.Acc);
_manPosL = true;
}
else
{
while (DIO.GetIOInput(eDIName.R_CYLUP) == false)
{
var dorlt = DIO.checkDigitalO(eDOName.R_CYLDN, new TimeSpan(1), false);
if (dorlt == eNormalResult.False)
System.Threading.Thread.Sleep(100);
else if (dorlt == eNormalResult.Error)
{
PUB.log.AddE("r_cylup check error");
return;
}
}
var zPos = MOT.GetRZPos(eRZLoc.READY).Clone();
zPos.Speed = 100;
MOT.Move(zPos);
dt = DateTime.Now;
while (MOT.getPositionMatch(zPos) == false)
{
if ((DateTime.Now - dt).TotalSeconds > 30) break;
System.Threading.Thread.Sleep(10);
}
var mPos = MOT.GetRMPos(eRMLoc.PRINTL07).Clone();
mPos.Speed = 100;
MOT.Move(mPos);
dt = DateTime.Now;
while (MOT.getPositionMatch(mPos) == false)
{
if ((DateTime.Now - dt).TotalSeconds > 30) break;
System.Threading.Thread.Sleep(10);
}
var zPos2 = MOT.GetRZPos(eRZLoc.PICKOFF);
var tPos = (zPos2.Position / 2f);
MOT.Move(eAxis.PR_UPDN, tPos, 100, zPos.Acc);
_manPosR = true;
}
});
return JsonConvert.SerializeObject(new { success = true, message = $"Moving to {side} management position" });
}
catch (Exception ex)
{
return JsonConvert.SerializeObject(new { success = false, message = ex.Message });
}
}
public string PickerManageReturn()
{
try
{
var Xpos = DIO.GetIOInput(eDIName.PICKER_SAFE);
if (Xpos == false)
return JsonConvert.SerializeObject(new { success = false, message = "Available only when picker is in center position" });
// Recover both positions
Task.Run(() => PosRecover(0));
Task.Run(() => PosRecover(2));
return JsonConvert.SerializeObject(new { success = true, message = "Returning to ready position" });
}
catch (Exception ex)
{
return JsonConvert.SerializeObject(new { success = false, message = ex.Message });
}
}
private void PosRecover(int vidx)
{
DateTime dt;
if (vidx == 0)
{
while (DIO.GetIOInput(eDIName.L_CYLUP) == false)
{
var dorlt = DIO.checkDigitalO(eDOName.L_CYLDN, new TimeSpan(1), false);
if (dorlt == eNormalResult.False)
System.Threading.Thread.Sleep(100);
else if (dorlt == eNormalResult.Error)
{
PUB.log.AddE("l_cylup check error");
return;
}
}
var zPos = MOT.GetLZPos(eLZLoc.READY).Clone();
zPos.Speed = 100;
MOT.Move(zPos);
dt = DateTime.Now;
while (MOT.getPositionMatch(zPos) == false)
{
if ((DateTime.Now - dt).TotalSeconds > 30) break;
System.Threading.Thread.Sleep(10);
}
var mPos = MOT.GetLMPos(eLMLoc.READY).Clone();
mPos.Speed = 100;
MOT.Move(mPos);
dt = DateTime.Now;
while (MOT.getPositionMatch(mPos) == false)
{
if ((DateTime.Now - dt).TotalSeconds > 30) break;
System.Threading.Thread.Sleep(10);
}
_manPosL = false;
}
else
{
while (DIO.GetIOInput(eDIName.R_CYLUP) == false)
{
var dorlt = DIO.checkDigitalO(eDOName.R_CYLDN, new TimeSpan(1), false);
if (dorlt == eNormalResult.False)
System.Threading.Thread.Sleep(100);
else if (dorlt == eNormalResult.Error)
{
PUB.log.AddE("R_cylup check error");
return;
}
}
var zPos = MOT.GetRZPos(eRZLoc.READY).Clone();
zPos.Speed = 100;
MOT.Move(zPos);
dt = DateTime.Now;
while (MOT.getPositionMatch(zPos) == false)
{
if ((DateTime.Now - dt).TotalSeconds > 30) break;
System.Threading.Thread.Sleep(10);
}
var mPos = MOT.GetRMPos(eRMLoc.READY).Clone();
mPos.Speed = 100;
MOT.Move(mPos);
dt = DateTime.Now;
while (MOT.getPositionMatch(mPos) == false)
{
if ((DateTime.Now - dt).TotalSeconds > 30) break;
System.Threading.Thread.Sleep(10);
}
_manPosR = false;
}
}
public string PickerZHome()
{
try
{
MOT.Home("Management_Web", eAxis.PZ_PICK, false);
return JsonConvert.SerializeObject(new { success = true, message = "Z-axis home search started" });
}
catch (Exception ex)
{
return JsonConvert.SerializeObject(new { success = false, message = ex.Message });
}
}
public string PickerZZero()
{
try
{
if (PUB.mot.IsHomeSet((int)eAxis.PZ_PICK) == false)
return JsonConvert.SerializeObject(new { success = false, message = "Z home operation is not completed. Please perform HOME first" });
MOT.Move(eAxis.PZ_PICK, 0, 500, 1000, false, false, false);
return JsonConvert.SerializeObject(new { success = true, message = "Moving Z-axis to zero" });
}
catch (Exception ex)
{
return JsonConvert.SerializeObject(new { success = false, message = ex.Message });
}
}
public string PickerTestPrint(string side)
{
try
{
if (side == "left")
{
PUB.PrinterL.TestPrint(AR.SETTING.Data.DrawOutbox, "", "");
PUB.log.Add("Temporary print L:" + PUB.PrinterL.LastPrintZPL);
}
else
{
PUB.PrinterR.TestPrint(AR.SETTING.Data.DrawOutbox, "", "");
PUB.log.Add("Temporary print R:" + PUB.PrinterR.LastPrintZPL);
}
return JsonConvert.SerializeObject(new { success = true, message = $"{side.ToUpper()} test print completed" });
}
catch (Exception ex)
{
return JsonConvert.SerializeObject(new { success = false, message = ex.Message });
}
}
public string CanCloseManage()
{
try
{
if (_manPosL || _manPosR)
{
return JsonConvert.SerializeObject(new { canClose = false, message = "Printer motion is in management position.\nReturn to position and try again" });
}
return JsonConvert.SerializeObject(new { canClose = true, message = "" });
}
catch (Exception ex)
{
return JsonConvert.SerializeObject(new { canClose = false, message = ex.Message });
}
}
// ===== INTERLOCK METHODS =====
/// <summary>
/// 인터락 토글 (DIOMonitor.cs의 gvILXF_ItemClick과 동일)
/// </summary>
public string ToggleInterlock(int axisIndex, int lockIndex)
{
try
{
if (axisIndex < 0 || axisIndex >= PUB.iLock.Length)
{
return JsonConvert.SerializeObject(new { success = false, message = "Invalid axis index" });
}
var curValue = PUB.iLock[axisIndex].get(lockIndex);
PUB.iLock[axisIndex].set(lockIndex, !curValue, "IOMONITOR_WEB");
PUB.log.Add($"[Web] Interlock toggle: axis={axisIndex}, lock={lockIndex}, newVal={!curValue}");
return JsonConvert.SerializeObject(new { success = true, newState = !curValue });
}
catch (Exception ex)
{
Console.WriteLine($"[ERROR] Failed to toggle interlock: {ex.Message}");
return JsonConvert.SerializeObject(new { success = false, message = ex.Message });
}
}
// ===== HISTORY DATA =====
/// <summary>
/// 작업 이력 데이터 조회 (fHistory.cs의 refreshList와 동일)
/// </summary>
public string GetHistoryData(string startDate, string endDate, string search)
{
try
{
var results = new List<object>();
using (var ta = new DataSet1TableAdapters.K4EE_Component_Reel_ResultTableAdapter())
{
var ds = new DataSet1();
// 검색어 처리
var searchPattern = string.IsNullOrEmpty(search) ? "%" : "%" + search + "%";
// DB에서 조회
ta.FillBySearch(ds.K4EE_Component_Reel_Result, AR.SETTING.Data.McName, startDate, endDate, searchPattern);
foreach (DataSet1.K4EE_Component_Reel_ResultRow row in ds.K4EE_Component_Reel_Result.Rows)
{
results.Add(new
{
idx = row.idx,
jtype = row.IsJTYPENull() ? "" : row.JTYPE,
rid = row.IsRIDNull() ? "" : row.RID,
sid = row.IsSIDNull() ? "" : row.SID,
qty = row.IsQTYNull() ? 0 : row.QTY,
vname = row.IsVNAMENull() ? "" : row.VNAME,
vlot = row.IsVLOTNull() ? "" : row.VLOT,
loc = row.IsLOCNull() ? "" : row.LOC,
qr = row.IsQRNull() ? "" : row.QR,
stime = row.STIME.ToString("yyyy-MM-dd HH:mm:ss"),
etime = row.IsETIMENull() ? "" : row.ETIME.ToString("yyyy-MM-dd HH:mm:ss"),
prnattach = !row.IsPRNATTACHNull() && row.PRNATTACH,
prnvalid = !row.IsPRNVALIDNull() && row.PRNVALID,
rid0 = row.IsRID0Null() ? "" : row.RID0,
sid0 = row.IsSID0Null() ? "" : row.SID0,
qtymax = row.IsqtymaxNull() ? 0 : row.qtymax
});
}
}
return JsonConvert.SerializeObject(new {
success = true,
data = results,
mcName = AR.SETTING.Data.McName
});
}
catch (Exception ex)
{
Console.WriteLine($"[ERROR] Failed to get history data: {ex.Message}");
return JsonConvert.SerializeObject(new { success = false, message = ex.Message, data = new List<object>() });
}
}
// ===== HARDWARE STATUS METHODS =====
/// <summary>
/// H/W 상태 조회 (_Interval_250ms.cs의 HWState 업데이트 로직과 동일)
/// </summary>
public string GetHWStatus()
{
try
{
var hwList = new List<object>();
// 1. KeyenceF (BCD Front) - 바코드 리더
if (PUB.keyenceF != null)
{
hwList.Add(new
{
name = "BCD-F",
title = PUB.keyenceF.IsConnect ? (PUB.keyenceF.IsTriggerOn ? "TRIG" : "ON") : "OFF",
status = PUB.keyenceF.IsConnect ? (PUB.keyenceF.IsTriggerOn ? 2 : 1) : 3
});
}
else
{
hwList.Add(new { name = "BCD-F", title = "SET", status = 0 });
}
// 2. KeyenceR (BCD Rear) - 바코드 리더
if (PUB.keyenceR != null)
{
hwList.Add(new
{
name = "BCD-R",
title = PUB.keyenceR.IsConnect ? (PUB.keyenceR.IsTriggerOn ? "TRIG" : "ON") : "OFF",
status = PUB.keyenceR.IsConnect ? (PUB.keyenceR.IsTriggerOn ? 2 : 1) : 3
});
}
else
{
hwList.Add(new { name = "BCD-R", title = "SET", status = 0 });
}
// 3. Vision WebSocket Left
if (PUB.wsL != null)
{
hwList.Add(new
{
name = "VIS-L",
title = PUB.wsL.Connected ? "ON" : "OFF",
status = PUB.wsL.Connected ? 1 : 3
});
}
else
{
hwList.Add(new { name = "VIS-L", title = "SET", status = 0 });
}
// 4. Vision WebSocket Right
if (PUB.wsR != null)
{
hwList.Add(new
{
name = "VIS-R",
title = PUB.wsR.Connected ? "ON" : "OFF",
status = PUB.wsR.Connected ? 1 : 3
});
}
else
{
hwList.Add(new { name = "VIS-R", title = "SET", status = 0 });
}
// 5. BarcodeFix (Fixed Barcode Reader)
hwList.Add(new
{
name = "FIX",
title = PUB.BarcodeFix.IsOpen() ? AR.SETTING.Data.Barcode_Port : "OFF",
status = PUB.BarcodeFix.IsOpen() ? 1 : 3
});
// 6. PrinterL
if (PUB.PrinterL != null)
{
hwList.Add(new
{
name = "PRT-L",
title = PUB.PrinterL.IsOpen ? AR.SETTING.Data.PrintL_Port : "OFF",
status = PUB.PrinterL.IsOpen ? 1 : 3
});
}
else
{
hwList.Add(new { name = "PRT-L", title = "SET", status = 0 });
}
// 7. PrinterR
if (PUB.PrinterR != null)
{
hwList.Add(new
{
name = "PRT-R",
title = PUB.PrinterR.IsOpen ? AR.SETTING.Data.PrintR_Port : "OFF",
status = PUB.PrinterR.IsOpen ? 1 : 3
});
}
else
{
hwList.Add(new { name = "PRT-R", title = "SET", status = 0 });
}
// 8. PLC
if (PUB.plc != null)
{
hwList.Add(new
{
name = "PLC",
title = PUB.plc.Init ? AR.SETTING.Data.swplc_name : "OFF",
status = PUB.plc.Init ? 1 : 3
});
}
else
{
hwList.Add(new { name = "PLC", title = "SET", status = 0 });
}
// 9. Motion
hwList.Add(new
{
name = "MOT",
title = PUB.mot?.IsInit == true ? "ON" : "OFF",
status = PUB.mot?.IsInit == true ? 1 : 3
});
return JsonConvert.SerializeObject(hwList);
}
catch (Exception ex)
{
Console.WriteLine($"[ERROR] Failed to get HW status: {ex.Message}");
return JsonConvert.SerializeObject(new List<object>());
}
}
/// <summary>
/// 인터락 목록 조회 (실시간 값 포함)
/// </summary>
public string GetInterlockList()
{
try
{
var interlocks = new List<object>();
for (int i = 0; i < PUB.iLock.Length; i++)
{
var axisName = ((AR.eAxis)i).ToString();
var nonAxis = false;
if (i >= 7)
{
axisName = PUB.iLock[i].Tag.ToString();
nonAxis = true;
}
string[] ilockNames;
if (i == 7) ilockNames = Enum.GetNames(typeof(eILockPRL));
else if (i == 8) ilockNames = Enum.GetNames(typeof(eILockPRR));
else if (i == 9) ilockNames = Enum.GetNames(typeof(eILockVS0));
else if (i == 10) ilockNames = Enum.GetNames(typeof(eILockVS1));
else if (i == 11) ilockNames = Enum.GetNames(typeof(eILockVS2));
else if (i == 12 || i == 13) ilockNames = Enum.GetNames(typeof(eILockCV));
else ilockNames = Enum.GetNames(typeof(eILock));
var lockValues = new List<object>();
for (int j = 0; j < ilockNames.Length && j < 64; j++)
{
bool state = PUB.iLock[i].get(j);
lockValues.Add(new
{
id = j,
name = ilockNames[j],
state = state
});
}
interlocks.Add(new
{
axisIndex = i,
axisName = axisName,
nonAxis = nonAxis,
locks = lockValues,
hexValue = PUB.iLock[i].Value().HexString()
});
}
return JsonConvert.SerializeObject(interlocks);
}
catch (Exception ex)
{
Console.WriteLine($"[ERROR] Failed to get interlock list: {ex.Message}");
return JsonConvert.SerializeObject(new List<object>());
}
}
}
}

View File

@@ -334,6 +334,13 @@ namespace Project.WebUI
var response = new { type = "MANAGE_RESULT", data = Newtonsoft.Json.JsonConvert.DeserializeObject(resultJson) };
await Send(socket, Newtonsoft.Json.JsonConvert.SerializeObject(response));
}
else if (type == "CLOSE_MANAGE")
{
var bridge = new MachineBridge(_mainForm);
string resultJson = bridge.CloseManage();
var response = new { type = "CLOSE_MANAGE_RESULT", data = Newtonsoft.Json.JsonConvert.DeserializeObject(resultJson) };
await Send(socket, Newtonsoft.Json.JsonConvert.SerializeObject(response));
}
else if (type == "OPEN_MANUAL")
{
var bridge = new MachineBridge(_mainForm);
@@ -376,6 +383,151 @@ namespace Project.WebUI
var response = new { type = "FOLDER_RESULT", data = Newtonsoft.Json.JsonConvert.DeserializeObject(resultJson) };
await Send(socket, Newtonsoft.Json.JsonConvert.SerializeObject(response));
}
// ===== PICKER MOVE HANDLERS =====
else if (type == "GET_PICKER_STATUS")
{
var bridge = new MachineBridge(_mainForm);
string resultJson = bridge.GetPickerStatus();
var response = new { type = "PICKER_STATUS", data = Newtonsoft.Json.JsonConvert.DeserializeObject(resultJson) };
await Send(socket, Newtonsoft.Json.JsonConvert.SerializeObject(response));
}
else if (type == "PICKER_MOVE_LEFT")
{
var bridge = new MachineBridge(_mainForm);
string resultJson = bridge.PickerMoveLeft();
var response = new { type = "PICKER_RESULT", data = Newtonsoft.Json.JsonConvert.DeserializeObject(resultJson) };
await Send(socket, Newtonsoft.Json.JsonConvert.SerializeObject(response));
}
else if (type == "PICKER_MOVE_LEFT_WAIT")
{
var bridge = new MachineBridge(_mainForm);
string resultJson = bridge.PickerMoveLeftWait();
var response = new { type = "PICKER_RESULT", data = Newtonsoft.Json.JsonConvert.DeserializeObject(resultJson) };
await Send(socket, Newtonsoft.Json.JsonConvert.SerializeObject(response));
}
else if (type == "PICKER_MOVE_CENTER")
{
var bridge = new MachineBridge(_mainForm);
string resultJson = bridge.PickerMoveCenter();
var response = new { type = "PICKER_RESULT", data = Newtonsoft.Json.JsonConvert.DeserializeObject(resultJson) };
await Send(socket, Newtonsoft.Json.JsonConvert.SerializeObject(response));
}
else if (type == "PICKER_MOVE_RIGHT_WAIT")
{
var bridge = new MachineBridge(_mainForm);
string resultJson = bridge.PickerMoveRightWait();
var response = new { type = "PICKER_RESULT", data = Newtonsoft.Json.JsonConvert.DeserializeObject(resultJson) };
await Send(socket, Newtonsoft.Json.JsonConvert.SerializeObject(response));
}
else if (type == "PICKER_MOVE_RIGHT")
{
var bridge = new MachineBridge(_mainForm);
string resultJson = bridge.PickerMoveRight();
var response = new { type = "PICKER_RESULT", data = Newtonsoft.Json.JsonConvert.DeserializeObject(resultJson) };
await Send(socket, Newtonsoft.Json.JsonConvert.SerializeObject(response));
}
else if (type == "PICKER_JOG_START")
{
var bridge = new MachineBridge(_mainForm);
string direction = json["direction"]?.ToString() ?? "";
string resultJson = bridge.PickerJogStart(direction);
var response = new { type = "PICKER_JOG_RESULT", data = Newtonsoft.Json.JsonConvert.DeserializeObject(resultJson) };
await Send(socket, Newtonsoft.Json.JsonConvert.SerializeObject(response));
}
else if (type == "PICKER_JOG_STOP")
{
var bridge = new MachineBridge(_mainForm);
string resultJson = bridge.PickerJogStop();
var response = new { type = "PICKER_JOG_RESULT", data = Newtonsoft.Json.JsonConvert.DeserializeObject(resultJson) };
await Send(socket, Newtonsoft.Json.JsonConvert.SerializeObject(response));
}
else if (type == "PICKER_STOP")
{
var bridge = new MachineBridge(_mainForm);
string resultJson = bridge.PickerStop();
var response = new { type = "PICKER_RESULT", data = Newtonsoft.Json.JsonConvert.DeserializeObject(resultJson) };
await Send(socket, Newtonsoft.Json.JsonConvert.SerializeObject(response));
}
else if (type == "CANCEL_VISION_VALIDATION")
{
var bridge = new MachineBridge(_mainForm);
string side = json["side"]?.ToString() ?? "left";
string resultJson = bridge.CancelVisionValidation(side);
var response = new { type = "VISION_CANCEL_RESULT", data = Newtonsoft.Json.JsonConvert.DeserializeObject(resultJson) };
await Send(socket, Newtonsoft.Json.JsonConvert.SerializeObject(response));
}
else if (type == "PICKER_MANAGE_POSITION")
{
var bridge = new MachineBridge(_mainForm);
string side = json["side"]?.ToString() ?? "left";
string resultJson = bridge.PickerManagePosition(side);
var response = new { type = "PICKER_MANAGE_RESULT", data = Newtonsoft.Json.JsonConvert.DeserializeObject(resultJson) };
await Send(socket, Newtonsoft.Json.JsonConvert.SerializeObject(response));
}
else if (type == "PICKER_MANAGE_RETURN")
{
var bridge = new MachineBridge(_mainForm);
string resultJson = bridge.PickerManageReturn();
var response = new { type = "PICKER_MANAGE_RESULT", data = Newtonsoft.Json.JsonConvert.DeserializeObject(resultJson) };
await Send(socket, Newtonsoft.Json.JsonConvert.SerializeObject(response));
}
else if (type == "PICKER_Z_HOME")
{
var bridge = new MachineBridge(_mainForm);
string resultJson = bridge.PickerZHome();
var response = new { type = "PICKER_RESULT", data = Newtonsoft.Json.JsonConvert.DeserializeObject(resultJson) };
await Send(socket, Newtonsoft.Json.JsonConvert.SerializeObject(response));
}
else if (type == "PICKER_Z_ZERO")
{
var bridge = new MachineBridge(_mainForm);
string resultJson = bridge.PickerZZero();
var response = new { type = "PICKER_RESULT", data = Newtonsoft.Json.JsonConvert.DeserializeObject(resultJson) };
await Send(socket, Newtonsoft.Json.JsonConvert.SerializeObject(response));
}
else if (type == "PICKER_TEST_PRINT")
{
var bridge = new MachineBridge(_mainForm);
string side = json["side"]?.ToString() ?? "left";
string resultJson = bridge.PickerTestPrint(side);
var response = new { type = "PICKER_PRINT_RESULT", data = Newtonsoft.Json.JsonConvert.DeserializeObject(resultJson) };
await Send(socket, Newtonsoft.Json.JsonConvert.SerializeObject(response));
}
else if (type == "CAN_CLOSE_MANAGE")
{
var bridge = new MachineBridge(_mainForm);
string resultJson = bridge.CanCloseManage();
var response = new { type = "CAN_CLOSE_MANAGE_RESULT", data = Newtonsoft.Json.JsonConvert.DeserializeObject(resultJson) };
await Send(socket, Newtonsoft.Json.JsonConvert.SerializeObject(response));
}
// ===== HISTORY DATA =====
else if (type == "GET_HISTORY_DATA")
{
var bridge = new MachineBridge(_mainForm);
string startDate = json["startDate"]?.ToString() ?? DateTime.Now.ToShortDateString();
string endDate = json["endDate"]?.ToString() ?? DateTime.Now.ToShortDateString();
string search = json["search"]?.ToString() ?? "";
string resultJson = bridge.GetHistoryData(startDate, endDate, search);
var response = new { type = "HISTORY_DATA_RESULT", data = Newtonsoft.Json.JsonConvert.DeserializeObject(resultJson) };
await Send(socket, Newtonsoft.Json.JsonConvert.SerializeObject(response));
}
// ===== INTERLOCK HANDLERS =====
else if (type == "TOGGLE_INTERLOCK")
{
var bridge = new MachineBridge(_mainForm);
int axisIndex = json["axisIndex"]?.ToObject<int>() ?? 0;
int lockIndex = json["lockIndex"]?.ToObject<int>() ?? 0;
string resultJson = bridge.ToggleInterlock(axisIndex, lockIndex);
var response = new { type = "TOGGLE_INTERLOCK_RESULT", data = Newtonsoft.Json.JsonConvert.DeserializeObject(resultJson) };
await Send(socket, Newtonsoft.Json.JsonConvert.SerializeObject(response));
}
else if (type == "GET_INTERLOCK_LIST")
{
var bridge = new MachineBridge(_mainForm);
string resultJson = bridge.GetInterlockList();
var response = new { type = "INTERLOCK_LIST_RESULT", data = Newtonsoft.Json.JsonConvert.DeserializeObject(resultJson) };
await Send(socket, Newtonsoft.Json.JsonConvert.SerializeObject(response));
}
}
catch (Exception ex)
{