2025-09-01 20:08:40 +08:00
|
|
|
|
#include "MqttEntity.h"
|
|
|
|
|
|
#include "common/Spdlogger.h"
|
2025-09-05 19:44:26 +08:00
|
|
|
|
#include "common/Utils.h"
|
2025-09-08 19:34:12 +08:00
|
|
|
|
#include "app/Application.h"
|
|
|
|
|
|
#include "app/AppData.h"
|
|
|
|
|
|
#include "app/Station.h"
|
|
|
|
|
|
#include "app/Device.h"
|
2025-09-01 20:08:40 +08:00
|
|
|
|
|
|
|
|
|
|
#define TIMEOUT 10000L
|
|
|
|
|
|
|
2025-09-08 19:34:12 +08:00
|
|
|
|
std::string REGAddrOffset(std::string addr, int offset)
|
|
|
|
|
|
{
|
|
|
|
|
|
unsigned int val;
|
|
|
|
|
|
std::stringstream ss;
|
|
|
|
|
|
ss << std::hex << addr;
|
|
|
|
|
|
ss >> val;
|
|
|
|
|
|
return Utils::toHexStr(val + offset);
|
|
|
|
|
|
}
|
2025-09-05 19:44:26 +08:00
|
|
|
|
|
|
|
|
|
|
static std::map<std::string, std::map<std::string, REGInfo>> g_mapRegInfo;
|
|
|
|
|
|
|
|
|
|
|
|
void MqttClient::loadDataStruct(std::string filename)
|
|
|
|
|
|
{
|
2025-09-06 15:23:07 +08:00
|
|
|
|
njson json;
|
|
|
|
|
|
JSON::load(filename, json);
|
2025-09-05 19:44:26 +08:00
|
|
|
|
|
|
|
|
|
|
// 遍历 JSON 对象
|
|
|
|
|
|
for (auto& jsonitem : json.items())
|
|
|
|
|
|
{
|
2025-09-08 19:34:12 +08:00
|
|
|
|
std::string name = jsonitem.key();
|
2025-09-13 17:28:35 +08:00
|
|
|
|
auto& jsonnodeItem = jsonitem.value();
|
2025-09-12 18:44:34 +08:00
|
|
|
|
//int count = jsonnodeItem["count"];
|
2025-09-08 19:34:12 +08:00
|
|
|
|
auto jsonaddrs = jsonnodeItem["addr"];
|
|
|
|
|
|
|
|
|
|
|
|
auto& mapItem = g_mapRegInfo[name];
|
|
|
|
|
|
int size = 0;
|
|
|
|
|
|
for (int i = 0; i<2; ++i)
|
2025-09-05 19:44:26 +08:00
|
|
|
|
{
|
2025-09-08 19:34:12 +08:00
|
|
|
|
for (auto& item : jsonaddrs)
|
|
|
|
|
|
{
|
|
|
|
|
|
std::string addr = item["key"];
|
|
|
|
|
|
if (i > 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
addr = REGAddrOffset(addr, size*i);
|
|
|
|
|
|
}
|
|
|
|
|
|
mapItem[addr] = REGInfo(addr, item["datatype"], item["remark"]);
|
|
|
|
|
|
if (i ==0)
|
|
|
|
|
|
{
|
|
|
|
|
|
size += mapItem[addr].bytes;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-09-05 19:44:26 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-09-10 20:10:51 +08:00
|
|
|
|
//
|
2025-09-05 19:44:26 +08:00
|
|
|
|
|
2025-09-04 19:31:04 +08:00
|
|
|
|
int MqttClient::init(string addr, string clientId, string username, string password)
|
2025-09-01 20:08:40 +08:00
|
|
|
|
{
|
2025-09-13 17:28:35 +08:00
|
|
|
|
if (isConnected)
|
|
|
|
|
|
{
|
|
|
|
|
|
return MQTTASYNC_SUCCESS;
|
|
|
|
|
|
}
|
|
|
|
|
|
if (addr.empty())
|
|
|
|
|
|
{
|
|
|
|
|
|
return MQTTASYNC_FAILURE;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-01 20:08:40 +08:00
|
|
|
|
this->addr = addr;
|
2025-09-04 19:31:04 +08:00
|
|
|
|
this->clientId = clientId;
|
2025-09-10 20:10:51 +08:00
|
|
|
|
|
2025-09-13 17:28:35 +08:00
|
|
|
|
this->mapTopicInfo["EMS_YX"] = TopicInfo("EMS_YX", 101);
|
|
|
|
|
|
this->mapTopicInfo["EMS_YC"] = TopicInfo("EMS_YC", 101);
|
|
|
|
|
|
this->mapTopicInfo["EMS_YT"] = TopicInfo("EMS_YT", 101);
|
|
|
|
|
|
this->mapTopicInfo["PCS_YX"] = TopicInfo("PCS_YX", 102, 1);
|
2025-09-12 18:44:34 +08:00
|
|
|
|
this->mapTopicInfo["PCS_YC"] = TopicInfo("PCS_YC", 102, 1);
|
2025-09-13 17:28:35 +08:00
|
|
|
|
this->mapTopicInfo["PCU_YX"] = TopicInfo("PCU_YX", 103);
|
|
|
|
|
|
this->mapTopicInfo["PCU_YC"] = TopicInfo("PCU_YC", 103);
|
|
|
|
|
|
this->mapTopicInfo["BMS_YX"] = TopicInfo("BMS_YX", 104);
|
|
|
|
|
|
this->mapTopicInfo["BMS_YC"] = TopicInfo("BMS_YC", 104);
|
|
|
|
|
|
this->mapTopicInfo["BCU_YX"] = TopicInfo("BCU_YX", 105, 1);
|
|
|
|
|
|
this->mapTopicInfo["BCU_YC"] = TopicInfo("BCU_YC", 105, 1);
|
|
|
|
|
|
this->mapTopicInfo["MEM_YC"] = TopicInfo("MEM_YC", 3);
|
|
|
|
|
|
this->mapTopicInfo["Cooling_YC"] = TopicInfo("Cooling_YC", 110);
|
|
|
|
|
|
this->mapTopicInfo["TH_YC"] = TopicInfo("TH_YC", 111);
|
|
|
|
|
|
this->mapTopicInfo["Gateway_YX"] = TopicInfo("Gateway_YX", 112);
|
|
|
|
|
|
this->mapTopicInfo["Charger_YC"] = TopicInfo("Charger_YC", 113);
|
2025-09-01 20:08:40 +08:00
|
|
|
|
|
|
|
|
|
|
MQTTAsync_connectOptions option = MQTTAsync_connectOptions_initializer;
|
|
|
|
|
|
MQTTAsync_message pubmsg = MQTTAsync_message_initializer;
|
|
|
|
|
|
int rc {0};
|
|
|
|
|
|
|
|
|
|
|
|
// "tcp://localhost:1883"
|
2025-09-05 19:44:26 +08:00
|
|
|
|
std::string str = "ESS-" + std::to_string(Utils::random(1000, 9999)) + "-" +clientId;
|
|
|
|
|
|
rc = MQTTAsync_create(&client, addr.c_str(), str.c_str(), MQTTCLIENT_PERSISTENCE_NONE, NULL);
|
2025-09-01 20:08:40 +08:00
|
|
|
|
if (rc != MQTTASYNC_SUCCESS)
|
|
|
|
|
|
{
|
|
|
|
|
|
spdlog::error("[mqtt] MQTTAsync_create error: {}", rc);
|
|
|
|
|
|
return rc;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
MQTTAsync_connectionLost* onConnectionLost =
|
|
|
|
|
|
[](void* context, char* cause)
|
|
|
|
|
|
{
|
|
|
|
|
|
static_cast<MqttClient*>(context)->onConnectionLost(cause);
|
|
|
|
|
|
};
|
|
|
|
|
|
MQTTAsync_messageArrived* onMessageArrived =
|
|
|
|
|
|
[](void* context, char* topicName, int topicLen, MQTTAsync_message* message)->int
|
|
|
|
|
|
{
|
|
|
|
|
|
return static_cast<MqttClient*>(context)->onMessageArrived(topicName, topicLen, message);
|
|
|
|
|
|
};
|
|
|
|
|
|
MQTTAsync_deliveryComplete* onDeliveryComplete =
|
|
|
|
|
|
[](void* context, MQTTAsync_token token)
|
|
|
|
|
|
{
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//设置连接丢失、接受消息的回调函数
|
|
|
|
|
|
rc = MQTTAsync_setCallbacks(client, this, onConnectionLost, onMessageArrived, onDeliveryComplete);
|
|
|
|
|
|
if (rc != MQTTASYNC_SUCCESS)
|
|
|
|
|
|
{
|
|
|
|
|
|
spdlog::error("[mqtt] MQTTAsync_setCallbacks error");
|
2025-09-04 19:31:04 +08:00
|
|
|
|
this->destory();
|
2025-09-01 20:08:40 +08:00
|
|
|
|
return rc;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
option.keepAliveInterval = 20;
|
|
|
|
|
|
option.cleansession = 1;
|
|
|
|
|
|
option.onSuccess = [](void* context, MQTTAsync_successData* resp) { static_cast<MqttClient*>(context)->onConnectSuccess(resp); };;
|
|
|
|
|
|
option.onFailure = [](void* context, MQTTAsync_failureData* resp) { static_cast<MqttClient*>(context)->onConnectFaiure(resp); };
|
|
|
|
|
|
option.context = this;
|
|
|
|
|
|
option.username = username.c_str();
|
|
|
|
|
|
option.password = password.c_str();
|
|
|
|
|
|
|
|
|
|
|
|
//断开重连设置
|
|
|
|
|
|
option.automaticReconnect = 1;//设置非零,断开自动重连
|
|
|
|
|
|
option.minRetryInterval = 5; //单位秒,重连间隔次数,每次重新连接失败时,重试间隔都会加倍,直到最大间隔
|
|
|
|
|
|
option.maxRetryInterval = 60;//单位秒,最大重连尝试间隔
|
|
|
|
|
|
|
|
|
|
|
|
rc = MQTTAsync_connect(client, &option);
|
|
|
|
|
|
if (rc != MQTTASYNC_SUCCESS)
|
|
|
|
|
|
{
|
|
|
|
|
|
spdlog::error("[mqtt] MQTTAsync_connect error");
|
|
|
|
|
|
return rc;
|
|
|
|
|
|
}
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
|
|
|
|
//MQTTAsync_disconnect(client, NULL);
|
|
|
|
|
|
//MQTTAsync_destroy(&client);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-04 19:31:04 +08:00
|
|
|
|
void MqttClient::destory()
|
|
|
|
|
|
{
|
2025-09-05 19:44:26 +08:00
|
|
|
|
return;
|
2025-09-04 19:31:04 +08:00
|
|
|
|
if (client)
|
|
|
|
|
|
{
|
|
|
|
|
|
MQTTAsync_destroy(&client);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-01 20:08:40 +08:00
|
|
|
|
struct SubscribInfo
|
|
|
|
|
|
{
|
|
|
|
|
|
std::function<void(int id)> callback;
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2025-09-04 19:31:04 +08:00
|
|
|
|
void MqttClient::subscribe()
|
2025-09-01 20:08:40 +08:00
|
|
|
|
{
|
2025-09-04 19:31:04 +08:00
|
|
|
|
MQTTAsync_onSuccess* funcSuccess = [](void* context, MQTTAsync_successData* response)
|
2025-09-01 20:08:40 +08:00
|
|
|
|
{
|
2025-09-04 19:31:04 +08:00
|
|
|
|
spdlog::info("[mqtt] subscribe {} success.", (char*)context);
|
2025-09-01 20:08:40 +08:00
|
|
|
|
};
|
2025-09-04 19:31:04 +08:00
|
|
|
|
MQTTAsync_onFailure* funcFailure = [](void* context, MQTTAsync_failureData* response)
|
2025-09-01 20:08:40 +08:00
|
|
|
|
{
|
2025-09-04 19:31:04 +08:00
|
|
|
|
spdlog::error("[mqtt] subscribe {} failed.", (char*)context);
|
2025-09-01 20:08:40 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
2025-09-04 19:31:04 +08:00
|
|
|
|
MQTTAsync_responseOptions options = MQTTAsync_responseOptions_initializer;
|
|
|
|
|
|
options.onSuccess = funcSuccess;
|
|
|
|
|
|
options.onFailure = funcFailure;
|
2025-09-10 20:10:51 +08:00
|
|
|
|
for (auto& item: mapTopicInfo)
|
2025-09-01 20:08:40 +08:00
|
|
|
|
{
|
2025-09-10 20:10:51 +08:00
|
|
|
|
std::string topic = "up/json/" + clientId + "/" + item.first;
|
|
|
|
|
|
options.context = (void*)&item.first;
|
2025-09-04 19:31:04 +08:00
|
|
|
|
int rc = MQTTAsync_subscribe(client, topic.data(), qos, &options);
|
2025-09-01 20:08:40 +08:00
|
|
|
|
if (rc != MQTTASYNC_SUCCESS)
|
|
|
|
|
|
{
|
2025-09-04 19:31:04 +08:00
|
|
|
|
spdlog::error("[mqtt] subscribe [{},{}] failed, err={}", topic, qos, rc);
|
2025-09-01 20:08:40 +08:00
|
|
|
|
}
|
2025-09-13 17:28:35 +08:00
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
spdlog::info("[mqtt] subscribe [{},{}] ", topic, qos);
|
|
|
|
|
|
}
|
2025-09-01 20:08:40 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-12 18:44:34 +08:00
|
|
|
|
int MqttClient::publish(std::string topic, std::string text)
|
2025-09-01 20:08:40 +08:00
|
|
|
|
{
|
|
|
|
|
|
MQTTAsync_responseOptions options = MQTTAsync_responseOptions_initializer;
|
2025-09-12 18:44:34 +08:00
|
|
|
|
options.onSuccess = [](void* context, MQTTAsync_successData* response) {};
|
|
|
|
|
|
options.onFailure = [](void* context, MQTTAsync_failureData* response) {};
|
2025-09-01 20:08:40 +08:00
|
|
|
|
options.context = this;
|
|
|
|
|
|
|
|
|
|
|
|
MQTTAsync_message msg = MQTTAsync_message_initializer;
|
2025-09-10 20:10:51 +08:00
|
|
|
|
msg.qos = this->qos;
|
2025-09-01 20:08:40 +08:00
|
|
|
|
msg.payload = text.data();
|
|
|
|
|
|
msg.payloadlen = text.size();
|
|
|
|
|
|
msg.retained = 0;
|
|
|
|
|
|
|
2025-09-12 18:44:34 +08:00
|
|
|
|
std::string topicName = "down/json/" + clientId + "/" + topic;
|
|
|
|
|
|
int rc = MQTTAsync_sendMessage(client, topicName.c_str(), &msg, &options);
|
|
|
|
|
|
if (rc == MQTTASYNC_SUCCESS)
|
2025-09-01 20:08:40 +08:00
|
|
|
|
{
|
2025-09-12 18:44:34 +08:00
|
|
|
|
spdlog::info("[mqtt] publish MQTTAsync_sendMessage success, topic={}, text={}", topicName, text);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
spdlog::error("[mqtt] publish MQTTAsync_sendMessage error, topic={}, text={}", topicName, text);
|
|
|
|
|
|
}
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int MqttClient::polling()
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!isConnected)
|
|
|
|
|
|
{
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
njson json;
|
|
|
|
|
|
json["ts"] = Utils::time();
|
|
|
|
|
|
json["no"] = 0; // 设备编号
|
|
|
|
|
|
|
|
|
|
|
|
auto& appdata = Application::data();
|
|
|
|
|
|
auto station = appdata.getStationByCode(clientId);
|
|
|
|
|
|
|
|
|
|
|
|
for (auto& item: mapTopicInfo)
|
|
|
|
|
|
{
|
|
|
|
|
|
auto& topicInfo = item.second;
|
|
|
|
|
|
if (topicInfo.polling)
|
2025-09-10 20:10:51 +08:00
|
|
|
|
{
|
2025-09-12 18:44:34 +08:00
|
|
|
|
if (station)
|
|
|
|
|
|
{
|
|
|
|
|
|
std::vector<std::shared_ptr<Device>> vecDevice;
|
|
|
|
|
|
station->getDeviceByType(topicInfo.deviceType, vecDevice);
|
|
|
|
|
|
for (auto device: vecDevice)
|
|
|
|
|
|
{
|
|
|
|
|
|
json["no"] = Utils::toInt(device->code);
|
|
|
|
|
|
this->publish(topicInfo.name, json.dump());
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-09-10 20:10:51 +08:00
|
|
|
|
}
|
2025-09-01 20:08:40 +08:00
|
|
|
|
}
|
2025-09-10 20:10:51 +08:00
|
|
|
|
return 0;
|
2025-09-01 20:08:40 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void MqttClient::onConnectionLost(char* cause)
|
|
|
|
|
|
{
|
|
|
|
|
|
this->isConnected = false;
|
2025-09-05 19:44:26 +08:00
|
|
|
|
//this->destory();
|
2025-09-01 20:08:40 +08:00
|
|
|
|
spdlog::error("MQTT connection lost, cause={}", cause);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-04 19:31:04 +08:00
|
|
|
|
std::string GetSubStr(std::string c, std::string& str)
|
|
|
|
|
|
{
|
|
|
|
|
|
std::string v;
|
|
|
|
|
|
int pos = str.find_first_of("/");
|
|
|
|
|
|
if (pos != string::npos)
|
|
|
|
|
|
{
|
|
|
|
|
|
v = str.substr(0, pos);
|
2025-09-08 19:34:12 +08:00
|
|
|
|
str = str.substr(pos+1);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
v = str;
|
|
|
|
|
|
str = "";
|
2025-09-04 19:31:04 +08:00
|
|
|
|
}
|
|
|
|
|
|
return v;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-01 20:08:40 +08:00
|
|
|
|
int MqttClient::onMessageArrived(char* topic, int topicLen, MQTTAsync_message* msg)
|
|
|
|
|
|
{
|
2025-09-04 19:31:04 +08:00
|
|
|
|
std::string topicStr = topic;
|
2025-09-01 20:08:40 +08:00
|
|
|
|
int len = msg->payloadlen;
|
2025-09-10 20:10:51 +08:00
|
|
|
|
std::string payload((const char*)msg->payload, len);
|
|
|
|
|
|
|
2025-09-01 20:08:40 +08:00
|
|
|
|
|
2025-09-04 19:31:04 +08:00
|
|
|
|
// <数据方向>/<数据格式>/<厂家ID>/<指合>/<设备标识,上行可选>
|
|
|
|
|
|
std::string direction = GetSubStr("/", topicStr);
|
|
|
|
|
|
std::string datatype = GetSubStr("/", topicStr);
|
2025-09-10 20:10:51 +08:00
|
|
|
|
std::string stationNo = GetSubStr("/", topicStr);
|
2025-09-04 19:31:04 +08:00
|
|
|
|
std::string command = GetSubStr("/", topicStr);
|
|
|
|
|
|
std::string deviceCode = GetSubStr("/", topicStr);
|
|
|
|
|
|
|
2025-09-12 18:44:34 +08:00
|
|
|
|
spdlog::info("[mqtt] <<<<<<<<<< message arrived: topic=[{},{}], len={}, payload={}", topic, msg->qos, len, payload);
|
2025-09-05 19:44:26 +08:00
|
|
|
|
|
2025-09-08 19:34:12 +08:00
|
|
|
|
njson json;
|
|
|
|
|
|
bool ret = JSON::parse(payload, json);
|
|
|
|
|
|
if (!ret)
|
|
|
|
|
|
{
|
|
|
|
|
|
spdlog::error("[mqtt] json parse error.");
|
|
|
|
|
|
return 1;
|
|
|
|
|
|
}
|
2025-09-10 20:10:51 +08:00
|
|
|
|
auto station = Application::data().getStationByCode(stationNo);
|
2025-09-08 19:34:12 +08:00
|
|
|
|
if (!station)
|
|
|
|
|
|
{
|
2025-09-10 20:10:51 +08:00
|
|
|
|
spdlog::error("[mqtt] get station error, clientId={}, stationId={}", clientId, stationNo);
|
2025-09-08 19:34:12 +08:00
|
|
|
|
return 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
auto iter = g_mapRegInfo.find(command);
|
|
|
|
|
|
if (iter == g_mapRegInfo.end())
|
|
|
|
|
|
{
|
2025-09-10 20:10:51 +08:00
|
|
|
|
spdlog::error("[mqtt] get register add info error, clientId={}, stationId={}, command={}", clientId, stationNo, command);
|
2025-09-08 19:34:12 +08:00
|
|
|
|
return 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
std::map<std::string, REGInfo>& mapRegInfo = iter->second;
|
|
|
|
|
|
|
2025-09-12 18:44:34 +08:00
|
|
|
|
|
|
|
|
|
|
auto iterTopic = mapTopicInfo.find(command);
|
|
|
|
|
|
if (iterTopic == mapTopicInfo.end())
|
|
|
|
|
|
{
|
|
|
|
|
|
spdlog::error("[mqtt] get topic info error, clientId={}, stationId={}, command={}", clientId, stationNo, command);
|
|
|
|
|
|
return 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
TopicInfo& topicInfo = iterTopic->second;
|
|
|
|
|
|
|
2025-09-08 19:34:12 +08:00
|
|
|
|
int deviceNo = -1;
|
|
|
|
|
|
JSON::read(json, "no", deviceNo);
|
2025-09-12 18:44:34 +08:00
|
|
|
|
auto device = station->getDeviceByType(topicInfo.deviceType, Utils::toStr(deviceNo));
|
2025-09-08 19:34:12 +08:00
|
|
|
|
if (!device)
|
|
|
|
|
|
{
|
|
|
|
|
|
return 1;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
for (auto& item: json.items())
|
|
|
|
|
|
{
|
|
|
|
|
|
std::string key = item.key();
|
|
|
|
|
|
if (key != "ts" && key != "no")
|
|
|
|
|
|
{
|
|
|
|
|
|
auto data = json.at(key);
|
|
|
|
|
|
if (data.is_array())
|
|
|
|
|
|
{
|
|
|
|
|
|
auto iter = mapRegInfo.find(key);
|
|
|
|
|
|
for (int i = 0; i<data.size(); ++i)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (iter != mapRegInfo.end())
|
|
|
|
|
|
{
|
|
|
|
|
|
auto addr = iter->first;
|
2025-09-13 17:28:35 +08:00
|
|
|
|
auto& val = data[i];
|
|
|
|
|
|
//spdlog::info("[mqtt] read register addr: [{}]={}, {}", addr, val, iter->second.remark);
|
2025-09-10 20:10:51 +08:00
|
|
|
|
device->setParam(addr, val);
|
2025-09-08 19:34:12 +08:00
|
|
|
|
++iter;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (data.is_number())
|
|
|
|
|
|
{
|
2025-09-13 17:28:35 +08:00
|
|
|
|
device->setParam(key, data.get<int>());
|
2025-09-08 19:34:12 +08:00
|
|
|
|
}
|
|
|
|
|
|
else if (data.is_string())
|
|
|
|
|
|
{
|
2025-09-13 17:28:35 +08:00
|
|
|
|
device->setParam(key, Utils::toInt(data.get<std::string>()));
|
2025-09-08 19:34:12 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-09-04 19:31:04 +08:00
|
|
|
|
|
2025-09-01 20:08:40 +08:00
|
|
|
|
// 必须释放消息内存!
|
|
|
|
|
|
MQTTAsync_freeMessage(&msg);
|
|
|
|
|
|
MQTTAsync_free(topic);
|
|
|
|
|
|
return 1; // 1表示消息已经处理
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 交付完成回调(可选)
|
|
|
|
|
|
void MqttClient::onDeliveryComplete(MQTTAsync_token token)
|
|
|
|
|
|
{
|
|
|
|
|
|
//spdlog::info("MQTT delivery complete, token={}", token);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void MqttClient::onConnectSuccess( MQTTAsync_successData* resp)
|
|
|
|
|
|
{
|
2025-09-05 19:44:26 +08:00
|
|
|
|
spdlog::info("[mqtt] connect to {} success, clientId={}.", addr, clientId);
|
2025-09-01 20:08:40 +08:00
|
|
|
|
this->isConnected = true;
|
2025-09-04 19:31:04 +08:00
|
|
|
|
this->subscribe();
|
2025-09-01 20:08:40 +08:00
|
|
|
|
}
|
2025-09-12 18:44:34 +08:00
|
|
|
|
|
2025-09-01 20:08:40 +08:00
|
|
|
|
void MqttClient::onConnectFaiure(MQTTAsync_failureData* resp)
|
|
|
|
|
|
{
|
2025-09-05 19:44:26 +08:00
|
|
|
|
spdlog::error("[mqtt] connect to {} error, clientId={}.", addr, clientId);
|
2025-09-01 20:08:40 +08:00
|
|
|
|
this->isConnected = false;
|
2025-09-04 19:31:04 +08:00
|
|
|
|
this->destory();
|
2025-09-01 20:08:40 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
2025-09-08 19:34:12 +08:00
|
|
|
|
void MqttClient::parseEMS_YX(std::shared_ptr<Station> station, njson& json, std::map<std::string, REGInfo>& mapRegInfo)
|
2025-09-01 20:08:40 +08:00
|
|
|
|
{
|
2025-09-08 19:34:12 +08:00
|
|
|
|
int deviceNo = -1;
|
|
|
|
|
|
JSON::read(json, "no", deviceNo);
|
|
|
|
|
|
auto device = station->getDeviceByType(101, Utils::toStr(deviceNo));
|
|
|
|
|
|
if (!device)
|
|
|
|
|
|
{
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
for (auto& item: json.items())
|
|
|
|
|
|
{
|
|
|
|
|
|
std::string key = item.key();
|
|
|
|
|
|
if (key != "ts" && key != "no")
|
|
|
|
|
|
{
|
|
|
|
|
|
auto data = json.at(key);
|
|
|
|
|
|
if (data.is_array())
|
|
|
|
|
|
{
|
|
|
|
|
|
auto iter = mapRegInfo.find(key);
|
|
|
|
|
|
for (int i = 0; i<data.size(); ++i)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (iter != mapRegInfo.end())
|
|
|
|
|
|
{
|
|
|
|
|
|
auto addr = iter->first;
|
|
|
|
|
|
device->mapParams[addr] = JSON::readStr(data[i], addr);
|
|
|
|
|
|
++iter;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (data.is_number())
|
|
|
|
|
|
{
|
|
|
|
|
|
device->mapParams[key] = Utils::toStr(data.get<int>());
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (data.is_string())
|
|
|
|
|
|
{
|
|
|
|
|
|
device->mapParams[key] = Utils::toStr(data.get<int>());
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
string MQTT::pack(std::string name)
|
|
|
|
|
|
{
|
|
|
|
|
|
njson json;
|
|
|
|
|
|
json["ts"] = Utils::time();
|
|
|
|
|
|
json["no"] = 1;
|
|
|
|
|
|
|
|
|
|
|
|
if (name == "EMS_YC")
|
|
|
|
|
|
{
|
|
|
|
|
|
//A相电压 R uint32 1V 0x107E
|
|
|
|
|
|
//B相电压 R uint32 1V 0x1080
|
|
|
|
|
|
//C相电压 R uint32 1V 0x1082
|
|
|
|
|
|
//A相电流 R int32 1A 0x1084
|
|
|
|
|
|
//B相电流 R int32 1A 0x1086
|
|
|
|
|
|
//C相电流 R int32 1A 0x1088
|
|
|
|
|
|
|
|
|
|
|
|
//储能系统SOC R uint16 0.1 0x107A
|
|
|
|
|
|
//储能系统SOH R uint16 0.1 0x107B
|
|
|
|
|
|
|
|
|
|
|
|
json["addr"] = {"0x107A", "0x107B", "0x107E", "0x1080", "0x1082", "0x1084", "0x1086", "0x1088"};
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (name == "PCS_YC")
|
|
|
|
|
|
{
|
|
|
|
|
|
//总充电量 R uint32 1kWh 0x0003
|
|
|
|
|
|
//总放电量 R uint32 1kWh 0x0005
|
|
|
|
|
|
|
|
|
|
|
|
//A相电压 R int16 1V 0x0010
|
|
|
|
|
|
//B相电压 R int16 1V 0x0011
|
|
|
|
|
|
//C相电压 R int16 1V 0x0012
|
|
|
|
|
|
|
|
|
|
|
|
//A相电流 R int16 1A 0x0019
|
|
|
|
|
|
//B相电流 R int16 1A 0x001A
|
|
|
|
|
|
//C相电流 R int16 1A 0x001B
|
|
|
|
|
|
|
|
|
|
|
|
//三相总有功功率 R int16 1kW 0x0025
|
|
|
|
|
|
//三相总无功功率 R int16 1kVar 0x0026
|
|
|
|
|
|
//三相总视在功率 R int16 1kVA 0x0027
|
|
|
|
|
|
//三相总功率因数 R int16 1 0x0028
|
|
|
|
|
|
|
|
|
|
|
|
//充电功率 R int16 1kW 0x002C
|
|
|
|
|
|
//放电功率 R int16 1kW 0x002D
|
|
|
|
|
|
json["addr"] = {"0x0003", "0x0005", "0x0010", "0x0011", "0x0012", "0x0019", "0x001A", "0x001B", "0x0025", "0x0026", "0x0027", "0x0028", "0x002C", "0x002D"};
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (name == "PCU_YC")
|
|
|
|
|
|
{
|
|
|
|
|
|
//PCS侧线A相电压 R int16 1v 0x0013
|
|
|
|
|
|
//PCS侧线B相电压 R int16 1v 0x0014
|
|
|
|
|
|
//PCS侧线C相电压 R int16 1v 0x0015
|
|
|
|
|
|
|
|
|
|
|
|
//PCS侧功率因数A R int16 1 0x0019
|
|
|
|
|
|
//PCS侧功率因数B R int16 1 0x001A
|
|
|
|
|
|
//PCS侧功率因数C R int16 1 0x001B
|
|
|
|
|
|
|
|
|
|
|
|
//PCS侧相电流A R int16 1A 0x001C
|
|
|
|
|
|
//PCS侧相电流B R int16 1A 0x001D
|
|
|
|
|
|
//PCS侧相电流C R int16 1A 0x001E
|
|
|
|
|
|
|
|
|
|
|
|
//PCS侧三相总有功功率 R int16 1kW 0x0028
|
|
|
|
|
|
//PCS侧三相总无功功率 R int16 1kVar 0x0029
|
|
|
|
|
|
//PCS侧三相总视在功率 R int16 1kVA 0x002A
|
|
|
|
|
|
//PCS侧三相总功率因数 R int16 1 0x002B
|
|
|
|
|
|
|
|
|
|
|
|
json["addr"] = {"0x0013", "0x0014", "0x0015", "0x1080", "0x1082", "0x1084", "0x1086", "0x1088"};
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (name == "BMS_YC")
|
|
|
|
|
|
{
|
|
|
|
|
|
//SOC R uint16 0.1 0x0001
|
|
|
|
|
|
//SOH R uint16 0.1 0x0002
|
|
|
|
|
|
//电压 R uint32 0.1V 0x0003
|
|
|
|
|
|
//电流 R int32 0.1A 0x0005
|
|
|
|
|
|
//可充电量 R uint32 1kWh 0x0007
|
|
|
|
|
|
//可放电量 R uint32 1kWh 0x0009
|
|
|
|
|
|
//可充电状态 R uint16 1:可充电;0:不可充电 0x0047
|
|
|
|
|
|
//可放电状态 R uint16 1:可放电;0:不可放电 0x0048
|
|
|
|
|
|
//运行状态 R uint16 运行状态 0-正常 1-告警 2-保护 0x0049
|
|
|
|
|
|
//充放电状态 R uint16 0-待机 1-充电 2-放电 0x004A
|
|
|
|
|
|
|
|
|
|
|
|
json["addr"] = {"0x0001", "0x0002", "0x0003", "0x0005", "0x0007", "0x0009", "0x0047", "0x0048", "0x0049", "0x004A"};
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (name == "BCU_YC")
|
|
|
|
|
|
{
|
|
|
|
|
|
//电表类型 R uint16 "0:储能站总表 1:逆变前侧电表 2:逆变后侧电表 3:配电柜电表 4:并网口电表" 0x0008
|
|
|
|
|
|
//A相电压 R uint32 1V 0x000B
|
|
|
|
|
|
//B相电压 R uint32 1V 0x000D
|
|
|
|
|
|
//C相电压 R uint32 1V 0x000F
|
|
|
|
|
|
//A相电流 R int32 1A 0x0011
|
|
|
|
|
|
//B相电流 R int32 1A 0x0013
|
|
|
|
|
|
//C相电流 R int32 1A 0x0015
|
|
|
|
|
|
|
|
|
|
|
|
//尖段电价 R uint32 1RMB 0x0027
|
|
|
|
|
|
//峰段电价 R uint32 1RMB 0x0029
|
|
|
|
|
|
//平段电价 R uint32 1RMB 0x002B
|
|
|
|
|
|
//谷段电价 R uint32 1RMB 0x002D
|
|
|
|
|
|
//日充电电量 R uint32 1kWh 0x002F
|
|
|
|
|
|
//日放电电量 R uint32 1kWh 0x0031
|
|
|
|
|
|
//日充电费用 R uint32 1RMB 0x0033
|
|
|
|
|
|
//日放电费用 R uint32 1RMB 0x0035
|
|
|
|
|
|
//日收益 R int32 1RMB 0x0037
|
|
|
|
|
|
|
|
|
|
|
|
//总充电电量 R uint32 1kWh 0x004D
|
|
|
|
|
|
//总放电电量 R uint32 1kWh 0x004F
|
|
|
|
|
|
//总充电费用 R uint32 1RMB 0x0051
|
|
|
|
|
|
//总放电费用 R uint32 1RMB 0x0053
|
|
|
|
|
|
//总收益 R int32 1RMB 0x0055
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (name == "TH_YC")
|
|
|
|
|
|
{
|
|
|
|
|
|
//所属通道号 R uint16 1 0x0001
|
|
|
|
|
|
//所属温湿度号 R uint16 1~10 0x0002
|
|
|
|
|
|
//温度 R int16 0.1℃ 0x0003
|
|
|
|
|
|
//湿度 R int16 0.1℃ 0x0004
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
return json.dump();
|
2025-09-01 20:08:40 +08:00
|
|
|
|
}
|