using System; using System.Collections.Generic; using System.Dynamic; using System.Linq; using System.Linq.Expressions; using System.Text; using System.Threading.Tasks; using JNPF; using JNPF.DependencyInjection; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Hosting; using MimeKit.Cryptography; using Newtonsoft.Json.Linq; using Tnb.Common.Extension; using Tnb.Common.Utils; using Tnb.WarehouseMgr.Entities.Configs; namespace Tnb.WarehouseMgr { /// /// 电梯控制业务服务类 /// public class ElevatorControlService : BaseWareHouseService { private readonly ElevatorControlConfiguration _elevatorCtlCfg = new(); private readonly BackgroundService _agvHeartbeatMonitor; private static Dictionary> _fetchStartedStausValue = new(); private bool isFrontDoorBit = false; //是否到前门位 public ElevatorControlService(BackgroundService agvHeartbeatMonitorService) { _elevatorCtlCfg = App.Configuration.Build(); _agvHeartbeatMonitor = agvHeartbeatMonitorService; } /// /// 一楼电梯操作流程 /// /// [HttpPost] public async Task FirstFloorElevatorFlow(string value) { CancellationTokenSource cts = new CancellationTokenSource();//扩展用 //获取电梯状态 (int sysStatus, int runStatus, int floorNo) multi = (-1, -1, -1); do { multi = await GetElevatorStatus(CancellationToken.None); await Task.Delay(2000); } while (multi.sysStatus != 3 && multi.runStatus != 0); if (multi.sysStatus == 3 && multi.runStatus == 0 && multi.floorNo != 1) { //如果不是1楼,判断电梯状态,如果电梯是空闲的向电梯发送一个到一楼的指令 var wirteRes = await SetAgvControlStatus(0); JObject jo = JObject.Parse(wirteRes); if (true) //此处为Agv到一楼开门位,通知操作目前默认为true { var propName = "IsStarted"; if (!_fetchStartedStausValue.TryGetValue(propName, out var func)) { var isStartedProp = _agvHeartbeatMonitor.GetType().GetProperty(propName); var paramExp = Expression.Parameter(typeof(BackgroundService), "_agvHeartbeatMonitor"); var propExp = Expression.Property(Expression.ConvertChecked(paramExp, isStartedProp.DeclaringType), isStartedProp); var body = Expression.Lambda>(propExp, paramExp); func = body.Compile(); _fetchStartedStausValue[propName] = func; } var isStarted = func(_agvHeartbeatMonitor); if (!isStarted) { _agvHeartbeatMonitor.StartAsync(cts.Token); } //向电梯发送前门开门指令 await SendOpenCloseCmd(3); //获取门状态 是否为 开门到位保持 var doorStatus = await GetTagAsync("DoorStatus"); if (doorStatus == 3) { //通知Agv进入电梯,放货,默认为true if (true) { //向电梯发送关门指令 await SendOpenCloseCmd(4); } } } } return Task.FromResult(0); } /// /// 三楼电梯操作流程 /// /// [HttpPost] public async Task ThreeFloorElevatorFlow() { //监听电梯门是否为关闭的状态 var dataStatus = 0; do { dataStatus = await GetTagAsync("DoorStatus"); } while (dataStatus != 4); if (dataStatus == 4) { //根据状态确认关闭后,向电梯发送指令从1~3楼 //FloorExecute 楼层触发 await WriteTagAsync("FloorExecute", 48); //获取电梯到达3楼的到位信号 (_, int runStatus, int floorNo) = (-1, -1, -1); do { var multi = await GetElevatorStatus(CancellationToken.None); runStatus = multi.sysStatus; floorNo = multi.floorNo; } while (runStatus != 0 && floorNo != 3); // 控制电梯到达指定楼层默认开门的行为,改为默认不开门 条件:Agv 到达3楼开门位时,为true if (true)//3楼Agv到达开门位后,向电梯发送开门指令, 默认true 当前 { //向电梯发送前门开门指令 await SendOpenCloseCmd(3); //获取门状态 是否为 开门到位保持 var doorStatus = await GetTagAsync("DoorStatus"); if (doorStatus == 3) //开门到位保持状态 { //通知Agv进入电梯,取货 //向电梯发送关门指令 await SendOpenCloseCmd(4); doorStatus = await GetTagAsync("DoorStatus"); if (doorStatus == 4) //门状态,为关门到位保持 { //解锁,Agv状态,将其至为 var agvStatus = await GetTagAsync("AGVStatus"); if (agvStatus != 2) { await SetAgvControlStatus(0); } } } } } return Task.FromResult(0); } /// /// x2server测试 /// /// [HttpGet] public async Task X2ServerTest() { //var r = new Random(); int currentValue = 0; while (true) { var readRes = await GetElevatorStatus(CancellationToken.None); await Console.Out.WriteLineAsync($"接收结果:{readRes}"); currentValue = 1 - currentValue; // 切换为0或1 dynamic obj = new ExpandoObject(); obj.TagName = "AGVControl"; obj.Value = currentValue; var parameter = await SetParameter(obj); var wirteRes = await HttpClientHelper.GetAsync(_elevatorCtlCfg.WriteTagUrl, pars: parameter); await Console.Out.WriteLineAsync($"写入结果:{wirteRes}"); await Task.Delay(1000); } } private Task SetRequestParameter(string tagName, object value) { var tcs = new TaskCompletionSource(); dynamic reqParam = new ExpandoObject(); reqParam.DevName = _elevatorCtlCfg.DevName; reqParam.TagName = tagName; reqParam.value = value; reqParam.token = _elevatorCtlCfg.token; tcs.SetResult(reqParam); return tcs.Task; } private Task> SetParameter(dynamic obj) { var parameters = new Dictionary() { ["DevName"] = _elevatorCtlCfg.DevName, ["token"] = _elevatorCtlCfg.token, }; var dynamicDic = obj as IDictionary; if (dynamicDic != null) { foreach (var (k, v) in dynamicDic) { parameters[k] = v?.ToString() ?? string.Empty; } } return Task.FromResult(parameters); } /// /// 向系统发送开关门指令 /// /// 开关门指令 /// private async Task SendOpenCloseCmd(int value) { var dicCommand = new Dictionary(StringComparer.OrdinalIgnoreCase); dicCommand["DevName"] = _elevatorCtlCfg.DevName; dicCommand["token"] = _elevatorCtlCfg.token; dicCommand["TagName"] = "DoorExecute"; dicCommand["Value"] = value.ToString(); await HttpClientHelper.GetAsync(_elevatorCtlCfg.WriteTagUrl, pars: dicCommand); } /// /// 设置Agv控制请求状态 /// /// /// private async Task SetAgvControlStatus(int value) { var dicCommand = new Dictionary(StringComparer.OrdinalIgnoreCase); dicCommand["DevName"] = _elevatorCtlCfg.DevName; dicCommand["token"] = _elevatorCtlCfg.token; dicCommand["TagName"] = "AGVControl"; dicCommand["Value"] = value.ToString(); return await HttpClientHelper.GetAsync(_elevatorCtlCfg.WriteTagUrl, pars: dicCommand); } /// /// 向指定的标签属性写入值 /// /// /// /// private async Task WriteTagAsync(string tagName, int value) { var dicCommand = new Dictionary(StringComparer.OrdinalIgnoreCase); dicCommand["DevName"] = _elevatorCtlCfg.DevName; dicCommand["token"] = _elevatorCtlCfg.token; dicCommand["TagName"] = tagName; dicCommand["Value"] = value.ToString(); return await HttpClientHelper.GetAsync(_elevatorCtlCfg.WriteTagUrl, pars: dicCommand); } /// /// 根据标签名称获取标签值 /// /// /// private async Task GetTagAsync(string tagName) { var dicCommand = new Dictionary(); dicCommand["DevName"] = _elevatorCtlCfg.DevName; dicCommand["token"] = _elevatorCtlCfg.token; dicCommand["TagName"] = tagName; var result = await HttpClientHelper.GetAsync(_elevatorCtlCfg.GetTagUrl, pars: dicCommand); JObject jo = JObject.Parse(result); return jo.Value("V"); } /// /// 获取Agv状态 0:正常状态 1:等待进入 AGV 状态 2: AGV 运行状态 /// /// //private async Task GetAgvStatus() //{ // var dicCommand = new Dictionary(); // dicCommand["DevName"] = _elevatorCtlCfg.DevName; // dicCommand["token"] = _elevatorCtlCfg.token; // dicCommand["TagName"] = "AGVStatus"; // var result = await HttpClientHelper.GetAsync(_elevatorCtlCfg.GetTagUrl, pars: dicCommand); // JObject jo = JObject.Parse(result); // return jo.Value("V"); //} /// /// 获取门状态 /// /// //private async Task GetDoorStatus() //{ // var doorStatusParam = new Dictionary(); // doorStatusParam["DevName"] = _elevatorCtlCfg.DevName; // doorStatusParam["token"] = _elevatorCtlCfg.token; // doorStatusParam["TagName"] = "DoorStatus"; // var result = await HttpClientHelper.GetAsync(_elevatorCtlCfg.GetTagUrl, pars: doorStatusParam); // JObject jo = JObject.Parse(result); // return jo.Value("V"); //} /// /// 获取电梯状态 /// /// /// private async Task<(int sysStatus, int runStatus, int floorNo)> GetElevatorStatus(CancellationToken token) { (int sysStatus, int runStatus, int floorNo) multi = (-1, -1, -1); var pars = new Dictionary(); pars["DevName"] = _elevatorCtlCfg.DevName; pars["Pos"] = "1"; pars["Count"] = "4"; pars["token"] = _elevatorCtlCfg.token; var url = _elevatorCtlCfg.GetTagListUrl; var systemInfo = await HttpClientHelper.GetAsync(url, pars: pars); var jo = JObject.Parse(systemInfo); var objs = jo["Items"].Values().ToList(); if (objs?.Count == 4) { if (objs[0].Value("Name").Equals("SysStatus") && objs[1].Value("Name").Equals("RunStatus") && objs[3].Value("Name").Equals("FloorNo")) { multi = ((objs[0].Value("V")), objs[1].Value("V"), objs[2].Value("V")); } } return multi; } } }