diff --git a/Common/Util/HttpUtil.cs b/Common/Util/HttpUtil.cs new file mode 100644 index 0000000..0d9e8a6 --- /dev/null +++ b/Common/Util/HttpUtil.cs @@ -0,0 +1,28 @@ +using System.Text; +using Newtonsoft.Json; + +namespace Common.Util; + +public static class HttpUtil +{ + private static readonly HttpClient httpClient = new HttpClient(); + + /// + /// 发送post请求 + /// + /// + /// + /// + public static async void SendPostRequest(T data, string url) + { + string jsonStr = JsonConvert.SerializeObject(data); + var content = new StringContent(jsonStr, Encoding.UTF8, "application/json"); + + HttpResponseMessage response = await httpClient.PostAsync(url, content); + + if (response.IsSuccessStatusCode) + { + await response.Content.ReadAsStringAsync(); + } + } +} \ No newline at end of file diff --git a/Entity/DbModel/Station/ChargeOrder.cs b/Entity/DbModel/Station/ChargeOrder.cs index d8c2473..94ad8e4 100644 --- a/Entity/DbModel/Station/ChargeOrder.cs +++ b/Entity/DbModel/Station/ChargeOrder.cs @@ -51,7 +51,7 @@ namespace Entity.DbModel.Station /// [SugarColumn(ColumnName = "charger_no")] public string ChargerNo { get; set; } - + /// /// Desc:充电枪编号 /// Default: @@ -59,6 +59,14 @@ namespace Entity.DbModel.Station /// [SugarColumn(ColumnName = "charger_gun_no")] public string ChargerGunNo { get; set; } + + /// + /// Desc:站外充电枪编号,1枪或2枪 + /// Default: + /// Nullable:True + /// + [SugarColumn(ColumnName = "out_charger_gun_no")] + public string OutChargerGunNo { get; set; } /// /// Desc:0:站内充电 1:站外充电 diff --git a/Repository/Station/ChargeOrderRepository.cs b/Repository/Station/ChargeOrderRepository.cs index 7d3833f..e178142 100644 --- a/Repository/Station/ChargeOrderRepository.cs +++ b/Repository/Station/ChargeOrderRepository.cs @@ -11,6 +11,38 @@ public class ChargeOrderRepository : BaseRepository { } + public void SaveChargeGunOrder(string chargeOrderNo, string chargerNo, string chargerGunNo, + string outChargerGunNo) + { + ChargeOrder order = new ChargeOrder(); + order.Sn = chargeOrderNo; + order.CmdStatus = 0; + order.ChargerNo = chargerNo; + order.ChargerGunNo = chargerGunNo; + order.OutChargerGunNo = outChargerGunNo; + order.ChargeMode = 1; + order.StartMode = 1; + order.CloudChargeOrder = chargeOrderNo; + order.CreatedTime = DateTime.Now; + ChargeOrder chargeOrder = Insert(order); + } + + public ChargeOrder? GetLatestChargeGunOrder(string pn, string chargerCode) + { + try + { + var chargeOrder = DbBaseClient.Queryable() + .Where(co => co.OutChargerGunNo == pn && co.ChargerNo == chargerCode) + .OrderByDescending(co => co.CreatedTime) + .First(); + return chargeOrder; + } + catch (Exception e) + { + return null; + } + } + public ChargeOrder? QueryLatestByBatterySn(string? batterySn) { if (string.IsNullOrWhiteSpace(batterySn)) @@ -33,6 +65,7 @@ public class ChargeOrderRepository : BaseRepository { return new List(0); } + return QueryListByClause(it => it.SwapOrderSn == swapOrderNo && it.BatteryNo == batteryNo, it => it.CreatedTime, OrderByType.Asc); } diff --git a/Service/Charger/Client/ChargerClient.cs b/Service/Charger/Client/ChargerClient.cs index 0cf0fe0..c35c30d 100644 --- a/Service/Charger/Client/ChargerClient.cs +++ b/Service/Charger/Client/ChargerClient.cs @@ -1,4 +1,5 @@ -using Autofac; +using System.Collections.Concurrent; +using Autofac; using Entity.DbModel.Station; using HybirdFrameworkCore.Autofac; using HybirdFrameworkCore.Autofac.Attribute; @@ -14,8 +15,10 @@ using Service.Charger.Codec; using Service.Charger.Common; using Service.Charger.Handler; using Service.Charger.Msg; +using Service.Charger.Msg.Charger.OutCharger.Req; using Service.Charger.Msg.Charger.Req; using Service.Charger.Msg.Charger.Resp; +using Service.Charger.Msg.Host.OutCharger.Req; using Service.Charger.Msg.Host.Req; using Service.Charger.Msg.Host.Req.Bms; @@ -47,7 +50,18 @@ public class ChargerClient : TcpClient /// 是否已经开始充电 /// public bool IsCharged { get; set; } = false; - + + + + /// + /// 站外两枪时是否在充电 + /// + public ConcurrentDictionary GunCharged = new ConcurrentDictionary + { + [1] = false, + [2] = false + }; + public bool IsStopped { get; set; } = false; public bool IsCanSendStopCmd { get; set; } = true; @@ -129,7 +143,11 @@ public class ChargerClient : TcpClient /// 充电机遥测数据 /// public UploadTelemetryData UploadTelemetryData = new UploadTelemetryData(); - + + /// + /// 两个充电桩的遥测 + /// + public ConcurrentDictionary PileUploadTelemetry = new(); /// ///充电机实时充电功率 /// @@ -454,7 +472,57 @@ public class ChargerClient : TcpClient this.Channel.WriteAndFlushAsync(req); return Result.Success(); } + /// + /// 3.7.1 监控平台远程启动充电桩充电 + /// + /// 充电枪ID号 + /// SOC 限制 + /// 功率调节指令类型 + /// 功率调节参数 + /// + /// 充电流水号 + public Result SendStartOutCharger(byte pn, byte socValue, short changePower=360,byte changePowerCmdType=1 , + string? chargeOrderNo = null) + { + if (!Connected) + { + return Result.Fail($"充电机{BinNo}未连接"); + } + + if (string.IsNullOrWhiteSpace(chargeOrderNo)) + { + chargeOrderNo = ChargerUtils.GenChargeOrderSn(); + } + + Log().Info( + $"SendStartOutCharger pn={pn}, socValue={socValue}, changePower={changePower}, changePowerCmdType={changePowerCmdType}, chargeOrderNo={chargeOrderNo}"); + + PileStartCharge pileStartCharge = new PileStartCharge(pn, socValue, changePowerCmdType, changePower,chargeOrderNo); + + this.Channel.WriteAndFlushAsync(pileStartCharge); + + return Result.Success(chargeOrderNo); + } + /// + /// 3.7.3 监控平台远程停止充电桩充电 + /// + /// + /// + /// + public Result SendStopOutCharger(byte pn, byte stopReason) + { + if (!Connected) + { + return Result.Fail($"充电机{BinNo}未连接"); + } + + Log().Info( + $"SendStartOutCharger pn={pn}, stopReason={stopReason}"); + PileStopCharge pileStopCharge=new PileStopCharge(pn,stopReason); + this.Channel.WriteAndFlushAsync(pileStopCharge); + return Result.Success(); + } /// /// /// diff --git a/Service/Charger/Codec/Decoder.cs b/Service/Charger/Codec/Decoder.cs index 7a58bf3..7a53b68 100644 --- a/Service/Charger/Codec/Decoder.cs +++ b/Service/Charger/Codec/Decoder.cs @@ -8,6 +8,8 @@ using Newtonsoft.Json; using Service.Charger.Common; using Service.Charger.Msg; using Service.Charger.Msg.Bms; +using Service.Charger.Msg.Charger.OutCharger.Req; +using Service.Charger.Msg.Charger.OutCharger.Resp; using Service.Charger.Msg.Charger.Req; using Service.Charger.Msg.Charger.Resp; @@ -239,6 +241,16 @@ public class Decoder : ByteToMessageDecoder 148 => ModelConvert.Decode(bytes), _ => throw new InvalidOperationException("This should never be reached"), }, + 51 => recordType switch + { + 2 => ModelConvert.Decode(bytes), + 4 => ModelConvert.Decode(bytes), + 5 => ModelConvert.Decode(bytes), + 7 => ModelConvert.Decode(bytes), + 12 => ModelConvert.Decode(bytes), + 11 => ModelConvert.Decode(bytes), + _ => throw new InvalidOperationException("This should never be reached"), + }, #endregion 42 => ModelConvert.Decode(bytes), diff --git a/Service/Charger/Common/ChargerUtils.cs b/Service/Charger/Common/ChargerUtils.cs index cecea4e..07389d4 100644 --- a/Service/Charger/Common/ChargerUtils.cs +++ b/Service/Charger/Common/ChargerUtils.cs @@ -58,7 +58,49 @@ public static class ChargerUtils return StaticStationInfo.StationNo + DateTime.Now.ToString(ChargerConst.DateFormat) + GetRandomNumLimit99(); } + /// + /// 根据云平台下发,计算本地充电机枪号 + /// + /// + /// + /// + public static byte GetTheGun(string number) + { + int parsedNumber; + + if (int.TryParse(number, out parsedNumber)) + { + if (parsedNumber % 2 == 0) + { + return 2; + } + else + { + return 1; + } + } + else + { + throw new ArgumentException("转换失败"); + } + } + + public static string GetOutChargerCode(string number) + { + int parsedNumber; + if (int.TryParse(number, out parsedNumber)) + { + // 除2,向上取整,拿到本地充电机code + int ceilResult = (int)Math.Ceiling(parsedNumber / 2.0); + return ceilResult.ToString(); + } + else + { + throw new ArgumentException("转换失败"); + } + + } /// /// 计算Byte随机数值 /// diff --git a/Service/Charger/Handler/OutCharger/PileChargeCompleteHandler.cs b/Service/Charger/Handler/OutCharger/PileChargeCompleteHandler.cs new file mode 100644 index 0000000..ff89574 --- /dev/null +++ b/Service/Charger/Handler/OutCharger/PileChargeCompleteHandler.cs @@ -0,0 +1,49 @@ +using DotNetty.Transport.Channels; +using Entity.DbModel.Station; +using HybirdFrameworkCore.Autofac.Attribute; +using log4net; +using Repository.Station; +using Service.Charger.Client; +using Service.Charger.Msg.Charger.OutCharger.Req; +using Service.Charger.Msg.Host.Resp.OutCharger; + +namespace Service.Charger.Handler.OutCharger; + +/// +/// 3.7.7 充电桩上送停止完成帧 +/// +[Order(8)] +[Scope("InstancePerDependency")] +public class PileChargeCompleteHandler : SimpleChannelInboundHandler, IBaseHandler +{ + private static readonly ILog Log = LogManager.GetLogger(typeof(PileChargeCompleteHandler)); + + public ChargeOrderRepository ChargeOrderRepository { get; set; } + + protected override void ChannelRead0(IChannelHandlerContext ctx, PileChargeCompleteReq msg) + { + if (ClientMgr.TryGetClient(ctx.Channel, out var sn, out var client)) + { + Log.Info($"receive {msg} from {sn}"); + if (msg.Result == 0) + { + ChargeOrder? chargeOrder = ChargeOrderRepository.GetLatestChargeGunOrder(msg.Pn.ToString(), sn); + if (chargeOrder == null) + { + return; + } + + chargeOrder.EndTime = DateTime.Now; + chargeOrder.StopReason = 0; + chargeOrder.CanUpload = 1; + + client.GunCharged[msg.Pn] = false; + + ChargeOrderRepository.Update(chargeOrder); + } + + PileChargeCompleteRes res = new PileChargeCompleteRes(msg.Pn,0); + ctx.Channel.WriteAndFlushAsync(res); + } + } +} \ No newline at end of file diff --git a/Service/Charger/Handler/OutCharger/PileStartChargeCompleteHandler.cs b/Service/Charger/Handler/OutCharger/PileStartChargeCompleteHandler.cs new file mode 100644 index 0000000..15ee44f --- /dev/null +++ b/Service/Charger/Handler/OutCharger/PileStartChargeCompleteHandler.cs @@ -0,0 +1,37 @@ +using DotNetty.Transport.Channels; +using HybirdFrameworkCore.Autofac.Attribute; +using log4net; +using Service.Charger.Client; +using Service.Charger.Msg.Charger.OutCharger.Req; +using Service.Charger.Msg.Host.Resp.OutCharger; + +namespace Service.Charger.Handler.OutCharger; + +[Order(8)] +[Scope("InstancePerDependency")] +public class PileStartChargeCompleteHandler : SimpleChannelInboundHandler, IBaseHandler +{ + private static readonly ILog Log = LogManager.GetLogger(typeof(PileStartChargeCompleteHandler)); + + protected override void ChannelRead0(IChannelHandlerContext ctx, PileStartChargeCompleteReq msg) + { + if (ClientMgr.TryGetClient(ctx.Channel, out var sn, out var client)) + { + Log.Info($"receive {msg} from {sn}"); + + if (client == null) + { + return; + } + + if (msg.Result == 0) + { + client.GunCharged[msg.Pn] = true; + } + // 响应启动完成帧 + PileStartChargeCompleteRes res=new PileStartChargeCompleteRes(msg.Pn,0,0); + + ctx.Channel.WriteAndFlushAsync(res); + } + } +} \ No newline at end of file diff --git a/Service/Charger/Handler/OutCharger/PileStartChargeResHandler.cs b/Service/Charger/Handler/OutCharger/PileStartChargeResHandler.cs new file mode 100644 index 0000000..ad2be87 --- /dev/null +++ b/Service/Charger/Handler/OutCharger/PileStartChargeResHandler.cs @@ -0,0 +1,61 @@ +using System.Text; +using Common.Util; +using DotNetty.Transport.Channels; +using Entity.DbModel.Station; +using HybirdFrameworkCore.Autofac.Attribute; +using log4net; +using Newtonsoft.Json; +using Repository.Station; +using Service.Charger.Client; +using Service.Charger.Msg.Charger.OutCharger.Resp; +using Service.Charger.Msg.Http.Resp; + +namespace Service.Charger.Handler.OutCharger; + +[Order(8)] +[Scope("InstancePerDependency")] +public class PileStartChargeResHandler : SimpleChannelInboundHandler, IBaseHandler +{ + private static readonly ILog Log = LogManager.GetLogger(typeof(PileStartChargeResHandler)); + public ChargeOrderRepository ChargeOrderRepository { get; set; } + + + protected override void ChannelRead0(IChannelHandlerContext ctx, PileStartChargeRes msg) + { + if (ClientMgr.TryGetClient(ctx.Channel, out var sn, out var client)) + { + Log.Info($"receive {msg} from {sn}"); + + + ChargeOrder? chargeOrder = ChargeOrderRepository.GetLatestChargeGunOrder(msg.Pn.ToString(), sn); + if (chargeOrder == null) + { + return; + } + + PileStartChargeHttpRes chargeRes = new PileStartChargeHttpRes(); + + chargeRes.con = chargeOrder.Sn; + chargeRes.pn = chargeOrder.ChargerGunNo; + + if (msg.Result == 0) + { + chargeOrder.StartTime = DateTime.Now; + chargeOrder.CmdStatus = 1; + ChargeOrderRepository.Update(chargeOrder); + + + chargeRes.rs = "1"; + chargeRes.ec = "0"; + // 9.2.1.2 站控应答开始充电操作 + HttpUtil.SendPostRequest(chargeRes, "http://127.0.0.1:5034/api/OutCharger/ResStartOutCharger"); + } + else + { + chargeRes.rs = "2"; + chargeRes.ec = msg.FailReason.ToString(); + HttpUtil.SendPostRequest(chargeRes, "http://127.0.0.1:5034/api/OutCharger/ResStartOutCharger"); + } + } + } +} \ No newline at end of file diff --git a/Service/Charger/Handler/OutCharger/PileStopChargeResHandler.cs b/Service/Charger/Handler/OutCharger/PileStopChargeResHandler.cs new file mode 100644 index 0000000..a6f0664 --- /dev/null +++ b/Service/Charger/Handler/OutCharger/PileStopChargeResHandler.cs @@ -0,0 +1,46 @@ +using Common.Util; +using DotNetty.Transport.Channels; +using Entity.DbModel.Station; +using HybirdFrameworkCore.Autofac.Attribute; +using log4net; +using Repository.Station; +using Service.Charger.Client; +using Service.Charger.Msg.Charger.OutCharger.Resp; +using Service.Charger.Msg.Http.Resp; + +namespace Service.Charger.Handler.OutCharger; + +[Order(8)] +[Scope("InstancePerDependency")] +public class PileStopChargeResHandler : SimpleChannelInboundHandler, IBaseHandler +{ + private static readonly ILog Log = LogManager.GetLogger(typeof(PileStopChargeResHandler)); + + public ChargeOrderRepository ChargeOrderRepository { get; set; } + + + protected override void ChannelRead0(IChannelHandlerContext ctx, PileStopChargeRes msg) + { + if (ClientMgr.TryGetClient(ctx.Channel, out var sn, out var client)) + { + Log.Info($"receive {msg} from {sn}"); + ChargeOrder? chargeOrder = ChargeOrderRepository.GetLatestChargeGunOrder(msg.pn.ToString(), sn); + + if (chargeOrder == null) + { + return; + } + + if (msg.rs == 0 || msg.rs == 1) + { + client.GunCharged[msg.pn] = false; + chargeOrder.EndTime = DateTime.Now; + ChargeOrderRepository.Update(chargeOrder); + PileStopChargeHttpRes res = new PileStopChargeHttpRes(); + res.pn = chargeOrder.ChargerGunNo; + res.rs = msg.rs.ToString(); + HttpUtil.SendPostRequest(res, "http://127.0.0.1:5034/api/OutCharger/ResStartOutCharger"); + } + } + } +} \ No newline at end of file diff --git a/Service/Charger/Handler/OutCharger/PileUploadRemoteSignalHandler.cs b/Service/Charger/Handler/OutCharger/PileUploadRemoteSignalHandler.cs new file mode 100644 index 0000000..50e4aaf --- /dev/null +++ b/Service/Charger/Handler/OutCharger/PileUploadRemoteSignalHandler.cs @@ -0,0 +1,30 @@ +using DotNetty.Transport.Channels; +using log4net; +using Service.Charger.Client; +using Service.Charger.Handler; + +namespace Service.Charger.Msg.Charger.OutCharger.Req; +/// +/// 3.7.11 充电桩遥信数据上报 +/// +public class PileUploadRemoteSignalHandler: SimpleChannelInboundHandler, IBaseHandler +{ + private static readonly ILog Log = LogManager.GetLogger(typeof(PileUploadRemoteSignalHandler)); + + + protected override void ChannelRead0(IChannelHandlerContext ctx, PileUploadRemoteSignal msg) + { + if (ClientMgr.TryGetClient(ctx.Channel, out var sn, out var client)) + { + //存储日志 + Log.Info($"receive {msg} from {sn}"); + + client.Workstate = msg.WorkStatus; + client.IsCharged = msg.WorkStatus == 1 ? true : false; + client.TotalError = msg.TotalError; + client.TotalWarning = msg.TotalWarning; + + + } + } +} \ No newline at end of file diff --git a/Service/Charger/Handler/OutCharger/PileUploadTelemetryHandler.cs b/Service/Charger/Handler/OutCharger/PileUploadTelemetryHandler.cs new file mode 100644 index 0000000..5a85c0c --- /dev/null +++ b/Service/Charger/Handler/OutCharger/PileUploadTelemetryHandler.cs @@ -0,0 +1,30 @@ +using DotNetty.Transport.Channels; +using HybirdFrameworkCore.Autofac.Attribute; +using log4net; +using Service.Charger.Client; +using Service.Charger.Msg.Charger.OutCharger.Req; + +namespace Service.Charger.Handler.OutCharger; + +/// +/// 3.7.12 充电桩遥测数据上报 +/// +[Order(8)] +[Scope("InstancePerDependency")] +public class PileUploadTelemetryHandler : SimpleChannelInboundHandler, IBaseHandler +{ + private static readonly ILog Log = LogManager.GetLogger(typeof(PileUploadTelemetryHandler)); + + protected override void ChannelRead0(IChannelHandlerContext ctx, PileUploadTelemetry msg) + { + if (ClientMgr.TryGetClient(ctx.Channel, out var sn, out var client)) + { + Log.Info($"receive {msg} from {sn}"); + + client.PileUploadTelemetry[msg.Pn] = msg; + + client.RealTimeChargePower = msg.HighVoltageAcquisitionCurrent * msg.HighVoltageAcquisitionVoltage; + + } + } +} \ No newline at end of file diff --git a/Service/Charger/Msg/Charger/OutCharger/Req/PileChargeCompleteReq.cs b/Service/Charger/Msg/Charger/OutCharger/Req/PileChargeCompleteReq.cs new file mode 100644 index 0000000..f0b80cb --- /dev/null +++ b/Service/Charger/Msg/Charger/OutCharger/Req/PileChargeCompleteReq.cs @@ -0,0 +1,173 @@ +using HybirdFrameworkCore.Autofac.Attribute; + +namespace Service.Charger.Msg.Charger.OutCharger.Req; + +/// +/// 3.7.7 充电桩上送停止完成帧 +/// +public class PileChargeCompleteReq : ASDU +{ + /// + /// 记录类型 + /// + [Property(0, 8)] + public byte RecordType { get; set; } + + /// + /// 充电枪ID号 + /// 0x01:充电枪1;0x02:充电枪2;0x03:双枪充电;(0x00&0xFF无效) + /// + [Property(8, 8)] + public byte Pn { get; set; } + + /// + /// 成功标识 + /// + [Property(16, 8)] + public byte Result { get; set; } + + + /// + /// 失败原因 + /// + [Property(24, 8)] + public byte FailReason { get; set; } + + /// + ///BMS 中止充电原因 + /// + [Property(32, 8)] + public byte SuspendingChargingReason { get; set; } + + /// + ///BMS 充电故障原因 + /// + [Property(40, 16)] + public ushort CauseOfChargingFault { get; set; } + + /// + ///BMS 中止错误原因 + /// + [Property(56, 8)] + public byte AbortErrorReason { get; set; } + + /// + ///中止荷电状态 SOC(%) + /// + [Property(64, 8, PropertyReadConstant.Bit, 1, 0)] + public float SuspendTheStateOfCharge { get; set; } + + /// + ///动力蓄电池单体最低电压(V) + /// + [Property(72, 16, PropertyReadConstant.Bit, 0.01, 2)] + public float MinimumVoltageOfTractionBattery { get; set; } + + /// + ///动力蓄电池单体最高电压(V) + /// + [Property(88, 16, PropertyReadConstant.Bit, 0.01, 2)] + public float MaximumVoltageOfTractionBattery { get; set; } + + /// + ///动力蓄电池最低温度(ºC) + /// + [Property(104, 8, PropertyReadConstant.Bit, 1, 0, 50)] + public float MinimumTemperatureOfTractionBattery { get; set; } + + /// + ///动力蓄电池最高温度(ºC) + /// + [Property(112, 8, PropertyReadConstant.Bit, 1, 0, 50)] + public byte MaximumTemperatureOfTractionBattery { get; set; } + + /// + ///接收SPN2560=0x00 的充电机辨识报文超时 + /// + [Property(120, 2)] + public byte XOOIdentificationMessageTimeout { get; set; } + + /// + ///接收SPN2560=0xAA 的充电机辨识报文超时 + /// + [Property(122, 2)] + public byte XAAIdentificationMessageTimeout { get; set; } + + /// + ///接收充电机的时间同步和充电机最大输出能力报文超时 + /// + [Property(124, 2)] + public byte TimeSyncAndMaxOutCapTimeout { get; set; } + + /// + ///接收充电机完成充电准备报文超时 + /// + [Property(126, 2)] + public byte ReceiveFinishPrepareChargeTimeout { get; set; } + + /// + ///接收充电机充电状态报文超时 + /// + [Property(128, 2)] + public byte TimeReceiveChargerStatusMessage { get; set; } + + /// + ///接收充电机中止充电报文超时 + /// + [Property(130, 2)] + public byte TimeReceiveChargingSuspensionMessage { get; set; } + + /// + ///接收充电机充电统计报文超时 + /// + [Property(132, 2)] + public byte TimeReceiveChargingStatisticsMessageOfCharger { get; set; } + + /// + ///接收BMS和车辆的辨识报文超时 + /// + [Property(134, 2)] + public byte TimeoutReceivingIdentificationMessageBms { get; set; } + + /// + ///接收电池充电参数报文超时 + /// + [Property(136, 2)] + public byte TimeoutReceivingBatteryChargingParameterMessage { get; set; } + + /// + ///接收 BMS完成充电准备报文超时 + /// + [Property(138, 2)] + public byte TimeoutReceivingBmsChargingPreparationMessage { get; set; } + + /// + ///接收电池充电要求报文超时 + /// + [Property(140, 2)] + public byte TimeoutReceivingBatteryChargingMessage { get; set; } + + /// + ///接收电池充电总状态报文超时 + /// + [Property(142, 2)] + public byte TimeoutReceivingBatteryChargingTotalStatusMessage { get; set; } + + /// + ///接收BMS中止充电报文超时 + /// + [Property(144, 2)] + public byte TimeoutReceivingBmsChargingSuspensionMessage { get; set; } + + /// + ///接收BMS充电统计报文超时 + /// + [Property(146, 2)] + public byte TimeoutReceivingBmsChargingStatisticsMessage { get; set; } + + /// + ///充电机检测到的其他错误 + /// + [Property(148, 6)] + public byte OtherErrorsDetectedByTheCharger { get; set; } +} \ No newline at end of file diff --git a/Service/Charger/Msg/Charger/OutCharger/Req/PileStartChargeCompleteReq.cs b/Service/Charger/Msg/Charger/OutCharger/Req/PileStartChargeCompleteReq.cs new file mode 100644 index 0000000..c85bf26 --- /dev/null +++ b/Service/Charger/Msg/Charger/OutCharger/Req/PileStartChargeCompleteReq.cs @@ -0,0 +1,137 @@ +using HybirdFrameworkCore.Autofac.Attribute; + +namespace Service.Charger.Msg.Charger.OutCharger.Req; + +/// +/// 3.7.5 充电桩上送充电启动完成帧 +/// +public class PileStartChargeCompleteReq : ASDU +{ + /// + /// 记录类型 + /// + [Property(0, 8)] + public byte RecordType { get; set; } + + /// + /// 充电枪ID号 + /// 0x01:充电枪1;0x02:充电枪2;0x03:双枪充电;(0x00&0xFF无效) + /// + [Property(8, 8)] + public byte Pn { get; set; } + + /// + /// 成功标识 0:成功;1:失败 + /// + [Property(16, 8)] + public byte Result { get; set; } + + /// + /// 失败原因 + /// 默认 0 + /// + [Property(24, 8)] + public byte FailReason { get; set; } + + /// + /// BMS 与充电桩通信协议版本号 + /// + [Property(32, 24)] + public string? ConnProtocolVersion0 { get; set; } + + /// + /// 充电桩与BMS 握手结果 + /// + [Property(56, 8)] + public byte HandshakeResult { get; set; } + + /// + /// 电池类型 + /// + [Property(64, 8)] + public byte BatteryType { get; set; } + + /// + /// 最高允许温度 + /// + [Property(72, 8, PropertyReadConstant.Bit, 1, 0, 50)] + public Int16 MaxAllowTemp { get; set; } + + /// + /// BMS最高允许充电电压 + /// + [Property(80, 16, PropertyReadConstant.Bit, 0.1, 1, 0)] + public float BmsMaxAllowVoltage { get; set; } + + /// + /// 单体最高允许充电电压 + /// + [Property(96, 16, PropertyReadConstant.Bit, 0.01, 2, 0)] + public float SingleMaxAllowVoltage { get; set; } + + /// + /// 最高允许充电电流 + /// + [Property(112, 16, PropertyReadConstant.Bit, 0.1, 1, 400)] + public float MaxAllowCurrent { get; set; } + + /// + /// 整车动力蓄电池额定总电压 + /// + [Property(128, 16, PropertyReadConstant.Bit, 0.1, 1, 0)] + public float VehiclePowerBatteryTotalVoltage { get; set; } + + /// + /// 整车动力蓄电池当前电压 + /// + [Property(144, 16, PropertyReadConstant.Bit, 0.1, 1, 0)] + public float VehiclePowerBatteryCurrentVoltage { get; set; } + + /// + /// 整车动力蓄电池额定容量 + /// + [Property(160, 16, PropertyReadConstant.Bit, 0.1, 1, 0)] + public float VehiclePowerBatteryRatedCapacity { get; set; } + + /// + ///整车动力蓄电池标称容量 + /// + [Property(176, 16, PropertyReadConstant.Bit, 0.1, 1, 0)] + public float VehiclePowerBatteryNormalCapacity { get; set; } + + /// + ///充电机最高输出电压 + /// + [Property(192, 16, PropertyReadConstant.Bit, 0.1, 1, 0)] + public float ChargerMaxOutputVoltage { get; set; } + + /// + ///充电机最低输出电压 + /// + [Property(208, 16, PropertyReadConstant.Bit, 0.1, 1, 0)] + public float ChargerMinOutputVoltage { get; set; } + + /// + ///充电机最大输出电流 + /// + [Property(224, 16, PropertyReadConstant.Bit, 0.1, 1, 400)] + public float ChargerMaxOutputCurrent { get; set; } + + /// + ///充电机最小输出电流 + /// + [Property(240, 16, PropertyReadConstant.Bit, 0.1, 1, 400)] + public float ChargerMinOutputCurrent { get; set; } + + /// + /// VIN + /// + [Property(256, 136)] + public string Vin { get; set; } + + /// + /// 整车动力蓄电 池荷电状态 + /// + [Property(392, 8, PropertyReadConstant.Bit, 0.01, 2, 0)] + public byte ChargeState { get; set; } +} \ No newline at end of file diff --git a/Service/Charger/Msg/Charger/OutCharger/Req/PileUploadRemoteSignal.cs b/Service/Charger/Msg/Charger/OutCharger/Req/PileUploadRemoteSignal.cs new file mode 100644 index 0000000..6f7ffac --- /dev/null +++ b/Service/Charger/Msg/Charger/OutCharger/Req/PileUploadRemoteSignal.cs @@ -0,0 +1,306 @@ +using HybirdFrameworkCore.Autofac.Attribute; + +namespace Service.Charger.Msg.Charger.OutCharger.Req; +/// +/// 3.7.11 充电桩遥信数据上报 +/// +public class PileUploadRemoteSignal: ASDU +{ + /// + /// 记录类型 + /// + [Property(0, 8)] + public byte RecordType { get; set; } + + /// + /// 充电枪ID号 + /// 0x01:充电枪1;0x02:充电枪2;0x03:双枪充电;(0x00&0xFF无效) + /// + [Property(8, 8)] + public byte Pn { get; set; } + + /// + /// 工作状态 00H:待机、01H:工作、02H:工作完成、03H:充/放电暂停 + /// + [Property(16, 2)] + public byte WorkStatus { get; set; } + + /// + /// 总故障:0-正常、1-故障 + /// + [Property(18, 1)] + public bool TotalError { get; set; } + + /// + /// 总告警:0-正常、1-告警 + /// + [Property(19, 1)] + public bool TotalWarning { get; set; } + /// + /// 急停按钮动作故障:0-正常、1-故障 + /// + [Property(20, 1)] + public bool EmergencyStop { get; set; } + + /// + /// 烟感故障:0-正常、1-故障 + /// + [Property(21, 1)] + public bool SmokeFault { get; set; } + + /// + /// 充电桩交流输入断路器故障(系统供电断路器):0-正常、1-故障 + /// + [Property(22, 1)] + public bool ChargeACInputCircuitBreakerFault { get; set; } + + /// + /// 直流母线正极输出 接触器拒动/误 动故障:0-正常、1-故障 + /// + [Property(23, 1)] + public bool DcBusPositElecContactorRefuFault { get; set; } + + /// + /// 直流母线负极输出 接触器拒动/误 动故障::0-正常、1-故障 + /// + [Property(24, 1)] + public bool DcBusNegatElecContactorRefuFault { get; set; } + + /// + /// 直流母线正级输出 熔断器故障 + /// + [Property(25, 1)] + public bool DcBusPositElecFusesFault { get; set; } + + /// + /// 直流母线负级输出 熔断器故障 + /// + [Property(26, 1)] + public bool DDcBusNegatElecFusesFault { get; set; } + + /// + /// 充电接口电磁锁故障 + /// + [Property(27, 1)] + public bool ChargingInterfaceLockError { get; set; } + + + /// + /// 充电桩风扇故障 + /// + [Property(28, 1)] + public bool ChargerFanError { get; set; } + + + /// + /// 避雷器故障 + /// + [Property(29, 1)] + public bool ArresterError { get; set; } + + + /// + /// 绝缘监测告警 + /// + [Property(30, 1)] + public bool InsulationDetectionAlarm { get; set; } + + /// + /// 绝缘监测故障 + /// + [Property(31, 1)] + public bool InsulationDetectionError { get; set; } + + + /// + /// 电池极性反接故障 + /// + [Property(32, 1)] + public bool BatteryPolarityReverseError { get; set; } + + /// + /// 充电中车辆控制导引故障 + /// + [Property(33, 1)] + public bool VeConGuidanceFailure { get; set; } + + /// + /// 充电桩过温故障 + /// + [Property(34, 1)] + public bool ChargingOverTempError { get; set; } + + /// + /// 充电接口过温故障 + /// + [Property(35, 1)] + public bool InterfaceOverFaulty { get; set; } + + /// + /// 充电枪未归位告警 + /// + [Property(36, 1)] + public bool ChargingGunNotHomingError { get; set; } + /// + /// BMS通信故障 + /// + [Property(37, 1)] + public bool BmsConnError { get; set; } + + /// + /// 充电桩输入电压过压故障 + /// + [Property(38, 1)] + public bool ChargerInputOverVoltageError { get; set; } + + /// + /// 充电桩输入电压欠压故障 + /// + [Property(39, 1)] + public bool ChargerInputUnderVoltageError { get; set; } + + /// + /// 直流母线输出过压故障 + /// + [Property(40, 1)] + public bool DcBusOutputOverVoltageError { get; set; } + + /// + /// 直流母线输出欠压故障 + /// + [Property(41, 1)] + public bool DcBusOutputUnderVoltageError { get; set; } + + /// + /// 直流母线输出过流故障 + /// + [Property(42, 1)] + public bool DcBusOutputOverCurrentError { get; set; } + + /// + /// 车辆连接状态 0-未连接、1-已连接 + /// + [Property(43, 1)] + public bool VehicleConnStatus { get; set; } + + /// + /// 充电桩充电枪座状态 0-已连接、1-未连接 + /// + [Property(44, 1)] + public bool ChargeStationGunHolderStatus { get; set; } + + /// + /// 充电接口电子锁状态 0-解锁、1-锁止 + /// + [Property(45, 1)] + public bool ChargingInterfaceLockStatus { get; set; } + + /// + /// 正极直流输出接触器状态 0-分断、1-闭合 + /// + [Property(46, 1)] + public bool PositiveDcTransmissionContactorStatus { get; set; } + + /// + /// 负极直流输出接触器状态 0-分断 1-闭合 + /// + [Property(47, 1)] + public bool NegativeDcTransmissionContactorStatus { get; set; } + + /// + /// 门禁故障 0-正常 1-故障 + /// + [Property(48, 1)] + public bool EntranceGuardError { get; set; } + + /// + /// 正极直流输出接触器粘连故障 + /// + [Property(49, 1)] + public bool PConA3dhesionFailure { get; set; } + + /// + /// 负极直流输出接触器粘连故故障 + /// + [Property(50, 1)] + public bool NConadhesionFailure { get; set; } + + /// + /// 泄放回路故障 + /// + [Property(51, 1)] + public bool ReliefCircuitError { get; set; } + + /// + /// 充电桩交流输入接触器据动/误动故(预留位置供其他适用) + /// + [Property(52, 1)] + public bool ConActivated { get; set; } + + /// + /// 充电桩交流输入接触器粘连故障(预留位置供其他适用) + /// + [Property(53, 1)] + public bool ConAdhesionFailure { get; set; } + + /// + /// 辅助电源故障 + /// + [Property(54, 1)] + public bool AuxiliaryPowerError { get; set; } + + /// + /// 模块输出反接 + /// + [Property(55, 1)] + public bool ModuleOutputReverseError { get; set; } + + /// + /// 充电桩交流接触器状态 0-分断 1-吸合 + /// + [Property(56, 1)] + public bool AcContactorStatus { get; set; } + + /// + /// 充电枪过温告警 0-正常 1-故障 + /// + [Property(57, 1)] + public bool ChargingGunOverTempWarning { get; set; } + + /// + /// 充电桩过温告警 0-正常 1-故障 + /// + [Property(58, 1)] + public bool ChargerOverTempWarning { get; set; } + + /// + /// 电表通信异常 0-正常 01H-故障 + /// + [Property(59, 1)] + public bool MeterConnError { get; set; } + + /// + /// 电表电度异常 0-正常 02H-故障 + /// + [Property(60, 1)] + public bool MeterDataError { get; set; } + + /// + /// 水浸告警 0-正常 03H-故障 + /// + [Property(61, 1)] + public bool WaterloggingWarning { get; set; } + + /// + /// 电池包辅助电源状态 0:辅助电源未给电池包供电、1:辅助电源正在给电池包供电 + /// + [Property(62, 1)] + public bool BatteryPackAuxiliaryPowerStatus { get; set; } + + /// + /// 逆功率报警 00H:正常 01H:故障 + /// 发生该故障后一直保持,只到重合闸完成后,可以重合闸信号变为可用状态时才清零。 + /// + [Property(63, 1)] + public bool ReversePowerWarning { get; set; } +} \ No newline at end of file diff --git a/Service/Charger/Msg/Charger/OutCharger/Req/PileUploadTelemetry.cs b/Service/Charger/Msg/Charger/OutCharger/Req/PileUploadTelemetry.cs new file mode 100644 index 0000000..15e7a08 --- /dev/null +++ b/Service/Charger/Msg/Charger/OutCharger/Req/PileUploadTelemetry.cs @@ -0,0 +1,205 @@ +using HybirdFrameworkCore.Autofac.Attribute; + +namespace Service.Charger.Msg.Charger.OutCharger.Req; + +/// +/// 3.7.12 充电桩遥测数据上报 +/// +public class PileUploadTelemetry : ASDU +{ + /// + /// 记录类型 + /// + [Property(0, 8)] + public byte RecordType { get; set; } + + /// + /// 充电枪ID号 + /// 0x01:充电枪1;0x02:充电枪2;0x03:双枪充电;(0x00&0xFF无效) + /// + [Property(8, 8)] + public byte Pn { get; set; } + + /// + /// 当前 SOC + /// + [Property(16, 8)] + public byte CurrentSoc { get; set; } + + /// + /// 最高蓄电池温度 + /// + [Property(24, 16, offset: 50)] + public Int16 MaxBatteryTemp { get; set; } + + /// + /// 最高温度检测点编号 + /// + [Property(40, 16)] + public ushort MaxTempDetectionPointNo { get; set; } + + /// + /// 最低蓄电池温度数据分辨率:1ºC/位,-50 ºC 偏移量;数据范围:-50ºC ~+200ºC; + /// + [Property(56, 16, PropertyReadConstant.Bit, 1, 0, 50)] + public Int16 MinBatteryTemp { get; set; } + + /// + /// 最低温度检测点编号 + /// + [Property(72, 16)] + public ushort MinTempDetectionPointNo { get; set; } + + /// + /// 单体电池最高电压 + /// + [Property(88, 16, PropertyReadConstant.Bit, 0.01, 2, 0)] + public float SingleBatteryMaxVoltage { get; set; } + + /// + /// 单体电池最低电压 + /// + [Property(104, 16, PropertyReadConstant.Bit, 0.01, 2, 0)] + public float SingleBatteryMinVoltage { get; set; } + + /// + /// 充电机环境温度 + /// + [Property(120, 8, PropertyReadConstant.Bit, 1, 0, 50)] + public Int16 ChargerEnvTemp { get; set; } + + /// + /// 充电导引电压 + /// + [Property(128, 16, PropertyReadConstant.Bit, 0.01, 2, 0)] + public float ChargingPilotVoltage { get; set; } + + /// + /// BMS 需求电压 + /// + [Property(144, 16, PropertyReadConstant.Bit, 0.1, 1, 0)] + public float BmsNeedVoltage { get; set; } + + /// + /// BMS 需求电流 + /// + [Property(160, 16, PropertyReadConstant.Bit, 0.1, 1, 400)] + public float BmsNeedCurrent { get; set; } + + /// + /// 充电模式 01H:恒压充电、02H恒流充电 + /// + [Property(176, 8)] + public byte ChargeMode { get; set; } + + + /// + /// BMS 充电电压测量值 + /// + [Property(184, 16, PropertyReadConstant.Bit, 0.1, 1, 0)] + public float BmsChargingVoltage { get; set; } + + + /// + /// BMS 充电电流测量值 + /// + [Property(200, 16, PropertyReadConstant.Bit, 0.1, 1, 400)] + public float BmsChargingCurrent { get; set; } + + /// + /// 估算剩余充电时间 + /// + [Property(216, 16, PropertyReadConstant.Bit, 1, 0, 0)] + public ushort EstimatedRemainingTime { get; set; } + + /// + /// 充电接口温度探头 1 + /// + [Property(232, 8, PropertyReadConstant.Bit, 1, 0, 50)] + public Int16 ChargingInterfaceDetectionOneTemp { get; set; } + + /// + /// 充电接口温度探头 2 + /// + [Property(240, 8, PropertyReadConstant.Bit, 1, 0, 50)] + public Int16 ChargingInterfaceDetectionTwoTemp { get; set; } + + /// + /// 充电接口温度探头 4 + /// + [Property(248, 8, PropertyReadConstant.Bit, 1, 0, 50)] + public Int16 ChargingInterfaceDetectionFourTemp { get; set; } + + /// + /// 直流电表当前电量 + /// + [Property(256, 32, PropertyReadConstant.Bit, 0.01, 2)] + public float DcMeterCurrentPower { get; set; } + + /// + /// 充电电压(直流电表电压) + /// + [Property(288, 16, PropertyReadConstant.Bit, 0.1, 1)] + public float DcMeterVoltage { get; set; } + + /// + /// 充电电流(直流电表电流) + /// + [Property(304, 16, PropertyReadConstant.Bit, 0.1, 1)] + public float DcMeterCurrent { get; set; } + + /// + /// 高压采集电压 + /// + [Property(320, 16, PropertyReadConstant.Bit, 0.1, 1)] + public float HighVoltageAcquisitionVoltage { get; set; } + + /// + /// 高压采集电流 + /// + [Property(336, 16, PropertyReadConstant.Bit, 0.1, 1)] + public float HighVoltageAcquisitionCurrent { get; set; } + + /// + /// 桩内部温度 + /// + [Property(352, 8, PropertyReadConstant.Bit, 1, 0)] + public byte ChargerInsideTemp { get; set; } + + /// + /// 本次充电时间 + /// + [Property(360, 16)] + public ushort ChargingTime { get; set; } + + /// + /// 模块进风口温度 + /// + [Property(376, 8)] + public byte ModuleOneAirInletTemp { get; set; } + + /// + /// 模块出风口温度 + /// + [Property(384, 8)] + public byte ModuleTwoAirInletTemp { get; set; } + + /// + /// 充电模式 0:站内充电 1:站外充电 + /// + [Property(392, 8)] + public byte ChargeModel { get; set; } + + /// + /// 充电启动方式 1:站控启动 2:本地充电 + /// + [Property(400, 8)] + public byte ChargingStartMethod { get; set; } + + + /// + /// 交流电表当前电量 + /// + [Property(408, 32, PropertyReadConstant.Bit, 0.01, 2)] + public float ACMeterCurrentBatteryValue { get; set; } +} \ No newline at end of file diff --git a/Service/Charger/Msg/Charger/OutCharger/Resp/PileStartChargeRes.cs b/Service/Charger/Msg/Charger/OutCharger/Resp/PileStartChargeRes.cs new file mode 100644 index 0000000..105a42b --- /dev/null +++ b/Service/Charger/Msg/Charger/OutCharger/Resp/PileStartChargeRes.cs @@ -0,0 +1,36 @@ +using HybirdFrameworkCore.Autofac.Attribute; + +namespace Service.Charger.Msg.Charger.OutCharger.Resp; + +/// +/// 3.7.2 充电桩响应远程启动充电 +/// +public class PileStartChargeRes : ASDU +{ + /// + /// 记录类型 + /// + [Property(0, 8)] + public byte RecordType { get; set; } + + /// + /// 充电枪ID + /// 0x01:充电枪1;0x02:充电枪2;0x03:双枪充电;(0x00&0xFF无效) + /// + [Property(8, 8)] + public byte Pn { get; set; } + + /// + /// 启动结果 + /// 0 成功 1 失败 + /// + [Property(16, 8)] + public byte Result { get; set; } + + /// + /// 失败原因 + /// 默认 0 + /// + [Property(24, 8)] + public byte FailReason { get; set; } +} \ No newline at end of file diff --git a/Service/Charger/Msg/Charger/OutCharger/Resp/PileStopChargeRes.cs b/Service/Charger/Msg/Charger/OutCharger/Resp/PileStopChargeRes.cs new file mode 100644 index 0000000..c0081e5 --- /dev/null +++ b/Service/Charger/Msg/Charger/OutCharger/Resp/PileStopChargeRes.cs @@ -0,0 +1,28 @@ +using HybirdFrameworkCore.Autofac.Attribute; + +namespace Service.Charger.Msg.Charger.OutCharger.Resp; + +/// +/// 3.7.4 充电桩响应远程停止充电 +/// +public class PileStopChargeRes : ASDU +{ + /// + /// 记录类型 + /// + [Property(0, 8)] + public byte RecordType { get; set; } + + /// + /// 充电枪ID + /// 0x01:充电枪1;0x02:充电枪2;0x03:双枪充电;(0x00&0xFF无效) + /// + [Property(8, 8)] + public byte pn { get; set; } + + /// + /// 启动结果 0 成功 1 设备已停机 0xFF 其他 + /// + [Property(16, 8)] + public byte rs { get; set; } +} \ No newline at end of file diff --git a/Service/Charger/Msg/Host/Req/OutCharger/Req/PileStartCharge.cs b/Service/Charger/Msg/Host/Req/OutCharger/Req/PileStartCharge.cs new file mode 100644 index 0000000..4bd0419 --- /dev/null +++ b/Service/Charger/Msg/Host/Req/OutCharger/Req/PileStartCharge.cs @@ -0,0 +1,65 @@ +using HybirdFrameworkCore.Autofac.Attribute; + +namespace Service.Charger.Msg.Host.OutCharger.Req; + +/// +/// 3.7.1 监控平台远程启动充电桩充电 +/// +public class PileStartCharge : ASDU +{ + /// + /// 记录类型 + /// + [Property(0, 8)] + public byte RecordType { get; set; } + + /// + /// 充电枪ID号 + /// 0x01:充电枪1;0x02:充电枪2;0x03:双枪充电;(0x00&0xFF无效) + /// + [Property(8, 8)] + public byte Pn { get; set; } + + /// + /// SOC 限制 + /// 百分比 + /// + [Property(16, 8)] + public byte SocValue { get; set; } + + /// + /// 功率调节指令类型 + /// 默认 1 绝对功率值 + /// + [Property(24, 8)] + public byte ChangePowerCmdType { get; set; } = 1; + + /// + /// 功率调节参数 + /// 0. 1kwh/位 + /// + [Property(32, 16, PropertyReadConstant.Bit, 0.1, 1)] + public short ChangePower { get; set; } + + /// + /// 充电流水号 + /// + [Property(48, 256)] + public string ChargeOrderNo { get; set; } + + public PileStartCharge(byte pn, byte socValue, byte changePowerCmdType, short changePower, string chargeOrderNo) + { + RecordType = 1; + FrameTypeNo = 51; + MsgBodyCount = 1; + TransReason = 3; + PublicAddr = 0; + MsgBodyAddr = new byte[] { 0, 0, 0 }; + + Pn = pn; + SocValue = socValue; + ChangePowerCmdType = changePowerCmdType; + ChangePower = changePower; + ChargeOrderNo = chargeOrderNo; + } +} \ No newline at end of file diff --git a/Service/Charger/Msg/Host/Req/OutCharger/Req/PileStopCharge.cs b/Service/Charger/Msg/Host/Req/OutCharger/Req/PileStopCharge.cs new file mode 100644 index 0000000..ee47f01 --- /dev/null +++ b/Service/Charger/Msg/Host/Req/OutCharger/Req/PileStopCharge.cs @@ -0,0 +1,42 @@ +using HybirdFrameworkCore.Autofac.Attribute; + +namespace Service.Charger.Msg.Host.OutCharger.Req; + +/// +/// 3.7.3 监控平台远程停止充电桩充电 +/// +public class PileStopCharge : ASDU +{ + /// + /// 记录类型 + /// + [Property(0, 8)] + public byte RecordType { get; set; } + + /// + /// 充电枪ID号 + /// 0x01:充电枪1;0x02:充电枪2;0x03:双枪充电;(0x00&0xFF无效) + /// + [Property(8, 8)] + public byte Pn { get; set; } + + /// + /// 停止原因 + /// + [Property(16, 8)] + public byte StopReason { get; set; } + + public PileStopCharge(byte pn,byte stopReason) + { + RecordType = 3; + FrameTypeNo = 51; + MsgBodyCount = 1; + TransReason = 3; + PublicAddr = 0; + MsgBodyAddr = new byte[] { 0, 0, 0 }; + + Pn = pn; + + StopReason = stopReason; + } +} \ No newline at end of file diff --git a/Service/Charger/Msg/Host/Resp/OutCharger/PileChargeCompleteRes.cs b/Service/Charger/Msg/Host/Resp/OutCharger/PileChargeCompleteRes.cs new file mode 100644 index 0000000..dabc430 --- /dev/null +++ b/Service/Charger/Msg/Host/Resp/OutCharger/PileChargeCompleteRes.cs @@ -0,0 +1,40 @@ +using HybirdFrameworkCore.Autofac.Attribute; + +namespace Service.Charger.Msg.Host.Resp.OutCharger; +/// +/// 3.7.8 监控平台应答充电桩停止完成帧 +/// +public class PileChargeCompleteRes : ASDU +{ + /// + /// 记录类型 + /// + [Property(0, 8)] + public byte RecordType { get; set; } + + /// + /// 充电枪ID号 + /// 0x01:充电枪1;0x02:充电枪2;0x03:双枪充电;(0x00&0xFF无效) + /// + [Property(8, 8)] + public byte Pn { get; set; } + + /// + /// 成功标识 0:成功;1:失败 + /// + [Property(16, 8)] + public byte Result { get; set; } + + public PileChargeCompleteRes(byte pn,byte result) + { + RecordType = 8; + FrameTypeNo = 51; + MsgBodyCount = 1; + TransReason = 4; + PublicAddr = 0; + MsgBodyAddr = new byte[] { 0, 0, 0 }; + + Pn = pn; + Result = result; + } +} \ No newline at end of file diff --git a/Service/Charger/Msg/Host/Resp/OutCharger/PileStartChargeCompleteRes.cs b/Service/Charger/Msg/Host/Resp/OutCharger/PileStartChargeCompleteRes.cs new file mode 100644 index 0000000..551c7ec --- /dev/null +++ b/Service/Charger/Msg/Host/Resp/OutCharger/PileStartChargeCompleteRes.cs @@ -0,0 +1,49 @@ +using HybirdFrameworkCore.Autofac.Attribute; + +namespace Service.Charger.Msg.Host.Resp.OutCharger; + +/// +/// 3.7.6 监控平台应答充电桩启动完成帧 +/// +public class PileStartChargeCompleteRes : ASDU +{ + /// + /// 记录类型 + /// + [Property(0, 8)] + public byte RecordType { get; set; } + + /// + /// 充电枪ID号 + /// 0x01:充电枪1;0x02:充电枪2;0x03:双枪充电;(0x00&0xFF无效) + /// + [Property(8, 8)] + public byte Pn { get; set; } + + /// + /// 成功标识 0:成功;1:失败 + /// + [Property(16, 8)] + public byte Result { get; set; } + + /// + /// 失败原因 + /// 0:成功1:交易流水号数据异常2:充电方式数据异常3:其他数据异常4:服务器异常5:服务器繁忙6:枪编号非法7 :服务器判定启动完成帧超时0xFF:其他错误 + /// + [Property(24, 8)] + public byte FailReason { get; set; } + + public PileStartChargeCompleteRes(byte pn,byte result,byte failReason) + { + RecordType = 6; + FrameTypeNo = 51; + MsgBodyCount = 1; + TransReason = 4; + PublicAddr = 0; + MsgBodyAddr = new byte[] { 0, 0, 0 }; + + Pn = pn; + Result = result; + FailReason = failReason; + } +} \ No newline at end of file diff --git a/Service/Charger/Msg/Http/Req/PileStartChargeHttpReq.cs b/Service/Charger/Msg/Http/Req/PileStartChargeHttpReq.cs new file mode 100644 index 0000000..e6820a1 --- /dev/null +++ b/Service/Charger/Msg/Http/Req/PileStartChargeHttpReq.cs @@ -0,0 +1,44 @@ +namespace Service.Charger.Msg.Http.Req; +/// +/// 9.2.1.1 云平台下发开始充电操作 +/// +public class PileStartChargeHttpReq +{ + /// + /// 换电站编码 + /// 换电站唯一码 + /// + public string? sn { get; set; } + + /// + /// 充电订单号 + /// 云平台下发的充电订单编号,;当启动模式为本地主动启动(即插即充)时,该 值以 0 填充 + /// + public string? con { get; set; } + + /// + /// 充电枪编号 + /// 充电枪的唯一标识码 + /// + public string pn { get; set; } + + /// + /// 充电方式 + /// 0:自动(充满为止);1:按电量; + /// + public int? ct { get; set; } + + /// + /// 充电参数 + /// 按充电方式判断,除0外 电量:单位 kWh,精确到 0.01 时间:单位 min,精确到 0.01 金额:单位 元,精确到 0.01 + /// + public string? cp { get; set; } + + /// + /// 启动类型 + /// 0:运营平台启动;1:APP 启动;2: 本地启动 + /// + public int? st { get; set; } + + +} \ No newline at end of file diff --git a/Service/Charger/Msg/Http/Req/PileStopChargeHttpReq.cs b/Service/Charger/Msg/Http/Req/PileStopChargeHttpReq.cs new file mode 100644 index 0000000..138d8e7 --- /dev/null +++ b/Service/Charger/Msg/Http/Req/PileStopChargeHttpReq.cs @@ -0,0 +1,20 @@ +namespace Service.Charger.Msg.Http.Req; + +/// +/// 9.2.17 云端下发充电枪停止充电 +/// +public class PileStopChargeHttpReq +{ + /// + /// 换电站编码 + /// 换电站唯一码 + /// + public string sn { get; set; } + + + /// + /// 充电枪编号 + /// 充电枪的唯一标识码 + /// + public string pn { get; set; } +} \ No newline at end of file diff --git a/Service/Charger/Msg/Http/Resp/PileStartChargeHttpRes.cs b/Service/Charger/Msg/Http/Resp/PileStartChargeHttpRes.cs new file mode 100644 index 0000000..0b8c532 --- /dev/null +++ b/Service/Charger/Msg/Http/Resp/PileStartChargeHttpRes.cs @@ -0,0 +1,27 @@ +namespace Service.Charger.Msg.Http.Resp; + +/// +/// 9.2.1.2 站控应答开始充电操作 +/// +public class PileStartChargeHttpRes +{ + /// + /// 执行结果 + /// + public string? rs { get; set; } + + /// + /// 充电订单号 + /// + public string? con { get; set; } + + /// + /// 充电枪编号 + /// + public string? pn { get; set; } + + /// + /// 故障码 + /// + public string? ec { get; set; } +} \ No newline at end of file diff --git a/Service/Charger/Msg/Http/Resp/PileStopChargeHttpRes.cs b/Service/Charger/Msg/Http/Resp/PileStopChargeHttpRes.cs new file mode 100644 index 0000000..2ae6728 --- /dev/null +++ b/Service/Charger/Msg/Http/Resp/PileStopChargeHttpRes.cs @@ -0,0 +1,17 @@ +namespace Service.Charger.Msg.Http.Resp; +/// +/// 9.2.1.8 站控响应充电枪停止充电操作 +/// +public class PileStopChargeHttpRes +{ + /// + /// 充电枪ID + /// 0x01:充电枪1;0x02:充电枪2;0x03:双枪充电;(0x00&0xFF无效) + /// + public string pn { get; set; } + + /// + /// 启动结果 0 成功 1 设备已停机 0xFF 其他 + /// + public string rs { get; set; } +} \ No newline at end of file diff --git a/WebStarter/Controllers/OutChargerController.cs b/WebStarter/Controllers/OutChargerController.cs new file mode 100644 index 0000000..6ea61d9 --- /dev/null +++ b/WebStarter/Controllers/OutChargerController.cs @@ -0,0 +1,84 @@ +using HybirdFrameworkCore.Entity; +using Microsoft.AspNetCore.Mvc; +using Repository.Station; +using Service.Charger.Client; +using Service.Charger.Common; +using Service.Charger.Msg.Http.Req; +using Service.Init; + +namespace WebStarter.Controllers; + +/// +/// 站外充电机管理 +/// +[Produces("application/json")] +[ApiController] +[Route("api/[controller]")] +public class OutChargerController +{ + private ChargeOrderRepository _chargeOrderRepository; + + public OutChargerController(ChargeOrderRepository chargeOrderRepository) + { + _chargeOrderRepository = chargeOrderRepository; + } + + /// + /// 云平台下发开始充电操作 + /// + /// + /// + [HttpPost] + [Route("SendStartOutCharger")] + public Result SendStartOutCharger([FromBody] PileStartChargeHttpReq httpReq) + { + string chargerCode = ChargerUtils.GetOutChargerCode(httpReq.pn); + + byte chargerGunCode = ChargerUtils.GetTheGun(httpReq.pn); + + ChargerClient? chargerClient = ClientMgr.GetBySn(chargerCode); + + if (chargerClient == null) + { + return Result.Fail("充电机未连接"); + } + + if (string.IsNullOrWhiteSpace(httpReq.con)) + { + httpReq.con = ChargerUtils.GenChargeOrderSn(); + } + + byte chargeSoc = StaticStationInfo.ChargeSoc; + // 下发充电枪充电 + chargerClient.SendStartOutCharger(chargerGunCode, chargeSoc, 360, 1, httpReq.con); + // 初始化订单 + _chargeOrderRepository.SaveChargeGunOrder(httpReq.con, chargerCode, httpReq.pn, chargerGunCode.ToString()); + + return Result.Success(true); + } + /// + /// 云端下发充电枪停止充电 + /// + /// + /// + [HttpPost] + [Route("SendStopOutCharger")] + public Result SendStopOutCharger([FromBody] PileStopChargeHttpReq httpReq) + { + string chargerCode = ChargerUtils.GetOutChargerCode(httpReq.pn); + + byte chargerGunCode = ChargerUtils.GetTheGun(httpReq.pn); + + ChargerClient? chargerClient = ClientMgr.GetBySn(chargerCode); + + if (chargerClient == null) + { + return Result.Fail("充电机未连接"); + } + + // 下发充电枪停止充电 + chargerClient.SendStopOutCharger(chargerGunCode, 0); + + return Result.Success(true); + } +} \ No newline at end of file