using System.Dynamic; using JNPF; using JNPF.Common.Extension; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Hosting; using Newtonsoft.Json.Linq; using Tnb.Common.Extension; using Tnb.Common.Utils; 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 readonly Dictionary> _fetchStartedStausValue = new(); private readonly bool isFrontDoorBit = false; //是否到前门位 public ElevatorControlService() { _elevatorCtlCfg = App.Configuration.Build(); //_agvHeartbeatMonitor = agvHeartbeatMonitorService; } /// /// 呼梯测试 /// /// [HttpPost] public async Task CallLiftTest(string devName, int floor) { bool isSuccefuly = false; (int sysStatus, int runStatus, _, int doorStatus, int agvStatus) = await GetElevatorStatus(devName, CancellationToken.None); //判断当前楼层是否是放货楼层,如不是则呼叫电梯到当前楼层 if (sysStatus.ToEnum() == EnumSysStatus.正常状态 && runStatus.ToEnum() == EnumRunStatus.停梯 && agvStatus.ToEnum() != EnumAgvStatus.AGV运行状态) { if (doorStatus.ToEnum() != EnumDoorStatus.关门到位保持) { _ = await SendOpenCloseCmd(devName, (int)EnumAgvControl.前门关门); } dynamic result = await WriteTagAsync(devName, ElevatorConsts.FloorExecute, floor); //呼叫电梯到指定楼层 if (!string.IsNullOrEmpty(result)) { JObject jo = JObject.Parse(result); isSuccefuly = jo?.Value("Result")?.Equals("Ok", StringComparison.OrdinalIgnoreCase) ?? false; } } return isSuccefuly; } /// /// 三楼电梯操作流程 /// /// [HttpPost] public dynamic 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) { TaskCompletionSource tcs = new(); 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) { Dictionary parameters = new() { ["DevName"] = _elevatorCtlCfg.DevName, ["token"] = _elevatorCtlCfg.token, }; if (obj is IDictionary dynamicDic) { foreach ((string k, object v) in dynamicDic) { parameters[k] = v?.ToString() ?? string.Empty; } } return Task.FromResult(parameters); } /// /// 向系统发送开关门指令 /// /// /// 开关门指令 /// public async Task SendOpenCloseCmd(string devName, int value) { Dictionary dicCommand = new(StringComparer.OrdinalIgnoreCase) { ["DevName"] = devName, ["token"] = _elevatorCtlCfg.token, ["TagName"] = "DoorExecute", ["Value"] = value.ToString() }; try { _ = await HttpClientHelper.GetAsync(_elevatorCtlCfg.WriteTagUrl, pars: dicCommand); } catch (Exception) { return false; } return true; } /// /// 设置Agv控制请求状态 /// /// /// private async Task SetAgvControlStatus(int value) { Dictionary dicCommand = new(StringComparer.OrdinalIgnoreCase) { ["DevName"] = _elevatorCtlCfg.DevName, ["TagName"] = "AGVControl", ["Value"] = value.ToString(), ["token"] = _elevatorCtlCfg.token }; return await HttpClientHelper.GetAsync(_elevatorCtlCfg.WriteTagUrl, pars: dicCommand); } /// /// 向指定的标签属性写入值 /// /// /// /// /// public async Task WriteTagAsync(string devName, string tagName, int value) { Dictionary dicCommand = new(StringComparer.OrdinalIgnoreCase) { ["DevName"] = devName, ["token"] = _elevatorCtlCfg.token, ["TagName"] = tagName, ["Value"] = value.ToString() }; return await HttpClientHelper.GetAsync(_elevatorCtlCfg.WriteTagUrl, pars: dicCommand); } /// /// 根据标签名称获取标签值 /// /// /// /// public async Task GetTagAsync(string devName, string tagName) { Dictionary dicCommand = new() { ["DevName"] = devName, ["token"] = _elevatorCtlCfg.token, ["TagName"] = tagName }; string 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); Dictionary pars = new() { ["DevName"] = devName, ["Pos"] = "1", ["Count"] = "11", ["token"] = _elevatorCtlCfg.token }; string url = _elevatorCtlCfg.GetTagListUrl; string systemInfo = await HttpClientHelper.GetAsync(url, pars: pars); JObject jo = JObject.Parse(systemInfo); List 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) { bool isInAgvStatus = false; int agvStatus = await GetTagAsync(devName, ElevatorConsts.AGVStatus); if (agvStatus.ToEnum() != EnumAgvStatus.AGV运行状态) { dynamic 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) { bool isSuccefuly = false; (int sysStatus, int runStatus, _, int doorStatus, int agvStatus) = await GetElevatorStatus(devName, CancellationToken.None); //判断当前楼层是否是放货楼层,如不是则呼叫电梯到当前楼层 if (sysStatus.ToEnum() == EnumSysStatus.正常状态 && runStatus.ToEnum() == EnumRunStatus.停梯 && agvStatus.ToEnum() != EnumAgvStatus.AGV运行状态) { if (doorStatus.ToEnum() != EnumDoorStatus.关门到位保持) { _ = await SendOpenCloseCmd(devName, (int)EnumAgvControl.前门关门); } dynamic result = await WriteTagAsync(devName, ElevatorConsts.FloorExecute, floor); //呼叫电梯到指定楼层 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; } } }