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.

527 lines
19 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

using Autofac;
using AutoMapper;
using Entity.Attr;
using Entity.Constant;
using Entity.DbModel.Station;
using Entity.Dto;
using HybirdFrameworkCore.Autofac;
using log4net;
using Repository.Station;
using Service.Cloud.Msg.Cloud.Resp;
using Service.Execute.Api;
using Service.Execute.Model;
using Service.Execute.Model.Tbox;
using Service.Execute.StaticTools;
using Service.Execute.SwapException;
using Service.Execute.Utils;
using Service.Init;
using Service.Station;
namespace Service.Execute.Step;
public class CarPrepareState : IState
{
private readonly ILog _log = LogManager.GetLogger(typeof(CarPrepareState));
private readonly CommonMgr _CommonMgr = AppInfo.Container.Resolve<CommonMgr>();
private readonly SwapOrderBatteryRepository _swapOrderBatteryRepository =
AppInfo.Container.Resolve<SwapOrderBatteryRepository>();
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连接
if (StaticStationInfo.TboxStateConnect)
{
InvokeStatus tboxConnect = TboxConnect(machine);
if (tboxConnect != InvokeStatus.Done)
{
return SwappingStateMachine.ReturnWithInvokeErr(tboxConnect, 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);
}
//读取车辆在拍照位置
InvokeStatus plcPhotoReady = CarInPhotoPosition(machine);
if (plcPhotoReady != InvokeStatus.Done)
{
return SwappingStateMachine.ReturnWithInvokeErr(plcPhotoReady, ExceptionReason.None);
}
//拍照
InvokeStatus takePhoto = TakePhoto(machine);
if (takePhoto != InvokeStatus.Done)
{
return SwappingStateMachine.ReturnWithInvokeErr(takePhoto, ExceptionReason.None);
}
//查看通道状态
StateResult checkChannelStatus = CheckChannelStatus(machine);
if (checkChannelStatus != null)
{
return checkChannelStatus;
}
return new StateResult()
{
SwappingState = SwappingState.CarCtrl
};
}
/// <summary>
/// 查看通道状态
/// :0无效值
/// 1000;拍照OK
///1010;拍照NG
///1020;拍照超限,请移车
/// </summary>
/// <returns></returns>
public StateResult CheckChannelStatus(SwappingStateMachine machine)
{
int count = 0;
while (!machine.ChannelStatusOkFlag)
{
if (machine.CancelFlag)
{
_log.Info($" CheckChannelStatus canceled");
return StateResult.Cancel;
}
_log.Info("begin plc CheckChannelStatus");
Thread.Sleep(2000);
var channelStatus = PlcApi.ChannelStatus();
if (count % 10 == 0)
{
SoundApi.PlayOneSound((int)InfoEnum.SwapInfo.CarTakePhotoInfo);
}
count++;
if (channelStatus == 1000)
{
machine.ChannelStatusOkFlag = true;
return null;
}
else if (channelStatus == 1020)
{
//需要移车 先解锁 提示移动车辆,等待3分钟
if (PlcApi.PlcCarInit())
{
// machine.LedTool?.WriteProgramContent(InfoEnum.SwapInfo.ErrChannelStatus.GetLed());
SoundApi.PlayOneSound((int)InfoEnum.SwapInfo.ErrChannelStatus);
//等待2分钟
Thread.Sleep(3 * 60 * 1000);
machine.SwapStatus = (int)InfoEnum.SwapOrderResult.Fail;
machine.SwapFailReason = "拍照故障 plc故障码1020";
//回归到本阶段的读锁止状态
return new StateResult()
{
SwappingState = SwappingState.SwapDone
};
}
}
else if (channelStatus == 1010)
{
//故障 不能继续换电,提示驶离,上报云平台,修改换电订单
machine.SwapStatus = (int)InfoEnum.SwapOrderResult.Fail;
machine.SwapFailReason = "拍照故障 plc故障码1010";
//跳转到SwappDone
return new StateResult()
{
SwappingState = SwappingState.SwapDone
};
}
}
return null;
}
/// <summary>
/// 拍照准备
/// </summary
/// <returns></returns>
public InvokeStatus CarInPhotoPosition(SwappingStateMachine machine)
{
return Invoker.Invoke("Car In Photo Position", 500, 10, machine.IsCanceled,
() => machine.CarInPhotoPositionFlag, () =>
{
machine.CarInPhotoPositionFlag = PlcApi.CarInPhotoPosition();
}, () =>
{
machine.ExceptionReason = ExceptionReason.CarInPhotoPositionError;
// SoundApi.PlayOneSound((int)InfoEnum.SwapInfo.ErrorTBoxConn);
}, false, () =>
{
machine.ExceptionReason = ExceptionReason.CarInPhotoPositionError;
}
, 20, InvokeStatus.None);
}
/// <summary>
/// 启动拍照
/// </summary
/// <returns></returns>
public InvokeStatus TakePhoto(SwappingStateMachine machine)
{
bool takePhotoFlag = false;
return Invoker.Invoke("Take Photo", 500, 10, machine.IsCanceled,
() => takePhotoFlag, () =>
{
takePhotoFlag = PlcApi.TakPhoto();
});
}
/// <summary>
/// 车辆到位
/// </summary>
/// <returns></returns>
public InvokeStatus CarInPosition(SwappingStateMachine machine)
{
return Invoker.Invoke("check CarInPosition", 500, 5, machine.IsCanceled,
() => machine.VehiclesInPlaceFlag, () =>
{
var result = TBoxApi.GetCarInfo(machine.RfidReadModel.VelVin);
int succCount = 0;
List<bool> succL = new List<bool>()
{
StaticStationInfo.TboxStateFlameout, StaticStationInfo.TboxStateBreak, StaticStationInfo.TboxStateN
};
var successCount = succL.Where(i => i).Count();
TboxCarInfoModel tboxCarInfoModel = result.Result;
var status = tboxCarInfoModel?.CarStatus;
PlcApi.ReadyPlcPhoto();
if (StaticStationInfo.TboxStateFlameout)
{
if (status?.Keys == 0)
{
succCount++;
}
}
if (StaticStationInfo.TboxStateBreak)
{
if (status?.Break == 1)
{
succCount++;
}
}
if (StaticStationInfo.TboxStateN)
{
if (status?.Gear == 0)
{
succCount++;
}
}
if (succCount == successCount)
{
machine.VehiclesInPlaceFlag = true;
//写入口等 :红灯
if (PlcApi.WriteEntranceLamp(1020))
{
// machine.LedTool?.WriteProgramContent(InfoEnum.SwapInfo.InfoCarInPosition.GetLed());
SoundApi.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();
_CommonMgr.InsertStep(InfoEnum.BusinessSwappingStep.CarInPositionFlag,
machine);
machine.BoxCarInfoModel = tboxCarInfoModel;
}
}
}, () =>
{
machine.ExceptionReason = ExceptionReason.CarInPositionError;
// machine.LedTool?.WriteProgramContent(InfoEnum.SwapInfo.ErrorCarInPositionTimeout.GetLed());
SoundApi.PlayOneSound((int)InfoEnum.SwapInfo.ErrorCarInPositionTimeout);
}, false, () => { }
, 10, InvokeStatus.None);
}
/// <summary>
/// 云平台车辆认证
/// </summary>
/// <returns></returns>
public InvokeStatus CloudCheckVel(SwappingStateMachine machine)
{
return Invoker.Invoke("cloud check vehicle", 500, 20, machine.IsCanceled,
() => machine.CloudVelCheckFlag, () =>
{
if (StationConstant.StationModel.Remote ==
BaseEnumExtensions.GetEnumByCode<StationConstant.StationModel>(
StaticStationInfo.StationModel))
{
CarAuthRes? vehicleCertificationResp =
CloudApi.VehicleCheck(machine.RfidReadModel, machine.SwapOrder);
if (vehicleCertificationResp == null || vehicleCertificationResp.re != 0)
{
_log.Info("cloud check vehicle error");
// machine.LedTool?.WriteProgramContent("换电准备中:云平台车辆验证完成");
}
else
{
machine.ExceptionReason = ExceptionReason.None;
_log.Info("cloud check vehicle done");
machine.CloudVelCheckFlag = true;
// machine.LedTool?.WriteProgramContent("换电准备中:云平台车辆验证完成");
machine.SwapOrder.CloudSn = vehicleCertificationResp.on;
_CommonMgr.InsertStep(InfoEnum.BusinessSwappingStep.CloudVelCheckFlag,
machine);
}
}
else
{
machine.CloudVelCheckFlag = true;
}
}, () =>
{
// machine.LedTool?.WriteProgramContent(InfoEnum.SwapInfo.ErrorCloudCheck.GetLed());
SoundApi.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, 10, machine.IsCanceled,
() => machine.BoxConnectFlag, () =>
{
Task<bool> result = TBoxApi.IsConnected(machine.RfidReadModel.VelVin);
bool isConnect = result.Result;
if (isConnect)
{
machine.BoxConnectFlag = true;
}
}, () =>
{
machine.ExceptionReason = ExceptionReason.ConnTBoxError;
SoundApi.PlayOneSound((int)InfoEnum.SwapInfo.ErrorTBoxConn);
}, false, () =>
{
machine.ExceptionReason = ExceptionReason.ConnTBoxError;
// machine.LedTool?.WriteProgramContent(InfoEnum.SwapInfo.ErrorTBoxConn.GetLed());
}
, 20, InvokeStatus.None);
}
/// <summary>
/// 连接TBox
/// </summary
/// <returns></returns>
public InvokeStatus TboxConnect(SwappingStateMachine machine)
{
return Invoker.Invoke("TBox connect", 1000, 10, machine.IsCanceled,
() => machine.BoxConnectFlag, () =>
{
Task<bool> result = TBoxApi.Connect(machine.RfidReadModel.VelVin);
bool isConnect = result.Result;
if (isConnect)
{
//读取车辆carNo=carVin
Task<TboxCarInfoModel> carInfoResult = TBoxApi.GetCarInfo(machine.RfidReadModel.VelVin);
var tboxCarInfoModel = carInfoResult.Result;
var carInfo = tboxCarInfoModel?.CarInfo;
if (carInfo != null)
{
if (carInfo.CarNo.Equals(carInfo.CarVin))
{
machine.BoxConnectFlag = true;
}
}
}
}, () =>
{
machine.ExceptionReason = ExceptionReason.ConnTBoxError;
SoundApi.PlayOneSound((int)InfoEnum.SwapInfo.ErrorTBoxConn);
}, false, () =>
{
machine.ExceptionReason = ExceptionReason.ConnTBoxError;
// machine.LedTool?.WriteProgramContent(InfoEnum.SwapInfo.ErrorTBoxConn.GetLed());
}
, 20, 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(machine.RfidReadModel.VelVin);
var tBoxCarInfoModel = carInfo.Result;
if (tBoxCarInfoModel.CarNo!.Trim().Equals(machine.RfidReadModel!.VelVin.Trim()))
{
machine.BoxLocalCheckFlag = true;
machine.BoxCarInfoModel = tBoxCarInfoModel;
}
}, () => { 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(machine.RfidReadModel.VelVin);
TboxCarInfoModel tBoxCarInfoModel = result.Result;
machine.BoxCarInfoModel = tBoxCarInfoModel;
if (tBoxCarInfoModel != null)
{
if (tBoxCarInfoModel.Connected)
{
//将数据上报云平台
// CloudApi.UploadTBoxCarInfo(machine.SwapOrder!, machine.BoxCarInfoModel);
}
}
}, () =>
{
// machine.LedTool?.WriteProgramContent("车辆电池数据上报异常,请联系站务人员");
// SoundApi.PlayOneSound(InfoEnum.SwapInfo.ErrorSelectPack);
}, 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 = _CommonMgr.QueryAmtOrder(machine);
return Invoker.Invoke("selectPack", 1000, 10, machine.IsCanceled,
() => machine.SelectPackFlag, () =>
{
SwapOrderBatteryInfo orderBatteryInfo = null;
if (swapAmtOrder != null)
{
orderBatteryInfo = _CommonMgr.SelectPackArm(swapAmtOrder, machine);
}
else
{
orderBatteryInfo = _CommonMgr.SelectPackNotArm(machine);
}
if (orderBatteryInfo.CanSwap != InfoEnum.SelectBinStatusInfo.Success)
{
// machine.LedTool?.WriteProgramContent(InfoEnum.SwapInfo.ErrorSelectPack.GetLed());
_log.Info($"SelectPack error CanSwap={machine.SwapOrderBatteryInfo.CanSwap}");
}
else
{
//选包成功
_CommonMgr.LockBinAndUpdateAmt(orderBatteryInfo);
machine.SwapOrderBatteryInfo = orderBatteryInfo;
machine.SelectPackFlag = true;
}
}, () =>
{
machine.ExceptionReason = ExceptionReason.SelectPackError;
SoundApi.PlayOneSound((int)InfoEnum.SwapInfo.ErrorSelectPack);
}
, false, () => { }, 10, InvokeStatus.None);
}
}