CenterService.cs 10.6 KB
using HHECS.DAQClient.Common;
using HHECS.DAQClient.Model;
using HHECS.DAQClient.Communications;
using HHECS.DAQClient.DataAccess;
using HslCommunication.Profinet.Siemens;
using HHECS.DAQClient.Dto;
using HHECS.EquipmentModel;
using System.Text.Json;
using HHECS.BllModel;

namespace HHECS.DAQClient.Services
{
    internal class CenterService
    {
        private readonly SystemLog _log = SystemLog.GetInstance();
        private readonly DataContext _context;
        private readonly HttpService _httpService;
        private List<Equipment> _equipments = new List<Equipment>();
        private List<ICommunication> communications = new List<ICommunication>();
        private CancellationTokenSource cts = new CancellationTokenSource();
        private readonly object _lock = new object();

        public CenterService(DataContext dataContext, HttpService httpService)
        {
            _context = dataContext;
            _httpService = httpService;
        }

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

                var equipmentProps = _context.EquipmentProp.Where(t => true).ToList();
                var equipmentTypes = _context.EquipmentType.Where(t => true).ToList();
                var equipmentTypePropTemplates = _context.EquipmentTypePropTemplate.Where(t => true).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 communicationConfigs = _context.CommunicationConfigs.Where(x => !x.Disable).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
                            {
                                var equipmentCaches = _equipments.Where(x => x.IP == item.IpAddress).ToList();
                                var props = equipmentCaches.SelectMany(x => x.EquipmentProps).Where(x => x.EquipmentTypePropTemplate.PropType != EquipmentPropType.Self).ToList();
                                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);
                                    await Task.Delay(1000);
                                    continue;
                                }

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

                                var records = equipmentCaches.Select(x => new EquipmentDataQueue
                                {
                                    EquipmentCode = x.Code,
                                    EquipmentTypeCode = x.EquipmentType.Code,
                                    IsCommit = false,
                                    Reported = JsonSerializer.Serialize(x.EquipmentProps.Select(p => new TagItem
                                    {
                                        Tag = p.Address,
                                        Value = p.Value
                                    }).ToList()),
                                    Version = 1,
                                    SourceTimestamp = ConvertToTimestamp(DateTime.Now),
                                    Created = DateTime.Now,
                                }).ToList();
                                var addResult = AddEquipmentDataQueues(records);
                                if (!addResult.Success)
                                {
                                    _log.LogError($"新增设备数据记录失败,{addResult.Msg}");
                                }
                                await Task.Delay(1000);
                            }
                            catch (Exception ex)
                            {
                                _log.LogError($"读取IP:{item.IpAddress}设备出现异常:{ex.Message}");
                            }
                            await Task.Delay(1000);
                        }
                    }, cts.Token);
                }

                _ = Task.Run(() =>
                {
                    SendEquipmentDataToCloud(cts);
                }, cts.Token);
            }
            catch (Exception ex)
            {
                _log.LogException($"数据初始化失败:{ex.Message}");
            }
        }

        /// <summary>
        /// 停止PLC数据采集
        /// </summary>
        /// <returns></returns>
        public void Stop()
        {
            _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);
                            break;
                        default:
                            break;
                    }
                }
            }
            catch (Exception ex)
            {
                _log.LogError($"设备通讯初始化异常:{ex.Message}");
            }
            return result;
        }

        private BllResult AddEquipmentDataQueues(IEnumerable<EquipmentDataQueue> equipments)
        {
            lock (_lock)
            {
                try
                {
                    _context.EquipmentDataQueue.AddRange(equipments);
                    _context.SaveChanges();
                    return BllResultFactory.Success();
                }
                catch (Exception ex)
                {
                    return BllResultFactory.Error(ex.Message);
                }
            }
        }

        private void SendEquipmentDataToCloud(CancellationTokenSource cancellationToken)
        {
            while (!cancellationToken.IsCancellationRequested)
            {
                var records = _context.EquipmentDataQueue.Where(x => !x.IsCommit).OrderByDescending(x => x.Created).ToList();
                foreach (var item in records.GroupBy(x => x.EquipmentCode))
                {
                    var data = item.Select(x => new EquipmentDataDto
                    {
                        Plmeid = x.Id,
                        EquipmentSN = x.EquipmentCode,
                        Reported = JsonSerializer.Deserialize<List<TagItem>>(x.Reported),
                        Version = x.Version,
                        SourceTimestamp = ConvertToTimestamp(DateTime.Now),
                        Timestamp = ConvertToTimestamp(DateTime.Now)
                    });
                    var result = _httpService.SendEquipmentData(data);
                    if (!result.Success)
                    {
                        _log.LogWarning($"推送[{item.Key}]设备数据失败,{result.Msg}");
                        continue;
                    }
                    _context.EquipmentDataQueue.RemoveRange(item.ToList());
                    _context.SaveChanges();
                }
                Task.Delay(1000).Wait();
            }
        }

        private static long ConvertToTimestamp(DateTime? dateTime)
        {
            if (dateTime == null)
            {
                return 0;
            }
            return Convert.ToInt64(((DateTime)dateTime - new DateTime(1970, 1, 1)).TotalSeconds);
        }
    }
}