diff --git a/Common/Util/HttpUtil.cs b/Common/Util/HttpUtil.cs index 0d9e8a6..db474ba 100644 --- a/Common/Util/HttpUtil.cs +++ b/Common/Util/HttpUtil.cs @@ -3,6 +3,9 @@ using Newtonsoft.Json; namespace Common.Util; +/// +/// http工具类 +/// public static class HttpUtil { private static readonly HttpClient httpClient = new HttpClient(); diff --git a/Service/Charger/Client/ChargerClient.cs b/Service/Charger/Client/ChargerClient.cs index 4b0d09c..e8c9f43 100644 --- a/Service/Charger/Client/ChargerClient.cs +++ b/Service/Charger/Client/ChargerClient.cs @@ -18,9 +18,9 @@ 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; +using Service.Charger.Msg.Host.Req.OutCharger.Req; namespace Service.Charger.Client; @@ -545,6 +545,24 @@ public class ChargerClient : TcpClient return Result.Success(); } + + /// + /// 3.7.9 监控平台发送充电桩功率调节指令 + /// + /// + /// + /// + public Result SendPileAdjustPower(byte pn,float expectedOperatingPower) + { + if (!Connected) + { + return Result.Fail($"charger-{BinNo} disconnect"); + } + + PileAdjustPower powerRegulation = new PileAdjustPower(pn,expectedOperatingPower); + this.Channel.WriteAndFlushAsync(powerRegulation); + return Result.Success(); + } /// /// /// diff --git a/Service/Charger/Client/ChargerPile.cs b/Service/Charger/Client/ChargerPile.cs index 240b1a6..a5f3f07 100644 --- a/Service/Charger/Client/ChargerPile.cs +++ b/Service/Charger/Client/ChargerPile.cs @@ -46,5 +46,10 @@ public class ChargerPile /// 充电枪的唯一标识码 /// public string? pn { get; set; } + + /// + /// 工作状态 + /// + public byte WorkStatus { get; set; } } \ No newline at end of file diff --git a/Service/Charger/Codec/Decoder.cs b/Service/Charger/Codec/Decoder.cs index 869098d..6826491 100644 --- a/Service/Charger/Codec/Decoder.cs +++ b/Service/Charger/Codec/Decoder.cs @@ -250,6 +250,7 @@ public class Decoder : ByteToMessageDecoder 12 => ModelConvert.Decode(bytes), 11 => ModelConvert.Decode(bytes), 14 => ModelConvert.Decode(bytes), + 10 => ModelConvert.Decode(bytes), _ => throw new InvalidOperationException("This should never be reached"), }, #endregion diff --git a/Service/Charger/Handler/OutCharger/PileAdjustPowerHandler.cs b/Service/Charger/Handler/OutCharger/PileAdjustPowerHandler.cs new file mode 100644 index 0000000..ca2a1c7 --- /dev/null +++ b/Service/Charger/Handler/OutCharger/PileAdjustPowerHandler.cs @@ -0,0 +1,22 @@ +using DotNetty.Transport.Channels; +using log4net; +using Service.Charger.Client; +using Service.Charger.Msg.Charger.OutCharger.Resp; + +namespace Service.Charger.Handler.OutCharger; +/// +/// 3.7.10 充电桩应答功率调节指令 +/// +public class PileAdjustPowerHandler : SimpleChannelInboundHandler, IBaseHandler +{ + private static readonly ILog Log = LogManager.GetLogger(typeof(PileAdjustPowerHandler)); + + + protected override void ChannelRead0(IChannelHandlerContext ctx, PileAdjustPowerRes msg) + { + if (ClientMgr.TryGetClient(ctx.Channel, out var sn, out var client)) + { + Log.Info($"receive {msg} from {sn}"); + } + } +} \ No newline at end of file diff --git a/Service/Charger/Handler/OutCharger/PileStartChargeResHandler.cs b/Service/Charger/Handler/OutCharger/PileStartChargeResHandler.cs index b2913bd..33c92d2 100644 --- a/Service/Charger/Handler/OutCharger/PileStartChargeResHandler.cs +++ b/Service/Charger/Handler/OutCharger/PileStartChargeResHandler.cs @@ -11,6 +11,7 @@ using Service.Charger.Msg.Charger.OutCharger.Resp; using Service.Charger.Msg.Http.Resp; namespace Service.Charger.Handler.OutCharger; + /// /// 3.7.2 充电桩响应远程启动充电 /// @@ -20,7 +21,7 @@ public class PileStartChargeResHandler : SimpleChannelInboundHandler +/// 3.7.10 充电桩应答功率调节指令 +/// +public class PileAdjustPowerRes: 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/Host/Req/OutCharger/Req/PileAdjustPower.cs b/Service/Charger/Msg/Host/Req/OutCharger/Req/PileAdjustPower.cs new file mode 100644 index 0000000..eb31fc0 --- /dev/null +++ b/Service/Charger/Msg/Host/Req/OutCharger/Req/PileAdjustPower.cs @@ -0,0 +1,42 @@ +using HybirdFrameworkCore.Autofac.Attribute; + +namespace Service.Charger.Msg.Host.Req.OutCharger.Req; +/// +/// 3.7.9 监控平台发送充电桩功率调节指令 +/// +public class PileAdjustPower: 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(8, 16, PropertyReadConstant.Bit, 0.1, 1)] + public float ExpectPower { get; set; } + + + public PileAdjustPower(byte pn,float expectPower) + { + RecordType = 9; + FrameTypeNo = 51; + MsgBodyCount = 1; + TransReason = 3; + PublicAddr = 0; + MsgBodyAddr = new byte[] { 0, 0, 0 }; + + Pn = pn; + ExpectPower = expectPower; + } +} \ 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 index 4bd0419..a0c74a4 100644 --- a/Service/Charger/Msg/Host/Req/OutCharger/Req/PileStartCharge.cs +++ b/Service/Charger/Msg/Host/Req/OutCharger/Req/PileStartCharge.cs @@ -1,6 +1,6 @@ using HybirdFrameworkCore.Autofac.Attribute; -namespace Service.Charger.Msg.Host.OutCharger.Req; +namespace Service.Charger.Msg.Host.Req.OutCharger.Req; /// /// 3.7.1 监控平台远程启动充电桩充电 diff --git a/Service/Charger/Msg/Host/Req/OutCharger/Req/PileStopCharge.cs b/Service/Charger/Msg/Host/Req/OutCharger/Req/PileStopCharge.cs index ee47f01..e011708 100644 --- a/Service/Charger/Msg/Host/Req/OutCharger/Req/PileStopCharge.cs +++ b/Service/Charger/Msg/Host/Req/OutCharger/Req/PileStopCharge.cs @@ -1,6 +1,6 @@ using HybirdFrameworkCore.Autofac.Attribute; -namespace Service.Charger.Msg.Host.OutCharger.Req; +namespace Service.Charger.Msg.Host.Req.OutCharger.Req; /// /// 3.7.3 监控平台远程停止充电桩充电 diff --git a/Service/Charger/Msg/Http/Req/PileRealtimeReq.cs b/Service/Charger/Msg/Http/Req/PileRealtimeReq.cs new file mode 100644 index 0000000..1128c8e --- /dev/null +++ b/Service/Charger/Msg/Http/Req/PileRealtimeReq.cs @@ -0,0 +1,45 @@ +namespace Service.Charger.Msg.Http.Req; +/// +/// 9.2.1.5 站控上报充电枪实时数据上报 +/// +public class PileRealtimeReq +{ + /// + /// 换电站编码 + /// + public string sn { get; set; } + + + /// + /// Desc:充电枪编号 + /// Default: + /// Nullable:True + /// + public string? pn { get; set; } + + /// + /// 充电枪状态 + /// + public int ps { get; set; } + + /// + /// 插枪状态 + /// + public int con { get; set; } + + + /// + /// 单枪输出电压 + /// + public float pov { get; set; } + + /// + /// 单枪输出电流 + /// + public float poe { get; set; } + + /// + /// 单枪故障代码 + /// + public int ec { get; set; } +} \ No newline at end of file diff --git a/Service/Charger/MyTask/PileChargeRealtimeTask.cs b/Service/Charger/MyTask/PileChargeRealtimeTask.cs new file mode 100644 index 0000000..d2cb561 --- /dev/null +++ b/Service/Charger/MyTask/PileChargeRealtimeTask.cs @@ -0,0 +1,103 @@ +using System.Collections.Concurrent; +using Common.Util; +using HybirdFrameworkCore.Autofac.Attribute; +using HybirdFrameworkCore.AutoTask; +using log4net; +using Service.Charger.Client; +using Service.Charger.Msg.Charger.OutCharger.Req; +using Service.Charger.Msg.Charger.Req; +using Service.Charger.Msg.Http.Req; +using Service.Init; + +namespace Service.Charger.MyTask; +/// +/// 9.2.1.7 站控上报充电枪充电遥测数据 +/// +[Scope] +public class PileChargeRealtimeTask : ITask +{ + private static readonly ILog Log = LogManager.GetLogger(typeof(PileChargeRealtimeTask)); + private volatile bool _stop; + + + public string Name() + { + return "PileChargeRealtimeTask"; + } + + public int Interval() + { + return 1000 * 30; + } + + public void Handle() + { + + ConcurrentDictionary chargerClients = ClientMgr.Dictionary; + + if (chargerClients.Values.Count <= 0) + { + return; + } + + foreach (var clientPair in chargerClients) + { + ChargerClient client = clientPair.Value; + + ProcessClient(client, 1); + ProcessClient(client, 2); + } + } + + private void ProcessClient(ChargerClient client, byte gunNumber) + { + if (client.GunCharged[gunNumber]) + { + ChargerPile chargerPile = client.ChargerPile[gunNumber]; + PileUploadTelemetry telemetry = client.PileUploadTelemetry[gunNumber]; + PileUploadRemoteSignal pileUploadRemoteSignal = client.PileUploadRemoteSignal[gunNumber]; + + PileChargeRealtimeReq req = new PileChargeRealtimeReq + { + sn = StaticStationInfo.StationNo, + con = chargerPile.con, + cosn = chargerPile.cosn, + pn = chargerPile.pn, + rv = telemetry.BmsNeedVoltage, + re = telemetry.BmsNeedCurrent, + cm = telemetry.ChargeMode, + cdv = telemetry.BmsChargingVoltage, + cde = telemetry.BmsChargingCurrent, + soc = telemetry.CurrentSoc, + tr = telemetry.EstimatedRemainingTime, + pov = telemetry.DcMeterVoltage, + poe = telemetry.DcMeterCurrent, + tct = telemetry.ChargingTime, + lbtn = telemetry.MinTempDetectionPointNo, + lbt = telemetry.MinBatteryTemp, + hbtn = telemetry.MaxTempDetectionPointNo, + hbt = telemetry.MaxBatteryTemp, + hlbva = pileUploadRemoteSignal.ChargerInputOverVoltageError ? 1 : + pileUploadRemoteSignal.ChargerInputUnderVoltageError ? 2 : 0, + bia = pileUploadRemoteSignal.InsulationDetectionAlarm ? 1 : 0 + }; + + HttpUtil.SendPostRequest(req, "http://127.0.0.1:5034/api/OutCharger/SendPileChargeRealtime"); + } + } + + public bool Stoped() + { + return _stop; + } + + public void Stop() + { + _stop = true; + } + + public void ResetStop() + { + _stop = false; + } +} \ No newline at end of file diff --git a/Service/Charger/MyTask/PileRealtimeTask.cs b/Service/Charger/MyTask/PileRealtimeTask.cs new file mode 100644 index 0000000..3b6bf4c --- /dev/null +++ b/Service/Charger/MyTask/PileRealtimeTask.cs @@ -0,0 +1,100 @@ +using System.Collections.Concurrent; +using Common.Util; +using HybirdFrameworkCore.Autofac.Attribute; +using HybirdFrameworkCore.AutoTask; +using log4net; +using Service.Charger.Client; +using Service.Charger.Msg.Charger.OutCharger.Req; +using Service.Charger.Msg.Http.Req; +using Service.Init; + +namespace Service.Charger.MyTask; +/// +/// 9.2.1.5 站控上报充电枪实时数据上报 +/// +[Scope] +public class PileRealtimeTask : ITask +{ + private static readonly ILog Log = LogManager.GetLogger(typeof(PileRealtimeTask)); + private volatile bool _stop; + + public string Name() + { + return "PileRealtimeTask"; + } + + public int Interval() + { + return 1000 * 5; + } + + public void Handle() + { + ConcurrentDictionary chargerClients = ClientMgr.Dictionary; + + if (chargerClients.Values.Count <= 0) + { + return; + } + + foreach (var kvp in chargerClients) + { + ChargerClient client = kvp.Value; + + HandleChargerPile(client, 1); + HandleChargerPile(client, 2); + } + } + + + + public bool Stoped() + { + return _stop; + } + + public void Stop() + { + _stop = true; + } + + public void ResetStop() + { + _stop = false; + } + + private void HandleChargerPile(ChargerClient client, byte pileIndex) + { + if (client.ChargedPile[pileIndex]) + { + ChargerPile chargerPile = client.ChargerPile[pileIndex]; + PileUploadTelemetry pileUploadTelemetry = client.PileUploadTelemetry[pileIndex]; + + PileRealtimeReq req = new PileRealtimeReq + { + sn = StaticStationInfo.StationNo, + pn = chargerPile.pn, + ps = GetPileStatus(chargerPile.WorkStatus), + pov = pileUploadTelemetry.BmsChargingVoltage, + poe = pileUploadTelemetry.BmsChargingCurrent, + ec = 0 + }; + + HttpUtil.SendPostRequest(req, "http://127.0.0.1:5034/api/OutCharger/SendPileRealtime"); + } + } + + private int GetPileStatus(int workStatus) + { + return workStatus switch + { + 0 => 1, + 1 => 3, + 2 => 4, + 3 => 5, + _ => 1 + }; + } + + +} \ No newline at end of file diff --git a/WebStarter/Controllers/OutChargerController.cs b/WebStarter/Controllers/OutChargerController.cs index 0cca89a..05eab35 100644 --- a/WebStarter/Controllers/OutChargerController.cs +++ b/WebStarter/Controllers/OutChargerController.cs @@ -32,6 +32,7 @@ public class OutChargerController [Route("SendStartOutCharger")] public Result SendStartOutCharger([FromBody] PileStartChargeHttpReq httpReq) { + string chargerCode = ChargerUtils.GetOutChargerCode(httpReq.pn); byte chargerGunCode = ChargerUtils.GetTheGun(httpReq.pn); @@ -92,4 +93,36 @@ public class OutChargerController return Result.Success(true); } + + /// + /// 给充电枪发送功率调节指令 + /// + /// 充电机code + /// 1枪 or 2枪 + /// 功率 + /// + [HttpGet] + [Route("SendPowerRegulation/{code}/{pn}/{power}")] + public Result SendPowerRegulation(string code,byte pn, float power) + { + if (power <=0 || power > 280) + { + return Result.Fail("功率值范围1到360"); + } + + if (pn != 1 && pn != 2) + { + return Result.Fail("请选择1枪或者2枪"); + } + + ChargerClient? chargerClient = ClientMgr.GetBySn(code); + + if (chargerClient != null) + { + chargerClient.SendPileAdjustPower(pn,power); + return Result.Success(true); + } + + return Result.Fail("充电机未连接"); + } } \ No newline at end of file