SiemensPLCDataAnalysis.cs 14.7 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 SiemensPLCDataAnalysis(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
            {
                #region Area1 - Area5

                var plcs = equipments.Where(x => x.EquipmentType == EquipmentTypeConst.SiemensPLC && x.Area >= 1 && x.Area <= 3 && x.EquipmentProperties.Any()).ToList();
                foreach (var plc in plcs)
                {
                    var communication = communications.Where(x => x.CommunicationId == plc.CommunicationId).First();
                    if (plc != null && plc.EquipmentProperties.Any(x => x.UpdateTime > DateTime.Now.AddSeconds(-30)))
                    {
                        SaveElectricityRecord(context, plc, equipments.Where(x => x.EquipmentType != EquipmentTypeConst.SiemensPLC && x.Area == plc.Area));
                        WriteWeldStatistics(context, plc, communication);
                    }

                    if (2 <= plc!.Area && plc!.Area <= 3)
                    {
                        SaveGasFlowRecord(context, plc);

                        #region Kuka C2数据写入PLC

                        var equipmentPropertyCodes = new List<RobotProps>
                        {
                            RobotProps.Weld_V,
                            RobotProps.Weld_I,
                            RobotProps.Weld_Speed,
                            RobotProps.Work_Mode,
                            RobotProps.Type,
                            RobotProps.Program_No,
                            RobotProps.Pos_X,
                            RobotProps.Pos_Y,
                            RobotProps.Pos_Z,
                            RobotProps.Pos_A,
                            RobotProps.Pos_B,
                            RobotProps.Pos_C,
                            RobotProps.Pos_E1,
                            RobotProps.Pos_E2,
                            RobotProps.Pos_E3,
                            RobotProps.Pos_E4,
                            RobotProps.BootFlag,
                            RobotProps.WorkFlag,
                            RobotProps.WeldFlag,
                            RobotProps.WeldCompleteFlag,
                            RobotProps.Weld_Gas,
                            RobotProps.Weld_CleanGun,
                            RobotProps.Alarm,
                            RobotProps.Work_Time,
                        }.Select(x => x.ToString()).ToList();

                        //待写入的属性
                        var propTemps = new List<EquipmentProperty>();

                        var robot = equipments.Where(x => x.EquipmentType == EquipmentTypeConst.Kuka && x.Area == plc.Area).First();
                        foreach (var code in equipmentPropertyCodes)
                        {
                            var plcProp = plc.EquipmentProperties.Where(x => x.Code == code).FirstOrDefault();
                            var robotProp = robot.EquipmentProperties.Where(x => x.Code == code).FirstOrDefault();
                            if (plcProp == null || robotProp == null) continue;
                            else if (string.IsNullOrWhiteSpace(robotProp.Value)) continue;
                            else if (robotProp.Value == plcProp.Value) continue;
                            //浮点数值一致则跳过
                            else if (robotProp.DataType == DataTypeConst.Real && plcProp.DataType == DataTypeConst.Real)
                            {
                                _ = float.TryParse(robotProp.Value, out var val1);
                                _ = float.TryParse(plcProp.Value, out var val2);
                                if (val1 == val2) continue;
                            }
                            propTemps.Add(new EquipmentProperty
                            {
                                Id = plcProp.Id,
                                Code = plcProp.Code,
                                Name = plcProp.Name,
                                Equipment = plc,
                                EquipmentId = plc.Id,
                                DataType = plcProp.DataType,
                                DataAddress = plcProp.DataAddress,
                                Value = robotProp.Value,
                            });
                        }

                        if (propTemps.Any())
                        {
                            communication?.Write(propTemps);
                        }

                        #endregion
                    }
                }

                #endregion
            }
            catch (Exception ex)
            {
                log.LogError($"[{nameof(SiemensPLCDataAnalysis)}]数据解析出现异常:{ex.Message}");
            }
        }

        /// <summary>
        /// 记录电量
        /// </summary>
        /// <param name="context"></param>
        /// <param name="kukaPlc"></param>
        /// <param name="robots"></param>
        public void SaveElectricityRecord(DataContext context, Equipment kukaPlc, IEnumerable<Equipment> robots)
        {
            var prop = kukaPlc.EquipmentProperties.Where(x => x.Code == SiemensPLCProps.Electricity.ToString()).FirstOrDefault();
            if (prop == null) return;
            _ = float.TryParse(prop.Value, out var electricityValue);
            if (electricityValue <= 0) return;//无数据则跳过

            #region 记录燃弧电量

            //焊接标志,需要记录燃弧耗电量
            foreach (var robot in robots)
            {
                _ = bool.TryParse(robot[RobotProps.WeldFlag.ToString()].Value, out var weldFlag);
                var weldCode = $"{RobotProps.WeldFlag}_{SiemensPLCProps.Electricity}";
                var weldRecord = context.EquipmentPropertyRecords.Where(x => x.EquipmentCode == robot.Code && x.EquipmentPropertyCode == weldCode && !x.IsEnd && x.CreateTime >= DateTime.Now.AddHours(-1)).FirstOrDefault();
                if (weldFlag)
                {
                    if (weldRecord == null)
                    {
                        context.EquipmentPropertyRecords.Add(new EquipmentPropertyRecord
                        {
                            EquipmentCode = robot.Code,
                            EquipmentName = robot.Name,
                            EquipmentPropertyCode = weldCode,
                            EquipmentPropertyName = prop.Name,
                            Value = "0",
                            IsEnd = false,
                            CreateTime = DateTime.Now,
                            UpdateTime = DateTime.Now,
                            Remark = electricityValue.ToString()//记录参考值
                        });
                        context.SaveChanges();
                    }
                    else
                    {
                        _ = float.TryParse(weldRecord.Remark, out var oldVal);
                        context.EquipmentPropertyRecords.Where(x => x.Id == weldRecord.Id).ExecuteUpdate(x => x.SetProperty(p => p.Value, (electricityValue - oldVal).ToString()));
                    }
                }
                else
                {
                    context.EquipmentPropertyRecords.Where(x => x.EquipmentCode == robot.Code && x.EquipmentPropertyCode == weldCode && !x.IsEnd).ExecuteUpdate(x => x.SetProperty(p => p.IsEnd, true));
                }
            }
            //结束6小时前的记录
            context.EquipmentPropertyRecords.Where(x => !x.IsEnd && x.CreateTime <= DateTime.Now.AddHours(-6)).ExecuteUpdate(x => x.SetProperty(p => p.IsEnd, true));

            #endregion

            //每小时存一条记录,记录总耗电量
            var startTime = DateTime.Today.AddHours(DateTime.Now.Hour);
            //结束之前的记录
            context.EquipmentPropertyRecords.Where(x => x.EquipmentCode == kukaPlc.Code && x.EquipmentPropertyCode == prop.Code && !x.IsEnd && x.CreateTime < startTime).ExecuteUpdate(x => x.SetProperty(e => e.IsEnd, true));

            var record = context.EquipmentPropertyRecords.Where(x => x.EquipmentCode == kukaPlc.Code && x.EquipmentPropertyCode == prop.Code && !x.IsEnd && x.CreateTime >= startTime).OrderByDescending(x => x.CreateTime).FirstOrDefault();

            if (record != null && record.Remark != electricityValue.ToString())
            {
                _ = float.TryParse(record.Remark, out var oldValue);
                context.EquipmentPropertyRecords.Where(x => x.Id == record.Id).ExecuteUpdate(x => x.SetProperty(p => p.Value, (electricityValue - oldValue).ToString()).SetProperty(p => p.UpdateTime, DateTime.Now));
            }
            else if (record == null)
            {
                context.EquipmentPropertyRecords.Add(new EquipmentPropertyRecord
                {
                    EquipmentCode = kukaPlc.Code,
                    EquipmentName = kukaPlc.Name,
                    EquipmentPropertyCode = prop.Code,
                    EquipmentPropertyName = prop.Name,
                    Value = "0",
                    IsEnd = false,
                    CreateTime = DateTime.Now,
                    UpdateTime = DateTime.Now,
                    Remark = electricityValue.ToString()//记录参考值
                });
                context.SaveChanges();
            }
        }

        /// <summary>
        /// 统计混合气体消耗
        /// </summary>
        /// <param name="context"></param>
        /// <param name="plc"></param>
        public void SaveGasFlowRecord(DataContext context, Equipment plc)
        {
            var gasFlowProp = plc[RobotProps.Gas_Flow.ToString()];
            var startTime = DateTime.Today.AddHours(DateTime.Now.Hour);
            var kukaEquipment = context.Equipments.Where(x => x.Area == plc.Area && x.EquipmentType == EquipmentTypeConst.Kuka).Select(x => new
            {
                x.Code,
                x.Name,
            }).FirstOrDefault();
            if (kukaEquipment == null) return;
            _ = float.TryParse(gasFlowProp.Value, out var gasVal);
            if (gasVal <= 0) return;
            var val = gasVal / 60;
            var record = context.EquipmentPropertyRecords.Where(x => x.EquipmentCode == kukaEquipment.Code && x.EquipmentPropertyCode == RobotProps.Gas_Flow.ToString() && !x.IsEnd && x.CreateTime >= startTime).OrderBy(x => x.CreateTime).FirstOrDefault();
            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 = kukaEquipment.Code,
                    EquipmentName = kukaEquipment.Name,
                    EquipmentPropertyCode = gasFlowProp.Code,
                    EquipmentPropertyName = gasFlowProp.Name,
                    Value = val.ToString(),
                    IsEnd = false,
                    CreateTime = DateTime.Now,
                    UpdateTime = DateTime.Now,
                });
                context.SaveChanges();
            }
        }

        /// <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(SiemensPLCDataAnalysis)}执行{nameof(WriteWeldStatistics)}方法异常,{nameof(communication)}不能为空!");
                return;
            }

            //写入数据
            var weld_Day_EquipmentProperty = plc[SiemensPLCProps.Weld_statistics_Day.ToString()];
            var weld_Month_EquipmentProperty = plc[SiemensPLCProps.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.Any())
            {
                communication.Write(properties);
            }
        }
    }
}