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.Common.Extension; 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; using Tnb.WarehouseMgr.Entities.Configs; using Tnb.WarehouseMgr.Entities.Consts; using Tnb.WarehouseMgr.Entities.Enums; using Tnb.WarehouseMgr.Interfaces; namespace Tnb.WarehouseMgr { /// /// 电梯控制业务服务类 /// public class ElevatorControlService : BaseWareHouseService, IElevatorControlService { 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();//扩展用 ////如果不是1楼,判断电梯状态,如果电梯是空闲的向电梯发送一个到一楼的指令 //var wirteRes = await SetAgvControlStatus(1); //JObject jo = JObject.Parse(wirteRes); //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); //} ////获取电梯状态 //(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) //{ // await WriteTagAsync("FloorExecute", 1); // if (true) //此处为Agv到一楼开门位,通知操作目前默认为true // { // //向电梯发送前门开门指令 // 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() { //test by close door _agvHeartbeatMonitor.StartAsync(CancellationToken.None); //await SendOpenCloseCmd(4); //await SetAgvControlStatus(1); //监听电梯门是否为关闭的状态 //var dataStatus = 0; //do //{ // dataStatus = await GetTagAsync("DoorStatus"); //} while (dataStatus != 4); //if (dataStatus == 4) //{ // //根据状态确认关闭后,向电梯发送指令从1~3楼 //FloorExecute 楼层触发 // await WriteTagAsync("FloorExecute", 1); // //获取电梯到达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); } 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); } /// /// 向系统发送开关门指令 /// /// 开关门指令 /// public async Task SendOpenCloseCmd(string devName, int value) { var dicCommand = new Dictionary(StringComparer.OrdinalIgnoreCase); dicCommand["DevName"] = devName; dicCommand["token"] = _elevatorCtlCfg.token; dicCommand["TagName"] = "DoorExecute"; dicCommand["Value"] = value.ToString(); var result = await HttpClientHelper.GetAsync(_elevatorCtlCfg.WriteTagUrl, pars: dicCommand); if (result.IsNotEmptyOrNull()) { JObject jo = JObject.Parse(result); if (jo != null) { return jo.Value("Result").Equals("Ok", StringComparison.OrdinalIgnoreCase); } } return false; } /// /// 设置Agv控制请求状态 /// /// /// private async Task SetAgvControlStatus(int value) { var dicCommand = new Dictionary(StringComparer.OrdinalIgnoreCase); dicCommand["DevName"] = _elevatorCtlCfg.DevName; dicCommand["TagName"] = "AGVControl"; dicCommand["Value"] = value.ToString(); dicCommand["token"] = _elevatorCtlCfg.token; return await HttpClientHelper.GetAsync(_elevatorCtlCfg.WriteTagUrl, pars: dicCommand); } /// /// 向指定的标签属性写入值 /// /// /// /// public async Task WriteTagAsync(string devName, string tagName, int value) { var dicCommand = new Dictionary(StringComparer.OrdinalIgnoreCase); dicCommand["DevName"] = devName; dicCommand["token"] = _elevatorCtlCfg.token; dicCommand["TagName"] = tagName; dicCommand["Value"] = value.ToString(); return await HttpClientHelper.GetAsync(_elevatorCtlCfg.WriteTagUrl, pars: dicCommand); } /// /// 根据标签名称获取标签值 /// /// /// public async Task GetTagAsync(string devName, string tagName) { var dicCommand = new Dictionary(); dicCommand["DevName"] = 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"); } /// /// 获取电梯状态 /// /// /// public async Task<(int sysStatus, int runStatus, int floorNo, int doorStatus, int agvStatus)> GetElevatorStatus(string devName, CancellationToken token) { (int sysStatus, int runStatus, int floorNo, int doorStatus, int agvStatus) multi = (-1, -1, -1, -1, -1); var pars = new Dictionary(); pars["DevName"] = devName; pars["Pos"] = "1"; pars["Count"] = "11"; 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[3].Value("V"), objs[2].Value("V"), objs[9].Value("V")); } } return multi; } /// /// 检查Agv状态 /// /// /// public async Task CheckAgvStatus(string devName, CancellationToken cancellationToken) { var isInAgvStatus = false; var agvStatus = await GetTagAsync(devName, ElevatorConsts.AGVStatus); if (agvStatus.ToEnum() != EnumAgvStatus.AGV运行状态) { var result = await WriteTagAsync(devName, ElevatorConsts.AGVControl, 1); JObject jo = JObject.Parse(result); if (jo != null && jo.Value("Result").Equals("Ok", StringComparison.OrdinalIgnoreCase)) { isInAgvStatus = true; } } return isInAgvStatus; } /// /// 呼梯操作 /// /// 设备名称 /// 呼叫楼层 /// 取消令牌 /// public async Task CallLift(string devName, int floor, CancellationToken cancellationToken) { var isSuccefuly = false; (int sysStatus, int runStatus, int floorNo, int doorStatus, int agvStatus) = await GetElevatorStatus(devName, CancellationToken.None); //判断当前楼层是否是放货楼层,如不是则呼叫电梯到当前楼层 if (sysStatus.ToEnum() == EnumSysStatus.正常状态 && runStatus.ToEnum() == EnumRunStatus.停梯 && agvStatus.ToEnum() != EnumAgvStatus.AGV运行状态 && floorNo != 4) { if (doorStatus.ToEnum() != EnumDoorStatus.关门到位保持) { await SendOpenCloseCmd(devName, (int)EnumAgvControl.前门关门); } var result = await WriteTagAsync(devName, ElevatorConsts.FloorExecute, floor); //呼叫电梯到4楼 if (!string.IsNullOrEmpty(result)) { JObject jo = JObject.Parse(result); isSuccefuly = jo?.Value("Result").Equals("Ok", StringComparison.OrdinalIgnoreCase) ?? false; } } return isSuccefuly; } } public class ElevatorData { public string name { get; set; } public string value { get; set; } } }