using BPA.Message; using BPA.Message.Enum; using BPASmartClient.Model; using BPASmartClient.Peripheral; using System; using System.Collections.Concurrent; using System.Collections.Generic; using System.Linq; using System.Reflection; using System.Text; using System.Threading; using System.Threading.Tasks; using System.Collections.ObjectModel; using BPASmartClient.Model.单片机; using BPA.Models; using BPA.Helper; namespace BPASmartClient.Device { /// /// 设备基类 /// public abstract class BaseDevice : IDevice { public BaseDevice() { } #region 属性 /// /// 订单物料信息 /// public OrderMaterialDelivery orderMaterialDelivery { get; set; } = new OrderMaterialDelivery(); /// /// 配方数据信息 /// public RecipeBoms recipeBoms { get; set; } = new RecipeBoms(); /// /// 设备ID /// public int DeviceId { get; set; } /// /// 设备所有状态 /// public DeviceStatus Status { get; set; } = new DeviceStatus(); /// /// 设备名称 /// public string Name { get; set; } /// /// 当前订单数量 /// protected int OrderCount { get; set; } /// /// 设备初始化中 /// protected bool Initing { get; set; } /// /// 设备类型 /// public abstract DeviceClientType DeviceType { get; } /// /// 是否忙碌 /// public bool IsBusy { get; protected set; } /// /// 是否健康 /// public bool IsHealth { get; protected set; } /// /// 设备运行日志 /// public List Log { get; set; } = new List(); /// /// 设备运行告警与错误 /// public List Error { get; set; } = new List(); /// /// mork_F暂用余量列表 /// public List BatchingInfos { get; set; } = new List(); /// /// 设备变量监控 /// public ObservableCollection variableMonitors { get; set; } = new ObservableCollection(); /// /// 外设状态,硬件设备数据 /// protected ConcurrentDictionary peripheralStatus = new ConcurrentDictionary(); protected /// /// 外设设备集合 /// private List peripherals; /// /// <炒锅>:<外设状态,硬件设备数据>的键值对 /// protected Dictionary> dicPort2peripheralStatus = new Dictionary>(); public Action AddErrorAction { get; set; } public Action DeleteErrorAction { get; set; } public List alarms { get; set; } = new List(); public IAlarm InterfaceAlarm { get; set; } public AlarmHelper alarmHelper { get; set; } = new AlarmHelper(); public IStatus InterfaceStatus { get; set; } public ObservableCollection variables { get; set; } = new ObservableCollection(); #endregion /// /// 写控制 /// /// /// public void WriteControl(string address, object value) { if (peripherals != null) { for (int i = 0; i < peripherals.Count; i++) { peripherals.ElementAt(i).WriteData(address, value); } } } /// /// 多设备分开写控制 /// /// /// public void WriteControlExact(string address, object value, int i) { if (peripherals != null) { if (peripherals.Count > i) { peripherals.ElementAt(i).WriteData(address, value); } } } /// /// 设备过程日志显示 /// /// public void DeviceProcessLogShow(string info) { Log.Insert(0, new { Time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss:fff"), Type = "流程", Text = info }); //MessageLog.GetInstance.DeviceProcessLogShow(DeviceId.ToString(), info); MessageLog.GetInstance.Show($"{DeviceId.ToString()};{info}"); if (Log.Count > 100) { Log.RemoveAt(Log.Count - 1); } } public void Initliaze() { } public void Initliaze(List peripherals) { peripherals.ForEach(p => { p.DeviceId = this.DeviceId; p.Init(); }); this.peripherals = peripherals; } public virtual void StartMain() { TaskManage.GetInstance.StartLong(new Action(() => { int i = 0; foreach (var peripheral in peripherals) { string TypeName = peripheral.GetType().FullName.Replace("BPASmartClient.", ""); Status.Update($"{TypeName}.IsConnected", peripheral.IsConnected); Status.Update($"{TypeName}.IsWork", peripheral.IsWork); //做为炒锅与状态字典的新数据 ConcurrentDictionary newPeripheralStatus = new ConcurrentDictionary(); foreach (var key in peripheral.GetAllStatus().Keys) { peripheralStatus[key] = peripheral.GetAllStatus()[key]; //新的硬件设备数据存储 newPeripheralStatus[key] = peripheral.GetAllStatus()[key]; if (TypeName != "PLC.PLCMachine") { Status.Update($"{TypeName}.{key}", peripheral.GetAllStatus()[key]); } } if (dicPort2peripheralStatus.ContainsKey(i)) { dicPort2peripheralStatus[i] = newPeripheralStatus; } else { //将存储的新硬件设备数据放入字典中,i是作为炒锅编号。 dicPort2peripheralStatus.Add(i, newPeripheralStatus); } i++; } if (AddErrorAction != null && DeleteErrorAction != null) { foreach (var item in Status.GetStatusT()) { if (item.Name == "Warning" || item.Name == "Fault") { if (item.Status != "无故障" && item.Status != "无警告" && item.Status != "未发生故障") { var res = Error?.FirstOrDefault(p => p.GetType().GetProperty("Text").GetValue(p).ToString() == item.Ms); if (res == null) { object obj = new { Time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), Type = item.Name == "Warning" ? "警告" : "故障", Text = item.Ms }; Error.Add(obj); AddErrorAction?.Invoke(DeviceId, obj); } } else { var res = Error?.FirstOrDefault(p => p.GetType().GetProperty("Text").GetValue(p).ToString().Contains(item.id)); if (res != null) { Error.Remove(res); DeleteErrorAction?.Invoke(DeviceId, res); } } } } } Thread.Sleep(100); }), $"GetAllStatus:{DeviceId}"); DoMain(); SimOrder(); GetGvlStatus(); InitResetTask(); InitTask(); } private void ResetStatus() { this.GetType().GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).ToList().ForEach(item => { var res = item.FieldType.GetInterfaces(); if (res != null) { foreach (var faces in res) { if (faces.Name == "IStatus") InterfaceStatus = item.GetValue(this) as IStatus; } } }); } private void GetGvlStatus() { this.GetType().GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).ToList().ForEach(item => { var res = item.FieldType.GetInterfaces(); if (res != null) { foreach (var faces in res) { if (faces.Name == "IStatus") { InterfaceStatus = item.GetValue(this) as IStatus; GetMonitorData(InterfaceStatus); } else if (faces.Name == "IAlarm") { InterfaceAlarm = item.GetValue(this) as IAlarm; alarmHelper.AddAction += new Action((s) => { var res = alarmHelper.Alarms.FirstOrDefault(p => p.Info == s); if (res != null) { object obj = new { Time = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), Type = res.Grade, Text = res.Info }; Error.Insert(0, obj); AddErrorAction?.Invoke(DeviceId, obj); } }); alarmHelper.RemoveAction += new Action((s) => { var res = Error.FirstOrDefault(p => p.GetType().GetProperty("Text").GetValue(p).ToString() == s); if (res != null && Error.Contains(res)) { Error.Remove(res); DeleteErrorAction?.Invoke(DeviceId, res); } }); TaskManage.GetInstance.StartLong(new Action(() => { AlarmMonitoring(); Thread.Sleep(500); }), $"报警检测监控:{DeviceId}"); } } } }); } /// /// 报警监控 /// /// /// private void AlarmMonitoring() { if (InterfaceAlarm == null) return; foreach (var item in InterfaceAlarm.GetType().GetProperties()) { var res = item.GetValue(InterfaceAlarm); if (res != null && res is bool blen) { if (item.CustomAttributes.Count() > 0 && item.CustomAttributes.ElementAt(0)?.ConstructorArguments.Count() > 0) { var info = item.GetCustomAttribute().AlarmInfo; if (info != null) alarmHelper.EdgeAlarm(blen, $"{info.ToString()}-{DeviceId}"); } } } } private void InitResetTask() { #region 复位程序 TaskManage.GetInstance.StartLong(new Action(() => { if (RTrig.GetInstance($"ResetProgram:{DeviceId}").Start(Initing)) { DeviceProcessLogShow("启动初始化"); //记录监控数据 DeviceProcessLogShow($"监控数据:【 {variableMonitors.ToJSON()} 】"); TaskManage.GetInstance.StopTask($"MainTask:{DeviceId}", new Action(() => { TaskManage.GetInstance.StopTask($"ReadData:{DeviceId}", new Action(() => { TaskManage.GetInstance.StopTask($"GvlStatusMonitor:{DeviceId}", new Action(() => { ActionManage.GetInstance.Send("ClearOrders"); ResetProgram(); ResetStatus(); InitTask(); })); })); })); } Thread.Sleep(10); }), $"ResetProgram:{DeviceId}"); #endregion } private void InitTask() { #region 数据读取 TaskManage.GetInstance.StartLong(new Action(() => { ReadData(); Thread.Sleep(10); }), $"ReadData:{DeviceId}", true); #endregion #region 任务流程 TaskManage.GetInstance.StartLong(new Action(() => { MainTask(); Thread.Sleep(10); }), $"MainTask:{DeviceId}", true); #endregion #region 设备状态监控 TaskManage.GetInstance.StartLong(new Action(() => { UpdateValue(InterfaceStatus); Thread.Sleep(1000); }), $"GvlStatusMonitor:{DeviceId}"); #endregion } /// /// 获取监控信息 /// private void GetMonitorData(IStatus status) { if (status == null) return; List vm = new List(); foreach (var item in status.GetType().GetProperties()) { if (item.CustomAttributes.Count() > 0) { var attributeName = item.CustomAttributes.FirstOrDefault(p => p.AttributeType.Name == "VariableMonitorAttribute"); if (attributeName == null) return; var plcadd = item.GetCustomAttribute()?.PLCAddress; var modadd = item.GetCustomAttribute()?.ModbusTcpAddress; var notes = item.GetCustomAttribute()?.Notes; if (item.PropertyType?.BaseType?.Name == "Array") { if (plcadd?.Length > 0) { var arrayRes = item.GetValue(status, null); if (arrayRes != null && arrayRes is Array arr) { for (int i = 0; i < arr.Length; i++) { var res = vm.FirstOrDefault(p => p.VarName == $"{item.Name}_{i + 1}"); if (res == null) { string[] plc = plcadd?.Substring(1).Split('.'); string TempPlcAddress = string.Empty; if (plc?.Length == 2) { int add = int.Parse(plc[1]); int firstAdd = int.Parse(plc[0]); if (add >= 0 && add < 7) { add += i; } else if (add >= 7) { add = 0; firstAdd++; } plc[0] = firstAdd.ToString(); plc[1] = add.ToString(); TempPlcAddress = $"M{plc[0]}.{plc[1]}"; } vm.Add(new VariableMonitor() { Id = vm.Count + 1, VarName = $"{item.Name}_{i + 1}", Notes = $"{notes}_{i + 1}", ModbusTcpAddress = $"{int.Parse(modadd) + i}", PLCAddress = TempPlcAddress, }); } } } } else { var arrayRes = item.GetValue(status, null); if (arrayRes != null && arrayRes is Array arr) { for (int i = 0; i < arr.Length; i++) { var res = vm.FirstOrDefault(p => p.VarName == $"{item.Name}_{i + 1}"); if (res == null) { vm.Add(new VariableMonitor() { Id = vm.Count + 1, VarName = $"{item.Name}_{i + 1}", Notes = $"{notes}_{i + 1}", }); } } } } } else { var res = vm.FirstOrDefault(p => p.VarName == item.Name); if (res == null) { vm.Add(new VariableMonitor() { Id = vm.Count + 1, VarName = item.Name, Notes = notes, ModbusTcpAddress = modadd, PLCAddress = plcadd, }); } } } } //监控列表排序 //vm.OrderBy(p => p.VarName).ToList().ForEach(item => { variableMonitors.Add(item); }); vm.ForEach(item => { variableMonitors.Add(item); }); } /// /// 更新数据 /// /// public void UpdateValue(IStatus status) { if (status == null) return; foreach (var item in status.GetType().GetProperties()) { if (item.CustomAttributes.Count() > 0) { if (item.PropertyType?.BaseType?.Name == "Array") { var arrayRes = item.GetValue(status); if (arrayRes != null && arrayRes is Array arr) { for (int i = 0; i < arr.Length; i++) { int index = Array.FindIndex(variableMonitors.ToArray(), p => p.VarName == $"{item.Name}_{i + 1}"); if (index >= 0 && index < variableMonitors.Count) { variableMonitors.ElementAt(index).CurrentValue = arr.GetValue(i)?.ToString(); } } } } else { int index = Array.FindIndex(variableMonitors.ToArray(), p => p.VarName == item.Name); if (index >= 0 && index < variableMonitors.Count) { variableMonitors.ElementAt(index).CurrentValue = item.GetValue(status)?.ToString(); } } } } } public abstract void DoMain(); public abstract void Stop(); /// /// 数据读取 /// public abstract void ReadData(); /// /// 主流程控制 /// public abstract void MainTask(); /// /// 复位程序 /// public abstract void ResetProgram(); /// /// 模拟订单 /// public abstract void SimOrder(); public object GetError() { return new { data = Error }; } public object GetLog() { return new { data = Log }; } public object GetVariableMonitor() { return new { data = variableMonitors }; } /// /// 获取某个对象中的属性值 /// /// /// /// public object GetPropertyValue(object info, string field) { if (info == null) return null; Type t = info.GetType(); IEnumerable property = from pi in t.GetProperties() where pi.Name.ToLower() == field.ToLower() select pi; return property.First().GetValue(info, null); } } }