mirror of
https://github.com/Serial-Studio/Serial-Studio.git
synced 2025-01-15 05:22:53 +08:00
Let Serial Studio act as a MQTT publisher (WIP)
This commit is contained in:
parent
44b734641f
commit
a8fb35cc49
@ -121,12 +121,8 @@ RESOURCES += \
|
||||
assets/assets.qrc
|
||||
|
||||
DISTFILES += \
|
||||
assets/qml/PlatformDependent/DecentMenuItem.qml \
|
||||
assets/qml/PlatformDependent/Menubar.qml \
|
||||
assets/qml/PlatformDependent/MenubarMacOS.qml \
|
||||
assets/qml/SetupPanes/Network.qml \
|
||||
assets/qml/SetupPanes/Serial.qml \
|
||||
assets/qml/SetupPanes/Settings.qml \
|
||||
assets/qml/PlatformDependent/*.qml \
|
||||
assets/qml/SetupPanes/*.qml \
|
||||
assets/qml/Widgets/*.qml \
|
||||
assets/qml/Windows/*.qml \
|
||||
assets/qml/SetupPanes/*.qml \
|
||||
@ -151,6 +147,7 @@ HEADERS += \
|
||||
src/JSON/FrameInfo.h \
|
||||
src/JSON/Generator.h \
|
||||
src/JSON/Group.h \
|
||||
src/MQTT/Publisher.h \
|
||||
src/Misc/ModuleManager.h \
|
||||
src/Misc/TimerEvents.h \
|
||||
src/Misc/Translator.h \
|
||||
@ -172,6 +169,7 @@ SOURCES += \
|
||||
src/JSON/FrameInfo.cpp \
|
||||
src/JSON/Generator.cpp \
|
||||
src/JSON/Group.cpp \
|
||||
src/MQTT/Publisher.cpp \
|
||||
src/Misc/ModuleManager.cpp \
|
||||
src/Misc/TimerEvents.cpp \
|
||||
src/Misc/Translator.cpp \
|
||||
|
@ -66,7 +66,7 @@
|
||||
<file>qml/Widgets/MapDelegate.qml</file>
|
||||
<file>qml/Widgets/Window.qml</file>
|
||||
<file>qml/Windows/About.qml</file>
|
||||
<file>qml/Windows/Acknowledgements.qml</file>
|
||||
<file>qml/Windows/Acknowledgements.qml</file>
|
||||
<file>qml/Windows/Console.qml</file>
|
||||
<file>qml/Windows/CsvPlayer.qml</file>
|
||||
<file>qml/Windows/DataGrid.qml</file>
|
||||
@ -94,5 +94,6 @@
|
||||
<file>qml/PlatformDependent/MenubarMacOS.qml</file>
|
||||
<file>qml/PlatformDependent/Menubar.qml</file>
|
||||
<file>qml/PlatformDependent/DecentMenuItem.qml</file>
|
||||
<file>qml/SetupPanes/MQTTPublisher.qml</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
269
assets/qml/SetupPanes/MQTTPublisher.qml
Normal file
269
assets/qml/SetupPanes/MQTTPublisher.qml
Normal file
@ -0,0 +1,269 @@
|
||||
/*
|
||||
* Copyright (c) 2020-2021 Alex Spataru <https://github.com/alex-spataru>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
import QtQuick 2.12
|
||||
import QtQuick.Layouts 1.12
|
||||
import QtQuick.Controls 2.12
|
||||
|
||||
Control {
|
||||
id: root
|
||||
implicitHeight: layout.implicitHeight + app.spacing * 2
|
||||
|
||||
//
|
||||
// Aliases
|
||||
//
|
||||
property alias host: _host.text
|
||||
property alias port: _port.text
|
||||
property alias topic: _topic.text
|
||||
property alias user: _user.text
|
||||
property alias password: _password.text
|
||||
property alias dnsAddress: _addrLookup.text
|
||||
|
||||
//
|
||||
// Layout
|
||||
//
|
||||
ColumnLayout {
|
||||
id: layout
|
||||
anchors.fill: parent
|
||||
anchors.margins: app.spacing
|
||||
|
||||
GridLayout {
|
||||
columns: 2
|
||||
Layout.fillWidth: true
|
||||
rowSpacing: app.spacing
|
||||
columnSpacing: app.spacing
|
||||
|
||||
//
|
||||
// MQTT version
|
||||
//
|
||||
Label {
|
||||
text: qsTr("Version") + ":"
|
||||
} ComboBox {
|
||||
Layout.fillWidth: true
|
||||
model: Cpp_MQTT_Publisher.mqttVersions
|
||||
currentIndex: Cpp_MQTT_Publisher.mqttVersion
|
||||
onCurrentIndexChanged: {
|
||||
if (Cpp_MQTT_Publisher.mqttVersion !== currentIndex)
|
||||
Cpp_MQTT_Publisher.mqttVersion = currentIndex
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Host
|
||||
//
|
||||
Label {
|
||||
opacity: enabled ? 1 : 0.5
|
||||
enabled: !Cpp_MQTT_Publisher.isConnectedToHost
|
||||
Behavior on opacity {NumberAnimation{}}
|
||||
text: qsTr("Host") + ":"
|
||||
} TextField {
|
||||
id: _host
|
||||
Layout.fillWidth: true
|
||||
text: Cpp_MQTT_Publisher.host
|
||||
placeholderText: Cpp_MQTT_Publisher.defaultHost
|
||||
onTextChanged: {
|
||||
if (Cpp_MQTT_Publisher.host !== text)
|
||||
Cpp_MQTT_Publisher.host = text
|
||||
}
|
||||
|
||||
opacity: enabled ? 1 : 0.5
|
||||
enabled: !Cpp_MQTT_Publisher.isConnectedToHost
|
||||
Behavior on opacity {NumberAnimation{}}
|
||||
}
|
||||
|
||||
//
|
||||
// Port
|
||||
//
|
||||
Label {
|
||||
opacity: enabled ? 1 : 0.5
|
||||
enabled: !Cpp_MQTT_Publisher.isConnectedToHost
|
||||
Behavior on opacity {NumberAnimation{}}
|
||||
text: qsTr("Port") + ":"
|
||||
} TextField {
|
||||
id: _port
|
||||
Layout.fillWidth: true
|
||||
text: Cpp_MQTT_Publisher.port
|
||||
placeholderText: Cpp_MQTT_Publisher.defaultPort
|
||||
onTextChanged: {
|
||||
if (Cpp_MQTT_Publisher.port !== text)
|
||||
Cpp_MQTT_Publisher.port = text
|
||||
}
|
||||
|
||||
validator: IntValidator {
|
||||
bottom: 0
|
||||
top: 65535
|
||||
}
|
||||
|
||||
opacity: enabled ? 1 : 0.5
|
||||
enabled: !Cpp_MQTT_Publisher.isConnectedToHost
|
||||
Behavior on opacity {NumberAnimation{}}
|
||||
}
|
||||
|
||||
//
|
||||
// Topic
|
||||
//
|
||||
Label {
|
||||
opacity: enabled ? 1 : 0.5
|
||||
enabled: !Cpp_MQTT_Publisher.isConnectedToHost
|
||||
Behavior on opacity {NumberAnimation{}}
|
||||
text: qsTr("Topic") + ":"
|
||||
} TextField {
|
||||
id: _topic
|
||||
Layout.fillWidth: true
|
||||
text: Cpp_MQTT_Publisher.topic
|
||||
placeholderText: qsTr("MQTT topic")
|
||||
onTextChanged: {
|
||||
if (Cpp_MQTT_Publisher.topic !== text)
|
||||
Cpp_MQTT_Publisher.topic = text
|
||||
}
|
||||
|
||||
opacity: enabled ? 1 : 0.5
|
||||
enabled: !Cpp_MQTT_Publisher.isConnectedToHost
|
||||
Behavior on opacity {NumberAnimation{}}
|
||||
}
|
||||
|
||||
//
|
||||
// Username
|
||||
//
|
||||
Label {
|
||||
opacity: enabled ? 1 : 0.5
|
||||
enabled: !Cpp_MQTT_Publisher.isConnectedToHost
|
||||
Behavior on opacity {NumberAnimation{}}
|
||||
text: qsTr("User") + ":"
|
||||
} TextField {
|
||||
id: _user
|
||||
Layout.fillWidth: true
|
||||
text: Cpp_MQTT_Publisher.username
|
||||
placeholderText: qsTr("MQTT username")
|
||||
onTextChanged: {
|
||||
if (Cpp_MQTT_Publisher.username !== text)
|
||||
Cpp_MQTT_Publisher.username = text
|
||||
}
|
||||
|
||||
opacity: enabled ? 1 : 0.5
|
||||
enabled: !Cpp_MQTT_Publisher.isConnectedToHost
|
||||
Behavior on opacity {NumberAnimation{}}
|
||||
}
|
||||
|
||||
//
|
||||
// Password
|
||||
//
|
||||
Label {
|
||||
opacity: enabled ? 1 : 0.5
|
||||
enabled: !Cpp_MQTT_Publisher.isConnectedToHost
|
||||
Behavior on opacity {NumberAnimation{}}
|
||||
text: qsTr("Password") + ":"
|
||||
} TextField {
|
||||
id: _password
|
||||
Layout.fillWidth: true
|
||||
text: Cpp_MQTT_Publisher.password
|
||||
placeholderText: qsTr("MQTT password")
|
||||
onTextChanged: {
|
||||
if (Cpp_MQTT_Publisher.password !== text)
|
||||
Cpp_MQTT_Publisher.password = text
|
||||
}
|
||||
|
||||
opacity: enabled ? 1 : 0.5
|
||||
enabled: !Cpp_MQTT_Publisher.isConnectedToHost
|
||||
Behavior on opacity {NumberAnimation{}}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Spacer
|
||||
//
|
||||
Item {
|
||||
Layout.fillHeight: true
|
||||
Layout.minimumHeight: app.spacing
|
||||
}
|
||||
|
||||
//
|
||||
// Address lookup
|
||||
//
|
||||
Label {
|
||||
text: qsTr("DNS lookup") + ": "
|
||||
opacity: enabled ? 1 : 0.5
|
||||
enabled: !Cpp_MQTT_Publisher.isConnectedToHost
|
||||
Behavior on opacity {NumberAnimation{}}
|
||||
} RowLayout {
|
||||
Layout.fillWidth: true
|
||||
spacing: app.spacing / 2
|
||||
|
||||
TextField {
|
||||
id: _addrLookup
|
||||
Layout.fillWidth: true
|
||||
opacity: enabled ? 1 : 0.5
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
onAccepted: Cpp_MQTT_Publisher.lookup(text)
|
||||
placeholderText: qsTr("Enter address (e.g. google.com)")
|
||||
enabled: !Cpp_MQTT_Publisher.isConnectedToHost &&
|
||||
!Cpp_MQTT_Publisher.lookupActive
|
||||
|
||||
Behavior on opacity {NumberAnimation{}}
|
||||
}
|
||||
|
||||
Button {
|
||||
icon.color: palette.text
|
||||
opacity: enabled ? 1 : 0.5
|
||||
Layout.maximumWidth: height
|
||||
Layout.alignment: Qt.AlignVCenter
|
||||
icon.source: "qrc:/icons/search.svg"
|
||||
onClicked: Cpp_MQTT_Publisher.lookup(_addrLookup.text)
|
||||
enabled: _addrLookup.text.length > 0 &&
|
||||
!Cpp_MQTT_Publisher.isConnectedToHost &&
|
||||
!Cpp_MQTT_Publisher.lookupActive
|
||||
|
||||
Behavior on opacity {NumberAnimation{}}
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Spacer
|
||||
//
|
||||
Item {
|
||||
Layout.fillHeight: true
|
||||
}
|
||||
|
||||
//
|
||||
// Connect/disconnect button
|
||||
//
|
||||
Button {
|
||||
icon.width: 24
|
||||
icon.height: 24
|
||||
font.bold: true
|
||||
Layout.fillWidth: true
|
||||
icon.color: palette.buttonText
|
||||
checked: Cpp_MQTT_Publisher.isConnectedToHost
|
||||
onClicked: Cpp_MQTT_Publisher.toggleConnection()
|
||||
palette.buttonText: checked ? "#d72d60" : "#2eed5c"
|
||||
text: (checked ? qsTr("Disconnect") : qsTr("Connect")) + " "
|
||||
icon.source: checked ? "qrc:/icons/disconnect.svg" : "qrc:/icons/connect.svg"
|
||||
}
|
||||
|
||||
//
|
||||
// Spacer
|
||||
//
|
||||
Item {
|
||||
Layout.fillHeight: true
|
||||
}
|
||||
}
|
||||
}
|
@ -65,6 +65,16 @@ Control {
|
||||
property alias socketType: network.socketType
|
||||
property alias addressLookup: network.addressLookup
|
||||
|
||||
//
|
||||
// MQTT settings
|
||||
//
|
||||
property alias mqttHost: mqttPublisher.host
|
||||
property alias mqttPort: mqttPublisher.port
|
||||
property alias mqttUser: mqttPublisher.user
|
||||
property alias mqttTopic: mqttPublisher.topic
|
||||
property alias mqttPassword: mqttPublisher.password
|
||||
property alias mqttDnsAddress: mqttPublisher.dnsAddress
|
||||
|
||||
//
|
||||
// App settings
|
||||
//
|
||||
@ -204,6 +214,12 @@ Control {
|
||||
width: implicitWidth + 2 * app.spacing
|
||||
}
|
||||
|
||||
TabButton {
|
||||
text: qsTr("MQTT")
|
||||
height: tab.height + 3
|
||||
width: implicitWidth + 2 * app.spacing
|
||||
}
|
||||
|
||||
TabButton {
|
||||
text: qsTr("Settings")
|
||||
height: tab.height + 3
|
||||
@ -238,7 +254,14 @@ Control {
|
||||
stack.implicitHeight = network.implicitHeight
|
||||
break
|
||||
case 2:
|
||||
stack.implicitHeight = mqttPublisher.implicitHeight
|
||||
break
|
||||
case 3:
|
||||
stack.implicitHeight = settings.implicitHeight
|
||||
break
|
||||
default:
|
||||
stack.implicitHeight = 0
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
@ -258,6 +281,14 @@ Control {
|
||||
}
|
||||
}
|
||||
|
||||
SetupPanes.MQTTPublisher {
|
||||
id: mqttPublisher
|
||||
background: TextField {
|
||||
enabled: false
|
||||
palette.base: "#16232a"
|
||||
}
|
||||
}
|
||||
|
||||
SetupPanes.Settings {
|
||||
id: settings
|
||||
background: TextField {
|
||||
|
@ -38,6 +38,48 @@
|
||||
using namespace IO;
|
||||
static Console *INSTANCE = nullptr;
|
||||
|
||||
/**
|
||||
* Generates a hexdump of the given data
|
||||
*/
|
||||
static QString HexDump(const char *data, size_t size)
|
||||
{
|
||||
char str[4096] = "";
|
||||
char ascii[17];
|
||||
|
||||
size_t i, j;
|
||||
ascii[16] = '\0';
|
||||
for (i = 0; i < size; ++i)
|
||||
{
|
||||
sprintf(str + strlen(str), "%02X ", static_cast<quint8>(data[i]));
|
||||
|
||||
if (data[i] >= ' ' && data[i] <= '~')
|
||||
ascii[i % 16] = data[i];
|
||||
else
|
||||
ascii[i % 16] = '.';
|
||||
|
||||
if ((i + 1) % 8 == 0 || i + 1 == size)
|
||||
{
|
||||
sprintf(str + strlen(str), " ");
|
||||
if ((i + 1) % 16 == 0)
|
||||
sprintf(str + strlen(str), "| %s \n", ascii);
|
||||
|
||||
else if (i + 1 == size)
|
||||
{
|
||||
ascii[(i + 1) % 16] = '\0';
|
||||
|
||||
if ((i + 1) % 16 <= 8)
|
||||
sprintf(str + strlen(str), " ");
|
||||
for (j = (i + 1) % 16; j < 16; ++j)
|
||||
sprintf(str + strlen(str), " ");
|
||||
|
||||
sprintf(str + strlen(str), "| %s \n", ascii);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return QString(str);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor function
|
||||
*/
|
||||
@ -610,19 +652,18 @@ QString Console::plainTextStr(const QByteArray &data)
|
||||
*/
|
||||
QString Console::hexadecimalStr(const QByteArray &data)
|
||||
{
|
||||
// Convert to hex string with spaces between bytes
|
||||
// Convert data to string with dump every ~80 chars
|
||||
QString str;
|
||||
QString hex = QString::fromUtf8(data.toHex());
|
||||
for (int i = 0; i < hex.length(); ++i)
|
||||
const int characters = 80;
|
||||
for (int i = 0; i < data.length(); ++i)
|
||||
{
|
||||
str.append(hex.at(i));
|
||||
if ((i + 1) % 2 == 0 && i > 0)
|
||||
str.append(" ");
|
||||
}
|
||||
QByteArray line;
|
||||
for (int j = 0; j < qMin(characters, data.length() - i); ++j)
|
||||
line.append(data.at(i + j));
|
||||
|
||||
// Add new line & carriage returns
|
||||
str.replace("0a", "0a\r");
|
||||
str.replace("0d", "0d\n");
|
||||
str.append(HexDump(line.data(), line.size()));
|
||||
str.append("\n");
|
||||
}
|
||||
|
||||
// Return string
|
||||
return str;
|
||||
|
@ -1,10 +1,23 @@
|
||||
/*
|
||||
* Copyright (C) MATUSICA S.A. de C.V. - All Rights Reserved
|
||||
* Copyright (c) 2020-2021 Alex Spataru <https://github.com/alex-spataru>
|
||||
*
|
||||
* Unauthorized copying of this file, via any medium is strictly prohibited.
|
||||
* Proprietary and confidential.
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* Written by Alex Spataru <https://alex-spataru.com/>, February 2021
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef IO_DATA_SOURCES_NETWORK_H
|
||||
|
230
src/MQTT/Publisher.cpp
Normal file
230
src/MQTT/Publisher.cpp
Normal file
@ -0,0 +1,230 @@
|
||||
/*
|
||||
* Copyright (c) 2020-2021 Alex Spataru <https://github.com/alex-spataru>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#include "Publisher.h"
|
||||
|
||||
#include <Misc/Utilities.h>
|
||||
#include <Misc/TimerEvents.h>
|
||||
|
||||
using namespace MQTT;
|
||||
|
||||
static Publisher *INSTANCE = nullptr;
|
||||
|
||||
Publisher::Publisher()
|
||||
{
|
||||
m_lookupActive = false;
|
||||
|
||||
connect(&m_client, &QMQTT::Client::connected, this, &Publisher::connectedChanged);
|
||||
connect(&m_client, &QMQTT::Client::disconnected, this, &Publisher::connectedChanged);
|
||||
connect(&m_client, &QMQTT::Client::error, this, &Publisher::onError);
|
||||
|
||||
setPort(defaultPort());
|
||||
setHost(defaultHost());
|
||||
}
|
||||
|
||||
Publisher::~Publisher()
|
||||
{
|
||||
disconnectFromHost();
|
||||
}
|
||||
|
||||
Publisher *Publisher::getInstance()
|
||||
{
|
||||
if (!INSTANCE)
|
||||
INSTANCE = new Publisher;
|
||||
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
quint16 Publisher::port() const
|
||||
{
|
||||
return m_client.port();
|
||||
}
|
||||
|
||||
QString Publisher::topic() const
|
||||
{
|
||||
return m_topic;
|
||||
}
|
||||
|
||||
int Publisher::mqttVersion() const
|
||||
{
|
||||
switch (m_client.version())
|
||||
{
|
||||
case QMQTT::V3_1_0:
|
||||
return 0;
|
||||
break;
|
||||
case QMQTT::V3_1_1:
|
||||
return 1;
|
||||
break;
|
||||
default:
|
||||
return -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
QString Publisher::username() const
|
||||
{
|
||||
return m_client.username();
|
||||
}
|
||||
|
||||
QString Publisher::password() const
|
||||
{
|
||||
return QString::fromUtf8(m_client.password());
|
||||
}
|
||||
|
||||
QString Publisher::host() const
|
||||
{
|
||||
return m_client.host().toString();
|
||||
}
|
||||
|
||||
bool Publisher::lookupActive() const
|
||||
{
|
||||
return m_lookupActive;
|
||||
}
|
||||
|
||||
bool Publisher::isConnectedToHost() const
|
||||
{
|
||||
return m_client.isConnectedToHost();
|
||||
}
|
||||
|
||||
QStringList Publisher::mqttVersions() const
|
||||
{
|
||||
return QStringList { "MQTT 3.1.0", "MQTT 3.1.1" };
|
||||
}
|
||||
|
||||
void Publisher::connectToHost()
|
||||
{
|
||||
m_client.connectToHost();
|
||||
}
|
||||
|
||||
/**
|
||||
* Connects/disconnects the application from the current MQTT broker. This function is
|
||||
* used as a convenience for the connect/disconnect button.
|
||||
*/
|
||||
void Publisher::toggleConnection()
|
||||
{
|
||||
if (isConnectedToHost())
|
||||
disconnectFromHost();
|
||||
else
|
||||
connectToHost();
|
||||
}
|
||||
|
||||
void Publisher::disconnectFromHost()
|
||||
{
|
||||
m_client.disconnectFromHost();
|
||||
}
|
||||
|
||||
/**
|
||||
* Performs a DNS lookup for the given @a host name
|
||||
*/
|
||||
void Publisher::lookup(const QString &host)
|
||||
{
|
||||
m_lookupActive = true;
|
||||
emit lookupActiveChanged();
|
||||
QHostInfo::lookupHost(host.simplified(), this, &Publisher::lookupFinished);
|
||||
}
|
||||
|
||||
void Publisher::setPort(const quint16 port)
|
||||
{
|
||||
m_client.setPort(port);
|
||||
emit portChanged();
|
||||
}
|
||||
|
||||
void Publisher::setHost(const QString &host)
|
||||
{
|
||||
m_client.setHost(QHostAddress(host));
|
||||
emit hostChanged();
|
||||
}
|
||||
|
||||
void Publisher::setTopic(const QString &topic)
|
||||
{
|
||||
m_topic = topic;
|
||||
emit topicChanged();
|
||||
}
|
||||
|
||||
void Publisher::setUsername(const QString &username)
|
||||
{
|
||||
m_client.setUsername(username);
|
||||
emit usernameChanged();
|
||||
}
|
||||
|
||||
void Publisher::setPassword(const QString &password)
|
||||
{
|
||||
m_client.setPassword(password.toUtf8());
|
||||
emit passwordChanged();
|
||||
}
|
||||
|
||||
void Publisher::setMqttVersion(const int versionIndex)
|
||||
{
|
||||
switch (versionIndex)
|
||||
{
|
||||
case 0:
|
||||
m_client.setVersion(QMQTT::V3_1_0);
|
||||
break;
|
||||
case 1:
|
||||
m_client.setVersion(QMQTT::V3_1_1);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
emit mqttVersionChanged();
|
||||
}
|
||||
|
||||
void Publisher::sendData()
|
||||
{
|
||||
// Sort JFI list from oldest to most recent
|
||||
JFI_SortList(&m_jfiList);
|
||||
|
||||
// Clear JFI list
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the host IP address when the lookup finishes.
|
||||
* If the lookup fails, the error code/string shall be shown to the user in a messagebox.
|
||||
*/
|
||||
void Publisher::lookupFinished(const QHostInfo &info)
|
||||
{
|
||||
m_lookupActive = false;
|
||||
emit lookupActiveChanged();
|
||||
|
||||
if (info.error() == QHostInfo::NoError)
|
||||
{
|
||||
auto addresses = info.addresses();
|
||||
if (addresses.count() >= 1)
|
||||
{
|
||||
setHost(addresses.first().toString());
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Misc::Utilities::showMessageBox(tr("IP address lookup error"), info.errorString());
|
||||
}
|
||||
|
||||
void Publisher::onError(const QMQTT::ClientError error)
|
||||
{
|
||||
qDebug() << error;
|
||||
}
|
||||
|
||||
void Publisher::registerJsonFrame(const JFI_Object &frameInfo)
|
||||
{
|
||||
m_jfiList.append(frameInfo);
|
||||
}
|
140
src/MQTT/Publisher.h
Normal file
140
src/MQTT/Publisher.h
Normal file
@ -0,0 +1,140 @@
|
||||
/*
|
||||
* Copyright (c) 2020-2021 Alex Spataru <https://github.com/alex-spataru>
|
||||
*
|
||||
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
* of this software and associated documentation files (the "Software"), to deal
|
||||
* in the Software without restriction, including without limitation the rights
|
||||
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
* copies of the Software, and to permit persons to whom the Software is
|
||||
* furnished to do so, subject to the following conditions:
|
||||
*
|
||||
* The above copyright notice and this permission notice shall be included in
|
||||
* all copies or substantial portions of the Software.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
* THE SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef MQTT_PUBLISHER_H
|
||||
#define MQTT_PUBLISHER_H
|
||||
|
||||
#include <QObject>
|
||||
#include <QHostInfo>
|
||||
#include <QByteArray>
|
||||
#include <QHostAddress>
|
||||
|
||||
#include <JSON/Frame.h>
|
||||
#include <JSON/FrameInfo.h>
|
||||
|
||||
#include <qmqtt.h>
|
||||
|
||||
namespace MQTT
|
||||
{
|
||||
class Publisher : public QObject
|
||||
{
|
||||
// clang-format off
|
||||
Q_OBJECT
|
||||
Q_PROPERTY(quint16 port
|
||||
READ port
|
||||
WRITE setPort
|
||||
NOTIFY portChanged)
|
||||
Q_PROPERTY(QString host
|
||||
READ host
|
||||
WRITE setHost
|
||||
NOTIFY hostChanged)
|
||||
Q_PROPERTY(QString topic
|
||||
READ topic
|
||||
WRITE setTopic
|
||||
NOTIFY topicChanged)
|
||||
Q_PROPERTY(int mqttVersion
|
||||
READ mqttVersion
|
||||
WRITE setMqttVersion
|
||||
NOTIFY mqttVersionChanged)
|
||||
Q_PROPERTY(QString username
|
||||
READ username
|
||||
WRITE setUsername
|
||||
NOTIFY usernameChanged)
|
||||
Q_PROPERTY(QString password
|
||||
READ password
|
||||
WRITE setPassword
|
||||
NOTIFY passwordChanged)
|
||||
Q_PROPERTY(bool isConnectedToHost
|
||||
READ isConnectedToHost
|
||||
NOTIFY connectedChanged)
|
||||
Q_PROPERTY(bool lookupActive
|
||||
READ lookupActive
|
||||
NOTIFY lookupActiveChanged)
|
||||
Q_PROPERTY(QStringList mqttVersions
|
||||
READ mqttVersions
|
||||
CONSTANT)
|
||||
Q_PROPERTY(quint16 defaultPort
|
||||
READ defaultPort
|
||||
CONSTANT)
|
||||
Q_PROPERTY(QString defaultHost
|
||||
READ defaultHost
|
||||
CONSTANT)
|
||||
// clang-format on
|
||||
|
||||
signals:
|
||||
void portChanged();
|
||||
void hostChanged();
|
||||
void topicChanged();
|
||||
void usernameChanged();
|
||||
void passwordChanged();
|
||||
void connectedChanged();
|
||||
void mqttVersionChanged();
|
||||
void lookupActiveChanged();
|
||||
|
||||
public:
|
||||
static Publisher *getInstance();
|
||||
|
||||
quint16 port() const;
|
||||
QString host() const;
|
||||
QString topic() const;
|
||||
int mqttVersion() const;
|
||||
QString username() const;
|
||||
QString password() const;
|
||||
bool lookupActive() const;
|
||||
bool isConnectedToHost() const;
|
||||
QStringList mqttVersions() const;
|
||||
|
||||
quint16 defaultPort() const { return 1883; }
|
||||
|
||||
QString defaultHost() const { return "127.0.0.1"; }
|
||||
|
||||
public slots:
|
||||
void connectToHost();
|
||||
void toggleConnection();
|
||||
void disconnectFromHost();
|
||||
void lookup(const QString &host);
|
||||
void setPort(const quint16 port);
|
||||
void setHost(const QString &host);
|
||||
void setTopic(const QString &topic);
|
||||
void setUsername(const QString &username);
|
||||
void setPassword(const QString &password);
|
||||
void setMqttVersion(const int versionIndex);
|
||||
|
||||
private:
|
||||
Publisher();
|
||||
~Publisher();
|
||||
|
||||
private slots:
|
||||
void sendData();
|
||||
void lookupFinished(const QHostInfo &info);
|
||||
void onError(const QMQTT::ClientError error);
|
||||
void registerJsonFrame(const JFI_Object &frameInfo);
|
||||
|
||||
private:
|
||||
QString m_topic;
|
||||
bool m_lookupActive;
|
||||
QMQTT::Client m_client;
|
||||
QList<JFI_Object> m_jfiList;
|
||||
};
|
||||
}
|
||||
|
||||
#endif
|
@ -48,6 +48,8 @@
|
||||
#include <Misc/TimerEvents.h>
|
||||
#include <Misc/ModuleManager.h>
|
||||
|
||||
#include <MQTT/Publisher.h>
|
||||
|
||||
#include <Logger.h>
|
||||
#include <FileAppender.h>
|
||||
#include <QSimpleUpdater.h>
|
||||
@ -148,6 +150,7 @@ void ModuleManager::initializeQmlInterface()
|
||||
auto ioNetwork = IO::DataSources::Network::getInstance();
|
||||
auto jsonGenerator = JSON::Generator::getInstance();
|
||||
auto utilities = Misc::Utilities::getInstance();
|
||||
auto mqttPublisher = MQTT::Publisher::getInstance();
|
||||
LOG_INFO() << "Finished initializing C++ modules";
|
||||
|
||||
// Retranslate the QML interface automagically
|
||||
@ -170,6 +173,7 @@ void ModuleManager::initializeQmlInterface()
|
||||
c->setContextProperty("Cpp_IO_Serial", ioSerial);
|
||||
c->setContextProperty("Cpp_IO_Network", ioNetwork);
|
||||
c->setContextProperty("Cpp_JSON_Generator", jsonGenerator);
|
||||
c->setContextProperty("Cpp_MQTT_Publisher", mqttPublisher);
|
||||
|
||||
// Register app info with QML
|
||||
c->setContextProperty("Cpp_AppName", qApp->applicationName());
|
||||
@ -207,6 +211,7 @@ void ModuleManager::stopOperations()
|
||||
CSV::Player::getInstance()->closeFile();
|
||||
IO::Manager::getInstance()->disconnectDevice();
|
||||
Misc::TimerEvents::getInstance()->stopTimers();
|
||||
MQTT::Publisher::getInstance()->disconnectFromHost();
|
||||
|
||||
LOG_INFO() << "Application modules stopped";
|
||||
}
|
||||
|
@ -419,7 +419,7 @@ void WidgetProvider::updateModels()
|
||||
|
||||
// Check if frame is valid
|
||||
if (!DataProvider::getInstance()->latestFrame()->isValid())
|
||||
return;
|
||||
return;
|
||||
|
||||
// Update groups
|
||||
m_mapGroups = getWidgetGroup("map");
|
||||
|
Loading…
x
Reference in New Issue
Block a user