#include "mqttsensorsource.h" #include MqttSensorSource::MqttSensorSource(QObject *parent) : QObject{parent} { } void MqttSensorSource::start(std::shared_ptr client, const QJsonObject& settings) { this->client = client; connect(client->getClient().get(), &QMqttClient::stateChanged, this, &MqttSensorSource::onClientStateChanged); 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(client->getBaseTopic() + "/" + sensor.topic); sensors.push_back(sensor); } } void MqttSensorSource::addSensor(const QString& topic, const QString& name) { if(!client) return; SensorSubscription sensor; sensor.topic = topic; sensor.name = name; sensor.id = qHash(client->getBaseTopic() + "/" + topic); sensors.push_back(sensor); // Subscribe if already connected if(client->getClient()->state() == QMqttClient::ClientState::Connected) { sensor.subscription = client->subscribe(client->getBaseTopic() + "/" + topic); connect(sensor.subscription->subscription, &QMqttSubscription::messageReceived, this, &MqttSensorSource::onMessageReceived); } } MqttSensorSource::SensorSubscription& MqttSensorSource::findSubscription(const QString& topic) { for(SensorSubscription& sensor : sensors) { if(client->getBaseTopic() + "/" + sensor.topic == topic) return sensor; } assert(false); return sensors.front(); } void MqttSensorSource::onClientStateChanged(QMqttClient::ClientState state) { if(state == QMqttClient::ClientState::Connected) { for(SensorSubscription& sensor : sensors) { sensor.subscription = client->subscribe(client->getBaseTopic() + "/" + sensor.topic); connect(sensor.subscription->subscription, &QMqttSubscription::messageReceived, this, &MqttSensorSource::onMessageReceived); } } else if (state == QMqttClient::ClientState::Disconnected) { for(SensorSubscription& sensor : sensors) { if(sensor.subscription) { client->unsubscribe(client->getBaseTopic() + "/" + sensor.topic); sensor.subscription = nullptr; } } } } 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, SENSOR_UPDATE_BACKEND); } if(obj.contains("local_temperature")) { sensor.name = baseName + " Temperature"; sensor.type = Sensor::TYPE_TEMPERATURE; sensor.field = obj["local_temperature"].toDouble(0); stateChanged(sensor, SENSOR_UPDATE_BACKEND); } if(obj.contains("humidity")) { sensor.name = baseName + " Humidity"; sensor.type = Sensor::TYPE_HUMIDITY; sensor.field = obj["humidity"].toDouble(0); stateChanged(sensor, SENSOR_UPDATE_BACKEND); } if(obj.contains("illuminance")) { sensor.name = baseName + " Illuminance"; sensor.type = Sensor::TYPE_BRIGHTNESS; sensor.field = obj["illuminance"].toDouble(0); stateChanged(sensor, SENSOR_UPDATE_BACKEND); } if(obj.contains("presence")) { sensor.name = baseName + " Presence"; sensor.type = Sensor::TYPE_OCUPANCY; sensor.field = obj["presence"].toBool() ? 1 : 0; stateChanged(sensor, SENSOR_UPDATE_BACKEND); } if(obj.contains("co2")) { sensor.name = baseName + " co2"; sensor.type = Sensor::TYPE_CO2; sensor.field = obj["co2"].toDouble(0); stateChanged(sensor, SENSOR_UPDATE_BACKEND); } if(obj.contains("formaldehyd")) { sensor.name = baseName + " Formaldehyd"; sensor.type = Sensor::TYPE_FORMALDEHYD; sensor.field = obj["formaldehyd"].toDouble(0); stateChanged(sensor, SENSOR_UPDATE_BACKEND); } if(obj.contains("pm25")) { sensor.name = baseName + " pm25"; sensor.type = Sensor::TYPE_PM25; sensor.field = obj["pm25"].toDouble(0); stateChanged(sensor, SENSOR_UPDATE_BACKEND); } if(obj.contains("voc")) { sensor.name = baseName + " VOC"; sensor.type = Sensor::TYPE_TOTAL_VOC; sensor.field = obj["voc"].toDouble(0); stateChanged(sensor, SENSOR_UPDATE_BACKEND); } if(obj.contains("power")) { sensor.name = baseName + " Power"; sensor.type = Sensor::TYPE_POWER; sensor.field = obj["power"].toDouble(0); stateChanged(sensor, SENSOR_UPDATE_BACKEND); } if(obj.contains("energy")) { sensor.name = baseName + " Energy"; sensor.type = Sensor::TYPE_ENERGY_USE; sensor.field = obj["energy"].toDouble(0); stateChanged(sensor, SENSOR_UPDATE_BACKEND); } if(obj.contains("voltage")) { sensor.name = baseName + " Voltage"; sensor.type = Sensor::TYPE_VOLTAGE; sensor.field = obj["voltage"].toDouble(0); stateChanged(sensor, SENSOR_UPDATE_BACKEND); } } } void MqttSensorSource::store(QJsonObject& json) { QJsonArray sensorsArray; for(const SensorSubscription& sensor : sensors) { QJsonObject sensorObject; sensorObject["Name"] = sensor.name; sensorObject["Topic"] = sensor.topic; sensorsArray.append(sensorObject); } json["Sensors"] = sensorsArray; } MqttSensorSource::~MqttSensorSource() { for(SensorSubscription& sub : sensors) client->unsubscribe(client->getBaseTopic() + "/" + sub.topic); } void MqttSensorSource::onSensorAdded(Sensor sensor, Sensor::sensor_backend_type_t backend, QJsonObject payload) { if(backend != Sensor::BACKEND_MQTT) return; QString topic = payload["Topic"].toString(); QString name = payload["Name"].toString(); if(topic.isEmpty()) return; addSensor(topic, name); }