RobotDataAnalysis.cs 15.6 KB
using DataAcquisition.Common.Communications;
using DataAcquisition.Common.Enums;
using DataAcquisition.Common.Utils;
using DataAcquisition.DataAccess;
using DataAcquisition.Models;
using Microsoft.EntityFrameworkCore;

namespace DataAcquisition.Services.DataAnalysis
{
    public class RobotDataAnalysis(IDbContextFactory<DataContext> dbContextFactory) : IDataAnalysis
    {
        private readonly IDbContextFactory<DataContext> dbContextFactory = dbContextFactory;
        private readonly SystemLog log = SystemLog.Instance;

        public void Analysis(IEnumerable<ICommunication> communications, IEnumerable<Equipment> equipments)
        {
            using var context = dbContextFactory.CreateDbContext();
            try
            {
                //加工记录超过15分钟未更新,则结束记录
                context.WorkpieceProductions.Where(x => !x.IsEnd && x.UpdateTime <= DateTime.Now.AddMinutes(-15)).ExecuteUpdate(x => x.SetProperty(p => p.IsEnd, true));

                var equipmentTypes = new List<EquipmentTypeConst>
                {
                    EquipmentTypeConst.Fanuc,
                };
                var robotEquipments = equipments.Where(x => equipmentTypes.Contains(x.EquipmentType) && x.EquipmentProperties.Any()).ToList();
                foreach (var item in robotEquipments)
                {
                    //超时未更新,则跳过
                    if (item == null || !item.EquipmentProperties.Any(x => x.UpdateTime > DateTime.Now.AddSeconds(-30)))
                    {
                        continue;
                    }

                    //设备未开机则跳过
                    if (item[RobotProps.BootFlag.ToString()].Value != bool.TrueString)
                    {
                        //结束当前设备所有记录
                        context.EquipmentPropertyRecords.Where(x => x.EquipmentCode == item.Code && !x.IsEnd).ExecuteUpdate(x => x.SetProperty(p => p.IsEnd, true));
                        continue;
                    }

                    var propCodes = new List<RobotProps>
                    {
                        RobotProps.BootFlag,//开机标志
                        RobotProps.WorkFlag,//工作标志
                        RobotProps.WeldFlag,//焊接标志
                        RobotProps.WeldCompleteFlag,//焊接完成标志
                        RobotProps.Alarm,//报警
                        RobotProps.Work_Time,//工作时长
                        RobotProps.Work_Mode,//工作模式
                    };

                    //记录设备状态
                    SetEquipmentRecord(context, item, propCodes);

                    //每小时存一条记录
                    var startTime = DateTime.Today.AddHours(DateTime.Now.Hour);

                    //浮点类型的数据
                    var propCodes2 = new List<RobotProps>
                    {
                        RobotProps.Weld_Speed,//米/分钟
                    };

                    foreach (var propCode in propCodes2)
                    {
                        var property = item[propCode.ToString()];
                        _ = float.TryParse(property.Value, out var propValue);
                        //结束之前的记录
                        context.EquipmentPropertyRecords.Where(x => x.EquipmentCode == item.Code && x.EquipmentPropertyCode == propCode.ToString() && !x.IsEnd && x.CreateTime < startTime).ExecuteUpdate(x => x.SetProperty(e => e.IsEnd, true));
                        if (propValue > 0)
                        {
                            var record = context.EquipmentPropertyRecords.Where(x => x.EquipmentCode == item.Code && x.EquipmentPropertyCode == propCode.ToString() && !x.IsEnd && x.CreateTime >= startTime).OrderByDescending(x => x.CreateTime).FirstOrDefault();

                            var val = propValue;
                            //送丝速度:米/分钟, 直径1.2mm,比重7.8g/cm³
                            if (propCode == RobotProps.Weld_Speed)
                            {
                                var weldLenght = propValue / 60 * 100;//每秒长度消耗(cm)12.5cm
                                var area = Math.PI * Math.Pow(1.2 / 2 / 10, 2);//(焊丝截面积cm³)0.011304
                                val = Convert.ToSingle(weldLenght * area * 7.85 / 1000d);
                            }

                            //存在记录则更新
                            if (record != null)
                            {
                                _ = float.TryParse(record.Value, out var oldValue);
                                context.EquipmentPropertyRecords.Where(x => x.Id == record.Id).ExecuteUpdate(x => x.SetProperty(e => e.Value, (oldValue + val).ToString()).SetProperty(x => x.UpdateTime, DateTime.Now));
                            }
                            else
                            {
                                context.EquipmentPropertyRecords.Add(new EquipmentPropertyRecord
                                {
                                    EquipmentCode = item.Code,
                                    EquipmentName = item.Name,
                                    EquipmentPropertyCode = property.Code,
                                    EquipmentPropertyName = property.Name,
                                    Value = val.ToString(),
                                    IsEnd = false,
                                    CreateTime = DateTime.Now,
                                    UpdateTime = DateTime.Now,
                                });
                                context.SaveChanges();
                            }
                        }
                    }
                    var currentCommunication = communications.Where(x => x.CommunicationId == item.CommunicationId).FirstOrDefault();
                    if (currentCommunication != null)
                    {
                        WriteWeldStatistics(context, item, currentCommunication);
                    }
                }
            }
            catch (Exception ex)
            {
                log.LogError($"[{nameof(RobotDataAnalysis)}]数据解析出现异常:{ex.Message}");
            }
        }

        /// <summary>
        /// 记录设备状态
        /// </summary>
        /// <param name="context"></param>
        /// <param name="equipment"></param>
        /// <param name="propCodes"></param>
        public void SetEquipmentRecord(DataContext context, Equipment equipment, IEnumerable<RobotProps> propCodes)
        {
            foreach (var propCode in propCodes)
            {
                //每小时存一条记录
                var startTime = DateTime.Today.AddHours(DateTime.Now.Hour);
                var prop = equipment[propCode.ToString()];
                _ = bool.TryParse(prop.Value, out var propValue);
                //结束之前的记录
                context.EquipmentPropertyRecords.Where(x => x.EquipmentCode == equipment.Code && x.EquipmentPropertyCode == propCode.ToString() && !x.IsEnd && x.CreateTime < startTime).ExecuteUpdate(x => x.SetProperty(e => e.IsEnd, true));
                if (propValue)
                {
                    if (propCode == RobotProps.Alarm)
                    {
                        _ = int.TryParse(equipment[RobotProps.Work_Mode.ToString()].Value, out var mode);
                        //设备报警仅在自动模式下记录
                        if (mode < 3) continue;
                    }

                    var oldRecord = context.EquipmentPropertyRecords.Where(x => x.EquipmentCode == equipment.Code && x.EquipmentPropertyCode == propCode.ToString() && !x.IsEnd && x.CreateTime >= startTime).OrderByDescending(x => x.CreateTime).FirstOrDefault();
                    if (oldRecord != null)
                    {
                        context.EquipmentPropertyRecords.Where(x => x.Id == oldRecord.Id).ExecuteUpdate(x => x.SetProperty(p => p.UpdateTime, DateTime.Now));
                    }
                    else
                    {
                        context.EquipmentPropertyRecords.Add(new EquipmentPropertyRecord
                        {
                            EquipmentCode = equipment.Code,
                            EquipmentName = equipment.Name,
                            EquipmentPropertyCode = prop.Code,
                            EquipmentPropertyName = prop.Name,
                            Value = propValue.ToString(),
                            IsEnd = false,
                            CreateTime = DateTime.Now,
                            UpdateTime = DateTime.Now,
                        });
                        context.SaveChanges();
                    }
                }
                //结束
                else
                {
                    context.EquipmentPropertyRecords.Where(x => x.EquipmentPropertyCode == equipment.Code && x.EquipmentPropertyCode == propCode.ToString() && !x.IsEnd).ExecuteUpdate(x => x.SetProperty(p => p.IsEnd, true));
                }

                #region 记录加工工件

                //True为开始焊接,False为焊接结束,这里用加工时长记录工件
                if (prop.Code == RobotProps.Work_Time.ToString())
                {
                    if (propValue)
                    {
                        var workRecord = context.WorkpieceProductions.Where(x => x.EquipmentCode == equipment.Code && !x.IsEnd && x.CreateTime >= DateTime.Today).OrderByDescending(x => x.CreateTime).FirstOrDefault();
                        if (workRecord != null)
                        {
                            if ((DateTime.Now - workRecord.UpdateTime) >= TimeSpan.FromMicroseconds(1))
                            {
                                var weld_I_Prop = equipment[RobotProps.Weld_I.ToString()];
                                var weld_V_Prop = equipment[RobotProps.Weld_V.ToString()];
                                var weldProcess = new List<WeldProcessRecord>
                                {
                                    new WeldProcessRecord
                                    {
                                        EquipmentId = equipment.Id,
                                        ProductionId = workRecord.Id,
                                        Code = weld_I_Prop.Code,
                                        Name = weld_I_Prop.Name,
                                        Value = weld_I_Prop.Value ?? "0",
                                        CreateTime = DateTime.Now,
                                    },
                                    new WeldProcessRecord
                                    {
                                        EquipmentId = equipment.Id,
                                        ProductionId = workRecord.Id,
                                        Code = weld_V_Prop.Code,
                                        Name = weld_V_Prop.Name,
                                        Value = weld_V_Prop.Value ?? "0",
                                        CreateTime = DateTime.Now,
                                    }
                                };
                                context.WeldProcessRecords.AddRange(weldProcess);
                                context.SaveChanges();
                                context.WorkpieceProductions.Where(x => x.Id == workRecord.Id).ExecuteUpdate(x => x.SetProperty(e => e.UpdateTime, DateTime.Now));
                            }
                        }
                        else
                        {
                            //_ = int.TryParse(equipment[RobotProps.Type.ToString()].Value, out var type);
                            var type = equipment[RobotProps.Type.ToString()].Value ?? string.Empty;
                            _ = int.TryParse(equipment[RobotProps.Program_No.ToString()].Value, out var program_No);
                            context.WorkpieceProductions.Add(new WorkpieceProduction
                            {
                                EquipmentCode = equipment.Code,
                                EquipmentName = equipment.Name,
                                WorkpieceCode = type,//待完善
                                ProgramNo = program_No,
                                IsEnd = false,
                                CreateTime = DateTime.Now,
                                UpdateTime = DateTime.Now,
                            });
                            context.SaveChanges();
                        }
                    }
                    else
                    {
                        context.WorkpieceProductions.Where(x => x.EquipmentCode == equipment.Code && !x.IsEnd).ExecuteUpdate(x => x.SetProperty(p => p.IsEnd, true));
                    }
                }

                #endregion
            }
        }

        /// <summary>
        /// 将焊丝消耗写入PLC
        /// </summary>
        /// <param name="context"></param>
        /// <param name="plc"></param>
        /// <param name="communication"></param>
        private void WriteWeldStatistics(DataContext context, Equipment plc, ICommunication communication)
        {
            if (communication == null)
            {
                log.LogWarning($"{nameof(RobotDataAnalysis)}执行{nameof(WriteWeldStatistics)}方法异常,{nameof(communication)}不能为空!");
                return;
            }

            //写入数据
            var weld_Day_EquipmentProperty = plc[RobotProps.Weld_statistics_Day.ToString()];
            var weld_Month_EquipmentProperty = plc[RobotProps.Weld_statistics_Month.ToString()];
            var equipmentCodes = context.Equipments.Where(x => x.Area == plc.Area).Select(x => x.Code).ToList();
            var monthStartTime = DateTime.Now.AddDays(1 - DateTime.Now.Day).Date;

            var todayValue = context.EquipmentPropertyRecords.Where(x => equipmentCodes.Contains(x.EquipmentCode) && x.EquipmentPropertyCode == RobotProps.Weld_Speed.ToString() && x.CreateTime > DateTime.Today).Select(x => x.Value).AsEnumerable().Sum(float.Parse);

            var monthValue = context.EquipmentPropertyRecords.Where(x => equipmentCodes.Contains(x.EquipmentCode) && x.EquipmentPropertyCode == RobotProps.Weld_Speed.ToString() && x.CreateTime > monthStartTime).Select(x => x.Value).AsEnumerable().Sum(float.Parse);
            //待写入的数据
            var properties = new List<EquipmentProperty>();
            //今日焊丝消耗
            if (!string.IsNullOrWhiteSpace(weld_Day_EquipmentProperty.Value) && weld_Day_EquipmentProperty.Value != todayValue.ToString())
            {
                properties.Add(new EquipmentProperty
                {
                    Id = weld_Day_EquipmentProperty.Id,
                    Equipment = plc,
                    EquipmentId = plc.Id,
                    DataAddress = weld_Day_EquipmentProperty.DataAddress,
                    DataType = weld_Day_EquipmentProperty.DataType,
                    Value = todayValue.ToString(),
                });
            }

            //本月焊丝消耗
            if (!string.IsNullOrWhiteSpace(weld_Month_EquipmentProperty.Value) && weld_Month_EquipmentProperty.Value != monthValue.ToString())
            {
                properties.Add(new EquipmentProperty
                {
                    Id = weld_Month_EquipmentProperty.Id,
                    Equipment = plc,
                    EquipmentId = plc.Id,
                    DataAddress = weld_Month_EquipmentProperty.DataAddress,
                    DataType = weld_Month_EquipmentProperty.DataType,
                    Value = monthValue.ToString(),
                });
            }

            //数据已变动,则写入
            if (properties.Count != 0)
            {
                communication.Write(properties);
            }
        }
    }
}