package com.ruoyi.integration.iotda.utils.tools;
import com.ruoyi.integration.iotda.constant.SendTagConstant;
import com.ruoyi.integration.iotda.enums.ServiceIdMenu;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.HashMap;
import java.util.Map;
/**
* 充电桩指令收发日志
*
* 1、使用独立 logger(pile-command)输出到独立日志文件,与业务日志分离(见 logback.xml);
* 2、日志记录统一打印指令含义,格式:指令=中文含义(service_id);
* 3、心跳指令(上行 ping、下行 pong)不记录,避免日志量过大。
*/
public class IotCommandLog {
/** 独立日志 logger,输出到独立日志文件(logback.xml 中 pile-command 配置) */
private static final Logger COMMAND_LOG = LoggerFactory.getLogger("pile-command");
/** 上行指令 service_id -> 中文含义 */
private static final Map UPLINK_MEANING = new HashMap<>();
static {
UPLINK_MEANING.put(SendTagConstant.ONLINE, "充电桩登录认证");
UPLINK_MEANING.put(SendTagConstant.PING, "充电桩心跳包");
UPLINK_MEANING.put(SendTagConstant.END_CHARGE, "充电结束");
UPLINK_MEANING.put(SendTagConstant.ERROR_MESSAGE, "错误报文");
UPLINK_MEANING.put(SendTagConstant.BILLING_MODE_VERIFY, "计费模型验证请求");
UPLINK_MEANING.put(SendTagConstant.ACQUISITION_BILLING_MODE, "充电桩计费模型请求");
UPLINK_MEANING.put(SendTagConstant.UPLOAD_REAL_TIME_MONITORING_DATA, "上传实时监测数据");
UPLINK_MEANING.put(SendTagConstant.CHARGING_HANDSHAKE, "充电握手");
UPLINK_MEANING.put(SendTagConstant.PARAMETER_SETTING, "参数配置");
UPLINK_MEANING.put(SendTagConstant.BMS_ABORT, "充电阶段BMS中止");
UPLINK_MEANING.put(SendTagConstant.MOTOR_ABORT, "充电阶段充电机中止");
UPLINK_MEANING.put(SendTagConstant.BMS_DEMAND_AND_CHARGER_EXPORTATION, "充电过程BMS需求、充电机输出");
UPLINK_MEANING.put(SendTagConstant.BMS_INFORMATION, "充电过程BMS信息");
UPLINK_MEANING.put(SendTagConstant.CHARGING_PILE_STARTS_CHARGING, "充电桩主动申请启动充电");
UPLINK_MEANING.put(SendTagConstant.PLATFORM_START_CHARGING_REPLY, "远程启机命令回复");
UPLINK_MEANING.put(SendTagConstant.PLATFORM_STOP_CHARGING_REPLY, "远程停机命令回复");
UPLINK_MEANING.put(SendTagConstant.TRANSACTION_RECORD, "交易记录");
UPLINK_MEANING.put(SendTagConstant.UPDATE_BALANCE_REPLY, "余额更新应答");
UPLINK_MEANING.put(SendTagConstant.SYNCHRONIZE_OFFLINE_CARD_REPLY, "卡数据同步应答");
UPLINK_MEANING.put(SendTagConstant.CLEAR_OFFLINE_CARD_REPLY, "离线卡数据清除应答");
UPLINK_MEANING.put(SendTagConstant.QUERY_OFFLINE_CARD_REPLY, "离线卡数据查询应答");
UPLINK_MEANING.put(SendTagConstant.WORKING_PARAMETER_SETTING_REPLY, "充电桩工作参数设置应答");
UPLINK_MEANING.put(SendTagConstant.TIMING_SETTING, "对时设置");
UPLINK_MEANING.put(SendTagConstant.SETUP_BILLING_MODEL_REPLY, "计费模型应答");
UPLINK_MEANING.put(SendTagConstant.GROUND_LOCK_REAL_TIME_DATA, "地锁数据上送");
UPLINK_MEANING.put(SendTagConstant.CHARGING_PILE_RETURNS_GROUND_LOCK_DATA, "充电桩返回地锁数据");
UPLINK_MEANING.put(SendTagConstant.PLATFORM_RESTART_REPLY, "远程重启应答");
UPLINK_MEANING.put(SendTagConstant.PLATFORM_REMOTE_UPDATE_REPLY, "远程更新应答");
UPLINK_MEANING.put(SendTagConstant.QR_CODE_DELIVERY_REPLY, "二维码下发应答");
UPLINK_MEANING.put(SendTagConstant.SECURITY_DETECTION, "安全监测");
UPLINK_MEANING.put(SendTagConstant.GUN_STATUS, "推送充电设备接口状态信息");
UPLINK_MEANING.put(SendTagConstant.ORDER_STATUS, "推送充电状态信息");
UPLINK_MEANING.put(SendTagConstant.ORDER_INFO, "推送充电订单信息");
}
private IotCommandLog() {
}
/**
* 记录上行指令(设备 -> 平台)
* 心跳(ping)不记录
*
* @param deviceNo 设备编号
* @param serviceId 指令 service_id
* @param payload 报文内容
*/
public static void uplink(String deviceNo, String serviceId, Object payload) {
if (SendTagConstant.PING.equals(serviceId)) {
// 心跳不记录日志
return;
}
COMMAND_LOG.info("[上行] 设备={} 指令={} 报文={}", deviceNo, describeUplink(serviceId), payload);
}
/**
* 记录下行指令(平台 -> 设备)
* 心跳应答(pong)不记录
*
* @param deviceNo 设备编号
* @param name 下发名称
* @param serviceId 指令 service_id
* @param payload 报文内容
*/
public static void downlink(String deviceNo, String name, String serviceId, Object payload) {
if (isPong(serviceId)) {
// 心跳应答不记录日志
return;
}
COMMAND_LOG.info("[下行] 设备={} 指令={} 报文={}", deviceNo, describeDownlink(serviceId, name), payload);
}
/**
* 记录下行指令下发失败
* 心跳应答(pong)不记录
*
* @param deviceNo 设备编号
* @param name 下发名称
* @param serviceId 指令 service_id
* @param payload 报文内容
* @param error 失败原因
*/
public static void downlinkFail(String deviceNo, String name, String serviceId, Object payload, String error) {
if (isPong(serviceId)) {
// 心跳应答不记录日志
return;
}
COMMAND_LOG.error("[下行失败] 设备={} 指令={} 报文={} 错误={}", deviceNo, describeDownlink(serviceId, name), payload, error);
}
/**
* 记录无法解析的上行原始报文(兜底)
* 报文解析失败时无法识别 service_id,不能判断是否为心跳,仍记录原始内容便于排查
*
* @param deviceNo 设备编号
* @param rawPayload 原始报文内容
*/
public static void uplinkUnparsed(String deviceNo, Object rawPayload) {
COMMAND_LOG.info("[上行-原始报文] 设备={} 报文={}", deviceNo, rawPayload);
}
/** 是否心跳应答(pong) */
private static boolean isPong(String serviceId) {
return ServiceIdMenu.PONG.getValue().equals(serviceId);
}
/** 上行指令含义:中文含义(service_id) */
private static String describeUplink(String serviceId) {
String meaning = UPLINK_MEANING.get(serviceId);
if (meaning == null || meaning.isEmpty()) {
meaning = "未识别指令";
}
return meaning + "(" + serviceId + ")";
}
/** 下行指令含义:中文含义(service_id) */
private static String describeDownlink(String serviceId, String name) {
String meaning = null;
if (serviceId != null) {
for (ServiceIdMenu menu : ServiceIdMenu.values()) {
if (menu.getValue().equals(serviceId)) {
meaning = menu.getKey();
break;
}
}
}
if (meaning == null || meaning.isEmpty()) {
meaning = (name == null || name.isEmpty()) ? "未识别指令" : name;
}
return meaning + "(" + serviceId + ")";
}
}