问题
执行 octt 测试用例 N56 后,SetVariableMonitoring报文会导致数据库存储错误的数据,会导致 ocpp 进程重启,随后所有的 ocpp 指令下发后都会类型转换错误。向平台输出错误日志
2025-04-07T06:44:17.737Z: ChargePoint>CentralSystem Unknown
[
4,
"3eb7e6c4-ea0e-4ed2-8c4f-a90f38f903d7",
"FormationViolation",
"No known conversion from value '6216488' to EventNotificationEnum",
{}
]解决方法
临时解决
rm /share/everest/modules/OCPP201/device_model_storage.db根本解决
将下面的的k.eventNotificationType = conversions::string_to_event_notification_enum(j.at("eventNotificationType"));直接注释掉。因为 SetVariableMonitoring 结构体并没有 eventNotificationType这个字段。这会导致数据库存入错误的数据,产生这个 BUG。
/// \brief Conversion from a given json object \p j to a given VariableMonitoring \p k
void from_json(const json& j, VariableMonitoring& k) {
// the required parts of the message
k.id = j.at("id");
k.transaction = j.at("transaction");
k.value = j.at("value");
k.type = conversions::string_to_monitor_enum(j.at("type"));
k.severity = j.at("severity");
//k.eventNotificationType = conversions::string_to_event_notification_enum(j.at("eventNotificationType"));
//std::cout << "eventNotificationType: " << j.at("eventNotificationType") << std::endl;
// the optional parts of the message
if (j.contains("customData")) {
k.customData.emplace(j.at("customData"));
}
}为什么删除数据库解决了问题
问题根源是数据库中存储了无效的 EventNotificationEnum 枚举值 “6216488”,而这个值在 OCPP 协议中不存在。
问题分析
查看代码,我们可以发现 EventNotificationEnum 只有 4 个合法值:
enum class EventNotificationEnum {
HardWiredNotification,
HardWiredMonitor,
PreconfiguredMonitor,
CustomMonitor,
};当 OCPP 重启时,它会从数据库读取之前存储的状态,然后尝试将字符串或数字转换为相应的枚举值:
EventNotificationEnum string_to_event_notification_enum(const std::string& s) {
if (s == "HardWiredNotification") {
return EventNotificationEnum::HardWiredNotification;
}
if (s == "HardWiredMonitor") {
return EventNotificationEnum::HardWiredMonitor;
}
if (s == "PreconfiguredMonitor") {
return EventNotificationEnum::PreconfiguredMonitor;
}
if (s == "CustomMonitor") {
return EventNotificationEnum::CustomMonitor;
}
throw StringToEnumException{s, "EventNotificationEnum"};
}当数据库中的值为 “6216488” 时,转换会失败并抛出异常,导致所有 OCPP 命令失败。
流程图解
sequenceDiagram
participant Client
participant OCPP
participant Database
Note over OCPP,Database: 启动前
Database->>Database: 存储了无效的枚举值 "6216488"
Note over OCPP,Database: 重启过程
Client->>OCPP: 发送重启指令
OCPP->>OCPP: 进程重启
OCPP->>Database: 读取存储的状态
Database-->>OCPP: 返回包含无效值 "6216488" 的数据
OCPP-->>OCPP: 尝试将 "6216488" 转换为 EventNotificationEnum
OCPP-->>OCPP: 转换失败,抛出 StringToEnumException
OCPP-->>Client: 返回错误 "FormationViolation"
Note over OCPP,Database: 修复过程
Client->>Database: 删除数据库文件
OCPP->>OCPP: 重启服务
OCPP->>Database: 初始化新的空数据库
OCPP->>Database: 创建新的数据结构,使用默认值
OCPP-->>Client: 正常处理命令