更新充电机 业务模型

master
lxw 8 months ago
parent d08484e8ad
commit 96a318cdfb

@ -3,97 +3,138 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using DotNetty.Buffers;
using HybirdFrameworkServices.ChargerManage.Msg;
namespace HybirdFrameworkServices
{
public class CMD202
/**
* (CMD=202/222)
*/
public class CMD202 : BaseMsg
{
public CMD202()
{
}
//调用父类的构造函数
public CMD202(IByteBuffer byteBuffer,string clientIp) : base(byteBuffer,clientIp)
{
}
public override void ParseBody()
{
}
/// <summary>
/// 预留
/// </summary>
public ushort Reserved1 { get; set; }
/// <summary>
/// 预留
/// </summary>
public ushort Reserved2 { get; set; }
/// <summary>
/// 充电桩编码
/// </summary>
public string ASCIINum { get; set; }
/// <summary>
/// 充电枪位置类型
/// <para>1-直流</para>
/// <para>2-交流</para>
/// </summary>
public byte PosType { get; set; }
/// <summary>
/// 充电枪口
/// </summary>
public byte ChargGun { get; set; }
/// <summary>
/// 充电卡号 32
/// </summary>
public string ChargID { get; set; }
/// <summary>
/// 充电开始时间
/// </summary>
public string StartTime { get; set; }
/// <summary>
/// 充电结束时间
/// </summary>
public string EndTime { get; set; }
/// <summary>
/// 充电时间长度
/// </summary>
public uint TimeSpan { get; set; }
/// <summary>
/// 开始 SOC
/// </summary>
public byte SOCStart { get; set; }
/// <summary>
/// 结束 SOC
/// </summary>
public byte SOCEnd { get; set; }
/// <summary>
/// 充电结束原因
/// </summary>
public uint EndReason { get; set; }
/// <summary>
/// 本次充电电量
/// </summary>
public string ChargCapacityNow { get; set; }
/// <summary>
/// 充电前电表读数
/// </summary>
public string SAmmeterValue { get; set; }
/// <summary>
/// 充电后电表读数
/// </summary>
public string EAmmeterValue { get; set; }
/// <summary>
/// 本次充电金额
/// </summary>
public uint ChargeAmount { get; set; }
/// <summary>
/// 内部索引号
/// </summary>
public int IndexNum { get; set; }
/// <summary>
/// 充电前卡余额
/// </summary>
public uint CardBalance { get; set; }
/// <summary>
/// 当前充电记录索引
/// </summary>
public uint ChargRecord { get; set; }
/// <summary>
/// 总充电记录条目
/// </summary>
public uint SumChargRecord { get; set; }
/// <summary>
/// 预留
/// </summary>
public byte Reserved3 { get; set; }
/// <summary>
/// 充电策略
/// <para>0:充满为止</para>
@ -102,6 +143,7 @@ namespace HybirdFrameworkServices
/// <para>3:电量控制充电</para>
/// </summary>
public byte ChargStrategy { get; set; }
/// <summary>
/// 充电策略参数
/// <code>时间单位为 1 秒</code>
@ -109,210 +151,261 @@ namespace HybirdFrameworkServices
/// <code>电量时单位为 0.01kw</code>
/// </summary>
public string ChargStrategyPara { get; set; }
/// <summary>
/// 车辆 VIN 17
/// </summary>
public string CarVIN { get; set; }
/// <summary>
/// 车牌号
/// </summary>
public string CarID { get; set; }
/// <summary>
/// 时段 1 充电电量
/// 命令 202 报文此字段是 2 字节,
/// 命令 222 报文此字段是 4 字节
/// </summary>
public string ChargCapacity01 { get; set; }
/// <summary>
///
/// </summary>
public string ChargCapacity02 { get; set; }
/// <summary>
///
/// </summary>
public string ChargCapacity03 { get; set; }
/// <summary>
///
/// </summary>
public string ChargCapacity04 { get; set; }
/// <summary>
///
/// </summary>
public string ChargCapacity05 { get; set; }
/// <summary>
///
/// </summary>
public string ChargCapacity06 { get; set; }
/// <summary>
///
/// </summary>
public string ChargCapacity07 { get; set; }
/// <summary>
///
/// </summary>
public string ChargCapacity08 { get; set; }
/// <summary>
///
/// </summary>
public string ChargCapacity09 { get; set; }
/// <summary>
///
/// </summary>
public string ChargCapacity10 { get; set; }
/// <summary>
///
/// </summary>
public string ChargCapacity11 { get; set; }
/// <summary>
///
/// </summary>
public string ChargCapacity12 { get; set; }
/// <summary>
///
/// </summary>
public string ChargCapacity13 { get; set; }
/// <summary>
///
/// </summary>
public string ChargCapacity14 { get; set; }
/// <summary>
///
/// </summary>
public string ChargCapacity15 { get; set; }
/// <summary>
///
/// </summary>
public string ChargCapacity16 { get; set; }
/// <summary>
///
/// </summary>
public string ChargCapacity17 { get; set; }
/// <summary>
///
/// </summary>
public string ChargCapacity18 { get; set; }
/// <summary>
///
/// </summary>
public string ChargCapacity19 { get; set; }
/// <summary>
///
/// </summary>
public string ChargCapacity20 { get; set; }
/// <summary>
///
/// </summary>
public string ChargCapacity21 { get; set; }
/// <summary>
///
/// </summary>
public string ChargCapacity22 { get; set; }
/// <summary>
///
/// </summary>
public string ChargCapacity23 { get; set; }
/// <summary>
///
/// </summary>
public string ChargCapacity24 { get; set; }
/// <summary>
///
/// </summary>
public string ChargCapacity25 { get; set; }
/// <summary>
///
/// </summary>
public string ChargCapacity26 { get; set; }
/// <summary>
///
/// </summary>
public string ChargCapacity27 { get; set; }
/// <summary>
///
/// </summary>
public string ChargCapacity28 { get; set; }
/// <summary>
///
/// </summary>
public string ChargCapacity29 { get; set; }
/// <summary>
///
/// </summary>
public string ChargCapacity30 { get; set; }
/// <summary>
///
/// </summary>
public string ChargCapacity31 { get; set; }
/// <summary>
///
/// </summary>
public string ChargCapacity32 { get; set; }
/// <summary>
///
/// </summary>
public string ChargCapacity33 { get; set; }
/// <summary>
///
/// </summary>
public string ChargCapacity34 { get; set; }
/// <summary>
///
/// </summary>
public string ChargCapacity35 { get; set; }
/// <summary>
///
/// </summary>
public string ChargCapacity36 { get; set; }
/// <summary>
///
/// </summary>
public string ChargCapacity37 { get; set; }
/// <summary>
///
/// </summary>
public string ChargCapacity38 { get; set; }
/// <summary>
///
/// </summary>
public string ChargCapacity39 { get; set; }
/// <summary>
///
/// </summary>
public string ChargCapacity40 { get; set; }
/// <summary>
///
/// </summary>
public string ChargCapacity41 { get; set; }
/// <summary>
///
/// </summary>
public string ChargCapacity42 { get; set; }
/// <summary>
///
/// </summary>
public string ChargCapacity43 { get; set; }
/// <summary>
///
/// </summary>
public string ChargCapacity44 { get; set; }
/// <summary>
///
/// </summary>
public string ChargCapacity45 { get; set; }
/// <summary>
///
/// </summary>
public string ChargCapacity46 { get; set; }
/// <summary>
///
/// </summary>
public string ChargCapacity47 { get; set; }
/// <summary>
/// 时段 48 充电电量
/// 命令 202 报文此字段是 2 字节,
/// 命令 222 报文此字段是 4 字节
/// </summary>
public string ChargCapacity48 { get; set; }
/// <summary>
/// 启动方式
/// <para>0本地刷卡启动</para>
@ -324,18 +417,22 @@ namespace HybirdFrameworkServices
/// <para>6迪文界面流程启动</para>
/// </summary>
public byte StartMode { get; set; }
/// <summary>
/// 充电流水号 32
/// </summary>
public string ChargSerialNum { get; set; }
/// <summary>
/// 充电服务费
/// </summary>
public uint ChargServiceCost { get; set; }
/// <summary>
/// 千分位电量
/// </summary>
public byte KilElectricity { get; set; }
/// <summary>
/// 并充标志
/// <para>0/1-单枪充电</para>
@ -343,6 +440,7 @@ namespace HybirdFrameworkServices
/// <para>3-双机柜双枪并充充电</para>
/// </summary>
public byte ParallelMark { get; set; }
/// <summary>
/// 充放电标志
///
@ -351,6 +449,7 @@ namespace HybirdFrameworkServices
/// 非协议定义值,都表示充电
/// </summary>
public byte ChargeOrDisMark { get; set; }
/// <summary>
/// 电表加密数据
///
@ -363,14 +462,17 @@ namespace HybirdFrameworkServices
/// 1 字节端钮历史状态(0 正常1 发生过端钮盖打开时间)
/// </summary>
public string MeterEncData { get; set; }
/// <summary>
/// 电表表号 6
/// </summary>
public string MeterNum { get; set; }
/// <summary>
/// 电表协议版本
/// </summary>
public ushort MeterProVersion { get; set; }
/// <summary>
/// 加密方式
/// 当前加密方式(工厂模式下配置,抄读无任何限制)
@ -382,6 +484,5 @@ namespace HybirdFrameworkServices
/// <para>05:其他</para>
/// </summary>
public byte EncMode { get; set; }
}
}
}

@ -3,11 +3,46 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using DotNetty.Buffers;
using HybirdFrameworkServices.ChargerManage.Msg;
/**
* (CMD=206)
*/
namespace HybirdFrameworkServices
{
public class CMD206
public class CMD206 : BaseMsg
{
public CMD206()
{
}
//调用父类的构造函数
public CMD206(IByteBuffer byteBuffer,string clientIp) : base(byteBuffer,clientIp)
{
}
public override void ParseBody()
{
this.Reserved1=this.ByteBuffer.GetUnsignedShortLE(BaseMsg.StartBodyIndex);
this.Reserved2=this.ByteBuffer.GetUnsignedShortLE(BaseMsg.StartBodyIndex+2);
ByteBuffer.SetReaderIndex(12);
// 读取接下来的32字节
byte[] no = new byte[32];
ByteBuffer.ReadBytes(no);
this.ASCIINum = Encoding.ASCII.GetString(no);
no = new byte[32];
ByteBuffer.ReadBytes(no);
this.ChargID = Encoding.ASCII.GetString(no);
no = new byte[32];
ByteBuffer.ReadBytes(no);
this.ChargPassword = Encoding.ASCII.GetString(no);
no = new byte[48];
ByteBuffer.ReadBytes(no);
this.RandomData = Encoding.ASCII.GetString(no);
}
/// <summary>
/// 预留
/// </summary>

@ -0,0 +1,38 @@
namespace HybirdFrameworkServices.ChargerManage;
/**
*
*/
public class ChargerInfo
{
public static Dictionary<string, ChargerInfo> ChargerInfoMap = new Dictionary<string, ChargerInfo>();
//充电机编号
public string? ChargerNo { get; set; }
//通道id
public string? ChannelId { get; set; }
//ip
public string? Ip { get; set; }
//端口
public int Port { get; set; }
public bool Status { get; set; }
//构造方法
public ChargerInfo(string chargerNo, string channelId, string ip, int port)
{
this.ChannelId = channelId;
this.Ip = ip;
this.Port = port;
this.ChargerNo = chargerNo;
}
}

@ -0,0 +1,27 @@
using DotNetty.Transport.Channels;
using HybirdFrameworkServices.ChargerManage.Msg;
namespace HybirdFrameworkServices.ChargerManage.Handler;
public class CMD206Handler:SimpleChannelInboundHandler<CMD206>
{
protected override void ChannelRead0(IChannelHandlerContext ctx, CMD206 msg)
{
//处理
string chargeNo = msg.MHeader.ChargerNo;
ChargerInfo chargerInfo;
ChargerInfo.ChargerInfoMap.TryGetValue(chargeNo, out chargerInfo);
if (null == chargerInfo)
{
throw new Exception("充电机未注册");
}
//TODO:: 业务(数据库交互)
//TODO:: 返回
ctx.WriteAndFlushAsync(msg);
}
}

@ -0,0 +1,149 @@
using System.Text;
using DotNetty.Buffers;
namespace HybirdFrameworkServices.ChargerManage.Msg;
/**
*
*/
public class BaseMsg
{
public static int StartBodyIndex = 8;
//请求头
public Header MHeader = new Header();
public string ClientIp;
//请求体
protected IByteBuffer ByteBuffer { get; set; }
public BaseMsg()
{
}
public void Parse()
{
this.ParseHeader();
this.ParseBody();
this.ByteBuffer.Release();
}
public BaseMsg(IByteBuffer byteBuffer, string clientIp)
{
this.ByteBuffer = byteBuffer;
this.ClientIp = clientIp;
}
protected void ParseHeader()
{
MHeader.LengthDomain = this.ByteBuffer.GetUnsignedShortLE(2);
byte[] bytes = new byte[MHeader.LengthDomain];
ByteBuffer.ReadBytes(bytes);
int checksum = 0;
for (int i = 6; i < bytes.Count() - 1; i++) //这里有校验域所以减一
{
checksum += bytes[i];
}
// 取校验和的低8位
//byte b1 = (byte)(checksum & 0xFF);
//byte b2 = (byte)(bytes[bytes.Count() - 1] & 0xFF);
bool checkFlag = (byte)(bytes[bytes.Count() - 1] & 0xFF) == (byte)(checksum & 0xFF);
if (!checkFlag)
{
throw new Exception("报文校验不通过");
}
var info = bytes[4];
//TODO:: 修改解密 目前流转使用的bytebuffer
if ((info & (1 << 1)) != 0) //AES加密
{
//这里要解密
List<byte> byteList = bytes.ToList();
byteList.Remove(8);
byteList.Remove(8); //移除前面两个长度
bytes = byteList.ToArray();
}
MHeader.InfoDomain = this.ByteBuffer.GetByte(4);
MHeader.SerialNumberDomain = this.ByteBuffer.GetByte(5);
MHeader.CMD = this.ByteBuffer.GetUnsignedShortLE(6);
MHeader.ChecksumDomain = this.ByteBuffer.GetByte(MHeader.LengthDomain - 1);
//看是否读到chargerNo 否则回塞 :主要解决一些应答报文不带充电机编号的问题(4位cmd 非业务报文 回塞充电机编号)
if (MHeader.CMD > 1000)
{
Dictionary<string, string> ipNoMap =
ChargerInfo.ChargerInfoMap.Values.ToDictionary(kvp => kvp.Ip, kvp => kvp.ChargerNo);
string value;
ipNoMap.TryGetValue(MHeader.Ip, out value);
MHeader.ChargerNo = value;
}
else
{
ByteBuffer.SetReaderIndex(12);
// 读取接下来的32字节
byte[] no = new byte[32];
ByteBuffer.ReadBytes(no);
MHeader.ChargerNo = Encoding.ASCII.GetString(no);
}
}
public virtual void ParseBody()
{
}
public class Header
{
public string Ip { get; set; }
/// <summary>
/// 起始域
/// </summary>
public ushort OriginDomain1 { get; set; } = 0xAAF5;
/// <summary>
/// 长度域 2
/// </summary>
public UInt16 LengthDomain { get; set; }
/// <summary>
/// 信息域
///
/// 除了 CMD=1202 加密能用 RSA 加密方式,
/// 其他报文若是加密,全部是采用 AES方式加密。
/// <para>bit0-3 当前协议是V2.6值填0x02</para>
/// </summary>
public byte InfoDomain { get; set; }
/// <summary>
/// 序列号域
/// </summary>
public byte SerialNumberDomain { get; set; }
/// <summary>
/// 命令代CMD
/// </summary>
public UInt16 CMD { get; set; }
/// <summary>
/// 数据域
/// </summary>
public byte[] DataDomain { get; set; }
/// <summary>
/// 校验和域
/// </summary>
public byte ChecksumDomain { get; set; }
public string ChargerNo { get; set; }
}
}

@ -10,6 +10,7 @@ using DotNetty.Transport.Bootstrapping;
using DotNetty.Transport.Channels;
using DotNetty.Transport.Channels.Sockets;
using HybirdFrameworkCore.Autofac.Attribute;
using HybirdFrameworkServices.ChargerManage.Handler;
using HybirdFrameworkServices.System;
using log4net;
@ -57,11 +58,8 @@ namespace HybirdFrameworkServices.Netty
pipeline.AddLast(new CustomFrameDecoder(new IByteBuffer[] { delimiter }, false, false));
pipeline.AddLast(new CustomFrameEncoder());
//// 添加客户端连接监控Handler
pipeline.AddLast(new ClientConnectionMonitorHandler());
//pipeline.AddLast("idleStateHandler", new IdleStateHandler(30, 0, 0)); // 触发读取超时
//pipeline.AddLast(new ReconnectHandler(this));
//pipeline.AddLast(new ClientHandler(this));
pipeline.AddLast(new CMD206Handler());
}));
Begin(_port);
}

@ -8,13 +8,19 @@ using DotNetty.Codecs;
using DotNetty.Transport.Channels;
using System;
using System.Collections.Generic;
using System.Net;
using System.Numerics;
using System.Text.RegularExpressions;
using HybirdFrameworkEntity;
using HybirdFrameworkServices.ChargerManage;
using HybirdFrameworkServices.ChargerManage.Msg;
namespace HybirdFrameworkServices
{
public class CustomFrameDecoder : ByteToMessageDecoder
{
private readonly IByteBuffer[] delimiters;
private readonly bool stripDelimiter;
private readonly bool failFast;
@ -49,83 +55,46 @@ namespace HybirdFrameworkServices
// 读取长度字段
int frameLength = buffer.GetUnsignedShortLE(buffer.ReaderIndex + frameLengthIndex);
int totalFrameLength = delimiterIndex + delimiter.Capacity + 2 + frameLength;
if (buffer.ReadableBytes < totalFrameLength)
if (buffer.ReadableBytes < frameLength)
{
// 数据不足,等待更多数据
return;
}
;
IPEndPoint remoteAddress = (IPEndPoint)ctx.Channel.RemoteAddress;
string clientIP = remoteAddress.Address.ToString();
output.Add( this.Parse(buffer,clientIP));
}
}
byte[] bytes = new byte[frameLength];
buffer.ReadBytes(bytes);
{
int checksum = 0;
for (int i = 6; i < bytes.Count() - 1; i++)//这里有校验域所以减一
{
checksum += bytes[i];
}
// 取校验和的低8位
//byte b1 = (byte)(checksum & 0xFF);
//byte b2 = (byte)(bytes[bytes.Count() - 1] & 0xFF);
if ((byte)(bytes[bytes.Count() - 1] & 0xFF) == (byte)(checksum & 0xFF))
{
var info = bytes[4];
if ((info & (1 << 1)) != 0)//AES加密
{
//这里要解密
List<byte> byteList = bytes.ToList();
byteList.Remove(8);
byteList.Remove(8);//移除前面两个长度
bytes = byteList.ToArray();
CmnChargingsEqmInfo._CHR01.decode(bytes);
}
else //不加密
{
//CmnChargingsEqmInfo._CHR01.decode(bytes);
string input = ctx.Channel.RemoteAddress.ToString();
// 正则表达式匹配IPv4地址和端口号
string pattern = @"\[(::ffff:)?(\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3})\]:(\d+)";
Match match = Regex.Match(input, pattern);
// 获取IP地址不包括IPv6前缀
string ipAddress = match.Groups[2].Value;
switch (ipAddress)
{
case "127.0.0.1":
CmnChargingsEqmInfo._CHR01.ID = ctx.Channel.Id;
CmnChargingsEqmInfo._CHR01.decode(bytes);
break;
case "127.0.0.2":
CmnChargingsEqmInfo._CHR02.ID = ctx.Channel.Id;
CmnChargingsEqmInfo._CHR02.decode(bytes);
break;
case "127.0.0.3":
CmnChargingsEqmInfo._CHR03.ID = ctx.Channel.Id;
CmnChargingsEqmInfo._CHR03.decode(bytes);
break;
case "127.0.0.4":
break;
case "127.0.0.5":
break;
case "127.0.0.6":
break;
case "127.0.0.7":
break;
case "127.0.0.8":
break;
}
}
}
//ctx.Channel.WriteAndFlushAsync(bytes);
}
output.Add(bytes);
}
//将消息给每个充电机对象
public BaseMsg Parse(IByteBuffer byteBuffer,string clientIp)
{
BaseMsg baseMsg = null;
//将cmd解析出来
ushort cmd = byteBuffer.GetUnsignedShortLE(6);
baseMsg = cmd switch
{
206 => new CMD206(byteBuffer,clientIp),
202=> new CMD202(byteBuffer,clientIp),
_ => new BaseMsg(byteBuffer,clientIp),
};
baseMsg.Parse();
return baseMsg;
}
private IByteBuffer FindDelimiter(IByteBuffer buffer)

Loading…
Cancel
Save