诊断数据的类型和来源
graph TB
A[硬件模块] --> B[传感器数据]
B --> C[底层驱动]
C --> D[Telemetry数据采集]
D --> E[TelemetryMap数据格式化]
E --> F[数据上报]
F --> G1[实时数据livedata]
F --> G2[事件数据events]
F --> G3[会话数据session]
subgraph 硬件数据来源
A
B
end
subgraph 数据处理层
C
D
E
end
subgraph 数据通道
F
G1
G2
G3
end
系统中主要收集和上报的诊断数据包括:
-
硬件状态数据:
- CP (Control Pilot) 电压高低值
- PWM占空比
- 电源电压和电流
- 温度数据(控制器温度、连接器温度)
- 计量表读数
-
事件数据:
- 交易开始/结束事件
- 错误事件
- 系统状态变化事件
-
会话数据:
- 充电会话信息
- 能量消耗数据
- 身份认证信息
诊断数据采集流程
sequenceDiagram
participant 硬件驱动 as Module Driver
participant 遥测线程 as Telemetry Thread
participant 遥测提供器 as TelemetryProvider
participant OCPP模块 as OCPP Module
participant 系统模块 as System Module
硬件驱动->>硬件驱动: 初始化硬件接口
硬件驱动->>遥测线程: 创建遥测数据收集线程
遥测线程->>遥测线程: 定时收集硬件状态数据
遥测线程->>遥测提供器: 发布遥测数据(publish)
遥测提供器->>OCPP模块: 转发遥测数据
OCPP模块->>系统模块: 发送诊断日志上传请求
系统模块->>系统模块: 创建临时诊断文件
系统模块->>系统模块: 收集系统诊断数据
系统模块->>系统模块: 启动上传线程
系统模块->>外部服务器: 上传诊断文件
关键代码实现分析
诊断数据收集
以YetiDriver模块为例,它通过定期读取硬件状态创建遥测数据:
// YetiDriver.cpp中的telemetryThreadHandle线程
telemetryThreadHandle = std::thread([this]() {
while (!telemetryThreadHandle.shouldExit()) {
sleep(10); // 每10秒收集一次数据
{
std::scoped_lock lock(telemetry_mutex);
publish_external_telemetry_livedata("power_path_controller", telemetry_power_path_controller);
publish_external_telemetry_livedata("rcd", telemetry_rcd);
publish_external_telemetry_livedata("power_path_controller_version",
telemetry_power_path_controller_version);
}
}
});数据发布机制
数据通过TelemetryProvider接口发布:
void YetiDriver::publish_external_telemetry_livedata(const std::string& topic, const Everest::TelemetryMap& data) {
if (info.telemetry_enabled) {
telemetry.publish("livedata", topic, data);
}
}诊断数据格式
诊断数据以TelemetryMap形式存储和传输,这是一种键值对映射:
// 电源数据示例
Everest::TelemetryMap telemetry_data{
{"timestamp", current_iso_time_string},
{"type", "power_path_controller"},
{"cp_voltage_high", p_p_c.cp_voltage_high},
{"cp_voltage_low", p_p_c.cp_voltage_low},
{"cp_pwm_duty_cycle", p_p_c.cp_pwm_duty_cycle},
{"cp_state", p_p_c.cp_state},
{"temperature_controller", p_p_c.temperature_controller},
{"temperature_car_connector", p_p_c.temperature_car_connector},
{"watchdog_reset_count", p_p_c.watchdog_reset_count},
{"error", p_p_c.error}
};诊断日志上传流程
系统模块提供了诊断日志上传功能,主要步骤:
graph TD
A[客户端/测试用例] -->|发送诊断请求| B[OCPP201模块]
B -->|调用System模块| C[System模块]
C -->|创建临时文件| D[创建diagnostics-xxx文件]
C -->|启动上传线程| E[upload_logs_thread]
E -->|调用脚本| F[diagnostics_uploader.sh]
F -->|上传结果| E
E -->|更新状态| G[publish_log_status]
G -->|消息发送| B
B -->|转换消息| H[message_callback处理]
H -->|尝试转换枚举值| I[EnumConversionException]
I -->|错误: 值'6675368'不能转换为EventNotificationEnum| J[处理失败]
系统模块的上传日志实现:
```cpp
types::system::UploadLogsResponse
systemImpl::handle_upload_logs(types::system::UploadLogsRequest& upload_logs_request) {
// 创建临时诊断文件
const auto diagnostics_file_path = create_temp_file(fs::temp_directory_path(), "diagnostics-" + date_time);
// 收集诊断数据(示例中是mock数据)
const auto fake_diagnostics_file = json({{"diagnostics", {{"key", "value"}}}});
std::ofstream diagnostics_file(diagnostics_file_path.c_str());
diagnostics_file << fake_diagnostics_file.dump();
// 启动上传线程
this->upload_logs_thread = std::thread([this, /*参数*/]() {
// 上传逻辑...
const auto diagnostics_uploader = this->scripts_path / DIAGNOSTICS_UPLOADER;
// 执行上传脚本
boost::process::child cmd(diagnostics_uploader.string(),
boost::process::args(args),
boost::process::std_out > stream);
// 处理上传结果...
});
}
诊断上传脚本
诊断上传通过Shell脚本实现:
#!/bin/bash
# diagnostics_uploader.sh
. "${1}" # 加载环境变量
echo "$UPLOADING" # 发出上传中状态
sleep 2
curl --progress-bar --ssl --connect-timeout "$CONNECTION_TIMEOUT" -T "${4}" "${2}"
curl_exit_code=$?
# 根据上传结果返回相应状态
if [ $curl_exit_code -eq 0 ]($curl_exit_code%20-eq%200.md); then
echo "$UPLOADED" # 上传成功
elif [ $curl_exit_code -eq 67 ]($curl_exit_code%20-eq%2067.md) || [ $curl_exit_code -eq 35 ]($curl_exit_code%20-eq%2035.md) || [ $curl_exit_code -eq 69 ]($curl_exit_code%20-eq%2069.md) ||
[ $curl_exit_code -eq 9 ]($curl_exit_code%20-eq%209.md); then
echo "$PERMISSION_DENIED" # 权限拒绝
# 其他错误处理...
else
echo "$UPLOAD_FAILURE" # 上传失败
fi数据流通路径
graph LR
A[硬件传感器] --> B[硬件驱动模块]
B --> C[TelemetryProvider]
C --> D1[本地存储]
C --> D2[MQTT发布]
C --> D3[OCPP模块]
D3 --> E[外部充电管理系统]
subgraph 数据转发
C
D1
D2
D3
end
总结
-
分层架构:诊断系统采用分层架构,从硬件数据采集到最终上报形成完整链路
-
多样数据源:收集各种硬件状态、事件和会话数据,以键值对形式组织
-
异步处理:使用独立线程进行数据采集和上报,不影响主业务逻辑
-
可靠机制:提供重试、状态通知等可靠性机制确保诊断数据成功上报
-
可扩展性:系统设计支持不同类型数据的收集和上报,便于扩展更多诊断功能
诊断上报功能使充电桩能够将运行状态、错误和会话数据发送到管理系统,便于远程监控、故障诊断和维护操作。