慧知开源充电桩多协议微服务平台慧知开源充电桩多协议微服务平台
首页
介绍
快速了解
多协议模块
GitHub
首页
介绍
快速了解
多协议模块
GitHub
  • 文档

    • 介绍
    • 快速了解
    • 环境部署
    • 项目介绍
    • 后台手册
    • 前端手册
    • 组件文档
    • 更新日志
  • 微服务

    • 服务网关
    • 认证中心
    • 注册中心
    • 配置中心
    • 服务调用
    • 服务监控
    • 系统接口
    • 链路追踪
    • 熔断和降级
    • 分布式文件
    • 分布式事务
    • 分布式日志
    • 应用容器部署
  • 多协议模块

    • 系统概述
    • 技术栈与依赖
    • 开发者指南
    • 部署与配置
    • 消息队列集成
    • 缓存架构
    • 监控与运维
    • 安全机制
    • 数据模型与数据库设计
    • 架构设计
      • 架构设计
      • 微服务架构
      • 数据流分析
      • 架构模式
    • API接口参考
      • API接口参考
      • gRPC API
      • REST API
    • 核心模块详解
      • 核心模块详解
      • 协议处理框架
      • 设备管理模块
      • 协议实现模块
        • 云快充协议实现
        • 核心架构与初始化
        • 上行消息处理
        • 下行消息处理
        • 绿能协议实现
        • 核心架构
        • 下行消息处理
  • 其他

    • 常见问题
    • 捐赠支持

下行消息处理

目录

  1. 引言
  2. gRPC调用接收与下行指令生成
  3. 协议命令转换机制
  4. 具体下行命令实现
  5. 消息序列化过程
  6. 指令重试与超时处理
  7. 完整时序图与报文格式示例
  8. 结论

引言

本文档系统阐述了绿能协议v3.40的下行消息处理流程。重点分析了从gRPC请求到设备响应的完整处理链路,包括LvnengDownlinkCmdExe如何接收gRPC调用并生成相应的下行指令,LvnengDownlinkCmdConverter如何将通用的协议命令转换为绿能协议特有的命令码,以及具体下行命令的实现细节。同时描述了消息序列化过程、指令重试机制和超时处理策略,并提供了完整的时序图和报文格式示例。

  • [LvnengDownlinkCmdExe.java](file://mp-protocol-lvneng/src/main/java/com/witos/mp/protocol/lvneng/LvnengDownlinkCmdExe.java)
  • [LvnengDownlinkCmdConverter.java](file://mp-protocol-lvneng/src/main/java/com/witos/mp/protocol/lvneng/mapping/LvnengDownlinkCmdConverter.java)
  • [LvnengV340RemoteStopDLCmd.java](file://mp-protocol-lvneng/src/main/java/com/witos/mp/protocol/lvneng/v340/cmd/LvnengV340RemoteStopDLCmd.java)
  • [LvnengV340SetPricingModelDLCmd.java](file://mp-protocol-lvneng/src/main/java/com/witos/mp/protocol/lvneng/v340/cmd/LvnengV340SetPricingModelDLCmd.java)
  • [AbstractLvnengCmdExe.java](file://mp-protocol-lvneng/src/main/java/com/witos/mp/protocol/lvneng/AbstractLvnengCmdExe.java)
  • [LvnengProtocolMessageProcessor.java](file://mp-protocol-lvneng/src/main/java/com/witos/mp/protocol/lvneng/LvnengProtocolMessageProcessor.java)
  • [DefaultPileProtocolService.java](file://mp-app/src/main/java/com/witos/mp/app/service/impl/DefaultPileProtocolService.java)
  • [TcpSession.java](file://mp-protocol-api/src/main/java/com/witos/mp/protocol/listener/tcp/TcpSession.java)
  • [ProtocolSession.java](file://mp-protocol-api/src/main/java/com/witos/mp/protocol/domain/ProtocolSession.java)

gRPC调用接收与下行指令生成

绿能协议v3.40的下行消息处理流程始于gRPC调用的接收。系统通过DownlinkGrpcService接收来自客户端的gRPC请求,这些请求被封装为 DownlinkRequestMessage对象。当gRPC服务接收到请求时,会通过ProtocolSession的onDownlink方法将消息传递给协议处理器。

LvnengProtocolMessageProcessor作为核心处理器,负责处理所有下行消息。它通过doDownlinkHandle方法接收 SessionToHandlerMsg对象,该对象包含了DownlinkRequestMessage和TcpSession。处理器首先从DownlinkRequestMessage中提取 downlinkCmd字段,并通过DownlinkCmdEnum.valueOf()将其转换为枚举类型。

sequenceDiagram
participant Client as "客户端"
participant GrpcService as "DownlinkGrpcService"
participant ProtocolSession as "ProtocolSession"
participant MessageProcessor as "LvnengProtocolMessageProcessor"
Client->>GrpcService : 发送gRPC请求(DownlinkRequestMessage)
GrpcService->>ProtocolSession : 调用onDownlink(DownlinkRequestMessage)
ProtocolSession->>MessageProcessor : 传递SessionToHandlerMsg
MessageProcessor->>MessageProcessor : 解析DownlinkCmdEnum
MessageProcessor->>MessageProcessor : 转换为协议特定命令码
MessageProcessor->>MessageProcessor : 执行具体命令处理器

Diagram sources

  • [DownlinkGrpcService.java](file://mp-protocol-api/src/main/java/com/witos/mp/protocol/adapter/DownlinkGrpcService.java#L123-L151)

  • [ProtocolSession.java](file://mp-protocol-api/src/main/java/com/witos/mp/protocol/domain/ProtocolSession.java#L0-L77)

  • [LvnengProtocolMessageProcessor.java](file://mp-protocol-lvneng/src/main/java/com/witos/mp/protocol/lvneng/LvnengProtocolMessageProcessor.java#L0-L186)

  • [LvnengProtocolMessageProcessor.java](file://mp-protocol-lvneng/src/main/java/com/witos/mp/protocol/lvneng/LvnengProtocolMessageProcessor.java)

  • [DownlinkGrpcService.java](file://mp-protocol-api/src/main/java/com/witos/mp/protocol/adapter/DownlinkGrpcService.java)

  • [ProtocolSession.java](file://mp-protocol-api/src/main/java/com/witos/mp/protocol/domain/ProtocolSession.java)

协议命令转换机制

绿能协议v3.40使用LvnengDownlinkCmdConverter类来实现通用协议命令到绿能协议特定命令码的转换。该类实现了 DownlinkCmdConverter接口,采用单例模式确保全局唯一实例。

转换器内部使用ConcurrentHashMap存储命令映射关系,提供O(1)的查找性能。在静态初始化块中,预定义了绿能协议支持的所有命令映射:

static {
    COMMAND_MAP.put(DownlinkCmdEnum.LOGIN_ACK, 105);
    COMMAND_MAP.put(DownlinkCmdEnum.SYNC_TIME_REQUEST, 3);
    COMMAND_MAP.put(DownlinkCmdEnum.TRANSACTION_RECORD_ACK, 201);
    COMMAND_MAP.put(DownlinkCmdEnum.HEARTBEAT_ACK, 101);
    COMMAND_MAP.put(DownlinkCmdEnum.REAL_TIME_DATA_ACK, 103);
    COMMAND_MAP.put(DownlinkCmdEnum.SET_PRICING, 1103);
    COMMAND_MAP.put(DownlinkCmdEnum.REMOTE_STOP_CHARGING, 5);
    COMMAND_MAP.put(DownlinkCmdEnum.SET_QRCODE, 3);
}

当需要转换命令时,convertToCmd方法会根据传入的DownlinkCmdEnum 返回对应的协议特定命令码。如果命令不被支持,则返回null。这种设计使得命令转换过程高效且易于维护,新增命令只需在静态块中添加映射关系即可。

classDiagram
class DownlinkCmdConverter {
<<interface>>
+convertToCmd(DownlinkCmdEnum) Integer
+supports(DownlinkCmdEnum) boolean
+getProtocolName() String
}
class LvnengDownlinkCmdConverter {
-INSTANCE LvnengDownlinkCmdConverter
-COMMAND_MAP Map~DownlinkCmdEnum, Integer~
+getInstance() LvnengDownlinkCmdConverter
+convertToCmd(DownlinkCmdEnum) Integer
+getProtocolName() String
}
DownlinkCmdConverter <|.. LvnengDownlinkCmdConverter

Diagram sources

  • [LvnengDownlinkCmdConverter.java](file://mp-protocol-lvneng/src/main/java/com/witos/mp/protocol/lvneng/mapping/LvnengDownlinkCmdConverter.java#L0-L75)

  • [DownlinkCmdConverter.java](file://mp-protocol-api/src/main/java/com/witos/mp/protocol/mapping/DownlinkCmdConverter.java#L0-L44)

  • [LvnengDownlinkCmdConverter.java](file://mp-protocol-lvneng/src/main/java/com/witos/mp/protocol/lvneng/mapping/LvnengDownlinkCmdConverter.java)

具体下行命令实现

远程停止充电指令实现

LvnengV340RemoteStopDLCmd类负责处理远程停止充电指令。该类继承自LvnengDownlinkCmdExe,并使用@ProtocolCmd 注解标记其支持的命令码为5,协议版本为V340。

在execute方法中,首先从LvnengDwonlinkMessage中提取RemoteStopChargingRequest对象,获取充电桩编码和充电枪号。然后构建消息体 ByteBuf,按照协议规范填充数据:

  1. 写入2字节预留字段(值为0x00)
  2. 写入1字节充电枪口编号
  3. 写入4字节启始命令地址(值为2)
  4. 写入1字节命令个数(值为1)
  5. 写入2字节命令参数长度(值为4)
  6. 写入4字节命令参数(值为0x55)

最后调用encodeAndWriteFlush方法将指令发送到设备。

flowchart TD
Start([开始]) --> ExtractData["提取RemoteStopChargingRequest数据"]
ExtractData --> CreateBuffer["创建44字节的ByteBuf"]
CreateBuffer --> WriteReserved["写入2字节预留字段(0x00)"]
WriteReserved --> WriteGunCode["写入充电枪口编号"]
WriteGunCode --> WriteStartAddr["写入启始命令地址(2)"]
WriteStartAddr --> WriteCmdCount["写入命令个数(1)"]
WriteCmdCount --> WriteParamLen["写入命令参数长度(4)"]
WriteParamLen --> WriteParam["写入命令参数(0x55)"]
WriteParam --> Send["调用encodeAndWriteFlush发送"]
Send --> End([结束])

Diagram sources

  • [LvnengV340RemoteStopDLCmd.java](file://mp-protocol-lvneng/src/main/java/com/witos/mp/protocol/lvneng/v340/cmd/LvnengV340RemoteStopDLCmd.java#L0-L67)

  • [LvnengV340RemoteStopDLCmd.java](file://mp-protocol-lvneng/src/main/java/com/witos/mp/protocol/lvneng/v340/cmd/LvnengV340RemoteStopDLCmd.java)

电价设置报文实现

LvnengV340SetPricingModelDLCmd类负责生成电价设置报文。该类同样继承自LvnengDownlinkCmdExe,并使用@ProtocolCmd 注解标记其支持的命令码为1103,协议版本为V340。

在execute方法中,首先从SetPricingRequest中提取计费模型信息。对于时段计价模式,遍历所有时间段,将每个时间段的开始时间、结束时间、电费和服务费编码到消息体中:

  1. 将开始时间解析为LocalTime对象,分别写入小时和分钟
  2. 将结束时间解析为LocalTime对象,分别写入小时和分钟
  3. 将电费价格乘以10000后转换为整数,写入4字节
  4. 将服务费价格乘以10000后转换为整数,写入4字节

价格转换通过buildPrice方法实现,使用BigDecimal进行精确计算,避免浮点数精度问题。在发送指令前,将计费ID存入会话的请求缓存中,用于后续的响应匹配。

flowchart TD
Start([开始]) --> ExtractData["提取SetPricingRequest数据"]
ExtractData --> CheckPricing["检查计费模式"]
CheckPricing --> |时段计价| ProcessPeriods["处理每个时间段"]
ProcessPeriods --> ParseStartTime["解析开始时间"]
ParseStartTime --> WriteStartHour["写入开始小时"]
WriteStartHour --> WriteStartMinute["写入开始分钟"]
WriteStartMinute --> ParseEndTime["解析结束时间"]
ParseEndTime --> WriteEndHour["写入结束小时"]
WriteEndHour --> WriteEndMinute["写入结束分钟"]
WriteEndMinute --> ConvertElecPrice["转换电费价格"]
ConvertElecPrice --> WriteElecPrice["写入4字节电费"]
WriteElecPrice --> ConvertServPrice["转换服务费价格"]
ConvertServPrice --> WriteServPrice["写入4字节服务费"]
WriteServPrice --> NextPeriod{"还有更多时间段?"}
NextPeriod --> |是| ProcessPeriods
NextPeriod --> |否| CachePricingId["缓存计费ID"]
CachePricingId --> Send["调用encodeAndWriteFlush发送"]
Send --> End([结束])

Diagram sources

  • [LvnengV340SetPricingModelDLCmd.java](file://mp-protocol-lvneng/src/main/java/com/witos/mp/protocol/lvneng/v340/cmd/LvnengV340SetPricingModelDLCmd.java#L0-L98)

  • [LvnengV340SetPricingModelDLCmd.java](file://mp-protocol-lvneng/src/main/java/com/witos/mp/protocol/lvneng/v340/cmd/LvnengV340SetPricingModelDLCmd.java)

消息序列化过程

绿能协议v3.40的消息序列化过程由AbstractLvnengCmdExe类的encode 方法实现。该方法按照协议规范构建完整的下行消息帧,格式为:帧头(2) + 长度(2) + 加密标识(1) + 序号(1) + 命令字(2) + 数据域( n) + 校验和(1)。

序列化过程分为以下几个步骤:

  1. 计算总长度:数据域长度 + 9字节固定头尾
  2. 构建消息头和数据域:依次写入帧头、长度、加密标识、序号、命令字和数据域
  3. 准备校验和计算数据:命令字 + 数据域
  4. 计算并写入校验和:使用ByteUtil.calculateSum方法计算累加和
  5. 转换为字节数组:使用ByteUtil.toBytes方法将ByteBuf转换为字节数组
flowchart TD
Start([开始]) --> CalculateLength["计算总长度 = 数据域长度 + 9"]
CalculateLength --> BuildHeader["构建消息头"]
BuildHeader --> WriteHead["写入帧头(0xAAF5)"]
WriteHead --> WriteLength["写入长度(小端序)"]
WriteLength --> WriteEncryption["写入加密标识(0x10)"]
WriteEncryption --> WriteSeqNo["写入序号"]
WriteSeqNo --> WriteCmd["写入命令字(小端序)"]
WriteCmd --> WriteData["写入数据域"]
WriteData --> PrepareSum["准备校验和数据(命令字+数据域)"]
PrepareSum --> CalculateSum["计算累加和(ByteUtil.calculateSum)"]
CalculateSum --> WriteSum["写入校验和"]
WriteSum --> ConvertBytes["转换为字节数组(ByteUtil.toBytes)"]
ConvertBytes --> End([结束])

Diagram sources

  • [AbstractLvnengCmdExe.java](file://mp-protocol-lvneng/src/main/java/com/witos/mp/protocol/lvneng/AbstractLvnengCmdExe.java#L30-L60)

  • [AbstractLvnengCmdExe.java](file://mp-protocol-lvneng/src/main/java/com/witos/mp/protocol/lvneng/AbstractLvnengCmdExe.java)

指令重试与超时处理

绿能协议v3.40的指令重试与超时处理机制主要通过会话层的请求缓存和定时任务实现。ProtocolSession类维护了一个requestCache ,用于存储待确认的请求。该缓存使用Caffeine构建,具有以下特性:

  • 初始容量:1000
  • 最大容量:1000
  • 过期策略:访问后1分钟过期

当发送下行指令时,相关的请求ID和业务数据会被存入缓存。如果在规定时间内未收到设备的响应,缓存项将自动过期,触发重试逻辑。 TcpSession类维护了一个原子整数sequenceNumber,用于生成消息序号,确保每条消息的唯一性。

classDiagram
class ProtocolSession {
-requestCache Cache~String, Object~
+onDownlink(DownlinkRequestMessage)
+close(SessionCloseReason)
}
class TcpSession {
-sequenceNumber AtomicInteger
+nextSeqNo(SequenceNumberLength)
+writeAndFlush(ByteBuf)
}
ProtocolSession "1" -- "1" TcpSession

Diagram sources

  • [ProtocolSession.java](file://mp-protocol-api/src/main/java/com/witos/mp/protocol/domain/ProtocolSession.java#L46-L77)

  • [TcpSession.java](file://mp-protocol-api/src/main/java/com/witos/mp/protocol/listener/tcp/TcpSession.java#L41-L98)

  • [ProtocolSession.java](file://mp-protocol-api/src/main/java/com/witos/mp/protocol/domain/ProtocolSession.java)

  • [TcpSession.java](file://mp-protocol-api/src/main/java/com/witos/mp/protocol/listener/tcp/TcpSession.java)

完整时序图与报文格式示例

完整时序图

sequenceDiagram
participant Client as "客户端"
participant AppService as "应用服务"
participant ProtocolService as "协议服务"
participant ProtocolProcessor as "协议处理器"
participant Device as "设备"
Client->>AppService : 调用setPricing(SetPricingDTO)
AppService->>ProtocolService : 构建DownlinkRequestMessage
ProtocolService->>ProtocolProcessor : 发送下行消息
ProtocolProcessor->>ProtocolProcessor : 转换命令码
ProtocolProcessor->>ProtocolProcessor : 构建消息体
ProtocolProcessor->>ProtocolProcessor : 序列化消息
ProtocolProcessor->>Device : 发送报文
Device->>ProtocolProcessor : 返回响应
ProtocolProcessor->>ProtocolService : 处理上行消息
ProtocolService->>AppService : 通知结果
AppService->>Client : 返回成功

报文格式示例

以远程停止充电指令为例,完整的报文格式如下:

字段长度(字节)值(十六进制)说明
帧头2AAF5固定值
长度2002C总长度44字节
加密标识110固定值
序号101消息序号
命令字20005REMOTE_STOP_CHARGING
数据域440000010200010455...消息体
校验和1XX累加和校验
  • [LvnengProtocolMessageProcessor.java](file://mp-protocol-lvneng/src/main/java/com/witos/mp/protocol/lvneng/LvnengProtocolMessageProcessor.java)
  • [AbstractLvnengCmdExe.java](file://mp-protocol-lvneng/src/main/java/com/witos/mp/protocol/lvneng/AbstractLvnengCmdExe.java)
  • [LvnengV340RemoteStopDLCmd.java](file://mp-protocol-lvneng/src/main/java/com/witos/mp/protocol/lvneng/v340/cmd/LvnengV340RemoteStopDLCmd.java)

结论

本文档详细阐述了绿能协议v3.40的下行消息处理流程。系统通过gRPC接口接收外部请求,经由LvnengProtocolMessageProcessor 进行命令解析和路由,使用LvnengDownlinkCmdConverter将通用命令转换为协议特定命令码,并通过具体的命令执行器(如 LvnengV340RemoteStopDLCmd和LvnengV340SetPricingModelDLCmd )生成相应的下行指令。消息序列化过程严格遵循协议规范,包含帧头、长度、加密标识、序号、命令字、数据域和校验和等字段。指令重试与超时处理通过会话层的请求缓存机制实现,确保了通信的可靠性。整个流程设计合理,模块职责清晰,为充电桩远程控制提供了稳定可靠的基础。

最近更新:: 2026/5/1 15:39
Contributors: feng
Prev
核心架构