站外帧补充

master
tq 5 months ago
parent 38b24cd5af
commit 79cfc5909f

@ -22,4 +22,16 @@ public class DateUtils
DateTime tomorrow = today.Date.AddDays(1); // 获取明天的日期
return new DateTime(tomorrow.Year, tomorrow.Month, tomorrow.Day, 0, 0, 0); // 获取明天的0点
}
/// <summary>
/// 组装只包含时分部分的时间
/// </summary>
/// <param name="hour"></param>
/// <param name="minute"></param>
/// <returns></returns>
public static string GetFormattedTime(byte hour, byte minute)
{
DateTime time = new DateTime(1, 1, 1, hour, minute, 0);
return time.ToString("HH:mm");
}
}

@ -97,6 +97,14 @@ namespace Entity.DbModel.Station
/// </summary>
[SugarColumn(ColumnName = "elec_plugin_status")]
public string ElecPluginStatus { get; set; }
/// <summary>
/// Desc:最后结束充电时间 结束充电后更新
/// Default:
/// Nullable:True
/// </summary>
[SugarColumn(ColumnName = "last_charge_finish_time")]
public DateTime? LastChargeFinishTime { get; set; }
/// <summary>
/// Desc:是否有水插头;0-无水插头1-有水插头

@ -11,11 +11,11 @@ public class ChargeOrderRepository : BaseRepository<ChargeOrder>
{
}
public void SaveChargeGunOrder(string chargeOrderNo, string chargerNo, string chargerGunNo,
public void SaveChargeGunOrder(string chargeOrder,string chargeOrderNo, string chargerNo, string chargerGunNo,
string outChargerGunNo)
{
ChargeOrder order = new ChargeOrder();
order.Sn = chargeOrderNo;
order.Sn = chargeOrder;
order.CmdStatus = 0;
order.ChargerNo = chargerNo;
order.ChargerGunNo = chargerGunNo;
@ -24,7 +24,7 @@ public class ChargeOrderRepository : BaseRepository<ChargeOrder>
order.StartMode = 1;
order.CloudChargeOrder = chargeOrderNo;
order.CreatedTime = DateTime.Now;
ChargeOrder chargeOrder = Insert(order);
Insert(order);
}
public ChargeOrder? GetLatestChargeGunOrder(string pn, string chargerCode)

@ -61,6 +61,14 @@ public class ChargerClient : TcpClient<IBaseHandler, Decoder, Encoder>
[1] = false,
[2] = false
};
/// <summary>
/// 充电桩连接状态
/// </summary>
public ConcurrentDictionary<byte, bool> ChargedPile = new ConcurrentDictionary<byte, bool>
{
[1] = false,
[2] = false
};
public bool IsStopped { get; set; } = false;
public bool IsCanSendStopCmd { get; set; } = true;
@ -145,14 +153,28 @@ public class ChargerClient : TcpClient<IBaseHandler, Decoder, Encoder>
public UploadTelemetryData UploadTelemetryData = new UploadTelemetryData();
/// <summary>
/// 两个充电桩的遥测
/// 充放电机上传单体动力蓄电池电压极值统计
/// </summary>
public VoltageExtremumStatistics? VoltageExtremumStatistics = new VoltageExtremumStatistics();
/// <summary>
/// 充电桩的遥测
/// </summary>
public ConcurrentDictionary<byte, PileUploadTelemetry> PileUploadTelemetry = new();
/// <summary>
/// 充电桩的遥信
/// </summary>
public ConcurrentDictionary<byte, PileUploadRemoteSignal> PileUploadRemoteSignal = new();
/// <summary>
/// 充电桩状态信息
/// </summary>
public ConcurrentDictionary<byte, ChargerPile> ChargerPile = new();
/// <summary>
///充电机实时充电功率
/// </summary>
public float RealTimeChargePower { get; set; } = 0;
/// <summary>
/// 心跳-桩状态
/// </summary>

@ -0,0 +1,50 @@
namespace Service.Charger.Client;
/// <summary>
/// 充电桩状态信息
/// </summary>
public class ChargerPile
{
/// <summary>
/// 充电方式
/// 0自动充满为止1按电量2按时间3按金额
/// </summary>
public int ct { get; set; }
/// <summary>
/// 充电参数
/// 按充电方式判断除0外 电量:单位 kWh精确到 0.01 时间:单位 min精确到 0.01 金额:单位 元,精确到 0.01
/// </summary>
public string cp { get; set; }
/// <summary>
/// 启动类型
/// 0运营平台启动1APP 启动2: 本地启动
/// </summary>
public int st { get; set; }
/// <summary>
/// 车辆vin
/// </summary>
public string Vin { get; set; }
/// <summary>
/// 充电订单号
/// 云平台下发的充电订单编号,;当启动模式为本地主动启动(即插即充)时,该 值以 0 填充
/// </summary>
public string con { get; set; }
/// <summary>
/// 充电流水号
/// </summary>
public string cosn { get; set; }
/// <summary>
/// 充电枪编号
/// 充电枪的唯一标识码
/// </summary>
public string? pn { get; set; }
}

@ -249,6 +249,7 @@ public class Decoder : ByteToMessageDecoder
7 => ModelConvert.Decode<PileChargeCompleteReq>(bytes),
12 => ModelConvert.Decode<PileUploadTelemetry>(bytes),
11 => ModelConvert.Decode<PileUploadRemoteSignal>(bytes),
14 => ModelConvert.Decode<PileUploadChargeRecord>(bytes),
_ => throw new InvalidOperationException("This should never be reached"),
},
#endregion

@ -101,6 +101,46 @@ public static class ChargerUtils
}
}
/// <summary>
/// 根据本地充电枪编号,充电机code,计算云平台下发充电枪编号
/// </summary>
/// <param name="chargerGun"></param>
/// <param name="chargerCode"></param>
/// <returns></returns>
/// <exception cref="ArgumentException"></exception>
public static string ReverseCalculateChargerGun(byte chargerGun, string chargerCode)
{
int number;
if (int.TryParse(chargerCode, out number))
{
int originalChargerGun;
if (chargerGun == 2)
{
// 站外2枪
originalChargerGun = number * 2;
}
else if (chargerGun == 1)
{
// 站外1枪
originalChargerGun = number * 2 - 1;
}
else
{
throw new ArgumentException("无效的chargerGun");
}
return originalChargerGun.ToString();
}
else
{
throw new ArgumentException("转换失败");
}
}
/// <summary>
/// 计算Byte随机数值
/// </summary>

@ -60,8 +60,16 @@ namespace Service.Charger.Handler
client.IsStopped = false;
}
int update = BinInfoRepository.Update(t => t.ChargeStatus == chargeStatus, t => t.No == client.BinNo);
Log.Info($"update {update} start charge finish status {chargeStatus} for {client.BinNo}");
BinInfo? binInfo = BinInfoRepository.QueryByBinNo(client.BinNo);
if (binInfo!=null)
{
binInfo.ChargeStatus = chargeStatus;
binInfo.LastChargeFinishTime = DateTime.Now;
bool update = BinInfoRepository.Update(binInfo);
Log.Info($"update {update} start charge finish status {chargeStatus} for {client.BinNo}");
}
ChargingStopFsdRes stopFsdRes = new ChargingStopFsdRes(0);

@ -33,9 +33,7 @@ public class PileChargeCompleteHandler : SimpleChannelInboundHandler<PileChargeC
return;
}
chargeOrder.EndTime = DateTime.Now;
chargeOrder.StopReason = 0;
chargeOrder.CanUpload = 1;
client.GunCharged[msg.Pn] = false;

@ -6,7 +6,9 @@ using Service.Charger.Msg.Charger.OutCharger.Req;
using Service.Charger.Msg.Host.Resp.OutCharger;
namespace Service.Charger.Handler.OutCharger;
/// <summary>
/// 3.7.5 充电桩上送充电启动完成帧
/// </summary>
[Order(8)]
[Scope("InstancePerDependency")]
public class PileStartChargeCompleteHandler : SimpleChannelInboundHandler<PileStartChargeCompleteReq>, IBaseHandler
@ -27,6 +29,7 @@ public class PileStartChargeCompleteHandler : SimpleChannelInboundHandler<PileSt
if (msg.Result == 0)
{
client.GunCharged[msg.Pn] = true;
client.ChargerPile[msg.Pn].Vin = msg.Vin;
}
// 响应启动完成帧
PileStartChargeCompleteRes res=new PileStartChargeCompleteRes(msg.Pn,0,0);

@ -11,7 +11,9 @@ using Service.Charger.Msg.Charger.OutCharger.Resp;
using Service.Charger.Msg.Http.Resp;
namespace Service.Charger.Handler.OutCharger;
/// <summary>
/// 3.7.2 充电桩响应远程启动充电
/// </summary>
[Order(8)]
[Scope("InstancePerDependency")]
public class PileStartChargeResHandler : SimpleChannelInboundHandler<PileStartChargeRes>, IBaseHandler

@ -9,7 +9,9 @@ using Service.Charger.Msg.Charger.OutCharger.Resp;
using Service.Charger.Msg.Http.Resp;
namespace Service.Charger.Handler.OutCharger;
/// <summary>
/// 3.7.4 充电桩响应远程停止充电
/// </summary>
[Order(8)]
[Scope("InstancePerDependency")]
public class PileStopChargeResHandler : SimpleChannelInboundHandler<PileStopChargeRes>, IBaseHandler
@ -32,10 +34,7 @@ public class PileStopChargeResHandler : SimpleChannelInboundHandler<PileStopChar
}
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();

@ -0,0 +1,255 @@
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.Common;
using Service.Charger.Msg.Charger.OutCharger.Req;
using Service.Charger.Msg.Host.Resp.OutCharger;
using Service.Charger.Msg.Http.Req;
using Service.Init;
namespace Service.Charger.Handler.OutCharger;
/// <summary>
/// 3.7.13 充电桩上送充电记录
/// </summary>
[Order(8)]
[Scope("InstancePerDependency")]
public class PileUploadChargeRecordHandler : SimpleChannelInboundHandler<PileUploadChargeRecord>, IBaseHandler
{
private static readonly ILog Log = LogManager.GetLogger(typeof(PileUploadChargeRecordHandler));
public ChargeOrderRepository ChargeOrderRepository { get; set; }
protected override void ChannelRead0(IChannelHandlerContext ctx, PileUploadChargeRecord msg)
{
if (ClientMgr.TryGetClient(ctx.Channel, out var sn, out var client))
{
if (client == null)
{
return;
}
float[] powersPeriods = new float[4] { 0, 0, 0, 0 }; //元素索引顺序代表值1234
var acPowersPeriods = PeaksAndValleys(msg, powersPeriods);
Log.Info($"receive {msg} from {sn}");
ChargeOrder chargeOrder = ChargeOrderRepository.QueryByClause(it => it.Sn == msg.ChargeOrderNo);
var startTime = new DateTime(msg.StartYear + 2000, msg.StartMonth, msg.StartDay, msg.StartHour,
msg.StartMinute, msg.StartSecond);
var endTime = new DateTime(msg.EndYear + 2000, msg.EndMonth, msg.EndDay, msg.EndHour, msg.EndMinute,
msg.EndSecond);
float chargingPower = msg.ChargingPower;
var socBefore = msg.SocBefore;
byte socAfter = msg.SocAfter;
void UpdateChargeOrder(ChargeOrder order)
{
order.StartTime = startTime;
order.EndTime = endTime;
order.StartSoc = socBefore;
order.StopSoc = socAfter;
order.ChargeTimeCount = (int)(endTime - startTime).TotalMinutes;
order.ElecCount = Convert.ToDecimal(chargingPower);
order.AcElecCount = Convert.ToDecimal(msg.AcMeterElecCount);
order.StartAcElec = Convert.ToDecimal(msg.AcMeterDataBefore);
order.StopAcElec = Convert.ToDecimal(msg.AcMeterDataAfter);
order.StartDcElec = Convert.ToDecimal(msg.DcMeterDataBefore);
order.StopDcElec = Convert.ToDecimal(msg.DcMeterDataAfter);
order.SharpElecCount = Convert.ToDecimal(powersPeriods[0]);
order.PeakElecCount = Convert.ToDecimal(powersPeriods[1]);
order.FlatElecCount = Convert.ToDecimal(powersPeriods[2]);
order.ValleyElecCount = Convert.ToDecimal(powersPeriods[3]);
order.AcSharpElecCount = Convert.ToDecimal(acPowersPeriods[0]);
order.AcPeakElecCount = Convert.ToDecimal(acPowersPeriods[1]);
order.AcFlatElecCount = Convert.ToDecimal(acPowersPeriods[2]);
order.AcValleyElecCount = Convert.ToDecimal(acPowersPeriods[3]);
order.ChargeMode = msg.ChargeMode;
order.StartMode = msg.StartMode;
}
if (chargeOrder == null)
{
ChargeOrder newOrder = new ChargeOrder()
{
Sn = msg.ChargeOrderNo
};
UpdateChargeOrder(newOrder);
ChargeOrderRepository.Insert(newOrder);
PileEndChargeReq req = new PileEndChargeReq();
req.sn = StaticStationInfo.StationNo;
req.con = msg.ChargeOrderNo;
req.cosn = msg.ChargeOrderNo;
UploadChargeRecord(msg, client, req, sn, startTime, endTime, chargingPower, socBefore, socAfter);
}
else
{
UpdateChargeOrder(chargeOrder);
// 充电完成入库
ChargeOrderRepository.Update(chargeOrder);
PileEndChargeReq req = new PileEndChargeReq();
req.sn = StaticStationInfo.StationNo;
req.con = chargeOrder.CloudChargeOrder;
req.cosn = chargeOrder.Sn;
// 充电完成上报云平台
UploadChargeRecord(msg, client, req, sn, startTime, endTime, chargingPower, socBefore, socAfter);
}
}
ctx.Channel.WriteAndFlushAsync(new PileUploadChargeRecordRes(msg.Pn));
}
private static void UploadChargeRecord(PileUploadChargeRecord msg, ChargerClient client, PileEndChargeReq req,
string sn, DateTime startTime, DateTime endTime, float chargingPower, byte socBefore, byte socAfter)
{
ChargerPile chargerPile = client.ChargerPile[msg.Pn];
req.pn = ChargerUtils.ReverseCalculateChargerGun(msg.Pn, sn);
req.ct = chargerPile.ct;
req.cp = chargerPile.cp;
req.st = chargerPile.st;
req.cst = startTime;
req.cet = endTime;
req.ceq = chargingPower;
req.cssoc = socBefore;
req.cesoc = socAfter;
req.ctn = msg.ChargingTimeCount;
List<PeriodReq> periodList = new List<PeriodReq>();
// 利用反射组装充电时间段数据
for (int i = 1; i <= msg.ChargingTimeCount; i++)
{
PeriodReq periodReq = new PeriodReq();
// 获取属性
var startTimeHourProperty = typeof(PileUploadChargeRecord).GetProperty($"StartTime{i}");
var startTimeMinuteProperty = typeof(PileUploadChargeRecord).GetProperty($"StartTimeMinute{i}");
if (startTimeHourProperty != null && startTimeMinuteProperty != null)
{
// 获取值
byte startTimeHour = (byte)startTimeHourProperty.GetValue(msg);
byte startTimeMinute = (byte)startTimeMinuteProperty.GetValue(msg);
periodReq.StartTimeMinute = DateUtils.GetFormattedTime(startTimeHour, startTimeMinute);
}
var chargingPowerProperty = typeof(PileUploadChargeRecord).GetProperty($"ChargingPowerOfTime{i}");
var flagOfTimeProperty = typeof(PileUploadChargeRecord).GetProperty($"FlagOfTime{i}");
if (chargingPowerProperty != null && flagOfTimeProperty != null)
{
periodReq.ChargingPowerOfTime = (float)chargingPowerProperty.GetValue(msg);
periodReq.FlagOfTime = (byte)flagOfTimeProperty.GetValue(msg);
}
periodList.Add(periodReq);
}
req.ctl = periodList;
req.cvin = chargerPile.Vin;
HttpUtil.SendPostRequest(req, "http://127.0.0.1:5034/api/OutCharger/SendPileEndCharge");
}
private static float[] PeaksAndValleys(PileUploadChargeRecord msg, float[] powersPeriods)
{
if (msg.FlagOfTime1 >= 1 && msg.FlagOfTime1 <= 4)
{
powersPeriods[msg.FlagOfTime1 - 1] += msg.ChargingPowerOfTime1;
}
if (msg.FlagOfTime2 >= 1 && msg.FlagOfTime2 <= 4)
{
powersPeriods[msg.FlagOfTime2 - 1] += msg.ChargingPowerOfTime2;
}
if (msg.FlagOfTime3 >= 1 && msg.FlagOfTime3 <= 4)
{
powersPeriods[msg.FlagOfTime3 - 1] += msg.ChargingPowerOfTime3;
}
if (msg.FlagOfTime4 >= 1 && msg.FlagOfTime4 <= 4)
{
powersPeriods[msg.FlagOfTime4 - 1] += msg.ChargingPowerOfTime4;
}
if (msg.FlagOfTime5 >= 1 && msg.FlagOfTime5 <= 4)
{
powersPeriods[msg.FlagOfTime5 - 1] += msg.ChargingPowerOfTime5;
}
if (msg.FlagOfTime6 >= 1 && msg.FlagOfTime6 <= 4)
{
powersPeriods[msg.FlagOfTime6 - 1] += msg.ChargingPowerOfTime6;
}
if (msg.FlagOfTime7 >= 1 && msg.FlagOfTime7 <= 4)
{
powersPeriods[msg.FlagOfTime7 - 1] += msg.ChargingPowerOfTime7;
}
if (msg.FlagOfTime8 >= 1 && msg.FlagOfTime8 <= 4)
{
powersPeriods[msg.FlagOfTime8 - 1] += msg.ChargingPowerOfTime8;
}
float[] acPowersPeriods = new float[4] { 0, 0, 0, 0 }; //元素索引顺序代表值1234
if (msg.AcFlagOfTime1 >= 1 && msg.AcFlagOfTime1 <= 4)
{
acPowersPeriods[msg.AcFlagOfTime1 - 1] += msg.AcChargingPowerOfTime1;
}
if (msg.AcFlagOfTime2 >= 1 && msg.AcFlagOfTime2 <= 4)
{
acPowersPeriods[msg.AcFlagOfTime2 - 1] += msg.AcChargingPowerOfTime2;
}
if (msg.AcFlagOfTime3 >= 1 && msg.AcFlagOfTime3 <= 4)
{
acPowersPeriods[msg.AcFlagOfTime3 - 1] += msg.AcChargingPowerOfTime3;
}
if (msg.AcFlagOfTime4 >= 1 && msg.AcFlagOfTime4 <= 4)
{
acPowersPeriods[msg.AcFlagOfTime4 - 1] += msg.AcChargingPowerOfTime4;
}
if (msg.AcFlagOfTime5 >= 1 && msg.AcFlagOfTime5 <= 4)
{
acPowersPeriods[msg.AcFlagOfTime5 - 1] += msg.AcChargingPowerOfTime5;
}
if (msg.AcFlagOfTime6 >= 1 && msg.AcFlagOfTime6 <= 4)
{
acPowersPeriods[msg.AcFlagOfTime6 - 1] += msg.AcChargingPowerOfTime6;
}
if (msg.AcFlagOfTime7 >= 1 && msg.AcFlagOfTime7 <= 4)
{
acPowersPeriods[msg.AcFlagOfTime7 - 1] += msg.AcChargingPowerOfTime7;
}
if (msg.AcFlagOfTime8 >= 1 && msg.AcFlagOfTime8 <= 4)
{
acPowersPeriods[msg.AcFlagOfTime8 - 1] += msg.AcChargingPowerOfTime8;
}
return acPowersPeriods;
}
}

@ -2,8 +2,9 @@
using log4net;
using Service.Charger.Client;
using Service.Charger.Handler;
using Service.Charger.Msg.Charger.OutCharger.Req;
namespace Service.Charger.Msg.Charger.OutCharger.Req;
namespace Service.Charger.Handler.OutCharger;
/// <summary>
/// 3.7.11 充电桩遥信数据上报
/// </summary>
@ -18,13 +19,17 @@ public class PileUploadRemoteSignalHandler: SimpleChannelInboundHandler<PileUplo
{
//存储日志
Log.Info($"receive {msg} from {sn}");
client.PileUploadRemoteSignal[msg.Pn] = msg;
client.Workstate = msg.WorkStatus;
client.IsCharged = msg.WorkStatus == 1 ? true : false;
client.TotalError = msg.TotalError;
client.TotalWarning = msg.TotalWarning;
client.GunCharged[msg.Pn] = msg.WorkStatus == 1 ? true : false;
client.ChargedPile[msg.Pn] = msg.ChargeStationGunHolderStatus;
}
}
}

@ -64,17 +64,22 @@ namespace Service.Charger.Handler
client.ChargeOrderNo = msg.ChargerOrderNo;
ChargeOrder db = _chargeOrderRepository.QueryByClause(it => it.Sn == msg.ChargerOrderNo);
DateTime startTime = new DateTime((msg.StartYear+2000) , msg.StartMonth ,msg.StartDay ,msg.StartHour, msg.StartMinute, msg.StartSecond);
DateTime endTime = new DateTime(msg.EndYear + 2000, msg.EndMonth, msg.EndDay, msg.EndHour, msg.EndMinute, msg.EndSecond);
if (db == null)
{
ChargeOrder chargeOrder = new ChargeOrder()
{
Sn = client.ChargeOrderNo,
BatteryNo = client.BatteryNo,
StartTime = new DateTime((msg.StartYear+2000) , msg.StartMonth ,msg.StartDay ,msg.StartHour, msg.StartMinute, msg.StartSecond),
EndTime = new DateTime(msg.EndYear + 2000, msg.EndMonth, msg.EndDay, msg.EndHour, msg.EndMinute, msg.EndSecond),
StartTime = startTime,
EndTime = endTime,
StartSoc = msg.SocBefore,
StopSoc = msg.SocAfter,
ChargeTimeCount= msg.ChargingTimeCount,
ChargeTimeCount = (int)(endTime - startTime).TotalMinutes,
ElecCount = Convert.ToDecimal(msg.ChargingPower),
AcElecCount = Convert.ToDecimal(msg.AcMeterElecCount),
StartAcElec = Convert.ToDecimal(msg.AcMeterDataBefore),

@ -23,6 +23,7 @@ namespace Service.Charger.Handler
if (ClientMgr.TryGetClient(ctx.Channel, out string sn, out var client))
{
Log.Info($"receive {msg} from {sn}");
client.VoltageExtremumStatistics = msg;
}
}
}

@ -0,0 +1,598 @@
using HybirdFrameworkCore.Autofac.Attribute;
namespace Service.Charger.Msg.Charger.OutCharger.Req;
/// <summary>
/// 3.7.13 充电桩上送充电记录
/// </summary>
public class PileUploadChargeRecord : ASDU
{
/// <summary>
/// 记录类型
/// </summary>
[Property(0, 8)]
public byte RecordType { get; set; }
/// <summary>
/// 充电枪ID号
/// 0x01充电枪10x02充电枪20x03双枪充电;(0x00&0xFF无效)
/// </summary>
[Property(8, 8)]
public byte Pn { get; set; }
/// <summary>
/// 充电流水号
/// </summary>
[Property(16, 256)]
public string ChargeOrderNo { get; set; }
/// <summary>
/// 充电开始时间-秒
/// </summary>
[Property(272, 8)]
public byte StartSecond { get; set; }
/// <summary>
/// 充电开始时间-分
/// </summary>
[Property(280, 8)]
public byte StartMinute { get; set; }
/// <summary>
/// 充电开始时间-时
/// </summary>
[Property(288, 8)]
public byte StartHour { get; set; }
/// <summary>
/// 充电开始时间-日
/// </summary>
[Property(296, 8)]
public byte StartDay { get; set; }
/// <summary>
/// 充电开始时间-月
/// </summary>
[Property(304, 8)]
public byte StartMonth { get; set; }
/// <summary>
/// 充电开始时间-年
/// </summary>
[Property(312, 8)]
public byte StartYear { get; set; }
/// <summary>
/// 充电结束时间-秒
/// </summary>
[Property(320, 8)]
public byte EndSecond { get; set; }
/// <summary>
/// 充电结束时间-分
/// </summary>
[Property(328, 8)]
public byte EndMinute { get; set; }
/// <summary>
/// 充电结束时间-时
/// </summary>
[Property(336, 8)]
public byte EndHour { get; set; }
/// <summary>
/// 充电结束时间-日
/// </summary>
[Property(344, 8)]
public byte EndDay { get; set; }
/// <summary>
/// 充电结束时间-月
/// </summary>
[Property(352, 8)]
public byte EndMonth { get; set; }
/// <summary>
/// 充电结束时间-年
/// </summary>
[Property(360, 8)]
public byte EndYear { get; set; }
/// <summary>
/// 充电开始时间 秒-分-时-日-月-年
/// </summary>
public string StartTime { get; set; }
/// <summary>
/// 充电结束时间
/// </summary>
public string EndTime { get; set; }
/// <summary>
/// 1 枪充电前电能表数据
/// </summary>
[Property(368, 32, PropertyReadConstant.Bit, 0.01, 2)]
public float FirstGunEnergyMeterDataBefore { get; set; }
/// <summary>
/// 1 枪充电后电能表数据
/// </summary>
[Property(400, 32, PropertyReadConstant.Bit, 0.01, 2)]
public float FirstGunEnergyMeterDataAfter { get; set; }
/// <summary>
/// 2 枪充电前电能表数据
/// </summary>
[Property(432, 32, PropertyReadConstant.Bit, 0.01, 2)]
public float SecondGunEnergyMeterDataBefore { get; set; }
/// <summary>
/// 2 枪充电后电能表数据
/// </summary>
[Property(464, 32, PropertyReadConstant.Bit, 0.01, 2)]
public float SecondGunEnergyMeterDataAfter { get; set; }
/// <summary>
/// 充电电量
/// </summary>
[Property(496, 32, PropertyReadConstant.Bit, 0.01, 2)]
public float ChargingPower { get; set; }
/// <summary>
/// 充电前SOC
/// </summary>
[Property(528, 8)]
public byte SocBefore { get; set; }
/// <summary>
/// 充电后SOC
/// </summary>
[Property(536, 8)]
public byte SocAfter { get; set; }
/// <summary>
/// 充电时段数量
/// </summary>
[Property(544, 8)]
public byte ChargingTimeCount { get; set; }
/// <summary>
/// 时段1 开始时间 时
/// </summary>
[Property(552, 8)]
public byte StartTime1 { get; set; }
/// <summary>
/// 时段1 开始时间 分
/// </summary>
[Property(560, 8)]
public byte StartTimeMinute1 { get; set; }
/// <summary>
/// 时段1 电量
/// </summary>
[Property(568, 32, PropertyReadConstant.Bit, 0.01, 2)]
public float ChargingPowerOfTime1 { get; set; }
/// <summary>
/// 时段1 标识
/// </summary>
[Property(600, 8)]
public byte FlagOfTime1 { get; set; }
/// <summary>
/// 时段2 开始时间 时
/// </summary>
[Property(608, 8)]
public byte StartTime2 { get; set; }
/// <summary>
/// 时段2 开始时间 分
/// </summary>
[Property(616, 8)]
public byte StartTimeMinute2 { get; set; }
/// <summary>
/// 时段2 电量
/// </summary>
[Property(624, 32, PropertyReadConstant.Bit, 0.01, 2)]
public float ChargingPowerOfTime2 { get; set; }
/// <summary>
/// 时段2 标识
/// </summary>
[Property(656, 8)]
public byte FlagOfTime2 { get; set; }
/// <summary>
/// 时段3 开始时间 时
/// </summary>
[Property(664, 8)]
public byte StartTime3 { get; set; }
/// <summary>
/// 时段3 开始时间 分
/// </summary>
[Property(672, 8)]
public byte StartTimeMinute3 { get; set; }
/// <summary>
/// 时段3 电量
/// </summary>
[Property(680, 32, PropertyReadConstant.Bit, 0.01, 2)]
public float ChargingPowerOfTime3 { get; set; }
/// <summary>
/// 时段3 标识
/// </summary>
[Property(712, 8)]
public byte FlagOfTime3 { get; set; }
/// <summary>
/// 时段4 开始时间 时
/// </summary>
[Property(720, 8)]
public byte StartTime4 { get; set; }
/// <summary>
/// 时段4 开始时间 分
/// </summary>
[Property(728, 8)]
public byte StartTimeMinute4 { get; set; }
/// <summary>
/// 时段4 电量
/// </summary>
[Property(736, 32, PropertyReadConstant.Bit, 0.01, 2)]
public float ChargingPowerOfTime4 { get; set; }
/// <summary>
/// 时段4 标识
/// </summary>
[Property(768, 8)]
public byte FlagOfTime4 { get; set; }
/// <summary>
/// 时段5 开始时间 时
/// </summary>
[Property(776, 8)]
public byte StartTime5 { get; set; }
/// <summary>
/// 时段5 开始时间 分
/// </summary>
[Property(784, 8)]
public byte StartTimeMinute5 { get; set; }
/// <summary>
/// 时段5 电量
/// </summary>
[Property(792, 32, PropertyReadConstant.Bit, 0.01, 2)]
public float ChargingPowerOfTime5 { get; set; }
/// <summary>
/// 时段5 标识
/// </summary>
[Property(824, 8)]
public byte FlagOfTime5 { get; set; }
/// <summary>
/// 时段6 开始时间 时
/// </summary>
[Property(832, 8)]
public byte StartTime6 { get; set; }
/// <summary>
/// 时段6 开始时间 分
/// </summary>
[Property(840, 8)]
public byte StartTimeMinute6 { get; set; }
/// <summary>
/// 时段6 电量
/// </summary>
[Property(848, 32, PropertyReadConstant.Bit, 0.01, 2)]
public float ChargingPowerOfTime6 { get; set; }
/// <summary>
/// 时段6 标识
/// </summary>
[Property(880, 8)]
public byte FlagOfTime6 { get; set; }
/// <summary>
/// 时段7 开始时间 时
/// </summary>
[Property(888, 8)]
public byte StartTime7 { get; set; }
/// <summary>
/// 时段7 开始时间 分
/// </summary>
[Property(896, 8)]
public byte StartTimeMinute7 { get; set; }
/// <summary>
/// 时段7 电量
/// </summary>
[Property(904, 32, PropertyReadConstant.Bit, 0.01, 2)]
public float ChargingPowerOfTime7 { get; set; }
/// <summary>
/// 时段7 标识
/// </summary>
[Property(936, 8)]
public byte FlagOfTime7 { get; set; }
/// <summary>
/// 时段8 开始时间 时
/// </summary>
[Property(944, 8)]
public byte StartTime8 { get; set; }
/// <summary>
/// 时段8 开始时间 分
/// </summary>
[Property(952, 8)]
public byte StartTimeMinute8 { get; set; }
/// <summary>
/// 时段8 电量
/// </summary>
[Property(960, 32, PropertyReadConstant.Bit, 0.01, 2)]
public float ChargingPowerOfTime8 { get; set; }
/// <summary>
/// 时段8 标识
/// </summary>
[Property(992, 8)]
public byte FlagOfTime8 { get; set; }
/// <summary>
/// 充电模式 0站内充电 1站外充电
/// </summary>
[Property(1000, 8)]
public byte ChargeMode { get; set; }
/// <summary>
/// 启动模式 0: 站控启动 1本地启动
/// </summary>
[Property(1008, 8)]
public byte StartMode { get; set; }
/// <summary>
/// 充电前直流表值
/// </summary>
[Property(1016, 32, PropertyReadConstant.Bit, 0.01, 2)]
public float DcMeterDataBefore { get; set; }
/// <summary>
/// 充电后直流表值
/// </summary>
[Property(1048, 32, PropertyReadConstant.Bit, 0.01, 2)]
public float DcMeterDataAfter { get; set; }
/// <summary>
/// 充电前交流表值
/// </summary>
[Property(1080, 32, PropertyReadConstant.Bit, 0.01, 2)]
public float AcMeterDataBefore { get; set; }
/// <summary>
/// 充电后交流表值
/// </summary>
[Property(1112, 32, PropertyReadConstant.Bit, 0.01, 2)]
public float AcMeterDataAfter { get; set; }
/// <summary>
/// 本次充电交流表值
/// </summary>
[Property(1144, 32, PropertyReadConstant.Bit, 0.01, 2)]
public float AcMeterElecCount { get; set; }
/// <summary>
/// 时段1 开始时间 时
/// </summary>
[Property(1176, 8)]
public byte AcStartTime1 { get; set; }
/// <summary>
/// 时段1 开始时间 分
/// </summary>
[Property(1184, 8)]
public byte AcStartTimeMinute1 { get; set; }
/// <summary>
/// 时段1 电量
/// </summary>
[Property(1192, 32, PropertyReadConstant.Bit, 0.01, 2)]
public float AcChargingPowerOfTime1 { get; set; }
/// <summary>
/// 时段1 标识
/// </summary>
[Property(1224, 8)]
public byte AcFlagOfTime1 { get; set; }
/// <summary>
/// 时段2 开始时间 时
/// </summary>
[Property(1232, 8)]
public byte AcStartTime2 { get; set; }
/// <summary>
/// 时段2 开始时间 分
/// </summary>
[Property(1240, 8)]
public byte AcStartTimeMinute2 { get; set; }
/// <summary>
/// 时段2 电量
/// </summary>
[Property(1248, 32, PropertyReadConstant.Bit, 0.01, 2)]
public float AcChargingPowerOfTime2 { get; set; }
/// <summary>
/// 时段2 标识
/// </summary>
[Property(1280, 8)]
public byte AcFlagOfTime2 { get; set; }
/// <summary>
/// 时段3 开始时间 时
/// </summary>
[Property(1288, 8)]
public byte AcStartTime3 { get; set; }
/// <summary>
/// 时段3 开始时间 分
/// </summary>
[Property(1296, 8)]
public byte AcStartTimeMinute3 { get; set; }
/// <summary>
/// 时段3 电量
/// </summary>
[Property(1304, 32, PropertyReadConstant.Bit, 0.01, 2)]
public float AcChargingPowerOfTime3 { get; set; }
/// <summary>
/// 时段3 标识
/// </summary>
[Property(1336, 8)]
public byte AcFlagOfTime3 { get; set; }
/// <summary>
/// 时段4 开始时间 时
/// </summary>
[Property(1344, 8)]
public byte AcStartTime4 { get; set; }
/// <summary>
/// 时段4 开始时间 分
/// </summary>
[Property(1352, 8)]
public byte AcStartTimeMinute4 { get; set; }
/// <summary>
/// 时段4 电量
/// </summary>
[Property(1360, 32, PropertyReadConstant.Bit, 0.01, 2)]
public float AcChargingPowerOfTime4 { get; set; }
/// <summary>
/// 时段4 标识
/// </summary>
[Property(1392, 8)]
public byte AcFlagOfTime4 { get; set; }
/// <summary>
/// 时段5 开始时间 时
/// </summary>
[Property(1400, 8)]
public byte AcStartTime5 { get; set; }
/// <summary>
/// 时段5 开始时间 分
/// </summary>
[Property(1408, 8)]
public byte AcStartTimeMinute5 { get; set; }
/// <summary>
/// 时段5 电量
/// </summary>
[Property(1416, 32, PropertyReadConstant.Bit, 0.01, 2)]
public float AcChargingPowerOfTime5 { get; set; }
/// <summary>
/// 时段5 标识
/// </summary>
[Property(1448, 8)]
public byte AcFlagOfTime5 { get; set; }
/// <summary>
/// 时段6 开始时间 时
/// </summary>
[Property(1456, 8)]
public byte AcStartTime6 { get; set; }
/// <summary>
/// 时段6 开始时间 分
/// </summary>
[Property(1464, 8)]
public byte AcStartTimeMinute6 { get; set; }
/// <summary>
/// 时段6 电量
/// </summary>
[Property(1472, 32, PropertyReadConstant.Bit, 0.01, 2)]
public float AcChargingPowerOfTime6 { get; set; }
/// <summary>
/// 时段6 标识
/// </summary>
[Property(1504, 8)]
public byte AcFlagOfTime6 { get; set; }
/// <summary>
/// 时段7 开始时间 时
/// </summary>
[Property(1512, 8)]
public byte AcStartTime7 { get; set; }
/// <summary>
/// 时段7 开始时间 分
/// </summary>
[Property(1520, 8)]
public byte AcStartTimeMinute7 { get; set; }
/// <summary>
/// 时段7 电量
/// </summary>
[Property(1528, 32, PropertyReadConstant.Bit, 0.01, 2)]
public float AcChargingPowerOfTime7 { get; set; }
/// <summary>
/// 时段7 标识
/// </summary>
[Property(1560, 8)]
public byte AcFlagOfTime7 { get; set; }
/// <summary>
/// 时段8 开始时间 时
/// </summary>
[Property(1568, 8)]
public byte AcStartTime8 { get; set; }
/// <summary>
/// 时段8 开始时间 分
/// </summary>
[Property(1572, 8)]
public byte AcStartTimeMinute8 { get; set; }
/// <summary>
/// 时段8 电量
/// </summary>
[Property(1580, 32, PropertyReadConstant.Bit, 0.01, 2)]
public float AcChargingPowerOfTime8 { get; set; }
/// <summary>
/// 时段8 标识
/// </summary>
[Property(1612, 8)]
public byte AcFlagOfTime8 { get; set; }
}

@ -0,0 +1,33 @@
using HybirdFrameworkCore.Autofac.Attribute;
namespace Service.Charger.Msg.Host.Resp.OutCharger;
/// <summary>
/// 3.7.14 主动上送充电记录响应
/// </summary>
public class PileUploadChargeRecordRes : ASDU
{
/// <summary>
/// 记录类型
/// </summary>
[Property(0, 8)]
public byte RecordType { get; set; }
/// <summary>
/// 充电枪ID号
/// 0x01充电枪10x02充电枪20x03双枪充电;(0x00&0xFF无效)
/// </summary>
[Property(8, 8)]
public byte Pn { get; set; }
public PileUploadChargeRecordRes(byte pn)
{
FrameTypeNo = 51;
RecordType = 14;
MsgBodyCount = 1;
TransReason = 4;
PublicAddr = 0;
MsgBodyAddr = new byte[] { 0, 0, 0 };
Pn = pn;
}
}

@ -0,0 +1,21 @@
namespace Service.Charger.Msg.Http.Req;
/// <summary>
/// 上报充电桩结束的计费时间段列表
/// </summary>
public class PeriodReq
{
/// <summary>
/// 时段 开始时间
/// </summary>
public string? StartTimeMinute { get; set; }
/// <summary>
/// 时段 电量
/// </summary>
public float ChargingPowerOfTime { get; set; }
/// <summary>
/// 时段 标识
/// </summary>
public byte FlagOfTime { get; set; }
}

@ -0,0 +1,152 @@
namespace Service.Charger.Msg.Http.Req;
/// <summary>
/// 9.2.1.7 站控上报充电枪充电遥测数据
/// </summary>
public class PileChargeRealtimeReq
{
/// <summary>
/// 换电站编码
/// </summary>
public string sn { get; set; }
/// <summary>
/// 充电订单号
/// 云平台下发的充电订单编号,;当启动模式为本地主动启动(即插即充)时,该 值以 0 填充
/// </summary>
public string con { get; set; }
/// <summary>
/// 充电流水号
/// 充电记录唯一编码
/// </summary>
public string cosn { get; set; }
/// <summary>
/// Desc:充电枪编号
/// Default:
/// Nullable:True
/// </summary>
public string? pn { get; set; }
/// <summary>
/// 需求电压
/// </summary>
public float rv { get; set; }
/// <summary>
/// 需求电流
/// </summary>
public float re { get; set; }
/// <summary>
/// 充电模式 01H:恒压充电、02H恒流充电
/// </summary>
public int cm { get; set; }
/// <summary>
/// 充电电压测量值
/// </summary>
public float cdv { get; set; }
/// <summary>
/// 充电电流测量值
/// </summary>
public float cde { get; set; }
/// <summary>
/// 当前荷电状态 S0C %
/// </summary>
public float soc { get; set; }
/// <summary>
/// 估算剩余充电时间
/// </summary>
public int tr { get; set; }
/// <summary>
/// 电桩电压输岀值
/// </summary>
public float pov { get; set; }
/// <summary>
/// 电桩电流输岀值
/// </summary>
public float poe { get; set; }
/// <summary>
/// 累计充电时间
/// </summary>
public int tct { get; set; }
/// <summary>
/// 最高单体动力 蓄电池电压所 在编号
/// </summary>
public int? hbvn { get; set; }
/// <summary>
/// 最高单体动力 蓄电池电压
/// </summary>
public float? hbv { get; set; }
/// <summary>
/// 最高温度检测 点编号
/// </summary>
public int hbtn { get; set; }
/// <summary>
/// 最高动力蓄电池温度
/// </summary>
public int hbt { get; set; }
/// <summary>
/// 最低单体动力 蓄电池电压所在编号
/// </summary>
public int lbvn { get; set; }
/// <summary>
/// 最低单体动力蓄电池电压
/// </summary>
public float lbv { get; set; }
/// <summary>
/// 最低动力蓄电池温度检测点 编号
/// </summary>
public int lbtn { get; set; }
/// <summary>
/// 最低动力蓄电 池温度
/// </summary>
public int lbt { get; set; }
/// <summary>
/// 单体动力蓄电 池电压过高 / 过低告警
/// </summary>
public int hlbva { get; set; }
/// <summary>
/// 整车动力蓄电 池荷电状态 S0C 过高/过低 告警
/// </summary>
public int hlbsa { get; set; }
/// <summary>
/// 动力蓄电池充电过流告警
/// </summary>
public int baa { get; set; }
/// <summary>
/// 动力蓄电池温度过高告警
/// </summary>
public int bta { get; set; }
/// <summary>
/// 动力蓄电池绝缘状态告警
/// </summary>
public int bia { get; set; }
/// <summary>
/// 动力蓄电池组 输岀连接器连 接状态告警
/// </summary>
public int bca { get; set; }
}

@ -0,0 +1,95 @@
namespace Service.Charger.Msg.Http.Req;
/// <summary>
/// 9.2.1.3 站控上报充电枪充电结束事件
/// </summary>
public class PileEndChargeReq
{
/// <summary>
/// 换电站编码
/// </summary>
public string sn { get; set; }
/// <summary>
/// 充电订单号
/// 云平台下发的充电订单编号,;当启动模式为本地主动启动(即插即充)时,该 值以 0 填充
/// </summary>
public string con { get; set; }
/// <summary>
/// 充电流水号
/// 充电记录唯一编码
/// </summary>
public string cosn { get; set; }
/// <summary>
/// Desc:充电枪编号
/// Default:
/// Nullable:True
/// </summary>
public string? pn { get; set; }
/// <summary>
/// 充电方式
/// 0自动充满为止 1按电量 2按时间 3按金额
/// </summary>
public int ct { get; set; }
/// <summary>
/// 充电参数
/// 按充电方式判断除0外 电量:单位 kWh精确到 0.01 时间:单位 min精确到 0.01 金额:单位 元,精确到 0.01
/// </summary>
public string cp { get; set; }
/// <summary>
/// 启动类型
/// 0运营平台启动1APP 启动2: 本地启动
/// </summary>
public int st { get; set; }
/// <summary>
/// 本次充电订单的开始时间 格式 yyyy-MM-dd HH:mm:ss
/// </summary>
public DateTime cst { get; set; }
/// <summary>
/// 本次充电订单的开始时间 格式 yyyy-MM-dd HH:mm:ss
/// </summary>
public DateTime? cet { get; set; }
/// <summary>
/// 充电电量
/// 至少保留两位有效小数
/// </summary>
public float ceq { get; set; }
/// <summary>
/// Desc:充电开始soc
/// Default:
/// Nullable:True
/// </summary>
public int? cssoc { get; set; }
/// <summary>
/// Desc:充电结束soc
/// Default:
/// Nullable:True
/// </summary>
public int? cesoc { get; set; }
/// <summary>
/// 计费时间段个数
/// </summary>
public int? ctn { get; set; }
/// <summary>
/// 计费时间段列表
/// </summary>
public List<PeriodReq> ctl { get; set; }
/// <summary>
/// 充电车辆车架号
/// </summary>
public string cvin { get; set; }
}

@ -8,7 +8,7 @@ public class PileStartChargeHttpReq
/// 换电站编码
/// 换电站唯一码
/// </summary>
public string? sn { get; set; }
public string sn { get; set; }
/// <summary>
/// 充电订单号
@ -26,19 +26,19 @@ public class PileStartChargeHttpReq
/// 充电方式
/// 0自动充满为止1按电量
/// </summary>
public int? ct { get; set; }
public int ct { get; set; }
/// <summary>
/// 充电参数
/// 按充电方式判断除0外 电量:单位 kWh精确到 0.01 时间:单位 min精确到 0.01 金额:单位 元,精确到 0.01
/// </summary>
public string? cp { get; set; }
public string cp { get; set; }
/// <summary>
/// 启动类型
/// 0运营平台启动1APP 启动2: 本地启动
/// </summary>
public int? st { get; set; }
public int st { get; set; }
}

@ -16,7 +16,7 @@ public class EmeterEnergyRecordTask : ITask
{
private static readonly ILog Log = LogManager.GetLogger(typeof(EmeterEnergyRecordTask));
private volatile bool _stop;
public EmeterEnergyRepository EmeterEnergyRepository { get; set; }
public EmeterEnergyChangeRepository EmeterEnergyChangeRepository { get; set; }

@ -43,19 +43,30 @@ public class OutChargerController
return Result<bool>.Fail("充电机未连接");
}
string chargeGunOrder = ChargerUtils.GenChargeOrderSn();
if (string.IsNullOrWhiteSpace(httpReq.con))
{
httpReq.con = ChargerUtils.GenChargeOrderSn();
httpReq.con = chargeGunOrder;
}
chargerClient.ChargerPile[chargerGunCode].ct = httpReq.ct;
chargerClient.ChargerPile[chargerGunCode].cp = httpReq.cp;
chargerClient.ChargerPile[chargerGunCode].st = httpReq.st;
chargerClient.ChargerPile[chargerGunCode].con = httpReq.con;
chargerClient.ChargerPile[chargerGunCode].cosn = chargeGunOrder;
chargerClient.ChargerPile[chargerGunCode].pn = httpReq.pn;
byte chargeSoc = StaticStationInfo.ChargeSoc;
// 下发充电枪充电
chargerClient.SendStartOutCharger(chargerGunCode, chargeSoc, 360, 1, httpReq.con);
chargerClient.SendStartOutCharger(chargerGunCode, chargeSoc, 360, 1, chargeGunOrder);
// 初始化订单
_chargeOrderRepository.SaveChargeGunOrder(httpReq.con, chargerCode, httpReq.pn, chargerGunCode.ToString());
_chargeOrderRepository.SaveChargeGunOrder(chargeGunOrder, httpReq.con, chargerCode, httpReq.pn,
chargerGunCode.ToString());
return Result<bool>.Success(true);
}
/// <summary>
/// 云端下发充电枪停止充电
/// </summary>

Loading…
Cancel
Save