From: Bas Schouten Date: Tue, 31 Jan 2023 02:50:02 +0000 (+0100) Subject: First, extremely rudimentary version of a Qt thermostat interface. X-Git-Url: https://git.basschouten.com/?a=commitdiff_plain;h=052c1059a163ea32a37f59a6bb86aed109591d13;p=qthomecontrol.git First, extremely rudimentary version of a Qt thermostat interface. --- 052c1059a163ea32a37f59a6bb86aed109591d13 diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4a0b530 --- /dev/null +++ b/.gitignore @@ -0,0 +1,74 @@ +# This file is used to ignore files which are generated +# ---------------------------------------------------------------------------- + +*~ +*.autosave +*.a +*.core +*.moc +*.o +*.obj +*.orig +*.rej +*.so +*.so.* +*_pch.h.cpp +*_resource.rc +*.qm +.#* +*.*# +core +!core/ +tags +.DS_Store +.directory +*.debug +Makefile* +*.prl +*.app +moc_*.cpp +ui_*.h +qrc_*.cpp +Thumbs.db +*.res +*.rc +/.qmake.cache +/.qmake.stash + +# qtcreator generated files +*.pro.user* +CMakeLists.txt.user* + +# xemacs temporary files +*.flc + +# Vim temporary files +.*.swp + +# Visual Studio generated files +*.ib_pdb_index +*.idb +*.ilk +*.pdb +*.sln +*.suo +*.vcproj +*vcproj.*.*.user +*.ncb +*.sdf +*.opensdf +*.vcxproj +*vcxproj.* + +# MinGW generated files +*.Debug +*.Release + +# Python byte code +*.pyc + +# Binaries +# -------- +*.dll +*.exe + diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..e0e40ec --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "paho.mqtt.c"] + path = paho.mqtt.c + url = https://github.com/eclipse/paho.mqtt.c diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..ff02d94 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,50 @@ +cmake_minimum_required(VERSION 3.16) + +project(qthomecontrol VERSION 0.1 LANGUAGES CXX) + +set(CMAKE_AUTOMOC ON) +set(CMAKE_CXX_STANDARD_REQUIRED ON) + +find_package(Qt6 6.2 COMPONENTS Quick REQUIRED) + +if (UNIX) + add_subdirectory ("paho.mqtt.c") +endif(UNIX) + +qt_add_executable(appqthomecontrol + main.cpp + mqttinterface.cpp + mqttinterface.h +) + +qt_add_qml_module(appqthomecontrol + URI qthomecontrol + VERSION 1.0 + QML_FILES main.qml + SOURCES + mqttinterface.h mqttinterface.cpp +) + +set_target_properties(appqthomecontrol PROPERTIES + MACOSX_BUNDLE_GUI_IDENTIFIER my.example.com + MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION} + MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR} + MACOSX_BUNDLE TRUE + WIN32_EXECUTABLE TRUE +) + +target_include_directories (appqthomecontrol PRIVATE paho.mqtt.c/src) + +target_link_libraries(appqthomecontrol + PRIVATE Qt6::Quick) + +if (WIN32) + target_link_libraries (appqthomecontrol PRIVATE ${CMAKE_SOURCE_DIR}/paho.mqtt.c/src/Release/paho-mqtt3a.lib ${CMAKE_SOURCE_DIR}/paho.mqtt.c/src/Release/paho-mqtt3c.lib) +endif (WIN32) +if (UNIX) + target_link_libraries (appqthomecontrol PRIVATE paho-mqtt3a paho-mqtt3c) +endif(UNIX) + +install(TARGETS appqthomecontrol + BUNDLE DESTINATION . + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}) diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..e4ddce2 --- /dev/null +++ b/main.cpp @@ -0,0 +1,19 @@ +#include +#include + + +int main(int argc, char *argv[]) +{ + QGuiApplication app(argc, argv); + + QQmlApplicationEngine engine; + const QUrl url(u"qrc:/qthomecontrol/main.qml"_qs); + QObject::connect(&engine, &QQmlApplicationEngine::objectCreated, + &app, [url](QObject *obj, const QUrl &objUrl) { + if (!obj && url == objUrl) + QCoreApplication::exit(-1); + }, Qt::QueuedConnection); + engine.load(url); + + return app.exec(); +} diff --git a/main.qml b/main.qml new file mode 100644 index 0000000..b5b938d --- /dev/null +++ b/main.qml @@ -0,0 +1,56 @@ +import QtQuick +import QtQuick.Controls 6.3 +import QtQuick.Layouts 6.3 +import qthomecontrol + +Window { + width: 720 + height: 720 + visible: true + color: "#000000" + title: qsTr("Hello World") + + MQTTInterface { + id: mqttinterface + } + + Slider { + id: slider + x: 13 + y: 534 + width: 695 + height: 178 + live: true + antialiasing: false + topPadding: 0 + orientation: Qt.Horizontal + snapMode: RangeSlider.SnapOnRelease + stepSize: 1 + to: 100 + value: 0 + } + + Text { + id: text1 + x: 206 + y: 114 + width: 309 + height: 129 + color: "#ffffff" + text: mqttinterface.bedroomTemperature.toFixed(1) + " °C" + font.pixelSize: 92 + horizontalAlignment: Text.AlignHCenter + } + + Text { + id: text2 + x: 206 + y: 285 + width: 309 + height: 129 + color: "#ffffff" + text: mqttinterface.bedroomHumidity.toFixed(0) + " %" + font.pixelSize: 92 + horizontalAlignment: Text.AlignHCenter + } +} diff --git a/mqttinterface.cpp b/mqttinterface.cpp new file mode 100644 index 0000000..cb8b81d --- /dev/null +++ b/mqttinterface.cpp @@ -0,0 +1,115 @@ +#include "mqttinterface.h" + +using namespace std; + +void delivered(void* context, MQTTClient_deliveryToken dt) +{ + MQTTInterface* thermostat = static_cast(context); + //thermostat->DeliverToken(dt); +} + +int msgarrvd(void* context, char* topicName, int topicLen, MQTTClient_message* message) +{ + MQTTInterface* thermostat = static_cast(context); + + if (string(topicName) == "bedroom/thermostat/temperature/raw") { + float temperature = stof(string((char*)message->payload)); + thermostat->updateBedroomTemperature(temperature); + } else if (string(topicName) == "bedroom/thermostat/humidity/raw") { + float humidity = stof(string((char*)message->payload)); + thermostat->updateBedroomHumidity(humidity); + } + + MQTTClient_freeMessage(&message); + MQTTClient_free(topicName); + + + return 1; +} + +void connlost(void* context, char* cause) +{ + MQTTInterface* thermostat = static_cast(context); + + printf("\nConnection lost\n"); + printf(" cause: %s\n", cause); + + //thermostat->ShouldReconnect(); +} + +#define QOS 1 + +MQTTInterface::MQTTInterface(QObject *parent) + : QObject{parent} +{ + MQTTClient_message pubmsg = MQTTClient_message_initializer; + MQTTClient_deliveryToken token; + + int rc; + MQTTClient_create(&mClient, "tcp://10.0.1.213:1883", "bedroom-thermostat-fe", + MQTTCLIENT_PERSISTENCE_NONE, NULL); + + if ((rc = MQTTClient_setCallbacks(mClient, this, connlost, msgarrvd, delivered)) != MQTTCLIENT_SUCCESS) + { + printf("Failed to set callbacks, return code %d\n", rc); + return; + } + + connectToServer(); + + char cbuf[256]; + sprintf(cbuf, "%.1f", 15.3); + pubmsg.payload = (void*)cbuf; + pubmsg.payloadlen = strlen(cbuf); + pubmsg.qos = QOS; + pubmsg.retained = 0; + MQTTClient_publishMessage(mClient, "newtest/test", &pubmsg, &token); +} + +void +MQTTInterface::updateBedroomTemperature(float aTemperature) +{ + { + unique_lock lk(mDataMutex); + mBedroomTemperature = aTemperature; + } + + emit bedroomTemperatureChanged(); +} + +void +MQTTInterface::updateBedroomHumidity(float aHumidity) +{ + { + unique_lock lk(mDataMutex); + mBedroomHumidity = aHumidity; + } + + emit bedroomHumidityChanged(); +} + +void +MQTTInterface::connectToServer() +{ + int rc = 0; + MQTTClient_disconnect(mClient, 10000); + + MQTTClient_connectOptions conn_opts = MQTTClient_connectOptions_initializer; + conn_opts.keepAliveInterval = 20; + conn_opts.cleansession = 1; + + if ((rc = MQTTClient_connect(mClient, &conn_opts)) != MQTTCLIENT_SUCCESS) + { + printf("Failed to connect, return code %d\n", rc); + return; + } + + if ((rc = MQTTClient_subscribe(mClient, "bedroom/thermostat/temperature/raw", QOS)) != MQTTCLIENT_SUCCESS) + { + printf("Failed to subscribe, return code %d\n", rc); + } + if ((rc = MQTTClient_subscribe(mClient, "bedroom/thermostat/humidity/raw", QOS)) != MQTTCLIENT_SUCCESS) + { + printf("Failed to subscribe, return code %d\n", rc); + } +} diff --git a/mqttinterface.h b/mqttinterface.h new file mode 100644 index 0000000..1b54a9a --- /dev/null +++ b/mqttinterface.h @@ -0,0 +1,45 @@ +#ifndef MQTTINTERFACE_H +#define MQTTINTERFACE_H + +#include +#include +#include + +#include "MQTTClient.h" + +class MQTTInterface : public QObject +{ + Q_OBJECT + Q_PROPERTY(qreal bedroomTemperature READ bedroomTemperature NOTIFY bedroomTemperatureChanged); + Q_PROPERTY(qreal bedroomHumidity READ bedroomHumidity NOTIFY bedroomHumidityChanged); + QML_ELEMENT + +public: + explicit MQTTInterface(QObject *parent = nullptr); + + qreal bedroomTemperature() { + std::unique_lock lk(mDataMutex); + return mBedroomTemperature; + } + qreal bedroomHumidity() { + std::unique_lock lk(mDataMutex); + return mBedroomHumidity; + } + + void updateBedroomTemperature(float aTemperature); + void updateBedroomHumidity(float aHumidity); + +signals: + void bedroomTemperatureChanged(); + void bedroomHumidityChanged(); + +private: + void connectToServer(); + + qreal mBedroomTemperature = 10; + qreal mBedroomHumidity = 50; + MQTTClient mClient; + std::mutex mDataMutex; +}; + +#endif // MQTTINTERFACE_H diff --git a/paho.mqtt.c b/paho.mqtt.c new file mode 160000 index 0000000..f7799da --- /dev/null +++ b/paho.mqtt.c @@ -0,0 +1 @@ +Subproject commit f7799da95e347bbc930b201b52a1173ebbad45a7