puzhibing
7 小时以前 fe9bba84f5ded2ff0efec46cc706149b1a4073d8
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
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;
 
/**
 * 充电桩指令收发日志
 * <p>
 * 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<String, String> 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 + ")";
    }
}