]> git.basschouten.com Git - qthomecontrol.git/commitdiff
First, extremely rudimentary version of a Qt thermostat interface.
authorBas Schouten <bas@basschouten.com>
Tue, 31 Jan 2023 02:50:02 +0000 (03:50 +0100)
committerBas Schouten <bas@basschouten.com>
Tue, 31 Jan 2023 02:50:02 +0000 (03:50 +0100)
.gitignore [new file with mode: 0644]
.gitmodules [new file with mode: 0644]
CMakeLists.txt [new file with mode: 0644]
main.cpp [new file with mode: 0644]
main.qml [new file with mode: 0644]
mqttinterface.cpp [new file with mode: 0644]
mqttinterface.h [new file with mode: 0644]
paho.mqtt.c [new submodule]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..4a0b530
--- /dev/null
@@ -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 (file)
index 0000000..e0e40ec
--- /dev/null
@@ -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 (file)
index 0000000..ff02d94
--- /dev/null
@@ -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 (file)
index 0000000..e4ddce2
--- /dev/null
+++ b/main.cpp
@@ -0,0 +1,19 @@
+#include <QGuiApplication>
+#include <QQmlApplicationEngine>
+
+
+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 (file)
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 (file)
index 0000000..cb8b81d
--- /dev/null
@@ -0,0 +1,115 @@
+#include "mqttinterface.h"
+
+using namespace std;
+
+void delivered(void* context, MQTTClient_deliveryToken dt)
+{
+  MQTTInterface* thermostat = static_cast<MQTTInterface*>(context);
+  //thermostat->DeliverToken(dt);
+}
+
+int msgarrvd(void* context, char* topicName, int topicLen, MQTTClient_message* message)
+{
+  MQTTInterface* thermostat = static_cast<MQTTInterface*>(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<MQTTInterface*>(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<mutex> lk(mDataMutex);
+        mBedroomTemperature = aTemperature;
+    }
+
+    emit bedroomTemperatureChanged();
+}
+
+void
+MQTTInterface::updateBedroomHumidity(float aHumidity)
+{
+    {
+        unique_lock<mutex> 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 (file)
index 0000000..1b54a9a
--- /dev/null
@@ -0,0 +1,45 @@
+#ifndef MQTTINTERFACE_H
+#define MQTTINTERFACE_H
+
+#include <QObject>
+#include <QtQml/qqmlregistration.h>
+#include <mutex>
+
+#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<std::mutex> lk(mDataMutex);
+        return mBedroomTemperature;
+    }
+    qreal bedroomHumidity() {
+        std::unique_lock<std::mutex> 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 (submodule)
index 0000000..f7799da
--- /dev/null
@@ -0,0 +1 @@
+Subproject commit f7799da95e347bbc930b201b52a1173ebbad45a7