Thermostat pour piloter jusqu'à 4 radiateurs avec fil pilote
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

190 lines
4.3 KiB

// SPDX-License-Identifier: GPL-3.0-or-later
/*
* Qt mutizone MQTT thermostat
*
* Copyright (C) 2019 Richard Genoud
*
*/
#include <QLoggingCategory>
#include <QtMqtt/QtMqtt>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonValue>
#include "mqttclient.h"
#include "settings.h"
#define TIMER_PERIOD_MS 30000
MQTTClient::MQTTClient(const QString& host, int port, QObject* parent)
: QMqttClient(parent)
{
this->setHostname(host);
this->setPort(port);
connect(this, SIGNAL(connected(void)), this, SLOT(onConnected(void)));
connect(this, SIGNAL(disconnected(void)), this, SLOT(onDisconnected(void)));
connect(this, SIGNAL(messageReceived(const QByteArray &, const QMqttTopicName &)),
this, SLOT(onReceived(const QByteArray &, const QMqttTopicName &)));
connect(this, SIGNAL(messageSent(qint32)), this, SLOT(onPublished(qint32)));
connect(this, SIGNAL(errorChanged(ClientError)),
this, SLOT(onError(ClientError)));
connect(this, SIGNAL(stateChanged(ClientState)),
this, SLOT(onStateChanged(ClientState)));
connect(&m_timer, SIGNAL(timeout()), this, SLOT(onConnectTimeout()));
m_timer.start(TIMER_PERIOD_MS);
}
MQTTClient::~MQTTClient() {
}
/*
* the QMqttClient doesn't handle auto-reconnection.
* It can stay in the connecting state for ever, even
* if the server is back on.
*/
void MQTTClient::onConnectTimeout(void)
{
switch (state()) {
case Connecting:
qDebug() << "force to disconnect";
disconnectFromHost();
/* fall through */
case Disconnected:
qDebug() << "re-try do connect";
connectToHost();
break;
case Connected:
break;
}
}
void MQTTClient::onStateChanged(ClientState state)
{
qDebug() << "mqtt state: ";
switch (state) {
case Disconnected:
qDebug() << "disconnected";
break;
case Connecting:
qDebug() << "Connecting";
break;
case Connected:
qDebug() << "Connected";
break;
}
}
void MQTTClient::onError(ClientError error)
{
qDebug() << "mqtt error " << error;
/* TODO */
switch (error) {
case NoError: break;
case InvalidProtocolVersion: break;
case IdRejected: break;
case ServerUnavailable: break;
case BadUsernameOrPassword: break;
case NotAuthorized: break;
case TransportInvalid: break;
case ProtocolViolation: break;
case UnknownError: break;
default: break;
}
}
void MQTTClient::onConnected()
{
qDebug() << "subscribe";
this->subscribe(QString("sensors/#"), 1);
}
void MQTTClient::onReceived(const QByteArray &message, const QMqttTopicName &topic)
{
Settings *s = Settings::getInstance();
QJsonDocument sensorData;
QJsonValue val;
qDebug() << "publish received: \"" << QString::fromUtf8(message)
<< "\"" << " from: " << topic.name();
for (int i = 0; i < s->nbZones(); ++i) {
if (s->getRoom(i).sensor_topic == topic.name()) {
qDebug() << "this is for us !";
sensorData = QJsonDocument::fromJson(message);
if (!sensorData.isObject()) {
qWarning() << "malformed JSON data";
goto out;
}
QJsonObject obj(sensorData.object());
val = obj["temperature"];
if (val.isDouble()) {
emit new_temperature(i, val.toDouble());
qDebug() << val.toDouble();
}
val = obj["humidity"];
if (val.isDouble()) {
emit new_hygro(i, val.toDouble());
qDebug() << val.toDouble();
}
val = obj["battery"];
if (val.isDouble()) {
emit new_battery(i, val.toDouble());
qDebug() << val.toDouble();
}
break;
}
if (s->getRoom(i).availability_topic == topic.name()) {
emit new_availability(i, message == QString("online").toUtf8());
}
}
out:
return;
}
void MQTTClient::onPublished(qint32 msgid)
{
qDebug() << "published id " << msgid;
}
void MQTTClient::onDisconnected(void)
{
/* TODO */
qDebug() << "disconnected";
}
void MQTTClient::publish_msg(const QString& topic, const QString& payload)
{
qint32 msgid;
msgid = this->publish(QMqttTopicName(topic), payload.toUtf8(), 1, true);
if (msgid == -1) {
qDebug() << "fail to publish message " << payload << " on " << topic;
}
}
void MQTTClient::allHeatersOn(bool on) {
Settings *s = Settings::getInstance();
QString payload = on ? QString("1") : QString("0");
for (int i = 0; i < s->nbZones(); i++) {
const struct Room r = s->getRoom(i);
for (int j = 0; j < r.heaters.count(); j++) {
const struct Heater *h = &(r.heaters.at(j));
publish_msg(h->ctrl_topic, payload);
}
}
}
/* vim: set tabstop=8 shiftwidth=8 softtabstop=0 noexpandtab: */