Let Serial Studio act as a MQTT publisher (WIP)

This commit is contained in:
Alex Spataru 2021-02-27 01:50:42 -05:00
parent 44b734641f
commit a8fb35cc49
10 changed files with 750 additions and 22 deletions

View File

@ -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 \

View File

@ -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>

View 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
}
}
}

View File

@ -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 {

View File

@ -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;

View File

@ -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
View 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
View 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

View File

@ -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";
}

View File

@ -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");