Skip to content

Commit

Permalink
Merge remote-tracking branch 'github/main' into prepare-for-github-ci
Browse files Browse the repository at this point in the history
  • Loading branch information
arnk-basyskom committed Jan 22, 2024
2 parents f3f0c57 + d8b45cf commit aa62e5d
Show file tree
Hide file tree
Showing 40 changed files with 309 additions and 226 deletions.
62 changes: 62 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<!--
// SPDX-FileCopyrightText: 2024 basysKom GmbH
// SPDX-FileContributor: Karsten Herrler <karsten.herrler@basyskom.com>
//
// SPDX-License-Identifier: CC0-1.0
-->
# OPC UA Browser

The OPC UA Browser from basysKom is an OPC UA client with a wide range of application options for OPC UA technology.

The OPC UA Browser can be used to establish an unencrypted connection to an OPC UA server as well as a connection encrypted via certificates. User authentication via user name and password is also supported.

The OPC UA Browser can be used to monitor selected nodes in order to obtain a quick overview of important components. Individual nodes can be easily added to and removed from the dashboard. It is possible to create several dashboards at the same time and quickly switch back and forth between them. The dashboards created can be easily saved so that they can be quickly reloaded in a new session.

The information model of the OPC UA server is displayed as a tree structure using the expert mode. Selecting a node displays its attributes and references. By clicking on a reference, you can quickly jump to the selected reference in the tree structure.

## Features

- Connecting to OPC UA Browser (uncrypted and encrypted via certificates, user authentication)
- Monitoring nodes in several dashboards
- Saving dashboards for reuse
- Browser for information model
- Windows, Linux, Android, iOS

## Getting OPC UA Browser

### Android

coming soon in Google Play store

### iOS

coming soon in App Store

## Compatibility
The application has been tested on:

- Windows using the MinGW 64-Bit compiler and Qt 6.5+

- Linux (Ubuntu 22.04 LTS) and Qt 6.5+

- Android using clang for arm64-v8a, armeabi-v7a, x86, x86_64

- iOS

## Dependencies

- Qt 6.5+
- Qt OPC UA (available at [https://doc.qt.io/qt-6/qtopcua-index.html))
- OpenSSL >= 3.0

## Building

To be done

## Contributing

Contributions are welcome! If you encounter any issues or would like to request a feature, feel free to open an issue or submit a pull request.

## License

This project is released under the GPLv3.0-or-later License.
9 changes: 6 additions & 3 deletions src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ SPDX-FileContributor: Karsten Herrler <karsten.herrler@basyskom.com>
SPDX-License-Identifier: BSD-3-Clause
]]

cmake_minimum_required(VERSION 3.19)
cmake_minimum_required(VERSION 3.19)

set(QT_QML_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/qml)
set(QML_IMPORT_PATH ${QT_QML_OUTPUT_DIRECTORY} CACHE STRING "Import paths for Qt Creator's code model" FORCE)

qt_add_executable(appOPC_UA_Browser
main.cpp
Expand All @@ -16,7 +19,8 @@ set_source_files_properties(qml/style/Style.qml PROPERTIES

qt_add_qml_module(appOPC_UA_Browser
URI OPC_UA_Browser
VERSION 1.0.0
VERSION 1.0
DEPENDENCIES QtCore QtQuick
QML_FILES qml/Main.qml
qml/BrowserView.qml
qml/ConnectionView.qml
Expand Down Expand Up @@ -77,7 +81,6 @@ qt_add_qml_module(appOPC_UA_Browser
reference.h reference.cpp
referencemodel.h referencemodel.cpp
treeitem.h treeitem.cpp
types.h
uisettings.h uisettings.cpp
x509certificate.h x509certificate.cpp
)
Expand Down
12 changes: 5 additions & 7 deletions src/backend.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,7 @@
#include <QOpcUaAuthenticationInformation>

#include "backend.h"
#include "dashboarditemmodel.h"
#include "monitoreditemmodel.h"
#include "opcuamodel.h"
#include "x509certificate.h"

static QString defaultPkiPath()
Expand Down Expand Up @@ -128,7 +126,7 @@ OpcUaModel *BackEnd::opcUaModel() const noexcept
return mOpcUaModel;
}

QAbstractItemModel *BackEnd::dashboardItemModel() const noexcept
DashboardItemModel *BackEnd::dashboardItemModel() const noexcept
{
return mDashboardItemModel;
}
Expand Down Expand Up @@ -281,11 +279,11 @@ void BackEnd::saveCurrentDashboard(const QString &name)

QSettings settings;
switch (mDashboardItemModel->getCurrentDashboardType()) {
case Types::DashboardType::Variables:
case DashboardItem::DashboardType::Variables:
settings.setValue("dashboards/variables/" % name, nodeIds);
addItemToStringListModel(mSavedVariableDashboardsModel, name);
break;
case Types::DashboardType::Events:
case DashboardItem::DashboardType::Events:
settings.setValue("dashboards/events/" % name, nodeIds);
addItemToStringListModel(mSavedEventDashboardsModel, name);
break;
Expand Down Expand Up @@ -526,8 +524,8 @@ void BackEnd::loadLastDashboardsFromSettings()
for (int i = 0; i < size; ++i) {
settings.setArrayIndex(i);
const QString name = settings.value("name").toString();
const Types::DashboardType type =
static_cast<Types::DashboardType>(settings.value("type", 0).toInt());
const DashboardItem::DashboardType type =
static_cast<DashboardItem::DashboardType>(settings.value("type", 0).toInt());

const int index = mDashboardItemModel->addItem(type, name);
auto model = mDashboardItemModel->getMonitoredItemModel(index);
Expand Down
16 changes: 12 additions & 4 deletions src/backend.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,19 @@
#include <QOpcUaProvider>
#include <QOpcUaErrorState>

#include "dashboarditemmodel.h"
#include "opcuamodel.h"

class DashboardItemModel;
class MonitoredItemModel;

// Workaround, otherwise qmllint doesn't recognise the QStringListModel
struct ThisIsAnnoying
{
Q_GADGET
QML_FOREIGN(QStringListModel)
QML_ANONYMOUS
};

class BackEnd : public QObject
{
Q_OBJECT
Expand All @@ -35,8 +43,8 @@ class BackEnd : public QObject
recentConnectionsChanged FINAL)
Q_PROPERTY(QVector<QString> serverList READ serverList NOTIFY serverListChanged FINAL)
Q_PROPERTY(QVector<QString> endpointList READ endpointList NOTIFY endpointListChanged FINAL)
Q_PROPERTY(QAbstractItemModel *opcUaModel READ opcUaModel NOTIFY opcUaModelChanged FINAL)
Q_PROPERTY(QAbstractItemModel *dashboardItemModel READ dashboardItemModel NOTIFY
Q_PROPERTY(OpcUaModel *opcUaModel READ opcUaModel NOTIFY opcUaModelChanged FINAL)
Q_PROPERTY(DashboardItemModel *dashboardItemModel READ dashboardItemModel NOTIFY
opcUaModelChanged FINAL)
Q_PROPERTY(QStringListModel *defaultVariableDashboards READ defaultVariableDashboards NOTIFY
defaultVariableDashboardsChanged FINAL)
Expand All @@ -58,7 +66,7 @@ class BackEnd : public QObject
QVector<QString> serverList() const noexcept;
QVector<QString> endpointList() const;
OpcUaModel *opcUaModel() const noexcept;
QAbstractItemModel *dashboardItemModel() const noexcept;
DashboardItemModel *dashboardItemModel() const noexcept;
QStringListModel *defaultVariableDashboards() const noexcept;
QStringListModel *defaultEventDashboards() const noexcept;
QStringListModel *savedVariableDashboards() const noexcept;
Expand Down
14 changes: 7 additions & 7 deletions src/dashboarditem.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,14 @@
#include "dashboarditem.h"
#include "monitoreditemmodel.h"

QString getDefaultNameForType(Types::DashboardType type)
QString getDefaultNameForType(DashboardItem::DashboardType type)
{
switch (type) {
case Types::DashboardType::Variables:
case DashboardItem::DashboardType::Variables:
return QCoreApplication::translate("OpcUaBrowser", "Dashboard");
case Types::DashboardType::Events:
case DashboardItem::DashboardType::Events:
return QCoreApplication::translate("OpcUaBrowser", "Event");
case Types::DashboardType::Add:
case DashboardItem::DashboardType::Add:
return QCoreApplication::translate("OpcUaBrowser", "Add");
default:
break;
Expand All @@ -27,14 +27,14 @@ QString getDefaultNameForType(Types::DashboardType type)
return QString();
}

DashboardItem::DashboardItem(Types::DashboardType type, const QString &name)
DashboardItem::DashboardItem(DashboardItem::DashboardType type, const QString &name)
: mName(name), mType(type)
{
if (mName.isEmpty()) {
mName = getDefaultNameForType(type);
}

if (type != Types::DashboardType::Add) {
if (type != DashboardItem::DashboardType::Add) {
mMonitoredItemModel = new MonitoredItemModel();
}
}
Expand All @@ -58,7 +58,7 @@ void DashboardItem::setName(const QString &name)
}
}

Types::DashboardType DashboardItem::type() const noexcept
DashboardItem::DashboardType DashboardItem::type() const noexcept
{
return mType;
}
Expand Down
15 changes: 10 additions & 5 deletions src/dashboarditem.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,27 +12,32 @@
#include <QQmlEngine>
#include <QString>

#include "types.h"

class MonitoredItemModel;
class QAbstractListModel;

class DashboardItem : public QObject
{
Q_OBJECT
QML_ELEMENT
QML_UNCREATABLE("DashboardItem is created by DashboardItemModel")

public:
explicit DashboardItem(Types::DashboardType type, const QString &name = QString());
enum class DashboardType { Unknown = -1, Variables, Events, Add };
Q_ENUM(DashboardType)

explicit DashboardItem(DashboardItem::DashboardType type, const QString &name = QString());
~DashboardItem();

const QString &name() const noexcept;
void setName(const QString &name);

Types::DashboardType type() const noexcept;
DashboardItem::DashboardType type() const noexcept;
QAbstractListModel *monitoredItemModel() const noexcept;
QStringList getMonitoredNodeIds() const;

private:
QString mName;
Types::DashboardType mType;
DashboardItem::DashboardType mType;
MonitoredItemModel *mMonitoredItemModel = nullptr;
};

Expand Down
14 changes: 7 additions & 7 deletions src/dashboarditemmodel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ enum Roles : int {
DashboardItemModel::DashboardItemModel(QObject *parent) : QAbstractListModel{ parent }
{
// Insert Add item
mItems.push_back(new DashboardItem(Types::DashboardType::Add));
mItems.push_back(new DashboardItem(DashboardItem::DashboardType::Add));
}

DashboardItemModel::~DashboardItemModel()
Expand Down Expand Up @@ -59,7 +59,7 @@ QVariant DashboardItemModel::data(const QModelIndex &index, int role) const
return QVariant();
}

int DashboardItemModel::addItem(Types::DashboardType type, const QString &name)
int DashboardItemModel::addItem(DashboardItem::DashboardType type, const QString &name)
{
const int pos = mItems.size() - 1;
DashboardItem *item = new DashboardItem(type, name);
Expand Down Expand Up @@ -90,7 +90,7 @@ void DashboardItemModel::clearItems()
qDeleteAll(mItems);
mItems.clear();
// Insert Add item
mItems.push_back(new DashboardItem(Types::DashboardType::Add));
mItems.push_back(new DashboardItem(DashboardItem::DashboardType::Add));
endResetModel();
}

Expand All @@ -107,10 +107,10 @@ MonitoredItemModel *DashboardItemModel::getCurrentMonitoredItemModel() const
return getMonitoredItemModel(mCurrentIndex);
}

Types::DashboardType DashboardItemModel::getCurrentDashboardType() const
DashboardItem::DashboardType DashboardItemModel::getCurrentDashboardType() const
{
if (mCurrentIndex >= mItems.size())
return Types::DashboardType::Unknown;
return DashboardItem::DashboardType::Unknown;

return mItems[mCurrentIndex]->type();
}
Expand All @@ -131,7 +131,7 @@ bool DashboardItemModel::isAddItem(uint index) const
if (index >= mItems.size())
return false;

return (mItems.at(index)->type() == Types::DashboardType::Add);
return (mItems.at(index)->type() == DashboardItem::DashboardType::Add);
}

void DashboardItemModel::setCurrentIndex(uint index)
Expand All @@ -152,7 +152,7 @@ void DashboardItemModel::saveDashboardsToSettings() const

settings.beginWriteArray("lastDashboards");
for (qsizetype i = 0; i < mItems.count(); ++i) {
if (mItems[i]->type() == Types::DashboardType::Add)
if (mItems[i]->type() == DashboardItem::DashboardType::Add)
continue;

settings.setArrayIndex(i);
Expand Down
9 changes: 7 additions & 2 deletions src/dashboarditemmodel.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,17 @@
#define DASHBOARDITEMMODEL_H

#include <QAbstractListModel>
#include <QQmlEngine>

#include "dashboarditem.h"

class MonitoredItemModel;

class DashboardItemModel : public QAbstractListModel
{
Q_OBJECT
QML_ANONYMOUS

public:
explicit DashboardItemModel(QObject *parent = nullptr);
~DashboardItemModel();
Expand All @@ -24,13 +29,13 @@ class DashboardItemModel : public QAbstractListModel
QVariant data(const QModelIndex &index, int role) const override;

bool containsItem(const QString &name) const noexcept;
Q_INVOKABLE int addItem(Types::DashboardType type, const QString &name = QString());
Q_INVOKABLE int addItem(DashboardItem::DashboardType type, const QString &name = QString());
Q_INVOKABLE void removeItem(int index);
void clearItems();

MonitoredItemModel *getMonitoredItemModel(int index) const;
MonitoredItemModel *getCurrentMonitoredItemModel() const;
Types::DashboardType getCurrentDashboardType() const;
DashboardItem::DashboardType getCurrentDashboardType() const;
void setCurrentDashboardName(const QString &name);

Q_INVOKABLE bool isAddItem(uint index) const;
Expand Down
4 changes: 0 additions & 4 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@
#include <QQmlContext>
#include <QQuickStyle>

#include "types.h"

static constexpr auto FontSwansea = "://font/Swansea.ttf";
static constexpr auto FontSwanseaBold = "://font/SwanseaBold.ttf";

Expand Down Expand Up @@ -49,8 +47,6 @@ int main(int argc, char *argv[])
&engine, &QQmlApplicationEngine::objectCreationFailed, &app,
[]() { QCoreApplication::exit(-1); }, Qt::QueuedConnection);

qmlRegisterUncreatableMetaObject(Types::staticMetaObject, "Types", 1, 0, "DashboardType",
"Error: only enums");
engine.loadFromModule("OPC_UA_Browser", "Main");

return app.exec();
Expand Down
2 changes: 1 addition & 1 deletion src/opcuamodel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ enum Roles : int {
QHash<int, QByteArray> OpcUaModel::roleNames() const
{
auto names = QAbstractItemModel::roleNames();
names[ColorRole] = "color";
names[ColorRole] = "indicatorColor";
names[ValueRole] = "value";
names[NodeIdRole] = "nodeId";
names[AttributesRole] = "attributes";
Expand Down
2 changes: 2 additions & 0 deletions src/opcuamodel.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#define OPCUAMODEL_H

#include <QAbstractItemModel>
#include <QQmlEngine>

#include "treeitem.h"

Expand All @@ -18,6 +19,7 @@ class QOpcUaNode;
class OpcUaModel : public QAbstractItemModel
{
Q_OBJECT
QML_ANONYMOUS

public:
explicit OpcUaModel(QObject *parent = nullptr);
Expand Down
Loading

0 comments on commit aa62e5d

Please sign in to comment.