Add support for generic IO connections

This commit is contained in:
Michael Zanetti 2020-04-05 19:36:43 +02:00
parent 26cda609c2
commit 373483f377
23 changed files with 1424 additions and 127 deletions

View File

@ -35,6 +35,7 @@
#include "types/browseritem.h"
#include "thinggroup.h"
#include "types/interface.h"
#include "types/ioconnections.h"
#include <QMetaEnum>
DeviceManager::DeviceManager(JsonRpcClient* jsonclient, QObject *parent) :
@ -43,6 +44,7 @@ DeviceManager::DeviceManager(JsonRpcClient* jsonclient, QObject *parent) :
m_plugins(new Plugins(this)),
m_devices(new Devices(this)),
m_deviceClasses(new DeviceClasses(this)),
m_ioConnections(new IOConnections(this)),
m_jsonClient(jsonclient)
{
m_jsonClient->registerNotificationHandler(this, "notificationReceived");
@ -54,6 +56,7 @@ void DeviceManager::clear()
m_deviceClasses->clearModel();
m_vendors->clearModel();
m_plugins->clearModel();
m_ioConnections->clearModel();
}
void DeviceManager::init()
@ -86,10 +89,21 @@ void DeviceManager::init()
}
}
// Register a custom notification handler for the Integrations namespace for now.
if (m_jsonClient->ensureServerVersion("5.1")) {
if (!m_integrationsHandler) {
m_integrationsHandler = new IntegrationsHandler(this);
m_jsonClient->registerNotificationHandler(m_integrationsHandler, "notificationReceived");
connect(m_integrationsHandler, &IntegrationsHandler::onNotificationReceived, this, [this](const QVariantMap &params){
notificationReceived(params);
});
}
}
m_fetchingData = true;
emit fetchingDataChanged();
m_jsonClient->sendCommand("Devices.GetPlugins", this, "getPluginsResponse");
m_jsonClient->sendCommand("Devices.GetSupportedDevices", this, "getSupportedDevicesResponse");
}
QString DeviceManager::nameSpace() const
@ -117,6 +131,11 @@ DeviceClasses *DeviceManager::deviceClasses() const
return m_deviceClasses;
}
IOConnections *DeviceManager::ioConnections() const
{
return m_ioConnections;
}
bool DeviceManager::fetchingData() const
{
return m_fetchingData;
@ -207,6 +226,22 @@ void DeviceManager::notificationReceived(const QVariantMap &data)
}
// qDebug() << "Event received" << deviceId.toString() << eventTypeId.toString();
dev->eventTriggered(eventTypeId.toString(), event.value("params").toMap());
} else if (notification == "Integrations.IOConnectionAdded") {
QVariantMap connectionMap = data.value("params").toMap().value("ioConnection").toMap();
QUuid id = connectionMap.value("id").toUuid();
QUuid inputThingId = connectionMap.value("inputThingId").toUuid();
QUuid inputStateTypeId = connectionMap.value("inputStateTypeId").toUuid();
QUuid outputThingId = connectionMap.value("outputThingId").toUuid();
QUuid outputStateTypeId = connectionMap.value("outputStateTypeId").toUuid();
IOConnection *ioConnection = new IOConnection(id, inputThingId, inputStateTypeId, outputThingId, outputStateTypeId);
m_ioConnections->addIOConnection(ioConnection);
} else if (notification == "Integrations.IOConnectionRemoved") {
QUuid connectionId = data.value("params").toMap().value("ioConnectionId").toUuid();
if (!m_ioConnections->getIOConnection(connectionId)) {
qWarning() << "Received an IO connection removed event for an IO connection we don't know.";
return;
}
m_ioConnections->removeIOConnection(connectionId);
} else {
qWarning() << "DeviceManager unhandled device notification received" << notification;
}
@ -223,8 +258,6 @@ void DeviceManager::getVendorsResponse(const QVariantMap &params)
// qDebug() << "Added Vendor:" << vendor->name();
}
}
m_jsonClient->sendCommand("Devices.GetSupportedDevices", this, "getSupportedDevicesResponse");
}
void DeviceManager::getSupportedDevicesResponse(const QVariantMap &params)
@ -321,6 +354,10 @@ void DeviceManager::getConfiguredDevicesResponse(const QVariantMap &params)
}
m_fetchingData = false;
emit fetchingDataChanged();
m_jsonClient->sendCommand("Integrations.GetIOConnections", this, "getIOConnectionsResponse");
m_jsonClient->sendCommand("Devices.GetPlugins", this, "getPluginsResponse");
}
void DeviceManager::addDeviceResponse(const QVariantMap &params)
@ -675,9 +712,52 @@ int DeviceManager::executeBrowserItemAction(const QUuid &deviceId, const QString
return m_jsonClient->sendCommand("Actions.ExecuteBrowserItemAction", data, this, "executeBrowserItemActionResponse");
}
int DeviceManager::connectIO(const QUuid &inputThingId, const QUuid &inputStateTypeId, const QUuid &outputThingId, const QUuid &outputStateTypeId)
{
QVariantMap data;
data.insert("inputThingId", inputThingId);
data.insert("inputStateTypeId", inputStateTypeId);
data.insert("outputThingId", outputThingId);
data.insert("outputStateTypeId", outputStateTypeId);
return m_jsonClient->sendCommand("Integrations.ConnectIO", data, this, "connectIOResponse");
}
int DeviceManager::disconnectIO(const QUuid &ioConnectionId)
{
QVariantMap data;
data.insert("ioConnectionId", ioConnectionId);
return m_jsonClient->sendCommand("Integrations.DisconnectIO", data, this, "disconnectIOResponse");
}
void DeviceManager::executeBrowserItemActionResponse(const QVariantMap &params)
{
qDebug() << "Execute Browser Item Action finished" << params;
emit executeBrowserItemActionReply(params);
}
void DeviceManager::getIOConnectionsResponse(const QVariantMap &params)
{
qDebug() << "Get IO connections response" << qUtf8Printable(QJsonDocument::fromVariant(params).toJson());
foreach (const QVariant &connectionVariant, params.value("params").toMap().value("ioConnections").toList()) {
QVariantMap connectionMap = connectionVariant.toMap();
QUuid id = connectionMap.value("id").toUuid();
QUuid inputThingId = connectionMap.value("inputThingId").toUuid();
QUuid inputStateTypeId = connectionMap.value("inputStateTypeId").toUuid();
QUuid outputThingId = connectionMap.value("outputThingId").toUuid();
QUuid outputStateTypeId = connectionMap.value("outputStateTypeId").toUuid();
IOConnection *ioConnection = new IOConnection(id, inputThingId, inputStateTypeId, outputThingId, outputStateTypeId);
m_ioConnections->addIOConnection(ioConnection);
}
}
void DeviceManager::connectIOResponse(const QVariantMap &params)
{
qDebug() << "ConnectIO response" << qUtf8Printable(QJsonDocument::fromVariant(params).toJson());
}
void DeviceManager::disconnectIOResponse(const QVariantMap &params)
{
qDebug() << "DisconnectIO response" << qUtf8Printable(QJsonDocument::fromVariant(params).toJson());
}

View File

@ -43,17 +43,20 @@
class BrowserItem;
class BrowserItems;
class EventHandler;
class ThingGroup;
class Interface;
class IOConnections;
class EventHandler;
class IntegrationsHandler;
class DeviceManager : public JsonHandler
{
Q_OBJECT
Q_PROPERTY(Vendors *vendors READ vendors CONSTANT)
Q_PROPERTY(Plugins *plugins READ plugins CONSTANT)
Q_PROPERTY(Devices *devices READ devices CONSTANT)
Q_PROPERTY(DeviceClasses *deviceClasses READ deviceClasses CONSTANT)
Q_PROPERTY(Vendors* vendors READ vendors CONSTANT)
Q_PROPERTY(Plugins* plugins READ plugins CONSTANT)
Q_PROPERTY(Devices* devices READ devices CONSTANT)
Q_PROPERTY(DeviceClasses* deviceClasses READ deviceClasses CONSTANT)
Q_PROPERTY(IOConnections* ioConnections READ ioConnections CONSTANT)
Q_PROPERTY(bool fetchingData READ fetchingData NOTIFY fetchingDataChanged)
@ -72,10 +75,11 @@ public:
QString nameSpace() const override;
Vendors *vendors() const;
Plugins *plugins() const;
Devices *devices() const;
DeviceClasses *deviceClasses() const;
Vendors* vendors() const;
Plugins* plugins() const;
Devices* devices() const;
DeviceClasses* deviceClasses() const;
IOConnections* ioConnections() const;
bool fetchingData() const;
@ -99,6 +103,9 @@ public:
Q_INVOKABLE int executeBrowserItem(const QUuid &deviceId, const QString &itemId);
Q_INVOKABLE int executeBrowserItemAction(const QUuid &deviceId, const QString &itemId, const QUuid &actionTypeId, const QVariantList &params = QVariantList());
Q_INVOKABLE int connectIO(const QUuid &inputThingId, const QUuid &inputStateTypeId, const QUuid &outputThingId, const QUuid &outputStateTypeId);
Q_INVOKABLE int disconnectIO(const QUuid &ioConnectionId);
private:
Q_INVOKABLE void notificationReceived(const QVariantMap &data);
Q_INVOKABLE void getVendorsResponse(const QVariantMap &params);
@ -118,6 +125,9 @@ private:
Q_INVOKABLE void browserItemResponse(const QVariantMap &params);
Q_INVOKABLE void executeBrowserItemResponse(const QVariantMap &params);
Q_INVOKABLE void executeBrowserItemActionResponse(const QVariantMap &params);
Q_INVOKABLE void getIOConnectionsResponse(const QVariantMap &params);
Q_INVOKABLE void connectIOResponse(const QVariantMap &params);
Q_INVOKABLE void disconnectIOResponse(const QVariantMap &params);
public slots:
void savePluginConfig(const QUuid &pluginId);
@ -145,6 +155,7 @@ private:
Plugins *m_plugins;
Devices *m_devices;
DeviceClasses *m_deviceClasses;
IOConnections *m_ioConnections;
bool m_fetchingData = false;
@ -158,6 +169,8 @@ private:
// Deprecated stuff for nymea < 0.17 (JSONRPC < 4.0)
EventHandler *m_eventHandler = nullptr;
// Register notifications for new stuff that's only available in the Integrations namespace for now
IntegrationsHandler *m_integrationsHandler = nullptr;
};
@ -181,4 +194,22 @@ private:
};
class IntegrationsHandler: public JsonHandler {
Q_OBJECT
public:
IntegrationsHandler(QObject *parent = nullptr): JsonHandler(parent) {}
QString nameSpace() const override {
return "Integrations";
}
signals:
void onNotificationReceived(const QVariantMap &data);
private:
Q_INVOKABLE void notificationReceived(const QVariantMap &data) {
emit onNotificationReceived(data);
}
};
#endif // DEVICEMANAGER_H

View File

@ -203,6 +203,66 @@ void DevicesProxy::setNameFilter(const QString &nameFilter)
}
}
bool DevicesProxy::showDigitalInputs() const
{
return m_showDigitalInputs;
}
void DevicesProxy::setShowDigitalInputs(bool showDigitalInputs)
{
if (m_showDigitalInputs != showDigitalInputs) {
m_showDigitalInputs = showDigitalInputs;
emit showDigitalInputsChanged();
invalidateFilter();
emit countChanged();
}
}
bool DevicesProxy::showDigitalOutputs() const
{
return m_showDigitalOutputs;
}
void DevicesProxy::setShowDigitalOutputs(bool showDigitalOutputs)
{
if (m_showDigitalOutputs != showDigitalOutputs) {
m_showDigitalOutputs = showDigitalOutputs;
emit showDigitalOutputsChanged();
invalidateFilter();
emit countChanged();
}
}
bool DevicesProxy::showAnalogInputs() const
{
return m_showAnalogInputs;
}
void DevicesProxy::setShowAnalogInputs(bool showAnalogInputs)
{
if (m_showAnalogInputs != showAnalogInputs) {
m_showAnalogInputs = showAnalogInputs;
emit showAnalogInputsChanged();
invalidateFilter();
emit countChanged();
}
}
bool DevicesProxy::showAnalogOutputs() const
{
return m_showDigitalOutputs;
}
void DevicesProxy::setShowAnalogOutputs(bool showAnalogOutputs)
{
if (m_showAnalogOutputs != showAnalogOutputs) {
m_showAnalogOutputs = showAnalogOutputs;
emit showAnalogOutputsChanged();
invalidateFilter();
emit countChanged();
}
}
bool DevicesProxy::filterBatteryCritical() const
{
return m_filterBatteryCritical;
@ -339,6 +399,21 @@ bool DevicesProxy::filterAcceptsRow(int source_row, const QModelIndex &source_pa
}
}
if (m_showDigitalInputs || m_showDigitalOutputs || m_showAnalogInputs || m_showAnalogOutputs) {
if (m_showDigitalInputs && deviceClass->stateTypes()->ioStateTypes(Types::IOTypeDigitalInput).isEmpty()) {
return false;
}
if (m_showDigitalOutputs && deviceClass->stateTypes()->ioStateTypes(Types::IOTypeDigitalOutput).isEmpty()) {
return false;
}
if (m_showAnalogInputs && deviceClass->stateTypes()->ioStateTypes(Types::IOTypeAnalogInput).isEmpty()) {
return false;
}
if (m_showAnalogOutputs && deviceClass->stateTypes()->ioStateTypes(Types::IOTypeAnalogOutput).isEmpty()) {
return false;
}
}
if (m_filterBatteryCritical) {
if (!deviceClass->interfaces().contains("battery") || device->stateValue(deviceClass->stateTypes()->findByName("batteryCritical")->id()).toBool() == false) {
return false;

View File

@ -53,6 +53,12 @@ class DevicesProxy : public QSortFilterProxyModel
Q_PROPERTY(QStringList hiddenInterfaces READ hiddenInterfaces WRITE setHiddenInterfaces NOTIFY hiddenInterfacesChanged)
Q_PROPERTY(QString nameFilter READ nameFilter WRITE setNameFilter NOTIFY nameFilterChanged)
// Setting one of those to true will hide those set to false. If all of those are false no IO filtering will be done
Q_PROPERTY(bool showDigitalInputs READ showDigitalInputs WRITE setShowDigitalInputs NOTIFY showDigitalInputsChanged)
Q_PROPERTY(bool showDigitalOutputs READ showDigitalOutputs WRITE setShowDigitalOutputs NOTIFY showDigitalOutputsChanged)
Q_PROPERTY(bool showAnalogInputs READ showAnalogInputs WRITE setShowAnalogInputs NOTIFY showAnalogInputsChanged)
Q_PROPERTY(bool showAnalogOutputs READ showAnalogOutputs WRITE setShowAnalogOutputs NOTIFY showAnalogOutputsChanged)
// Setting this to true will imply filtering for "battery" interface
Q_PROPERTY(bool filterBatteryCritical READ filterBatteryCritical WRITE setFilterBatteryCritical NOTIFY filterBatteryCriticalChanged)
@ -91,6 +97,18 @@ public:
QString nameFilter() const;
void setNameFilter(const QString &nameFilter);
bool showDigitalInputs() const;
void setShowDigitalInputs(bool showDigitalInputs);
bool showDigitalOutputs() const;
void setShowDigitalOutputs(bool showDigitalOutputs);
bool showAnalogInputs() const;
void setShowAnalogInputs(bool showAnalogInputs);
bool showAnalogOutputs() const;
void setShowAnalogOutputs(bool showAnalogOutputs);
bool filterBatteryCritical() const;
void setFilterBatteryCritical(bool filterBatteryCritical);
@ -113,6 +131,10 @@ signals:
void shownInterfacesChanged();
void hiddenInterfacesChanged();
void nameFilterChanged();
void showDigitalInputsChanged();
void showDigitalOutputsChanged();
void showAnalogInputsChanged();
void showAnalogOutputsChanged();
void filterBatteryCriticalChanged();
void filterDisconnectedChanged();
void groupByInterfaceChanged();
@ -131,6 +153,11 @@ private:
QStringList m_hiddenInterfaces;
QString m_nameFilter;
bool m_showDigitalInputs = false;
bool m_showDigitalOutputs = false;
bool m_showAnalogInputs = false;
bool m_showAnalogOutputs = false;
bool m_filterBatteryCritical = false;
bool m_filterDisconnected = false;

View File

@ -189,6 +189,11 @@ StateType *JsonTypes::unpackStateType(const QVariantMap &stateTypeMap, QObject *
QPair<Types::Unit, QString> unit = stringToUnit(stateTypeMap.value("unit").toString());
stateType->setUnit(unit.first);
stateType->setUnitString(unit.second);
QMetaEnum metaEnum = QMetaEnum::fromType<Types::IOType>();
Types::IOType ioType = static_cast<Types::IOType>(metaEnum.keyToValue(stateTypeMap.value("ioType").toByteArray()));
stateType->setIOType(ioType);
return stateType;
}

View File

@ -110,6 +110,10 @@
#include "types/tokeninfo.h"
#include "types/userinfo.h"
#include "thinggroup.h"
#include "types/statetypesproxy.h"
#include "types/ioconnection.h"
#include "types/ioconnections.h"
#include "types/ioconnectionwatcher.h"
#include <QtQml/qqml.h>
@ -157,6 +161,7 @@ void registerQmlTypes() {
qmlRegisterUncreatableType<StateTypes>(uri, 1, 0, "StateTypes", "Can't create this in QML. Get it from the DeviceClass.");
qmlRegisterUncreatableType<ActionType>(uri, 1, 0, "ActionType", "Can't create this in QML. Get it from the ActionTypes.");
qmlRegisterUncreatableType<ActionTypes>(uri, 1, 0, "ActionTypes", "Can't create this in QML. Get it from the DeviceClass.");
qmlRegisterType<StateTypesProxy>(uri, 1, 0, "StateTypesProxy");
qmlRegisterUncreatableType<State>(uri, 1, 0, "State", "Can't create this in QML. Get it from the States.");
qmlRegisterUncreatableType<States>(uri, 1, 0, "States", "Can't create this in QML. Get it from the Device.");
@ -293,6 +298,11 @@ void registerQmlTypes() {
qmlRegisterUncreatableType<UserInfo>(uri, 1, 0, "UserInfo", "Get it from UserManager");
qmlRegisterUncreatableType<TokenInfo>(uri, 1, 0, "TokenInfo", "Get it from TokenInfos");
qmlRegisterUncreatableType<TokenInfos>(uri, 1, 0, "TokenInfos", "Get it from UserManager");
qmlRegisterUncreatableType<IOConnections>(uri, 1, 0, "IOConnections", "Get it from DeviceManager");
qmlRegisterUncreatableType<IOConnection>(uri, 1, 0, "IOConnection", "Get it from IOConnections");
qmlRegisterType<IOInputConnectionWatcher>(uri, 1, 0, "IOInputConnectionWatcher");
qmlRegisterType<IOOutputConnectionWatcher>(uri, 1, 0, "IOOutputConnectionWatcher");
}
#endif // LIBNYMEAAPPCORE_H

View File

@ -48,6 +48,7 @@ SOURCES += \
types/paramtypes.cpp \
types/statetype.cpp \
types/statetypes.cpp \
types/statetypesproxy.cpp \
types/eventtype.cpp \
types/eventtypes.cpp \
types/actiontype.cpp \
@ -86,6 +87,9 @@ SOURCES += \
types/tokeninfo.cpp \
types/tokeninfos.cpp \
types/userinfo.cpp \
types/ioconnection.cpp \
types/ioconnections.cpp \
types/ioconnectionwatcher.cpp \
connection/nymeahost.cpp \
connection/nymeahosts.cpp \
connection/nymeaconnection.cpp \
@ -176,6 +180,7 @@ HEADERS += \
types/paramtypes.h \
types/statetype.h \
types/statetypes.h \
types/statetypesproxy.h \
types/eventtype.h \
types/eventtypes.h \
types/actiontype.h \
@ -214,6 +219,9 @@ HEADERS += \
types/tokeninfo.h \
types/tokeninfos.h \
types/userinfo.h \
types/ioconnection.h \
types/ioconnections.h \
types/ioconnectionwatcher.h \
connection/nymeahost.h \
connection/nymeahosts.h \
connection/nymeaconnection.h \

View File

@ -0,0 +1,67 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2020, nymea GmbH
* Contact: contact@nymea.io
*
* This file is part of nymea.
* This project including source code and documentation is protected by
* copyright law, and remains the property of nymea GmbH. All rights, including
* reproduction, publication, editing and translation, are reserved. The use of
* this project is subject to the terms of a license agreement to be concluded
* with nymea GmbH in accordance with the terms of use of nymea GmbH, available
* under https://nymea.io/license
*
* GNU General Public License Usage
* Alternatively, this project may be redistributed and/or modified under the
* terms of the GNU General Public License as published by the Free Software
* Foundation, GNU version 3. This project is distributed in the hope that it
* will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* this project. If not, see <https://www.gnu.org/licenses/>.
*
* For any further details and any questions please contact us under
* contact@nymea.io or see our FAQ/Licensing Information on
* https://nymea.io/license/faq
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "ioconnection.h"
IOConnection::IOConnection(const QUuid &id, const QUuid &inputThingId, const QUuid &inputStateTypeId, const QUuid &outputThingId, const QUuid &outputStateTypeId, QObject *parent):
QObject(parent),
m_id(id),
m_inputThingId(inputThingId),
m_inputStateTypeId(inputStateTypeId),
m_outputThingId(outputThingId),
m_outputStateTypeId(outputStateTypeId)
{
}
QUuid IOConnection::id() const
{
return m_id;
}
QUuid IOConnection::inputThingId() const
{
return m_inputThingId;
}
QUuid IOConnection::inputStateTypeId() const
{
return m_inputStateTypeId;
}
QUuid IOConnection::outputThingId() const
{
return m_outputThingId;
}
QUuid IOConnection::outputStateTypeId() const
{
return m_outputStateTypeId;
}

View File

@ -0,0 +1,63 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2020, nymea GmbH
* Contact: contact@nymea.io
*
* This file is part of nymea.
* This project including source code and documentation is protected by
* copyright law, and remains the property of nymea GmbH. All rights, including
* reproduction, publication, editing and translation, are reserved. The use of
* this project is subject to the terms of a license agreement to be concluded
* with nymea GmbH in accordance with the terms of use of nymea GmbH, available
* under https://nymea.io/license
*
* GNU General Public License Usage
* Alternatively, this project may be redistributed and/or modified under the
* terms of the GNU General Public License as published by the Free Software
* Foundation, GNU version 3. This project is distributed in the hope that it
* will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* this project. If not, see <https://www.gnu.org/licenses/>.
*
* For any further details and any questions please contact us under
* contact@nymea.io or see our FAQ/Licensing Information on
* https://nymea.io/license/faq
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef IOCONNECTION_H
#define IOCONNECTION_H
#include <QObject>
#include <QUuid>
class IOConnection : public QObject
{
Q_OBJECT
Q_PROPERTY(QUuid id READ id CONSTANT)
Q_PROPERTY(QUuid inputThingId READ inputThingId CONSTANT)
Q_PROPERTY(QUuid inputStateTypeId READ inputStateTypeId CONSTANT)
Q_PROPERTY(QUuid outputThingId READ outputThingId CONSTANT)
Q_PROPERTY(QUuid outputStateTypeId READ outputStateTypeId CONSTANT)
public:
explicit IOConnection(const QUuid &id, const QUuid &inputThingId, const QUuid &inputStateTypeId, const QUuid &outputThingId, const QUuid &outputStateTypeId, QObject *parent = nullptr);
QUuid id() const;
QUuid inputThingId() const;
QUuid inputStateTypeId() const;
QUuid outputThingId() const;
QUuid outputStateTypeId() const;
private:
QUuid m_id;
QUuid m_inputThingId;
QUuid m_inputStateTypeId;
QUuid m_outputThingId;
QUuid m_outputStateTypeId;
};
#endif // IOCONNECTION_H

View File

@ -0,0 +1,129 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2020, nymea GmbH
* Contact: contact@nymea.io
*
* This file is part of nymea.
* This project including source code and documentation is protected by
* copyright law, and remains the property of nymea GmbH. All rights, including
* reproduction, publication, editing and translation, are reserved. The use of
* this project is subject to the terms of a license agreement to be concluded
* with nymea GmbH in accordance with the terms of use of nymea GmbH, available
* under https://nymea.io/license
*
* GNU General Public License Usage
* Alternatively, this project may be redistributed and/or modified under the
* terms of the GNU General Public License as published by the Free Software
* Foundation, GNU version 3. This project is distributed in the hope that it
* will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* this project. If not, see <https://www.gnu.org/licenses/>.
*
* For any further details and any questions please contact us under
* contact@nymea.io or see our FAQ/Licensing Information on
* https://nymea.io/license/faq
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "ioconnections.h"
IOConnections::IOConnections(QObject *parent) : QAbstractListModel(parent)
{
}
int IOConnections::rowCount(const QModelIndex &parent) const
{
Q_UNUSED(parent)
return m_list.count();
}
QVariant IOConnections::data(const QModelIndex &index, int role) const
{
switch (role) {
case RoleInputThingId:
return m_list.at(index.row())->inputThingId();
case RoleInputStateTypeId:
return m_list.at(index.row())->inputStateTypeId();
case RoleOutputThingId:
return m_list.at(index.row())->outputThingId();
case RoleOutputStateTypeId:
return m_list.at(index.row())->outputStateTypeId();
}
return QVariant();
}
QHash<int, QByteArray> IOConnections::roleNames() const
{
QHash<int, QByteArray> roles;
roles.insert(RoleInputThingId, "inputThingId");
roles.insert(RoleInputStateTypeId, "inputStateTypeId");
roles.insert(RoleOutputThingId, "outputThingId");
roles.insert(RoleOutputStateTypeId, "outputStateTypeId");
return roles;
}
void IOConnections::addIOConnection(IOConnection *ioConnection)
{
ioConnection->setParent(this);
beginInsertRows(QModelIndex(), m_list.count(), m_list.count());
m_list.append(ioConnection);
endInsertRows();
emit countChanged();
}
void IOConnections::removeIOConnection(const QUuid &ioConnectionId)
{
int idx = -1;
for (int i = 0; i < m_list.count(); i++) {
if (m_list.at(i)->id() == ioConnectionId) {
idx = i;
break;
}
}
beginRemoveRows(QModelIndex(), idx, idx);
m_list.takeAt(idx)->deleteLater();
endRemoveRows();
emit countChanged();
}
void IOConnections::clearModel()
{
beginResetModel();
qDeleteAll(m_list);
m_list.clear();
endResetModel();
}
IOConnection *IOConnections::getIOConnection(const QUuid &ioConnectionId) const
{
foreach (IOConnection* ioConnection, m_list) {
if (ioConnection->id() == ioConnectionId) {
return ioConnection;
}
}
return nullptr;
}
IOConnection *IOConnections::findIOConnectionByInput(const QUuid &inputThingId, const QUuid &inputStateTypeId) const
{
foreach (IOConnection* ioConnection, m_list) {
if (ioConnection->inputThingId() == inputThingId && ioConnection->inputStateTypeId() == inputStateTypeId) {
return ioConnection;
}
}
return nullptr;
}
IOConnection *IOConnections::findIOConnectionByOutput(const QUuid &outputThingId, const QUuid &outputStateTypeId) const
{
foreach (IOConnection* ioConnection, m_list) {
if (ioConnection->outputThingId() == outputThingId && ioConnection->outputStateTypeId() == outputStateTypeId) {
return ioConnection;
}
}
return nullptr;
}

View File

@ -0,0 +1,73 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2020, nymea GmbH
* Contact: contact@nymea.io
*
* This file is part of nymea.
* This project including source code and documentation is protected by
* copyright law, and remains the property of nymea GmbH. All rights, including
* reproduction, publication, editing and translation, are reserved. The use of
* this project is subject to the terms of a license agreement to be concluded
* with nymea GmbH in accordance with the terms of use of nymea GmbH, available
* under https://nymea.io/license
*
* GNU General Public License Usage
* Alternatively, this project may be redistributed and/or modified under the
* terms of the GNU General Public License as published by the Free Software
* Foundation, GNU version 3. This project is distributed in the hope that it
* will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* this project. If not, see <https://www.gnu.org/licenses/>.
*
* For any further details and any questions please contact us under
* contact@nymea.io or see our FAQ/Licensing Information on
* https://nymea.io/license/faq
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef IOCONNECTIONS_H
#define IOCONNECTIONS_H
#include "ioconnection.h"
#include <QAbstractListModel>
class IOConnections : public QAbstractListModel
{
Q_OBJECT
Q_PROPERTY(int count READ rowCount NOTIFY countChanged)
public:
enum Roles {
RoleInputThingId,
RoleInputStateTypeId,
RoleOutputThingId,
RoleOutputStateTypeId
};
Q_ENUM(Roles)
explicit IOConnections(QObject *parent = nullptr);
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role) const override;
QHash<int, QByteArray> roleNames() const;
void addIOConnection(IOConnection *ioConnection);
void removeIOConnection(const QUuid &ioConnectionId);
void clearModel();
Q_INVOKABLE IOConnection* getIOConnection(const QUuid &ioConnectionId) const;
Q_INVOKABLE IOConnection* findIOConnectionByInput(const QUuid &inputThingId, const QUuid &inputStateTypeId) const;
Q_INVOKABLE IOConnection* findIOConnectionByOutput(const QUuid &outputThingId, const QUuid &outputStateTypeId) const;
signals:
void countChanged();
private:
QList<IOConnection*> m_list;
};
#endif // IOCONNECTIONS_H

View File

@ -0,0 +1,157 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2020, nymea GmbH
* Contact: contact@nymea.io
*
* This file is part of nymea.
* This project including source code and documentation is protected by
* copyright law, and remains the property of nymea GmbH. All rights, including
* reproduction, publication, editing and translation, are reserved. The use of
* this project is subject to the terms of a license agreement to be concluded
* with nymea GmbH in accordance with the terms of use of nymea GmbH, available
* under https://nymea.io/license
*
* GNU General Public License Usage
* Alternatively, this project may be redistributed and/or modified under the
* terms of the GNU General Public License as published by the Free Software
* Foundation, GNU version 3. This project is distributed in the hope that it
* will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* this project. If not, see <https://www.gnu.org/licenses/>.
*
* For any further details and any questions please contact us under
* contact@nymea.io or see our FAQ/Licensing Information on
* https://nymea.io/license/faq
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "ioconnectionwatcher.h"
#include "ioconnections.h"
#include "ioconnection.h"
IOInputConnectionWatcher::IOInputConnectionWatcher(QObject *parent) : QObject(parent)
{
}
IOConnections *IOInputConnectionWatcher::ioConnections() const
{
return m_ioConnections;
}
void IOInputConnectionWatcher::setIOConnections(IOConnections *ioConnections)
{
if (m_ioConnections != ioConnections) {
if (m_ioConnections) {
disconnect(ioConnections, &IOConnections::countChanged, this, &IOInputConnectionWatcher::ioConnectionChanged);
}
m_ioConnections = ioConnections;
emit ioConnectionsChanged();
emit ioConnectionChanged();
connect(ioConnections, &IOConnections::countChanged, this, &IOInputConnectionWatcher::ioConnectionChanged);
}
}
QUuid IOInputConnectionWatcher::inputThingId() const
{
return m_inputThingId;
}
void IOInputConnectionWatcher::setInputThingId(const QUuid &inputThingId)
{
if (m_inputThingId != inputThingId) {
m_inputThingId = inputThingId;
emit inputThingIdChanged();
emit ioConnectionChanged();
}
}
QUuid IOInputConnectionWatcher::inputStateTypeId() const
{
return m_inputStateTypeId;
}
void IOInputConnectionWatcher::setInputStateTypeId(const QUuid &inputStateTypeId)
{
if (m_inputStateTypeId != inputStateTypeId) {
m_inputStateTypeId = inputStateTypeId;
emit inputStateTypeIdChanged();
emit ioConnectionChanged();
}
}
IOConnection* IOInputConnectionWatcher::ioConnection() const
{
if (!m_ioConnections) {
return nullptr;
}
return m_ioConnections->findIOConnectionByInput(m_inputThingId, m_inputStateTypeId);
}
IOOutputConnectionWatcher::IOOutputConnectionWatcher(QObject *parent): QObject(parent)
{
}
IOConnections *IOOutputConnectionWatcher::ioConnections() const
{
return m_ioConnections;
}
void IOOutputConnectionWatcher::setIOConnections(IOConnections *ioConnections)
{
if (m_ioConnections != ioConnections) {
if (m_ioConnections) {
disconnect(ioConnections, &IOConnections::countChanged, this, &IOOutputConnectionWatcher::ioConnectionChanged);
}
m_ioConnections = ioConnections;
emit ioConnectionsChanged();
emit ioConnectionChanged();
connect(ioConnections, &IOConnections::countChanged, this, &IOOutputConnectionWatcher::ioConnectionChanged);
}
}
QUuid IOOutputConnectionWatcher::outputThingId() const
{
return m_outputThingId;
}
void IOOutputConnectionWatcher::setOutputThingId(const QUuid &outputThingId)
{
if (m_outputThingId != outputThingId) {
m_outputThingId = outputThingId;
emit outputThingIdChanged();
emit ioConnectionChanged();
}
}
QUuid IOOutputConnectionWatcher::outputStateTypeId() const
{
return m_outputStateTypeId;
}
void IOOutputConnectionWatcher::setOutputStateTypeId(const QUuid &outputStateTypeId)
{
if (m_outputStateTypeId != outputStateTypeId) {
m_outputStateTypeId = outputStateTypeId;
emit outputStateTypeIdChanged();
emit ioConnectionChanged();
}
}
IOConnection *IOOutputConnectionWatcher::ioConnection() const
{
if (!m_ioConnections) {
return nullptr;
}
return m_ioConnections->findIOConnectionByOutput(m_outputThingId, m_outputStateTypeId);
}

View File

@ -0,0 +1,107 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2020, nymea GmbH
* Contact: contact@nymea.io
*
* This file is part of nymea.
* This project including source code and documentation is protected by
* copyright law, and remains the property of nymea GmbH. All rights, including
* reproduction, publication, editing and translation, are reserved. The use of
* this project is subject to the terms of a license agreement to be concluded
* with nymea GmbH in accordance with the terms of use of nymea GmbH, available
* under https://nymea.io/license
*
* GNU General Public License Usage
* Alternatively, this project may be redistributed and/or modified under the
* terms of the GNU General Public License as published by the Free Software
* Foundation, GNU version 3. This project is distributed in the hope that it
* will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* this project. If not, see <https://www.gnu.org/licenses/>.
*
* For any further details and any questions please contact us under
* contact@nymea.io or see our FAQ/Licensing Information on
* https://nymea.io/license/faq
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef IOCONNECTIONWATCHER_H
#define IOCONNECTIONWATCHER_H
#include <QObject>
#include <QUuid>
class IOConnection;
class IOConnections;
class IOInputConnectionWatcher : public QObject
{
Q_OBJECT
Q_PROPERTY(IOConnections* ioConnections READ ioConnections WRITE setIOConnections NOTIFY ioConnectionsChanged)
Q_PROPERTY(QUuid inputThingId READ inputThingId WRITE setInputThingId NOTIFY inputThingIdChanged)
Q_PROPERTY(QUuid inputStateTypeId READ inputStateTypeId WRITE setInputStateTypeId NOTIFY inputStateTypeIdChanged)
Q_PROPERTY(IOConnection* ioConnection READ ioConnection NOTIFY ioConnectionChanged)
public:
explicit IOInputConnectionWatcher(QObject *parent = nullptr);
IOConnections* ioConnections() const;
void setIOConnections(IOConnections *ioConnections);
QUuid inputThingId() const;
void setInputThingId(const QUuid &inputThingId);
QUuid inputStateTypeId() const;
void setInputStateTypeId(const QUuid &inputStateTypeId);
IOConnection* ioConnection() const;
signals:
void ioConnectionsChanged();
void inputThingIdChanged();
void inputStateTypeIdChanged();
void ioConnectionChanged();
private:
IOConnections *m_ioConnections = nullptr;
QUuid m_inputThingId;
QUuid m_inputStateTypeId;
};
class IOOutputConnectionWatcher : public QObject
{
Q_OBJECT
Q_PROPERTY(IOConnections* ioConnections READ ioConnections WRITE setIOConnections NOTIFY ioConnectionsChanged)
Q_PROPERTY(QUuid outputThingId READ outputThingId WRITE setOutputThingId NOTIFY outputThingIdChanged)
Q_PROPERTY(QUuid outputStateTypeId READ outputStateTypeId WRITE setOutputStateTypeId NOTIFY outputStateTypeIdChanged)
Q_PROPERTY(IOConnection* ioConnection READ ioConnection NOTIFY ioConnectionChanged)
public:
explicit IOOutputConnectionWatcher(QObject *parent = nullptr);
IOConnections* ioConnections() const;
void setIOConnections(IOConnections *ioConnections);
QUuid outputThingId() const;
void setOutputThingId(const QUuid &outputThingId);
QUuid outputStateTypeId() const;
void setOutputStateTypeId(const QUuid &outputStateTypeId);
IOConnection* ioConnection() const;
signals:
void ioConnectionsChanged();
void outputThingIdChanged();
void outputStateTypeIdChanged();
void ioConnectionChanged();
private:
IOConnections *m_ioConnections = nullptr;
QUuid m_outputThingId;
QUuid m_outputStateTypeId;
};
#endif // IOCONNECTIONWATCHER_H

View File

@ -149,3 +149,13 @@ void StateType::setMaxValue(const QVariant &maxValue)
{
m_maxValue = maxValue;
}
Types::IOType StateType::ioType() const
{
return m_ioType;
}
void StateType::setIOType(Types::IOType ioType)
{
m_ioType = ioType;
}

View File

@ -48,6 +48,7 @@ class StateType : public QObject
Q_PROPERTY(QVariant defaultValue READ defaultValue CONSTANT)
Q_PROPERTY(QVariantList allowedValues READ allowedValues CONSTANT)
Q_PROPERTY(Types::Unit unit READ unit CONSTANT)
Q_PROPERTY(Types::IOType ioType READ ioType CONSTANT)
Q_PROPERTY(QString unitString READ unitString CONSTANT)
Q_PROPERTY(QVariant minValue READ minValue CONSTANT)
Q_PROPERTY(QVariant maxValue READ maxValue CONSTANT)
@ -80,6 +81,9 @@ public:
Types::Unit unit() const;
void setUnit(const Types::Unit &unit);
Types::IOType ioType() const;
void setIOType(Types::IOType ioType);
QString unitString() const;
void setUnitString(const QString &unitString);
@ -97,7 +101,8 @@ private:
int m_index;
QVariant m_defaultValue;
QVariantList m_allowedValues;
Types::Unit m_unit;
Types::Unit m_unit = Types::UnitNone;
Types::IOType m_ioType = Types::IOTypeNone;
QString m_unitString;
QVariant m_minValue;
QVariant m_maxValue;

View File

@ -87,6 +87,8 @@ QVariant StateTypes::data(const QModelIndex &index, int role) const
return stateType->unitString();
case RoleUnit:
return stateType->unit();
case RoleIOType:
return stateType->ioType();
}
return QVariant();
}
@ -110,6 +112,17 @@ StateType *StateTypes::findByName(const QString &name) const
return nullptr;
}
QList<StateType *> StateTypes::ioStateTypes(Types::IOType ioType) const
{
QList<StateType*> ret;
foreach (StateType* stateType, m_stateTypes) {
if (stateType->ioType() == ioType) {
ret.append(stateType);
}
}
return ret;
}
void StateTypes::clearModel()
{
beginResetModel();
@ -129,6 +142,7 @@ QHash<int, QByteArray> StateTypes::roleNames() const
roles[RoleDefaultValue] = "defaultValue";
roles[RoleUnitString] = "unitString";
roles[RoleUnit] = "unit";
roles[RoleIOType] = "ioType";
return roles;
}

View File

@ -49,10 +49,11 @@ public:
RoleType,
RoleDefaultValue,
RoleUnit,
RoleUnitString
RoleUnitString,
RoleIOType,
};
StateTypes(QObject *parent = 0);
StateTypes(QObject *parent = nullptr);
QList<StateType *> stateTypes();
@ -66,6 +67,8 @@ public:
Q_INVOKABLE StateType *findByName(const QString &name) const;
QList<StateType*> ioStateTypes(Types::IOType ioType) const;
void clearModel();
protected:

View File

@ -0,0 +1,140 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2020, nymea GmbH
* Contact: contact@nymea.io
*
* This file is part of nymea.
* This project including source code and documentation is protected by
* copyright law, and remains the property of nymea GmbH. All rights, including
* reproduction, publication, editing and translation, are reserved. The use of
* this project is subject to the terms of a license agreement to be concluded
* with nymea GmbH in accordance with the terms of use of nymea GmbH, available
* under https://nymea.io/license
*
* GNU General Public License Usage
* Alternatively, this project may be redistributed and/or modified under the
* terms of the GNU General Public License as published by the Free Software
* Foundation, GNU version 3. This project is distributed in the hope that it
* will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* this project. If not, see <https://www.gnu.org/licenses/>.
*
* For any further details and any questions please contact us under
* contact@nymea.io or see our FAQ/Licensing Information on
* https://nymea.io/license/faq
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "statetypesproxy.h"
StateTypesProxy::StateTypesProxy(QObject *parent) : QSortFilterProxyModel(parent)
{
}
StateTypes *StateTypesProxy::stateTypes() const
{
return m_stateTypes;
}
void StateTypesProxy::setStateTypes(StateTypes *stateTypes)
{
if (m_stateTypes != stateTypes) {
m_stateTypes = stateTypes;
setSourceModel(stateTypes);
emit countChanged();
}
}
bool StateTypesProxy::digitalInputs() const
{
return m_digitalInputs;
}
void StateTypesProxy::setDigitalInputs(bool digitalInputs)
{
if (m_digitalInputs != digitalInputs) {
m_digitalInputs = digitalInputs;
emit digitalInputsChanged();
invalidateFilter();
emit countChanged();
}
}
bool StateTypesProxy::digitalOutputs() const
{
return m_digitalOutputs;
}
void StateTypesProxy::setDigitalOutputs(bool digitalOutputs)
{
if (m_digitalOutputs != digitalOutputs) {
m_digitalOutputs = digitalOutputs;
emit digitalOutputsChanged();
invalidateFilter();
emit countChanged();
}
}
bool StateTypesProxy::analogInputs() const
{
return m_analogInputs;
}
void StateTypesProxy::setAnalogInputs(bool analogInputs)
{
if (m_analogInputs != analogInputs) {
m_analogInputs = analogInputs;
emit analogInputsChanged();
invalidateFilter();
emit countChanged();
}
}
bool StateTypesProxy::analogOutputs() const
{
return m_analogOutputs;
}
void StateTypesProxy::setAnalogOutputs(bool analogOutputs)
{
if (m_analogOutputs != analogOutputs) {
m_analogOutputs = analogOutputs;
emit analogOutputsChanged();
invalidateFilter();
emit countChanged();
}
}
StateType *StateTypesProxy::get(int index) const
{
return m_stateTypes->get(mapToSource(this->index(index, 0)).row());
}
bool StateTypesProxy::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const
{
Q_UNUSED(source_parent)
if (!m_digitalInputs && !m_digitalOutputs && !m_analogInputs && !m_analogOutputs) {
// filtering disabled
return true;
}
StateType* stateType = m_stateTypes->get(source_row);
switch (stateType->ioType()) {
case Types::IOTypeNone:
return false;
case Types::IOTypeDigitalInput:
return m_digitalInputs;
case Types::IOTypeDigitalOutput:
return m_digitalOutputs;
case Types::IOTypeAnalogInput:
return m_analogInputs;
case Types::IOTypeAnalogOutput:
return m_analogOutputs;
}
return false;
}

View File

@ -0,0 +1,89 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2020, nymea GmbH
* Contact: contact@nymea.io
*
* This file is part of nymea.
* This project including source code and documentation is protected by
* copyright law, and remains the property of nymea GmbH. All rights, including
* reproduction, publication, editing and translation, are reserved. The use of
* this project is subject to the terms of a license agreement to be concluded
* with nymea GmbH in accordance with the terms of use of nymea GmbH, available
* under https://nymea.io/license
*
* GNU General Public License Usage
* Alternatively, this project may be redistributed and/or modified under the
* terms of the GNU General Public License as published by the Free Software
* Foundation, GNU version 3. This project is distributed in the hope that it
* will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
* of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License along with
* this project. If not, see <https://www.gnu.org/licenses/>.
*
* For any further details and any questions please contact us under
* contact@nymea.io or see our FAQ/Licensing Information on
* https://nymea.io/license/faq
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef STATETYPESPROXY_H
#define STATETYPESPROXY_H
#include <QSortFilterProxyModel>
#include "statetypes.h"
class StateTypesProxy : public QSortFilterProxyModel
{
Q_OBJECT
Q_PROPERTY(int count READ rowCount NOTIFY countChanged)
Q_PROPERTY(StateTypes* stateTypes READ stateTypes WRITE setStateTypes NOTIFY stateTypesChanged)
Q_PROPERTY(bool digitalInputs READ digitalInputs WRITE setDigitalInputs NOTIFY digitalInputsChanged)
Q_PROPERTY(bool digitalOutputs READ digitalOutputs WRITE setDigitalOutputs NOTIFY digitalOutputsChanged)
Q_PROPERTY(bool analogInputs READ analogInputs WRITE setAnalogInputs NOTIFY analogInputsChanged)
Q_PROPERTY(bool analogOutputs READ analogOutputs WRITE setAnalogOutputs NOTIFY analogOutputsChanged)
public:
explicit StateTypesProxy(QObject *parent = nullptr);
StateTypes* stateTypes() const;
void setStateTypes(StateTypes *stateTypes);
bool digitalInputs() const;
void setDigitalInputs(bool digitalInputs);
bool digitalOutputs() const;
void setDigitalOutputs(bool digitalOutputs);
bool analogInputs() const;
void setAnalogInputs(bool analogInputs);
bool analogOutputs() const;
void setAnalogOutputs(bool analogOutputs);
Q_INVOKABLE StateType* get(int index) const;
signals:
void countChanged();
void stateTypesChanged();
void digitalInputsChanged();
void digitalOutputsChanged();
void analogInputsChanged();
void analogOutputsChanged();
protected:
bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override;
private:
StateTypes *m_stateTypes = nullptr;
bool m_digitalInputs = false;
bool m_digitalOutputs = false;
bool m_analogInputs = false;
bool m_analogOutputs = false;
};
#endif // STATETYPESPROXY_H

View File

@ -120,6 +120,15 @@ public:
};
Q_ENUM(Unit)
enum IOType {
IOTypeNone,
IOTypeDigitalInput,
IOTypeDigitalOutput,
IOTypeAnalogInput,
IOTypeAnalogOutput
};
Q_ENUM(IOType)
enum UnitSystem {
UnitSystemMetric,
UnitSystemImperial

View File

@ -218,5 +218,6 @@
<file>ui/images/smartlock.svg</file>
<file>ui/images/key.svg</file>
<file>ui/images/browser/MediaBrowserIconRadioParadise.svg</file>
<file>ui/images/io-connections.svg</file>
</qresource>
</RCC>

View File

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg id="svg4874" width="96" height="96" version="1.1" viewBox="0 0 96 96" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<metadata id="metadata4879">
<rdf:RDF>
<cc:Work rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type rdf:resource="http://purl.org/dc/dcmitype/StillImage"/>
<dc:title/>
</cc:Work>
</rdf:RDF>
</metadata>
<g id="layer1" transform="translate(67.857 -78.505)">
<rect id="rect4782-638" transform="rotate(90)" x="78.505" y="-28.143" width="96" height="96" style="color:#000000;fill:none"/>
<path id="rect4747-4-8" d="m8.1428 140.51 1 4h-45v-4z" style="color:#000000;fill:#808080"/>
<path id="path4175" d="m-47.857 108.5-1 4h45v-4z" style="color:#000000;fill:#808080"/>
<path id="path5839" d="m-5.8725 130.5 0.0076 24c3.65-1.6687 7.3659-3.5359 11.149-5.5987 3.7477-2.0678 7.3628-4.2005 10.843-6.4002-3.4801-2.1558-7.0952-4.2681-10.843-6.3358-3.7853-2.0639-7.5033-3.9519-11.155-5.6652z" style="color:#000000;fill:#808080"/>
<path id="path5856" d="m-33.874 122.52-0.0076-24c-3.65 1.6687-7.3659 3.5359-11.149 5.5987-3.7477 2.0678-7.3628 4.2005-10.843 6.4003 3.48 2.1558 7.0951 4.2681 10.843 6.3358 3.7853 2.0639 7.5033 3.9519 11.155 5.6651z" style="color:#000000;fill:#808080"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -35,7 +35,7 @@ import Nymea 1.0
import "../components"
import "../delegates"
Page {
SettingsPageBase {
id: root
property Device device: null
readonly property DeviceClass deviceClass: device ? device.deviceClass : null
@ -110,120 +110,174 @@ Page {
}
}
Flickable {
anchors.fill: parent
contentHeight: contentColumn.implicitHeight
ColumnLayout {
id: contentColumn
width: parent.width
Label {
Layout.fillWidth: true
Layout.margins: app.margins
text: qsTr("Information")
color: app.accentColor
}
RowLayout {
Layout.leftMargin: app.margins; Layout.rightMargin: app.margins
Label {
text: qsTr("Vendor:")
Layout.fillWidth: true
}
Label {
text: engine.deviceManager.vendors.getVendor(root.deviceClass.vendorId).displayName
}
}
RowLayout {
Layout.leftMargin: app.margins; Layout.rightMargin: app.margins
Label {
text: qsTr("Type")
Layout.fillWidth: true
}
Label {
text: root.deviceClass.displayName
}
}
Label {
Layout.fillWidth: true
Layout.leftMargin: app.margins
Layout.rightMargin: app.margins
Layout.topMargin: app.margins
text: qsTr("Parameters")
color: app.accentColor
visible: root.deviceClass.paramTypes.count > 0
}
Repeater {
model: root.device.params
delegate: ParamDelegate {
Layout.fillWidth: true
paramType: root.deviceClass.paramTypes.getParamType(model.id)
param: root.device.params.get(index)
writable: false
}
}
Label {
Layout.fillWidth: true
Layout.leftMargin: app.margins
Layout.rightMargin: app.margins
Layout.topMargin: app.margins
text: qsTr("Settings")
color: app.accentColor
visible: root.deviceClass.settingsTypes.count > 0
}
Repeater {
id: settingsRepeater
model: root.device.settings
delegate: ParamDelegate {
Layout.fillWidth: true
paramType: root.deviceClass.settingsTypes.getParamType(model.id)
value: root.device.settings.get(index).value
writable: true
property bool dirty: root.device.settings.get(index).value !== value
onDirtyChanged: settingsRepeater.checkDirty()
}
function checkDirty() {
for (var i = 0; i < settingsRepeater.count; i++) {
if (settingsRepeater.itemAt(i).dirty) {
dirty = true;
return;
}
}
dirty = false;
}
property bool dirty: false
}
Button {
Layout.fillWidth: true
Layout.leftMargin: app.margins
Layout.rightMargin: app.margins
text: qsTr("Apply")
enabled: settingsRepeater.dirty
visible: settingsRepeater.count > 0
onClicked: {
var params = []
for (var i = 0; i < settingsRepeater.count; i++) {
if (!settingsRepeater.itemAt(i).dirty) {
continue;
}
var setting = {}
setting["paramTypeId"] = settingsRepeater.itemAt(i).param.paramTypeId
setting["value"] = settingsRepeater.itemAt(i).param.value
params.push(setting)
}
engine.deviceManager.setDeviceSettings(root.device.id, params);
}
}
// ThinDivider {}
Label {
Layout.fillWidth: true
Layout.margins: app.margins
text: qsTr("Information")
color: app.accentColor
}
RowLayout {
Layout.leftMargin: app.margins; Layout.rightMargin: app.margins
Label {
text: qsTr("Vendor:")
Layout.fillWidth: true
}
Label {
text: engine.deviceManager.vendors.getVendor(root.deviceClass.vendorId).displayName
}
}
RowLayout {
Layout.leftMargin: app.margins; Layout.rightMargin: app.margins
Label {
text: qsTr("Type")
Layout.fillWidth: true
}
Label {
text: root.deviceClass.displayName
}
}
Label {
Layout.fillWidth: true
Layout.leftMargin: app.margins
Layout.rightMargin: app.margins
Layout.topMargin: app.margins
text: qsTr("Parameters")
color: app.accentColor
visible: root.deviceClass.paramTypes.count > 0
}
Repeater {
model: root.device.params
delegate: ParamDelegate {
Layout.fillWidth: true
paramType: root.deviceClass.paramTypes.getParamType(model.id)
param: root.device.params.get(index)
writable: false
}
}
Label {
Layout.fillWidth: true
Layout.leftMargin: app.margins
Layout.rightMargin: app.margins
Layout.topMargin: app.margins
text: qsTr("Input/Output Connections")
color: app.accentColor
visible: ioModel.count > 0
}
StateTypesProxy {
id: ioModel
stateTypes: root.deviceClass.stateTypes
digitalInputs: true
digitalOutputs: true
analogInputs: true
analogOutputs: true
}
Repeater {
model: ioModel
delegate: NymeaListItemDelegate {
Layout.fillWidth: true
iconName: "../images/io-connections.svg"
text: model.displayName
subText: {
if (ioStateType.ioType == Types.IOTypeDigitalInput || ioStateType.ioType == Types.IOTypeAnalogInput) {
if (inputConnectionWatcher.ioConnection) {
return "%1: %2".arg(inputConnectionWatcher.outputThing.name).arg(inputConnectionWatcher.outputStateType.displayName)
}
} else {
if (outputConnectionWatcher.ioConnection) {
return "%1: %2".arg(outputConnectionWatcher.inputThing.name).arg(outputConnectionWatcher.inputStateType.displayName)
}
}
return qsTr("Not connected")
}
property StateType ioStateType: ioModel.get(index)
IOInputConnectionWatcher {
id: inputConnectionWatcher
ioConnections: engine.deviceManager.ioConnections
inputThingId: root.device.id
inputStateTypeId: ioStateType.id
property Device outputThing: ioConnection ? engine.deviceManager.devices.getDevice(ioConnection.outputThingId) : null
property StateType outputStateType: ioConnection ? outputThing.deviceClass.stateTypes.getStateType(ioConnection.outputStateTypeId) : null
}
IOOutputConnectionWatcher {
id: outputConnectionWatcher
ioConnections: engine.deviceManager.ioConnections
outputThingId: root.device.id
outputStateTypeId: ioStateType.id
property Device inputThing: ioConnection ? engine.deviceManager.devices.getDevice(ioConnection.inputThingId) : null
property StateType inputStateType: ioConnection ? inputThing.deviceClass.stateTypes.getStateType(ioConnection.inputStateTypeId) : null
}
onClicked: {
var popup = ioConnectionsDialogComponent.createObject(app, {ioStateType: ioStateType, inputWatcher: inputConnectionWatcher, outputWatcher: outputConnectionWatcher})
popup.open()
}
}
}
Label {
Layout.fillWidth: true
Layout.leftMargin: app.margins
Layout.rightMargin: app.margins
Layout.topMargin: app.margins
text: qsTr("Settings")
color: app.accentColor
visible: root.deviceClass.settingsTypes.count > 0
}
Repeater {
id: settingsRepeater
model: root.device.settings
delegate: ParamDelegate {
Layout.fillWidth: true
paramType: root.deviceClass.settingsTypes.getParamType(model.id)
value: root.device.settings.get(index).value
writable: true
property bool dirty: root.device.settings.get(index).value !== value
onDirtyChanged: settingsRepeater.checkDirty()
}
function checkDirty() {
for (var i = 0; i < settingsRepeater.count; i++) {
if (settingsRepeater.itemAt(i).dirty) {
dirty = true;
return;
}
}
dirty = false;
}
property bool dirty: false
}
Button {
Layout.fillWidth: true
Layout.leftMargin: app.margins
Layout.rightMargin: app.margins
text: qsTr("Apply")
enabled: settingsRepeater.dirty
visible: settingsRepeater.count > 0
onClicked: {
var params = []
for (var i = 0; i < settingsRepeater.count; i++) {
if (!settingsRepeater.itemAt(i).dirty) {
continue;
}
var setting = {}
setting["paramTypeId"] = settingsRepeater.itemAt(i).param.paramTypeId
setting["value"] = settingsRepeater.itemAt(i).param.value
params.push(setting)
}
engine.deviceManager.setDeviceSettings(root.device.id, params);
}
}
Component {
@ -264,4 +318,124 @@ Page {
}
}
Component {
id: ioConnectionsDialogComponent
MeaDialog {
id: ioConnectionDialog
standardButtons: Dialog.Ok | Dialog.Cancel | Dialog.Reset
title: qsTr("Connect Inputs/Outputs")
property StateType ioStateType: null
property IOInputConnectionWatcher inputWatcher: null
property IOOutputConnectionWatcher outputWatcher: null
Label {
Layout.fillWidth: true
text: qsTr("Connect \"%1\" to:").arg(ioConnectionDialog.ioStateType.displayName)
wrapMode: Text.WordWrap
}
Label { text: "\n" } // Fake in some spacing
GridLayout {
columns: (ioConnectionDialog.width / 400) * 2
Label {
Layout.fillWidth: true
text: qsTr("Thing")
}
ComboBox {
id: ioThingComboBox
model: DevicesProxy {
id: connectableIODevices
engine: _engine
showDigitalInputs: ioConnectionDialog.ioStateType.ioType == Types.IOTypeDigitalOutput
showDigitalOutputs: ioConnectionDialog.ioStateType.ioType == Types.IOTypeDigitalInput
showAnalogInputs: ioConnectionDialog.ioStateType.ioType == Types.IOTypeAnalogOutput
showAnalogOutputs: ioConnectionDialog.ioStateType.ioType == Types.IOTypeAnalogInput
}
textRole: "name"
Layout.fillWidth: true
Component.onCompleted: {
for (var i = 0; i < connectableIODevices.count; i++) {
if (ioConnectionDialog.ioStateType.ioType == Types.IOTypeDigitalInput || ioConnectionDialog.ioStateType.ioType == Types.IOTypeAnalogInput) {
if (connectableIODevices.get(i).id === ioConnectionDialog.inputWatcher.ioConnection.outputThingId) {
ioThingComboBox.currentIndex = i;
break;
}
} else {
if (connectableIODevices.get(i).id === ioConnectionDialog.outputWatcher.ioConnection.inputThingId) {
ioThingComboBox.currentIndex = i;
break;
}
}
}
}
}
Label {
Layout.fillWidth: true
text: (ioConnectionDialog.ioStateType.ioType == Types.IOTypeDigitalInput || ioConnectionDialog.ioStateType.ioType == Types.IOTypeAnalogInput) ? qsTr("Output") : qsTr("Input")
}
ComboBox {
id: ioStateComboBox
model: StateTypesProxy {
id: connectableStateTypes
stateTypes: connectableIODevices.get(ioThingComboBox.currentIndex).deviceClass.stateTypes
digitalInputs: ioConnectionDialog.ioStateType.ioType == Types.IOTypeDigitalOutput
digitalOutputs: ioConnectionDialog.ioStateType.ioType == Types.IOTypeDigitalInput
analogInputs: ioConnectionDialog.ioStateType.ioType == Types.IOTypeAnalogOutput
analogOutputs: ioConnectionDialog.ioStateType.ioType == Types.IOTypeAnalogInput
}
textRole: "displayName"
Layout.fillWidth: true
onCountChanged: {
// print("loading for:", ioConnectionDialog.inputWatcher.ioConnection.outputStateTypeId)
for (var i = 0; i < connectableStateTypes.count; i++) {
print("checking:", connectableStateTypes.get(i).id)
if (ioConnectionDialog.ioStateType.ioType == Types.IOTypeDigitalInput || ioConnectionDialog.ioStateType.ioType == Types.IOTypeAnalogInput) {
if (connectableStateTypes.get(i).id === ioConnectionDialog.inputWatcher.ioConnection.outputStateTypeId) {
ioStateComboBox.currentIndex = i;
break;
}
} else {
if (connectableStateTypes.get(i).id === ioConnectionDialog.outputWatcher.ioConnection.inputStateTypeId) {
ioStateComboBox.currentIndex = i;
break;
}
}
}
}
}
}
onAccepted: {
var inputThingId;
var inputStateTypeId;
var outputThingId;
var outputStateTypeId;
if (ioConnectionDialog.ioStateType.ioType == Types.IOTypeDigitalInput
|| ioConnectionDialog.ioStateType.ioType == Types.IOTypeAnalogInput) {
inputThingId = root.device.id;
inputStateTypeId = ioConnectionDialog.ioStateType.id;
outputThingId = connectableIODevices.get(ioThingComboBox.currentIndex).id;
outputStateTypeId = connectableStateTypes.get(ioStateComboBox.currentIndex).id;
} else {
inputThingId = connectableIODevices.get(ioThingComboBox.currentIndex).id;
inputStateTypeId = connectableStateTypes.get(ioStateComboBox.currentIndex).id;
outputThingId = root.device.id;
outputStateTypeId = ioConnectionDialog.ioStateType.id;
}
print("connecting", inputThingId, inputStateTypeId, outputThingId, outputStateTypeId)
engine.deviceManager.connectIO(inputThingId, inputStateTypeId, outputThingId, outputStateTypeId);
}
onReset: {
engine.deviceManager.disconnectIO(ioConnectionDialog.watcher.ioConnection.id);
ioConnectionDialog.reject();
}
}
}
}