换电流程 CarPrepareState

zw
lxw 6 months ago
parent b195a52329
commit 3bd1a56865

@ -13,9 +13,7 @@ namespace Entity.Api.Req
/// <summary> /// <summary>
/// Desc:订单编号 /// 订单编号
/// Default:
/// Nullable:True
/// </summary> /// </summary>
public string? Sn {get;set;} public string? Sn {get;set;}

@ -204,5 +204,12 @@ namespace Entity.Api.Resp
/// </summary> /// </summary>
public DateTime? UpdatedTime {get;set;} public DateTime? UpdatedTime {get;set;}
/// <summary>
/// 云平台订单号
/// </summary>
public string? CloudSn { get; set; }
} }
} }

@ -0,0 +1,30 @@
using System.ComponentModel;
using System.Reflection;
namespace Entity.Constant;
public class BaseEnumExtensions
{
//根据枚举获取注释
public static string GetDescription(Enum value)
{
FieldInfo field = value.GetType().GetField(value.ToString());
DescriptionAttribute attribute =
Attribute.GetCustomAttribute(field, typeof(DescriptionAttribute)) as DescriptionAttribute;
return attribute == null ? value.ToString() : attribute.Description;
}
//根据code获取枚举
public static T GetEnumByCode<T>(int code) where T : Enum
{
return (T)Enum.ToObject(typeof(T), code);
}
//根据code获取值
public static string GetEnumDescriptionByCode<T>(int code) where T : Enum
{
return GetDescription((T)Enum.ToObject(typeof(T), code));
}
}

@ -47,17 +47,7 @@ public class StationConstant
} }
public static class EnumExtensions
{
public static string GetDescription( Enum value)
{
FieldInfo field = value.GetType().GetField(value.ToString());
DescriptionAttribute attribute = Attribute.GetCustomAttribute(field, typeof(DescriptionAttribute)) as DescriptionAttribute;
return attribute == null ? value.ToString() : attribute.Description;
}
}
} }

@ -191,5 +191,18 @@ namespace Entity.DbModel.Station
[SugarColumn(ColumnName="updated_time")] [SugarColumn(ColumnName="updated_time")]
public DateTime? UpdatedTime {get;set;} public DateTime? UpdatedTime {get;set;}
/// <summary>
/// 电池是否在为
/// 0:不在位 1在位 2无效
/// </summary>
[SugarColumn(ColumnName="exists")]
public int? Exists { get; set; }
/// <summary>
/// 最后结束充电的时间
/// </summary>
[SugarColumn(ColumnName="last_charge_finish_time")]
public DateTime? LastChargeFinishTime { get; set; }
} }
} }

@ -151,5 +151,10 @@ namespace Entity.DbModel.Station
[SugarColumn(ColumnName="updated_time")] [SugarColumn(ColumnName="updated_time")]
public DateTime? UpdatedTime {get;set;} public DateTime? UpdatedTime {get;set;}
/// <summary>
/// 车牌
/// </summary>
public string VehicleNo { get; set; }
} }
} }

@ -11,137 +11,141 @@ namespace Entity.DbModel.Station
[SugarTable("swap_order")] [SugarTable("swap_order")]
public partial class SwapOrder public partial class SwapOrder
{ {
public SwapOrder(){ public SwapOrder()
{
} }
/// <summary> /// <summary>
/// Desc:id /// Desc:id
/// Default: /// Default:
/// Nullable:False /// Nullable:False
/// </summary> /// </summary>
[SugarColumn(IsPrimaryKey=true,IsIdentity=true,ColumnName="id")] [SugarColumn(IsPrimaryKey = true, IsIdentity = true, ColumnName = "id")]
public int Id {get;set;} public int Id { get; set; }
/// <summary> /// <summary>
/// Desc:订单编号 /// Desc:订单编号
/// Default: /// Default:
/// Nullable:True /// Nullable:True
/// </summary> /// </summary>
[SugarColumn(ColumnName="sn")] [SugarColumn(ColumnName = "sn")]
public string Sn {get;set;} public string Sn { get; set; }
/// <summary> /// <summary>
/// Desc:车牌号 /// Desc:车牌号
/// Default: /// Default:
/// Nullable:True /// Nullable:True
/// </summary> /// </summary>
[SugarColumn(ColumnName="vehicle_no")] [SugarColumn(ColumnName = "vehicle_no")]
public string VehicleNo {get;set;} public string VehicleNo { get; set; }
/// <summary> /// <summary>
/// Desc:车辆mac /// Desc:车辆mac
/// Default: /// Default:
/// Nullable:True /// Nullable:True
/// </summary> /// </summary>
[SugarColumn(ColumnName="vehicle_mac")] [SugarColumn(ColumnName = "vehicle_mac")]
public string VehicleMac {get;set;} public string VehicleMac { get; set; }
/// <summary> /// <summary>
/// Desc:车辆vin码 /// Desc:车辆vin码
/// Default: /// Default:
/// Nullable:True /// Nullable:True
/// </summary> /// </summary>
[SugarColumn(ColumnName="vehicle_vin")] [SugarColumn(ColumnName = "vehicle_vin")]
public string VehicleVin {get;set;} public string VehicleVin { get; set; }
/// <summary> /// <summary>
/// Desc:车辆进场时间 /// Desc:车辆进场时间
/// Default: /// Default:
/// Nullable:True /// Nullable:True
/// </summary> /// </summary>
[SugarColumn(ColumnName="vehicle_enter_time")] [SugarColumn(ColumnName = "vehicle_enter_time")]
public DateTime? VehicleEnterTime {get;set;} public DateTime? VehicleEnterTime { get; set; }
/// <summary> /// <summary>
/// Desc:车辆离场时间 /// Desc:车辆离场时间
/// Default: /// Default:
/// Nullable:True /// Nullable:True
/// </summary> /// </summary>
[SugarColumn(ColumnName="vehicle_leave_time")] [SugarColumn(ColumnName = "vehicle_leave_time")]
public DateTime? VehicleLeaveTime {get;set;} public DateTime? VehicleLeaveTime { get; set; }
/// <summary> /// <summary>
/// Desc:换电开始时间 /// Desc:换电开始时间
/// Default: /// Default:
/// Nullable:True /// Nullable:True
/// </summary> /// </summary>
[SugarColumn(ColumnName="swap_begin_time")] [SugarColumn(ColumnName = "swap_begin_time")]
public DateTime? SwapBeginTime {get;set;} public DateTime? SwapBeginTime { get; set; }
/// <summary> /// <summary>
/// Desc:换电结束时间 /// Desc:换电结束时间
/// Default: /// Default:
/// Nullable:True /// Nullable:True
/// </summary> /// </summary>
[SugarColumn(ColumnName="swap_end_time")] [SugarColumn(ColumnName = "swap_end_time")]
public DateTime? SwapEndTime {get;set;} public DateTime? SwapEndTime { get; set; }
/// <summary> /// <summary>
/// Desc:换电结果;0-未知1-成功2-失败 /// Desc:换电结果;0-未知1-成功2-失败
/// Default:0 /// Default:0
/// Nullable:True /// Nullable:True
/// </summary> /// </summary>
[SugarColumn(ColumnName="swap_result")] [SugarColumn(ColumnName = "swap_result")]
public int? SwapResult {get;set;} public int? SwapResult { get; set; }
/// <summary> /// <summary>
/// Desc:失败原因 /// Desc:失败原因
/// Default: /// Default:
/// Nullable:True /// Nullable:True
/// </summary> /// </summary>
[SugarColumn(ColumnName="fail_reason")] [SugarColumn(ColumnName = "fail_reason")]
public string FailReason {get;set;} public string FailReason { get; set; }
/// <summary> /// <summary>
/// Desc:上传云平台状态;0-未上传1-已上传 /// Desc:上传云平台状态;0-未上传1-已上传
/// Default:0 /// Default:0
/// Nullable:True /// Nullable:True
/// </summary> /// </summary>
[SugarColumn(ColumnName="cloud_report_status")] [SugarColumn(ColumnName = "cloud_report_status")]
public int? CloudReportStatus {get;set;} public int? CloudReportStatus { get; set; }
/// <summary> /// <summary>
/// Desc:创建人 /// Desc:创建人
/// Default: /// Default:
/// Nullable:True /// Nullable:True
/// </summary> /// </summary>
[SugarColumn(ColumnName="created_by")] [SugarColumn(ColumnName = "created_by")]
public string CreatedBy {get;set;} public string CreatedBy { get; set; }
/// <summary> /// <summary>
/// Desc:创建时间 /// Desc:创建时间
/// Default:CURRENT_TIMESTAMP /// Default:CURRENT_TIMESTAMP
/// Nullable:True /// Nullable:True
/// </summary> /// </summary>
[SugarColumn(ColumnName="created_time")] [SugarColumn(ColumnName = "created_time")]
public DateTime? CreatedTime {get;set;} public DateTime? CreatedTime { get; set; }
/// <summary> /// <summary>
/// Desc:更新人 /// Desc:更新人
/// Default: /// Default:
/// Nullable:True /// Nullable:True
/// </summary> /// </summary>
[SugarColumn(ColumnName="updated_by")] [SugarColumn(ColumnName = "updated_by")]
public string UpdatedBy {get;set;} public string UpdatedBy { get; set; }
/// <summary> /// <summary>
/// Desc:更新时间 /// Desc:更新时间
/// Default:CURRENT_TIMESTAMP /// Default:CURRENT_TIMESTAMP
/// Nullable:True /// Nullable:True
/// </summary> /// </summary>
[SugarColumn(ColumnName="updated_time")] [SugarColumn(ColumnName = "updated_time")]
public DateTime? UpdatedTime {get;set;} public DateTime? UpdatedTime { get; set; }
/// <summary>
/// 云平台订单号
/// </summary>
[SugarColumn(ColumnName = "cloud_sn")]
public string? CloudSn { get; set; }
} }
} }

@ -27,10 +27,6 @@
<PackageReference Include="Yitter.IdGenerator" Version="1.0.14" /> <PackageReference Include="Yitter.IdGenerator" Version="1.0.14" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<Folder Include="DbModel\Station\" />
</ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Common\Common.csproj" /> <ProjectReference Include="..\Common\Common.csproj" />
<ProjectReference Include="..\HybirdFrameworkCore\HybirdFrameworkCore.csproj" /> <ProjectReference Include="..\HybirdFrameworkCore\HybirdFrameworkCore.csproj" />

@ -26,6 +26,8 @@
<PackageReference Include="Swashbuckle.AspNetCore.Swagger" Version="6.5.0" /> <PackageReference Include="Swashbuckle.AspNetCore.Swagger" Version="6.5.0" />
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerGen" Version="6.5.0" /> <PackageReference Include="Swashbuckle.AspNetCore.SwaggerGen" Version="6.5.0" />
<PackageReference Include="Swashbuckle.AspNetCore.SwaggerUI" Version="6.5.0" /> <PackageReference Include="Swashbuckle.AspNetCore.SwaggerUI" Version="6.5.0" />
<PackageReference Include="Vse.Web.Serialization.ControlledSerializationJsonConverter" Version="1.0.3" />
<PackageReference Include="WebApiContrib.Formatting.JavaScriptSerializer" Version="0.9.2" />
</ItemGroup> </ItemGroup>
</Project> </Project>

@ -18,6 +18,8 @@
"Swashbuckle.AspNetCore.Swagger": "6.5.0", "Swashbuckle.AspNetCore.Swagger": "6.5.0",
"Swashbuckle.AspNetCore.SwaggerGen": "6.5.0", "Swashbuckle.AspNetCore.SwaggerGen": "6.5.0",
"Swashbuckle.AspNetCore.SwaggerUI": "6.5.0", "Swashbuckle.AspNetCore.SwaggerUI": "6.5.0",
"Vse.Web.Serialization.ControlledSerializationJsonConverter": "1.0.3",
"WebApiContrib.Formatting.JavaScriptSerializer": "0.9.2",
"log4net": "2.0.15" "log4net": "2.0.15"
}, },
"runtime": { "runtime": {
@ -57,6 +59,18 @@
} }
} }
}, },
"Microsoft.AspNet.WebApi.Client/4.0.20710": {
"dependencies": {
"Microsoft.Net.Http": "2.0.20710",
"Newtonsoft.Json": "13.0.3"
},
"runtime": {
"lib/net40/System.Net.Http.Formatting.dll": {
"assemblyVersion": "4.0.0.0",
"fileVersion": "4.0.20710.0"
}
}
},
"Microsoft.CSharp/4.7.0": {}, "Microsoft.CSharp/4.7.0": {},
"Microsoft.Extensions.ApiDescription.Server/6.0.5": {}, "Microsoft.Extensions.ApiDescription.Server/6.0.5": {},
"Microsoft.Extensions.Configuration/7.0.0": { "Microsoft.Extensions.Configuration/7.0.0": {
@ -156,6 +170,7 @@
} }
} }
}, },
"Microsoft.Net.Http/2.0.20710": {},
"Microsoft.NETCore.Platforms/2.0.0": {}, "Microsoft.NETCore.Platforms/2.0.0": {},
"Microsoft.OpenApi/1.2.3": { "Microsoft.OpenApi/1.2.3": {
"runtime": { "runtime": {
@ -317,6 +332,25 @@
"fileVersion": "7.0.22.51805" "fileVersion": "7.0.22.51805"
} }
} }
},
"Vse.Web.Serialization.ControlledSerializationJsonConverter/1.0.3": {
"runtime": {
"lib/net45/Vse.Web.Serialization.dll": {
"assemblyVersion": "1.0.3.0",
"fileVersion": "1.0.3.0"
}
}
},
"WebApiContrib.Formatting.JavaScriptSerializer/0.9.2": {
"dependencies": {
"Microsoft.AspNet.WebApi.Client": "4.0.20710"
},
"runtime": {
"lib/net40/WebApiContrib.Formatting.JavaScriptSerializer.dll": {
"assemblyVersion": "0.0.0.0",
"fileVersion": "0.0.0.0"
}
}
} }
} }
}, },
@ -347,6 +381,13 @@
"path": "log4net/2.0.15", "path": "log4net/2.0.15",
"hashPath": "log4net.2.0.15.nupkg.sha512" "hashPath": "log4net.2.0.15.nupkg.sha512"
}, },
"Microsoft.AspNet.WebApi.Client/4.0.20710": {
"type": "package",
"serviceable": true,
"sha512": "sha512-BwFtW0cGr8tg02XalvF8MmznOpYrhquD2eXWI0oF3LLSqLMFoFkb8Pmke/7SnqkiNc+YfsaUqdXEKbjhv1Ctrw==",
"path": "microsoft.aspnet.webapi.client/4.0.20710",
"hashPath": "microsoft.aspnet.webapi.client.4.0.20710.nupkg.sha512"
},
"Microsoft.CSharp/4.7.0": { "Microsoft.CSharp/4.7.0": {
"type": "package", "type": "package",
"serviceable": true, "serviceable": true,
@ -424,6 +465,13 @@
"path": "microsoft.extensions.primitives/7.0.0", "path": "microsoft.extensions.primitives/7.0.0",
"hashPath": "microsoft.extensions.primitives.7.0.0.nupkg.sha512" "hashPath": "microsoft.extensions.primitives.7.0.0.nupkg.sha512"
}, },
"Microsoft.Net.Http/2.0.20710": {
"type": "package",
"serviceable": true,
"sha512": "sha512-OsB/5QO9tYJRLYIgBOhRl4Tssh3pw7+UAO9tMGMBg63f98GfjsniVIwLWRC0vcRr/F6HLP/NvRlHyGBhtD7Bmw==",
"path": "microsoft.net.http/2.0.20710",
"hashPath": "microsoft.net.http.2.0.20710.nupkg.sha512"
},
"Microsoft.NETCore.Platforms/2.0.0": { "Microsoft.NETCore.Platforms/2.0.0": {
"type": "package", "type": "package",
"serviceable": true, "serviceable": true,
@ -556,6 +604,20 @@
"sha512": "sha512-DaGSsVqKsn/ia6RG8frjwmJonfos0srquhw09TlT8KRw5I43E+4gs+/bZj4K0vShJ5H9imCuXupb4RmS+dBy3w==", "sha512": "sha512-DaGSsVqKsn/ia6RG8frjwmJonfos0srquhw09TlT8KRw5I43E+4gs+/bZj4K0vShJ5H9imCuXupb4RmS+dBy3w==",
"path": "system.text.json/7.0.0", "path": "system.text.json/7.0.0",
"hashPath": "system.text.json.7.0.0.nupkg.sha512" "hashPath": "system.text.json.7.0.0.nupkg.sha512"
},
"Vse.Web.Serialization.ControlledSerializationJsonConverter/1.0.3": {
"type": "package",
"serviceable": true,
"sha512": "sha512-eG8d1pOgu/espdIFfi9iAEE890oT9k5h/61RY9hpfu4+s1cozrZAkuwpHif6UadgKfexa5/BEVBZ8DNH1eA10w==",
"path": "vse.web.serialization.controlledserializationjsonconverter/1.0.3",
"hashPath": "vse.web.serialization.controlledserializationjsonconverter.1.0.3.nupkg.sha512"
},
"WebApiContrib.Formatting.JavaScriptSerializer/0.9.2": {
"type": "package",
"serviceable": true,
"sha512": "sha512-OHJxwvqZhrpIw5fz7058vEiGHozBE/GGfnWMWrd/DnZC4fXwCZPKKqiyvzqq5KWQw/xf1jZ+e0ip/m6M2ZiEpw==",
"path": "webapicontrib.formatting.javascriptserializer/0.9.2",
"hashPath": "webapicontrib.formatting.javascriptserializer.0.9.2.nupkg.sha512"
} }
} }
} }

@ -0,0 +1,14 @@
using Entity.DbModel.Station;
using HybirdFrameworkCore.Autofac.Attribute;
using SqlSugar;
namespace Repository.Station;
[Scope("SingleInstance")]
public class BinInfoRepository:BaseRepository<BinInfo>
{
public BinInfoRepository(ISqlSugarClient sqlSugar) : base(sqlSugar)
{
}
}

@ -0,0 +1,14 @@
using Entity.DbModel.Station;
using HybirdFrameworkCore.Autofac.Attribute;
using SqlSugar;
namespace Repository.Station;
[Scope("SingleInstance")]
public class SwapAmtOrderRepository:BaseRepository<SwapAmtOrder>
{
public SwapAmtOrderRepository(ISqlSugarClient sqlSugar) : base(sqlSugar)
{
}
}

@ -1,6 +1,38 @@
using Entity.DbModel.Station;
using log4net;
using Service.Execute.Enum;
using Service.Execute.Model;
namespace Service.Execute.Api; namespace Service.Execute.Api;
public class CloudApi public class CloudApi
{ {
/// <summary>
/// 云平台车辆认证
/// </summary>
/// <param name="rfidReadModel"></param>
/// <returns></returns>
public static bool VehicleCheck(RfidReadModel rfidReadModel)
{
return true;
}
/// <summary>
/// 上报换电步序到云端
/// </summary>
/// <param name="swapOrder"></param>
/// <param name="state"></param>
public static void SendStateLog(SwapOrder swapOrder, InfoEnum.BusinessSwappingForCloudState state)
{
return;
}
/// <summary>
/// 上报tbox数据
/// </summary>
public static void UploadTBoxCarInfo(SwapOrder swapOrder, TboxCarInfoModel model)
{
return ;
}
} }

@ -33,4 +33,16 @@ public class PlcApi
//TODO:: //TODO::
return true; return true;
} }
/// <summary>
/// 写入口灯
/// 红灯1020
/// 绿灯1000
/// </summary>
/// <param name="data"></param>
/// <returns></returns>
public static bool WriteEntranceLamp(int data)
{
return true;
}
} }

@ -1,6 +1,6 @@
using log4net; using log4net;
using Newtonsoft.Json; using Newtonsoft.Json;
using Swapping.Business.Rfid; using Service.Execute.Model;
namespace Service.Execute.Api; namespace Service.Execute.Api;

@ -1,6 +1,65 @@
using log4net;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Service.Execute.Model;
namespace Service.Execute.Api; namespace Service.Execute.Api;
public class TBoxApi public class TBoxApi
{ {
private static readonly ILog Log = LogManager.GetLogger(typeof(TBoxApi));
//TODO::TBox 服务地址
private static readonly string BASE_URL = "http://localhost:7243";
private static readonly HttpClient _httpClient = new HttpClient()
{
Timeout = TimeSpan.FromSeconds(60)
};
public static async Task<TboxCarInfoModel> GetCarInfo()
{
Log.Info("GetCarInfo");
string url = BASE_URL + "/CarControl/getCarInfo";
try
{
string s = await _httpClient.GetStringAsync(url);
TboxCarInfoModel? tboxCarInfoModel = null;
if (!String.IsNullOrWhiteSpace(s))
{
tboxCarInfoModel = JsonConvert.DeserializeObject<TboxCarInfoModel>(s);
}
Log.Info($"GetCarInfo resp = {tboxCarInfoModel}");
return tboxCarInfoModel;
}
catch (Exception e)
{
Console.WriteLine(e);
return null;
}
}
public static async Task<bool> IsConnected()
{
Log.Info("IsConnected");
string url = BASE_URL + "/CarControl/getCarInfo";
try
{
string s = await _httpClient.GetStringAsync(url);
TboxCarInfoModel? tboxCarInfoModel = null;
if (!String.IsNullOrWhiteSpace(s))
{
tboxCarInfoModel = JsonConvert.DeserializeObject<TboxCarInfoModel>(s);
}
Log.Info($"GetCarInfo resp = {tboxCarInfoModel}");
return tboxCarInfoModel.Connected;
}
catch (Exception e)
{
Console.WriteLine(e);
return false;
}
}
} }

@ -45,7 +45,6 @@ public class InfoEnum
[Remark("符合soc限制数量不足")] LessOfSoc, [Remark("符合soc限制数量不足")] LessOfSoc,
[Remark("结束充电大于3分钟的数量不足")] LessOf3Minute, [Remark("结束充电大于3分钟的数量不足")] LessOf3Minute,
[Remark("各种差数量不足")] LessOfMean, [Remark("各种差数量不足")] LessOfMean,
[Remark("未被预约数量不足")] LessOfUnAmt,
[Remark("预约电池异常")] AmtError, [Remark("预约电池异常")] AmtError,
[Remark("电池捆绑选包失败")] GroupError, [Remark("电池捆绑选包失败")] GroupError,
[Remark("无可用捆绑")] NoGroupError [Remark("无可用捆绑")] NoGroupError
@ -63,22 +62,21 @@ public class InfoEnum
[Remark("预约失败")] Expire = 7, [Remark("预约失败")] Expire = 7,
} }
public enum BusinessSwappingState : byte public enum BusinessSwappingForCloudState : byte
{ {
[Remark("未知")] UnKnown, [Remark("未知")] UnKnown,
[Remark("空闲")] Idle, [Remark("空闲")] Idle,
[Remark("RFID扫描完成")] ScanRfid, [Remark("占位")] TakeUp,
[Remark("云平台验证完成")] CloudCheck, [Remark("换电准备")] SwapReady,
[Remark("车辆到位")] CarInPosition,
[Remark("车辆准备完成N档、手刹")] CarPrepare,
[Remark("云平台启动换电完成")] CloudBeginSwap,
[Remark("车辆调整完成(下高压、下低压)")] CarAdjust,
[Remark("开始换电")] BeginSwap, [Remark("开始换电")] BeginSwap,
[Remark("拆卸亏电包")] UnPack, [Remark("换电中")] Swapping,
[Remark("安装满电包")] Pack, [Remark("换电完成")] SwapFinish,
[Remark("包安装完成")] PackFinish, [Remark("换电中故障,等待修复")] SwappingErrWait,
[Remark("车辆自检")] CarSelfCheck, [Remark("换电中故障,修复完成")] SwappingErrDone,
[Remark("换电完成(车辆驶离)")] SwapDone [Remark("换电暂停")] SwapPause,
[Remark("换电继续")] SwapContinue,
[Remark("换电完成(车辆未驶离)")] SwapDoneWithVel,
[Remark("换电完成(车辆驶离)")] SwapDoneWithoutVel
} }
public enum AmtBatLockStatus : byte public enum AmtBatLockStatus : byte

@ -45,11 +45,12 @@ public class Invoker
return InvokeStatus.Done; return InvokeStatus.Done;
} }
public static InvokeStatus Invoke(string name, int duration, int times, Func<bool> cancel, Func<bool> done, public static InvokeStatus Invoke(string name, int duration, int times, Func<bool> cancel, Func<bool> done,
Action doAction, Action doAction,
Action timeoutAction, bool isTimeOutExit, Action exceptionAction) Action exceptionAction)
{ {
int hvPwrOffTimes = 0; int count = 0;
while (!done()) while (!done())
{ {
Log.Info($"begin {name}"); Log.Info($"begin {name}");
@ -70,22 +71,12 @@ public class Invoker
exceptionAction(); exceptionAction();
} }
if (hvPwrOffTimes++ > times)
{
timeoutAction();
Log.Info($" {name} timeout");
if (isTimeOutExit)
{
return InvokeStatus.TimeOut;
}
}
} }
Log.Info($" {name} done"); Log.Info($" {name} done");
return InvokeStatus.Done; return InvokeStatus.Done;
} }
public static InvokeStatus Invoke(string name, int duration, int times, Func<bool> cancel, Func<bool> done, public static InvokeStatus Invoke(string name, int duration, int times, Func<bool> cancel, Func<bool> done,
Action doAction, Action doAction,
Action timeoutAction, bool isTimeOutExit, Action exceptionAction, int timeOutActionTime,InvokeStatus timeOutException) Action timeoutAction, bool isTimeOutExit, Action exceptionAction, int timeOutActionTime,InvokeStatus timeOutException)
@ -163,5 +154,6 @@ public enum InvokeStatus
Cancel, Cancel,
TimeOut, TimeOut,
Done, Done,
Exception Exception,
None
} }

@ -1,4 +1,4 @@
namespace Swapping.Business.Rfid; namespace Service.Execute.Model;
public class RfidReadModel public class RfidReadModel
{ {

@ -0,0 +1,17 @@
using Entity.DbModel.Station;
using NewLife.Common;
using Service.Execute.Enum;
namespace Service.Execute.Model;
public class SwapOrderBatteryInfo
{
public bool isAmt;
public SwapAmtOrder swapAmtOrder;
public SwapOrderBattery SwapOrderBattery;
public InfoEnum.SelectBinStatusInfo CanSwap;
public BinInfo UpBinInfo;
public BinInfo InBinInfo;
}

@ -0,0 +1,27 @@
namespace Service.Execute.Model;
/// <summary>
/// 车辆数据
/// </summary>
public class TboxCarInfoModel
{
/// <summary>
/// 连接状态
/// </summary>
public bool Connected { get; set; }
/// <summary>
/// 车牌号
/// </summary>
public string? CarNo { get; set; }
/// <summary>
/// 度电数据
/// </summary>
public TboxElecMsg? ElecMsg { get; set; }
/// <summary>
/// 状态数据
/// </summary>
public TboxHeartBeatMsg? HeartBeatMsg { get; set; }
}

@ -0,0 +1,84 @@
using HybirdFrameworkCore.Autofac.Attribute;
namespace Service.Execute.Model;
public class TboxElecMsg
{
/// <summary>
/// 车辆累计放电量
/// </summary>
[Property(248, 24, scale: 0.01, round: 2)]
public double AccDischargeCount { get; set; }
/// <summary>
/// 车辆累计回馈电量
/// </summary>
[Property(272, 24, scale: 0.01, round: 2)]
public double AccFallbackCount { get; set; }
/// <summary>
/// 车辆累计插枪充电量
/// </summary>
[Property(296, 24, scale: 0.01, round: 2)]
public double AccChargeCount { get; set; }
/// <summary>
/// 5 车辆累计综合能耗
/// </summary>
[Property(320, 24, scale: 0.01, round: 2)]
public double AccKgce { get; set; }
/// <summary>
/// 6 本次实时放电量
/// </summary>
[Property(344, 24, scale: 0.01, round: 2)]
public double ThisTimeRealDischarge { get; set; }
/// <summary>
/// 7 上一次结算放电量
/// </summary>
[Property(368, 24, scale: 0.01, round: 2)]
public double LastTimeBalanceDischarge { get; set; }
/// <summary>
/// 8 本次实时回馈电量
/// </summary>
[Property(392, 24, scale: 0.01, round: 2)]
public double ThisTimeRealFeedbackPower { get; set; }
/// <summary>
/// 9 上一次结算回馈电量
/// </summary>
[Property(416, 24, scale: 0.01, round: 2)]
public double LastTimeBalanceFeedbackPower { get; set; }
/// <summary>
/// 10 本次实时插枪充电量
/// </summary>
[Property(440, 24, scale: 0.01, round: 2)]
public double ThisTimeRealChargeCount { get; set; }
/// <summary>
/// 11 上一次结算插枪充电量
/// </summary>
[Property(464, 24, scale: 0.01, round: 2)]
public double LastTimeBalanceChargeCount { get; set; }
/// <summary>
/// 12 本次实时综合能耗
/// </summary>
[Property(488, 24, scale: 0.01, round: 2)]
public double ThisTimeRealKgce { get; set; }
/// <summary>
/// 13 上一次结算综合能耗
/// </summary>
[Property(512, 24, scale: 0.01, round: 2)]
public double LastTimeBalanceKgce { get; set; }
/// <summary>
/// 14 待结算电费电量
/// </summary>
[Property(536, 24, scale: 0.01, round: 2)]
public double ElectricityToBeSettled { get; set; }
}

@ -0,0 +1,22 @@
using HybirdFrameworkCore.Autofac.Attribute;
namespace Service.Execute.Model;
public class TboxHeartBeatMsg
{
/// <summary>
/// 锁止状态 1 解锁状态 2 上锁状态
/// </summary>
[Property(248, 8)]
public byte LockStatus { get; set; }
/// <summary>
/// 钥匙状态 0: OFF 1: ACC 2: ON 0xFF: 不支持
/// </summary>
[Property(256, 8)]
public byte KeyStatus { get; set; }
/// <summary>
/// 电磁阀驱动状态 0驱动关闭 1驱动打开
/// </summary>
[Property(264, 8)]
public byte SolenoidValveStatus { get; set; }
}

@ -1,14 +1,446 @@
namespace Service.Execute.Step; 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 Swapping.Business.Tech;
public class CarPrepareState: IState namespace Service.Execute.Step;
public class CarPrepareState : IState
{ {
private readonly ILog _log = LogManager.GetLogger(typeof(CarPrepareState));
private BinInfoRepository BinInfoRepository { get; set; }
private SwapAmtOrderRepository AmtOrderRepository { get; set; }
private SwapOrderBatteryRepository SwapOrderBatteryRepository { get; set; }
public StateResult Handle(SwappingStateMachine machine) 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);
}
SwappingStateMachine.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() return new StateResult()
{ {
SwappingState = SwappingState.SelectPack
};
}
SwappingState = SwappingState.StationReady
/// <summary>
/// 车辆到位
/// </summary>
/// <returns></returns>
public InvokeStatus CarInPosition(SwappingStateMachine machine)
{
return Invoker.Invoke("check CarInPosition", 500, 50, machine.IsCanceled,
() => SwappingStateMachine.VehiclesInPlaceFlag, () =>
{
var result = TBoxApi.GetCarInfo();
TboxCarInfoModel tboxCarInfoModel = result.Result;
if (tboxCarInfoModel.HeartBeatMsg.KeyStatus == 0)
{
SwappingStateMachine.VehiclesInPlaceFlag = true;
//写入口等 :红灯
if (PlcApi.WriteEntranceLamp(1020))
{
machine.LedTool?.WriteProgramContent(InfoEnum.SwapInfo.InfoCarInPosition.GetLed());
SoundTool.PlayOneSound((int)InfoEnum.SwapInfo.InfoCarInPosition);
SwappingStateMachine.VehiclesInPlaceFlag = true;
}
}
}, () =>
{
SwappingStateMachine.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,
() => SwappingStateMachine.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
{
//置为换电准备中 ,上报换电准备中
SwappingStateMachine.BusinessSwappingForCloudState =
InfoEnum.BusinessSwappingForCloudState.SwapReady;
SwappingStateMachine.ExceptionReason = ExceptionReason.None;
_log.Info("cloud check vehicle done");
SwappingStateMachine.CloudVelCheckFlag = true;
machine.LedTool.WriteProgramContent("换电准备中:云平台车辆验证完成");
CloudApi.SendStateLog(machine.SwapOrder, SwappingStateMachine.BusinessSwappingForCloudState);
SwappingStateMachine.CloudVelCheckFlag = true;
}
}
else
{
SwappingStateMachine.CloudVelCheckFlag = true;
}
}, () =>
{
machine.LedTool?.WriteProgramContent(InfoEnum.SwapInfo.ErrorCloudCheck.GetLed());
SoundTool.PlayOneSound((int)InfoEnum.SwapInfo.ErrorCloudCheck);
}, false, () => { SwappingStateMachine.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,
() => SwappingStateMachine.TBoxConnectFlag, () =>
{
Task<bool> result = TBoxApi.IsConnected();
bool isConnect = result.Result;
if (isConnect)
{
SwappingStateMachine.TBoxConnectFlag = true;
}
}, () => { SwappingStateMachine.ExceptionReason = ExceptionReason.ConnTBoxError; }, false, () =>
{
SwappingStateMachine.ExceptionReason = ExceptionReason.ConnTBoxError;
}
, 10, InvokeStatus.None);
}
/// <summary>
/// 车辆本地验证:车牌校验
/// </summary>
/// <returns></returns>
public InvokeStatus CheckTBoxVelLocalFlag(SwappingStateMachine machine)
{
return Invoker.Invoke("check TBox VelLocal", 1000, 20, machine.IsCanceled,
() => SwappingStateMachine.TBoxLocalCheckFlag, () =>
{
Task<TboxCarInfoModel> carInfo = TBoxApi.GetCarInfo();
var tBoxCarInfoModel = carInfo.Result;
//TODO::不知道Tbox给的CardNo是什么
if (tBoxCarInfoModel.CarNo.Trim().Equals(machine.RfidReadModel.VelNo.Trim()))
{
SwappingStateMachine.TBoxLocalCheckFlag = true;
}
}, () => { SwappingStateMachine.ExceptionReason = ExceptionReason.LocalCheckVarError; }, true, () =>
{
SwappingStateMachine.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,
() => SwappingStateMachine.CloudTBoxFlag, () =>
{
Task<TboxCarInfoModel> result = TBoxApi.GetCarInfo();
TboxCarInfoModel tBoxCarInfoModel = result.Result;
machine.TBoxCarInfoModel = tBoxCarInfoModel;
if (tBoxCarInfoModel != null)
{
if (tBoxCarInfoModel.Connected)
{
//将数据上报云平台
CloudApi.UploadTBoxCarInfo(machine.SwapOrder, machine.TBoxCarInfoModel);
}
}
}, () => { machine.LedTool?.WriteProgramContent("车机蓝牙车辆数据上报异常,请联系站务人员"); }, false, () =>
{
SwappingStateMachine.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 == 1 && i.VehicleNo.Equals(machine.TBoxCarInfoModel.CarNo));
return Invoker.Invoke("selectPack", 500, 20, machine.IsCanceled,
() => SwappingStateMachine.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);
SwappingStateMachine.SelectPackFlag = true;
}
}, () => { SwappingStateMachine.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 = "1";
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 = 6;
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 == "1" && 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 == "0");
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 == "0"
&& i.Exists == 0);
if (list.Count <= 0)
{
orderBatteryInfo.CanSwap = InfoEnum.SelectBinStatusInfo.LessOfEmptyBin;
return;
}
orderBatteryInfo.InBinInfo = list[0];
orderBatteryInfo.CanSwap = InfoEnum.SelectBinStatusInfo.Success;
} }
} }

@ -0,0 +1,52 @@
using Entity.Constant;
namespace Service.Execute.Step;
/// <summary>
/// 云平台下发换电
/// </summary>
public class CloudSendOutSwapState: IState
{
public StateResult Handle(SwappingStateMachine machine)
{
return new StateResult()
{
SwappingState = SwappingState.StationReady
};
}
/// <summary>
/// 等待云平台下发换电
/// </summary>
/// <returns></returns>
/*public InvokeStatus CloudSendOutSwap(SwappingStateMachine machine)
{
return Invoker.Invoke("check CarInPosition", 500, 50, machine.IsCanceled,
() => SwappingStateMachine.VehiclesInPlaceFlag, () =>
{
var result = TBoxApi.GetCarInfo();
TboxCarInfoModel tboxCarInfoModel = result.Result;
if (tboxCarInfoModel.HeartBeatMsg.KeyStatus == 0)
{
SwappingStateMachine.VehiclesInPlaceFlag = true;
//写入口等 :红灯
if (PlcApi.WriteEntranceLamp(1020))
{
machine.LedTool?.WriteProgramContent(InfoEnum.SwapInfo.InfoCarInPosition.GetLed());
SoundTool.PlayOneSound((int)InfoEnum.SwapInfo.InfoCarInPosition);
SwappingStateMachine.VehiclesInPlaceFlag = true;
}
}
}, () =>
{
SwappingStateMachine.ExceptionReason = ExceptionReason.CarInPositionError;
machine.LedTool?.WriteProgramContent(InfoEnum.SwapInfo.ErrorCarInPositionTimeout.GetLed());
SoundTool.PlayOneSound((int)InfoEnum.SwapInfo.ErrorCarInPositionTimeout);
}, false, () => { }
, 20, InvokeStatus.None);
}*/
}

@ -1,14 +0,0 @@
namespace Service.Execute.Step;
public class SelectPackState: IState
{
public StateResult Handle(SwappingStateMachine machine)
{
return new StateResult()
{
SwappingState = SwappingState.StationReady
};
}
}

@ -2,16 +2,17 @@
using Entity.Constant; using Entity.Constant;
using Entity.DbModel.Station; using Entity.DbModel.Station;
using log4net; using log4net;
using Microsoft.OpenApi.Extensions;
using Microsoft.VisualBasic; using Microsoft.VisualBasic;
using Newtonsoft.Json; using Newtonsoft.Json;
using Repository.Station; using Repository.Station;
using Service.Execute.Api; using Service.Execute.Api;
using Service.Execute.Enum; using Service.Execute.Enum;
using Service.Execute.Model;
using Service.Execute.StaticTools; using Service.Execute.StaticTools;
using Service.Execute.SwapException; using Service.Execute.SwapException;
using Service.Init; using Service.Init;
using Swapping.Business.Common; using Swapping.Business.Common;
using Swapping.Business.Rfid;
using Swapping.Business.Tech; using Swapping.Business.Tech;
namespace Service.Execute.Step; namespace Service.Execute.Step;
@ -28,7 +29,7 @@ public class StationReadyState : IState
_log.Info($"'goto stationReady"); _log.Info($"'goto stationReady");
machine.Reset(); machine.Reset();
SwappingStateMachine.BusinessSwappingState = InfoEnum.BusinessSwappingState.Idle; SwappingStateMachine.BusinessSwappingForCloudState = InfoEnum.BusinessSwappingForCloudState.Idle;
SwappingStateMachine.BusinessSwappingStateUpdateTime = DateTime.Now; SwappingStateMachine.BusinessSwappingStateUpdateTime = DateTime.Now;
//判断换电站是否具备换电条件 //判断换电站是否具备换电条件
@ -78,20 +79,29 @@ public class StationReadyState : IState
public InvokeStatus PlcIsRemote(SwappingStateMachine machine) public InvokeStatus PlcIsRemote(SwappingStateMachine machine)
{ {
return Invoker.Invoke("check plc remote", 1000, 5, machine.IsCanceled, PlcApi.IsRemote, bool isRemote = false;
return Invoker.Invoke("check plc remote", 1000, 5, machine.IsCanceled, () => isRemote,
() => () =>
{ {
//LED显示-欢迎光临_换电站点_正在营业三行展示 if (PlcApi.IsRemote())
{
//写入口灯绿灯
if (PlcApi.WriteEntranceLamp(1000))
{
//LED显示-欢迎光临_换电站点_正在营业
string welcomeContent = "欢迎光临" + StaticStationInfo.StationName + "正在营业"; string welcomeContent = "欢迎光临" + StaticStationInfo.StationName + "正在营业";
machine.LedTool?.WriteContent(welcomeContent); machine.LedTool?.WriteContent(welcomeContent);
isRemote = true;
}
}
}, },
() => { }, false); () => { }, true);
} }
public InvokeStatus EntranceRadar(SwappingStateMachine machine) public InvokeStatus EntranceRadar(SwappingStateMachine machine)
{ {
return Invoker.Invoke("wait entrance radar", 1000, 1, machine.IsCanceled, return Invoker.Invoke("wait entrance radar", 1000, 5, machine.IsCanceled,
() => SwappingStateMachine.RadarInFlag, () => () => SwappingStateMachine.RadarInFlag, () =>
{ {
if (!PlcApi.EntranceRadar()) if (!PlcApi.EntranceRadar())
@ -128,7 +138,8 @@ public class StationReadyState : IState
{ {
machine.LedTool.WriteProgramContent(InfoEnum.SwapInfo.ErrorReadRfid.GetLed()); machine.LedTool.WriteProgramContent(InfoEnum.SwapInfo.ErrorReadRfid.GetLed());
SoundTool.PlayOneSound((int)InfoEnum.SwapInfo.ErrorReadRfid); SoundTool.PlayOneSound((int)InfoEnum.SwapInfo.ErrorReadRfid);
}, false, () => { SwappingStateMachine.ExceptionReason = ExceptionReason.ReadRfidError; }); }, false, () => { SwappingStateMachine.ExceptionReason = ExceptionReason.ReadRfidError; }
, 1, InvokeStatus.TimeOut);
} }
/// <summary> /// <summary>
@ -139,13 +150,19 @@ public class StationReadyState : IState
/// <returns></returns> /// <returns></returns>
private bool IsAutoSwapping() private bool IsAutoSwapping()
{ {
var statusDes = StationConstant.EnumExtensions.GetDescription(StaticStationInfo.StationStatus); var statusDes =
BaseEnumExtensions.GetEnumDescriptionByCode<StationConstant.StationStatus>(
int.Parse(StaticStationInfo.StationStatus));
_log.Info($"换电站处于{statusDes}状态"); _log.Info($"换电站处于{statusDes}状态");
var wayDes = StationConstant.EnumExtensions.GetDescription(StaticStationInfo.StationWay); var wayDes =
BaseEnumExtensions.GetEnumDescriptionByCode<StationConstant.StationWay>(
int.Parse(StaticStationInfo.StationWay));
_log.Info($"换电站处于{wayDes}模式"); _log.Info($"换电站处于{wayDes}模式");
if (StationConstant.StationStatus.Run == StaticStationInfo.StationStatus if (StationConstant.StationStatus.Run ==
&& StationConstant.StationWay.Auto == StaticStationInfo.StationWay) BaseEnumExtensions.GetEnumByCode<StationConstant.StationStatus>(int.Parse(StaticStationInfo.StationStatus))
&& StationConstant.StationWay.Auto ==
BaseEnumExtensions.GetEnumByCode<StationConstant.StationWay>(int.Parse(StaticStationInfo.StationWay)))
{ {
return true; return true;
} }
@ -177,9 +194,8 @@ public class StationReadyState : IState
_log.Info($"read rfid={JsonConvert.SerializeObject(machine.RfidReadModel)}"); _log.Info($"read rfid={JsonConvert.SerializeObject(machine.RfidReadModel)}");
SwappingStateMachine.ExceptionReason = ExceptionReason.None; SwappingStateMachine.ExceptionReason = ExceptionReason.None;
SwappingStateMachine.BusinessSwappingState = InfoEnum.BusinessSwappingState.ScanRfid;
SwappingStateMachine.BusinessSwappingStateUpdateTime = DateTime.Now; SwappingStateMachine.BusinessSwappingStateUpdateTime = DateTime.Now;
_log.Info($"BusinessSwappingState={SwappingStateMachine.BusinessSwappingState}"); _log.Info($"BusinessSwappingForCloudState={SwappingStateMachine.BusinessSwappingForCloudState}");
machine.SwapOrder = SaveOrder(BuildOrder(machine.RfidReadModel)); machine.SwapOrder = SaveOrder(BuildOrder(machine.RfidReadModel));

@ -8,11 +8,11 @@ namespace Service.Execute.SwapException;
{ {
None, None,
ReadRfidError, ReadRfidError,
OpenBarrierError, ConnTBoxError,
ConnVbleError,
CarStateCheckError, CarStateCheckError,
CloudCheckError, CloudCheckError,
CloudVbleDataError, LocalCheckVarError,
CloudCarDataUploadError,
CarInPositionError, CarInPositionError,
CloudSendSwapError, CloudSendSwapError,
SelectPackError, SelectPackError,

@ -2,11 +2,11 @@
using log4net; using log4net;
using Newtonsoft.Json; using Newtonsoft.Json;
using Service.Execute.Enum; using Service.Execute.Enum;
using Service.Execute.Model;
using Service.Execute.StaticTools; using Service.Execute.StaticTools;
using Service.Execute.Step; using Service.Execute.Step;
using Service.Execute.SwapException; using Service.Execute.SwapException;
using Service.Execute.Tech; using Service.Execute.Tech;
using Swapping.Business.Rfid;
namespace Service.Execute; namespace Service.Execute;
@ -22,16 +22,21 @@ public class SwappingStateMachine : IDisposable
private Dictionary<SwappingState, IState> Dictionary = new Dictionary<SwappingState, IState>(); private Dictionary<SwappingState, IState> Dictionary = new Dictionary<SwappingState, IState>();
private StateResult _result = new StateResult() { SwappingState = SwappingState.Begin }; private StateResult _result = new StateResult() { SwappingState = SwappingState.Begin };
public static InfoEnum.BusinessSwappingState BusinessSwappingState = InfoEnum.BusinessSwappingState.UnKnown; //给云平台的实时状态
public static InfoEnum.BusinessSwappingForCloudState BusinessSwappingForCloudState =
InfoEnum.BusinessSwappingForCloudState.UnKnown;
public static DateTime BusinessSwappingStateUpdateTime = DateTime.Now; public static DateTime BusinessSwappingStateUpdateTime = DateTime.Now;
public static ExceptionReason ExceptionReason = ExceptionReason.None; public static ExceptionReason ExceptionReason = ExceptionReason.None;
public RfidReadModel? RfidReadModel=null; public RfidReadModel? RfidReadModel=null;
public TboxCarInfoModel? TBoxCarInfoModel = null;
public SwapOrder? SwapOrder=null; public SwapOrder? SwapOrder=null;
public SwapOrderBatteryInfo SwapOrderBatteryInfo = null;
#region 小步状态 #region 小步状态
@ -46,7 +51,13 @@ public class SwappingStateMachine : IDisposable
public static bool CloudVelCheckFlag = false; public static bool CloudVelCheckFlag = false;
//Tbox连接 //Tbox连接
public static bool TBoxConnectionFlag = false; public static bool TBoxConnectFlag = false;
//Tbox本地校验
public static bool TBoxLocalCheckFlag = false;
//Tbox数据上传
public static bool CloudTBoxFlag = false;
//选包 //选包
public static bool SelectPackFlag = false; public static bool SelectPackFlag = false;
@ -102,7 +113,7 @@ public class SwappingStateMachine : IDisposable
Dictionary[SwappingState.Begin] = new BeginState(); Dictionary[SwappingState.Begin] = new BeginState();
Dictionary[SwappingState.StationReady] = new StationReadyState(); Dictionary[SwappingState.StationReady] = new StationReadyState();
Dictionary[SwappingState.CarPrepare] = new CarPrepareState(); Dictionary[SwappingState.CarPrepare] = new CarPrepareState();
Dictionary[SwappingState.SelectPack] = new SelectPackState(); Dictionary[SwappingState.SelectPack] = new CloudSendOutSwapState();
Dictionary[SwappingState.CarCtrl] = new CarCtrlState(); Dictionary[SwappingState.CarCtrl] = new CarCtrlState();
Dictionary[SwappingState.DoSwapping] = new DoSwappingState(); Dictionary[SwappingState.DoSwapping] = new DoSwappingState();
Dictionary[SwappingState.SwapDone] = new SwapDoneState(); Dictionary[SwappingState.SwapDone] = new SwapDoneState();

@ -11,11 +11,23 @@ namespace Service.Init;
/// </summary> /// </summary>
public class StaticStationInfo public class StaticStationInfo
{ {
public static StationConstant.StationStatus StationStatus;
public static StationConstant.StationWay StationWay;
public static StationConstant.StationModel StationModel; public static string StationStatus
{
get => Resolve(StationParamConst.StationStatus);
set => Set(StationParamConst.StationStatus, value);
}
public static string StationWay
{
get => Resolve(StationParamConst.StationWay);
set => Set(StationParamConst.StationWay, value);
}
public static string StationModel
{
get => Resolve(StationParamConst.StationModel);
set => Set(StationParamConst.StationModel, value);
}
public static string StationName public static string StationName
{ {
@ -23,12 +35,26 @@ public class StaticStationInfo
set => Set(StationParamConst.StationName, value); set => Set(StationParamConst.StationName, value);
} }
public static string StationNo public static string StationNo
{ {
get => Resolve(StationParamConst.StationNo); get => Resolve(StationParamConst.StationNo);
set => Set(StationParamConst.StationNo, value); set => Set(StationParamConst.StationNo, value);
} }
public static string SwapFinishChargeTime
{
get => Resolve(StationParamConst.SwapFinishChargeTime);
set => Set(StationParamConst.SwapFinishChargeTime, value);
}
public static string SwapSoc
{
get => Resolve(StationParamConst.SwapSoc);
set => Set(StationParamConst.SwapSoc, value);
}
#region cloud #region cloud

@ -5,6 +5,15 @@ public class StationParamConst
public static readonly string StationNo = "Station.StationNo"; public static readonly string StationNo = "Station.StationNo";
public static readonly string StationName = "Station.StationName"; public static readonly string StationName = "Station.StationName";
//选包策略中最后结束充电时间需要>此值
public static readonly string SwapFinishChargeTime = "Station.SwapFinishChargeTime";
//选包策略换电Soc
public static readonly string SwapSoc = "Station.SwapSoc";
public static readonly string StationStatus = "Station.StationStatus";
public static readonly string StationWay = "Station.StationWay";
public static readonly string StationModel = "Station.StationModel";
#region cloud param #region cloud param
public static readonly string CloudServerIp = "Cloud.CloudServerIp"; public static readonly string CloudServerIp = "Cloud.CloudServerIp";

@ -1,3 +1,4 @@
using Entity.DbModel.Station;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Repository.Station; using Repository.Station;
using SqlSugar; using SqlSugar;
@ -30,17 +31,17 @@ public class GenController : ControllerBase
.FormatFileName(it => ToPascalCase(it)) //格式化文件名(文件名和表名不一样情况) .FormatFileName(it => ToPascalCase(it)) //格式化文件名(文件名和表名不一样情况)
.FormatClassName(it => ToPascalCase(it)) //格式化类名 (类名和表名不一样的情况) .FormatClassName(it => ToPascalCase(it)) //格式化类名 (类名和表名不一样的情况)
.FormatPropertyName(it => ToPascalCase(it)) //格式化属性名 (属性名和字段名不一样情况) .FormatPropertyName(it => ToPascalCase(it)) //格式化属性名 (属性名和字段名不一样情况)
.CreateClassFile("D:\\lxw\\work\\pro\\c#\\hn_back_main\\Entity\\DbModel\\Station", .CreateClassFile("D:\\lxw\\work\\pro\\c#\\hn_back_main\\Entity\\DbModel\\Station\\Temp",
"Entity.DbModel.Station"); "Entity.DbModel.Station");
Console.WriteLine("生成完毕"); Console.WriteLine("生成完毕");
} }
/*[HttpGet("test115")] [HttpGet("test115")]
public void Test115() public void Test115()
{ {
_batteryGroupRepository.Insert(new List<BatteryGroup>() /*_batteryGroupRepository.Insert(new List<BatteryGroup>()
{ {
new BatteryGroup() new BatteryGroup()
{ {
@ -52,17 +53,25 @@ public class GenController : ControllerBase
BatteryNo = "2", BatteryNo = "2",
Group = 2, Group = 2,
}, },
}); });*/
List<BatteryGroup> batteryGroups = _batteryGroupRepository.Query(); BatteryGroup batteryGroups = _batteryGroupRepository.QueryByClause(i=>i.Group==1);
BatteryGroup batteryGroup = batteryGroups[0]; /*BatteryGroup batteryGroup = batteryGroups[0];
_batteryGroupRepository.Delete(batteryGroup); _batteryGroupRepository.Delete(batteryGroup);
BatteryGroup batteryGroup1 = batteryGroups[1]; BatteryGroup batteryGroup1 = batteryGroups[1];
batteryGroup1.Group = 3; batteryGroup1.Group = 3;
_batteryGroupRepository.Update(batteryGroup1); _batteryGroupRepository.Update(batteryGroup1);*/
if (batteryGroups == null)
{
Console.WriteLine();
}
else
{
Console.WriteLine();
}
Console.WriteLine("测试完毕"); Console.WriteLine("测试完毕");
}*/ }
static string ToPascalCase(string input) static string ToPascalCase(string input)

Loading…
Cancel
Save