Initial backend with MQTT support

This commit is contained in:
2024-02-14 18:16:42 -03:00
parent 9c6410ebe7
commit 510af52e97
9 changed files with 190 additions and 27 deletions

View File

@@ -11,18 +11,20 @@ set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON) set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOUIC ON) set(CMAKE_AUTOUIC ON)
find_package(Qt6 COMPONENTS Widgets Qml QuickControls2 REQUIRED) find_package(Qt6 COMPONENTS Widgets Qml QuickControls2 Mqtt REQUIRED)
add_executable(${PROJECT} add_executable(${PROJECT}
src/main.cpp src/main.cpp
src/FileIO.cpp src/FileIO.cpp
src/Backend.cpp
src/resources.qrc src/resources.qrc
src/Gui/Style/resources.qrc) src/Gui/Style/resources.qrc)
target_link_libraries(${PROJECT} target_link_libraries(${PROJECT}
Qt::Widgets Qt::Widgets
Qt::Qml Qt::Qml
Qt::QuickControls2) Qt::QuickControls2
Qt::Mqtt)
if(CMAKE_BUILD_TYPE STREQUAL "Release") if(CMAKE_BUILD_TYPE STREQUAL "Release")
set_property(TARGET ${PROJECT} PROPERTY WIN32_EXECUTABLE true) set_property(TARGET ${PROJECT} PROPERTY WIN32_EXECUTABLE true)

62
src/Backend.cpp Normal file
View File

@@ -0,0 +1,62 @@
/**
* @file Backend.cpp
* @author Juny <marisa@fwmari.net>
* @brief Implementation of backend module for QML
* @version 0.1
* @date 2024-02-13
*
* @copyright Copyright (c) 2024
*
*/
#include "Backend.hpp"
void Backend::registerTypes(const char *uri) {
qmlRegisterType<Backend>(uri, 0, 1, "Backend");
}
Backend::Backend(QObject *parent) : QObject(parent) {
this->m_client = new QMqttClient(this);
connect(this->m_client, &QMqttClient::hostnameChanged, this,
&Backend::brokerHostChanged);
connect(this->m_client, &QMqttClient::portChanged, this,
&Backend::brokerPortChanged);
connect(this->m_client, &QMqttClient::stateChanged, this,
&Backend::brokerStateChanged);
connect(this->m_client, &QMqttClient::stateChanged, this,
&Backend::onBrokerStateChanged);
}
void Backend::connectToBroker() { this->m_client->connectToHost(); }
void Backend::disconnectFromBroker() { this->m_client->disconnectFromHost(); }
const QString Backend::brokerHost() const { return this->m_client->hostname(); }
void Backend::setBrokerHost(const QString &host) {
this->m_client->setHostname(host);
}
int Backend::brokerPort() const { return this->m_client->port(); }
void Backend::setBrokerPort(int port) {
if (port < 0 || port > std::numeric_limits<quint16>::max()) {
qWarning() << "Invalid port: " << port;
return;
}
this->m_client->setPort(static_cast<quint16>(port));
}
const QMqttClient::ClientState Backend::brokerState() const {
return this->m_client->state();
}
void Backend::setBrokerState(const QMqttClient::ClientState &state) {
this->m_client->setState(state);
}
void Backend::onBrokerStateChanged(const QMqttClient::ClientState &state) {
qWarning() << "State change" << state;
if (state != QMqttClient::Connected)
return;
// TODO: subscribe
}

61
src/Backend.hpp Normal file
View File

@@ -0,0 +1,61 @@
/**
* @file Backend.hpp
* @author Juny <marisa@fwmari.net>
* @brief Backend module for QML
* @version 0.1
* @date 2024-02-13
*
* @copyright Copyright (c) 2024
*
*/
#pragma once
#include <QMqttClient>
#include <QObject>
#include <QtQml>
class Backend : public QObject {
Q_OBJECT
Q_PROPERTY(QString brokerHost READ brokerHost WRITE setBrokerHost NOTIFY
brokerHostChanged)
Q_PROPERTY(int brokerPort READ brokerPort WRITE setBrokerPort NOTIFY
brokerPortChanged)
Q_PROPERTY(QMqttClient::ClientState brokerState READ brokerState WRITE
setBrokerState NOTIFY brokerStateChanged)
QML_NAMED_ELEMENT(Backend)
public:
explicit Backend(QObject *parent = nullptr);
static void registerTypes(const char *uri);
static QObject *singletonProvider(QQmlEngine *engine, QJSEngine *);
// QML functions
Q_INVOKABLE void connectToBroker();
Q_INVOKABLE void disconnectFromBroker();
// QML Properties
const QString brokerHost() const;
void setBrokerHost(const QString &host);
int brokerPort() const;
void setBrokerPort(int port);
const QMqttClient::ClientState brokerState() const;
void setBrokerState(const QMqttClient::ClientState &state);
signals:
void brokerHostChanged();
void brokerPortChanged();
void brokerStateChanged();
private slots:
void onBrokerStateChanged(const QMqttClient::ClientState &state);
private:
Q_DISABLE_COPY(Backend)
QMqttClient *m_client;
};

View File

@@ -4,12 +4,12 @@ import QtQuick
import "Settings" import "Settings"
QtObject { import QSpec.Backend
Backend {
id: app id: app
property string brokerURL: Settings._json.brokerURL || "" property string brokerURL: Settings._json.brokerURL || ""
property string brokerHost
property string brokerPort
property string brokerUsername: Settings._json.brokerUsername || "" property string brokerUsername: Settings._json.brokerUsername || ""
property string brokerPassword: Settings._json.brokerPassword || "" property string brokerPassword: Settings._json.brokerPassword || ""
@@ -19,11 +19,13 @@ QtObject {
brokerPort = brokerURL.split(":")[1] || 1883 brokerPort = brokerURL.split(":")[1] || 1883
} }
function saveBroker(url, user, pass) { function tryConnect(url, user, pass) {
Settings._json.brokerURL = url brokerURL = Settings._json.brokerURL = url
Settings._json.brokerUsername = user brokerUsername = Settings._json.brokerUsername = user
Settings._json.brokerPassword = pass brokerPassword = Settings._json.brokerPassword = pass
Settings.save() Settings.save()
connectToBroker()
} }
function setup() { function setup() {

View File

@@ -11,6 +11,8 @@ ColumnLayout {
signal tryConnect(url: string, username: string, password: string) signal tryConnect(url: string, username: string, password: string)
Component.onCompleted: checkUrl(brokerURL.tfText)
Timer { Timer {
id: focusTimer id: focusTimer
running: true running: true
@@ -40,19 +42,7 @@ ColumnLayout {
tfText: App.brokerURL || "" tfText: App.brokerURL || ""
onTfAccepted: _tryConnect() onTfAccepted: _tryConnect()
onTfChanged: (text) => checkUrl(text)
onTfChanged: (text) => {
let url;
try {
url = new URL(`https://${text}`)
} catch (_) {
btn.enabled = false
return
}
btn.enabled = true
}
} }
} }
@@ -84,7 +74,7 @@ ColumnLayout {
id: btn id: btn
text: qsTr("Connect") text: qsTr("Connect")
Layout.fillWidth: true Layout.fillWidth: true
// enabled: false enabled: false
onClicked: _tryConnect() onClicked: _tryConnect()
} }
@@ -92,4 +82,22 @@ ColumnLayout {
function _tryConnect() { function _tryConnect() {
tryConnect(brokerURL.tfText, brokerUsername.tfText, brokerPassword.tfText) tryConnect(brokerURL.tfText, brokerUsername.tfText, brokerPassword.tfText)
} }
function checkUrl(text) {
let url;
if (text == "") {
btn.enabled = false
return
}
try {
url = new URL(`https://${text}`)
} catch (_) {
btn.enabled = false
return
}
btn.enabled = true
}
} }

View File

@@ -20,7 +20,7 @@ PStackView {
anchors.centerIn: parent anchors.centerIn: parent
onTryConnect: (url, user, pass) => { onTryConnect: (url, user, pass) => {
App.saveBroker(url, user, pass) App.tryConnect(url, user, pass)
login.push(loadInstance) login.push(loadInstance)
} }
} }

View File

@@ -3,7 +3,7 @@ pragma Singleton
import QtQuick import QtQuick
import QtCore import QtCore
import QSpec import QSpec.FileIO
QtObject { QtObject {
property string configDir: StandardPaths.writableLocation(StandardPaths.AppConfigLocation) property string configDir: StandardPaths.writableLocation(StandardPaths.AppConfigLocation)

View File

@@ -16,6 +16,11 @@ Window {
Component.onCompleted: { Component.onCompleted: {
App.setup() App.setup()
loadingTimer.running = true loadingTimer.running = true
App.brokerStateChanged.connect(() => {
if (App.brokerState == 2)
connectTimer.running = true
})
} }
Timer { Timer {
@@ -23,11 +28,21 @@ Window {
running: false running: false
repeat: false repeat: false
interval: 500 interval: 750
onTriggered: loader.source = "qrc:/Login/Login.qml" onTriggered: loader.source = "qrc:/Login/Login.qml"
} }
Timer {
id: connectTimer
running: false
repeat: false
interval: 750
onTriggered: loader.sourceComponent = mainPane
}
Loader { Loader {
id: loader id: loader
anchors.fill: parent anchors.fill: parent
@@ -55,4 +70,15 @@ Window {
} }
} }
} }
Component {
id: mainPane
PBackground {
PText {
anchors.centerIn: parent
text: qsTr("YAAAAY I AM CONNECTED")
}
}
}
} }

View File

@@ -19,6 +19,7 @@
#include <QQuickStyle> #include <QQuickStyle>
#include <QQuickWindow> #include <QQuickWindow>
#include "Backend.hpp"
#include "FileIO.hpp" #include "FileIO.hpp"
int main(int argc, char *argv[]) { int main(int argc, char *argv[]) {
@@ -35,7 +36,8 @@ int main(int argc, char *argv[]) {
QObject::connect(engine, &QQmlEngine::quit, &QApplication::quit); QObject::connect(engine, &QQmlEngine::quit, &QApplication::quit);
FileIO::registerTypes("QSpec"); FileIO::registerTypes("QSpec.FileIO");
Backend::registerTypes("QSpec.Backend");
engine->addImportPath("qrc:/"); engine->addImportPath("qrc:/");