From b4d97080bdcf1e3a310d8621961623fff903c1e7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Mon, 1 Feb 2021 15:21:14 +0100 Subject: [PATCH 01/24] Add basic modbus rtu hardware resource structure --- debian/control | 1 + ...odbusrtuhardwareresourceimplementation.cpp | 97 +++++++++++++++++++ .../modbusrtuhardwareresourceimplementation.h | 65 +++++++++++++ libnymea-core/jsonrpc/modbusrtuhandler.cpp | 45 +++++++++ libnymea-core/jsonrpc/modbusrtuhandler.h | 54 +++++++++++ libnymea-core/libnymea-core.pro | 19 ++++ libnymea-core/modbus/modbusrtumanager.cpp | 44 +++++++++ libnymea-core/modbus/modbusrtumanager.h | 50 ++++++++++ libnymea-core/modbus/modbusrtumaster.cpp | 40 ++++++++ libnymea-core/modbus/modbusrtumaster.h | 50 ++++++++++ .../modbus/modbusrtuhardwareresource.cpp | 37 +++++++ .../modbus/modbusrtuhardwareresource.h | 48 +++++++++ libnymea/libnymea.pro | 2 + 13 files changed, 552 insertions(+) create mode 100644 libnymea-core/hardware/modbus/modbusrtuhardwareresourceimplementation.cpp create mode 100644 libnymea-core/hardware/modbus/modbusrtuhardwareresourceimplementation.h create mode 100644 libnymea-core/jsonrpc/modbusrtuhandler.cpp create mode 100644 libnymea-core/jsonrpc/modbusrtuhandler.h create mode 100644 libnymea-core/modbus/modbusrtumanager.cpp create mode 100644 libnymea-core/modbus/modbusrtumanager.h create mode 100644 libnymea-core/modbus/modbusrtumaster.cpp create mode 100644 libnymea-core/modbus/modbusrtumaster.h create mode 100644 libnymea/hardware/modbus/modbusrtuhardwareresource.cpp create mode 100644 libnymea/hardware/modbus/modbusrtuhardwareresource.h diff --git a/debian/control b/debian/control index 0581cb77..825ff765 100644 --- a/debian/control +++ b/debian/control @@ -26,6 +26,7 @@ Build-Depends: debhelper (>= 9.0.0), qttools5-dev-tools, qtconnectivity5-dev, qtdeclarative5-dev, + | libqt5serialbus5-dev (>= 5.8~) Package: nymea Architecture: any diff --git a/libnymea-core/hardware/modbus/modbusrtuhardwareresourceimplementation.cpp b/libnymea-core/hardware/modbus/modbusrtuhardwareresourceimplementation.cpp new file mode 100644 index 00000000..26d347ec --- /dev/null +++ b/libnymea-core/hardware/modbus/modbusrtuhardwareresourceimplementation.cpp @@ -0,0 +1,97 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2021, 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 Lesser General Public License Usage +* Alternatively, this project may be redistributed and/or modified under the +* terms of the GNU Lesser General Public License as published by the Free +* Software Foundation; 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 +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License +* along with this project. If not, see . +* +* 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 "modbusrtuhardwareresourceimplementation.h" +#include "loggingcategories.h" +#include "nymeasettings.h" + +NYMEA_LOGGING_CATEGORY(dcModbusRtuResource, "ModbusRtuResource") + +namespace nymeaserver { + +ModbusRtuHardwareResourceImplementation::ModbusRtuHardwareResourceImplementation(QObject *parent) : + ModbusRtuHardwareResource(parent) +{ + +} + +bool ModbusRtuHardwareResourceImplementation::available() const +{ + return m_available; +} + +bool ModbusRtuHardwareResourceImplementation::enabled() const +{ + return m_enabled; +} + +bool ModbusRtuHardwareResourceImplementation::enable() +{ + qCWarning(dcModbusRtuResource()) << "Enable hardware resource. Not implemented yet."; + + // TODO: enable all modbus clients + + return true; +} + +bool ModbusRtuHardwareResourceImplementation::disable() +{ + qCWarning(dcModbusRtuResource()) << "Disable hardware resource. Not implemented yet."; + + // TODO: disable all modbus clients + + return true; +} + +void ModbusRtuHardwareResourceImplementation::setEnabled(bool enabled) +{ + qCDebug(dcModbusRtuResource()) << "Set" << (enabled ? "enabled" : "disabled"); + if (m_enabled && enabled) { + qCDebug(dcModbusRtuResource()) << "Already enabled."; + return; + } else if (!m_enabled && !enabled) { + qCDebug(dcModbusRtuResource()) << "Already disabled."; + return; + } + + bool success = false; + if (enabled) { + success = enable(); + } else { + success = disable(); + } + + if (success) { + m_enabled = enabled; + emit enabledChanged(m_enabled); + } +} + +} diff --git a/libnymea-core/hardware/modbus/modbusrtuhardwareresourceimplementation.h b/libnymea-core/hardware/modbus/modbusrtuhardwareresourceimplementation.h new file mode 100644 index 00000000..8fd10b2d --- /dev/null +++ b/libnymea-core/hardware/modbus/modbusrtuhardwareresourceimplementation.h @@ -0,0 +1,65 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2021, 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 Lesser General Public License Usage +* Alternatively, this project may be redistributed and/or modified under the +* terms of the GNU Lesser General Public License as published by the Free +* Software Foundation; 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 +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License +* along with this project. If not, see . +* +* 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 MODBUSRTUHARDWARERESOURCEIMPLEMENTATION_H +#define MODBUSRTUHARDWARERESOURCEIMPLEMENTATION_H + +#include + +#include "hardware/modbus/modbusrtuhardwareresource.h" + +namespace nymeaserver { + +class ModbusRtuHardwareResourceImplementation : public ModbusRtuHardwareResource +{ + Q_OBJECT +public: + explicit ModbusRtuHardwareResourceImplementation(QObject *parent = nullptr); + + bool available() const override; + bool enabled() const override; + +public slots: + bool enable(); + bool disable(); + + +protected: + void setEnabled(bool enabled) override; + +private: + bool m_available = false; + bool m_enabled = false; + +}; + +} + +#endif // MODBUSRTUHARDWARERESOURCEIMPLEMENTATION_H diff --git a/libnymea-core/jsonrpc/modbusrtuhandler.cpp b/libnymea-core/jsonrpc/modbusrtuhandler.cpp new file mode 100644 index 00000000..535deb6b --- /dev/null +++ b/libnymea-core/jsonrpc/modbusrtuhandler.cpp @@ -0,0 +1,45 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2021, 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 Lesser General Public License Usage +* Alternatively, this project may be redistributed and/or modified under the +* terms of the GNU Lesser General Public License as published by the Free +* Software Foundation; 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 +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License +* along with this project. If not, see . +* +* 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 "modbusrtuhandler.h" + +namespace nymeaserver { + +ModbusRtuHandler::ModbusRtuHandler(QObject *parent) : JsonHandler(parent) +{ + +} + +QString ModbusRtuHandler::name() const +{ + return "ModbusRtu"; +} + +} diff --git a/libnymea-core/jsonrpc/modbusrtuhandler.h b/libnymea-core/jsonrpc/modbusrtuhandler.h new file mode 100644 index 00000000..a0242525 --- /dev/null +++ b/libnymea-core/jsonrpc/modbusrtuhandler.h @@ -0,0 +1,54 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2021, 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 Lesser General Public License Usage +* Alternatively, this project may be redistributed and/or modified under the +* terms of the GNU Lesser General Public License as published by the Free +* Software Foundation; 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 +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License +* along with this project. If not, see . +* +* 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 MODBUSRTUHANDLER_H +#define MODBUSRTUHANDLER_H + +#include + +#include "jsonrpc/jsonhandler.h" + +namespace nymeaserver { + +class ModbusRtuHandler : public JsonHandler +{ + Q_OBJECT +public: + explicit ModbusRtuHandler(QObject *parent = nullptr); + + QString name() const override; + +signals: + +}; + +} + +#endif // MODBUSRTUHANDLER_H diff --git a/libnymea-core/libnymea-core.pro b/libnymea-core/libnymea-core.pro index 1d2d0197..6847069d 100644 --- a/libnymea-core/libnymea-core.pro +++ b/libnymea-core/libnymea-core.pro @@ -35,6 +35,17 @@ CONFIG(withoutpython) { CONFIG -= python } +# Qt serial bus module is officially available since Qt 5.8 +# but not all platforms host the qt serialbus package. +# Let's check if the package exists, not the qt version +packagesExist(Qt5SerialBus) { + DEFINES += WITH_QTSERIALBUS + Qt += serialbus +} else { + message("Qt5SerialBus not available") +} + + target.path = $$[QT_INSTALL_LIBS] INSTALLS += target @@ -44,6 +55,7 @@ RESOURCES += $$top_srcdir/icons.qrc \ HEADERS += nymeacore.h \ + hardware/modbus/modbusrtuhardwareresourceimplementation.h \ integrations/apikeysprovidersloader.h \ integrations/plugininfocache.h \ integrations/python/pyapikeystorage.h \ @@ -55,7 +67,10 @@ HEADERS += nymeacore.h \ integrations/thingmanagerimplementation.h \ integrations/translator.h \ experiences/experiencemanager.h \ + jsonrpc/modbusrtuhandler.h \ jsonrpc/zigbeehandler.h \ + modbus/modbusrtumanager.h \ + modbus/modbusrtumaster.h \ ruleengine/ruleengine.h \ ruleengine/rule.h \ ruleengine/stateevaluator.h \ @@ -138,12 +153,16 @@ HEADERS += nymeacore.h \ SOURCES += nymeacore.cpp \ + hardware/modbus/modbusrtuhardwareresourceimplementation.cpp \ integrations/apikeysprovidersloader.cpp \ integrations/plugininfocache.cpp \ integrations/thingmanagerimplementation.cpp \ integrations/translator.cpp \ experiences/experiencemanager.cpp \ + jsonrpc/modbusrtuhandler.cpp \ jsonrpc/zigbeehandler.cpp \ + modbus/modbusrtumanager.cpp \ + modbus/modbusrtumaster.cpp \ ruleengine/ruleengine.cpp \ ruleengine/rule.cpp \ ruleengine/stateevaluator.cpp \ diff --git a/libnymea-core/modbus/modbusrtumanager.cpp b/libnymea-core/modbus/modbusrtumanager.cpp new file mode 100644 index 00000000..af2edba9 --- /dev/null +++ b/libnymea-core/modbus/modbusrtumanager.cpp @@ -0,0 +1,44 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2021, 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 Lesser General Public License Usage +* Alternatively, this project may be redistributed and/or modified under the +* terms of the GNU Lesser General Public License as published by the Free +* Software Foundation; 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 +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License +* along with this project. If not, see . +* +* 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 "modbusrtumanager.h" +#include "nymeasettings.h" +#include "loggingcategories.h" + +NYMEA_LOGGING_CATEGORY(dcModbusRtu, "ModbusRtu") + +namespace nymeaserver { + +ModbusRtuManager::ModbusRtuManager(QObject *parent) : QObject(parent) +{ + +} + +} diff --git a/libnymea-core/modbus/modbusrtumanager.h b/libnymea-core/modbus/modbusrtumanager.h new file mode 100644 index 00000000..47ddfdbb --- /dev/null +++ b/libnymea-core/modbus/modbusrtumanager.h @@ -0,0 +1,50 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2021, 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 Lesser General Public License Usage +* Alternatively, this project may be redistributed and/or modified under the +* terms of the GNU Lesser General Public License as published by the Free +* Software Foundation; 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 +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License +* along with this project. If not, see . +* +* 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 MODBUSRTUMANAGER_H +#define MODBUSRTUMANAGER_H + +#include + +namespace nymeaserver { + +class ModbusRtuManager : public QObject +{ + Q_OBJECT +public: + explicit ModbusRtuManager(QObject *parent = nullptr); + +signals: + +}; + +} + +#endif // MODBUSRTUMANAGER_H diff --git a/libnymea-core/modbus/modbusrtumaster.cpp b/libnymea-core/modbus/modbusrtumaster.cpp new file mode 100644 index 00000000..69f98b13 --- /dev/null +++ b/libnymea-core/modbus/modbusrtumaster.cpp @@ -0,0 +1,40 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2021, 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 Lesser General Public License Usage +* Alternatively, this project may be redistributed and/or modified under the +* terms of the GNU Lesser General Public License as published by the Free +* Software Foundation; 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 +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License +* along with this project. If not, see . +* +* 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 "modbusrtumaster.h" + +namespace nymeaserver { + +ModbusRtuMaster::ModbusRtuMaster(QObject *parent) : QObject(parent) +{ + +} + +} diff --git a/libnymea-core/modbus/modbusrtumaster.h b/libnymea-core/modbus/modbusrtumaster.h new file mode 100644 index 00000000..8cc42e52 --- /dev/null +++ b/libnymea-core/modbus/modbusrtumaster.h @@ -0,0 +1,50 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2021, 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 Lesser General Public License Usage +* Alternatively, this project may be redistributed and/or modified under the +* terms of the GNU Lesser General Public License as published by the Free +* Software Foundation; 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 +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License +* along with this project. If not, see . +* +* 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 MODBUSRTUMASTER_H +#define MODBUSRTUMASTER_H + +#include + +namespace nymeaserver { + +class ModbusRtuMaster : public QObject +{ + Q_OBJECT +public: + explicit ModbusRtuMaster(QObject *parent = nullptr); + +signals: + +}; + +} + +#endif // MODBUSRTUMASTER_H diff --git a/libnymea/hardware/modbus/modbusrtuhardwareresource.cpp b/libnymea/hardware/modbus/modbusrtuhardwareresource.cpp new file mode 100644 index 00000000..2b9be8a4 --- /dev/null +++ b/libnymea/hardware/modbus/modbusrtuhardwareresource.cpp @@ -0,0 +1,37 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2021, 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 Lesser General Public License Usage +* Alternatively, this project may be redistributed and/or modified under the +* terms of the GNU Lesser General Public License as published by the Free +* Software Foundation; 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 +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License +* along with this project. If not, see . +* +* 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 "modbusrtuhardwareresource.h" + +ModbusRtuHardwareResource::ModbusRtuHardwareResource(QObject *parent) : + HardwareResource("Modbus RTU client resource", parent) +{ + +} diff --git a/libnymea/hardware/modbus/modbusrtuhardwareresource.h b/libnymea/hardware/modbus/modbusrtuhardwareresource.h new file mode 100644 index 00000000..a6cfc497 --- /dev/null +++ b/libnymea/hardware/modbus/modbusrtuhardwareresource.h @@ -0,0 +1,48 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2021, 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 Lesser General Public License Usage +* Alternatively, this project may be redistributed and/or modified under the +* terms of the GNU Lesser General Public License as published by the Free +* Software Foundation; 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 +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License +* along with this project. If not, see . +* +* 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 MODBUSRTUHARDWARERESOURCE_H +#define MODBUSRTUHARDWARERESOURCE_H + +#include +#include "hardwareresource.h" + +class ModbusRtuHardwareResource : public HardwareResource +{ + Q_OBJECT +public: + explicit ModbusRtuHardwareResource(QObject *parent = nullptr); + virtual ~ModbusRtuHardwareResource() = default; + +signals: + +}; + +#endif // MODBUSRTUHARDWARERESOURCE_H diff --git a/libnymea/libnymea.pro b/libnymea/libnymea.pro index 02e7b57f..b9de355e 100644 --- a/libnymea/libnymea.pro +++ b/libnymea/libnymea.pro @@ -13,6 +13,7 @@ PKGCONFIG += nymea-zigbee nymea-mqtt QMAKE_LFLAGS += -fPIC HEADERS += \ + hardware/modbus/modbusrtuhardwareresource.h \ hardware/zigbee/zigbeehandler.h \ hardware/zigbee/zigbeehardwareresource.h \ integrations/browseractioninfo.h \ @@ -108,6 +109,7 @@ HEADERS += \ experiences/experienceplugin.h \ SOURCES += \ + hardware/modbus/modbusrtuhardwareresource.cpp \ hardware/zigbee/zigbeehandler.cpp \ hardware/zigbee/zigbeehardwareresource.cpp \ integrations/browseractioninfo.cpp \ From 01262b43e9db22030e322832ed22b1e630d4fa68 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Thu, 4 Feb 2021 18:05:47 +0100 Subject: [PATCH 02/24] Add basic structure of the resource and start implement modbus rtu master --- ...odbusrtuhardwareresourceimplementation.cpp | 11 +- .../modbusrtuhardwareresourceimplementation.h | 7 +- .../hardwaremanagerimplementation.cpp | 6 + libnymea-core/hardwaremanagerimplementation.h | 2 + libnymea-core/libnymea-core.pro | 12 +- libnymea-core/modbus/modbusrtumanager.cpp | 28 +++ libnymea-core/modbus/modbusrtumanager.h | 16 ++ libnymea-core/modbus/modbusrtumasterimpl.cpp | 218 ++++++++++++++++++ libnymea-core/modbus/modbusrtumasterimpl.h | 83 +++++++ libnymea-core/modbus/modbusrtureplyimpl.cpp | 94 ++++++++ ...dbusrtumaster.cpp => modbusrtureplyimpl.h} | 39 +++- .../modbus/modbusrtuhardwareresource.cpp | 2 +- .../modbus/modbusrtuhardwareresource.h | 6 + libnymea/hardware/modbus/modbusrtumaster.h | 70 ++++++ .../hardware/modbus/modbusrtureply.h | 42 +++- libnymea/hardwaremanager.h | 2 + libnymea/libnymea.pro | 2 + 17 files changed, 618 insertions(+), 22 deletions(-) create mode 100644 libnymea-core/modbus/modbusrtumasterimpl.cpp create mode 100644 libnymea-core/modbus/modbusrtumasterimpl.h create mode 100644 libnymea-core/modbus/modbusrtureplyimpl.cpp rename libnymea-core/modbus/{modbusrtumaster.cpp => modbusrtureplyimpl.h} (60%) create mode 100644 libnymea/hardware/modbus/modbusrtumaster.h rename libnymea-core/modbus/modbusrtumaster.h => libnymea/hardware/modbus/modbusrtureply.h (63%) diff --git a/libnymea-core/hardware/modbus/modbusrtuhardwareresourceimplementation.cpp b/libnymea-core/hardware/modbus/modbusrtuhardwareresourceimplementation.cpp index 26d347ec..902d75ba 100644 --- a/libnymea-core/hardware/modbus/modbusrtuhardwareresourceimplementation.cpp +++ b/libnymea-core/hardware/modbus/modbusrtuhardwareresourceimplementation.cpp @@ -31,17 +31,24 @@ #include "modbusrtuhardwareresourceimplementation.h" #include "loggingcategories.h" #include "nymeasettings.h" +#include "modbus/modbusrtumanager.h" NYMEA_LOGGING_CATEGORY(dcModbusRtuResource, "ModbusRtuResource") namespace nymeaserver { -ModbusRtuHardwareResourceImplementation::ModbusRtuHardwareResourceImplementation(QObject *parent) : - ModbusRtuHardwareResource(parent) +ModbusRtuHardwareResourceImplementation::ModbusRtuHardwareResourceImplementation(ModbusRtuManager *modbusRtuManager, QObject *parent) : + ModbusRtuHardwareResource(parent), + m_modbusRtuManager(modbusRtuManager) { } +//QList ModbusRtuHardwareResourceImplementation::modbusRtuMasters() const +//{ +// return m_modbusRtuManager->modbusRtuMasters(); +//} + bool ModbusRtuHardwareResourceImplementation::available() const { return m_available; diff --git a/libnymea-core/hardware/modbus/modbusrtuhardwareresourceimplementation.h b/libnymea-core/hardware/modbus/modbusrtuhardwareresourceimplementation.h index 8fd10b2d..ef33dd69 100644 --- a/libnymea-core/hardware/modbus/modbusrtuhardwareresourceimplementation.h +++ b/libnymea-core/hardware/modbus/modbusrtuhardwareresourceimplementation.h @@ -33,6 +33,7 @@ #include +#include "modbus/modbusrtumanager.h" #include "hardware/modbus/modbusrtuhardwareresource.h" namespace nymeaserver { @@ -41,7 +42,9 @@ class ModbusRtuHardwareResourceImplementation : public ModbusRtuHardwareResource { Q_OBJECT public: - explicit ModbusRtuHardwareResourceImplementation(QObject *parent = nullptr); + explicit ModbusRtuHardwareResourceImplementation(ModbusRtuManager *modbusRtuManager, QObject *parent = nullptr); + + //QList modbusRtuMasters() const override; bool available() const override; bool enabled() const override; @@ -50,11 +53,11 @@ public slots: bool enable(); bool disable(); - protected: void setEnabled(bool enabled) override; private: + ModbusRtuManager *m_modbusRtuManager = nullptr; bool m_available = false; bool m_enabled = false; diff --git a/libnymea-core/hardwaremanagerimplementation.cpp b/libnymea-core/hardwaremanagerimplementation.cpp index 8d19558c..754924f0 100644 --- a/libnymea-core/hardwaremanagerimplementation.cpp +++ b/libnymea-core/hardwaremanagerimplementation.cpp @@ -43,6 +43,7 @@ #include "hardware/network/mqtt/mqttproviderimplementation.h" #include "hardware/i2c/i2cmanagerimplementation.h" #include "hardware/zigbee/zigbeehardwareresourceimplementation.h" +#include "hardware/modbus/modbusrtuhardwareresourceimplementation.h" namespace nymeaserver { @@ -142,6 +143,11 @@ ZigbeeHardwareResource *HardwareManagerImplementation::zigbeeResource() return m_zigbeeResource; } +ModbusRtuHardwareResouce *HardwareManagerImplementation::modbusRtuResource() +{ + return m_modbusRtuResource; +} + void HardwareManagerImplementation::thingsLoaded() { m_zigbeeResource->thingsLoaded(); diff --git a/libnymea-core/hardwaremanagerimplementation.h b/libnymea-core/hardwaremanagerimplementation.h index 8a67e54e..3d799adf 100644 --- a/libnymea-core/hardwaremanagerimplementation.h +++ b/libnymea-core/hardwaremanagerimplementation.h @@ -61,6 +61,7 @@ public: MqttProvider *mqttProvider() override; I2CManager *i2cManager() override; ZigbeeHardwareResource *zigbeeResource() override; + ModbusRtuHardwareResouce *modbusRtuResource() override; public slots: void thingsLoaded(); @@ -79,6 +80,7 @@ private: MqttProvider *m_mqttProvider = nullptr; I2CManager *m_i2cManager = nullptr; ZigbeeHardwareResourceImplementation *m_zigbeeResource = nullptr; + ModbusRtuHardwareResouce *m_modbusRtuResource = nullptr; }; } diff --git a/libnymea-core/libnymea-core.pro b/libnymea-core/libnymea-core.pro index 6847069d..c427f3d6 100644 --- a/libnymea-core/libnymea-core.pro +++ b/libnymea-core/libnymea-core.pro @@ -40,7 +40,7 @@ CONFIG(withoutpython) { # Let's check if the package exists, not the qt version packagesExist(Qt5SerialBus) { DEFINES += WITH_QTSERIALBUS - Qt += serialbus + Qt += serialbus serialport } else { message("Qt5SerialBus not available") } @@ -55,7 +55,6 @@ RESOURCES += $$top_srcdir/icons.qrc \ HEADERS += nymeacore.h \ - hardware/modbus/modbusrtuhardwareresourceimplementation.h \ integrations/apikeysprovidersloader.h \ integrations/plugininfocache.h \ integrations/python/pyapikeystorage.h \ @@ -70,7 +69,8 @@ HEADERS += nymeacore.h \ jsonrpc/modbusrtuhandler.h \ jsonrpc/zigbeehandler.h \ modbus/modbusrtumanager.h \ - modbus/modbusrtumaster.h \ + modbus/modbusrtumasterimpl.h \ + modbus/modbusrtureplyimpl.h \ ruleengine/ruleengine.h \ ruleengine/rule.h \ ruleengine/stateevaluator.h \ @@ -133,6 +133,7 @@ HEADERS += nymeacore.h \ hardware/bluetoothlowenergy/bluetoothlowenergymanagerimplementation.h \ hardware/bluetoothlowenergy/bluetoothlowenergydeviceimplementation.h \ hardware/bluetoothlowenergy/bluetoothdiscoveryreplyimplementation.h \ + hardware/modbus/modbusrtuhardwareresourceimplementation.h \ hardware/network/networkaccessmanagerimpl.h \ hardware/network/upnp/upnpdiscoveryimplementation.h \ hardware/network/upnp/upnpdiscoveryrequest.h \ @@ -153,7 +154,6 @@ HEADERS += nymeacore.h \ SOURCES += nymeacore.cpp \ - hardware/modbus/modbusrtuhardwareresourceimplementation.cpp \ integrations/apikeysprovidersloader.cpp \ integrations/plugininfocache.cpp \ integrations/thingmanagerimplementation.cpp \ @@ -162,7 +162,8 @@ SOURCES += nymeacore.cpp \ jsonrpc/modbusrtuhandler.cpp \ jsonrpc/zigbeehandler.cpp \ modbus/modbusrtumanager.cpp \ - modbus/modbusrtumaster.cpp \ + modbus/modbusrtumasterimpl.cpp \ + modbus/modbusrtureplyimpl.cpp \ ruleengine/ruleengine.cpp \ ruleengine/rule.cpp \ ruleengine/stateevaluator.cpp \ @@ -224,6 +225,7 @@ SOURCES += nymeacore.cpp \ hardware/bluetoothlowenergy/bluetoothlowenergymanagerimplementation.cpp \ hardware/bluetoothlowenergy/bluetoothlowenergydeviceimplementation.cpp \ hardware/bluetoothlowenergy/bluetoothdiscoveryreplyimplementation.cpp \ + hardware/modbus/modbusrtuhardwareresourceimplementation.cpp \ hardware/network/networkaccessmanagerimpl.cpp \ hardware/network/upnp/upnpdiscoveryimplementation.cpp \ hardware/network/upnp/upnpdiscoveryrequest.cpp \ diff --git a/libnymea-core/modbus/modbusrtumanager.cpp b/libnymea-core/modbus/modbusrtumanager.cpp index af2edba9..12d51bfc 100644 --- a/libnymea-core/modbus/modbusrtumanager.cpp +++ b/libnymea-core/modbus/modbusrtumanager.cpp @@ -41,4 +41,32 @@ ModbusRtuManager::ModbusRtuManager(QObject *parent) : QObject(parent) } +QList ModbusRtuManager::modbusRtuMasters() const +{ + return m_modbusRtuMasters.values(); +} + +bool ModbusRtuManager::hasModbusRtuMaster(const QUuid &modbusUuid) const +{ + return m_modbusRtuMasters.value(modbusUuid) != nullptr; +} + +ModbusRtuMaster *ModbusRtuManager::getModbusRtuMaster(const QUuid &modbusUuid) +{ + if (hasModbusRtuMaster(modbusUuid)) { + return m_modbusRtuMasters.value(modbusUuid); + } + + return nullptr; +} + +void ModbusRtuManager::init() +{ + // Load uart configurations + + // Init modbus rtu masters + + // Connect signals +} + } diff --git a/libnymea-core/modbus/modbusrtumanager.h b/libnymea-core/modbus/modbusrtumanager.h index 47ddfdbb..f31dca9a 100644 --- a/libnymea-core/modbus/modbusrtumanager.h +++ b/libnymea-core/modbus/modbusrtumanager.h @@ -32,6 +32,9 @@ #define MODBUSRTUMANAGER_H #include +#include + +#include "hardware/modbus/modbusrtumaster.h" namespace nymeaserver { @@ -40,8 +43,21 @@ class ModbusRtuManager : public QObject Q_OBJECT public: explicit ModbusRtuManager(QObject *parent = nullptr); + ~ModbusRtuManager() = default; + + QList modbusRtuMasters() const; + bool hasModbusRtuMaster(const QUuid &modbusUuid) const; + ModbusRtuMaster *getModbusRtuMaster(const QUuid &modbusUuid); + + void init(); signals: + void modbusRtuMasterAdded(ModbusRtuMaster *modbusRtuMaster); + void modbusRtuMasterRemoved(ModbusRtuMaster *modbusRtuMaster); + void modbusRtuMasterChanged(ModbusRtuMaster *modbusRtuMaster); + +private: + QHash m_modbusRtuMasters; }; diff --git a/libnymea-core/modbus/modbusrtumasterimpl.cpp b/libnymea-core/modbus/modbusrtumasterimpl.cpp new file mode 100644 index 00000000..ba6c3406 --- /dev/null +++ b/libnymea-core/modbus/modbusrtumasterimpl.cpp @@ -0,0 +1,218 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2021, 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 Lesser General Public License Usage +* Alternatively, this project may be redistributed and/or modified under the +* terms of the GNU Lesser General Public License as published by the Free +* Software Foundation; 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 +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License +* along with this project. If not, see . +* +* 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 "modbusrtumasterimpl.h" +#include "modbusrtureplyimpl.h" + +#ifdef WITH_QTSERIALBUS +#include +#include +#endif + +Q_DECLARE_LOGGING_CATEGORY(dcModbusRtu) + +namespace nymeaserver { + +ModbusRtuMasterImpl::ModbusRtuMasterImpl(const QUuid &modbusUuid, const QString &serialPort, qint32 baudrate, QSerialPort::Parity parity, QSerialPort::DataBits dataBits, QSerialPort::StopBits stopBits, QObject *parent) : + ModbusRtuMaster(parent), + m_modbusUuid(modbusUuid) +{ +#ifdef WITH_QTSERIALBUS + m_modbus = new QModbusRtuSerialMaster(this); + m_modbus->setConnectionParameter(QModbusDevice::SerialPortNameParameter, serialPort); + m_modbus->setConnectionParameter(QModbusDevice::SerialBaudRateParameter, baudrate); + m_modbus->setConnectionParameter(QModbusDevice::SerialDataBitsParameter, dataBits); + m_modbus->setConnectionParameter(QModbusDevice::SerialStopBitsParameter, stopBits); + m_modbus->setConnectionParameter(QModbusDevice::SerialParityParameter, parity); + + connect(m_modbus, &QModbusTcpClient::stateChanged, this, [=](QModbusDevice::State state){ + qCDebug(dcModbusRtu()) << "Connection state changed" << m_modbusUuid.toString() << serialPort << state; + }); + //connect(m_modbus, &QModbusRtuSerialMaster::errorOccurred, this, &ModbusRtuMaster::onModbusErrorOccurred); + +// m_reconnectTimer = new QTimer(this); +// m_reconnectTimer->setSingleShot(true); +// connect(m_reconnectTimer, &QTimer::timeout, this, &ModbusRTUMaster::onReconnectTimer); + +#endif +} + +QUuid ModbusRtuMasterImpl::modbusUuid() const +{ + return m_modbusUuid; +} + +QString ModbusRtuMasterImpl::serialPort() const +{ + return m_serialPort; +} + +bool ModbusRtuMasterImpl::connected() const +{ + return m_connected; +} + +ModbusRtuReply *ModbusRtuMasterImpl::readCoil(uint slaveAddress, uint registerAddress, uint size) +{ +#ifndef WITH_QTSERIALBUS + Q_UNUSED(slaveAddress) + Q_UNUSED(registerAddress) + Q_UNUSED(size) + return nullptr; +#else + + QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::Coils, registerAddress, size); + QModbusReply *modbusReply = m_modbus->sendReadRequest(request, slaveAddress); + + // TODO: fill data and return reply + ModbusRtuReplyImpl *reply = new ModbusRtuReplyImpl(slaveAddress, registerAddress, this); + connect(modbusReply, &QModbusReply::finished, modbusReply, [=](){ + if (modbusReply->error() != QModbusDevice::NoError) { + qCWarning(dcModbusRtu()) << "Read coil request finished with error" << modbusReply->error() << modbusReply->errorString(); + + } + }); + return qobject_cast(reply); +#endif +} + +ModbusRtuReply *ModbusRtuMasterImpl::readDiscreteInput(uint slaveAddress, uint registerAddress, uint size) +{ +#ifndef WITH_QTSERIALBUS + Q_UNUSED(slaveAddress) + Q_UNUSED(registerAddress) + Q_UNUSED(size) + return nullptr; +#else + // TODO: + Q_UNUSED(slaveAddress) + Q_UNUSED(registerAddress) + Q_UNUSED(size) + return nullptr; +#endif +} + +ModbusRtuReply *ModbusRtuMasterImpl::readInputRegister(uint slaveAddress, uint registerAddress, uint size) +{ +#ifndef WITH_QTSERIALBUS + Q_UNUSED(slaveAddress) + Q_UNUSED(registerAddress) + Q_UNUSED(size) + return nullptr; +#else + // TODO: + Q_UNUSED(slaveAddress) + Q_UNUSED(registerAddress) + Q_UNUSED(size) + return nullptr; +#endif +} + +ModbusRtuReply *ModbusRtuMasterImpl::readHoldingRegister(uint slaveAddress, uint registerAddress, uint size) +{ +#ifndef WITH_QTSERIALBUS + Q_UNUSED(slaveAddress) + Q_UNUSED(registerAddress) + Q_UNUSED(size) + return nullptr; +#else + // TODO: + Q_UNUSED(slaveAddress) + Q_UNUSED(registerAddress) + Q_UNUSED(size) + return nullptr; +#endif +} + +ModbusRtuReply *ModbusRtuMasterImpl::writeCoil(uint slaveAddress, uint registerAddress, bool status) +{ +#ifndef WITH_QTSERIALBUS + Q_UNUSED(slaveAddress) + Q_UNUSED(registerAddress) + Q_UNUSED(size) + return nullptr; +#else + // TODO: + Q_UNUSED(slaveAddress) + Q_UNUSED(registerAddress) + Q_UNUSED(status) + return nullptr; +#endif +} + +ModbusRtuReply *ModbusRtuMasterImpl::writeCoils(uint slaveAddress, uint registerAddress, const QVector &values) +{ +#ifndef WITH_QTSERIALBUS + Q_UNUSED(slaveAddress) + Q_UNUSED(registerAddress) + Q_UNUSED(values) + return nullptr; +#else + // TODO: + Q_UNUSED(slaveAddress) + Q_UNUSED(registerAddress) + Q_UNUSED(values) + return nullptr; +#endif +} + +ModbusRtuReply *ModbusRtuMasterImpl::writeHoldingRegister(uint slaveAddress, uint registerAddress, quint16 value) +{ +#ifndef WITH_QTSERIALBUS + Q_UNUSED(slaveAddress) + Q_UNUSED(registerAddress) + Q_UNUSED(value) + return nullptr; +#else + // TODO: + Q_UNUSED(slaveAddress) + Q_UNUSED(registerAddress) + Q_UNUSED(value) + return nullptr; +#endif +} + +ModbusRtuReply *ModbusRtuMasterImpl::writeHoldingRegisters(uint slaveAddress, uint registerAddress, const QVector &values) +{ +#ifndef WITH_QTSERIALBUS + Q_UNUSED(slaveAddress) + Q_UNUSED(registerAddress) + Q_UNUSED(values) + return nullptr; +#else + // TODO: + Q_UNUSED(slaveAddress) + Q_UNUSED(registerAddress) + Q_UNUSED(values) + return nullptr; +#endif +} + +} diff --git a/libnymea-core/modbus/modbusrtumasterimpl.h b/libnymea-core/modbus/modbusrtumasterimpl.h new file mode 100644 index 00000000..b47f6b7a --- /dev/null +++ b/libnymea-core/modbus/modbusrtumasterimpl.h @@ -0,0 +1,83 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2021, 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 Lesser General Public License Usage +* Alternatively, this project may be redistributed and/or modified under the +* terms of the GNU Lesser General Public License as published by the Free +* Software Foundation; 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 +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License +* along with this project. If not, see . +* +* 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 MODBUSRTUMASTERIMPL_H +#define MODBUSRTUMASTERIMPL_H + +#include + +#ifdef WITH_QTSERIALBUS +#include +#include +#endif + +#include "hardware/modbus/modbusrtumaster.h" + +namespace nymeaserver { + +class ModbusRtuMasterImpl : public ModbusRtuMaster +{ + Q_OBJECT +public: + explicit ModbusRtuMasterImpl(const QUuid &modbusUuid, const QString &serialPort, qint32 baudrate, QSerialPort::Parity parity, QSerialPort::DataBits dataBits, QSerialPort::StopBits stopBits, QObject *parent = nullptr); + ~ModbusRtuMasterImpl() override = default; + + QUuid modbusUuid() const override; + + QString serialPort() const override; + + bool connected() const override; + + // Requests + ModbusRtuReply *readCoil(uint slaveAddress, uint registerAddress, uint size = 1) override; + ModbusRtuReply *readDiscreteInput(uint slaveAddress, uint registerAddress, uint size = 1) override; + ModbusRtuReply *readInputRegister(uint slaveAddress, uint registerAddress, uint size = 1) override; + ModbusRtuReply *readHoldingRegister(uint slaveAddress, uint registerAddress, uint size = 1) override; + + ModbusRtuReply *writeCoil(uint slaveAddress, uint registerAddress, bool status) override; + ModbusRtuReply *writeCoils(uint slaveAddress, uint registerAddress, const QVector &values) override; + + ModbusRtuReply *writeHoldingRegister(uint slaveAddress, uint registerAddress, quint16 value) override; + ModbusRtuReply *writeHoldingRegisters(uint slaveAddress, uint registerAddress, const QVector &values) override; + +private: + QUuid m_modbusUuid; + +#ifdef WITH_QTSERIALBUS + QModbusRtuSerialMaster *m_modbus = nullptr; +#endif + + QString m_serialPort; + bool m_connected = false; +}; + +} + +#endif // MODBUSRTUMASTERIMPL_H diff --git a/libnymea-core/modbus/modbusrtureplyimpl.cpp b/libnymea-core/modbus/modbusrtureplyimpl.cpp new file mode 100644 index 00000000..ff14b0f6 --- /dev/null +++ b/libnymea-core/modbus/modbusrtureplyimpl.cpp @@ -0,0 +1,94 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2021, 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 Lesser General Public License Usage +* Alternatively, this project may be redistributed and/or modified under the +* terms of the GNU Lesser General Public License as published by the Free +* Software Foundation; 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 +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License +* along with this project. If not, see . +* +* 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 "modbusrtureplyimpl.h" + + +namespace nymeaserver { + +ModbusRtuReplyImpl::ModbusRtuReplyImpl(uint slaveAddress, uint registerAddress, QObject *parent) : + ModbusRtuReply(parent), + m_slaveAddress(slaveAddress), + m_registerAddress(registerAddress) +{ + +} + +bool ModbusRtuReplyImpl::isFinished() const +{ + return m_finished; +} + +void ModbusRtuReplyImpl::setFinished(bool finished) +{ + m_finished = finished; +} + +uint ModbusRtuReplyImpl::slaveAddress() const +{ + return m_slaveAddress; +} + +uint ModbusRtuReplyImpl::registerAddress() const +{ + return m_registerAddress; +} + +QString ModbusRtuReplyImpl::errorString() const +{ + return m_errorString; +} + +void ModbusRtuReplyImpl::setErrorString(const QString &errorString) +{ + m_errorString = errorString; +} + +ModbusRtuReply::Error ModbusRtuReplyImpl::error() const +{ + return m_error; +} + +void ModbusRtuReplyImpl::setError(ModbusRtuReply::Error error) +{ + m_error = error; +} + +QVector ModbusRtuReplyImpl::result() const +{ + return m_result; +} + +void ModbusRtuReplyImpl::setResult(const QVector &result) +{ + m_result = result; +} + +} diff --git a/libnymea-core/modbus/modbusrtumaster.cpp b/libnymea-core/modbus/modbusrtureplyimpl.h similarity index 60% rename from libnymea-core/modbus/modbusrtumaster.cpp rename to libnymea-core/modbus/modbusrtureplyimpl.h index 69f98b13..10da27c5 100644 --- a/libnymea-core/modbus/modbusrtumaster.cpp +++ b/libnymea-core/modbus/modbusrtureplyimpl.h @@ -28,13 +28,46 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#include "modbusrtumaster.h" +#ifndef MODBUSRTUREPLYIMPL_H +#define MODBUSRTUREPLYIMPL_H + +#include + +#include "hardware/modbus/modbusrtureply.h" namespace nymeaserver { -ModbusRtuMaster::ModbusRtuMaster(QObject *parent) : QObject(parent) +class ModbusRtuReplyImpl : public ModbusRtuReply { + Q_OBJECT +public: + explicit ModbusRtuReplyImpl(uint slaveAddress, uint registerAddress, QObject *parent = nullptr); + + bool isFinished() const override; + void setFinished(bool finished); + + uint slaveAddress() const override; + uint registerAddress() const override; + + QString errorString() const override; + void setErrorString(const QString &errorString); + + ModbusRtuReply::Error error() const override; + void setError(ModbusRtuReply::Error error); + + QVector result() const override; + void setResult(const QVector &result); + +private: + bool m_finished = false; + uint m_slaveAddress; + uint m_registerAddress; + Error m_error = UnknownError; + QString m_errorString; + QVector m_result; + +}; } -} +#endif // MODBUSRTUREPLYIMPL_H diff --git a/libnymea/hardware/modbus/modbusrtuhardwareresource.cpp b/libnymea/hardware/modbus/modbusrtuhardwareresource.cpp index 2b9be8a4..15756334 100644 --- a/libnymea/hardware/modbus/modbusrtuhardwareresource.cpp +++ b/libnymea/hardware/modbus/modbusrtuhardwareresource.cpp @@ -31,7 +31,7 @@ #include "modbusrtuhardwareresource.h" ModbusRtuHardwareResource::ModbusRtuHardwareResource(QObject *parent) : - HardwareResource("Modbus RTU client resource", parent) + HardwareResource("Modbus RTU resource", parent) { } diff --git a/libnymea/hardware/modbus/modbusrtuhardwareresource.h b/libnymea/hardware/modbus/modbusrtuhardwareresource.h index a6cfc497..0767e7e5 100644 --- a/libnymea/hardware/modbus/modbusrtuhardwareresource.h +++ b/libnymea/hardware/modbus/modbusrtuhardwareresource.h @@ -31,7 +31,10 @@ #ifndef MODBUSRTUHARDWARERESOURCE_H #define MODBUSRTUHARDWARERESOURCE_H +#include #include + +#include "modbusrtumaster.h" #include "hardwareresource.h" class ModbusRtuHardwareResource : public HardwareResource @@ -40,6 +43,9 @@ class ModbusRtuHardwareResource : public HardwareResource public: explicit ModbusRtuHardwareResource(QObject *parent = nullptr); virtual ~ModbusRtuHardwareResource() = default; + //virtual QList modbusRtuMasters() const = 0; + +protected: signals: diff --git a/libnymea/hardware/modbus/modbusrtumaster.h b/libnymea/hardware/modbus/modbusrtumaster.h new file mode 100644 index 00000000..754ccfb2 --- /dev/null +++ b/libnymea/hardware/modbus/modbusrtumaster.h @@ -0,0 +1,70 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2021, 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 Lesser General Public License Usage +* Alternatively, this project may be redistributed and/or modified under the +* terms of the GNU Lesser General Public License as published by the Free +* Software Foundation; 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 +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License +* along with this project. If not, see . +* +* 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 MODBUSRTUMASTER_H +#define MODBUSRTUMASTER_H + +#include +#include + +#include "modbusrtureply.h" + +class ModbusRtuMaster : public QObject +{ + Q_OBJECT +public: + // Properties + virtual QUuid modbusUuid() const = 0; + virtual QString serialPort() const = 0; + + virtual bool connected() const = 0; + + // Requests + virtual ModbusRtuReply *readCoil(uint slaveAddress, uint registerAddress, uint size = 1) = 0; + virtual ModbusRtuReply *readDiscreteInput(uint slaveAddress, uint registerAddress, uint size = 1) = 0; + virtual ModbusRtuReply *readInputRegister(uint slaveAddress, uint registerAddress, uint size = 1) = 0; + virtual ModbusRtuReply *readHoldingRegister(uint slaveAddress, uint registerAddress, uint size = 1) = 0; + + virtual ModbusRtuReply *writeCoil(uint slaveAddress, uint registerAddress, bool status) = 0; + virtual ModbusRtuReply *writeCoils(uint slaveAddress, uint registerAddress, const QVector &values) = 0; + + virtual ModbusRtuReply *writeHoldingRegister(uint slaveAddress, uint registerAddress, quint16 value) = 0; + virtual ModbusRtuReply *writeHoldingRegisters(uint slaveAddress, uint registerAddress, const QVector &values) = 0; + +protected: + explicit ModbusRtuMaster(QObject *parent = nullptr) : QObject(parent) { }; + virtual ~ModbusRtuMaster() = default; + +signals: + void connectedChanged(bool connected); + +}; + +#endif // MODBUSRTUMASTER_H diff --git a/libnymea-core/modbus/modbusrtumaster.h b/libnymea/hardware/modbus/modbusrtureply.h similarity index 63% rename from libnymea-core/modbus/modbusrtumaster.h rename to libnymea/hardware/modbus/modbusrtureply.h index 8cc42e52..eec9f8ab 100644 --- a/libnymea-core/modbus/modbusrtumaster.h +++ b/libnymea/hardware/modbus/modbusrtureply.h @@ -28,23 +28,47 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ -#ifndef MODBUSRTUMASTER_H -#define MODBUSRTUMASTER_H +#ifndef MODBUSRTUREPLY_H +#define MODBUSRTUREPLY_H #include +#include -namespace nymeaserver { - -class ModbusRtuMaster : public QObject +class ModbusRtuReply : public QObject { Q_OBJECT public: - explicit ModbusRtuMaster(QObject *parent = nullptr); + enum Error { + NoError, + ReadError, + WriteError, + ConnectionError, + ConfigurationError, + TimeoutError, + ProtocolError, + ReplyAbortedError, + UnknownError + }; + Q_ENUM(Error) + + virtual bool isFinished() const = 0; + + virtual uint slaveAddress() const = 0; + virtual uint registerAddress() const = 0; + + virtual QString errorString() const = 0; + virtual ModbusRtuReply::Error error() const = 0; + + virtual QVector result() const = 0; + +protected: + explicit ModbusRtuReply(QObject *parent = nullptr) : QObject(parent) { }; + virtual ~ModbusRtuReply() = default; signals: + void finished(); + void errorOccurred(ModbusRtuReply::Error error); }; -} - -#endif // MODBUSRTUMASTER_H +#endif // MODBUSRTUREPLY_H diff --git a/libnymea/hardwaremanager.h b/libnymea/hardwaremanager.h index 745a4ca9..711a0995 100644 --- a/libnymea/hardwaremanager.h +++ b/libnymea/hardwaremanager.h @@ -44,6 +44,7 @@ class MqttProvider; class I2CManager; class ZigbeeHardwareResource; class HardwareResource; +class ModbusRtuHardwareResouce; class HardwareManager : public QObject { @@ -63,6 +64,7 @@ public: virtual MqttProvider *mqttProvider() = 0; virtual I2CManager *i2cManager() = 0; virtual ZigbeeHardwareResource *zigbeeResource() = 0; + virtual ModbusRtuHardwareResouce *modbusRtuResource() = 0; protected: void setResourceEnabled(HardwareResource* resource, bool enabled); diff --git a/libnymea/libnymea.pro b/libnymea/libnymea.pro index b9de355e..0b6382c6 100644 --- a/libnymea/libnymea.pro +++ b/libnymea/libnymea.pro @@ -14,6 +14,8 @@ QMAKE_LFLAGS += -fPIC HEADERS += \ hardware/modbus/modbusrtuhardwareresource.h \ + hardware/modbus/modbusrtumaster.h \ + hardware/modbus/modbusrtureply.h \ hardware/zigbee/zigbeehandler.h \ hardware/zigbee/zigbeehardwareresource.h \ integrations/browseractioninfo.h \ From d6e5347666895fa9783208a13cd918d306aaa524 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Fri, 5 Feb 2021 13:07:48 +0100 Subject: [PATCH 03/24] Implement loading and saving of modbus hardware resources and finish the RTU master implementation --- ...odbusrtuhardwareresourceimplementation.cpp | 18 +- .../modbusrtuhardwareresourceimplementation.h | 4 +- libnymea-core/libnymea-core.pro | 6 +- libnymea-core/modbus/modbusrtumanager.cpp | 39 +- libnymea-core/modbus/modbusrtumanager.h | 11 +- libnymea-core/modbus/modbusrtumasterimpl.cpp | 382 ++++++++++++++---- libnymea-core/modbus/modbusrtumasterimpl.h | 28 +- libnymea-core/modbus/modbusrtureplyimpl.cpp | 6 +- libnymea-core/modbus/modbusrtureplyimpl.h | 10 +- .../modbus/modbusrtuhardwareresource.h | 11 +- libnymea/hardware/modbus/modbusrtumaster.h | 31 +- libnymea/hardware/modbus/modbusrtureply.h | 4 +- libnymea/libnymea.pro | 2 +- libnymea/nymeasettings.cpp | 15 +- libnymea/nymeasettings.h | 2 + 15 files changed, 431 insertions(+), 138 deletions(-) diff --git a/libnymea-core/hardware/modbus/modbusrtuhardwareresourceimplementation.cpp b/libnymea-core/hardware/modbus/modbusrtuhardwareresourceimplementation.cpp index 902d75ba..2e76b0b5 100644 --- a/libnymea-core/hardware/modbus/modbusrtuhardwareresourceimplementation.cpp +++ b/libnymea-core/hardware/modbus/modbusrtuhardwareresourceimplementation.cpp @@ -44,10 +44,20 @@ ModbusRtuHardwareResourceImplementation::ModbusRtuHardwareResourceImplementation } -//QList ModbusRtuHardwareResourceImplementation::modbusRtuMasters() const -//{ -// return m_modbusRtuManager->modbusRtuMasters(); -//} +QList ModbusRtuHardwareResourceImplementation::modbusRtuMasters() const +{ + return m_modbusRtuManager->modbusRtuMasters(); +} + +bool ModbusRtuHardwareResourceImplementation::hasModbusRtuMaster(const QUuid &modbusUuid) +{ + return m_modbusRtuManager->hasModbusRtuMaster(modbusUuid); +} + +ModbusRtuMaster *ModbusRtuHardwareResourceImplementation::getModbusRtuMaster(const QUuid &modbusUuid) +{ + return m_modbusRtuManager->getModbusRtuMaster(modbusUuid); +} bool ModbusRtuHardwareResourceImplementation::available() const { diff --git a/libnymea-core/hardware/modbus/modbusrtuhardwareresourceimplementation.h b/libnymea-core/hardware/modbus/modbusrtuhardwareresourceimplementation.h index ef33dd69..edf2873f 100644 --- a/libnymea-core/hardware/modbus/modbusrtuhardwareresourceimplementation.h +++ b/libnymea-core/hardware/modbus/modbusrtuhardwareresourceimplementation.h @@ -44,7 +44,9 @@ class ModbusRtuHardwareResourceImplementation : public ModbusRtuHardwareResource public: explicit ModbusRtuHardwareResourceImplementation(ModbusRtuManager *modbusRtuManager, QObject *parent = nullptr); - //QList modbusRtuMasters() const override; + QList modbusRtuMasters() const override; + bool hasModbusRtuMaster(const QUuid &modbusUuid) override; + ModbusRtuMaster *getModbusRtuMaster(const QUuid &modbusUuid) override; bool available() const override; bool enabled() const override; diff --git a/libnymea-core/libnymea-core.pro b/libnymea-core/libnymea-core.pro index c427f3d6..11701bd4 100644 --- a/libnymea-core/libnymea-core.pro +++ b/libnymea-core/libnymea-core.pro @@ -3,7 +3,7 @@ TARGET = nymea-core include(../nymea.pri) -QT += bluetooth dbus qml sql websockets +QT += bluetooth dbus qml sql websockets serialport INCLUDEPATH += $$top_srcdir/libnymea $$top_builddir LIBS += -L$$top_builddir/libnymea/ -lnymea -lssl -lcrypto @@ -40,9 +40,9 @@ CONFIG(withoutpython) { # Let's check if the package exists, not the qt version packagesExist(Qt5SerialBus) { DEFINES += WITH_QTSERIALBUS - Qt += serialbus serialport + Qt += serialbus } else { - message("Qt5SerialBus not available") + message("Qt5SerialBus library is not available. Modbus resource disabled.") } diff --git a/libnymea-core/modbus/modbusrtumanager.cpp b/libnymea-core/modbus/modbusrtumanager.cpp index 12d51bfc..148b63e4 100644 --- a/libnymea-core/modbus/modbusrtumanager.cpp +++ b/libnymea-core/modbus/modbusrtumanager.cpp @@ -31,6 +31,7 @@ #include "modbusrtumanager.h" #include "nymeasettings.h" #include "loggingcategories.h" +#include "modbusrtumasterimpl.h" NYMEA_LOGGING_CATEGORY(dcModbusRtu, "ModbusRtu") @@ -63,10 +64,46 @@ ModbusRtuMaster *ModbusRtuManager::getModbusRtuMaster(const QUuid &modbusUuid) void ModbusRtuManager::init() { // Load uart configurations + NymeaSettings settings(NymeaSettings::SettingsRoleModbusRtu); + qCDebug(dcModbusRtu()) << "Loading modbus RTU resources from" << settings.fileName(); - // Init modbus rtu masters + settings.beginGroup("ModbusRtuMasters"); + foreach (const QString &uuidString, settings.childGroups()) { + settings.beginGroup(uuidString); + QString serialPort = settings.value("serialPort").toString(); + quint32 baudrate = settings.value("baudrate").toUInt(); + QSerialPort::Parity parity = static_cast(settings.value("parity").toInt()); + QSerialPort::DataBits dataBits = static_cast(settings.value("dataBits").toInt()); + QSerialPort::StopBits stopBits = static_cast(settings.value("stopBits").toInt()); + settings.endGroup(); // uuid + + ModbusRtuMasterImpl *modbus = new ModbusRtuMasterImpl(QUuid(uuidString), serialPort, baudrate, parity, dataBits, stopBits, this); + ModbusRtuMaster *modbusRtuMaster = qobject_cast(modbus); + qCDebug(dcModbusRtu()) << "Loaded" << modbusRtuMaster; + m_modbusRtuMasters.insert(modbusRtuMaster->modbusUuid(), modbusRtuMaster); + emit modbusRtuMasterAdded(modbusRtuMaster->modbusUuid()); + } + + settings.endGroup(); // ModbusRtuMasters // Connect signals + + // Enable autoconnect for each modbus rtu master + +} + +void ModbusRtuManager::saveModbusRtuMaster(ModbusRtuMaster *modbusRtuMaster) +{ + NymeaSettings settings(NymeaSettings::SettingsRoleModbusRtu); + settings.beginGroup("ModbusRtuMasters"); + settings.beginGroup(modbusRtuMaster->modbusUuid().toString()); + settings.setValue("serialPort", modbusRtuMaster->serialPort()); + settings.setValue("baudrate", modbusRtuMaster->baudrate()); + settings.setValue("parity", static_cast(modbusRtuMaster->parity())); + settings.setValue("dataBits", static_cast(modbusRtuMaster->dataBits())); + settings.setValue("stopBits", static_cast(modbusRtuMaster->stopBits())); + settings.endGroup(); // uuid + settings.endGroup(); // ModbusRtuMasters } } diff --git a/libnymea-core/modbus/modbusrtumanager.h b/libnymea-core/modbus/modbusrtumanager.h index f31dca9a..95497e00 100644 --- a/libnymea-core/modbus/modbusrtumanager.h +++ b/libnymea-core/modbus/modbusrtumanager.h @@ -31,8 +31,9 @@ #ifndef MODBUSRTUMANAGER_H #define MODBUSRTUMANAGER_H -#include #include +#include +#include #include "hardware/modbus/modbusrtumaster.h" @@ -52,13 +53,15 @@ public: void init(); signals: - void modbusRtuMasterAdded(ModbusRtuMaster *modbusRtuMaster); - void modbusRtuMasterRemoved(ModbusRtuMaster *modbusRtuMaster); - void modbusRtuMasterChanged(ModbusRtuMaster *modbusRtuMaster); + void modbusRtuMasterAdded(const QUuid &modbusUuid); + void modbusRtuMasterRemoved(const QUuid &modbusUuid); + void modbusRtuMasterChanged(const QUuid &modbusUuid); private: QHash m_modbusRtuMasters; + void saveModbusRtuMaster(ModbusRtuMaster *modbusRtuMaster); + }; } diff --git a/libnymea-core/modbus/modbusrtumasterimpl.cpp b/libnymea-core/modbus/modbusrtumasterimpl.cpp index ba6c3406..14be6556 100644 --- a/libnymea-core/modbus/modbusrtumasterimpl.cpp +++ b/libnymea-core/modbus/modbusrtumasterimpl.cpp @@ -42,25 +42,36 @@ namespace nymeaserver { ModbusRtuMasterImpl::ModbusRtuMasterImpl(const QUuid &modbusUuid, const QString &serialPort, qint32 baudrate, QSerialPort::Parity parity, QSerialPort::DataBits dataBits, QSerialPort::StopBits stopBits, QObject *parent) : ModbusRtuMaster(parent), - m_modbusUuid(modbusUuid) + m_modbusUuid(modbusUuid), + m_serialPort(serialPort), + m_baudrate(baudrate), + m_parity(parity), + m_dataBits(dataBits), + m_stopBits(stopBits) { #ifdef WITH_QTSERIALBUS m_modbus = new QModbusRtuSerialMaster(this); - m_modbus->setConnectionParameter(QModbusDevice::SerialPortNameParameter, serialPort); - m_modbus->setConnectionParameter(QModbusDevice::SerialBaudRateParameter, baudrate); - m_modbus->setConnectionParameter(QModbusDevice::SerialDataBitsParameter, dataBits); - m_modbus->setConnectionParameter(QModbusDevice::SerialStopBitsParameter, stopBits); - m_modbus->setConnectionParameter(QModbusDevice::SerialParityParameter, parity); + m_modbus->setConnectionParameter(QModbusDevice::SerialPortNameParameter, m_serialPort); + m_modbus->setConnectionParameter(QModbusDevice::SerialBaudRateParameter, m_baudrate); + m_modbus->setConnectionParameter(QModbusDevice::SerialDataBitsParameter, m_dataBits); + m_modbus->setConnectionParameter(QModbusDevice::SerialStopBitsParameter, m_stopBits); + m_modbus->setConnectionParameter(QModbusDevice::SerialParityParameter, m_parity); connect(m_modbus, &QModbusTcpClient::stateChanged, this, [=](QModbusDevice::State state){ - qCDebug(dcModbusRtu()) << "Connection state changed" << m_modbusUuid.toString() << serialPort << state; + qCDebug(dcModbusRtu()) << "Connection state changed" << m_modbusUuid.toString() << m_serialPort << state; + if (state == QModbusDevice::ConnectedState) { + m_connected = true; + emit connectedChanged(m_connected); + } else { + m_connected = false; + emit connectedChanged(m_connected); + } }); - //connect(m_modbus, &QModbusRtuSerialMaster::errorOccurred, this, &ModbusRtuMaster::onModbusErrorOccurred); - -// m_reconnectTimer = new QTimer(this); -// m_reconnectTimer->setSingleShot(true); -// connect(m_reconnectTimer, &QTimer::timeout, this, &ModbusRTUMaster::onReconnectTimer); + connect(m_modbus, &QModbusRtuSerialMaster::errorOccurred, this, [=](QModbusDevice::Error error){ + qCDebug(dcModbusRtu()) << "Error occured for modbus RTU master" << m_modbusUuid.toString() << m_serialPort << error << m_modbus->errorString(); + // TODO: check if disconnected... + }); #endif } @@ -74,143 +85,344 @@ QString ModbusRtuMasterImpl::serialPort() const return m_serialPort; } +qint32 ModbusRtuMasterImpl::baudrate() const +{ + return m_baudrate; +} + +QSerialPort::Parity ModbusRtuMasterImpl::parity() const +{ + return m_parity; +} + +QSerialPort::DataBits ModbusRtuMasterImpl::dataBits() const +{ + return m_dataBits; +} + +QSerialPort::StopBits ModbusRtuMasterImpl::stopBits() +{ + return m_stopBits; +} + bool ModbusRtuMasterImpl::connected() const { return m_connected; } -ModbusRtuReply *ModbusRtuMasterImpl::readCoil(uint slaveAddress, uint registerAddress, uint size) +ModbusRtuReply *ModbusRtuMasterImpl::readCoil(int slaveAddress, int registerAddress, quint16 size) { -#ifndef WITH_QTSERIALBUS - Q_UNUSED(slaveAddress) - Q_UNUSED(registerAddress) - Q_UNUSED(size) - return nullptr; -#else +#ifdef WITH_QTSERIALBUS + // Create the reply for the plugin + ModbusRtuReplyImpl *reply = new ModbusRtuReplyImpl(slaveAddress, registerAddress, this); + connect(reply, &ModbusRtuReplyImpl::finished, reply, &ModbusRtuReplyImpl::deleteLater); + // Create the actual modbus lib reply QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::Coils, registerAddress, size); QModbusReply *modbusReply = m_modbus->sendReadRequest(request, slaveAddress); - // TODO: fill data and return reply - ModbusRtuReplyImpl *reply = new ModbusRtuReplyImpl(slaveAddress, registerAddress, this); connect(modbusReply, &QModbusReply::finished, modbusReply, [=](){ + modbusReply->deleteLater(); + + // Fill common reply data + reply->setFinished(true); + reply->setError(static_cast(modbusReply->error())); + reply->setErrorString(modbusReply->errorString()); + + // Check if the reply finished with an error if (modbusReply->error() != QModbusDevice::NoError) { qCWarning(dcModbusRtu()) << "Read coil request finished with error" << modbusReply->error() << modbusReply->errorString(); - + emit reply->errorOccurred(reply->error()); + emit reply->finished(); + return; } + + // Parse the data unit and set reply result + const QModbusDataUnit unit = modbusReply->result(); + reply->setResult(unit.values()); + emit reply->finished(); }); + + connect(modbusReply, &QModbusReply::errorOccurred, modbusReply, [=](QModbusDevice::Error error){ + qCWarning(dcModbusRtu()) << "Read coil request finished with error" << error << modbusReply->errorString(); + reply->setFinished(true); + reply->setError(static_cast(modbusReply->error())); + reply->setErrorString(modbusReply->errorString()); + emit reply->errorOccurred(reply->error()); + emit reply->finished(); + }); + return qobject_cast(reply); -#endif -} - -ModbusRtuReply *ModbusRtuMasterImpl::readDiscreteInput(uint slaveAddress, uint registerAddress, uint size) -{ -#ifndef WITH_QTSERIALBUS - Q_UNUSED(slaveAddress) - Q_UNUSED(registerAddress) - Q_UNUSED(size) - return nullptr; #else - // TODO: Q_UNUSED(slaveAddress) Q_UNUSED(registerAddress) Q_UNUSED(size) + return nullptr; #endif } -ModbusRtuReply *ModbusRtuMasterImpl::readInputRegister(uint slaveAddress, uint registerAddress, uint size) +ModbusRtuReply *ModbusRtuMasterImpl::readDiscreteInput(int slaveAddress, int registerAddress, quint16 size) { -#ifndef WITH_QTSERIALBUS - Q_UNUSED(slaveAddress) - Q_UNUSED(registerAddress) - Q_UNUSED(size) - return nullptr; +#ifdef WITH_QTSERIALBUS + // Create the reply for the plugin + ModbusRtuReplyImpl *reply = new ModbusRtuReplyImpl(slaveAddress, registerAddress, this); + connect(reply, &ModbusRtuReplyImpl::finished, reply, &ModbusRtuReplyImpl::deleteLater); + + // Create the actual modbus lib reply + QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::DiscreteInputs, registerAddress, size); + QModbusReply *modbusReply = m_modbus->sendReadRequest(request, slaveAddress); + + connect(modbusReply, &QModbusReply::finished, modbusReply, [=](){ + modbusReply->deleteLater(); + + // Fill common reply data + reply->setFinished(true); + reply->setError(static_cast(modbusReply->error())); + reply->setErrorString(modbusReply->errorString()); + + // Check if the reply finished with an error + if (modbusReply->error() != QModbusDevice::NoError) { + qCWarning(dcModbusRtu()) << "Read descrete inputs request finished with error" << modbusReply->error() << modbusReply->errorString(); + emit reply->errorOccurred(reply->error()); + emit reply->finished(); + return; + } + + // Parse the data unit and set reply result + const QModbusDataUnit unit = modbusReply->result(); + reply->setResult(unit.values()); + emit reply->finished(); + }); + + connect(modbusReply, &QModbusReply::errorOccurred, modbusReply, [=](QModbusDevice::Error error){ + qCWarning(dcModbusRtu()) << "Read descrete inputs request finished with error" << error << modbusReply->errorString(); + reply->setFinished(true); + reply->setError(static_cast(modbusReply->error())); + reply->setErrorString(modbusReply->errorString()); + emit reply->errorOccurred(reply->error()); + emit reply->finished(); + }); + + return qobject_cast(reply); #else - // TODO: Q_UNUSED(slaveAddress) Q_UNUSED(registerAddress) Q_UNUSED(size) + return nullptr; #endif } -ModbusRtuReply *ModbusRtuMasterImpl::readHoldingRegister(uint slaveAddress, uint registerAddress, uint size) +ModbusRtuReply *ModbusRtuMasterImpl::readInputRegister(int slaveAddress, int registerAddress, quint16 size) { -#ifndef WITH_QTSERIALBUS - Q_UNUSED(slaveAddress) - Q_UNUSED(registerAddress) - Q_UNUSED(size) - return nullptr; +#ifdef WITH_QTSERIALBUS + // Create the reply for the plugin + ModbusRtuReplyImpl *reply = new ModbusRtuReplyImpl(slaveAddress, registerAddress, this); + connect(reply, &ModbusRtuReplyImpl::finished, reply, &ModbusRtuReplyImpl::deleteLater); + + // Create the actual modbus lib reply + QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::InputRegisters, registerAddress, size); + QModbusReply *modbusReply = m_modbus->sendReadRequest(request, slaveAddress); + + connect(modbusReply, &QModbusReply::finished, modbusReply, [=](){ + modbusReply->deleteLater(); + + // Fill common reply data + reply->setFinished(true); + reply->setError(static_cast(modbusReply->error())); + reply->setErrorString(modbusReply->errorString()); + + // Check if the reply finished with an error + if (modbusReply->error() != QModbusDevice::NoError) { + qCWarning(dcModbusRtu()) << "Read input registers request finished with error" << modbusReply->error() << modbusReply->errorString(); + emit reply->errorOccurred(reply->error()); + emit reply->finished(); + return; + } + + // Parse the data unit and set reply result + const QModbusDataUnit unit = modbusReply->result(); + reply->setResult(unit.values()); + emit reply->finished(); + }); + + connect(modbusReply, &QModbusReply::errorOccurred, modbusReply, [=](QModbusDevice::Error error){ + qCWarning(dcModbusRtu()) << "Read input registers request finished with error" << error << modbusReply->errorString(); + reply->setFinished(true); + reply->setError(static_cast(modbusReply->error())); + reply->setErrorString(modbusReply->errorString()); + emit reply->errorOccurred(reply->error()); + emit reply->finished(); + }); + + return qobject_cast(reply); #else - // TODO: Q_UNUSED(slaveAddress) Q_UNUSED(registerAddress) Q_UNUSED(size) + return nullptr; #endif } -ModbusRtuReply *ModbusRtuMasterImpl::writeCoil(uint slaveAddress, uint registerAddress, bool status) +ModbusRtuReply *ModbusRtuMasterImpl::readHoldingRegister(int slaveAddress, int registerAddress, quint16 size) { -#ifndef WITH_QTSERIALBUS - Q_UNUSED(slaveAddress) - Q_UNUSED(registerAddress) - Q_UNUSED(size) - return nullptr; +#ifdef WITH_QTSERIALBUS + // Create the reply for the plugin + ModbusRtuReplyImpl *reply = new ModbusRtuReplyImpl(slaveAddress, registerAddress, this); + connect(reply, &ModbusRtuReplyImpl::finished, reply, &ModbusRtuReplyImpl::deleteLater); + + // Create the actual modbus lib reply + QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, registerAddress, size); + QModbusReply *modbusReply = m_modbus->sendReadRequest(request, slaveAddress); + + connect(modbusReply, &QModbusReply::finished, modbusReply, [=](){ + modbusReply->deleteLater(); + + // Fill common reply data + reply->setFinished(true); + reply->setError(static_cast(modbusReply->error())); + reply->setErrorString(modbusReply->errorString()); + + // Check if the reply finished with an error + if (modbusReply->error() != QModbusDevice::NoError) { + qCWarning(dcModbusRtu()) << "Read holding registers request finished with error" << modbusReply->error() << modbusReply->errorString(); + emit reply->errorOccurred(reply->error()); + emit reply->finished(); + return; + } + + // Parse the data unit and set reply result + const QModbusDataUnit unit = modbusReply->result(); + reply->setResult(unit.values()); + emit reply->finished(); + }); + + connect(modbusReply, &QModbusReply::errorOccurred, modbusReply, [=](QModbusDevice::Error error){ + qCWarning(dcModbusRtu()) << "Read holding registers request finished with error" << error << modbusReply->errorString(); + reply->setFinished(true); + reply->setError(static_cast(modbusReply->error())); + reply->setErrorString(modbusReply->errorString()); + emit reply->errorOccurred(reply->error()); + emit reply->finished(); + }); + + return qobject_cast(reply); #else - // TODO: Q_UNUSED(slaveAddress) Q_UNUSED(registerAddress) - Q_UNUSED(status) + Q_UNUSED(size) + return nullptr; #endif } -ModbusRtuReply *ModbusRtuMasterImpl::writeCoils(uint slaveAddress, uint registerAddress, const QVector &values) +ModbusRtuReply *ModbusRtuMasterImpl::writeCoils(int slaveAddress, int registerAddress, const QVector &values) { -#ifndef WITH_QTSERIALBUS - Q_UNUSED(slaveAddress) - Q_UNUSED(registerAddress) - Q_UNUSED(values) - return nullptr; -#else - // TODO: +#ifdef WITH_QTSERIALBUS + // Create the reply for the plugin + ModbusRtuReplyImpl *reply = new ModbusRtuReplyImpl(slaveAddress, registerAddress, this); + connect(reply, &ModbusRtuReplyImpl::finished, reply, &ModbusRtuReplyImpl::deleteLater); + + // Create the actual modbus lib reply + QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::Coils, registerAddress, values.length()); + request.setValues(values); + + QModbusReply *modbusReply = m_modbus->sendWriteRequest(request, slaveAddress); + + connect(modbusReply, &QModbusReply::finished, modbusReply, [=](){ + modbusReply->deleteLater(); + + // Fill common reply data + reply->setFinished(true); + reply->setError(static_cast(modbusReply->error())); + reply->setErrorString(modbusReply->errorString()); + + // Check if the reply finished with an error + if (modbusReply->error() != QModbusDevice::NoError) { + qCWarning(dcModbusRtu()) << "Read coil request finished with error" << modbusReply->error() << modbusReply->errorString(); + emit reply->errorOccurred(reply->error()); + emit reply->finished(); + return; + } + + // Parse the data unit and set reply result + const QModbusDataUnit unit = modbusReply->result(); + reply->setResult(unit.values()); + emit reply->finished(); + }); + + connect(modbusReply, &QModbusReply::errorOccurred, modbusReply, [=](QModbusDevice::Error error){ + qCWarning(dcModbusRtu()) << "Read coil request finished with error" << error << modbusReply->errorString(); + reply->setFinished(true); + reply->setError(static_cast(modbusReply->error())); + reply->setErrorString(modbusReply->errorString()); + emit reply->errorOccurred(reply->error()); + emit reply->finished(); + }); + + return qobject_cast(reply); +#else Q_UNUSED(slaveAddress) Q_UNUSED(registerAddress) Q_UNUSED(values) + return nullptr; #endif } -ModbusRtuReply *ModbusRtuMasterImpl::writeHoldingRegister(uint slaveAddress, uint registerAddress, quint16 value) + +ModbusRtuReply *ModbusRtuMasterImpl::writeHoldingRegisters(int slaveAddress, int registerAddress, const QVector &values) { -#ifndef WITH_QTSERIALBUS - Q_UNUSED(slaveAddress) - Q_UNUSED(registerAddress) - Q_UNUSED(value) - return nullptr; -#else - // TODO: - Q_UNUSED(slaveAddress) - Q_UNUSED(registerAddress) - Q_UNUSED(value) - return nullptr; -#endif -} +#ifdef WITH_QTSERIALBUS + // Create the reply for the plugin + ModbusRtuReplyImpl *reply = new ModbusRtuReplyImpl(slaveAddress, registerAddress, this); + connect(reply, &ModbusRtuReplyImpl::finished, reply, &ModbusRtuReplyImpl::deleteLater); -ModbusRtuReply *ModbusRtuMasterImpl::writeHoldingRegisters(uint slaveAddress, uint registerAddress, const QVector &values) -{ -#ifndef WITH_QTSERIALBUS - Q_UNUSED(slaveAddress) - Q_UNUSED(registerAddress) - Q_UNUSED(values) - return nullptr; + // Create the actual modbus lib reply + QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, registerAddress, values.length()); + request.setValues(values); + + QModbusReply *modbusReply = m_modbus->sendWriteRequest(request, slaveAddress); + + connect(modbusReply, &QModbusReply::finished, modbusReply, [=](){ + modbusReply->deleteLater(); + + // Fill common reply data + reply->setFinished(true); + reply->setError(static_cast(modbusReply->error())); + reply->setErrorString(modbusReply->errorString()); + + // Check if the reply finished with an error + if (modbusReply->error() != QModbusDevice::NoError) { + qCWarning(dcModbusRtu()) << "Read coil request finished with error" << modbusReply->error() << modbusReply->errorString(); + emit reply->errorOccurred(reply->error()); + emit reply->finished(); + return; + } + + // Parse the data unit and set reply result + const QModbusDataUnit unit = modbusReply->result(); + reply->setResult(unit.values()); + emit reply->finished(); + }); + + connect(modbusReply, &QModbusReply::errorOccurred, modbusReply, [=](QModbusDevice::Error error){ + qCWarning(dcModbusRtu()) << "Read coil request finished with error" << error << modbusReply->errorString(); + reply->setFinished(true); + reply->setError(static_cast(modbusReply->error())); + reply->setErrorString(modbusReply->errorString()); + emit reply->errorOccurred(reply->error()); + emit reply->finished(); + }); + + return qobject_cast(reply); #else - // TODO: Q_UNUSED(slaveAddress) Q_UNUSED(registerAddress) Q_UNUSED(values) + return nullptr; #endif } diff --git a/libnymea-core/modbus/modbusrtumasterimpl.h b/libnymea-core/modbus/modbusrtumasterimpl.h index b47f6b7a..15a99f52 100644 --- a/libnymea-core/modbus/modbusrtumasterimpl.h +++ b/libnymea-core/modbus/modbusrtumasterimpl.h @@ -32,10 +32,10 @@ #define MODBUSRTUMASTERIMPL_H #include +#include #ifdef WITH_QTSERIALBUS #include -#include #endif #include "hardware/modbus/modbusrtumaster.h" @@ -50,32 +50,36 @@ public: ~ModbusRtuMasterImpl() override = default; QUuid modbusUuid() const override; - QString serialPort() const override; + qint32 baudrate() const override; + QSerialPort::Parity parity() const override; + QSerialPort::DataBits dataBits() const override; + QSerialPort::StopBits stopBits() override; bool connected() const override; // Requests - ModbusRtuReply *readCoil(uint slaveAddress, uint registerAddress, uint size = 1) override; - ModbusRtuReply *readDiscreteInput(uint slaveAddress, uint registerAddress, uint size = 1) override; - ModbusRtuReply *readInputRegister(uint slaveAddress, uint registerAddress, uint size = 1) override; - ModbusRtuReply *readHoldingRegister(uint slaveAddress, uint registerAddress, uint size = 1) override; + ModbusRtuReply *readCoil(int slaveAddress, int registerAddress, quint16 size = 1) override; + ModbusRtuReply *readDiscreteInput(int slaveAddress, int registerAddress, quint16 size = 1) override; + ModbusRtuReply *readInputRegister(int slaveAddress, int registerAddress, quint16 size = 1) override; + ModbusRtuReply *readHoldingRegister(int slaveAddress, int registerAddress, quint16 size = 1) override; - ModbusRtuReply *writeCoil(uint slaveAddress, uint registerAddress, bool status) override; - ModbusRtuReply *writeCoils(uint slaveAddress, uint registerAddress, const QVector &values) override; - - ModbusRtuReply *writeHoldingRegister(uint slaveAddress, uint registerAddress, quint16 value) override; - ModbusRtuReply *writeHoldingRegisters(uint slaveAddress, uint registerAddress, const QVector &values) override; + ModbusRtuReply *writeCoils(int slaveAddress, int registerAddress, const QVector &values) override; + ModbusRtuReply *writeHoldingRegisters(int slaveAddress, int registerAddress, const QVector &values) override; private: QUuid m_modbusUuid; + bool m_connected = false; #ifdef WITH_QTSERIALBUS QModbusRtuSerialMaster *m_modbus = nullptr; #endif QString m_serialPort; - bool m_connected = false; + qint32 m_baudrate; + QSerialPort::Parity m_parity; + QSerialPort::DataBits m_dataBits; + QSerialPort::StopBits m_stopBits; }; } diff --git a/libnymea-core/modbus/modbusrtureplyimpl.cpp b/libnymea-core/modbus/modbusrtureplyimpl.cpp index ff14b0f6..0c66d2ac 100644 --- a/libnymea-core/modbus/modbusrtureplyimpl.cpp +++ b/libnymea-core/modbus/modbusrtureplyimpl.cpp @@ -33,7 +33,7 @@ namespace nymeaserver { -ModbusRtuReplyImpl::ModbusRtuReplyImpl(uint slaveAddress, uint registerAddress, QObject *parent) : +ModbusRtuReplyImpl::ModbusRtuReplyImpl(int slaveAddress, int registerAddress, QObject *parent) : ModbusRtuReply(parent), m_slaveAddress(slaveAddress), m_registerAddress(registerAddress) @@ -51,12 +51,12 @@ void ModbusRtuReplyImpl::setFinished(bool finished) m_finished = finished; } -uint ModbusRtuReplyImpl::slaveAddress() const +int ModbusRtuReplyImpl::slaveAddress() const { return m_slaveAddress; } -uint ModbusRtuReplyImpl::registerAddress() const +int ModbusRtuReplyImpl::registerAddress() const { return m_registerAddress; } diff --git a/libnymea-core/modbus/modbusrtureplyimpl.h b/libnymea-core/modbus/modbusrtureplyimpl.h index 10da27c5..5851b423 100644 --- a/libnymea-core/modbus/modbusrtureplyimpl.h +++ b/libnymea-core/modbus/modbusrtureplyimpl.h @@ -41,13 +41,13 @@ class ModbusRtuReplyImpl : public ModbusRtuReply { Q_OBJECT public: - explicit ModbusRtuReplyImpl(uint slaveAddress, uint registerAddress, QObject *parent = nullptr); + explicit ModbusRtuReplyImpl(int slaveAddress, int registerAddress, QObject *parent = nullptr); bool isFinished() const override; void setFinished(bool finished); - uint slaveAddress() const override; - uint registerAddress() const override; + int slaveAddress() const override; + int registerAddress() const override; QString errorString() const override; void setErrorString(const QString &errorString); @@ -60,8 +60,8 @@ public: private: bool m_finished = false; - uint m_slaveAddress; - uint m_registerAddress; + int m_slaveAddress; + int m_registerAddress; Error m_error = UnknownError; QString m_errorString; QVector m_result; diff --git a/libnymea/hardware/modbus/modbusrtuhardwareresource.h b/libnymea/hardware/modbus/modbusrtuhardwareresource.h index 0767e7e5..55356537 100644 --- a/libnymea/hardware/modbus/modbusrtuhardwareresource.h +++ b/libnymea/hardware/modbus/modbusrtuhardwareresource.h @@ -41,13 +41,18 @@ class ModbusRtuHardwareResource : public HardwareResource { Q_OBJECT public: - explicit ModbusRtuHardwareResource(QObject *parent = nullptr); - virtual ~ModbusRtuHardwareResource() = default; - //virtual QList modbusRtuMasters() const = 0; + virtual QList modbusRtuMasters() const = 0; + virtual bool hasModbusRtuMaster(const QUuid &modbusUuid) = 0; + virtual ModbusRtuMaster *getModbusRtuMaster(const QUuid &modbusUuid) = 0; protected: + explicit ModbusRtuHardwareResource(QObject *parent = nullptr); + virtual ~ModbusRtuHardwareResource() = default; signals: + void modbusRtuMasterAdded(const QUuid &modbusUuid); + void modbusRtuMasterRemoved(const QUuid &modbusUuid); + void modbusRtuMasterChanged(const QUuid &modbusUuid); }; diff --git a/libnymea/hardware/modbus/modbusrtumaster.h b/libnymea/hardware/modbus/modbusrtumaster.h index 754ccfb2..a8caf09c 100644 --- a/libnymea/hardware/modbus/modbusrtumaster.h +++ b/libnymea/hardware/modbus/modbusrtumaster.h @@ -31,8 +31,10 @@ #ifndef MODBUSRTUMASTER_H #define MODBUSRTUMASTER_H -#include #include +#include +#include +#include #include "modbusrtureply.h" @@ -43,20 +45,21 @@ public: // Properties virtual QUuid modbusUuid() const = 0; virtual QString serialPort() const = 0; + virtual qint32 baudrate() const = 0; + virtual QSerialPort::Parity parity() const = 0; + virtual QSerialPort::DataBits dataBits() const = 0; + virtual QSerialPort::StopBits stopBits() = 0; virtual bool connected() const = 0; // Requests - virtual ModbusRtuReply *readCoil(uint slaveAddress, uint registerAddress, uint size = 1) = 0; - virtual ModbusRtuReply *readDiscreteInput(uint slaveAddress, uint registerAddress, uint size = 1) = 0; - virtual ModbusRtuReply *readInputRegister(uint slaveAddress, uint registerAddress, uint size = 1) = 0; - virtual ModbusRtuReply *readHoldingRegister(uint slaveAddress, uint registerAddress, uint size = 1) = 0; + virtual ModbusRtuReply *readCoil(int slaveAddress, int registerAddress, quint16 size = 1) = 0; + virtual ModbusRtuReply *readDiscreteInput(int slaveAddress, int registerAddress, quint16 size = 1) = 0; + virtual ModbusRtuReply *readInputRegister(int slaveAddress, int registerAddress, quint16 size = 1) = 0; + virtual ModbusRtuReply *readHoldingRegister(int slaveAddress, int registerAddress, quint16 size = 1) = 0; - virtual ModbusRtuReply *writeCoil(uint slaveAddress, uint registerAddress, bool status) = 0; - virtual ModbusRtuReply *writeCoils(uint slaveAddress, uint registerAddress, const QVector &values) = 0; - - virtual ModbusRtuReply *writeHoldingRegister(uint slaveAddress, uint registerAddress, quint16 value) = 0; - virtual ModbusRtuReply *writeHoldingRegisters(uint slaveAddress, uint registerAddress, const QVector &values) = 0; + virtual ModbusRtuReply *writeCoils(int slaveAddress, int registerAddress, const QVector &values) = 0; + virtual ModbusRtuReply *writeHoldingRegisters(int slaveAddress, int registerAddress, const QVector &values) = 0; protected: explicit ModbusRtuMaster(QObject *parent = nullptr) : QObject(parent) { }; @@ -67,4 +70,12 @@ signals: }; +inline QDebug operator<<(QDebug debug, ModbusRtuMaster *modbusRtuMaster) { + debug.nospace() << "ModbusRtuMaster(" << modbusRtuMaster->modbusUuid().toString(); + debug.nospace() << ", " << modbusRtuMaster->serialPort(); + debug.nospace() << ", BaudRate: " << modbusRtuMaster->baudrate() << ") "; + return debug; +}; + + #endif // MODBUSRTUMASTER_H diff --git a/libnymea/hardware/modbus/modbusrtureply.h b/libnymea/hardware/modbus/modbusrtureply.h index eec9f8ab..46e5a86a 100644 --- a/libnymea/hardware/modbus/modbusrtureply.h +++ b/libnymea/hardware/modbus/modbusrtureply.h @@ -53,8 +53,8 @@ public: virtual bool isFinished() const = 0; - virtual uint slaveAddress() const = 0; - virtual uint registerAddress() const = 0; + virtual int slaveAddress() const = 0; + virtual int registerAddress() const = 0; virtual QString errorString() const = 0; virtual ModbusRtuReply::Error error() const = 0; diff --git a/libnymea/libnymea.pro b/libnymea/libnymea.pro index 0b6382c6..41752d75 100644 --- a/libnymea/libnymea.pro +++ b/libnymea/libnymea.pro @@ -3,7 +3,7 @@ include(../nymea.pri) TARGET = nymea TEMPLATE = lib -QT += network bluetooth dbus +QT += network bluetooth dbus serialport QT -= gui DEFINES += LIBNYMEA_LIBRARY diff --git a/libnymea/nymeasettings.cpp b/libnymea/nymeasettings.cpp index 417c7472..e57c3a25 100644 --- a/libnymea/nymeasettings.cpp +++ b/libnymea/nymeasettings.cpp @@ -64,6 +64,10 @@ This role will create the \b{mqttpolicies.conf} file and is used to store the \l{MqttPolicy}{MqttPolicies}. \value SettingsRoleIOConnections This role will create the \b{ioconnections.conf} file and is used to store the \l{IOConnection}{IOConnections}. + \value SettingsRoleZigbee + This role will create the \b{zigbee.conf} file and is used to store the Zigbee networks. + \value SettingsRoleModbusRtu + This role will create the \b{modbusrtu.conf} file and is used to store the modbus RTU resources. */ @@ -83,7 +87,7 @@ NymeaSettings::NymeaSettings(const SettingsRole &role, QObject *parent): QString settingsPrefix = QCoreApplication::instance()->organizationName() + "/"; QString basePath; - if (!qgetenv("SNAP").isEmpty()) { + if (!qEnvironmentVariableIsEmpty("SNAP")) { basePath = QString(qgetenv("SNAP_DATA")) + "/"; settingsPrefix.clear(); // We don't want that in the snappy case... } else if (settingsPrefix == "nymea-test/") { @@ -125,6 +129,9 @@ NymeaSettings::NymeaSettings(const SettingsRole &role, QObject *parent): case SettingsRoleZigbee: fileName = "zigbee.conf"; break; + case SettingsRoleModbusRtu: + fileName = "modbusrtu.conf"; + break; } m_settings = new QSettings(basePath + settingsPrefix + fileName, QSettings::IniFormat, this); } @@ -157,7 +164,7 @@ QString NymeaSettings::settingsPath() QString path; QString organisationName = QCoreApplication::instance()->organizationName(); - if (!qgetenv("SNAP").isEmpty()) { + if (!qEnvironmentVariableIsEmpty("SNAP")) { path = QString(qgetenv("SNAP_DATA")); } else if (organisationName == "nymea-test") { path = "/tmp/" + organisationName; @@ -174,7 +181,7 @@ QString NymeaSettings::translationsPath() { QString organisationName = QCoreApplication::instance()->organizationName(); - if (!qgetenv("SNAP").isEmpty()) { + if (!qEnvironmentVariableIsEmpty("SNAP")) { return QString(qgetenv("SNAP") + "/usr/share/nymea/translations"); } else if (organisationName == "nymea-test") { return "/tmp/" + organisationName; @@ -188,7 +195,7 @@ QString NymeaSettings::storagePath() { QString path; QString organisationName = QCoreApplication::instance()->organizationName(); - if (!qgetenv("SNAP").isEmpty()) { + if (!qEnvironmentVariableIsEmpty("SNAP")) { path = QString(qgetenv("SNAP_DATA")); } else if (organisationName == "nymea-test") { path = "/tmp/" + organisationName; diff --git a/libnymea/nymeasettings.h b/libnymea/nymeasettings.h index 36301eb3..8c514b68 100644 --- a/libnymea/nymeasettings.h +++ b/libnymea/nymeasettings.h @@ -53,7 +53,9 @@ public: SettingsRoleMqttPolicies, SettingsRoleIOConnections, SettingsRoleZigbee, + SettingsRoleModbusRtu }; + Q_ENUM(SettingsRole) explicit NymeaSettings(const SettingsRole &role = SettingsRoleNone, QObject *parent = nullptr); ~NymeaSettings(); From fc9c030ebc8f943bbda34b803f2bb12b80333d91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Fri, 5 Feb 2021 17:10:45 +0100 Subject: [PATCH 04/24] Update build information --- libnymea-core/libnymea-core.pro | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/libnymea-core/libnymea-core.pro b/libnymea-core/libnymea-core.pro index 11701bd4..7227a848 100644 --- a/libnymea-core/libnymea-core.pro +++ b/libnymea-core/libnymea-core.pro @@ -39,10 +39,11 @@ CONFIG(withoutpython) { # but not all platforms host the qt serialbus package. # Let's check if the package exists, not the qt version packagesExist(Qt5SerialBus) { - DEFINES += WITH_QTSERIALBUS + message("Building with QtSerialBus support.") Qt += serialbus + DEFINES += WITH_QTSERIALBUS } else { - message("Qt5SerialBus library is not available. Modbus resource disabled.") + message("Qt5SerialBus package not found. Building without QtSerialBus support.") } From 673bce61ff1e039a1770f914edf5ee17d4c6a797 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Mon, 8 Feb 2021 16:20:51 +0100 Subject: [PATCH 05/24] Initialize modbus manager and clean up class hirarchy --- .../modbusrtuhardwareresourceimplementation.cpp | 4 ++-- .../modbusrtuhardwareresourceimplementation.h | 6 ++++-- libnymea-core/hardwaremanagerimplementation.cpp | 8 ++++++-- libnymea-core/hardwaremanagerimplementation.h | 8 +++++--- libnymea-core/libnymea-core.pro | 3 ++- libnymea-core/modbus/modbusrtumanager.cpp | 15 ++++++++------- libnymea-core/modbus/modbusrtumanager.h | 3 +-- libnymea-core/nymeacore.cpp | 12 +++++++++++- libnymea-core/nymeacore.h | 3 +++ .../hardware/modbus/modbusrtuhardwareresource.cpp | 1 + .../hardware/modbus/modbusrtuhardwareresource.h | 6 +++--- libnymea/hardwaremanager.h | 4 ++-- tests/auto/autotests.pri | 12 ++++++++++++ tests/testlib/testlib.pro | 8 ++++++++ 14 files changed, 68 insertions(+), 25 deletions(-) diff --git a/libnymea-core/hardware/modbus/modbusrtuhardwareresourceimplementation.cpp b/libnymea-core/hardware/modbus/modbusrtuhardwareresourceimplementation.cpp index 2e76b0b5..96c9c19e 100644 --- a/libnymea-core/hardware/modbus/modbusrtuhardwareresourceimplementation.cpp +++ b/libnymea-core/hardware/modbus/modbusrtuhardwareresourceimplementation.cpp @@ -49,12 +49,12 @@ QList ModbusRtuHardwareResourceImplementation::modbusRtuMaste return m_modbusRtuManager->modbusRtuMasters(); } -bool ModbusRtuHardwareResourceImplementation::hasModbusRtuMaster(const QUuid &modbusUuid) +bool ModbusRtuHardwareResourceImplementation::hasModbusRtuMaster(const QUuid &modbusUuid) const { return m_modbusRtuManager->hasModbusRtuMaster(modbusUuid); } -ModbusRtuMaster *ModbusRtuHardwareResourceImplementation::getModbusRtuMaster(const QUuid &modbusUuid) +ModbusRtuMaster *ModbusRtuHardwareResourceImplementation::getModbusRtuMaster(const QUuid &modbusUuid) const { return m_modbusRtuManager->getModbusRtuMaster(modbusUuid); } diff --git a/libnymea-core/hardware/modbus/modbusrtuhardwareresourceimplementation.h b/libnymea-core/hardware/modbus/modbusrtuhardwareresourceimplementation.h index edf2873f..a26be359 100644 --- a/libnymea-core/hardware/modbus/modbusrtuhardwareresourceimplementation.h +++ b/libnymea-core/hardware/modbus/modbusrtuhardwareresourceimplementation.h @@ -34,6 +34,7 @@ #include #include "modbus/modbusrtumanager.h" +#include "hardware/modbus/modbusrtumaster.h" #include "hardware/modbus/modbusrtuhardwareresource.h" namespace nymeaserver { @@ -43,10 +44,11 @@ class ModbusRtuHardwareResourceImplementation : public ModbusRtuHardwareResource Q_OBJECT public: explicit ModbusRtuHardwareResourceImplementation(ModbusRtuManager *modbusRtuManager, QObject *parent = nullptr); + ~ModbusRtuHardwareResourceImplementation() override = default; QList modbusRtuMasters() const override; - bool hasModbusRtuMaster(const QUuid &modbusUuid) override; - ModbusRtuMaster *getModbusRtuMaster(const QUuid &modbusUuid) override; + bool hasModbusRtuMaster(const QUuid &modbusUuid) const override; + ModbusRtuMaster *getModbusRtuMaster(const QUuid &modbusUuid) const override; bool available() const override; bool enabled() const override; diff --git a/libnymea-core/hardwaremanagerimplementation.cpp b/libnymea-core/hardwaremanagerimplementation.cpp index 754924f0..aece0d95 100644 --- a/libnymea-core/hardwaremanagerimplementation.cpp +++ b/libnymea-core/hardwaremanagerimplementation.cpp @@ -43,11 +43,13 @@ #include "hardware/network/mqtt/mqttproviderimplementation.h" #include "hardware/i2c/i2cmanagerimplementation.h" #include "hardware/zigbee/zigbeehardwareresourceimplementation.h" + +#include "modbus/modbusrtumanager.h" #include "hardware/modbus/modbusrtuhardwareresourceimplementation.h" namespace nymeaserver { -HardwareManagerImplementation::HardwareManagerImplementation(Platform *platform, MqttBroker *mqttBroker, ZigbeeManager *zigbeeManager, QObject *parent) : +HardwareManagerImplementation::HardwareManagerImplementation(Platform *platform, MqttBroker *mqttBroker, ZigbeeManager *zigbeeManager, ModbusRtuManager *modbusRtuManager, QObject *parent) : HardwareManager(parent), m_platform(platform) { @@ -74,6 +76,8 @@ HardwareManagerImplementation::HardwareManagerImplementation(Platform *platform, m_zigbeeResource = new ZigbeeHardwareResourceImplementation(zigbeeManager, this); + m_modbusRtuResource = new ModbusRtuHardwareResourceImplementation(modbusRtuManager, this); + // Enable all the resources setResourceEnabled(m_pluginTimerManager, true); setResourceEnabled(m_radio433, true); @@ -143,7 +147,7 @@ ZigbeeHardwareResource *HardwareManagerImplementation::zigbeeResource() return m_zigbeeResource; } -ModbusRtuHardwareResouce *HardwareManagerImplementation::modbusRtuResource() +ModbusRtuHardwareResource *HardwareManagerImplementation::modbusRtuResource() { return m_modbusRtuResource; } diff --git a/libnymea-core/hardwaremanagerimplementation.h b/libnymea-core/hardwaremanagerimplementation.h index 3d799adf..c808b0d2 100644 --- a/libnymea-core/hardwaremanagerimplementation.h +++ b/libnymea-core/hardwaremanagerimplementation.h @@ -43,13 +43,15 @@ class Platform; class MqttBroker; class ZigbeeManager; class ZigbeeHardwareResourceImplementation; +class ModbusRtuManager; +class ModbusRtuHardwareResourceImplementation; class HardwareManagerImplementation : public HardwareManager { Q_OBJECT public: - explicit HardwareManagerImplementation(Platform *platform, MqttBroker *mqttBroker, ZigbeeManager *zigbeeManager, QObject *parent = nullptr); + explicit HardwareManagerImplementation(Platform *platform, MqttBroker *mqttBroker, ZigbeeManager *zigbeeManager, ModbusRtuManager *modbusRtuManager, QObject *parent = nullptr); ~HardwareManagerImplementation() override; Radio433 *radio433() override; @@ -61,7 +63,7 @@ public: MqttProvider *mqttProvider() override; I2CManager *i2cManager() override; ZigbeeHardwareResource *zigbeeResource() override; - ModbusRtuHardwareResouce *modbusRtuResource() override; + ModbusRtuHardwareResource *modbusRtuResource() override; public slots: void thingsLoaded(); @@ -80,7 +82,7 @@ private: MqttProvider *m_mqttProvider = nullptr; I2CManager *m_i2cManager = nullptr; ZigbeeHardwareResourceImplementation *m_zigbeeResource = nullptr; - ModbusRtuHardwareResouce *m_modbusRtuResource = nullptr; + ModbusRtuHardwareResourceImplementation *m_modbusRtuResource = nullptr; }; } diff --git a/libnymea-core/libnymea-core.pro b/libnymea-core/libnymea-core.pro index 7227a848..1668715f 100644 --- a/libnymea-core/libnymea-core.pro +++ b/libnymea-core/libnymea-core.pro @@ -40,7 +40,8 @@ CONFIG(withoutpython) { # Let's check if the package exists, not the qt version packagesExist(Qt5SerialBus) { message("Building with QtSerialBus support.") - Qt += serialbus + # Qt += serialbus + PKGCONFIG += Qt5SerialBus DEFINES += WITH_QTSERIALBUS } else { message("Qt5SerialBus package not found. Building without QtSerialBus support.") diff --git a/libnymea-core/modbus/modbusrtumanager.cpp b/libnymea-core/modbus/modbusrtumanager.cpp index 148b63e4..f6101364 100644 --- a/libnymea-core/modbus/modbusrtumanager.cpp +++ b/libnymea-core/modbus/modbusrtumanager.cpp @@ -31,6 +31,7 @@ #include "modbusrtumanager.h" #include "nymeasettings.h" #include "loggingcategories.h" + #include "modbusrtumasterimpl.h" NYMEA_LOGGING_CATEGORY(dcModbusRtu, "ModbusRtu") @@ -39,6 +40,12 @@ namespace nymeaserver { ModbusRtuManager::ModbusRtuManager(QObject *parent) : QObject(parent) { + // Load uart configurations + loadRtuMasters(); + + // Connect signals + + // Enable autoconnect for each modbus rtu master } @@ -61,9 +68,8 @@ ModbusRtuMaster *ModbusRtuManager::getModbusRtuMaster(const QUuid &modbusUuid) return nullptr; } -void ModbusRtuManager::init() +void ModbusRtuManager::loadRtuMasters() { - // Load uart configurations NymeaSettings settings(NymeaSettings::SettingsRoleModbusRtu); qCDebug(dcModbusRtu()) << "Loading modbus RTU resources from" << settings.fileName(); @@ -85,11 +91,6 @@ void ModbusRtuManager::init() } settings.endGroup(); // ModbusRtuMasters - - // Connect signals - - // Enable autoconnect for each modbus rtu master - } void ModbusRtuManager::saveModbusRtuMaster(ModbusRtuMaster *modbusRtuMaster) diff --git a/libnymea-core/modbus/modbusrtumanager.h b/libnymea-core/modbus/modbusrtumanager.h index 95497e00..0ee8ca82 100644 --- a/libnymea-core/modbus/modbusrtumanager.h +++ b/libnymea-core/modbus/modbusrtumanager.h @@ -50,8 +50,6 @@ public: bool hasModbusRtuMaster(const QUuid &modbusUuid) const; ModbusRtuMaster *getModbusRtuMaster(const QUuid &modbusUuid); - void init(); - signals: void modbusRtuMasterAdded(const QUuid &modbusUuid); void modbusRtuMasterRemoved(const QUuid &modbusUuid); @@ -60,6 +58,7 @@ signals: private: QHash m_modbusRtuMasters; + void loadRtuMasters(); void saveModbusRtuMaster(ModbusRtuMaster *modbusRtuMaster); }; diff --git a/libnymea-core/nymeacore.cpp b/libnymea-core/nymeacore.cpp index a746f8b8..4f8d9330 100644 --- a/libnymea-core/nymeacore.cpp +++ b/libnymea-core/nymeacore.cpp @@ -53,6 +53,8 @@ #include "zigbee/zigbeemanager.h" +#include "modbus/modbusrtumanager.h" + #include #include @@ -108,8 +110,11 @@ void NymeaCore::init(const QStringList &additionalInterfaces) { qCDebug(dcCore()) << "Create Zigbee Manager"; m_zigbeeManager = new ZigbeeManager(this); + qCDebug(dcCore()) << "Create Modbus RTU Manager"; + m_modbusRtuManager = new ModbusRtuManager(this); + qCDebug(dcCore) << "Creating Hardware Manager"; - m_hardwareManager = new HardwareManagerImplementation(m_platform, m_serverManager->mqttBroker(), m_zigbeeManager, this); + m_hardwareManager = new HardwareManagerImplementation(m_platform, m_serverManager->mqttBroker(), m_zigbeeManager, m_modbusRtuManager, this); qCDebug(dcCore) << "Creating Thing Manager (locale:" << m_configuration->locale() << ")"; m_thingManager = new ThingManagerImplementation(m_hardwareManager, m_configuration->locale(), this); @@ -645,6 +650,11 @@ ZigbeeManager *NymeaCore::zigbeeManager() const return m_zigbeeManager; } +ModbusRtuManager *NymeaCore::modbusRtuManager() const +{ + return m_modbusRtuManager; +} + void NymeaCore::gotEvent(const Event &event) { emit eventTriggered(event); diff --git a/libnymea-core/nymeacore.h b/libnymea-core/nymeacore.h index 3201b4d6..2514f7d4 100644 --- a/libnymea-core/nymeacore.h +++ b/libnymea-core/nymeacore.h @@ -67,6 +67,7 @@ class ExperienceManager; class ScriptEngine; class CloudManager; class ZigbeeManager; +class ModbusRtuManager; class NymeaCore : public QObject { @@ -107,6 +108,7 @@ public: TagsStorage *tagsStorage() const; Platform *platform() const; ZigbeeManager *zigbeeManager() const; + ModbusRtuManager *modbusRtuManager() const; static QStringList getAvailableLanguages(); static QStringList loggingFilters(); @@ -151,6 +153,7 @@ private: System *m_system; ExperienceManager *m_experienceManager; ZigbeeManager *m_zigbeeManager; + ModbusRtuManager *m_modbusRtuManager; QList m_executingRules; diff --git a/libnymea/hardware/modbus/modbusrtuhardwareresource.cpp b/libnymea/hardware/modbus/modbusrtuhardwareresource.cpp index 15756334..ddab12a7 100644 --- a/libnymea/hardware/modbus/modbusrtuhardwareresource.cpp +++ b/libnymea/hardware/modbus/modbusrtuhardwareresource.cpp @@ -29,6 +29,7 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "modbusrtuhardwareresource.h" +#include "modbusrtumaster.h" ModbusRtuHardwareResource::ModbusRtuHardwareResource(QObject *parent) : HardwareResource("Modbus RTU resource", parent) diff --git a/libnymea/hardware/modbus/modbusrtuhardwareresource.h b/libnymea/hardware/modbus/modbusrtuhardwareresource.h index 55356537..9be1a590 100644 --- a/libnymea/hardware/modbus/modbusrtuhardwareresource.h +++ b/libnymea/hardware/modbus/modbusrtuhardwareresource.h @@ -34,16 +34,16 @@ #include #include -#include "modbusrtumaster.h" #include "hardwareresource.h" +#include "modbusrtumaster.h" class ModbusRtuHardwareResource : public HardwareResource { Q_OBJECT public: virtual QList modbusRtuMasters() const = 0; - virtual bool hasModbusRtuMaster(const QUuid &modbusUuid) = 0; - virtual ModbusRtuMaster *getModbusRtuMaster(const QUuid &modbusUuid) = 0; + virtual bool hasModbusRtuMaster(const QUuid &modbusUuid) const = 0; + virtual ModbusRtuMaster *getModbusRtuMaster(const QUuid &modbusUuid) const = 0; protected: explicit ModbusRtuHardwareResource(QObject *parent = nullptr); diff --git a/libnymea/hardwaremanager.h b/libnymea/hardwaremanager.h index 711a0995..4dab713e 100644 --- a/libnymea/hardwaremanager.h +++ b/libnymea/hardwaremanager.h @@ -44,7 +44,7 @@ class MqttProvider; class I2CManager; class ZigbeeHardwareResource; class HardwareResource; -class ModbusRtuHardwareResouce; +class ModbusRtuHardwareResource; class HardwareManager : public QObject { @@ -64,7 +64,7 @@ public: virtual MqttProvider *mqttProvider() = 0; virtual I2CManager *i2cManager() = 0; virtual ZigbeeHardwareResource *zigbeeResource() = 0; - virtual ModbusRtuHardwareResouce *modbusRtuResource() = 0; + virtual ModbusRtuHardwareResource *modbusRtuResource() = 0; protected: void setResourceEnabled(HardwareResource* resource, bool enabled); diff --git a/tests/auto/autotests.pri b/tests/auto/autotests.pri index e2572913..5d2153e6 100644 --- a/tests/auto/autotests.pri +++ b/tests/auto/autotests.pri @@ -2,6 +2,18 @@ QT += dbus testlib network sql websockets CONFIG += testcase CONFIG += link_pkgconfig +# Qt serial bus module is officially available since Qt 5.8 +# but not all platforms host the qt serialbus package. +# Let's check if the package exists, not the qt version +packagesExist(Qt5SerialBus) { + message("Building with QtSerialBus support.") + # Qt += serialbus + PKGCONFIG += Qt5SerialBus + DEFINES += WITH_QTSERIALBUS +} else { + message("Qt5SerialBus package not found. Building without QtSerialBus support.") +} + INCLUDEPATH += $$top_srcdir/libnymea \ $$top_srcdir/libnymea-core \ $$top_srcdir/tests/testlib/ \ diff --git a/tests/testlib/testlib.pro b/tests/testlib/testlib.pro index 2c27f65e..b1768333 100644 --- a/tests/testlib/testlib.pro +++ b/tests/testlib/testlib.pro @@ -5,6 +5,14 @@ include(../../nymea.pri) QT += testlib dbus network sql websockets +# Qt serial bus module is officially available since Qt 5.8 +# but not all platforms host the qt serialbus package. +# Let's check if the package exists, not the qt version +packagesExist(Qt5SerialBus) { + Qt += serialbus + DEFINES += WITH_QTSERIALBUS +} + INCLUDEPATH += $$top_srcdir/libnymea \ $$top_srcdir/libnymea-core From ab7579de42cea2e63ea9153c9770fec0971c1c66 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Mon, 8 Feb 2021 16:21:41 +0100 Subject: [PATCH 06/24] Fix debian build dependency for serialbus --- debian/control | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/debian/control b/debian/control index 825ff765..cb26ac41 100644 --- a/debian/control +++ b/debian/control @@ -26,7 +26,7 @@ Build-Depends: debhelper (>= 9.0.0), qttools5-dev-tools, qtconnectivity5-dev, qtdeclarative5-dev, - | libqt5serialbus5-dev (>= 5.8~) + libqt5serialbus5-dev Package: nymea Architecture: any From af7948dc1e456d20846472031005db8433c55360 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Mon, 8 Feb 2021 17:55:33 +0100 Subject: [PATCH 07/24] Implement add/remove/reconfigure for modbus rtu manager --- libnymea-core/modbus/modbusrtumanager.cpp | 101 ++++++++++++++++++- libnymea-core/modbus/modbusrtumanager.h | 18 +++- libnymea-core/modbus/modbusrtumasterimpl.cpp | 60 +++++++++++ libnymea-core/modbus/modbusrtumasterimpl.h | 13 +++ libnymea/hardware/modbus/modbusrtumaster.h | 5 + 5 files changed, 191 insertions(+), 6 deletions(-) diff --git a/libnymea-core/modbus/modbusrtumanager.cpp b/libnymea-core/modbus/modbusrtumanager.cpp index f6101364..241f2e3c 100644 --- a/libnymea-core/modbus/modbusrtumanager.cpp +++ b/libnymea-core/modbus/modbusrtumanager.cpp @@ -40,13 +40,35 @@ namespace nymeaserver { ModbusRtuManager::ModbusRtuManager(QObject *parent) : QObject(parent) { + // Load available serial ports + updateSerialPorts(); + // Load uart configurations loadRtuMasters(); - // Connect signals - // Enable autoconnect for each modbus rtu master + m_timer = new QTimer(this); + m_timer->setInterval(5000); + m_timer->setSingleShot(false); + connect(m_timer, &QTimer::timeout, this, [=](){ + // Update serial port list + updateSerialPorts(); + // Check if we have to reconnect a device + foreach (ModbusRtuMaster *modbusMaster, m_modbusRtuMasters.values()) { + ModbusRtuMasterImpl *modbusMasterImpl = qobject_cast(modbusMaster); + + if (!modbusMasterImpl->connected()) { + if (!modbusMasterImpl->connectDevice()) { + qCDebug(dcModbusRtu()) << "Reconnect" << modbusMaster << "failed."; + } else { + qCDebug(dcModbusRtu()) << "Reconnected" << modbusMaster << "sucessfully."; + } + } + } + }); + + m_timer->start(); } QList ModbusRtuManager::modbusRtuMasters() const @@ -68,6 +90,79 @@ ModbusRtuMaster *ModbusRtuManager::getModbusRtuMaster(const QUuid &modbusUuid) return nullptr; } +QPair ModbusRtuManager::addNewModbusRtuMaster(const QString &serialPort, qint32 baudrate, QSerialPort::Parity parity, QSerialPort::DataBits dataBits, QSerialPort::StopBits stopBits) +{ + // Check if the serial port exists + + // Check if the serial port is not occupied + + QUuid modbusUuid = QUuid::createUuid(); + ModbusRtuMasterImpl *modbusMaster = new ModbusRtuMasterImpl(modbusUuid, serialPort, baudrate, parity, dataBits, stopBits, this); + ModbusRtuMaster *modbus = qobject_cast(modbusMaster); + qCDebug(dcModbusRtu()) << "Adding new" << qobject_cast(modbusMaster) << parity << dataBits << stopBits; + + // Connect the modbus master bus; + m_modbusRtuMasters.insert(modbusUuid, modbus); + emit modbusRtuMasterAdded(modbus); + saveModbusRtuMaster(modbus); + + return QPair(ErrorNoError, modbusUuid); +} + +ModbusRtuManager::Error ModbusRtuManager::reconfigureRtuMaster(const QUuid &modbusUuid, const QString &serialPort, qint32 baudrate, QSerialPort::Parity parity, QSerialPort::DataBits dataBits, QSerialPort::StopBits stopBits) +{ + if (!m_modbusRtuMasters.contains(modbusUuid)) { + qCWarning(dcModbusRtu()) << "Could not reconfigure modbus RTU master because no resource could be found with uuid" << modbusUuid.toString(); + return ErrorNotFound; + } + + ModbusRtuMasterImpl *modbusMaster = qobject_cast(m_modbusRtuMasters.value(modbusUuid)); + + // Disconnect + modbusMaster->disconnectDevice(); + + // Reconfigure + modbusMaster->setSerialPort(serialPort); + modbusMaster->setBaudrate(baudrate); + modbusMaster->setParity(parity); + modbusMaster->setDataBits(dataBits); + modbusMaster->setStopBits(stopBits); + + // Connect again + if (!modbusMaster->connectDevice()) { + qCWarning(dcModbusRtu()) << "Failed to connect to" << m_modbusRtuMasters.value(modbusUuid); + return ErrorConnectionFailed; + } + + emit modbusRtuMasterChanged(m_modbusRtuMasters.value(modbusUuid)); + + qCDebug(dcModbusRtu()) << "Reconfigured successfully" << m_modbusRtuMasters.value(modbusUuid); + return ErrorNoError; +} + + +ModbusRtuManager::Error ModbusRtuManager::removeModbusRtuMaster(const QUuid &modbusUuid) +{ + ModbusRtuMasterImpl *modbusMaster = qobject_cast(m_modbusRtuMasters.value(modbusUuid)); + if (!modbusMaster) { + qCWarning(dcModbusRtu()) << "Could not remove modbus RTU master because no resource could be found with uuid" << modbusUuid.toString(); + return ErrorNotFound; + } + + qCDebug(dcModbusRtu()) << "Removing modbus RTU master" << qobject_cast(modbusMaster); + emit modbusRtuMasterRemoved(modbusMaster); + + modbusMaster->deleteLater(); + return ErrorNoError; +} + +void ModbusRtuManager::updateSerialPorts() +{ + // Check if serial port added or removed + +} + + void ModbusRtuManager::loadRtuMasters() { NymeaSettings settings(NymeaSettings::SettingsRoleModbusRtu); @@ -87,7 +182,7 @@ void ModbusRtuManager::loadRtuMasters() ModbusRtuMaster *modbusRtuMaster = qobject_cast(modbus); qCDebug(dcModbusRtu()) << "Loaded" << modbusRtuMaster; m_modbusRtuMasters.insert(modbusRtuMaster->modbusUuid(), modbusRtuMaster); - emit modbusRtuMasterAdded(modbusRtuMaster->modbusUuid()); + emit modbusRtuMasterAdded(modbusRtuMaster); } settings.endGroup(); // ModbusRtuMasters diff --git a/libnymea-core/modbus/modbusrtumanager.h b/libnymea-core/modbus/modbusrtumanager.h index 0ee8ca82..fc01aa32 100644 --- a/libnymea-core/modbus/modbusrtumanager.h +++ b/libnymea-core/modbus/modbusrtumanager.h @@ -34,6 +34,7 @@ #include #include #include +#include #include "hardware/modbus/modbusrtumaster.h" @@ -43,6 +44,13 @@ class ModbusRtuManager : public QObject { Q_OBJECT public: + enum Error { + ErrorNoError, + ErrorNotFound, + ErrorConnectionFailed + }; + Q_ENUM(Error) + explicit ModbusRtuManager(QObject *parent = nullptr); ~ModbusRtuManager() = default; @@ -50,10 +58,14 @@ public: bool hasModbusRtuMaster(const QUuid &modbusUuid) const; ModbusRtuMaster *getModbusRtuMaster(const QUuid &modbusUuid); + QPair addNewModbusRtuMaster(const QString &serialPort, qint32 baudrate, QSerialPort::Parity parity, QSerialPort::DataBits dataBits, QSerialPort::StopBits stopBits); + Error reconfigureRtuMaster(const QUuid &modbusUuid, const QString &serialPort, qint32 baudrate, QSerialPort::Parity parity, QSerialPort::DataBits dataBits, QSerialPort::StopBits stopBits); + Error removeModbusRtuMaster(const QUuid &modbusUuid); + signals: - void modbusRtuMasterAdded(const QUuid &modbusUuid); - void modbusRtuMasterRemoved(const QUuid &modbusUuid); - void modbusRtuMasterChanged(const QUuid &modbusUuid); + void modbusRtuMasterAdded(ModbusRtuMaster *modbusRtuMaster); + void modbusRtuMasterRemoved(ModbusRtuMaster *modbusRtuMaster); + void modbusRtuMasterChanged(ModbusRtuMaster *modbusRtuMaster); private: QHash m_modbusRtuMasters; diff --git a/libnymea-core/modbus/modbusrtumasterimpl.cpp b/libnymea-core/modbus/modbusrtumasterimpl.cpp index 14be6556..de13800b 100644 --- a/libnymea-core/modbus/modbusrtumasterimpl.cpp +++ b/libnymea-core/modbus/modbusrtumasterimpl.cpp @@ -85,31 +85,91 @@ QString ModbusRtuMasterImpl::serialPort() const return m_serialPort; } +void ModbusRtuMasterImpl::setSerialPort(const QString &serialPort) +{ + if (m_serialPort == serialPort) + return; + + m_serialPort = serialPort; + emit serialPortChanged(m_serialPort); +} + qint32 ModbusRtuMasterImpl::baudrate() const { return m_baudrate; } +void ModbusRtuMasterImpl::setBaudrate(qint32 baudrate) +{ + if (m_baudrate == baudrate) + return; + + m_baudrate = baudrate; + emit baudrateChanged(m_baudrate); +} + QSerialPort::Parity ModbusRtuMasterImpl::parity() const { return m_parity; } +void ModbusRtuMasterImpl::setParity(QSerialPort::Parity parity) +{ + if (m_parity == parity) + return; + + m_parity = parity; + emit parityChanged(m_parity); +} + QSerialPort::DataBits ModbusRtuMasterImpl::dataBits() const { return m_dataBits; } +void ModbusRtuMasterImpl::setDataBits(QSerialPort::DataBits dataBits) +{ + if (m_dataBits == dataBits) + return; + + m_dataBits = dataBits; + emit dataBitsChanged(m_dataBits); +} + QSerialPort::StopBits ModbusRtuMasterImpl::stopBits() { return m_stopBits; } +void ModbusRtuMasterImpl::setStopBits(QSerialPort::StopBits stopBits) +{ + if (m_stopBits == stopBits) + return; + + m_stopBits = stopBits; + emit stopBitsChanged(m_stopBits); +} + bool ModbusRtuMasterImpl::connected() const { return m_connected; } +bool ModbusRtuMasterImpl::connectDevice() +{ + m_modbus->setConnectionParameter(QModbusDevice::SerialPortNameParameter, m_serialPort); + m_modbus->setConnectionParameter(QModbusDevice::SerialBaudRateParameter, m_baudrate); + m_modbus->setConnectionParameter(QModbusDevice::SerialDataBitsParameter, m_dataBits); + m_modbus->setConnectionParameter(QModbusDevice::SerialStopBitsParameter, m_stopBits); + m_modbus->setConnectionParameter(QModbusDevice::SerialParityParameter, m_parity); + return m_modbus->connectDevice(); +} + +void ModbusRtuMasterImpl::disconnectDevice() +{ + m_modbus->disconnectDevice(); +} + ModbusRtuReply *ModbusRtuMasterImpl::readCoil(int slaveAddress, int registerAddress, quint16 size) { #ifdef WITH_QTSERIALBUS diff --git a/libnymea-core/modbus/modbusrtumasterimpl.h b/libnymea-core/modbus/modbusrtumasterimpl.h index 15a99f52..d9eadd8c 100644 --- a/libnymea-core/modbus/modbusrtumasterimpl.h +++ b/libnymea-core/modbus/modbusrtumasterimpl.h @@ -50,14 +50,27 @@ public: ~ModbusRtuMasterImpl() override = default; QUuid modbusUuid() const override; + QString serialPort() const override; + void setSerialPort(const QString &serialPort); + qint32 baudrate() const override; + void setBaudrate(qint32 baudrate); + QSerialPort::Parity parity() const override; + void setParity(QSerialPort::Parity parity); + QSerialPort::DataBits dataBits() const override; + void setDataBits(QSerialPort::DataBits dataBits); + QSerialPort::StopBits stopBits() override; + void setStopBits(QSerialPort::StopBits stopBits); bool connected() const override; + bool connectDevice(); + void disconnectDevice(); + // Requests ModbusRtuReply *readCoil(int slaveAddress, int registerAddress, quint16 size = 1) override; ModbusRtuReply *readDiscreteInput(int slaveAddress, int registerAddress, quint16 size = 1) override; diff --git a/libnymea/hardware/modbus/modbusrtumaster.h b/libnymea/hardware/modbus/modbusrtumaster.h index a8caf09c..4d6740a5 100644 --- a/libnymea/hardware/modbus/modbusrtumaster.h +++ b/libnymea/hardware/modbus/modbusrtumaster.h @@ -67,6 +67,11 @@ protected: signals: void connectedChanged(bool connected); + void serialPortChanged(const QString &serialPort); + void baudrateChanged(quint32 baudrate); + void parityChanged(QSerialPort::Parity parity); + void dataBitsChanged(QSerialPort::DataBits dataBits); + void stopBitsChanged(QSerialPort::StopBits stopBits); }; From 72a0db6d0d47442e63afacea37f68736f5a3a31f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Wed, 10 Feb 2021 17:07:57 +0100 Subject: [PATCH 08/24] Implement ModbusRtu JSONRPC API --- .../hardware/serialport/serialportmonitor.cpp | 189 ++++++++++++++++ .../hardware/serialport/serialportmonitor.h | 145 ++++++++++++ .../jsonrpc/jsonrpcserverimplementation.cpp | 2 + libnymea-core/jsonrpc/modbusrtuhandler.cpp | 214 +++++++++++++++++- libnymea-core/jsonrpc/modbusrtuhandler.h | 24 +- libnymea-core/libnymea-core.pro | 10 + libnymea-core/modbus/modbusrtumanager.cpp | 102 +++++---- libnymea-core/modbus/modbusrtumanager.h | 27 ++- libnymea-core/nymeacore.cpp | 6 +- libnymea-core/nymeacore.h | 2 + 10 files changed, 663 insertions(+), 58 deletions(-) create mode 100644 libnymea-core/hardware/serialport/serialportmonitor.cpp create mode 100644 libnymea-core/hardware/serialport/serialportmonitor.h diff --git a/libnymea-core/hardware/serialport/serialportmonitor.cpp b/libnymea-core/hardware/serialport/serialportmonitor.cpp new file mode 100644 index 00000000..cd1addfc --- /dev/null +++ b/libnymea-core/hardware/serialport/serialportmonitor.cpp @@ -0,0 +1,189 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2021, 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 Lesser General Public License Usage +* Alternatively, this project may be redistributed and/or modified under the +* terms of the GNU Lesser General Public License as published by the Free +* Software Foundation; 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 +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License +* along with this project. If not, see . +* +* 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 "serialportmonitor.h" +#include "loggingcategories.h" + +namespace nymeaserver { + +NYMEA_LOGGING_CATEGORY(dcSerialPortMonitor, "SerialPortMonitor") + +SerialPortMonitor::SerialPortMonitor(QObject *parent) : QObject(parent) +{ + // Read initially all tty devices + foreach (const QSerialPortInfo &serialPortInfo, QSerialPortInfo::availablePorts()) { + m_serialPorts.insert(serialPortInfo.systemLocation(), SerialPort(serialPortInfo)); + } + +#ifdef WITH_UDEV + // Init udev + m_udev = udev_new(); + if (!m_udev) { + qCWarning(dcSerialPortMonitor()) << "Could not initialize udev for the adapter monitor"; + return; + } + + // Create udev monitor + m_monitor = udev_monitor_new_from_netlink(m_udev, "udev"); + if (!m_monitor) { + qCWarning(dcSerialPortMonitor()) << "Could not initialize udev monitor."; + udev_unref(m_udev); + m_udev = nullptr; + return; + } + + // Set monitor filter to tty subsystem + if (udev_monitor_filter_add_match_subsystem_devtype(m_monitor, "tty", nullptr) < 0) { + qCWarning(dcSerialPortMonitor()) << "Could not set subsystem device type filter to tty."; + udev_monitor_unref(m_monitor); + m_monitor = nullptr; + udev_unref(m_udev); + m_udev = nullptr; + return; + } + + // Enable the monitor + if (udev_monitor_enable_receiving(m_monitor) < 0) { + qCWarning(dcSerialPortMonitor()) << "Could not enable udev monitor."; + udev_monitor_unref(m_monitor); + m_monitor = nullptr; + udev_unref(m_udev); + m_udev = nullptr; + return; + } + + // Create socket notifier for read + int socketDescriptor = udev_monitor_get_fd(m_monitor); + m_notifier = new QSocketNotifier(socketDescriptor, QSocketNotifier::Read, this); + connect(m_notifier, &QSocketNotifier::activated, this, [this, socketDescriptor](int socket){ + // Make sure the socket matches + if (socketDescriptor != socket) { + qCWarning(dcSerialPortMonitor()) << "Socket handles do not match. socket != socketdescriptor"; + return; + } + + // Create udev device + udev_device *device = udev_monitor_receive_device(m_monitor); + if (!device) { + qCWarning(dcSerialPortMonitor()) << "Got socket sotification but could not read device information."; + return; + } + + QString actionString = QString::fromLatin1(udev_device_get_action(device)); + QString systemPath = QString::fromLatin1(udev_device_get_property_value(device,"DEVNAME")); + QString manufacturerString = QString::fromLatin1(udev_device_get_property_value(device,"ID_VENDOR_ENC")); + QString descriptionString = QString::fromLatin1(udev_device_get_property_value(device,"ID_MODEL_ENC")); + QString serialNumberString = QString::fromLatin1(udev_device_get_property_value(device, "ID_SERIAL_SHORT")); + + // Clean udev device + udev_device_unref(device); + + // Make sure we know the action + if (actionString.isEmpty()) + return; + + if (actionString == "add") { + qCDebug(dcSerialPortMonitor()) << "[+]" << systemPath << serialNumberString << manufacturerString << descriptionString; + if (!m_serialPorts.contains(systemPath)) { + // Get the serial port info and add it internally + foreach (const QSerialPortInfo &serialPortInfo, QSerialPortInfo::availablePorts()) { + if (serialPortInfo.systemLocation() == systemPath) { + addSerialPortInternally(SerialPort(serialPortInfo)); + } + } + + } + } + + if (actionString == "remove") { + qCDebug(dcSerialPortMonitor()) << "[-]" << systemPath << serialNumberString << manufacturerString << descriptionString; + if (m_serialPorts.contains(systemPath)) { + SerialPort serialPort = m_serialPorts.take(systemPath); + qCDebug(dcSerialPortMonitor()) << "Removed" << serialPort.systemLocation(); + emit serialPortRemoved(serialPort); + } + } + }); + + qCDebug(dcSerialPortMonitor()) << "Serial port monitor enabled successfully"; + foreach (const SerialPort &serialPort, m_serialPorts) { + qCDebug(dcSerialPortMonitor()) << "-" << serialPort.systemLocation() << serialPort.description(); + } + m_notifier->setEnabled(true); +#else + m_timer = new QTimer(this); + m_timer->setInterval(5000); + m_timer->setSingleShot(false); + connect(m_timer, &QTimer::timeout, this, [=](){ + QStringList availablePorts; + // Add a new adapter if not in the list already + foreach (const QSerialPortInfo &serialPortInfo, QSerialPortInfo::availablePorts()) { + availablePorts.append(serialPortInfo.systemLocation()); + if (!m_serialPorts.keys().contains(serialPortInfo.systemLocation())) { + qCDebug(dcSerialPortMonitor()) << "[+]" << serialPortInfo.systemLocation() << serialPortInfo.manufacturer() << serialPortInfo.description(); + addSerialPortInternally(SerialPort(serialPortInfo)); + } + } + // Remove adapters no longer available + foreach (const QString &systemLocation, m_serialPorts.keys()) { + if (!availablePorts.contains(systemLocation)) { + SerialPort serialPortInfo = m_serialPorts.take(systemLocation); + qCDebug(dcSerialPortMonitor()) << "[-]" << serialPortInfo.systemLocation() << serialPortInfo.manufacturer() << serialPortInfo.description(); + emit serialPortRemoved(serialPortInfo); + } + } + }); + m_timer->start(); + +#endif +} + +SerialPorts SerialPortMonitor::serialPorts() const +{ + return m_serialPorts.values(); +} + +bool SerialPortMonitor::serialPortAvailable(const QString &systemLocation) const +{ + return m_serialPorts.keys().contains(systemLocation); +} + +void SerialPortMonitor::addSerialPortInternally(const SerialPort &serialPort) +{ + if (m_serialPorts.keys().contains(serialPort.systemLocation())) { + qCWarning(dcSerialPortMonitor()) << "Tried to add serial port but the port has alrady been added."; + return; + } + + m_serialPorts.insert(serialPort.systemLocation(), serialPort); + emit serialPortAdded(serialPort); +} + +} diff --git a/libnymea-core/hardware/serialport/serialportmonitor.h b/libnymea-core/hardware/serialport/serialportmonitor.h new file mode 100644 index 00000000..115b6b04 --- /dev/null +++ b/libnymea-core/hardware/serialport/serialportmonitor.h @@ -0,0 +1,145 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * +* +* Copyright 2013 - 2021, 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 Lesser General Public License Usage +* Alternatively, this project may be redistributed and/or modified under the +* terms of the GNU Lesser General Public License as published by the Free +* Software Foundation; 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 +* Lesser General Public License for more details. +* +* You should have received a copy of the GNU Lesser General Public License +* along with this project. If not, see . +* +* 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 SERIALPORTMONITOR_H +#define SERIALPORTMONITOR_H + +#include +#include +#include +#include + +#ifdef WITH_UDEV +#include +#include +#else +#include +#endif + +namespace nymeaserver { + +class SerialPort : public QSerialPortInfo { + Q_GADGET + Q_PROPERTY(QString systemLocation READ systemLocation) + Q_PROPERTY(QString manufacturer READ manufacturer) + Q_PROPERTY(QString description READ description) + Q_PROPERTY(QString serialNumber READ serialNumber) + +public: + enum SerialPortParity { + SerialPortParityNoParity = 0, + SerialPortParityEvenParity = 2, + SerialPortParityOddParity = 3, + SerialPortParitySpaceParity = 4, + SerialPortParityMarkParity = 5, + SerialPortParityUnknownParity = -1 + }; + Q_ENUM(SerialPortParity) + + + enum SerialPortDataBits { + SerialPortDataBitsData5 = 5, + SerialPortDataBitsData6 = 6, + SerialPortDataBitsData7 = 7, + SerialPortDataBitsData8 = 8, + SerialPortDataBitsUnknownDataBits = -1 + }; + Q_ENUM(SerialPortDataBits) + + + enum SerialPortStopBits { + SerialPortStopBitsOneStop = 1, + SerialPortStopBitsOneAndHalfStop = 3, + SerialPortStopBitsTwoStop = 2, + SerialPortStopBitsUnknownStopBits = -1 + }; + Q_ENUM(SerialPortStopBits) + + SerialPort() : QSerialPortInfo() { }; + explicit SerialPort(const QSerialPortInfo &other) : QSerialPortInfo(other) { }; + +}; + +class SerialPorts : public QList +{ + Q_GADGET + Q_PROPERTY(int count READ count) + +public: + inline SerialPorts() = default; + inline SerialPorts(const QList &other) : QList(other) { }; + inline bool hasSerialPort(const QString &serialPort) { + for (int i = 0; i < count(); i++) { + if (at(i).systemLocation() == serialPort) { + return true; + } + } + return false; + }; + + inline Q_INVOKABLE QVariant get(int index) const { return QVariant::fromValue(at(index)); }; + inline Q_INVOKABLE void put(const QVariant &variant) { append(variant.value()); }; +}; + + +class SerialPortMonitor : public QObject +{ + Q_OBJECT +public: + explicit SerialPortMonitor(QObject *parent = nullptr); + + SerialPorts serialPorts() const; + bool serialPortAvailable(const QString &systemLocation) const; + +signals: + void serialPortAdded(const SerialPort &serialPort); + void serialPortRemoved(const SerialPort &serialPort); + +private: + QHash m_serialPorts; + + void addSerialPortInternally(const SerialPort &serialPort); + +#ifdef WITH_UDEV + struct udev *m_udev = nullptr; + struct udev_monitor *m_monitor = nullptr; + QSocketNotifier *m_notifier = nullptr; +#else + QTimer *m_timer = nullptr; +#endif + +}; + +} + +Q_DECLARE_METATYPE(nymeaserver::SerialPort) +Q_DECLARE_METATYPE(nymeaserver::SerialPorts) + +#endif // SERIALPORTMONITOR_H diff --git a/libnymea-core/jsonrpc/jsonrpcserverimplementation.cpp b/libnymea-core/jsonrpc/jsonrpcserverimplementation.cpp index 36a75646..147c460e 100644 --- a/libnymea-core/jsonrpc/jsonrpcserverimplementation.cpp +++ b/libnymea-core/jsonrpc/jsonrpcserverimplementation.cpp @@ -75,6 +75,7 @@ #include "systemhandler.h" #include "usershandler.h" #include "zigbeehandler.h" +#include "modbusrtuhandler.h" #include #include @@ -599,6 +600,7 @@ void JsonRPCServerImplementation::setup() registerHandler(new SystemHandler(NymeaCore::instance()->platform(), this)); registerHandler(new UsersHandler(NymeaCore::instance()->userManager(), this)); registerHandler(new ZigbeeHandler(NymeaCore::instance()->zigbeeManager(), this)); + registerHandler(new ModbusRtuHandler(NymeaCore::instance()->modbusRtuManager(), this)); connect(NymeaCore::instance()->cloudManager(), &CloudManager::pairingReply, this, &JsonRPCServerImplementation::pairingFinished); connect(NymeaCore::instance()->cloudManager(), &CloudManager::connectionStateChanged, this, &JsonRPCServerImplementation::onCloudConnectionStateChanged); diff --git a/libnymea-core/jsonrpc/modbusrtuhandler.cpp b/libnymea-core/jsonrpc/modbusrtuhandler.cpp index 535deb6b..1a210485 100644 --- a/libnymea-core/jsonrpc/modbusrtuhandler.cpp +++ b/libnymea-core/jsonrpc/modbusrtuhandler.cpp @@ -29,12 +29,140 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "modbusrtuhandler.h" +#include "modbus/modbusrtumanager.h" +#include "hardware/serialport/serialportmonitor.h" namespace nymeaserver { -ModbusRtuHandler::ModbusRtuHandler(QObject *parent) : JsonHandler(parent) +ModbusRtuHandler::ModbusRtuHandler(ModbusRtuManager *modbusRtuManager, QObject *parent) : + JsonHandler(parent), + m_modbusRtuManager(modbusRtuManager) { + qRegisterMetaType(); + registerEnum(); + registerEnum(); + registerEnum(); + registerEnum(); + registerObject(); + QVariantMap modbusRtuMasterDescription; + modbusRtuMasterDescription.insert("modbusUuid", enumValueName(Uuid)); + modbusRtuMasterDescription.insert("connected", enumValueName(Bool)); + modbusRtuMasterDescription.insert("serialPort", enumValueName(String)); + modbusRtuMasterDescription.insert("baudrate", enumValueName(Uint)); + modbusRtuMasterDescription.insert("parity", enumRef()); + modbusRtuMasterDescription.insert("stopBits", enumRef()); + modbusRtuMasterDescription.insert("dataBits", enumRef()); + registerObject("ModbusRtuMaster", modbusRtuMasterDescription); + + QVariantMap params, returns; + QString description; + + // GetSerialPorts + params.clear(); returns.clear(); + description = "Get the list of available serial ports from the host system."; + returns.insert("serialPorts", objectRef()); + registerMethod("GetSerialPorts", description, params, returns); + + // SerialPortAdded notification + params.clear(); + description = "Emitted whenever a serial port has been added to the system."; + params.insert("serialPort", objectRef()); + registerNotification("SerialPortAdded", description, params); + + // SerialPortRemoved notification + params.clear(); + description = "Emitted whenever a serial port has been removed from the system."; + params.insert("serialPort", objectRef()); + registerNotification("SerialPortRemoved", description, params); + + // GetModbusRtuMasters + params.clear(); returns.clear(); + description = "Get the list of configured modbus RTU masters."; + returns.insert("modbusRtuMasters", QVariantList() << objectRef("ModbusRtuMaster")); + registerMethod("GetModbusRtuMasters", description, params, returns); + + // ModbusRtuMasterAdded notification + params.clear(); + description = "Emitted whenever a new modbus RTU master has been added to the system."; + params.insert("modbusRtuMaster", objectRef("ModbusRtuMaster")); + registerNotification("ModbusRtuMasterAdded", description, params); + + // ModbusRtuMasterRemoved notification + params.clear(); + description = "Emitted whenever a new modbus RTU master has been removed from the system."; + params.insert("modbusUuid", enumValueName(Uuid)); + registerNotification("ModbusRtuMasterRemoved", description, params); + + // ModbusRtuMasterChanged notification + params.clear(); + description = "Emitted whenever a new modbus RTU master has been changed to the system."; + params.insert("modbusRtuMaster", objectRef("ModbusRtuMaster")); + registerNotification("ModbusRtuMasterChanged", description, params); + + // AddModbusRtuMaster + params.clear(); returns.clear(); + description = "Add a new modbus RTU master with the given configuration."; + params.insert("serialPort", enumValueName(String)); + params.insert("baudrate", enumValueName(Uint)); + params.insert("parity", enumRef()); + params.insert("dataBits", enumRef()); + params.insert("stopBits", enumRef()); + returns.insert("o:modbusUuid", enumValueName(Uuid)); + returns.insert("modbusError", enumRef()); + registerMethod("AddModbusRtuMaster", description, params, returns); + + // RemoveModbusRtuMaster + params.clear(); returns.clear(); + description = "Remove the modbus RTU master with the given modbus UUID."; + params.insert("modbusUuid", enumValueName(Uuid)); + returns.insert("modbusError", enumRef()); + registerMethod("RemoveModbusRtuMaster", description, params, returns); + + // ReconfigureModbusRtuMaster + params.clear(); returns.clear(); + description = "Rconfigure the modbus RTU master with the given UUID and configuration."; + params.insert("modbusUuid", enumValueName(Uuid)); + params.insert("serialPort", enumValueName(String)); + params.insert("baudrate", enumValueName(Uint)); + params.insert("parity", enumRef()); + params.insert("dataBits", enumRef()); + params.insert("stopBits", enumRef()); + returns.insert("modbusError", enumRef()); + registerMethod("ReconfigureModbusRtuMaster", description, params, returns); + + // Serial port monitor + connect(modbusRtuManager->serialPortMonitor(), &SerialPortMonitor::serialPortAdded, this, [=](const SerialPort &serialPort){ + QVariantMap params; + params.insert("serialPort", pack(serialPort)); + emit SerialPortAdded(params); + }); + + connect(modbusRtuManager->serialPortMonitor(), &SerialPortMonitor::serialPortRemoved, this, [=](const SerialPort &serialPort){ + QVariantMap params; + params.insert("serialPort", pack(serialPort)); + emit SerialPortAdded(params); + }); + + + // Modbus manager + connect(modbusRtuManager, &ModbusRtuManager::modbusRtuMasterAdded, this, [=](ModbusRtuMaster *modbusRtuMaster){ + QVariantMap params; + params.insert("modbusRtuMaster", packModbusRtuMaster(modbusRtuMaster)); + emit ModbusRtuMasterAdded(params); + }); + + connect(modbusRtuManager, &ModbusRtuManager::modbusRtuMasterChanged, this, [=](ModbusRtuMaster *modbusRtuMaster){ + QVariantMap params; + params.insert("modbusRtuMaster", packModbusRtuMaster(modbusRtuMaster)); + emit ModbusRtuMasterChanged(params); + }); + + connect(modbusRtuManager, &ModbusRtuManager::modbusRtuMasterRemoved, this, [=](ModbusRtuMaster *modbusRtuMaster){ + QVariantMap params; + params.insert("modbusUuid", modbusRtuMaster->modbusUuid()); + emit ModbusRtuMasterRemoved(params); + }); } QString ModbusRtuHandler::name() const @@ -42,4 +170,88 @@ QString ModbusRtuHandler::name() const return "ModbusRtu"; } +JsonReply *ModbusRtuHandler::GetSerialPorts(const QVariantMap ¶ms) +{ + Q_UNUSED(params) + + QVariantMap returnMap; + QVariantList portList; + foreach (const SerialPort &serialPort, m_modbusRtuManager->serialPortMonitor()->serialPorts()) { + portList << pack(serialPort); + } + returnMap.insert("serialPorts", portList); + return createReply(returnMap); +} + +JsonReply *ModbusRtuHandler::GetModbusRtuMasters(const QVariantMap ¶ms) +{ + Q_UNUSED(params) + + QVariantMap returnMap; + QVariantList modbusList; + foreach (ModbusRtuMaster *modbusMaster, m_modbusRtuManager->modbusRtuMasters()) { + modbusList << packModbusRtuMaster(modbusMaster); + } + returnMap.insert("modbusRtuMasters", modbusList); + return createReply(returnMap); +} + +JsonReply *ModbusRtuHandler::AddModbusRtuMaster(const QVariantMap ¶ms) +{ + QString serialPort = params.value("serialPort").toString(); + qint32 baudrate = params.value("baudrate").toUInt(); + QSerialPort::Parity parity = static_cast(enumNameToValue(params.value("parity").toString())); + QSerialPort::StopBits stopBits = static_cast(enumNameToValue(params.value("stopBits").toString())); + QSerialPort::DataBits dataBits = static_cast(enumNameToValue(params.value("dataBits").toString())); + + QPair result = m_modbusRtuManager->addNewModbusRtuMaster(serialPort, baudrate, parity, dataBits, stopBits); + + QVariantMap returnMap; + returnMap.insert("modbusError", enumValueName(result.first)); + if (result.first == ModbusRtuManager::ModbusRtuErrorNoError) { + returnMap.insert("modbusUuid", result.second); + } + + return createReply(returnMap); +} + +JsonReply *ModbusRtuHandler::RemoveModbusRtuMaster(const QVariantMap ¶ms) +{ + QUuid modbusUuid = params.value("modbusUuid").toUuid(); + + ModbusRtuManager::ModbusRtuError result = m_modbusRtuManager->removeModbusRtuMaster(modbusUuid); + QVariantMap returnMap; + returnMap.insert("modbusError", enumValueName(result)); + return createReply(returnMap); +} + +JsonReply *ModbusRtuHandler::ReconfigureModbusRtuMaster(const QVariantMap ¶ms) +{ + QUuid modbusUuid = params.value("modbusUuid").toUuid(); + QString serialPort = params.value("serialPort").toString(); + qint32 baudrate = params.value("baudrate").toUInt(); + QSerialPort::Parity parity = static_cast(enumNameToValue(params.value("parity").toString())); + QSerialPort::StopBits stopBits = static_cast(enumNameToValue(params.value("stopBits").toString())); + QSerialPort::DataBits dataBits = static_cast(enumNameToValue(params.value("dataBits").toString())); + + ModbusRtuManager::ModbusRtuError result = m_modbusRtuManager->reconfigureModbusRtuMaster(modbusUuid, serialPort, baudrate, parity, dataBits, stopBits); + QVariantMap returnMap; + returnMap.insert("modbusError", enumValueName(result)); + return createReply(returnMap); +} + + +QVariantMap ModbusRtuHandler::packModbusRtuMaster(ModbusRtuMaster *modbusRtuMaster) +{ + QVariantMap modbusRtuMasterMap; + modbusRtuMasterMap.insert("modbusUuid", modbusRtuMaster->modbusUuid()); + modbusRtuMasterMap.insert("connected", modbusRtuMaster->connected()); + modbusRtuMasterMap.insert("serialPort", modbusRtuMaster->serialPort()); + modbusRtuMasterMap.insert("baudrate", modbusRtuMaster->baudrate()); + modbusRtuMasterMap.insert("parity", enumValueName(static_cast(modbusRtuMaster->parity()))); + modbusRtuMasterMap.insert("stopBits", enumValueName(static_cast(modbusRtuMaster->stopBits()))); + modbusRtuMasterMap.insert("dataBits", enumValueName(static_cast(modbusRtuMaster->dataBits()))); + return modbusRtuMasterMap; +} + } diff --git a/libnymea-core/jsonrpc/modbusrtuhandler.h b/libnymea-core/jsonrpc/modbusrtuhandler.h index a0242525..171d3540 100644 --- a/libnymea-core/jsonrpc/modbusrtuhandler.h +++ b/libnymea-core/jsonrpc/modbusrtuhandler.h @@ -34,19 +34,39 @@ #include #include "jsonrpc/jsonhandler.h" +#include "hardware/modbus/modbusrtumaster.h" namespace nymeaserver { +class ModbusRtuManager; + class ModbusRtuHandler : public JsonHandler { Q_OBJECT public: - explicit ModbusRtuHandler(QObject *parent = nullptr); + explicit ModbusRtuHandler(ModbusRtuManager *modbusRtuManager, QObject *parent = nullptr); QString name() const override; -signals: + Q_INVOKABLE JsonReply *GetSerialPorts(const QVariantMap ¶ms); + Q_INVOKABLE JsonReply *GetModbusRtuMasters(const QVariantMap ¶ms); + Q_INVOKABLE JsonReply *AddModbusRtuMaster(const QVariantMap ¶ms); + Q_INVOKABLE JsonReply *RemoveModbusRtuMaster(const QVariantMap ¶ms); + Q_INVOKABLE JsonReply *ReconfigureModbusRtuMaster(const QVariantMap ¶ms); + +signals: + void SerialPortAdded(const QVariantMap ¶ms); + void SerialPortRemoved(const QVariantMap ¶ms); + + void ModbusRtuMasterAdded(const QVariantMap ¶ms); + void ModbusRtuMasterRemoved(const QVariantMap ¶ms); + void ModbusRtuMasterChanged(const QVariantMap ¶ms); + +private: + ModbusRtuManager *m_modbusRtuManager = nullptr; + + QVariantMap packModbusRtuMaster(ModbusRtuMaster *modbusRtuMaster); }; } diff --git a/libnymea-core/libnymea-core.pro b/libnymea-core/libnymea-core.pro index 1668715f..eb17feef 100644 --- a/libnymea-core/libnymea-core.pro +++ b/libnymea-core/libnymea-core.pro @@ -47,6 +47,14 @@ packagesExist(Qt5SerialBus) { message("Qt5SerialBus package not found. Building without QtSerialBus support.") } +# Note: udev is not available on all platforms +packagesExist(libudev) { + message("Build with udev support") + PKGCONFIG += libudev + DEFINES += WITH_UDEV +} else { + message("Build without udev support.") +} target.path = $$[QT_INSTALL_LIBS] INSTALLS += target @@ -57,6 +65,7 @@ RESOURCES += $$top_srcdir/icons.qrc \ HEADERS += nymeacore.h \ + hardware/serialport/serialportmonitor.h \ integrations/apikeysprovidersloader.h \ integrations/plugininfocache.h \ integrations/python/pyapikeystorage.h \ @@ -156,6 +165,7 @@ HEADERS += nymeacore.h \ SOURCES += nymeacore.cpp \ + hardware/serialport/serialportmonitor.cpp \ integrations/apikeysprovidersloader.cpp \ integrations/plugininfocache.cpp \ integrations/thingmanagerimplementation.cpp \ diff --git a/libnymea-core/modbus/modbusrtumanager.cpp b/libnymea-core/modbus/modbusrtumanager.cpp index 241f2e3c..55b20a37 100644 --- a/libnymea-core/modbus/modbusrtumanager.cpp +++ b/libnymea-core/modbus/modbusrtumanager.cpp @@ -33,32 +33,28 @@ #include "loggingcategories.h" #include "modbusrtumasterimpl.h" +#include "hardware/serialport/serialportmonitor.h" NYMEA_LOGGING_CATEGORY(dcModbusRtu, "ModbusRtu") namespace nymeaserver { -ModbusRtuManager::ModbusRtuManager(QObject *parent) : QObject(parent) +ModbusRtuManager::ModbusRtuManager(SerialPortMonitor *serialPortMonitor, QObject *parent) : + QObject(parent), + m_serialPortMonitor(serialPortMonitor) { - // Load available serial ports - updateSerialPorts(); - // Load uart configurations loadRtuMasters(); - // Enable autoconnect for each modbus rtu master - m_timer = new QTimer(this); - m_timer->setInterval(5000); - m_timer->setSingleShot(false); - connect(m_timer, &QTimer::timeout, this, [=](){ - // Update serial port list - updateSerialPorts(); + connect(m_serialPortMonitor, &SerialPortMonitor::serialPortAdded, this, [=](const QSerialPortInfo &serialPortInfo){ + qCDebug(dcModbusRtu()) << "Serial port added. Verify modbus RTU masters..."; - // Check if we have to reconnect a device + // Check if we have to reconnect any modbus RTU masters foreach (ModbusRtuMaster *modbusMaster, m_modbusRtuMasters.values()) { ModbusRtuMasterImpl *modbusMasterImpl = qobject_cast(modbusMaster); - if (!modbusMasterImpl->connected()) { + // Try only to reconnect if the added serial port matches a disconnected modbus RTU master + if (!modbusMasterImpl->connected() && modbusMasterImpl->serialPort() == serialPortInfo.systemLocation()) { if (!modbusMasterImpl->connectDevice()) { qCDebug(dcModbusRtu()) << "Reconnect" << modbusMaster << "failed."; } else { @@ -67,8 +63,11 @@ ModbusRtuManager::ModbusRtuManager(QObject *parent) : QObject(parent) } } }); +} - m_timer->start(); +SerialPortMonitor *ModbusRtuManager::serialPortMonitor() const +{ + return m_serialPortMonitor; } QList ModbusRtuManager::modbusRtuMasters() const @@ -90,30 +89,37 @@ ModbusRtuMaster *ModbusRtuManager::getModbusRtuMaster(const QUuid &modbusUuid) return nullptr; } -QPair ModbusRtuManager::addNewModbusRtuMaster(const QString &serialPort, qint32 baudrate, QSerialPort::Parity parity, QSerialPort::DataBits dataBits, QSerialPort::StopBits stopBits) +QPair ModbusRtuManager::addNewModbusRtuMaster(const QString &serialPort, qint32 baudrate, QSerialPort::Parity parity, QSerialPort::DataBits dataBits, QSerialPort::StopBits stopBits) { // Check if the serial port exists - - // Check if the serial port is not occupied + if (!m_serialPortMonitor->serialPortAvailable(serialPort)) { + qCWarning(dcModbusRtu()) << "Cannot add new modbus RTU master because the serial port" << serialPort << "is not available any more"; + return QPair(ModbusRtuErrorHardwareNotFound, QUuid()); + } QUuid modbusUuid = QUuid::createUuid(); ModbusRtuMasterImpl *modbusMaster = new ModbusRtuMasterImpl(modbusUuid, serialPort, baudrate, parity, dataBits, stopBits, this); ModbusRtuMaster *modbus = qobject_cast(modbusMaster); - qCDebug(dcModbusRtu()) << "Adding new" << qobject_cast(modbusMaster) << parity << dataBits << stopBits; + qCDebug(dcModbusRtu()) << "Adding new" << modbus << parity << dataBits << stopBits; - // Connect the modbus master bus; - m_modbusRtuMasters.insert(modbusUuid, modbus); - emit modbusRtuMasterAdded(modbus); + // Note: We could add the modbus master event if a connection is currently not possible...not sure yet + if (!modbusMaster->connectDevice()) { + qCWarning(dcModbusRtu()) << "Failed to add new modbus RTU master. Could not connect to" << modbus << parity << dataBits << stopBits; + modbusMaster->deleteLater(); + return QPair(ModbusRtuErrorConnectionFailed, QUuid()); + } + + addModbusRtuMasterInternally(modbusMaster); saveModbusRtuMaster(modbus); - return QPair(ErrorNoError, modbusUuid); + return QPair(ModbusRtuErrorNoError, modbusUuid); } -ModbusRtuManager::Error ModbusRtuManager::reconfigureRtuMaster(const QUuid &modbusUuid, const QString &serialPort, qint32 baudrate, QSerialPort::Parity parity, QSerialPort::DataBits dataBits, QSerialPort::StopBits stopBits) +ModbusRtuManager::ModbusRtuError ModbusRtuManager::reconfigureModbusRtuMaster(const QUuid &modbusUuid, const QString &serialPort, qint32 baudrate, QSerialPort::Parity parity, QSerialPort::DataBits dataBits, QSerialPort::StopBits stopBits) { if (!m_modbusRtuMasters.contains(modbusUuid)) { qCWarning(dcModbusRtu()) << "Could not reconfigure modbus RTU master because no resource could be found with uuid" << modbusUuid.toString(); - return ErrorNotFound; + return ModbusRtuErrorUuidNotFound; } ModbusRtuMasterImpl *modbusMaster = qobject_cast(m_modbusRtuMasters.value(modbusUuid)); @@ -131,38 +137,33 @@ ModbusRtuManager::Error ModbusRtuManager::reconfigureRtuMaster(const QUuid &modb // Connect again if (!modbusMaster->connectDevice()) { qCWarning(dcModbusRtu()) << "Failed to connect to" << m_modbusRtuMasters.value(modbusUuid); - return ErrorConnectionFailed; + emit modbusRtuMasterChanged(m_modbusRtuMasters.value(modbusUuid)); + return ModbusRtuErrorConnectionFailed; } emit modbusRtuMasterChanged(m_modbusRtuMasters.value(modbusUuid)); qCDebug(dcModbusRtu()) << "Reconfigured successfully" << m_modbusRtuMasters.value(modbusUuid); - return ErrorNoError; + return ModbusRtuErrorNoError; } - -ModbusRtuManager::Error ModbusRtuManager::removeModbusRtuMaster(const QUuid &modbusUuid) +ModbusRtuManager::ModbusRtuError ModbusRtuManager::removeModbusRtuMaster(const QUuid &modbusUuid) { - ModbusRtuMasterImpl *modbusMaster = qobject_cast(m_modbusRtuMasters.value(modbusUuid)); - if (!modbusMaster) { + if (!m_modbusRtuMasters.contains(modbusUuid)) { qCWarning(dcModbusRtu()) << "Could not remove modbus RTU master because no resource could be found with uuid" << modbusUuid.toString(); - return ErrorNotFound; + return ModbusRtuErrorUuidNotFound; } + ModbusRtuMasterImpl *modbusMaster = qobject_cast(m_modbusRtuMasters.take(modbusUuid)); qCDebug(dcModbusRtu()) << "Removing modbus RTU master" << qobject_cast(modbusMaster); + modbusMaster->disconnectDevice(); + modbusMaster->deleteLater(); + emit modbusRtuMasterRemoved(modbusMaster); - modbusMaster->deleteLater(); - return ErrorNoError; + return ModbusRtuErrorNoError; } -void ModbusRtuManager::updateSerialPorts() -{ - // Check if serial port added or removed - -} - - void ModbusRtuManager::loadRtuMasters() { NymeaSettings settings(NymeaSettings::SettingsRoleModbusRtu); @@ -178,11 +179,7 @@ void ModbusRtuManager::loadRtuMasters() QSerialPort::StopBits stopBits = static_cast(settings.value("stopBits").toInt()); settings.endGroup(); // uuid - ModbusRtuMasterImpl *modbus = new ModbusRtuMasterImpl(QUuid(uuidString), serialPort, baudrate, parity, dataBits, stopBits, this); - ModbusRtuMaster *modbusRtuMaster = qobject_cast(modbus); - qCDebug(dcModbusRtu()) << "Loaded" << modbusRtuMaster; - m_modbusRtuMasters.insert(modbusRtuMaster->modbusUuid(), modbusRtuMaster); - emit modbusRtuMasterAdded(modbusRtuMaster); + addModbusRtuMasterInternally(new ModbusRtuMasterImpl(QUuid(uuidString), serialPort, baudrate, parity, dataBits, stopBits, this)); } settings.endGroup(); // ModbusRtuMasters @@ -191,6 +188,7 @@ void ModbusRtuManager::loadRtuMasters() void ModbusRtuManager::saveModbusRtuMaster(ModbusRtuMaster *modbusRtuMaster) { NymeaSettings settings(NymeaSettings::SettingsRoleModbusRtu); + qCDebug(dcModbusRtu()) << "Saving" << modbusRtuMaster << "to" << settings.fileName(); settings.beginGroup("ModbusRtuMasters"); settings.beginGroup(modbusRtuMaster->modbusUuid().toString()); settings.setValue("serialPort", modbusRtuMaster->serialPort()); @@ -202,4 +200,18 @@ void ModbusRtuManager::saveModbusRtuMaster(ModbusRtuMaster *modbusRtuMaster) settings.endGroup(); // ModbusRtuMasters } +void ModbusRtuManager::addModbusRtuMasterInternally(ModbusRtuMasterImpl *modbusRtuMaster) +{ + ModbusRtuMaster *modbusMaster = qobject_cast(modbusRtuMaster); + qCDebug(dcModbusRtu()) << "Adding" << modbusMaster; + m_modbusRtuMasters.insert(modbusMaster->modbusUuid(), modbusMaster); + + connect(modbusMaster, &ModbusRtuMaster::connectedChanged, this, [=](bool connected){ + qCDebug(dcModbusRtu()) << modbusMaster << (connected ? "connected" : "disconnected"); + emit modbusRtuMasterChanged(modbusMaster); + }); + + emit modbusRtuMasterAdded(modbusMaster); +} + } diff --git a/libnymea-core/modbus/modbusrtumanager.h b/libnymea-core/modbus/modbusrtumanager.h index fc01aa32..f4529ec4 100644 --- a/libnymea-core/modbus/modbusrtumanager.h +++ b/libnymea-core/modbus/modbusrtumanager.h @@ -40,27 +40,33 @@ namespace nymeaserver { +class SerialPortMonitor; +class ModbusRtuMasterImpl; + class ModbusRtuManager : public QObject { Q_OBJECT public: - enum Error { - ErrorNoError, - ErrorNotFound, - ErrorConnectionFailed + enum ModbusRtuError { + ModbusRtuErrorNoError, + ModbusRtuErrorUuidNotFound, + ModbusRtuErrorHardwareNotFound, + ModbusRtuErrorConnectionFailed }; - Q_ENUM(Error) + Q_ENUM(ModbusRtuError) - explicit ModbusRtuManager(QObject *parent = nullptr); + explicit ModbusRtuManager(SerialPortMonitor *serialPortMonitor, QObject *parent = nullptr); ~ModbusRtuManager() = default; + SerialPortMonitor *serialPortMonitor() const; + QList modbusRtuMasters() const; bool hasModbusRtuMaster(const QUuid &modbusUuid) const; ModbusRtuMaster *getModbusRtuMaster(const QUuid &modbusUuid); - QPair addNewModbusRtuMaster(const QString &serialPort, qint32 baudrate, QSerialPort::Parity parity, QSerialPort::DataBits dataBits, QSerialPort::StopBits stopBits); - Error reconfigureRtuMaster(const QUuid &modbusUuid, const QString &serialPort, qint32 baudrate, QSerialPort::Parity parity, QSerialPort::DataBits dataBits, QSerialPort::StopBits stopBits); - Error removeModbusRtuMaster(const QUuid &modbusUuid); + QPair addNewModbusRtuMaster(const QString &serialPort, qint32 baudrate, QSerialPort::Parity parity, QSerialPort::DataBits dataBits, QSerialPort::StopBits stopBits); + ModbusRtuError reconfigureModbusRtuMaster(const QUuid &modbusUuid, const QString &serialPort, qint32 baudrate, QSerialPort::Parity parity, QSerialPort::DataBits dataBits, QSerialPort::StopBits stopBits); + ModbusRtuError removeModbusRtuMaster(const QUuid &modbusUuid); signals: void modbusRtuMasterAdded(ModbusRtuMaster *modbusRtuMaster); @@ -69,10 +75,13 @@ signals: private: QHash m_modbusRtuMasters; + SerialPortMonitor *m_serialPortMonitor = nullptr; void loadRtuMasters(); void saveModbusRtuMaster(ModbusRtuMaster *modbusRtuMaster); + void addModbusRtuMasterInternally(ModbusRtuMasterImpl *modbusRtuMaster); + }; } diff --git a/libnymea-core/nymeacore.cpp b/libnymea-core/nymeacore.cpp index 4f8d9330..ca7cda79 100644 --- a/libnymea-core/nymeacore.cpp +++ b/libnymea-core/nymeacore.cpp @@ -54,6 +54,7 @@ #include "zigbee/zigbeemanager.h" #include "modbus/modbusrtumanager.h" +#include "hardware/serialport/serialportmonitor.h" #include @@ -110,8 +111,11 @@ void NymeaCore::init(const QStringList &additionalInterfaces) { qCDebug(dcCore()) << "Create Zigbee Manager"; m_zigbeeManager = new ZigbeeManager(this); + qCDebug(dcCore()) << "Create Serial Port Monitor"; + m_serialPortMonitor = new SerialPortMonitor(this); + qCDebug(dcCore()) << "Create Modbus RTU Manager"; - m_modbusRtuManager = new ModbusRtuManager(this); + m_modbusRtuManager = new ModbusRtuManager(m_serialPortMonitor, this); qCDebug(dcCore) << "Creating Hardware Manager"; m_hardwareManager = new HardwareManagerImplementation(m_platform, m_serverManager->mqttBroker(), m_zigbeeManager, m_modbusRtuManager, this); diff --git a/libnymea-core/nymeacore.h b/libnymea-core/nymeacore.h index 2514f7d4..b67ac29a 100644 --- a/libnymea-core/nymeacore.h +++ b/libnymea-core/nymeacore.h @@ -68,6 +68,7 @@ class ScriptEngine; class CloudManager; class ZigbeeManager; class ModbusRtuManager; +class SerialPortMonitor; class NymeaCore : public QObject { @@ -153,6 +154,7 @@ private: System *m_system; ExperienceManager *m_experienceManager; ZigbeeManager *m_zigbeeManager; + SerialPortMonitor *m_serialPortMonitor; ModbusRtuManager *m_modbusRtuManager; QList m_executingRules; From 8d944fe0075c831f7abef14dce52dafd6d9dd516 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Wed, 10 Feb 2021 17:10:04 +0100 Subject: [PATCH 09/24] Bump JSONRPC version --- tests/auto/api.json | 130 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 130 insertions(+) diff --git a/tests/auto/api.json b/tests/auto/api.json index b1c0dfc2..72b2e1ff 100644 --- a/tests/auto/api.json +++ b/tests/auto/api.json @@ -150,6 +150,12 @@ "MediaBrowserIconSoundCloud", "MediaBrowserIconRadioParadise" ], + "ModbusRtuError": [ + "ModbusRtuErrorNoError", + "ModbusRtuErrorUuidNotFound", + "ModbusRtuErrorHardwareNotFound", + "ModbusRtuErrorConnectionFailed" + ], "NetworkDeviceState": [ "NetworkDeviceStateUnknown", "NetworkDeviceStateUnmanaged", @@ -232,6 +238,27 @@ "ScriptMessageTypeLog", "ScriptMessageTypeWarning" ], + "SerialPortDataBits": [ + "SerialPortDataBitsData5", + "SerialPortDataBitsData6", + "SerialPortDataBitsData7", + "SerialPortDataBitsData8", + "SerialPortDataBitsUnknownDataBits" + ], + "SerialPortParity": [ + "SerialPortParityNoParity", + "SerialPortParityEvenParity", + "SerialPortParityOddParity", + "SerialPortParitySpaceParity", + "SerialPortParityMarkParity", + "SerialPortParityUnknownParity" + ], + "SerialPortStopBits": [ + "SerialPortStopBitsOneStop", + "SerialPortStopBitsOneAndHalfStop", + "SerialPortStopBitsTwoStop", + "SerialPortStopBitsUnknownStopBits" + ], "SetupMethod": [ "SetupMethodJustAdd", "SetupMethodDisplayPin", @@ -1478,6 +1505,61 @@ "offset": "Int" } }, + "ModbusRtu.AddModbusRtuMaster": { + "description": "Add a new modbus RTU master with the given configuration.", + "params": { + "baudrate": "Uint", + "dataBits": "$ref:SerialPortDataBits", + "parity": "$ref:SerialPortParity", + "serialPort": "String", + "stopBits": "$ref:SerialPortStopBits" + }, + "returns": { + "modbusError": "$ref:ModbusRtuError", + "o:modbusUuid": "Uuid" + } + }, + "ModbusRtu.GetModbusRtuMasters": { + "description": "Get the list of configured modbus RTU masters.", + "params": { + }, + "returns": { + "modbusRtuMasters": [ + "$ref:ModbusRtuMaster" + ] + } + }, + "ModbusRtu.GetSerialPorts": { + "description": "Get the list of available serial ports from the host system.", + "params": { + }, + "returns": { + "serialPorts": "$ref:SerialPorts" + } + }, + "ModbusRtu.ReconfigureModbusRtuMaster": { + "description": "Rconfigure the modbus RTU master with the given UUID and configuration.", + "params": { + "baudrate": "Uint", + "dataBits": "$ref:SerialPortDataBits", + "modbusUuid": "Uuid", + "parity": "$ref:SerialPortParity", + "serialPort": "String", + "stopBits": "$ref:SerialPortStopBits" + }, + "returns": { + "modbusError": "$ref:ModbusRtuError" + } + }, + "ModbusRtu.RemoveModbusRtuMaster": { + "description": "Remove the modbus RTU master with the given modbus UUID.", + "params": { + "modbusUuid": "Uuid" + }, + "returns": { + "modbusError": "$ref:ModbusRtuError" + } + }, "NetworkManager.ConnectWifiNetwork": { "description": "Connect to the wifi network with the given ssid and password.", "params": { @@ -2316,6 +2398,36 @@ "logEntry": "$ref:LogEntry" } }, + "ModbusRtu.ModbusRtuMasterAdded": { + "description": "Emitted whenever a new modbus RTU master has been added to the system.", + "params": { + "modbusRtuMaster": "$ref:ModbusRtuMaster" + } + }, + "ModbusRtu.ModbusRtuMasterChanged": { + "description": "Emitted whenever a new modbus RTU master has been changed to the system.", + "params": { + "modbusRtuMaster": "$ref:ModbusRtuMaster" + } + }, + "ModbusRtu.ModbusRtuMasterRemoved": { + "description": "Emitted whenever a new modbus RTU master has been removed from the system.", + "params": { + "modbusUuid": "Uuid" + } + }, + "ModbusRtu.SerialPortAdded": { + "description": "Emitted whenever a serial port has been added to the system.", + "params": { + "serialPort": "$ref:SerialPort" + } + }, + "ModbusRtu.SerialPortRemoved": { + "description": "Emitted whenever a serial port has been removed from the system.", + "params": { + "serialPort": "$ref:SerialPort" + } + }, "NetworkManager.NetworkStatusChanged": { "description": "Emitted whenever a status of a NetworkManager changes.", "params": { @@ -2709,6 +2821,15 @@ "r:source": "$ref:LoggingSource", "r:timestamp": "Uint" }, + "ModbusRtuMaster": { + "baudrate": "Uint", + "connected": "Bool", + "dataBits": "$ref:SerialPortDataBits", + "modbusUuid": "Uuid", + "parity": "$ref:SerialPortParity", + "serialPort": "String", + "stopBits": "$ref:SerialPortStopBits" + }, "MqttPolicy": { "allowedPublishTopicFilters": "StringList", "allowedSubscribeTopicFilters": "StringList", @@ -2836,6 +2957,15 @@ "Scripts": [ "$ref:Script" ], + "SerialPort": { + "r:description": "String", + "r:manufacturer": "String", + "r:serialNumber": "String", + "r:systemLocation": "String" + }, + "SerialPorts": [ + "$ref:SerialPort" + ], "ServerConfiguration": { "address": "String", "authenticationEnabled": "Bool", From 0dcda9352bafed46b0a6662d608807231edd9311 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Wed, 10 Feb 2021 17:13:09 +0100 Subject: [PATCH 10/24] Add serial port build dependency for debian packaging --- debian/control | 1 + 1 file changed, 1 insertion(+) diff --git a/debian/control b/debian/control index cb26ac41..62258bd4 100644 --- a/debian/control +++ b/debian/control @@ -26,6 +26,7 @@ Build-Depends: debhelper (>= 9.0.0), qttools5-dev-tools, qtconnectivity5-dev, qtdeclarative5-dev, + libqt5serialport5-dev, libqt5serialbus5-dev Package: nymea From 9967b1007dd888834d5059b6b8ae435f00c7de2e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Wed, 10 Feb 2021 17:15:29 +0100 Subject: [PATCH 11/24] Add new namespace to the JSON RPC test --- tests/auto/jsonrpc/testjsonrpc.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/auto/jsonrpc/testjsonrpc.cpp b/tests/auto/jsonrpc/testjsonrpc.cpp index 813b7215..ddafd3c0 100644 --- a/tests/auto/jsonrpc/testjsonrpc.cpp +++ b/tests/auto/jsonrpc/testjsonrpc.cpp @@ -674,7 +674,7 @@ void TestJSONRPC::enableDisableNotifications_legacy() QStringList expectedNamespaces; if (enabled == "true") { - expectedNamespaces << "Actions" << "NetworkManager" << "Devices" << "Integrations" << "System" << "Rules" << "States" << "Logging" << "Tags" << "AppData" << "JSONRPC" << "Configuration" << "Events" << "Scripts" << "Users" << "Zigbee"; + expectedNamespaces << "Actions" << "NetworkManager" << "Devices" << "Integrations" << "System" << "Rules" << "States" << "Logging" << "Tags" << "AppData" << "JSONRPC" << "Configuration" << "Events" << "Scripts" << "Users" << "Zigbee" << "ModbusRtu"; } std::sort(expectedNamespaces.begin(), expectedNamespaces.end()); From 1f247b30be309a4d1f516b2107b3cc10f5320540 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Mon, 15 Feb 2021 17:33:09 +0100 Subject: [PATCH 12/24] Fix building and JSON RPC for modbus management --- libnymea-core/jsonrpc/modbusrtuhandler.cpp | 4 ++-- libnymea-core/modbus/modbusrtumanager.h | 1 + libnymea-core/modbus/modbusrtumasterimpl.cpp | 15 +++++++++++++++ 3 files changed, 18 insertions(+), 2 deletions(-) diff --git a/libnymea-core/jsonrpc/modbusrtuhandler.cpp b/libnymea-core/jsonrpc/modbusrtuhandler.cpp index 1a210485..a218fd73 100644 --- a/libnymea-core/jsonrpc/modbusrtuhandler.cpp +++ b/libnymea-core/jsonrpc/modbusrtuhandler.cpp @@ -121,7 +121,7 @@ ModbusRtuHandler::ModbusRtuHandler(ModbusRtuManager *modbusRtuManager, QObject * // ReconfigureModbusRtuMaster params.clear(); returns.clear(); - description = "Rconfigure the modbus RTU master with the given UUID and configuration."; + description = "Reconfigure the modbus RTU master with the given UUID and configuration."; params.insert("modbusUuid", enumValueName(Uuid)); params.insert("serialPort", enumValueName(String)); params.insert("baudrate", enumValueName(Uint)); @@ -141,7 +141,7 @@ ModbusRtuHandler::ModbusRtuHandler(ModbusRtuManager *modbusRtuManager, QObject * connect(modbusRtuManager->serialPortMonitor(), &SerialPortMonitor::serialPortRemoved, this, [=](const SerialPort &serialPort){ QVariantMap params; params.insert("serialPort", pack(serialPort)); - emit SerialPortAdded(params); + emit SerialPortRemoved(params); }); diff --git a/libnymea-core/modbus/modbusrtumanager.h b/libnymea-core/modbus/modbusrtumanager.h index f4529ec4..c0776ac0 100644 --- a/libnymea-core/modbus/modbusrtumanager.h +++ b/libnymea-core/modbus/modbusrtumanager.h @@ -49,6 +49,7 @@ class ModbusRtuManager : public QObject public: enum ModbusRtuError { ModbusRtuErrorNoError, + ModbusRtuErrorNotAvailable, ModbusRtuErrorUuidNotFound, ModbusRtuErrorHardwareNotFound, ModbusRtuErrorConnectionFailed diff --git a/libnymea-core/modbus/modbusrtumasterimpl.cpp b/libnymea-core/modbus/modbusrtumasterimpl.cpp index de13800b..ac8189b6 100644 --- a/libnymea-core/modbus/modbusrtumasterimpl.cpp +++ b/libnymea-core/modbus/modbusrtumasterimpl.cpp @@ -157,17 +157,26 @@ bool ModbusRtuMasterImpl::connected() const bool ModbusRtuMasterImpl::connectDevice() { +#ifdef WITH_QTSERIALBUS m_modbus->setConnectionParameter(QModbusDevice::SerialPortNameParameter, m_serialPort); m_modbus->setConnectionParameter(QModbusDevice::SerialBaudRateParameter, m_baudrate); m_modbus->setConnectionParameter(QModbusDevice::SerialDataBitsParameter, m_dataBits); m_modbus->setConnectionParameter(QModbusDevice::SerialStopBitsParameter, m_stopBits); m_modbus->setConnectionParameter(QModbusDevice::SerialParityParameter, m_parity); return m_modbus->connectDevice(); +#else + qCWarning(dcModbusRtu()) << "Modbus is not available on this platform."; + return false; +#endif } void ModbusRtuMasterImpl::disconnectDevice() { +#ifdef WITH_QTSERIALBUS m_modbus->disconnectDevice(); +#else + qCWarning(dcModbusRtu()) << "Modbus is not available on this platform."; +#endif } ModbusRtuReply *ModbusRtuMasterImpl::readCoil(int slaveAddress, int registerAddress, quint16 size) @@ -217,6 +226,7 @@ ModbusRtuReply *ModbusRtuMasterImpl::readCoil(int slaveAddress, int registerAddr Q_UNUSED(slaveAddress) Q_UNUSED(registerAddress) Q_UNUSED(size) + qCWarning(dcModbusRtu()) << "Modbus is not available on this platform."; return nullptr; #endif @@ -269,6 +279,7 @@ ModbusRtuReply *ModbusRtuMasterImpl::readDiscreteInput(int slaveAddress, int reg Q_UNUSED(slaveAddress) Q_UNUSED(registerAddress) Q_UNUSED(size) + qCWarning(dcModbusRtu()) << "Modbus is not available on this platform."; return nullptr; #endif @@ -321,6 +332,7 @@ ModbusRtuReply *ModbusRtuMasterImpl::readInputRegister(int slaveAddress, int reg Q_UNUSED(slaveAddress) Q_UNUSED(registerAddress) Q_UNUSED(size) + qCWarning(dcModbusRtu()) << "Modbus is not available on this platform."; return nullptr; #endif @@ -373,6 +385,7 @@ ModbusRtuReply *ModbusRtuMasterImpl::readHoldingRegister(int slaveAddress, int r Q_UNUSED(slaveAddress) Q_UNUSED(registerAddress) Q_UNUSED(size) + qCWarning(dcModbusRtu()) << "Modbus is not available on this platform."; return nullptr; #endif @@ -427,6 +440,7 @@ ModbusRtuReply *ModbusRtuMasterImpl::writeCoils(int slaveAddress, int registerAd Q_UNUSED(slaveAddress) Q_UNUSED(registerAddress) Q_UNUSED(values) + qCWarning(dcModbusRtu()) << "Modbus is not available on this platform."; return nullptr; #endif @@ -482,6 +496,7 @@ ModbusRtuReply *ModbusRtuMasterImpl::writeHoldingRegisters(int slaveAddress, int Q_UNUSED(slaveAddress) Q_UNUSED(registerAddress) Q_UNUSED(values) + qCWarning(dcModbusRtu()) << "Modbus is not available on this platform."; return nullptr; #endif From abcfd32febb80e10c70dcada3d3afb9518ec3768 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Tue, 16 Feb 2021 20:42:16 +0100 Subject: [PATCH 13/24] Add support and fix modbus rtu storage cleanup --- libnymea-core/jsonrpc/modbusrtuhandler.cpp | 21 +++++++---- libnymea-core/modbus/modbusrtumanager.cpp | 39 +++++++++++++++++++- libnymea-core/modbus/modbusrtumanager.h | 4 ++ libnymea-core/modbus/modbusrtumasterimpl.cpp | 6 ++- 4 files changed, 60 insertions(+), 10 deletions(-) diff --git a/libnymea-core/jsonrpc/modbusrtuhandler.cpp b/libnymea-core/jsonrpc/modbusrtuhandler.cpp index a218fd73..5f0f702f 100644 --- a/libnymea-core/jsonrpc/modbusrtuhandler.cpp +++ b/libnymea-core/jsonrpc/modbusrtuhandler.cpp @@ -79,7 +79,8 @@ ModbusRtuHandler::ModbusRtuHandler(ModbusRtuManager *modbusRtuManager, QObject * // GetModbusRtuMasters params.clear(); returns.clear(); description = "Get the list of configured modbus RTU masters."; - returns.insert("modbusRtuMasters", QVariantList() << objectRef("ModbusRtuMaster")); + returns.insert("o:modbusRtuMasters", QVariantList() << objectRef("ModbusRtuMaster")); + returns.insert("modbusError", enumRef()); registerMethod("GetModbusRtuMasters", description, params, returns); // ModbusRtuMasterAdded notification @@ -144,7 +145,6 @@ ModbusRtuHandler::ModbusRtuHandler(ModbusRtuManager *modbusRtuManager, QObject * emit SerialPortRemoved(params); }); - // Modbus manager connect(modbusRtuManager, &ModbusRtuManager::modbusRtuMasterAdded, this, [=](ModbusRtuMaster *modbusRtuMaster){ QVariantMap params; @@ -188,11 +188,19 @@ JsonReply *ModbusRtuHandler::GetModbusRtuMasters(const QVariantMap ¶ms) Q_UNUSED(params) QVariantMap returnMap; - QVariantList modbusList; - foreach (ModbusRtuMaster *modbusMaster, m_modbusRtuManager->modbusRtuMasters()) { - modbusList << packModbusRtuMaster(modbusMaster); + + if (m_modbusRtuManager->supported()) { + QVariantList modbusList; + foreach (ModbusRtuMaster *modbusMaster, m_modbusRtuManager->modbusRtuMasters()) { + modbusList << packModbusRtuMaster(modbusMaster); + } + returnMap.insert("modbusRtuMasters", modbusList); + returnMap.insert("modbusError", enumValueName(ModbusRtuManager::ModbusRtuErrorNoError)); + } else { + returnMap.insert("modbusError", enumValueName(ModbusRtuManager::ModbusRtuErrorNotSupported)); } - returnMap.insert("modbusRtuMasters", modbusList); + + return createReply(returnMap); } @@ -211,7 +219,6 @@ JsonReply *ModbusRtuHandler::AddModbusRtuMaster(const QVariantMap ¶ms) if (result.first == ModbusRtuManager::ModbusRtuErrorNoError) { returnMap.insert("modbusUuid", result.second); } - return createReply(returnMap); } diff --git a/libnymea-core/modbus/modbusrtumanager.cpp b/libnymea-core/modbus/modbusrtumanager.cpp index 55b20a37..20de42c6 100644 --- a/libnymea-core/modbus/modbusrtumanager.cpp +++ b/libnymea-core/modbus/modbusrtumanager.cpp @@ -70,6 +70,15 @@ SerialPortMonitor *ModbusRtuManager::serialPortMonitor() const return m_serialPortMonitor; } +bool ModbusRtuManager::supported() const +{ +#ifdef WITH_QTSERIALBUS + return true; +#else + return false; +#endif +} + QList ModbusRtuManager::modbusRtuMasters() const { return m_modbusRtuMasters.values(); @@ -91,6 +100,11 @@ ModbusRtuMaster *ModbusRtuManager::getModbusRtuMaster(const QUuid &modbusUuid) QPair ModbusRtuManager::addNewModbusRtuMaster(const QString &serialPort, qint32 baudrate, QSerialPort::Parity parity, QSerialPort::DataBits dataBits, QSerialPort::StopBits stopBits) { + if (!supported()) { + qCWarning(dcModbusRtu()) << "Cannot add new modbus RTU master because serialbus is not suppoerted on this platform."; + return QPair(ModbusRtuErrorNotSupported, QUuid()); + } + // Check if the serial port exists if (!m_serialPortMonitor->serialPortAvailable(serialPort)) { qCWarning(dcModbusRtu()) << "Cannot add new modbus RTU master because the serial port" << serialPort << "is not available any more"; @@ -105,6 +119,7 @@ QPair ModbusRtuManager::addNewModbusRt // Note: We could add the modbus master event if a connection is currently not possible...not sure yet if (!modbusMaster->connectDevice()) { qCWarning(dcModbusRtu()) << "Failed to add new modbus RTU master. Could not connect to" << modbus << parity << dataBits << stopBits; + modbusMaster->deleteLater(); return QPair(ModbusRtuErrorConnectionFailed, QUuid()); } @@ -117,6 +132,11 @@ QPair ModbusRtuManager::addNewModbusRt ModbusRtuManager::ModbusRtuError ModbusRtuManager::reconfigureModbusRtuMaster(const QUuid &modbusUuid, const QString &serialPort, qint32 baudrate, QSerialPort::Parity parity, QSerialPort::DataBits dataBits, QSerialPort::StopBits stopBits) { + if (!supported()) { + qCWarning(dcModbusRtu()) << "Cannot reconfigure modbus RTU master because serialbus is not suppoerted on this platform."; + return ModbusRtuErrorNotSupported; + } + if (!m_modbusRtuMasters.contains(modbusUuid)) { qCWarning(dcModbusRtu()) << "Could not reconfigure modbus RTU master because no resource could be found with uuid" << modbusUuid.toString(); return ModbusRtuErrorUuidNotFound; @@ -137,6 +157,7 @@ ModbusRtuManager::ModbusRtuError ModbusRtuManager::reconfigureModbusRtuMaster(co // Connect again if (!modbusMaster->connectDevice()) { qCWarning(dcModbusRtu()) << "Failed to connect to" << m_modbusRtuMasters.value(modbusUuid); + // FIXME: check if we should reload the old configuration emit modbusRtuMasterChanged(m_modbusRtuMasters.value(modbusUuid)); return ModbusRtuErrorConnectionFailed; } @@ -144,11 +165,17 @@ ModbusRtuManager::ModbusRtuError ModbusRtuManager::reconfigureModbusRtuMaster(co emit modbusRtuMasterChanged(m_modbusRtuMasters.value(modbusUuid)); qCDebug(dcModbusRtu()) << "Reconfigured successfully" << m_modbusRtuMasters.value(modbusUuid); + saveModbusRtuMaster(modbusMaster); return ModbusRtuErrorNoError; } ModbusRtuManager::ModbusRtuError ModbusRtuManager::removeModbusRtuMaster(const QUuid &modbusUuid) { + if (!supported()) { + qCWarning(dcModbusRtu()) << "Cannot remove modbus RTU master because serialbus is not suppoerted on this platform."; + return ModbusRtuErrorNotSupported; + } + if (!m_modbusRtuMasters.contains(modbusUuid)) { qCWarning(dcModbusRtu()) << "Could not remove modbus RTU master because no resource could be found with uuid" << modbusUuid.toString(); return ModbusRtuErrorUuidNotFound; @@ -159,6 +186,14 @@ ModbusRtuManager::ModbusRtuError ModbusRtuManager::removeModbusRtuMaster(const Q modbusMaster->disconnectDevice(); modbusMaster->deleteLater(); + // Remove from settings + NymeaSettings settings(NymeaSettings::SettingsRoleModbusRtu); + settings.beginGroup("ModbusRtuMasters"); + settings.beginGroup(modbusUuid.toString()); + settings.remove(""); + settings.endGroup(); // modbusUuid + settings.endGroup(); // ModbusRtuMasters + emit modbusRtuMasterRemoved(modbusMaster); return ModbusRtuErrorNoError; @@ -166,9 +201,11 @@ ModbusRtuManager::ModbusRtuError ModbusRtuManager::removeModbusRtuMaster(const Q void ModbusRtuManager::loadRtuMasters() { + if (!supported()) + return; + NymeaSettings settings(NymeaSettings::SettingsRoleModbusRtu); qCDebug(dcModbusRtu()) << "Loading modbus RTU resources from" << settings.fileName(); - settings.beginGroup("ModbusRtuMasters"); foreach (const QString &uuidString, settings.childGroups()) { settings.beginGroup(uuidString); diff --git a/libnymea-core/modbus/modbusrtumanager.h b/libnymea-core/modbus/modbusrtumanager.h index c0776ac0..67adf82f 100644 --- a/libnymea-core/modbus/modbusrtumanager.h +++ b/libnymea-core/modbus/modbusrtumanager.h @@ -52,6 +52,8 @@ public: ModbusRtuErrorNotAvailable, ModbusRtuErrorUuidNotFound, ModbusRtuErrorHardwareNotFound, + ModbusRtuErrorResourceBusy, + ModbusRtuErrorNotSupported, ModbusRtuErrorConnectionFailed }; Q_ENUM(ModbusRtuError) @@ -61,6 +63,8 @@ public: SerialPortMonitor *serialPortMonitor() const; + bool supported() const; + QList modbusRtuMasters() const; bool hasModbusRtuMaster(const QUuid &modbusUuid) const; ModbusRtuMaster *getModbusRtuMaster(const QUuid &modbusUuid); diff --git a/libnymea-core/modbus/modbusrtumasterimpl.cpp b/libnymea-core/modbus/modbusrtumasterimpl.cpp index ac8189b6..27f2d773 100644 --- a/libnymea-core/modbus/modbusrtumasterimpl.cpp +++ b/libnymea-core/modbus/modbusrtumasterimpl.cpp @@ -69,8 +69,10 @@ ModbusRtuMasterImpl::ModbusRtuMasterImpl(const QUuid &modbusUuid, const QString }); connect(m_modbus, &QModbusRtuSerialMaster::errorOccurred, this, [=](QModbusDevice::Error error){ - qCDebug(dcModbusRtu()) << "Error occured for modbus RTU master" << m_modbusUuid.toString() << m_serialPort << error << m_modbus->errorString(); - // TODO: check if disconnected... + qCWarning(dcModbusRtu()) << "Error occured for modbus RTU master" << m_modbusUuid.toString() << m_serialPort << error << m_modbus->errorString(); + if (error != QModbusDevice::NoError) { + disconnectDevice(); + } }); #endif } From a69b81937355e0cb77bb24028921433fa8aee30e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Wed, 17 Feb 2021 11:21:43 +0100 Subject: [PATCH 14/24] Implement modbus resource siganls and improve connected state notifications --- .../modbusrtuhardwareresourceimplementation.cpp | 12 +++++++++++- libnymea-core/modbus/modbusrtumanager.cpp | 2 +- libnymea-core/modbus/modbusrtumasterimpl.cpp | 12 ++++++++---- libnymea/hardware/modbus/modbusrtumaster.h | 2 +- 4 files changed, 21 insertions(+), 7 deletions(-) diff --git a/libnymea-core/hardware/modbus/modbusrtuhardwareresourceimplementation.cpp b/libnymea-core/hardware/modbus/modbusrtuhardwareresourceimplementation.cpp index 96c9c19e..b2ac270a 100644 --- a/libnymea-core/hardware/modbus/modbusrtuhardwareresourceimplementation.cpp +++ b/libnymea-core/hardware/modbus/modbusrtuhardwareresourceimplementation.cpp @@ -41,7 +41,17 @@ ModbusRtuHardwareResourceImplementation::ModbusRtuHardwareResourceImplementation ModbusRtuHardwareResource(parent), m_modbusRtuManager(modbusRtuManager) { + connect(m_modbusRtuManager, &ModbusRtuManager::modbusRtuMasterAdded, this, [=](ModbusRtuMaster *modbusRtuMaster){ + emit modbusRtuMasterAdded(modbusRtuMaster->modbusUuid()); + }); + connect(m_modbusRtuManager, &ModbusRtuManager::modbusRtuMasterRemoved, this, [=](ModbusRtuMaster *modbusRtuMaster){ + emit modbusRtuMasterRemoved(modbusRtuMaster->modbusUuid()); + }); + + connect(m_modbusRtuManager, &ModbusRtuManager::modbusRtuMasterChanged, this, [=](ModbusRtuMaster *modbusRtuMaster){ + emit modbusRtuMasterChanged(modbusRtuMaster->modbusUuid()); + }); } QList ModbusRtuHardwareResourceImplementation::modbusRtuMasters() const @@ -61,7 +71,7 @@ ModbusRtuMaster *ModbusRtuHardwareResourceImplementation::getModbusRtuMaster(con bool ModbusRtuHardwareResourceImplementation::available() const { - return m_available; + return m_modbusRtuManager->supported(); } bool ModbusRtuHardwareResourceImplementation::enabled() const diff --git a/libnymea-core/modbus/modbusrtumanager.cpp b/libnymea-core/modbus/modbusrtumanager.cpp index 20de42c6..2fa405ea 100644 --- a/libnymea-core/modbus/modbusrtumanager.cpp +++ b/libnymea-core/modbus/modbusrtumanager.cpp @@ -58,7 +58,7 @@ ModbusRtuManager::ModbusRtuManager(SerialPortMonitor *serialPortMonitor, QObject if (!modbusMasterImpl->connectDevice()) { qCDebug(dcModbusRtu()) << "Reconnect" << modbusMaster << "failed."; } else { - qCDebug(dcModbusRtu()) << "Reconnected" << modbusMaster << "sucessfully."; + qCDebug(dcModbusRtu()) << "Reconnected" << modbusMaster << "successfully."; } } } diff --git a/libnymea-core/modbus/modbusrtumasterimpl.cpp b/libnymea-core/modbus/modbusrtumasterimpl.cpp index 27f2d773..0eaec754 100644 --- a/libnymea-core/modbus/modbusrtumasterimpl.cpp +++ b/libnymea-core/modbus/modbusrtumasterimpl.cpp @@ -60,11 +60,15 @@ ModbusRtuMasterImpl::ModbusRtuMasterImpl(const QUuid &modbusUuid, const QString connect(m_modbus, &QModbusTcpClient::stateChanged, this, [=](QModbusDevice::State state){ qCDebug(dcModbusRtu()) << "Connection state changed" << m_modbusUuid.toString() << m_serialPort << state; if (state == QModbusDevice::ConnectedState) { - m_connected = true; - emit connectedChanged(m_connected); + if (m_connected != true) { + m_connected = true; + emit connectedChanged(m_connected); + } } else { - m_connected = false; - emit connectedChanged(m_connected); + if (m_connected != false) { + m_connected = false; + emit connectedChanged(m_connected); + } } }); diff --git a/libnymea/hardware/modbus/modbusrtumaster.h b/libnymea/hardware/modbus/modbusrtumaster.h index 4d6740a5..df4fb94d 100644 --- a/libnymea/hardware/modbus/modbusrtumaster.h +++ b/libnymea/hardware/modbus/modbusrtumaster.h @@ -79,7 +79,7 @@ inline QDebug operator<<(QDebug debug, ModbusRtuMaster *modbusRtuMaster) { debug.nospace() << "ModbusRtuMaster(" << modbusRtuMaster->modbusUuid().toString(); debug.nospace() << ", " << modbusRtuMaster->serialPort(); debug.nospace() << ", BaudRate: " << modbusRtuMaster->baudrate() << ") "; - return debug; + return debug.space(); }; From d3f446e7f92c102973f8ad773a76b73dc58a801b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Wed, 17 Feb 2021 11:40:11 +0100 Subject: [PATCH 15/24] Update json rpc introspect --- tests/auto/api.json | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/tests/auto/api.json b/tests/auto/api.json index 72b2e1ff..73639aad 100644 --- a/tests/auto/api.json +++ b/tests/auto/api.json @@ -152,8 +152,11 @@ ], "ModbusRtuError": [ "ModbusRtuErrorNoError", + "ModbusRtuErrorNotAvailable", "ModbusRtuErrorUuidNotFound", "ModbusRtuErrorHardwareNotFound", + "ModbusRtuErrorResourceBusy", + "ModbusRtuErrorNotSupported", "ModbusRtuErrorConnectionFailed" ], "NetworkDeviceState": [ @@ -1524,7 +1527,8 @@ "params": { }, "returns": { - "modbusRtuMasters": [ + "modbusError": "$ref:ModbusRtuError", + "o:modbusRtuMasters": [ "$ref:ModbusRtuMaster" ] } @@ -1538,7 +1542,7 @@ } }, "ModbusRtu.ReconfigureModbusRtuMaster": { - "description": "Rconfigure the modbus RTU master with the given UUID and configuration.", + "description": "Reconfigure the modbus RTU master with the given UUID and configuration.", "params": { "baudrate": "Uint", "dataBits": "$ref:SerialPortDataBits", From ee81b223501cb59edfa78d73f84e41023f5d5180 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Thu, 18 Feb 2021 17:19:06 +0100 Subject: [PATCH 16/24] Fix mussing logging category include --- libnymea-core/modbus/modbusrtumasterimpl.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/libnymea-core/modbus/modbusrtumasterimpl.cpp b/libnymea-core/modbus/modbusrtumasterimpl.cpp index 0eaec754..3656b267 100644 --- a/libnymea-core/modbus/modbusrtumasterimpl.cpp +++ b/libnymea-core/modbus/modbusrtumasterimpl.cpp @@ -31,6 +31,8 @@ #include "modbusrtumasterimpl.h" #include "modbusrtureplyimpl.h" +#include + #ifdef WITH_QTSERIALBUS #include #include From 16382eb620bc3d513274f40940df01924c0ae088 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Mon, 26 Apr 2021 14:49:53 +0200 Subject: [PATCH 17/24] Fix RTU masters not connecting after system restart --- libnymea-core/modbus/modbusrtumanager.cpp | 5 +++++ libnymea/hardware/modbus/modbusrtumaster.h | 5 ++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/libnymea-core/modbus/modbusrtumanager.cpp b/libnymea-core/modbus/modbusrtumanager.cpp index 2fa405ea..0ac63f46 100644 --- a/libnymea-core/modbus/modbusrtumanager.cpp +++ b/libnymea-core/modbus/modbusrtumanager.cpp @@ -249,6 +249,11 @@ void ModbusRtuManager::addModbusRtuMasterInternally(ModbusRtuMasterImpl *modbusR }); emit modbusRtuMasterAdded(modbusMaster); + + // Try to connect the modbus rtu master after adding the bus + if (!modbusRtuMaster->connectDevice()) { + qCWarning(dcModbusRtu()) << "Failed to connect modbus RTU master. Could not connect to" << modbusMaster; + } } } diff --git a/libnymea/hardware/modbus/modbusrtumaster.h b/libnymea/hardware/modbus/modbusrtumaster.h index df4fb94d..3be61a6b 100644 --- a/libnymea/hardware/modbus/modbusrtumaster.h +++ b/libnymea/hardware/modbus/modbusrtumaster.h @@ -78,7 +78,10 @@ signals: inline QDebug operator<<(QDebug debug, ModbusRtuMaster *modbusRtuMaster) { debug.nospace() << "ModbusRtuMaster(" << modbusRtuMaster->modbusUuid().toString(); debug.nospace() << ", " << modbusRtuMaster->serialPort(); - debug.nospace() << ", BaudRate: " << modbusRtuMaster->baudrate() << ") "; + debug.nospace() << ", BaudRate: " << modbusRtuMaster->baudrate(); + debug.nospace() << ", " << modbusRtuMaster->dataBits(); + debug.nospace() << ", " << modbusRtuMaster->stopBits(); + debug.nospace() << ", " << modbusRtuMaster->parity() << ") "; return debug.space(); }; From 11f62d05558feff3f5d212c938d333dd540e0770 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Mon, 26 Apr 2021 15:57:58 +0200 Subject: [PATCH 18/24] Add timeout and number of retries to the modbus RTU master and propagate the settings to the API --- libnymea-core/jsonrpc/modbusrtuhandler.cpp | 34 +++++++++++++--- libnymea-core/modbus/modbusrtumanager.cpp | 15 +++++-- libnymea-core/modbus/modbusrtumanager.h | 5 ++- libnymea-core/modbus/modbusrtumasterimpl.cpp | 41 +++++++++++++++++++- libnymea-core/modbus/modbusrtumasterimpl.h | 10 ++++- libnymea/hardware/modbus/modbusrtumaster.h | 8 +++- 6 files changed, 97 insertions(+), 16 deletions(-) diff --git a/libnymea-core/jsonrpc/modbusrtuhandler.cpp b/libnymea-core/jsonrpc/modbusrtuhandler.cpp index 5f0f702f..19d43772 100644 --- a/libnymea-core/jsonrpc/modbusrtuhandler.cpp +++ b/libnymea-core/jsonrpc/modbusrtuhandler.cpp @@ -53,6 +53,9 @@ ModbusRtuHandler::ModbusRtuHandler(ModbusRtuManager *modbusRtuManager, QObject * modbusRtuMasterDescription.insert("parity", enumRef()); modbusRtuMasterDescription.insert("stopBits", enumRef()); modbusRtuMasterDescription.insert("dataBits", enumRef()); + modbusRtuMasterDescription.insert("numberOfRetries", enumValueName(Uint)); + modbusRtuMasterDescription.insert("timeout", enumValueName(Uint)); + registerObject("ModbusRtuMaster", modbusRtuMasterDescription); QVariantMap params, returns; @@ -91,24 +94,26 @@ ModbusRtuHandler::ModbusRtuHandler(ModbusRtuManager *modbusRtuManager, QObject * // ModbusRtuMasterRemoved notification params.clear(); - description = "Emitted whenever a new modbus RTU master has been removed from the system."; + description = "Emitted whenever a modbus RTU master has been removed from the system."; params.insert("modbusUuid", enumValueName(Uuid)); registerNotification("ModbusRtuMasterRemoved", description, params); // ModbusRtuMasterChanged notification params.clear(); - description = "Emitted whenever a new modbus RTU master has been changed to the system."; + description = "Emitted whenever a modbus RTU master has been changed in the system."; params.insert("modbusRtuMaster", objectRef("ModbusRtuMaster")); registerNotification("ModbusRtuMasterChanged", description, params); // AddModbusRtuMaster params.clear(); returns.clear(); - description = "Add a new modbus RTU master with the given configuration."; + description = "Add a new modbus RTU master with the given configuration. The timeout value is in milli seconds and the minimum value is 10 ms."; params.insert("serialPort", enumValueName(String)); params.insert("baudrate", enumValueName(Uint)); params.insert("parity", enumRef()); params.insert("dataBits", enumRef()); params.insert("stopBits", enumRef()); + params.insert("numberOfRetries", enumValueName(Uint)); + params.insert("timeout", enumValueName(Uint)); returns.insert("o:modbusUuid", enumValueName(Uuid)); returns.insert("modbusError", enumRef()); registerMethod("AddModbusRtuMaster", description, params, returns); @@ -129,6 +134,8 @@ ModbusRtuHandler::ModbusRtuHandler(ModbusRtuManager *modbusRtuManager, QObject * params.insert("parity", enumRef()); params.insert("dataBits", enumRef()); params.insert("stopBits", enumRef()); + params.insert("numberOfRetries", enumValueName(Uint)); + params.insert("timeout", enumValueName(Uint)); returns.insert("modbusError", enumRef()); registerMethod("ReconfigureModbusRtuMaster", description, params, returns); @@ -211,10 +218,16 @@ JsonReply *ModbusRtuHandler::AddModbusRtuMaster(const QVariantMap ¶ms) QSerialPort::Parity parity = static_cast(enumNameToValue(params.value("parity").toString())); QSerialPort::StopBits stopBits = static_cast(enumNameToValue(params.value("stopBits").toString())); QSerialPort::DataBits dataBits = static_cast(enumNameToValue(params.value("dataBits").toString())); - - QPair result = m_modbusRtuManager->addNewModbusRtuMaster(serialPort, baudrate, parity, dataBits, stopBits); + uint numberOfRetries = params.value("numberOfRetries").toUInt(); + uint timeout = params.value("timeout").toUInt(); QVariantMap returnMap; + if (timeout < 10) { + returnMap.insert("modbusError", enumValueName(ModbusRtuManager::ModbusRtuErrorInvalidTimeoutValue)); + return createReply(returnMap); + } + + QPair result = m_modbusRtuManager->addNewModbusRtuMaster(serialPort, baudrate, parity, dataBits, stopBits, numberOfRetries, timeout); returnMap.insert("modbusError", enumValueName(result.first)); if (result.first == ModbusRtuManager::ModbusRtuErrorNoError) { returnMap.insert("modbusUuid", result.second); @@ -240,9 +253,16 @@ JsonReply *ModbusRtuHandler::ReconfigureModbusRtuMaster(const QVariantMap ¶m QSerialPort::Parity parity = static_cast(enumNameToValue(params.value("parity").toString())); QSerialPort::StopBits stopBits = static_cast(enumNameToValue(params.value("stopBits").toString())); QSerialPort::DataBits dataBits = static_cast(enumNameToValue(params.value("dataBits").toString())); + uint numberOfRetries = params.value("numberOfRetries").toUInt(); + uint timeout = params.value("timeout").toUInt(); - ModbusRtuManager::ModbusRtuError result = m_modbusRtuManager->reconfigureModbusRtuMaster(modbusUuid, serialPort, baudrate, parity, dataBits, stopBits); QVariantMap returnMap; + if (timeout < 10) { + returnMap.insert("modbusError", enumValueName(ModbusRtuManager::ModbusRtuErrorInvalidTimeoutValue)); + return createReply(returnMap); + } + + ModbusRtuManager::ModbusRtuError result = m_modbusRtuManager->reconfigureModbusRtuMaster(modbusUuid, serialPort, baudrate, parity, dataBits, stopBits, numberOfRetries, timeout); returnMap.insert("modbusError", enumValueName(result)); return createReply(returnMap); } @@ -258,6 +278,8 @@ QVariantMap ModbusRtuHandler::packModbusRtuMaster(ModbusRtuMaster *modbusRtuMast modbusRtuMasterMap.insert("parity", enumValueName(static_cast(modbusRtuMaster->parity()))); modbusRtuMasterMap.insert("stopBits", enumValueName(static_cast(modbusRtuMaster->stopBits()))); modbusRtuMasterMap.insert("dataBits", enumValueName(static_cast(modbusRtuMaster->dataBits()))); + modbusRtuMasterMap.insert("numberOfRetries", modbusRtuMaster->numberOfRetries()); + modbusRtuMasterMap.insert("timeout", modbusRtuMaster->timeout()); return modbusRtuMasterMap; } diff --git a/libnymea-core/modbus/modbusrtumanager.cpp b/libnymea-core/modbus/modbusrtumanager.cpp index 0ac63f46..3e0c6f13 100644 --- a/libnymea-core/modbus/modbusrtumanager.cpp +++ b/libnymea-core/modbus/modbusrtumanager.cpp @@ -98,7 +98,7 @@ ModbusRtuMaster *ModbusRtuManager::getModbusRtuMaster(const QUuid &modbusUuid) return nullptr; } -QPair ModbusRtuManager::addNewModbusRtuMaster(const QString &serialPort, qint32 baudrate, QSerialPort::Parity parity, QSerialPort::DataBits dataBits, QSerialPort::StopBits stopBits) +QPair ModbusRtuManager::addNewModbusRtuMaster(const QString &serialPort, qint32 baudrate, QSerialPort::Parity parity, QSerialPort::DataBits dataBits, QSerialPort::StopBits stopBits, int numberOfRetries, int timeout) { if (!supported()) { qCWarning(dcModbusRtu()) << "Cannot add new modbus RTU master because serialbus is not suppoerted on this platform."; @@ -112,7 +112,7 @@ QPair ModbusRtuManager::addNewModbusRt } QUuid modbusUuid = QUuid::createUuid(); - ModbusRtuMasterImpl *modbusMaster = new ModbusRtuMasterImpl(modbusUuid, serialPort, baudrate, parity, dataBits, stopBits, this); + ModbusRtuMasterImpl *modbusMaster = new ModbusRtuMasterImpl(modbusUuid, serialPort, baudrate, parity, dataBits, stopBits, numberOfRetries, timeout, this); ModbusRtuMaster *modbus = qobject_cast(modbusMaster); qCDebug(dcModbusRtu()) << "Adding new" << modbus << parity << dataBits << stopBits; @@ -130,7 +130,7 @@ QPair ModbusRtuManager::addNewModbusRt return QPair(ModbusRtuErrorNoError, modbusUuid); } -ModbusRtuManager::ModbusRtuError ModbusRtuManager::reconfigureModbusRtuMaster(const QUuid &modbusUuid, const QString &serialPort, qint32 baudrate, QSerialPort::Parity parity, QSerialPort::DataBits dataBits, QSerialPort::StopBits stopBits) +ModbusRtuManager::ModbusRtuError ModbusRtuManager::reconfigureModbusRtuMaster(const QUuid &modbusUuid, const QString &serialPort, qint32 baudrate, QSerialPort::Parity parity, QSerialPort::DataBits dataBits, QSerialPort::StopBits stopBits, int numberOfRetries, int timeout) { if (!supported()) { qCWarning(dcModbusRtu()) << "Cannot reconfigure modbus RTU master because serialbus is not suppoerted on this platform."; @@ -142,6 +142,7 @@ ModbusRtuManager::ModbusRtuError ModbusRtuManager::reconfigureModbusRtuMaster(co return ModbusRtuErrorUuidNotFound; } + // Take the modbus masters ModbusRtuMasterImpl *modbusMaster = qobject_cast(m_modbusRtuMasters.value(modbusUuid)); // Disconnect @@ -153,6 +154,8 @@ ModbusRtuManager::ModbusRtuError ModbusRtuManager::reconfigureModbusRtuMaster(co modbusMaster->setParity(parity); modbusMaster->setDataBits(dataBits); modbusMaster->setStopBits(stopBits); + modbusMaster->setNumberOfRetries(numberOfRetries); + modbusMaster->setTimeout(timeout); // Connect again if (!modbusMaster->connectDevice()) { @@ -214,9 +217,11 @@ void ModbusRtuManager::loadRtuMasters() QSerialPort::Parity parity = static_cast(settings.value("parity").toInt()); QSerialPort::DataBits dataBits = static_cast(settings.value("dataBits").toInt()); QSerialPort::StopBits stopBits = static_cast(settings.value("stopBits").toInt()); + int numberOfRetries = settings.value("numberOfRetries").toInt(); + int timeout = settings.value("timeout").toInt(); settings.endGroup(); // uuid - addModbusRtuMasterInternally(new ModbusRtuMasterImpl(QUuid(uuidString), serialPort, baudrate, parity, dataBits, stopBits, this)); + addModbusRtuMasterInternally(new ModbusRtuMasterImpl(QUuid(uuidString), serialPort, baudrate, parity, dataBits, stopBits, numberOfRetries, timeout, this)); } settings.endGroup(); // ModbusRtuMasters @@ -233,6 +238,8 @@ void ModbusRtuManager::saveModbusRtuMaster(ModbusRtuMaster *modbusRtuMaster) settings.setValue("parity", static_cast(modbusRtuMaster->parity())); settings.setValue("dataBits", static_cast(modbusRtuMaster->dataBits())); settings.setValue("stopBits", static_cast(modbusRtuMaster->stopBits())); + settings.setValue("numberOfRetries", modbusRtuMaster->numberOfRetries()); + settings.setValue("timeout", modbusRtuMaster->timeout()); settings.endGroup(); // uuid settings.endGroup(); // ModbusRtuMasters } diff --git a/libnymea-core/modbus/modbusrtumanager.h b/libnymea-core/modbus/modbusrtumanager.h index 67adf82f..837188c6 100644 --- a/libnymea-core/modbus/modbusrtumanager.h +++ b/libnymea-core/modbus/modbusrtumanager.h @@ -54,6 +54,7 @@ public: ModbusRtuErrorHardwareNotFound, ModbusRtuErrorResourceBusy, ModbusRtuErrorNotSupported, + ModbusRtuErrorInvalidTimeoutValue, ModbusRtuErrorConnectionFailed }; Q_ENUM(ModbusRtuError) @@ -69,8 +70,8 @@ public: bool hasModbusRtuMaster(const QUuid &modbusUuid) const; ModbusRtuMaster *getModbusRtuMaster(const QUuid &modbusUuid); - QPair addNewModbusRtuMaster(const QString &serialPort, qint32 baudrate, QSerialPort::Parity parity, QSerialPort::DataBits dataBits, QSerialPort::StopBits stopBits); - ModbusRtuError reconfigureModbusRtuMaster(const QUuid &modbusUuid, const QString &serialPort, qint32 baudrate, QSerialPort::Parity parity, QSerialPort::DataBits dataBits, QSerialPort::StopBits stopBits); + QPair addNewModbusRtuMaster(const QString &serialPort, qint32 baudrate, QSerialPort::Parity parity, QSerialPort::DataBits dataBits, QSerialPort::StopBits stopBits, int numberOfRetries, int timeout); + ModbusRtuError reconfigureModbusRtuMaster(const QUuid &modbusUuid, const QString &serialPort, qint32 baudrate, QSerialPort::Parity parity, QSerialPort::DataBits dataBits, QSerialPort::StopBits stopBits, int numberOfRetries, int timeout); ModbusRtuError removeModbusRtuMaster(const QUuid &modbusUuid); signals: diff --git a/libnymea-core/modbus/modbusrtumasterimpl.cpp b/libnymea-core/modbus/modbusrtumasterimpl.cpp index 3656b267..3d18eb4e 100644 --- a/libnymea-core/modbus/modbusrtumasterimpl.cpp +++ b/libnymea-core/modbus/modbusrtumasterimpl.cpp @@ -42,14 +42,16 @@ Q_DECLARE_LOGGING_CATEGORY(dcModbusRtu) namespace nymeaserver { -ModbusRtuMasterImpl::ModbusRtuMasterImpl(const QUuid &modbusUuid, const QString &serialPort, qint32 baudrate, QSerialPort::Parity parity, QSerialPort::DataBits dataBits, QSerialPort::StopBits stopBits, QObject *parent) : +ModbusRtuMasterImpl::ModbusRtuMasterImpl(const QUuid &modbusUuid, const QString &serialPort, qint32 baudrate, QSerialPort::Parity parity, QSerialPort::DataBits dataBits, QSerialPort::StopBits stopBits, int numberOfRetries, int timeout, QObject *parent) : ModbusRtuMaster(parent), m_modbusUuid(modbusUuid), m_serialPort(serialPort), m_baudrate(baudrate), m_parity(parity), m_dataBits(dataBits), - m_stopBits(stopBits) + m_stopBits(stopBits), + m_numberOfRetries(numberOfRetries), + m_timeout(timeout) { #ifdef WITH_QTSERIALBUS m_modbus = new QModbusRtuSerialMaster(this); @@ -58,6 +60,8 @@ ModbusRtuMasterImpl::ModbusRtuMasterImpl(const QUuid &modbusUuid, const QString m_modbus->setConnectionParameter(QModbusDevice::SerialDataBitsParameter, m_dataBits); m_modbus->setConnectionParameter(QModbusDevice::SerialStopBitsParameter, m_stopBits); m_modbus->setConnectionParameter(QModbusDevice::SerialParityParameter, m_parity); + m_modbus->setNumberOfRetries(m_numberOfRetries); + m_modbus->setTimeout(m_timeout); connect(m_modbus, &QModbusTcpClient::stateChanged, this, [=](QModbusDevice::State state){ qCDebug(dcModbusRtu()) << "Connection state changed" << m_modbusUuid.toString() << m_serialPort << state; @@ -171,6 +175,8 @@ bool ModbusRtuMasterImpl::connectDevice() m_modbus->setConnectionParameter(QModbusDevice::SerialDataBitsParameter, m_dataBits); m_modbus->setConnectionParameter(QModbusDevice::SerialStopBitsParameter, m_stopBits); m_modbus->setConnectionParameter(QModbusDevice::SerialParityParameter, m_parity); + m_modbus->setNumberOfRetries(m_numberOfRetries); + m_modbus->setTimeout(m_timeout); return m_modbus->connectDevice(); #else qCWarning(dcModbusRtu()) << "Modbus is not available on this platform."; @@ -187,6 +193,37 @@ void ModbusRtuMasterImpl::disconnectDevice() #endif } +int ModbusRtuMasterImpl::numberOfRetries() const +{ + return m_numberOfRetries; +} + +void ModbusRtuMasterImpl::setNumberOfRetries(int numberOfRetries) +{ + if (m_numberOfRetries == numberOfRetries) + return; + + m_numberOfRetries = numberOfRetries; + emit numberOfRetriesChanged(m_numberOfRetries); + + m_modbus->setNumberOfRetries(m_numberOfRetries); +} + +int ModbusRtuMasterImpl::timeout() const +{ + return m_timeout; +} + +void ModbusRtuMasterImpl::setTimeout(int timeout) +{ + if (m_timeout == timeout) + return; + + m_timeout = timeout; + emit timeoutChanged(m_timeout); + m_modbus->setTimeout(m_timeout); +} + ModbusRtuReply *ModbusRtuMasterImpl::readCoil(int slaveAddress, int registerAddress, quint16 size) { #ifdef WITH_QTSERIALBUS diff --git a/libnymea-core/modbus/modbusrtumasterimpl.h b/libnymea-core/modbus/modbusrtumasterimpl.h index d9eadd8c..6df0749f 100644 --- a/libnymea-core/modbus/modbusrtumasterimpl.h +++ b/libnymea-core/modbus/modbusrtumasterimpl.h @@ -46,7 +46,7 @@ class ModbusRtuMasterImpl : public ModbusRtuMaster { Q_OBJECT public: - explicit ModbusRtuMasterImpl(const QUuid &modbusUuid, const QString &serialPort, qint32 baudrate, QSerialPort::Parity parity, QSerialPort::DataBits dataBits, QSerialPort::StopBits stopBits, QObject *parent = nullptr); + explicit ModbusRtuMasterImpl(const QUuid &modbusUuid, const QString &serialPort, qint32 baudrate, QSerialPort::Parity parity, QSerialPort::DataBits dataBits, QSerialPort::StopBits stopBits, int numberOfRetries, int timeout, QObject *parent = nullptr); ~ModbusRtuMasterImpl() override = default; QUuid modbusUuid() const override; @@ -71,6 +71,12 @@ public: bool connectDevice(); void disconnectDevice(); + int numberOfRetries() const override; + void setNumberOfRetries(int numberOfRetries); + + int timeout() const override; + void setTimeout(int timeout); + // Requests ModbusRtuReply *readCoil(int slaveAddress, int registerAddress, quint16 size = 1) override; ModbusRtuReply *readDiscreteInput(int slaveAddress, int registerAddress, quint16 size = 1) override; @@ -93,6 +99,8 @@ private: QSerialPort::Parity m_parity; QSerialPort::DataBits m_dataBits; QSerialPort::StopBits m_stopBits; + int m_numberOfRetries = 3; + int m_timeout = 100; }; } diff --git a/libnymea/hardware/modbus/modbusrtumaster.h b/libnymea/hardware/modbus/modbusrtumaster.h index 3be61a6b..4be61031 100644 --- a/libnymea/hardware/modbus/modbusrtumaster.h +++ b/libnymea/hardware/modbus/modbusrtumaster.h @@ -49,6 +49,8 @@ public: virtual QSerialPort::Parity parity() const = 0; virtual QSerialPort::DataBits dataBits() const = 0; virtual QSerialPort::StopBits stopBits() = 0; + virtual int numberOfRetries() const = 0; + virtual int timeout() const = 0; virtual bool connected() const = 0; @@ -72,6 +74,8 @@ signals: void parityChanged(QSerialPort::Parity parity); void dataBitsChanged(QSerialPort::DataBits dataBits); void stopBitsChanged(QSerialPort::StopBits stopBits); + void numberOfRetriesChanged(int numberOfRetries); + void timeoutChanged(int timeout); }; @@ -81,7 +85,9 @@ inline QDebug operator<<(QDebug debug, ModbusRtuMaster *modbusRtuMaster) { debug.nospace() << ", BaudRate: " << modbusRtuMaster->baudrate(); debug.nospace() << ", " << modbusRtuMaster->dataBits(); debug.nospace() << ", " << modbusRtuMaster->stopBits(); - debug.nospace() << ", " << modbusRtuMaster->parity() << ") "; + debug.nospace() << ", " << modbusRtuMaster->parity(); + debug.nospace() << ", Retries:" << modbusRtuMaster->numberOfRetries(); + debug.nospace() << ", Timeout:" << modbusRtuMaster->numberOfRetries() << "ms)"; return debug.space(); }; From 0cff50dc2c5abb64a6f3b5ff989c9f03388e0ec3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Mon, 26 Apr 2021 16:06:35 +0200 Subject: [PATCH 19/24] Update api.json to newest modbus changes --- tests/auto/api.json | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/tests/auto/api.json b/tests/auto/api.json index 73639aad..47cd6cfb 100644 --- a/tests/auto/api.json +++ b/tests/auto/api.json @@ -157,6 +157,7 @@ "ModbusRtuErrorHardwareNotFound", "ModbusRtuErrorResourceBusy", "ModbusRtuErrorNotSupported", + "ModbusRtuErrorInvalidTimeoutValue", "ModbusRtuErrorConnectionFailed" ], "NetworkDeviceState": [ @@ -1509,13 +1510,15 @@ } }, "ModbusRtu.AddModbusRtuMaster": { - "description": "Add a new modbus RTU master with the given configuration.", + "description": "Add a new modbus RTU master with the given configuration. The timeout value is in milli seconds and the minimum value is 10 ms.", "params": { "baudrate": "Uint", "dataBits": "$ref:SerialPortDataBits", + "numberOfRetries": "Uint", "parity": "$ref:SerialPortParity", "serialPort": "String", - "stopBits": "$ref:SerialPortStopBits" + "stopBits": "$ref:SerialPortStopBits", + "timeout": "Uint" }, "returns": { "modbusError": "$ref:ModbusRtuError", @@ -1547,9 +1550,11 @@ "baudrate": "Uint", "dataBits": "$ref:SerialPortDataBits", "modbusUuid": "Uuid", + "numberOfRetries": "Uint", "parity": "$ref:SerialPortParity", "serialPort": "String", - "stopBits": "$ref:SerialPortStopBits" + "stopBits": "$ref:SerialPortStopBits", + "timeout": "Uint" }, "returns": { "modbusError": "$ref:ModbusRtuError" @@ -2409,13 +2414,13 @@ } }, "ModbusRtu.ModbusRtuMasterChanged": { - "description": "Emitted whenever a new modbus RTU master has been changed to the system.", + "description": "Emitted whenever a modbus RTU master has been changed in the system.", "params": { "modbusRtuMaster": "$ref:ModbusRtuMaster" } }, "ModbusRtu.ModbusRtuMasterRemoved": { - "description": "Emitted whenever a new modbus RTU master has been removed from the system.", + "description": "Emitted whenever a modbus RTU master has been removed from the system.", "params": { "modbusUuid": "Uuid" } @@ -2830,9 +2835,11 @@ "connected": "Bool", "dataBits": "$ref:SerialPortDataBits", "modbusUuid": "Uuid", + "numberOfRetries": "Uint", "parity": "$ref:SerialPortParity", "serialPort": "String", - "stopBits": "$ref:SerialPortStopBits" + "stopBits": "$ref:SerialPortStopBits", + "timeout": "Uint" }, "MqttPolicy": { "allowedPublishTopicFilters": "StringList", From 055ace3cc1f336dbe5429cd3387992ebdb7f1a8b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Mon, 26 Apr 2021 16:17:18 +0200 Subject: [PATCH 20/24] Fix building without modbus support --- libnymea-core/modbus/modbusrtumasterimpl.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/libnymea-core/modbus/modbusrtumasterimpl.cpp b/libnymea-core/modbus/modbusrtumasterimpl.cpp index 3d18eb4e..eab5c4c7 100644 --- a/libnymea-core/modbus/modbusrtumasterimpl.cpp +++ b/libnymea-core/modbus/modbusrtumasterimpl.cpp @@ -205,8 +205,9 @@ void ModbusRtuMasterImpl::setNumberOfRetries(int numberOfRetries) m_numberOfRetries = numberOfRetries; emit numberOfRetriesChanged(m_numberOfRetries); - +#ifdef WITH_QTSERIALBUS m_modbus->setNumberOfRetries(m_numberOfRetries); +#endif } int ModbusRtuMasterImpl::timeout() const @@ -221,7 +222,9 @@ void ModbusRtuMasterImpl::setTimeout(int timeout) m_timeout = timeout; emit timeoutChanged(m_timeout); +#ifdef WITH_QTSERIALBUS m_modbus->setTimeout(m_timeout); +#endif } ModbusRtuReply *ModbusRtuMasterImpl::readCoil(int slaveAddress, int registerAddress, quint16 size) From becd6c33743e97ac91e28ccc98ff5aeec66a5faa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Tue, 27 Apr 2021 09:51:09 +0200 Subject: [PATCH 21/24] Fix debug print for modbus RTU master and try to connect masters after loading them --- libnymea-core/modbus/modbusrtumanager.cpp | 14 +++++++++----- libnymea/hardware/modbus/modbusrtumaster.h | 4 ++-- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/libnymea-core/modbus/modbusrtumanager.cpp b/libnymea-core/modbus/modbusrtumanager.cpp index 3e0c6f13..d2cdafa4 100644 --- a/libnymea-core/modbus/modbusrtumanager.cpp +++ b/libnymea-core/modbus/modbusrtumanager.cpp @@ -63,6 +63,15 @@ ModbusRtuManager::ModbusRtuManager(SerialPortMonitor *serialPortMonitor, QObject } } }); + + // Try to connect the modbus rtu masters + foreach (ModbusRtuMaster *modbusMaster, m_modbusRtuMasters.values()) { + ModbusRtuMasterImpl *modbusMasterImpl = qobject_cast(modbusMaster); + if (!modbusMasterImpl->connectDevice()) { + qCWarning(dcModbusRtu()) << "Failed to connect modbus RTU master. Could not connect to" << modbusMaster; + } + } + } SerialPortMonitor *ModbusRtuManager::serialPortMonitor() const @@ -256,11 +265,6 @@ void ModbusRtuManager::addModbusRtuMasterInternally(ModbusRtuMasterImpl *modbusR }); emit modbusRtuMasterAdded(modbusMaster); - - // Try to connect the modbus rtu master after adding the bus - if (!modbusRtuMaster->connectDevice()) { - qCWarning(dcModbusRtu()) << "Failed to connect modbus RTU master. Could not connect to" << modbusMaster; - } } } diff --git a/libnymea/hardware/modbus/modbusrtumaster.h b/libnymea/hardware/modbus/modbusrtumaster.h index 4be61031..39ba94be 100644 --- a/libnymea/hardware/modbus/modbusrtumaster.h +++ b/libnymea/hardware/modbus/modbusrtumaster.h @@ -86,8 +86,8 @@ inline QDebug operator<<(QDebug debug, ModbusRtuMaster *modbusRtuMaster) { debug.nospace() << ", " << modbusRtuMaster->dataBits(); debug.nospace() << ", " << modbusRtuMaster->stopBits(); debug.nospace() << ", " << modbusRtuMaster->parity(); - debug.nospace() << ", Retries:" << modbusRtuMaster->numberOfRetries(); - debug.nospace() << ", Timeout:" << modbusRtuMaster->numberOfRetries() << "ms)"; + debug.nospace() << ", Retries: " << modbusRtuMaster->numberOfRetries(); + debug.nospace() << ", Timeout: " << modbusRtuMaster->timeout() << "ms)"; return debug.space(); }; From 675782997c557826ddc1879ec2bf4716244c1aa0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Wed, 19 May 2021 08:36:05 +0200 Subject: [PATCH 22/24] Move modbus RTU classes into hardware source code section --- .../modbusrtuhardwareresourceimplementation.cpp | 2 +- .../modbus/modbusrtuhardwareresourceimplementation.h | 2 +- .../{ => hardware}/modbus/modbusrtumanager.cpp | 0 .../{ => hardware}/modbus/modbusrtumanager.h | 0 .../{ => hardware}/modbus/modbusrtumasterimpl.cpp | 0 .../{ => hardware}/modbus/modbusrtumasterimpl.h | 0 .../{ => hardware}/modbus/modbusrtureplyimpl.cpp | 1 - .../{ => hardware}/modbus/modbusrtureplyimpl.h | 0 libnymea-core/hardwaremanagerimplementation.cpp | 2 +- libnymea-core/jsonrpc/modbusrtuhandler.cpp | 2 +- libnymea-core/libnymea-core.pro | 12 ++++++------ libnymea-core/nymeacore.cpp | 2 +- 12 files changed, 11 insertions(+), 12 deletions(-) rename libnymea-core/{ => hardware}/modbus/modbusrtumanager.cpp (100%) rename libnymea-core/{ => hardware}/modbus/modbusrtumanager.h (100%) rename libnymea-core/{ => hardware}/modbus/modbusrtumasterimpl.cpp (100%) rename libnymea-core/{ => hardware}/modbus/modbusrtumasterimpl.h (100%) rename libnymea-core/{ => hardware}/modbus/modbusrtureplyimpl.cpp (99%) rename libnymea-core/{ => hardware}/modbus/modbusrtureplyimpl.h (100%) diff --git a/libnymea-core/hardware/modbus/modbusrtuhardwareresourceimplementation.cpp b/libnymea-core/hardware/modbus/modbusrtuhardwareresourceimplementation.cpp index b2ac270a..501691bb 100644 --- a/libnymea-core/hardware/modbus/modbusrtuhardwareresourceimplementation.cpp +++ b/libnymea-core/hardware/modbus/modbusrtuhardwareresourceimplementation.cpp @@ -31,7 +31,7 @@ #include "modbusrtuhardwareresourceimplementation.h" #include "loggingcategories.h" #include "nymeasettings.h" -#include "modbus/modbusrtumanager.h" +#include "hardware/modbus/modbusrtumanager.h" NYMEA_LOGGING_CATEGORY(dcModbusRtuResource, "ModbusRtuResource") diff --git a/libnymea-core/hardware/modbus/modbusrtuhardwareresourceimplementation.h b/libnymea-core/hardware/modbus/modbusrtuhardwareresourceimplementation.h index a26be359..73e480dc 100644 --- a/libnymea-core/hardware/modbus/modbusrtuhardwareresourceimplementation.h +++ b/libnymea-core/hardware/modbus/modbusrtuhardwareresourceimplementation.h @@ -33,7 +33,7 @@ #include -#include "modbus/modbusrtumanager.h" +#include "hardware/modbus/modbusrtumanager.h" #include "hardware/modbus/modbusrtumaster.h" #include "hardware/modbus/modbusrtuhardwareresource.h" diff --git a/libnymea-core/modbus/modbusrtumanager.cpp b/libnymea-core/hardware/modbus/modbusrtumanager.cpp similarity index 100% rename from libnymea-core/modbus/modbusrtumanager.cpp rename to libnymea-core/hardware/modbus/modbusrtumanager.cpp diff --git a/libnymea-core/modbus/modbusrtumanager.h b/libnymea-core/hardware/modbus/modbusrtumanager.h similarity index 100% rename from libnymea-core/modbus/modbusrtumanager.h rename to libnymea-core/hardware/modbus/modbusrtumanager.h diff --git a/libnymea-core/modbus/modbusrtumasterimpl.cpp b/libnymea-core/hardware/modbus/modbusrtumasterimpl.cpp similarity index 100% rename from libnymea-core/modbus/modbusrtumasterimpl.cpp rename to libnymea-core/hardware/modbus/modbusrtumasterimpl.cpp diff --git a/libnymea-core/modbus/modbusrtumasterimpl.h b/libnymea-core/hardware/modbus/modbusrtumasterimpl.h similarity index 100% rename from libnymea-core/modbus/modbusrtumasterimpl.h rename to libnymea-core/hardware/modbus/modbusrtumasterimpl.h diff --git a/libnymea-core/modbus/modbusrtureplyimpl.cpp b/libnymea-core/hardware/modbus/modbusrtureplyimpl.cpp similarity index 99% rename from libnymea-core/modbus/modbusrtureplyimpl.cpp rename to libnymea-core/hardware/modbus/modbusrtureplyimpl.cpp index 0c66d2ac..dc00ac94 100644 --- a/libnymea-core/modbus/modbusrtureplyimpl.cpp +++ b/libnymea-core/hardware/modbus/modbusrtureplyimpl.cpp @@ -30,7 +30,6 @@ #include "modbusrtureplyimpl.h" - namespace nymeaserver { ModbusRtuReplyImpl::ModbusRtuReplyImpl(int slaveAddress, int registerAddress, QObject *parent) : diff --git a/libnymea-core/modbus/modbusrtureplyimpl.h b/libnymea-core/hardware/modbus/modbusrtureplyimpl.h similarity index 100% rename from libnymea-core/modbus/modbusrtureplyimpl.h rename to libnymea-core/hardware/modbus/modbusrtureplyimpl.h diff --git a/libnymea-core/hardwaremanagerimplementation.cpp b/libnymea-core/hardwaremanagerimplementation.cpp index aece0d95..e873b839 100644 --- a/libnymea-core/hardwaremanagerimplementation.cpp +++ b/libnymea-core/hardwaremanagerimplementation.cpp @@ -44,7 +44,7 @@ #include "hardware/i2c/i2cmanagerimplementation.h" #include "hardware/zigbee/zigbeehardwareresourceimplementation.h" -#include "modbus/modbusrtumanager.h" +#include "hardware/modbus/modbusrtumanager.h" #include "hardware/modbus/modbusrtuhardwareresourceimplementation.h" namespace nymeaserver { diff --git a/libnymea-core/jsonrpc/modbusrtuhandler.cpp b/libnymea-core/jsonrpc/modbusrtuhandler.cpp index 19d43772..89b169c4 100644 --- a/libnymea-core/jsonrpc/modbusrtuhandler.cpp +++ b/libnymea-core/jsonrpc/modbusrtuhandler.cpp @@ -29,7 +29,7 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "modbusrtuhandler.h" -#include "modbus/modbusrtumanager.h" +#include "hardware/modbus/modbusrtumanager.h" #include "hardware/serialport/serialportmonitor.h" namespace nymeaserver { diff --git a/libnymea-core/libnymea-core.pro b/libnymea-core/libnymea-core.pro index eb17feef..2ae5d350 100644 --- a/libnymea-core/libnymea-core.pro +++ b/libnymea-core/libnymea-core.pro @@ -79,9 +79,6 @@ HEADERS += nymeacore.h \ experiences/experiencemanager.h \ jsonrpc/modbusrtuhandler.h \ jsonrpc/zigbeehandler.h \ - modbus/modbusrtumanager.h \ - modbus/modbusrtumasterimpl.h \ - modbus/modbusrtureplyimpl.h \ ruleengine/ruleengine.h \ ruleengine/rule.h \ ruleengine/stateevaluator.h \ @@ -145,6 +142,9 @@ HEADERS += nymeacore.h \ hardware/bluetoothlowenergy/bluetoothlowenergydeviceimplementation.h \ hardware/bluetoothlowenergy/bluetoothdiscoveryreplyimplementation.h \ hardware/modbus/modbusrtuhardwareresourceimplementation.h \ + hardware/modbus/modbusrtumanager.h \ + hardware/modbus/modbusrtumasterimpl.h \ + hardware/modbus/modbusrtureplyimpl.h \ hardware/network/networkaccessmanagerimpl.h \ hardware/network/upnp/upnpdiscoveryimplementation.h \ hardware/network/upnp/upnpdiscoveryrequest.h \ @@ -173,9 +173,6 @@ SOURCES += nymeacore.cpp \ experiences/experiencemanager.cpp \ jsonrpc/modbusrtuhandler.cpp \ jsonrpc/zigbeehandler.cpp \ - modbus/modbusrtumanager.cpp \ - modbus/modbusrtumasterimpl.cpp \ - modbus/modbusrtureplyimpl.cpp \ ruleengine/ruleengine.cpp \ ruleengine/rule.cpp \ ruleengine/stateevaluator.cpp \ @@ -238,6 +235,9 @@ SOURCES += nymeacore.cpp \ hardware/bluetoothlowenergy/bluetoothlowenergydeviceimplementation.cpp \ hardware/bluetoothlowenergy/bluetoothdiscoveryreplyimplementation.cpp \ hardware/modbus/modbusrtuhardwareresourceimplementation.cpp \ + hardware/modbus/modbusrtumanager.cpp \ + hardware/modbus/modbusrtumasterimpl.cpp \ + hardware/modbus/modbusrtureplyimpl.cpp \ hardware/network/networkaccessmanagerimpl.cpp \ hardware/network/upnp/upnpdiscoveryimplementation.cpp \ hardware/network/upnp/upnpdiscoveryrequest.cpp \ diff --git a/libnymea-core/nymeacore.cpp b/libnymea-core/nymeacore.cpp index ca7cda79..7e6f7d3d 100644 --- a/libnymea-core/nymeacore.cpp +++ b/libnymea-core/nymeacore.cpp @@ -53,7 +53,7 @@ #include "zigbee/zigbeemanager.h" -#include "modbus/modbusrtumanager.h" +#include "hardware/modbus/modbusrtumanager.h" #include "hardware/serialport/serialportmonitor.h" #include From 2731adc5c573190ea4ea885e48a9e8425c265988 Mon Sep 17 00:00:00 2001 From: Michael Zanetti Date: Mon, 7 Jun 2021 22:16:38 +0200 Subject: [PATCH 23/24] Bump jsonrpc api version --- nymea.pro | 2 +- tests/auto/api.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/nymea.pro b/nymea.pro index f51820af..d5d719b7 100644 --- a/nymea.pro +++ b/nymea.pro @@ -5,7 +5,7 @@ NYMEA_VERSION_STRING=$$system('dpkg-parsechangelog | sed -n -e "s/^Version: //p" # define protocol versions JSON_PROTOCOL_VERSION_MAJOR=5 -JSON_PROTOCOL_VERSION_MINOR=5 +JSON_PROTOCOL_VERSION_MINOR=6 JSON_PROTOCOL_VERSION="$${JSON_PROTOCOL_VERSION_MAJOR}.$${JSON_PROTOCOL_VERSION_MINOR}" LIBNYMEA_API_VERSION_MAJOR=7 LIBNYMEA_API_VERSION_MINOR=0 diff --git a/tests/auto/api.json b/tests/auto/api.json index 47cd6cfb..f449b0c4 100644 --- a/tests/auto/api.json +++ b/tests/auto/api.json @@ -1,4 +1,4 @@ -5.5 +5.6 { "enums": { "BasicType": [ From 355dcd50d42a93a450c734855485265332df93c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Mon, 28 Jun 2021 08:54:49 +0200 Subject: [PATCH 24/24] Update qmake udev build information message --- libnymea-core/libnymea-core.pro | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/libnymea-core/libnymea-core.pro b/libnymea-core/libnymea-core.pro index 2ae5d350..7985a191 100644 --- a/libnymea-core/libnymea-core.pro +++ b/libnymea-core/libnymea-core.pro @@ -49,11 +49,11 @@ packagesExist(Qt5SerialBus) { # Note: udev is not available on all platforms packagesExist(libudev) { - message("Build with udev support") + message("Building with udev support") PKGCONFIG += libudev DEFINES += WITH_UDEV } else { - message("Build without udev support.") + message("Building without udev support.") } target.path = $$[QT_INSTALL_LIBS]