CenterService.cs 10.9 KB
using HHECS.DAQClient.Common;
using HHECS.DAQClient.Model;
using HHECS.DAQClient.Communications;
using HslCommunication.Profinet.Siemens;
using HHECS.DAQClient.Dto;
using HHECS.EquipmentModel;
using System.Text.Json;
using System.Configuration;
using System.Collections.Concurrent;
using LinqKit;

namespace HHECS.DAQClient.Services
{
    public class CenterService
    {
        public ConcurrentQueue<EquipmentDataQueue> EquipmentDataQueues = new ConcurrentQueue<EquipmentDataQueue>();
        public List<EquipmentExtend> Equipments = new List<EquipmentExtend>();

        private readonly SystemLog _log = SystemLog.GetInstance();
        private readonly IFreeSql _freeSql;
        private List<ICommunication> communications = new List<ICommunication>();
        private CancellationTokenSource cts = new CancellationTokenSource();

        /// <summary>
        /// 当前区域
        /// </summary>
        /// <remarks>倘若指定了区域,则只加载该区域的数据</remarks>
        private readonly string currentArea = string.Empty;

        public CenterService(IFreeSql freeSql)
        {
            _freeSql = freeSql;
            currentArea = ConfigurationManager.AppSettings["Area"];
        }

        /// <summary>
        /// 重新加载设备信息并开始采集数据
        /// </summary>
        /// <returns></returns>
        public void Start()
        {
            cts = new CancellationTokenSource();
            try
            {
                if (string.IsNullOrWhiteSpace(currentArea))
                {
                    Equipments = _freeSql.Queryable<EquipmentExtend>().Where(x => !x.Disable).ToList();
                }
                else
                {
                    Equipments = _freeSql.Queryable<EquipmentExtend>().Where(x => !x.Disable && x.DestinationArea == currentArea).ToList();
                }
                if (Equipments.Count == 0)
                {
                    _log.LogWarning($"设备数据为空,请配置数据后操作!");
                    cts.Cancel();
                    return;
                }

                var equipmentIds = Equipments.Select(x => x.Id).ToList();
                var equipmentTypeIds = Equipments.Select(x => x.EquipmentTypeId).Distinct().ToList();

                var equipmentProps = _freeSql.Queryable<EquipmentPropExtend>().Where(x => equipmentIds.Contains(x.EquipmentId)).ToList();
                var equipmentTypes = _freeSql.Queryable<EquipmentTypeExtend>().Where(x => equipmentTypeIds.Contains(x.Id)).ToList();
                var equipmentTypePropTemplates = _freeSql.Queryable<EquipmentTypePropTemplateExtend>().Where(x => equipmentTypeIds.Contains(x.EquipmentTypeId)).ToList();
                //组合逻辑外键
                Equipments.ForEach(t =>
                {
                    t.EquipmentType = equipmentTypes.FirstOrDefault(i => i.Id == t.EquipmentTypeId);
                    t.EquipmentProps = equipmentProps.Where(i => i.EquipmentId == t.Id).ToList();
                });
                equipmentProps.ForEach(t =>
                {
                    t.Equipment = Equipments.FirstOrDefault(i => i.Id == t.EquipmentId);
                    t.EquipmentTypePropTemplate = equipmentTypePropTemplates.FirstOrDefault(i => i.Id == t.EquipmentTypePropTemplateId);
                });

                var communicationConfigFliter = PredicateBuilder.New<CommunicationConfig>(true);
                communicationConfigFliter = communicationConfigFliter.And(x => !x.Disable);
                if (!string.IsNullOrWhiteSpace(currentArea))
                {
                    var equipmentIPAddressList = Equipments.Select(x => x.IP).ToList();
                    communicationConfigFliter = communicationConfigFliter.And(x => equipmentIPAddressList.Contains(x.IpAddress));
                }

                var communicationConfigs = _freeSql.Queryable<CommunicationConfig>().Where(communicationConfigFliter).ToList();

                if (communicationConfigs.Count == 0)
                {
                    _log.LogWarning($"通讯配置数据为空,请配置数据后操作!");
                    cts.Cancel();
                    return;
                }

                communications = InitialCommunication(communicationConfigs);
                //采集数据
                foreach (var item in communications)
                {
                    _ = Task.Run(async () =>
                    {
                        while (!cts.IsCancellationRequested)
                        {
                            try
                            {
                                await Task.Delay(1000);
                                var equipmentTemps = Equipments.Where(x => x.IP == item.IpAddress).ToList();
                                var props = equipmentTemps.SelectMany(x => x.EquipmentProps).Where(x => x.EquipmentTypePropTemplate.PropType != EquipmentPropType.Self).ToList();

                                if (props.Count == 0)
                                {
                                    continue;
                                }

                                var temps = props.Select(x => new DataItem
                                {
                                    Id = x.Id,
                                    Code = x.EquipmentTypePropTemplateCode,
                                    DataAddress = x.Address,
                                    DataType = x.EquipmentTypePropTemplate.DataType,
                                    Value = string.Empty
                                }).ToList();
                                //读取数据
                                var result = item.Read(temps);
                                if (!result.Success)
                                {
                                    _log.LogError(result.Msg);
                                    continue;
                                }

                                //赋值
                                foreach (var item in props)
                                {
                                    item.Value = temps.Find(x => x.Id == item.Id).Value;
                                    item.Updated = DateTime.Now;
                                }

                                foreach (var item in equipmentTemps)
                                {
                                    var tags = item.EquipmentProps.Where(x =>
                                    {
                                        if (x.EquipmentTypePropTemplate.PropType == EquipmentPropType.PLCMonitorAddress
                                        && x.EquipmentTypePropTemplate.DataType == EquipmentDataType.BOOL)
                                        {
                                            //监控地址,只返回有报警的记录
                                            return x.Value == bool.TrueString;
                                        }
                                        return true;
                                    }).Select(x => new TagItem
                                    {
                                        Tag = x.EquipmentTypePropTemplateCode,
                                        Value = x.Value
                                    }).ToList();

                                    var record = new EquipmentDataQueue
                                    {
                                        EquipmentCode = item.Code,
                                        EquipmentName = item.Name,
                                        EquipmentTypeCode = item.EquipmentType.Code,
                                        IsCommit = false,
                                        Reported = JsonSerializer.Serialize(tags),
                                        Version = 1,
                                        SourceTimestamp = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),
                                        Created = DateTime.Now,
                                    };
                                    EquipmentDataQueues.Enqueue(record);
                                }
                            }
                            catch (Exception ex)
                            {
                                _log.LogError($"读取IP:{item.IpAddress}设备出现异常:{ex.Message}");
                            }
                        }
                    }, cts.Token);
                }
                _log.LogInfo($"程序已启动");
            }
            catch (Exception ex)
            {
                _log.LogException($"数据初始化失败:{ex.Message}");
            }
        }

        /// <summary>
        /// 停止PLC数据采集
        /// </summary>
        /// <returns></returns>
        public void Stop()
        {
            Equipments.Clear();
            _log.Log("已停止采集!");
            cts.Cancel();//取消异步线程
        }

        private List<ICommunication> InitialCommunication(IEnumerable<CommunicationConfig> communicationConfigs)
        {
            var result = new List<ICommunication>();
            try
            {
                foreach (var item in communicationConfigs)
                {
                    ICommunication communication;
                    switch (item.CommunicationType)
                    {
                        case CommunicationTypeConst.None:
                            break;
                        case CommunicationTypeConst.KukaVarProxy:
                            communication = new KukaAvarProxyCommunication(item.Id, item.IpAddress, item.Port);
                            result.Add(communication);
                            break;
                        case CommunicationTypeConst.Siemens_S1200:
                            communication = new SiemensS7Communication(item.Id, SiemensPLCS.S1200, item.IpAddress);
                            result.Add(communication);
                            break;
                        case CommunicationTypeConst.Siemens_S1500:
                            communication = new SiemensS7Communication(item.Id, SiemensPLCS.S1500, item.IpAddress);
                            result.Add(communication);
                            break;
                        case CommunicationTypeConst.TcpClient:
                            communication = new TcpClientCommunication(item.Id, item.IpAddress, item.Port);
                            result.Add(communication);
                            break;
                        case CommunicationTypeConst.ModbusTcp:
                            communication = new ModbusTcpCommunication(item.Id, item.IpAddress, item.Port);
                            result.Add(communication);
                            break;
                        default:
                            break;
                    }
                }
            }
            catch (Exception ex)
            {
                _log.LogError($"设备通讯初始化异常:{ex.Message}");
            }
            return result;
        }
    }
}