187 lines
4.9 KiB
C++
187 lines
4.9 KiB
C++
#include "mqttsensorsource.h"
|
|
|
|
#include<QJsonArray>
|
|
|
|
MqttSensorSource::MqttSensorSource(QObject *parent)
|
|
: QObject{parent}
|
|
{
|
|
}
|
|
|
|
void MqttSensorSource::start(const QJsonObject& settings)
|
|
{
|
|
baseTopicName = settings["BaseTopic"].toString("zigbee2mqtt");
|
|
|
|
connect(&client, &QMqttClient::stateChanged, this, &MqttSensorSource::onClientStateChanged);
|
|
connect(&client, &QMqttClient::errorChanged, this, &MqttSensorSource::onClientError);
|
|
|
|
client.setHostname(settings["Host"].toString("127.0.0.1"));
|
|
client.setPort(settings["Port"].toInt(1883));
|
|
if(settings.contains("User"))
|
|
client.setUsername(settings["User"].toString());
|
|
if(settings.contains("Password"))
|
|
client.setPassword(settings["Password"].toString());
|
|
client.setProtocolVersion(QMqttClient::MQTT_5_0);
|
|
|
|
client.connectToHost();
|
|
|
|
QJsonArray sensorsArray = settings["Sensors"].toArray();
|
|
|
|
for(QJsonValueRef sensorRef : sensorsArray)
|
|
{
|
|
QJsonObject sensorObject = sensorRef.toObject();
|
|
if(!sensorObject.contains("Topic"))
|
|
continue;
|
|
SensorSubscription sensor;
|
|
sensor.topic = sensorObject["Topic"].toString();
|
|
if(!sensorObject.contains("Name"))
|
|
sensor.name = sensor.topic;
|
|
else
|
|
sensor.name = sensorObject["Name"].toString();
|
|
sensor.id = qHash(baseTopicName + "/" + sensor.topic);
|
|
sensors.push_back(sensor);
|
|
}
|
|
}
|
|
|
|
void MqttSensorSource::onClientError(QMqttClient::ClientError error)
|
|
{
|
|
qWarning()<<"MQTT Client error:"<<error;
|
|
}
|
|
|
|
MqttSensorSource::SensorSubscription& MqttSensorSource::findSubscription(const QString& topic)
|
|
{
|
|
for(SensorSubscription& sensor : sensors)
|
|
{
|
|
if(baseTopicName + "/" + sensor.topic == topic)
|
|
return sensor;
|
|
}
|
|
assert(false);
|
|
}
|
|
|
|
void MqttSensorSource::onClientStateChanged(QMqttClient::ClientState state)
|
|
{
|
|
if(state == QMqttClient::ClientState::Connected)
|
|
{
|
|
qInfo()<<"Connected to MQTT broker at "<<client.hostname()<<client.port();
|
|
for(SensorSubscription& sensor : sensors)
|
|
{
|
|
qDebug()<<"MQTT subscribeing to"<<baseTopicName + "/" + sensor.topic;
|
|
sensor.subscription = client.subscribe(baseTopicName + "/" + sensor.topic);
|
|
connect(sensor.subscription, &QMqttSubscription::messageReceived, this, &MqttSensorSource::onMessageReceived);
|
|
}
|
|
}
|
|
else if (state == QMqttClient::ClientState::Disconnected)
|
|
{
|
|
qWarning()<<"Lost connection to MQTT broker";
|
|
for(SensorSubscription& sensor : sensors)
|
|
{
|
|
if(sensor.subscription)
|
|
{
|
|
client.unsubscribe(sensor.topic);
|
|
sensor.subscription = nullptr;
|
|
}
|
|
}
|
|
}
|
|
else if(state == QMqttClient::ClientState::Connecting)
|
|
{
|
|
qInfo()<<"Connecting to MQTT broker at "<<client.hostname()<<client.port();
|
|
}
|
|
}
|
|
|
|
void MqttSensorSource::onMessageReceived(const QMqttMessage& message)
|
|
{
|
|
Sensor sensor;
|
|
SensorSubscription& sensorSub = findSubscription(message.topic().name());
|
|
QString baseName = sensorSub.name;
|
|
sensor.id = sensorSub.id;
|
|
sensor.updateSeen();
|
|
|
|
QJsonDocument doc = QJsonDocument::fromJson(message.payload());
|
|
if(doc.isObject())
|
|
{
|
|
QJsonObject obj = doc.object();
|
|
if(obj.contains("temperature"))
|
|
{
|
|
sensor.name = baseName + " Temperature";
|
|
sensor.type = Sensor::TYPE_TEMPERATURE;
|
|
sensor.field = obj["temperature"].toDouble(0);
|
|
stateChanged(sensor);
|
|
}
|
|
|
|
if(obj.contains("humidity"))
|
|
{
|
|
sensor.name = baseName + " Humidity";
|
|
sensor.type = Sensor::TYPE_HUMIDITY;
|
|
sensor.field = obj["humidity"].toDouble(0);
|
|
stateChanged(sensor);
|
|
}
|
|
|
|
if(obj.contains("illuminance"))
|
|
{
|
|
sensor.name = baseName + " Illuminance";
|
|
sensor.type = Sensor::TYPE_BRIGHTNESS;
|
|
sensor.field = obj["illuminance"].toDouble(0);
|
|
stateChanged(sensor);
|
|
}
|
|
|
|
if(obj.contains("presence"))
|
|
{
|
|
sensor.name = baseName + " Presence";
|
|
sensor.type = Sensor::TYPE_OCUPANCY;
|
|
sensor.field = obj["presence"].toBool() ? 1 : 0;
|
|
stateChanged(sensor);
|
|
}
|
|
|
|
if(obj.contains("co2"))
|
|
{
|
|
sensor.name = baseName + " co2";
|
|
sensor.type = Sensor::TYPE_CO2;
|
|
sensor.field = obj["co2"].toDouble(0);
|
|
stateChanged(sensor);
|
|
}
|
|
|
|
if(obj.contains("formaldehyd"))
|
|
{
|
|
sensor.name = baseName + " Formaldehyd";
|
|
sensor.type = Sensor::TYPE_FORMALDEHYD;
|
|
sensor.field = obj["formaldehyd"].toDouble(0);
|
|
stateChanged(sensor);
|
|
}
|
|
|
|
if(obj.contains("pm25"))
|
|
{
|
|
sensor.name = baseName + " pm25";
|
|
sensor.type = Sensor::TYPE_PM25;
|
|
sensor.field = obj["pm25"].toDouble(0);
|
|
stateChanged(sensor);
|
|
}
|
|
|
|
if(obj.contains("voc"))
|
|
{
|
|
sensor.name = baseName + " VOC";
|
|
sensor.type = Sensor::TYPE_TOTAL_VOC;
|
|
sensor.field = obj["voc"].toDouble(0);
|
|
stateChanged(sensor);
|
|
}
|
|
}
|
|
}
|
|
|
|
void MqttSensorSource::store(QJsonObject& json)
|
|
{
|
|
json["Host"] = client.hostname();
|
|
json["Port"] = client.port();
|
|
json["BaseTopic"] = baseTopicName;
|
|
if(client.username() != "")
|
|
json["User"] = client.username();
|
|
if(client.password() != "")
|
|
json["Password"] = client.password();
|
|
QJsonArray sensorsArray;
|
|
for(const SensorSubscription& sensor : sensors)
|
|
{
|
|
QJsonObject sensorObject;
|
|
sensorObject["Name"] = sensor.name;
|
|
sensorObject["Topic"] = sensor.topic;
|
|
sensorsArray.append(sensorObject);
|
|
}
|
|
json["Sensors"] = sensorsArray;
|
|
}
|
|
|