You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
461 lines
17 KiB
461 lines
17 KiB
using AutoMapper;
|
|
using Entity.Constant;
|
|
using Entity.DbModel.Station;
|
|
using log4net;
|
|
using Repository.Station;
|
|
using Service.Execute.Api;
|
|
using Service.Execute.Enum;
|
|
using Service.Execute.Model;
|
|
using Service.Execute.StaticTools;
|
|
using Service.Execute.SwapException;
|
|
using Service.Init;
|
|
using Service.Station;
|
|
using Swapping.Business.Tech;
|
|
|
|
namespace Service.Execute.Step;
|
|
|
|
public class CarPrepareState : IState
|
|
{
|
|
private readonly ILog _log = LogManager.GetLogger(typeof(CarPrepareState));
|
|
|
|
|
|
private BinInfoRepository BinInfoRepository { get; set; }
|
|
public SwapOrderStepService SwapOrderStepService { get; set; }
|
|
private SwapAmtOrderRepository AmtOrderRepository { get; set; }
|
|
|
|
private SwapOrderBatteryRepository SwapOrderBatteryRepository { get; set; }
|
|
|
|
public StateResult Handle(SwappingStateMachine machine)
|
|
{
|
|
Thread.Sleep(500);
|
|
RfidReadModel? rfidReadModel = machine.RfidReadModel;
|
|
if (rfidReadModel == null)
|
|
{
|
|
_log.Error("rfid is null");
|
|
return new StateResult()
|
|
{
|
|
SwappingState = SwappingState.StationReady
|
|
};
|
|
}
|
|
|
|
//云平台车辆认证
|
|
var cloudCheckVel = CloudCheckVel(machine);
|
|
if (cloudCheckVel != InvokeStatus.Done)
|
|
{
|
|
return SwappingStateMachine.ReturnWithInvokeErr(cloudCheckVel, ExceptionReason.None);
|
|
}
|
|
|
|
//检查tbox链接状态
|
|
InvokeStatus checkTBoxConnect = CheckTBoxConnectFlag(machine);
|
|
if (checkTBoxConnect != InvokeStatus.Done)
|
|
{
|
|
return SwappingStateMachine.ReturnWithInvokeErr(checkTBoxConnect, ExceptionReason.None);
|
|
}
|
|
|
|
//车辆本地验证
|
|
InvokeStatus checkTBoxVelLocal = CheckTBoxVelLocalFlag(machine);
|
|
if (checkTBoxVelLocal != InvokeStatus.Done)
|
|
{
|
|
return SwappingStateMachine.ReturnWithInvokeErr(checkTBoxVelLocal, ExceptionReason.None);
|
|
}
|
|
|
|
|
|
//云端数据上报
|
|
InvokeStatus cloudTBox = CloudTBoxFlag(machine);
|
|
if (cloudTBox != InvokeStatus.Done)
|
|
{
|
|
return SwappingStateMachine.ReturnWithInvokeErr(cloudTBox, ExceptionReason.None);
|
|
}
|
|
|
|
machine.ExceptionReason = ExceptionReason.None;
|
|
|
|
//选包
|
|
InvokeStatus selectPack = SelectPack(machine);
|
|
if (selectPack != InvokeStatus.Done)
|
|
{
|
|
return SwappingStateMachine.ReturnWithInvokeErr(selectPack, ExceptionReason.None);
|
|
}
|
|
|
|
//车辆到位
|
|
InvokeStatus carInPosition = CarInPosition(machine);
|
|
if (carInPosition != InvokeStatus.Done)
|
|
{
|
|
return SwappingStateMachine.ReturnWithInvokeErr(carInPosition, ExceptionReason.None);
|
|
}
|
|
|
|
return new StateResult()
|
|
{
|
|
SwappingState = SwappingState.SwapCanStart
|
|
};
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// 车辆到位
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public InvokeStatus CarInPosition(SwappingStateMachine machine)
|
|
{
|
|
return Invoker.Invoke("check CarInPosition", 500, 50, machine.IsCanceled,
|
|
() => machine.VehiclesInPlaceFlag, () =>
|
|
{
|
|
var result = TBoxApi.GetCarInfo();
|
|
TboxCarInfoModel tboxCarInfoModel = result.Result;
|
|
|
|
if (tboxCarInfoModel.HeartBeatMsg.KeyStatus == 0)
|
|
{
|
|
machine.VehiclesInPlaceFlag = true;
|
|
//写入口等 :红灯
|
|
if (PlcApi.WriteEntranceLamp(1020))
|
|
{
|
|
machine.LedTool?.WriteProgramContent(InfoEnum.SwapInfo.InfoCarInPosition.GetLed());
|
|
SoundTool.PlayOneSound((int)InfoEnum.SwapInfo.InfoCarInPosition);
|
|
machine.VehiclesInPlaceFlag = true;
|
|
//告知云平台换电准备完成
|
|
machine.BusinessSwappingForCloudState =
|
|
InfoEnum.BusinessSwappingForCloudState.SwapReady;
|
|
machine.ExceptionReason = ExceptionReason.None;
|
|
CloudApi.SendStateLog(machine.SwapOrder, machine.BusinessSwappingForCloudState);
|
|
//清除下发的指令,等待新的指令
|
|
CloudApi.ClearCarCanStartInfo();
|
|
|
|
SwapOrderStepService.InsertSwapStepForSwapMain(InfoEnum.BusinessSwappingStep.CarInPositionFlag,
|
|
machine.StepSort++, machine.SwapOrder.Sn);
|
|
}
|
|
}
|
|
}, () =>
|
|
{
|
|
machine.ExceptionReason = ExceptionReason.CarInPositionError;
|
|
machine.LedTool?.WriteProgramContent(InfoEnum.SwapInfo.ErrorCarInPositionTimeout.GetLed());
|
|
SoundTool.PlayOneSound((int)InfoEnum.SwapInfo.ErrorCarInPositionTimeout);
|
|
}, false, () => { }
|
|
, 20, InvokeStatus.None);
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// 云平台车辆认证
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public InvokeStatus CloudCheckVel(SwappingStateMachine machine)
|
|
{
|
|
return Invoker.Invoke("cloud check vehicle", 500, 20, machine.IsCanceled,
|
|
() => machine.CloudVelCheckFlag, () =>
|
|
{
|
|
if (BaseEnumExtensions.GetEnumByCode<StationConstant.StationModel>(
|
|
int.Parse(StaticStationInfo.StationModel)) == StationConstant.StationModel.Remote)
|
|
{
|
|
bool flag = CloudApi.VehicleCheck(machine.RfidReadModel);
|
|
|
|
if (!flag)
|
|
{
|
|
_log.Info("cloud check vehicle error");
|
|
}
|
|
else
|
|
{
|
|
machine.ExceptionReason = ExceptionReason.None;
|
|
_log.Info("cloud check vehicle done");
|
|
machine.CloudVelCheckFlag = true;
|
|
machine.LedTool.WriteProgramContent("换电准备中:云平台车辆验证完成");
|
|
|
|
SwapOrderStepService.InsertSwapStepForSwapMain(InfoEnum.BusinessSwappingStep.CloudVelCheckFlag,
|
|
machine.StepSort++, machine.SwapOrder.Sn);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
machine.CloudVelCheckFlag = true;
|
|
}
|
|
}, () =>
|
|
{
|
|
machine.LedTool?.WriteProgramContent(InfoEnum.SwapInfo.ErrorCloudCheck.GetLed());
|
|
SoundTool.PlayOneSound((int)InfoEnum.SwapInfo.ErrorCloudCheck);
|
|
}, false, () => { machine.ExceptionReason = ExceptionReason.CloudCheckError; }
|
|
, 20, InvokeStatus.None);
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// 检查tbox连接状态
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public InvokeStatus CheckTBoxConnectFlag(SwappingStateMachine machine)
|
|
{
|
|
return Invoker.Invoke("check TBox connect", 1000, 20, machine.IsCanceled,
|
|
() => machine.BoxConnectFlag, () =>
|
|
{
|
|
Task<bool> result = TBoxApi.IsConnected();
|
|
bool isConnect = result.Result;
|
|
if (isConnect)
|
|
{
|
|
machine.BoxConnectFlag = true;
|
|
}
|
|
}, () => { machine.ExceptionReason = ExceptionReason.ConnTBoxError; }, false, () =>
|
|
{
|
|
machine.ExceptionReason = ExceptionReason.ConnTBoxError;
|
|
machine.LedTool?.WriteProgramContent(InfoEnum.SwapInfo.ErrorTBoxConn.GetLed());
|
|
SoundTool.PlayOneSound((int)InfoEnum.SwapInfo.ErrorTBoxConn);
|
|
}
|
|
, 10, InvokeStatus.None);
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// 车辆本地验证:车牌校验
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public InvokeStatus CheckTBoxVelLocalFlag(SwappingStateMachine machine)
|
|
{
|
|
return Invoker.Invoke("check TBox VelLocal", 1000, 20, machine.IsCanceled,
|
|
() => machine.BoxLocalCheckFlag, () =>
|
|
{
|
|
Task<TboxCarInfoModel> carInfo = TBoxApi.GetCarInfo();
|
|
var tBoxCarInfoModel = carInfo.Result;
|
|
//TODO::不知道Tbox给的CardNo是什么
|
|
if (tBoxCarInfoModel.CarNo!.Trim().Equals(machine.RfidReadModel!.VelNo.Trim()))
|
|
{
|
|
machine.BoxLocalCheckFlag = true;
|
|
}
|
|
}, () => { machine.ExceptionReason = ExceptionReason.LocalCheckVarError; }, true, () =>
|
|
{
|
|
machine.ExceptionReason = ExceptionReason.LocalCheckVarError;
|
|
}
|
|
, 3, InvokeStatus.TimeOut);
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// 蓝牙数据云平台上报
|
|
/// </summary>
|
|
/// <returns></returns>
|
|
public InvokeStatus CloudTBoxFlag(SwappingStateMachine machine)
|
|
{
|
|
return Invoker.Invoke("cloud TBox upload", 500, 20, machine.IsCanceled,
|
|
() => machine.CloudTBoxFlag, () =>
|
|
{
|
|
Task<TboxCarInfoModel> result = TBoxApi.GetCarInfo();
|
|
TboxCarInfoModel tBoxCarInfoModel = result.Result;
|
|
machine.BoxCarInfoModel = tBoxCarInfoModel;
|
|
if (tBoxCarInfoModel != null)
|
|
{
|
|
if (tBoxCarInfoModel.Connected)
|
|
{
|
|
//将数据上报云平台
|
|
CloudApi.UploadTBoxCarInfo(machine.SwapOrder!, machine.BoxCarInfoModel);
|
|
}
|
|
}
|
|
}, () => { machine.LedTool?.WriteProgramContent("车机蓝牙车辆数据上报异常,请联系站务人员"); }, false, () =>
|
|
{
|
|
machine.ExceptionReason = ExceptionReason.CloudCarDataUploadError;
|
|
}
|
|
, 20, InvokeStatus.None);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 选包:
|
|
/// 有预约单: 获取预约单的电池
|
|
/// 无预约单:
|
|
/// 1.仓位状态:启动
|
|
/// 2.电池在位
|
|
/// 3.充电状态:不在充电中
|
|
/// 4.未锁定
|
|
/// 5.最后一次结束充电时间> ()
|
|
/// 6.soc >()
|
|
/// </summary>
|
|
/// <param name="machine"></param>
|
|
public InvokeStatus SelectPack(SwappingStateMachine machine)
|
|
{
|
|
SwapAmtOrder? swapAmtOrder =
|
|
AmtOrderRepository.QueryByClause(i =>
|
|
i.Status == (int)InfoEnum.AmtOrderStatus.Success && i.VehicleNo.Equals(machine.BoxCarInfoModel.CarNo));
|
|
|
|
|
|
return Invoker.Invoke("selectPack", 500, 20, machine.IsCanceled,
|
|
() => machine.SelectPackFlag, () =>
|
|
|
|
{
|
|
SwapOrderBatteryInfo orderBatteryInfo = null;
|
|
if (swapAmtOrder != null)
|
|
{
|
|
orderBatteryInfo = SelectPackArm(swapAmtOrder);
|
|
}
|
|
else
|
|
{
|
|
orderBatteryInfo = SelectPackNotArm();
|
|
}
|
|
|
|
if (orderBatteryInfo.CanSwap != InfoEnum.SelectBinStatusInfo.Success)
|
|
{
|
|
machine.LedTool?.WriteProgramContent(InfoEnum.SwapInfo.ErrorSelectPack.GetLed());
|
|
SoundTool.PlayOneSound((int)InfoEnum.SwapInfo.ErrorSelectPack);
|
|
Thread.Sleep(1000 * 3);
|
|
_log.Info($"SelectPack error CanSwap={machine.SwapOrderBatteryInfo.CanSwap}");
|
|
}
|
|
else
|
|
{
|
|
//选包成功
|
|
LockBinAndUpdateAmt(orderBatteryInfo);
|
|
machine.SwapOrderBatteryInfo = orderBatteryInfo;
|
|
SaveSwapBattery(machine);
|
|
machine.SelectPackFlag = true;
|
|
}
|
|
}, () => { machine.ExceptionReason = ExceptionReason.SelectPackError; });
|
|
}
|
|
|
|
private void SaveSwapBattery(SwappingStateMachine machine)
|
|
{
|
|
BinInfo UpBin = machine.SwapOrderBatteryInfo.UpBinInfo;
|
|
BinInfo InBin = machine.SwapOrderBatteryInfo.InBinInfo;
|
|
SwapOrderBattery swapOrderBattery = new SwapOrderBattery()
|
|
{
|
|
SwapOrderSn = machine.SwapOrder.Sn,
|
|
UpBatterySoc = UpBin.Soc,
|
|
UpBatteryNo = UpBin.BatteryNo,
|
|
UpBatterySoe = UpBin.Soe,
|
|
UpBatteryBinNo = int.Parse(UpBin.No),
|
|
DownBatteryBinNo = int.Parse(InBin.No),
|
|
};
|
|
SwapOrderBatteryRepository.Insert(swapOrderBattery);
|
|
}
|
|
|
|
/// <summary>
|
|
/// 1.锁仓
|
|
/// 2.更改预约单
|
|
/// </summary>
|
|
private void LockBinAndUpdateAmt(SwapOrderBatteryInfo orderBatteryInfo)
|
|
{
|
|
var configBinInfo =
|
|
new MapperConfiguration(cfg => cfg.CreateMap<BinInfo, BinInfo>().ReverseMap());
|
|
IMapper mapperBinInfo = configBinInfo.CreateMapper();
|
|
BinInfo dbBinInfo = mapperBinInfo.Map<BinInfo>(orderBatteryInfo.UpBinInfo);
|
|
|
|
dbBinInfo.AmtLock = (int)InfoEnum.AmtBatLockStatus.Lock;
|
|
BinInfoRepository.Update(dbBinInfo);
|
|
if (!orderBatteryInfo.isAmt)
|
|
{
|
|
return;
|
|
}
|
|
|
|
var configAmt =
|
|
new MapperConfiguration(cfg => cfg.CreateMap<SwapAmtOrder, SwapAmtOrder>().ReverseMap());
|
|
IMapper mapperAmt = configAmt.CreateMapper();
|
|
SwapAmtOrder swapAmtOrder = mapperAmt.Map<SwapAmtOrder>(orderBatteryInfo.swapAmtOrder);
|
|
swapAmtOrder.Status = (int)InfoEnum.AmtOrderStatus.Swapping;
|
|
AmtOrderRepository.Update(swapAmtOrder);
|
|
}
|
|
|
|
/// 1.仓位状态:启动
|
|
/// 2.电池在位
|
|
/// 3.充电状态:不在充电中
|
|
/// 4.未锁定
|
|
/// 5.最后一次结束充电时间> ()
|
|
/// 6.soc >()
|
|
/**
|
|
* && i.ChargeStatus == 2
|
|
&& i.AmtLock == "0"
|
|
&& new TimeSpan(DateTime.Now.Ticks -
|
|
i.LastChargeFinishTime.ToDateTime().Ticks)
|
|
.TotalMinutes > StaticStationInfo.SwapFinishChargeTime
|
|
&& i.Soc > StaticStationInfo.Soc
|
|
*/
|
|
private SwapOrderBatteryInfo SelectPackNotArm()
|
|
{
|
|
SwapOrderBatteryInfo orderBatteryInfo = new SwapOrderBatteryInfo();
|
|
UpBin(orderBatteryInfo);
|
|
if (orderBatteryInfo.CanSwap != InfoEnum.SelectBinStatusInfo.Success)
|
|
{
|
|
return orderBatteryInfo;
|
|
}
|
|
|
|
InBin(orderBatteryInfo);
|
|
|
|
return orderBatteryInfo;
|
|
}
|
|
|
|
private SwapOrderBatteryInfo SelectPackArm(SwapAmtOrder swapAmtOrder)
|
|
{
|
|
SwapOrderBatteryInfo orderBatteryInfo = new SwapOrderBatteryInfo();
|
|
orderBatteryInfo.swapAmtOrder = swapAmtOrder;
|
|
orderBatteryInfo.isAmt = true;
|
|
BinInfo UpBin = BinInfoRepository.QueryByClause(i => i.No.Equals(swapAmtOrder.AmtBinNoList));
|
|
bool CanSwap = UpBin.Exists == 1 && UpBin.Status == 1 && UpBin.ChargeStatus == 2
|
|
&& UpBin.AmtLock == (int)InfoEnum.AmtBatLockStatus.Lock && new TimeSpan(DateTime.Now.Ticks -
|
|
UpBin.LastChargeFinishTime.ToDateTime()
|
|
.Ticks)
|
|
.TotalMinutes > int.Parse(StaticStationInfo.SwapFinishChargeTime) &&
|
|
UpBin.Soc > int.Parse(StaticStationInfo.SwapSoc);
|
|
if (!CanSwap)
|
|
{
|
|
orderBatteryInfo.CanSwap = InfoEnum.SelectBinStatusInfo.AmtError;
|
|
|
|
return orderBatteryInfo;
|
|
}
|
|
|
|
orderBatteryInfo.UpBinInfo = UpBin;
|
|
InBin(orderBatteryInfo);
|
|
return orderBatteryInfo;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 取电池判断
|
|
/// </summary>
|
|
/// <param name="orderBatteryInfo"></param>
|
|
private void UpBin(SwapOrderBatteryInfo orderBatteryInfo)
|
|
{
|
|
List<BinInfo> list =
|
|
BinInfoRepository.QueryListByClause(i =>
|
|
i.Exists == 1 && i.Status == 1 && i.AmtLock == (int)InfoEnum.AmtBatLockStatus.UnLock);
|
|
if (list.Count <= 0)
|
|
{
|
|
orderBatteryInfo.CanSwap = InfoEnum.SelectBinStatusInfo.NoBattery;
|
|
return;
|
|
}
|
|
|
|
list = list.Where(i => i.ChargeStatus == 2).ToList();
|
|
if (list.Count <= 0)
|
|
{
|
|
orderBatteryInfo.CanSwap = InfoEnum.SelectBinStatusInfo.LessOfFinishCharging;
|
|
return;
|
|
}
|
|
|
|
|
|
list = list.Where(i => i.Soc > int.Parse(StaticStationInfo.SwapSoc)).ToList();
|
|
if (list.Count <= 0)
|
|
{
|
|
orderBatteryInfo.CanSwap = InfoEnum.SelectBinStatusInfo.LessOfSoc;
|
|
return;
|
|
}
|
|
|
|
list = list.Where(i => new TimeSpan(DateTime.Now.Ticks -
|
|
i.LastChargeFinishTime.ToDateTime().Ticks)
|
|
.TotalMinutes > int.Parse(StaticStationInfo.SwapFinishChargeTime)).ToList();
|
|
if (list.Count <= 0)
|
|
{
|
|
orderBatteryInfo.CanSwap = InfoEnum.SelectBinStatusInfo.LessOf3Minute;
|
|
return;
|
|
}
|
|
|
|
orderBatteryInfo.UpBinInfo = list[0];
|
|
orderBatteryInfo.CanSwap = InfoEnum.SelectBinStatusInfo.Success;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 放电池判断
|
|
/// </summary>
|
|
/// <param name="orderBatteryInfo"></param>
|
|
private void InBin(SwapOrderBatteryInfo orderBatteryInfo)
|
|
{
|
|
List<BinInfo> list =
|
|
BinInfoRepository.QueryListByClause(i =>
|
|
i.Exists == 1 && i.Status == 1 && i.AmtLock == (int)InfoEnum.AmtBatLockStatus.UnLock
|
|
&& i.Exists == 0);
|
|
if (list.Count <= 0)
|
|
{
|
|
orderBatteryInfo.CanSwap = InfoEnum.SelectBinStatusInfo.LessOfEmptyBin;
|
|
return;
|
|
}
|
|
|
|
orderBatteryInfo.InBinInfo = list[0];
|
|
orderBatteryInfo.CanSwap = InfoEnum.SelectBinStatusInfo.Success;
|
|
}
|
|
} |