From 78c30f54da25c9b71c737a34552dfd5768f924aa Mon Sep 17 00:00:00 2001 From: Boernsman Date: Tue, 16 Jun 2020 16:55:45 +0200 Subject: [PATCH] Wallbe changed to QModbus --- drexelundweiss/drexelundweiss.pro | 8 +- .../integrationplugindrexelundweiss.h | 3 +- fronius/fronius.pro | 6 +- .../integrationpluginmodbuscommander.cpp | 11 +- .../integrationpluginmodbuscommander.h | 5 +- modbuscommander/modbuscommander.pro | 11 +- modbuscommander/modbusrtumaster.cpp | 371 ----------------- modbuscommander/modbusrtumaster.h | 81 ---- modbuscommander/modbustcpmaster.cpp | 375 ------------------ modbuscommander/modbustcpmaster.h | 85 ---- mypv/integrationpluginmypv.cpp | 12 +- mypv/integrationpluginmypv.h | 13 +- mypv/modbustcpmaster.cpp | 184 --------- mypv/modbustcpmaster.h | 66 --- mypv/mypv.pro | 5 +- wallbe/integrationpluginwallbe.cpp | 181 ++++++--- wallbe/integrationpluginwallbe.h | 29 +- wallbe/wallbe.cpp | 2 +- wallbe/wallbe.h | 5 +- wallbe/wallbe.pro | 4 +- 20 files changed, 195 insertions(+), 1262 deletions(-) delete mode 100644 modbuscommander/modbusrtumaster.cpp delete mode 100644 modbuscommander/modbusrtumaster.h delete mode 100644 modbuscommander/modbustcpmaster.cpp delete mode 100644 modbuscommander/modbustcpmaster.h delete mode 100644 mypv/modbustcpmaster.cpp delete mode 100644 mypv/modbustcpmaster.h diff --git a/drexelundweiss/drexelundweiss.pro b/drexelundweiss/drexelundweiss.pro index 0638497..561d18d 100644 --- a/drexelundweiss/drexelundweiss.pro +++ b/drexelundweiss/drexelundweiss.pro @@ -6,11 +6,9 @@ QT += \ SOURCES += \ integrationplugindrexelundweiss.cpp \ - modbusrtumaster.cpp \ + ../modbus/modbusrtumaster.cpp \ HEADERS += \ integrationplugindrexelundweiss.h \ - modbusrtumaster.h \ - modbusdegisterdefinition.h - - + modbusdegisterdefinition.h \ + ../modbus/modbusrtumaster.h \ diff --git a/drexelundweiss/integrationplugindrexelundweiss.h b/drexelundweiss/integrationplugindrexelundweiss.h index 282440e..aef6390 100644 --- a/drexelundweiss/integrationplugindrexelundweiss.h +++ b/drexelundweiss/integrationplugindrexelundweiss.h @@ -34,8 +34,9 @@ #include "integrations/integrationplugin.h" #include "plugintimer.h" -#include #include "modbusrtumaster.h" + +#include #include class IntegrationPluginDrexelUndWeiss : public IntegrationPlugin diff --git a/fronius/fronius.pro b/fronius/fronius.pro index 7ee3bf0..0a0729e 100644 --- a/fronius/fronius.pro +++ b/fronius/fronius.pro @@ -11,7 +11,8 @@ SOURCES += \ froniusinverter.cpp \ froniusstorage.cpp \ froniusmeter.cpp \ - sunspecthing.cpp + sunspecthing.cpp \ + ../modbus/modbustcpmaster.h \ HEADERS += \ integrationpluginfronius.h \ @@ -20,4 +21,5 @@ HEADERS += \ froniusinverter.h \ froniusstorage.h \ froniusmeter.h \ - sunspecthing.h + sunspecthing.h \ + ../modbus/modbustcpmaster.h \ diff --git a/modbuscommander/integrationpluginmodbuscommander.cpp b/modbuscommander/integrationpluginmodbuscommander.cpp index b88d92d..b51ebd7 100644 --- a/modbuscommander/integrationpluginmodbuscommander.cpp +++ b/modbuscommander/integrationpluginmodbuscommander.cpp @@ -28,7 +28,6 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ - #include "integrationpluginmodbuscommander.h" #include "plugininfo.h" @@ -70,20 +69,20 @@ void IntegrationPluginModbusCommander::setupThing(ThingSetupInfo *info) Thing *thing = info->thing(); if (thing->thingClassId() == modbusTCPClientThingClassId) { - QString ipAddress = thing->paramValue(modbusTCPClientThingIpv4addressParamTypeId).toString(); + QHostAddress hostAddress = QHostAddress(thing->paramValue(modbusTCPClientThingIpv4addressParamTypeId).toString()); uint port = thing->paramValue(modbusTCPClientThingPortParamTypeId).toUInt(); foreach (ModbusTCPMaster *modbusTCPMaster, m_modbusTCPMasters.values()) { - if ((modbusTCPMaster->ipv4Address() == ipAddress) && (modbusTCPMaster->port() == port)){ + if ((modbusTCPMaster->hostAddress() == hostAddress) && (modbusTCPMaster->port() == port)){ m_modbusTCPMasters.insert(thing, modbusTCPMaster); return info->finish(Thing::ThingErrorNoError); } } - ModbusTCPMaster *modbusTCPMaster = new ModbusTCPMaster(ipAddress, port, this); + ModbusTCPMaster *modbusTCPMaster = new ModbusTCPMaster(hostAddress, port, this); connect(modbusTCPMaster, &ModbusTCPMaster::connectionStateChanged, this, &IntegrationPluginModbusCommander::onConnectionStateChanged); - connect(modbusTCPMaster, &ModbusTCPMaster::requestExecuted, this, &IntegrationPluginModbusCommander::onRequestExecuted); - connect(modbusTCPMaster, &ModbusTCPMaster::requestError, this, &IntegrationPluginModbusCommander::onRequestError); + connect(modbusTCPMaster, &ModbusTCPMaster::writeRequestExecuted, this, &IntegrationPluginModbusCommander::onRequestExecuted); + connect(modbusTCPMaster, &ModbusTCPMaster::writeRequestError, this, &IntegrationPluginModbusCommander::onRequestError); connect(modbusTCPMaster, &ModbusTCPMaster::receivedCoil, this, &IntegrationPluginModbusCommander::onReceivedCoil); connect(modbusTCPMaster, &ModbusTCPMaster::receivedDiscreteInput, this, &IntegrationPluginModbusCommander::onReceivedDiscreteInput); connect(modbusTCPMaster, &ModbusTCPMaster::receivedHoldingRegister, this, &IntegrationPluginModbusCommander::onReceivedHoldingRegister); diff --git a/modbuscommander/integrationpluginmodbuscommander.h b/modbuscommander/integrationpluginmodbuscommander.h index f343caf..c9b4a9d 100644 --- a/modbuscommander/integrationpluginmodbuscommander.h +++ b/modbuscommander/integrationpluginmodbuscommander.h @@ -33,8 +33,9 @@ #include "integrations/integrationplugin.h" #include "plugintimer.h" -#include "modbustcpmaster.h" -#include "modbusrtumaster.h" + +#include "../modbus/modbustcpmaster.h" +#include "../modbus/modbusrtumaster.h" #include #include diff --git a/modbuscommander/modbuscommander.pro b/modbuscommander/modbuscommander.pro index 98c7984..276537d 100644 --- a/modbuscommander/modbuscommander.pro +++ b/modbuscommander/modbuscommander.pro @@ -1,4 +1,4 @@ -include(../plugin.pri) +include(../plugins.pri) QT += \ serialport \ @@ -6,11 +6,10 @@ QT += \ serialbus \ SOURCES += \ - integrationpluginmodbuscommander.cpp \ - modbustcpmaster.cpp \ - modbusrtumaster.cpp \ + integrationpluginmodbuscommander.cpp \ + ../modbus/modbustcpmaster.cpp \ HEADERS += \ integrationpluginmodbuscommander.h \ - modbustcpmaster.h \ - modbusrtumaster.h \ + ../modbus/modbustcpmaster.h \ + diff --git a/modbuscommander/modbusrtumaster.cpp b/modbuscommander/modbusrtumaster.cpp deleted file mode 100644 index 5742168..0000000 --- a/modbuscommander/modbusrtumaster.cpp +++ /dev/null @@ -1,371 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -* -* Copyright 2013 - 2020, nymea GmbH -* Contact: contact@nymea.io -* -* This file is part of nymea. -* This project including source code and documentation is protected by -* copyright law, and remains the property of nymea GmbH. All rights, including -* reproduction, publication, editing and translation, are reserved. The use of -* this project is subject to the terms of a license agreement to be concluded -* with nymea GmbH in accordance with the terms of use of nymea GmbH, available -* under https://nymea.io/license -* -* GNU 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" -#include "extern-plugininfo.h" - -#include - -ModbusRTUMaster::ModbusRTUMaster(QString serialPort, uint baudrate, QSerialPort::Parity parity, uint dataBits, uint stopBits, QObject *parent) : - QObject(parent) -{ - m_modbusRtuSerialMaster = new QModbusRtuSerialMaster(this); - m_modbusRtuSerialMaster->setConnectionParameter(QModbusDevice::SerialPortNameParameter, serialPort); - m_modbusRtuSerialMaster->setConnectionParameter(QModbusDevice::SerialBaudRateParameter, baudrate); - m_modbusRtuSerialMaster->setConnectionParameter(QModbusDevice::SerialDataBitsParameter, dataBits); - m_modbusRtuSerialMaster->setConnectionParameter(QModbusDevice::SerialStopBitsParameter, stopBits); - m_modbusRtuSerialMaster->setConnectionParameter(QModbusDevice::SerialParityParameter, parity); - //m_modbusRtuSerialMaster->setTimeout(100); - //m_modbusRtuSerialMaster->setNumberOfRetries(1); - connect(m_modbusRtuSerialMaster, &QModbusTcpClient::stateChanged, this, &ModbusRTUMaster::onModbusStateChanged); - connect(m_modbusRtuSerialMaster, &QModbusRtuSerialMaster::errorOccurred, this, &ModbusRTUMaster::onModbusErrorOccurred); - - m_reconnectTimer = new QTimer(this); - m_reconnectTimer->setSingleShot(true); - connect(m_reconnectTimer, &QTimer::timeout, this, &ModbusRTUMaster::onReconnectTimer); -} - - -ModbusRTUMaster::~ModbusRTUMaster() -{ - if (!m_modbusRtuSerialMaster) { - m_modbusRtuSerialMaster->disconnectDevice(); - m_modbusRtuSerialMaster->deleteLater(); - } - if (!m_reconnectTimer) { - m_reconnectTimer->stop(); - m_reconnectTimer->deleteLater(); - } -} - -bool ModbusRTUMaster::connectDevice() -{ - qCDebug(dcModbusCommander()) << "Setting up TCP connecion"; - - if (!m_modbusRtuSerialMaster) - return false; - - return m_modbusRtuSerialMaster->connectDevice(); -} - -QString ModbusRTUMaster::serialPort() -{ - return m_modbusRtuSerialMaster->connectionParameter(QModbusDevice::SerialPortNameParameter).toString(); -} - -void ModbusRTUMaster::onReconnectTimer() -{ - if(!m_modbusRtuSerialMaster->connectDevice()) { - m_reconnectTimer->start(10000); - } -} - -QUuid ModbusRTUMaster::readCoil(uint slaveAddress, uint registerAddress) -{ - if (!m_modbusRtuSerialMaster) { - return ""; - } - QUuid requestId = QUuid::createUuid(); - - QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::Coils, registerAddress, 1); - - if (QModbusReply *reply = m_modbusRtuSerialMaster->sendReadRequest(request, slaveAddress)) { - if (!reply->isFinished()) { - connect(reply, &QModbusReply::finished, this, [reply, requestId, this] { - - - if (reply->error() == QModbusDevice::NoError) { - requestExecuted(requestId, true); - const QModbusDataUnit unit = reply->result(); - uint modbusAddress = unit.startAddress(); - emit receivedCoil(reply->serverAddress(), modbusAddress, unit.value(0)); - - } else { - requestExecuted(requestId, false); - qCWarning(dcModbusCommander()) << "Read response error:" << reply->error(); - } - reply->deleteLater(); - }); - connect(reply, &QModbusReply::errorOccurred, this, [reply, requestId, this] (QModbusDevice::Error error){ - - qCWarning(dcModbusCommander()) << "Modbus replay error:" << error; - - emit requestError(requestId, reply->errorString()); - reply->finished(); // To make sure it will be deleted - }); - QTimer::singleShot(200, reply, &QModbusReply::deleteLater); - } else { - delete reply; // broadcast replies return immediately - return ""; - } - } else { - qCWarning(dcModbusCommander()) << "Read error: " << m_modbusRtuSerialMaster->errorString(); - return ""; - } - return requestId; -} - -QUuid ModbusRTUMaster::writeCoil(uint slaveAddress, uint registerAddress, bool value) -{ - if (!m_modbusRtuSerialMaster) { - return ""; - } - QUuid requestId = QUuid::createUuid(); - - QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::Coils, registerAddress, 1); - request.setValue(0, static_cast(value)); - - if (QModbusReply *reply = m_modbusRtuSerialMaster->sendWriteRequest(request, slaveAddress)) { - if (!reply->isFinished()) { - connect(reply, &QModbusReply::finished, this, [reply, requestId, this] { - - if (reply->error() == QModbusDevice::NoError) { - requestExecuted(requestId, true); - const QModbusDataUnit unit = reply->result(); - uint modbusAddress = unit.startAddress(); - emit receivedCoil(reply->serverAddress(), modbusAddress, unit.value(0)); - - } else { - requestExecuted(requestId, false); - qCWarning(dcModbusCommander()) << "Read response error:" << reply->error(); - } - reply->deleteLater(); - }); - connect(reply, &QModbusReply::errorOccurred, this, [reply, requestId, this] (QModbusDevice::Error error){ - - qCWarning(dcModbusCommander()) << "Modbus replay error:" << error; - emit requestError(requestId, reply->errorString()); - reply->finished(); // To make sure it will be deleted - }); - QTimer::singleShot(200, reply, &QModbusReply::deleteLater); - } else { - delete reply; // broadcast replies return immediately - return ""; - } - } else { - qCWarning(dcModbusCommander()) << "Read error: " << m_modbusRtuSerialMaster->errorString(); - return ""; - } - return requestId; -} - -QUuid ModbusRTUMaster::writeHoldingRegister(uint slaveAddress, uint registerAddress, uint value) -{ - if (!m_modbusRtuSerialMaster) { - return ""; - } - QUuid requestId = QUuid::createUuid(); - - QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, registerAddress, 1); - request.setValue(0, static_cast(value)); - - if (QModbusReply *reply = m_modbusRtuSerialMaster->sendWriteRequest(request, slaveAddress)) { - if (!reply->isFinished()) { - connect(reply, &QModbusReply::finished, this, [reply, requestId, this] { - - if (reply->error() == QModbusDevice::NoError) { - requestExecuted(requestId, true); - const QModbusDataUnit unit = reply->result(); - uint modbusAddress = unit.startAddress(); - emit receivedHoldingRegister(reply->serverAddress(), modbusAddress, unit.value(0)); - - } else { - requestExecuted(requestId, false); - qCWarning(dcModbusCommander()) << "Read response error:" << reply->error(); - } - reply->deleteLater(); - }); - connect(reply, &QModbusReply::errorOccurred, this, [reply, requestId, this] (QModbusDevice::Error error){ - - qCWarning(dcModbusCommander()) << "Modbus replay error:" << error; - emit requestError(requestId, reply->errorString()); - reply->finished(); // To make sure it will be deleted - }); - QTimer::singleShot(200, reply, &QModbusReply::deleteLater); - } else { - delete reply; // broadcast replies return immediately - return ""; - } - } else { - qCWarning(dcModbusCommander()) << "Read error: " << m_modbusRtuSerialMaster->errorString(); - return ""; - } - return requestId; -} - -QUuid ModbusRTUMaster::readDiscreteInput(uint slaveAddress, uint registerAddress) -{ - if (!m_modbusRtuSerialMaster) { - return ""; - } - QUuid requestId = QUuid::createUuid(); - - QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::DiscreteInputs, registerAddress, 1); - - if (QModbusReply *reply = m_modbusRtuSerialMaster->sendReadRequest(request, slaveAddress)) { - if (!reply->isFinished()) { - connect(reply, &QModbusReply::finished, this, [reply, requestId, this] { - - if (reply->error() == QModbusDevice::NoError) { - requestExecuted(requestId, true); - const QModbusDataUnit unit = reply->result(); - uint modbusAddress = unit.startAddress(); - emit receivedDiscreteInput(reply->serverAddress(), modbusAddress, unit.value(0)); - - } else { - requestExecuted(requestId, false); - qCWarning(dcModbusCommander()) << "Read response error:" << reply->error(); - } - reply->deleteLater(); - }); - connect(reply, &QModbusReply::errorOccurred, this, [reply, requestId, this] (QModbusDevice::Error error){ - - qCWarning(dcModbusCommander()) << "Modbus replay error:" << error; - - emit requestError(requestId, reply->errorString()); - reply->finished(); // To make sure it will be deleted - }); - QTimer::singleShot(200, reply, &QModbusReply::deleteLater); - } else { - delete reply; // broadcast replies return immediately - return ""; - } - } else { - qCWarning(dcModbusCommander()) << "Read error: " << m_modbusRtuSerialMaster->errorString(); - return ""; - } - return requestId; -} - -QUuid ModbusRTUMaster::readInputRegister(uint slaveAddress, uint registerAddress) -{ - if (!m_modbusRtuSerialMaster) { - return ""; - } - QUuid requestId = QUuid::createUuid(); - - QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::InputRegisters, registerAddress, 1); - - if (QModbusReply *reply = m_modbusRtuSerialMaster->sendReadRequest(request, slaveAddress)) { - if (!reply->isFinished()) { - connect(reply, &QModbusReply::finished, this, [reply, requestId, this] { - - - if (reply->error() == QModbusDevice::NoError) { - requestExecuted(requestId, true); - const QModbusDataUnit unit = reply->result(); - uint modbusAddress = unit.startAddress(); - emit receivedInputRegister(reply->serverAddress(), modbusAddress, unit.value(0)); - - } else { - requestExecuted(requestId, false); - qCWarning(dcModbusCommander()) << "Read response error:" << reply->error(); - } - reply->deleteLater(); - }); - connect(reply, &QModbusReply::errorOccurred, this, [reply, requestId, this] (QModbusDevice::Error error){ - - qCWarning(dcModbusCommander()) << "Modbus replay error:" << error; - - emit requestError(requestId, reply->errorString()); - reply->finished(); // To make sure it will be deleted - }); - QTimer::singleShot(200, reply, &QModbusReply::deleteLater); - } else { - delete reply; // broadcast replies return immediately - return ""; - } - } else { - qCWarning(dcModbusCommander()) << "Read error: " << m_modbusRtuSerialMaster->errorString(); - return ""; - } - return requestId; -} - -QUuid ModbusRTUMaster::readHoldingRegister(uint slaveAddress, uint registerAddress) -{ - if (!m_modbusRtuSerialMaster) { - return ""; - } - QUuid requestId = QUuid::createUuid(); - - QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, registerAddress, 1); - - if (QModbusReply *reply = m_modbusRtuSerialMaster->sendReadRequest(request, slaveAddress)) { - if (!reply->isFinished()) { - connect(reply, &QModbusReply::finished, this, [reply, requestId, this] { - - if (reply->error() == QModbusDevice::NoError) { - requestExecuted(requestId, true); - const QModbusDataUnit unit = reply->result(); - uint modbusAddress = unit.startAddress(); - emit receivedHoldingRegister(reply->serverAddress(), modbusAddress, unit.value(0)); - - } else { - requestExecuted(requestId, false); - qCWarning(dcModbusCommander()) << "Read response error:" << reply->error(); - } - reply->deleteLater(); - }); - connect(reply, &QModbusReply::errorOccurred, this, [reply, requestId, this] (QModbusDevice::Error error){ - - qCWarning(dcModbusCommander()) << "Modbus replay error:" << error; - - emit requestError(requestId, reply->errorString()); - reply->finished(); // To make sure it will be deleted - }); - QTimer::singleShot(200, reply, &QModbusReply::deleteLater); - } else { - delete reply; // broadcast replies return immediately - return ""; - } - } else { - qCWarning(dcModbusCommander()) << "Read error: " << m_modbusRtuSerialMaster->errorString(); - return ""; - } - return requestId; -} - - -void ModbusRTUMaster::onModbusErrorOccurred(QModbusDevice::Error error) -{ - qCWarning(dcModbusCommander()) << "An error occured" << error; -} - - -void ModbusRTUMaster::onModbusStateChanged(QModbusDevice::State state) -{ - bool connected = (state != QModbusDevice::UnconnectedState); - if (!connected) { - //try to reconnect in 10 seconds - m_reconnectTimer->start(10000); - } - emit connectionStateChanged(connected); -} diff --git a/modbuscommander/modbusrtumaster.h b/modbuscommander/modbusrtumaster.h deleted file mode 100644 index cc8c7fb..0000000 --- a/modbuscommander/modbusrtumaster.h +++ /dev/null @@ -1,81 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -* -* Copyright 2013 - 2020, nymea GmbH -* Contact: contact@nymea.io -* -* This file is part of nymea. -* This project including source code and documentation is protected by -* copyright law, and remains the property of nymea GmbH. All rights, including -* reproduction, publication, editing and translation, are reserved. The use of -* this project is subject to the terms of a license agreement to be concluded -* with nymea GmbH in accordance with the terms of use of nymea GmbH, available -* under https://nymea.io/license -* -* GNU 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 -#include -#include - -class ModbusRTUMaster : public QObject -{ - Q_OBJECT -public: - explicit ModbusRTUMaster(QString serialPort, uint baudrate, QSerialPort::Parity parity, uint dataBits, uint stopBits, QObject *parent = nullptr); - ~ModbusRTUMaster(); - - bool connectDevice(); - - QUuid readCoil(uint slaveAddress, uint registerAddress); - QUuid readDiscreteInput(uint slaveAddress, uint registerAddress); - QUuid readInputRegister(uint slaveAddress, uint registerAddress); - QUuid readHoldingRegister(uint slaveAddress, uint registerAddress); - - QUuid writeCoil(uint slaveAddress, uint registerAddress, bool status); - QUuid writeHoldingRegister(uint slaveAddress, uint registerAddress, uint data); - - QString serialPort(); - -private: - QModbusRtuSerialMaster *m_modbusRtuSerialMaster; - QTimer *m_reconnectTimer = nullptr; - -private slots: - void onReconnectTimer(); - - void onModbusErrorOccurred(QModbusDevice::Error error); - void onModbusStateChanged(QModbusDevice::State state); - -signals: - void connectionStateChanged(bool status); - - void requestExecuted(QUuid requestId, bool success); - void requestError(QUuid requestId, const QString &error); - - void receivedCoil(uint slaveAddress, uint modbusRegister, bool value); - void receivedDiscreteInput(uint slaveAddress, uint modbusRegister, bool value); - void receivedHoldingRegister(uint slaveAddress, uint modbusRegister, uint value); - void receivedInputRegister(uint slaveAddress, uint modbusRegister, uint value); -}; - -#endif // MODBUSRTUMASTER_H diff --git a/modbuscommander/modbustcpmaster.cpp b/modbuscommander/modbustcpmaster.cpp deleted file mode 100644 index 7d03051..0000000 --- a/modbuscommander/modbustcpmaster.cpp +++ /dev/null @@ -1,375 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -* -* Copyright 2013 - 2020, nymea GmbH -* Contact: contact@nymea.io -* -* This file is part of nymea. -* This project including source code and documentation is protected by -* copyright law, and remains the property of nymea GmbH. All rights, including -* reproduction, publication, editing and translation, are reserved. The use of -* this project is subject to the terms of a license agreement to be concluded -* with nymea GmbH in accordance with the terms of use of nymea GmbH, available -* under https://nymea.io/license -* -* GNU 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 "modbustcpmaster.h" -#include "extern-plugininfo.h" - -ModbusTCPMaster::ModbusTCPMaster(QString IPv4Address, uint port, QObject *parent) : - QObject(parent) -{ - m_modbusTcpClient = new QModbusTcpClient(this); - m_modbusTcpClient->setConnectionParameter(QModbusDevice::NetworkPortParameter, port); - m_modbusTcpClient->setConnectionParameter(QModbusDevice::NetworkAddressParameter, IPv4Address); - //m_modbusTcpClient->setTimeout(100); - //m_modbusTcpClient->setNumberOfRetries(1); - - connect(m_modbusTcpClient, &QModbusTcpClient::stateChanged, this, &ModbusTCPMaster::onModbusStateChanged); - connect(m_modbusTcpClient, &QModbusRtuSerialMaster::errorOccurred, this, &ModbusTCPMaster::onModbusErrorOccurred); - - m_reconnectTimer = new QTimer(this); - m_reconnectTimer->setSingleShot(true); - connect(m_reconnectTimer, &QTimer::timeout, this, &ModbusTCPMaster::onReconnectTimer); -} - -ModbusTCPMaster::~ModbusTCPMaster() -{ - if (!m_modbusTcpClient) { - m_modbusTcpClient->disconnectDevice(); - m_modbusTcpClient->deleteLater(); - } - if (!m_reconnectTimer) { - m_reconnectTimer->stop(); - m_reconnectTimer->deleteLater(); - } -} - -bool ModbusTCPMaster::connectDevice() { - // TCP connction to target device - qCDebug(dcModbusCommander()) << "Setting up TCP connecion"; - - if (!m_modbusTcpClient) - return false; - - return m_modbusTcpClient->connectDevice(); -} - -uint ModbusTCPMaster::port() -{ - return m_modbusTcpClient->connectionParameter(QModbusDevice::NetworkPortParameter).toUInt(); -} - -bool ModbusTCPMaster::setIPv4Address(QString ipv4Address) -{ - m_modbusTcpClient->setConnectionParameter(QModbusDevice::NetworkAddressParameter, ipv4Address); - return connectDevice(); -} - -bool ModbusTCPMaster::setPort(uint port) -{ - m_modbusTcpClient->setConnectionParameter(QModbusDevice::NetworkPortParameter, port); - return connectDevice(); -} - -void ModbusTCPMaster::onReconnectTimer() -{ - if(!m_modbusTcpClient->connectDevice()) { - m_reconnectTimer->start(10000); - } -} - -QString ModbusTCPMaster::ipv4Address() -{ - return m_modbusTcpClient->connectionParameter(QModbusDevice::NetworkAddressParameter).toString(); -} - -QUuid ModbusTCPMaster::readCoil(uint slaveAddress, uint registerAddress) -{ - if (!m_modbusTcpClient) { - return ""; - } - QUuid requestId = QUuid::createUuid(); - - QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::Coils, registerAddress, 1); - - if (QModbusReply *reply = m_modbusTcpClient->sendReadRequest(request, slaveAddress)) { - if (!reply->isFinished()) { - connect(reply, &QModbusReply::finished, this, [reply, requestId, this] { - reply->deleteLater(); - - if (reply->error() == QModbusDevice::NoError) { - requestExecuted(requestId, true); - const QModbusDataUnit unit = reply->result(); - uint modbusAddress = unit.startAddress(); - emit receivedCoil(reply->serverAddress(), modbusAddress, unit.value(0)); - - } else { - requestExecuted(requestId, false); - qCWarning(dcModbusCommander()) << "Read response error:" << reply->error(); - } - }); - connect(reply, &QModbusReply::errorOccurred, this, [reply, requestId, this] (QModbusDevice::Error error){ - - qCWarning(dcModbusCommander()) << "Modbus reply error:" << error; - emit requestError(requestId, reply->errorString()); - reply->finished(); // To make sure it will be deleted - }); - QTimer::singleShot(200, reply, &QModbusReply::deleteLater); - } else { - delete reply; // broadcast replies return immediately - return ""; - } - } else { - qCWarning(dcModbusCommander()) << "Read error: " << m_modbusTcpClient->errorString(); - return ""; - } - return requestId; -} - -QUuid ModbusTCPMaster::writeHoldingRegister(uint slaveAddress, uint registerAddress, uint value) -{ - if (!m_modbusTcpClient) { - return ""; - } - QUuid requestId = QUuid::createUuid(); - QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, registerAddress, 1); - request.setValue(0, static_cast(value)); - - if (QModbusReply *reply = m_modbusTcpClient->sendWriteRequest(request, slaveAddress)) { - if (!reply->isFinished()) { - connect(reply, &QModbusReply::finished, this, [reply, requestId, this] { - - if (reply->error() == QModbusDevice::NoError) { - requestExecuted(requestId, true); - const QModbusDataUnit unit = reply->result(); - uint modbusAddress = unit.startAddress(); - emit receivedHoldingRegister(reply->serverAddress(), modbusAddress, unit.value(0)); - - } else { - requestExecuted(requestId, false); - qCWarning(dcModbusCommander()) << "Read response error:" << reply->error(); - } - reply->deleteLater(); - }); - connect(reply, &QModbusReply::errorOccurred, this, [reply, requestId, this] (QModbusDevice::Error error){ - - qCWarning(dcModbusCommander()) << "Modbus replay error:" << error; - emit requestError(requestId, reply->errorString()); - reply->finished(); // To make sure it will be deleted - }); - QTimer::singleShot(200, reply, &QModbusReply::deleteLater); - } else { - delete reply; // broadcast replies return immediately - return ""; - } - } else { - qCWarning(dcModbusCommander()) << "Read error: " << m_modbusTcpClient->errorString(); - return ""; - } - return requestId; -} - -QUuid ModbusTCPMaster::readDiscreteInput(uint slaveAddress, uint registerAddress) -{ - if (!m_modbusTcpClient) { - return ""; - } - QUuid requestId = QUuid::createUuid(); - - QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::DiscreteInputs, registerAddress, 1); - - if (QModbusReply *reply = m_modbusTcpClient->sendReadRequest(request, slaveAddress)) { - if (!reply->isFinished()) { - connect(reply, &QModbusReply::finished, this, [reply, requestId, this] { - reply->deleteLater(); - if (reply->error() == QModbusDevice::NoError) { - requestExecuted(requestId, true); - const QModbusDataUnit unit = reply->result(); - uint modbusAddress = unit.startAddress(); - emit receivedDiscreteInput(reply->serverAddress(), modbusAddress, unit.value(0)); - - } else { - requestExecuted(requestId, false); - qCWarning(dcModbusCommander()) << "Read response error:" << reply->error(); - } - }); - connect(reply, &QModbusReply::errorOccurred, this, [requestId, this] (QModbusDevice::Error error){ - - qCWarning(dcModbusCommander()) << "Modbus replay error:" << error; - QModbusReply *reply = qobject_cast(sender()); - emit requestError(requestId, reply->errorString()); - reply->finished(); // To make sure it will be deleted - }); - QTimer::singleShot(200, reply, &QModbusReply::deleteLater); - } else { - delete reply; // broadcast replies return immediately - return ""; - } - } else { - qCWarning(dcModbusCommander()) << "Read error: " << m_modbusTcpClient->errorString(); - return ""; - } - return requestId; -} - -QUuid ModbusTCPMaster::readInputRegister(uint slaveAddress, uint registerAddress) -{ - if (!m_modbusTcpClient) { - return ""; - } - QUuid requestId = QUuid::createUuid(); - - QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::InputRegisters, registerAddress, 1); - - if (QModbusReply *reply = m_modbusTcpClient->sendReadRequest(request, slaveAddress)) { - if (!reply->isFinished()) { - connect(reply, &QModbusReply::finished, this, [reply, requestId, this] { - reply->deleteLater(); - if (reply->error() == QModbusDevice::NoError) { - requestExecuted(requestId, true); - const QModbusDataUnit unit = reply->result(); - uint modbusAddress = unit.startAddress(); - emit receivedInputRegister(reply->serverAddress(), modbusAddress, unit.value(0)); - - } else { - requestExecuted(requestId, false); - qCWarning(dcModbusCommander()) << "Read response error:" << reply->error(); - } - }); - connect(reply, &QModbusReply::errorOccurred, this, [reply, requestId, this] (QModbusDevice::Error error){ - - qCWarning(dcModbusCommander()) << "Modbus reply error:" << error; - emit requestError(requestId, reply->errorString()); - reply->finished(); // To make sure it will be deleted - }); - QTimer::singleShot(200, reply, &QModbusReply::deleteLater); - } else { - delete reply; // broadcast replies return immediately - return ""; - } - } else { - qCWarning(dcModbusCommander()) << "Read error: " << m_modbusTcpClient->errorString(); - return ""; - } - return requestId; -} - -QUuid ModbusTCPMaster::readHoldingRegister(uint slaveAddress, uint registerAddress) -{ - if (!m_modbusTcpClient) { - return ""; - } - QUuid requestId = QUuid::createUuid(); - - QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, registerAddress, 1); - - if (QModbusReply *reply = m_modbusTcpClient->sendReadRequest(request, slaveAddress)) { - if (!reply->isFinished()) { - connect(reply, &QModbusReply::finished, this, [reply, requestId, this] { - - if (reply->error() == QModbusDevice::NoError) { - requestExecuted(requestId, true); - const QModbusDataUnit unit = reply->result(); - uint modbusAddress = unit.startAddress(); - emit receivedHoldingRegister(reply->serverAddress(), modbusAddress, unit.value(0)); - - } else { - requestExecuted(requestId, false); - qCWarning(dcModbusCommander()) << "Read response error:" << reply->error(); - } - reply->deleteLater(); - }); - connect(reply, &QModbusReply::errorOccurred, this, [reply, requestId, this] (QModbusDevice::Error error){ - - qCWarning(dcModbusCommander()) << "Modbus replay error:" << error; - emit requestError(requestId, reply->errorString()); - reply->finished(); // To make sure it will be deleted - }); - QTimer::singleShot(200, reply, &QModbusReply::deleteLater); - } else { - delete reply; // broadcast replies return immediately - return ""; - } - } else { - qCWarning(dcModbusCommander()) << "Read error: " << m_modbusTcpClient->errorString(); - return ""; - } - return requestId; -} - -QUuid ModbusTCPMaster::writeCoil(uint slaveAddress, uint registerAddress, bool value) -{ - if (!m_modbusTcpClient) { - return ""; - } - QUuid requestId = QUuid::createUuid(); - - QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::Coils, registerAddress, 1); - request.setValue(0, static_cast(value)); - - if (QModbusReply *reply = m_modbusTcpClient->sendWriteRequest(request, slaveAddress)) { - if (!reply->isFinished()) { - connect(reply, &QModbusReply::finished, this, [reply, requestId, this] () { - - if (reply->error() == QModbusDevice::NoError) { - requestExecuted(requestId, true); - const QModbusDataUnit unit = reply->result(); - uint modbusAddress = unit.startAddress(); - emit receivedCoil(reply->serverAddress(), modbusAddress, unit.value(0)); - - } else { - requestExecuted(requestId, false); - qCWarning(dcModbusCommander()) << "Read response error:" << reply->error(); - } - reply->deleteLater(); - }); - connect(reply, &QModbusReply::errorOccurred, this, [reply, requestId, this] (QModbusDevice::Error error){ - - qCWarning(dcModbusCommander()) << "Modbus reply error:" << error; - emit requestError(requestId, reply->errorString()); - reply->finished(); // To make sure it will be deleted - }); - QTimer::singleShot(200, reply, &QModbusReply::deleteLater); - } else { - delete reply; // broadcast replies return immediately - return ""; - } - } else { - qCWarning(dcModbusCommander()) << "Read error: " << m_modbusTcpClient->errorString(); - return ""; - } - return requestId; -} - - -void ModbusTCPMaster::onModbusErrorOccurred(QModbusDevice::Error error) -{ - qCWarning(dcModbusCommander()) << "An error occured" << error; -} - - -void ModbusTCPMaster::onModbusStateChanged(QModbusDevice::State state) -{ - bool connected = (state != QModbusDevice::UnconnectedState); - if (!connected) { - //try to reconnect in 10 seconds - m_reconnectTimer->start(10000); - } - emit connectionStateChanged(connected); -} diff --git a/modbuscommander/modbustcpmaster.h b/modbuscommander/modbustcpmaster.h deleted file mode 100644 index 0862c48..0000000 --- a/modbuscommander/modbustcpmaster.h +++ /dev/null @@ -1,85 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -* -* Copyright 2013 - 2020, nymea GmbH -* Contact: contact@nymea.io -* -* This file is part of nymea. -* This project including source code and documentation is protected by -* copyright law, and remains the property of nymea GmbH. All rights, including -* reproduction, publication, editing and translation, are reserved. The use of -* this project is subject to the terms of a license agreement to be concluded -* with nymea GmbH in accordance with the terms of use of nymea GmbH, available -* under https://nymea.io/license -* -* GNU 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 MODBUSTCPMASTER_H -#define MODBUSTCPMASTER_H - -#include -#include -#include -#include -#include - -class ModbusTCPMaster : public QObject -{ - Q_OBJECT -public: - explicit ModbusTCPMaster(QString ipAddress, uint port, QObject *parent = nullptr); - ~ModbusTCPMaster(); - - bool connectDevice(); - - QUuid readCoil(uint slaveAddress, uint registerAddress); - QUuid readDiscreteInput(uint slaveAddress, uint registerAddress); - QUuid readInputRegister(uint slaveAddress, uint registerAddress); - QUuid readHoldingRegister(uint slaveAddress, uint registerAddress); - - QUuid writeCoil(uint slaveAddress, uint registerAddress, bool status); - QUuid writeHoldingRegister(uint slaveAddress, uint registerAddress, uint data); - - QString ipv4Address(); - uint port(); - bool setIPv4Address(QString ipAddress); - bool setPort(uint port); - - -private: - QTimer *m_reconnectTimer = nullptr; - QModbusTcpClient *m_modbusTcpClient; - -private slots: - void onReconnectTimer(); - - void onModbusErrorOccurred(QModbusDevice::Error error); - void onModbusStateChanged(QModbusDevice::State state); - -signals: - void connectionStateChanged(bool status); - - void requestExecuted(QUuid requestId, bool success); - void requestError(QUuid requestId, const QString &error); - - void receivedCoil(uint slaveAddress, uint modbusRegister, bool value); - void receivedDiscreteInput(uint slaveAddress, uint modbusRegister, bool value); - void receivedHoldingRegister(uint slaveAddress, uint modbusRegister, uint value); - void receivedInputRegister(uint slaveAddress, uint modbusRegister, uint value); -}; - -#endif // MODBUSTCPMASTER_H diff --git a/mypv/integrationpluginmypv.cpp b/mypv/integrationpluginmypv.cpp index e04be9d..f145a46 100644 --- a/mypv/integrationpluginmypv.cpp +++ b/mypv/integrationpluginmypv.cpp @@ -36,7 +36,6 @@ IntegrationPluginMyPv::IntegrationPluginMyPv() { - } @@ -162,14 +161,14 @@ void IntegrationPluginMyPv::executeAction(ThingActionInfo *info) if (action.actionTypeId() == elwaHeatingPowerActionTypeId) { int heatingPower = action.param(elwaHeatingPowerActionHeatingPowerParamTypeId).value().toInt(); - if(!modbusTCPMaster->setRegister(0xff, ElwaModbusRegisters::Power, heatingPower)){ + if(!modbusTCPMaster->writeHoldingRegister(0xff, ElwaModbusRegisters::Power, heatingPower)){ return info->finish(Thing::ThingErrorHardwareFailure); } return; } else if (action.actionTypeId() == elwaPowerActionTypeId) { bool power = action.param(elwaHeatingPowerActionHeatingPowerParamTypeId).value().toBool(); if(power) { - if(!modbusTCPMaster->setRegister(0xff, ElwaModbusRegisters::ManuelStart, 1)){ + if(!modbusTCPMaster->writeHoldingRegister(0xff, ElwaModbusRegisters::ManuelStart, 1)){ return info->finish(Thing::ThingErrorHardwareFailure); } } @@ -188,13 +187,18 @@ void IntegrationPluginMyPv::onRefreshTimer(){ } } +void IntegrationPluginMyPv::onConnectionStateChanged(bool status) +{ +//TODO set device connected state +} + void IntegrationPluginMyPv::update(Thing *thing) { if (thing->thingClassId() == elwaThingClassId) { ModbusTCPMaster *modbusTCPMaster = m_modbusTcpMasters.value(thing); int data; - if (modbusTCPMaster->getRegister(0xff, ElwaModbusRegisters::Status, &data)) { + if (modbusTCPMaster->readHoldingRegister(0xff, ElwaModbusRegisters::Status, &data)) { switch (data) { case Heating: { thing->setStateValue(elwaStatusStateTypeId, "Heating"); diff --git a/mypv/integrationpluginmypv.h b/mypv/integrationpluginmypv.h index 83d923a..82497ef 100644 --- a/mypv/integrationpluginmypv.h +++ b/mypv/integrationpluginmypv.h @@ -33,7 +33,8 @@ #include "integrations/integrationplugin.h" #include "plugintimer.h" -#include "modbustcpmaster.h" + +#include "../modbus/modbustcpmaster.h" #include @@ -84,6 +85,16 @@ private: private slots: void onRefreshTimer(); + + void onPluginConfigurationChanged(const ParamTypeId ¶mTypeId, const QVariant &value); + + void onConnectionStateChanged(bool status); + void onRequestExecuted(QUuid requestId, bool success); + void onRequestError(QUuid requestId, const QString &error); + void onReceivedCoil(quint32 slaveAddress, quint32 modbusRegister, bool value); + void onReceivedDiscreteInput(quint32 slaveAddress, quint32 modbusRegister, bool value); + void onReceivedHoldingRegister(quint32 slaveAddress, quint32 modbusRegister, int value); + void onReceivedInputRegister(quint32 slaveAddress, quint32 modbusRegister, int value); }; #endif // INTEGRATIONPLUGINMYPV_H diff --git a/mypv/modbustcpmaster.cpp b/mypv/modbustcpmaster.cpp deleted file mode 100644 index e895d77..0000000 --- a/mypv/modbustcpmaster.cpp +++ /dev/null @@ -1,184 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -* -* Copyright 2013 - 2020, nymea GmbH -* Contact: contact@nymea.io -* -* This file is part of nymea. -* This project including source code and documentation is protected by -* copyright law, and remains the property of nymea GmbH. All rights, including -* reproduction, publication, editing and translation, are reserved. The use of -* this project is subject to the terms of a license agreement to be concluded -* with nymea GmbH in accordance with the terms of use of nymea GmbH, available -* under https://nymea.io/license -* -* GNU 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 "modbustcpmaster.h" -#include "extern-plugininfo.h" -#include - -Q_DECLARE_LOGGING_CATEGORY(dcModbus) -Q_LOGGING_CATEGORY(dcModbus, "Modbus") - -ModbusTCPMaster::ModbusTCPMaster(QHostAddress IPv4Address, int port, QObject *parent) : - QObject(parent), - m_IPv4Address(IPv4Address), - m_port(port) -{ - -} - -ModbusTCPMaster::~ModbusTCPMaster() -{ - if (m_mb != NULL) { - modbus_close(m_mb); - } - modbus_free(m_mb); -} - -bool ModbusTCPMaster::createInterface() { - // TCP connction to target device - qCDebug(dcModbus()) << "Setting up TCP connecion" << m_IPv4Address.toString() << "port:" << m_port; - const char *address = m_IPv4Address.toString().toLatin1().data(); - m_mb = modbus_new_tcp(address, m_port); - - if(m_mb == nullptr){ - qCWarning(dcMypv()) << "Error modbus TCP: " << modbus_strerror(errno) ; - return false; - } - - // Extend the timeout to 3 seconds - //struct timeval response_timeout; - //response_timeout.tv_sec = 3; - //response_timeout.tv_usec = 0; - //modbus_set_response_timeout(m_mb, &response_timeout); - - if(modbus_connect(m_mb) == -1){ - qCWarning(dcMypv()) << "Error connecting modbus:" << modbus_strerror(errno) ; - return false; - } - return true; -} - -int ModbusTCPMaster::port() -{ - return m_port; -} - -bool ModbusTCPMaster::setIPv4Address(QHostAddress ipv4Address) -{ - m_IPv4Address = ipv4Address; - if (!createInterface()) { - return false; - } - return true; -} - -bool ModbusTCPMaster::setPort(int port) -{ - m_port = port; - if (!createInterface()) { - return false; - } - return true; -} - -QHostAddress ModbusTCPMaster::ipv4Address() -{ - return m_IPv4Address; -} - -bool ModbusTCPMaster::setCoil(int slaveAddress, int coilAddress, bool status) -{ - if (m_mb == nullptr) { - if (!createInterface()) - return false; - } - - if(modbus_set_slave(m_mb, slaveAddress) == -1){ - qCWarning(dcMypv()) << "Error setting slave ID" << slaveAddress << "Reason:" << modbus_strerror(errno) ; - return false; - } - - if (modbus_write_bit(m_mb, coilAddress, status) == -1) { - qCWarning(dcMypv()) << "Could not write Coil" << coilAddress << "Reason:" << modbus_strerror(errno); - return false; - } - return true; -} - -bool ModbusTCPMaster::setRegister(int slaveAddress, int registerAddress, int data) -{ - if (m_mb == nullptr) { - if (!createInterface()) - return false; - } - if(modbus_set_slave(m_mb, slaveAddress) == -1){ - qCWarning(dcMypv()) << "Error setting slave ID" << slaveAddress << "Reason:" << modbus_strerror(errno) ; - return false; - } - - if (modbus_write_register(m_mb, registerAddress, data) == -1) { - qCWarning(dcMypv()) << "Could not write Register" << registerAddress << "Reason:" << modbus_strerror(errno); - return false; - } - return true; -} - -bool ModbusTCPMaster::getCoil(int slaveAddress, int coilAddress, bool *result) -{ - if (m_mb == nullptr) { - if (!createInterface()) - return false; - } - - if(modbus_set_slave(m_mb, slaveAddress) == -1){ - qCWarning(dcMypv()) << "Error setting slave ID" << slaveAddress << "Reason:" << modbus_strerror(errno) ; - return false; - } - - uint8_t status; - if (modbus_read_bits(m_mb, coilAddress, 1, &status) == -1){ - qCWarning(dcMypv()) << "Could not read bits" << coilAddress << "Reason:"<< modbus_strerror(errno); - return false; - } - *result = (bool)status; - return true; -} - -bool ModbusTCPMaster::getRegister(int slaveAddress, int registerAddress, int *result) -{ - uint16_t data; - - if (m_mb == nullptr) { - if (!createInterface()) - return false; - } - - if(modbus_set_slave(m_mb, slaveAddress) == -1){ - qCWarning(dcMypv()) << "Error setting slave ID" << slaveAddress << "Reason:" << modbus_strerror(errno) ; - return false; - } - - if (modbus_read_registers(m_mb, registerAddress, 1, &data) == -1){ - qCWarning(dcMypv()) << "Could not read register" << registerAddress << "Reason:" << modbus_strerror(errno); - return false; - } - *result = data; - return true; -} diff --git a/mypv/modbustcpmaster.h b/mypv/modbustcpmaster.h deleted file mode 100644 index 73907c0..0000000 --- a/mypv/modbustcpmaster.h +++ /dev/null @@ -1,66 +0,0 @@ -/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * -* -* Copyright 2013 - 2020, nymea GmbH -* Contact: contact@nymea.io -* -* This file is part of nymea. -* This project including source code and documentation is protected by -* copyright law, and remains the property of nymea GmbH. All rights, including -* reproduction, publication, editing and translation, are reserved. The use of -* this project is subject to the terms of a license agreement to be concluded -* with nymea GmbH in accordance with the terms of use of nymea GmbH, available -* under https://nymea.io/license -* -* GNU 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 MODBUSTCPMASTER_H -#define MODBUSTCPMASTER_H - -#include -#include -#include - -class ModbusTCPMaster : public QObject -{ - Q_OBJECT -public: - explicit ModbusTCPMaster(QHostAddress IPv4Address, int port, QObject *parent = 0); - ~ModbusTCPMaster(); - bool createInterface(); - - bool getCoil(int slaveAddress, int coilAddress, bool *result); - bool getRegister(int slaveAddress, int registerAddress, int *result); - bool setCoil(int slaveAddress, int coilAddress, bool status); - bool setRegister(int slaveAddress, int registerAddress, int data); - QHostAddress ipv4Address(); - int port(); - bool setIPv4Address(QHostAddress IPv4Address); - bool setPort(int port); - -private: - modbus_t *m_mb; - QHostAddress m_IPv4Address; - int m_port; - - -signals: - -public slots: -}; - -#endif // MODBUSTCPMASTER_H diff --git a/mypv/mypv.pro b/mypv/mypv.pro index 9754d69..f17f844 100644 --- a/mypv/mypv.pro +++ b/mypv/mypv.pro @@ -6,10 +6,9 @@ QT += \ SOURCES += \ integrationpluginmypv.cpp \ - modbustcpmaster.cpp \ + ../modbus/modbustcpmaster.cpp \ HEADERS += \ integrationpluginmypv.h \ - modbustcpmaster.h \ - + ../modbus/modbustcpmaster.h \ diff --git a/wallbe/integrationpluginwallbe.cpp b/wallbe/integrationpluginwallbe.cpp index 417a241..06b39cf 100644 --- a/wallbe/integrationpluginwallbe.cpp +++ b/wallbe/integrationpluginwallbe.cpp @@ -52,15 +52,24 @@ void IntegrationPluginWallbe::setupThing(ThingSetupInfo *info) QHostAddress address(thing->paramValue(wallbeEcoThingIpParamTypeId).toString()); if (address.isNull()){ - qCWarning(dcWallbe) << "IP address is null"; + qCWarning(dcWallbe) << "IP address is not valid"; info->finish(Thing::ThingErrorSetupFailed, tr("IP address parameter not valid")); return; } + ModbusTCPMaster *modbusTcpMaster = new ModbusTCPMaster(address, 502, this); + connect(modbusTcpMaster, &ModbusTCPMaster::connectionStateChanged, this, &IntegrationPluginWallbe::onConnectionStateChanged); + connect(modbusTcpMaster, &ModbusTCPMaster::receivedHoldingRegister, this, &IntegrationPluginWallbe::onReceivedHoldingRegister); + connect(modbusTcpMaster, &ModbusTCPMaster::writeRequestExecuted, this, &IntegrationPluginWallbe::onWriteRequestExecuted); + connect(modbusTcpMaster, &ModbusTCPMaster::writeRequestError, this, &IntegrationPluginWallbe::onWriteRequestError); - WallBe *wallbe = new WallBe(address, 502, this); - m_connections.insert(thing, wallbe); - - info->finish(Thing::ThingErrorNoError); + m_connections.insert(thing, modbusTcpMaster); + connect(modbusTcpMaster, &ModbusTCPMaster::connectionStateChanged, info, [this, modbusTcpMaster](bool connected) { + if(connected) { + info->finish(Thing::ThingErrorNoError); + } else { + info->finish(Thing::ThingErrorHardwareNotAvailable); + } + }); } @@ -85,12 +94,11 @@ void IntegrationPluginWallbe::discoverThings(ThingDiscoveryInfo *info) } info->finish(Thing::ThingErrorNoError); }); - return; + } else { + Q_ASSERT_X(false, "discoverThings", QString("Unhandled thingClassId: %1").arg(info->thingClassId().toString()).toUtf8()); } - Q_ASSERT_X(false, "discoverThings", QString("Unhandled thingClassId: %1").arg(info->thingClassId().toString()).toUtf8()); } - void IntegrationPluginWallbe::postSetupThing(Thing *thing) { if (!m_pluginTimer) { @@ -115,9 +123,9 @@ void IntegrationPluginWallbe::executeAction(ThingActionInfo *info) Thing *thing = info->thing(); Action action = info->action(); - WallBe *wallbe = m_connections.value(thing); - if (!wallbe) { - qCWarning(dcWallbe()) << "Wallbe object not available"; + ModbusTCPMaster *modbusTcpMaster = m_connections.value(thing); + if (!modbusTcpMaster) { + qCWarning(dcWallbe()) << "Modbus connection not available"; info->finish(Thing::ThingErrorHardwareFailure); return; } @@ -130,34 +138,37 @@ void IntegrationPluginWallbe::executeAction(ThingActionInfo *info) // get the param value of the charging action bool charging = action.param(wallbeEcoPowerActionPowerParamTypeId).value().toBool(); qCDebug(dcWallbe) << "start Charging button" << thing->name() << "set power to" << charging; - wallbe->setChargingStatus(charging); + QUuid requestId = modbusTcpMaster->writeCoil(0xff, WallbeRegisterAddress::ChargingStatus, charging); // Set the "power" state thing->setStateValue(wallbeEcoPowerStateTypeId, charging); - info->finish(Thing::ThingErrorNoError); - return; + m_asyncActions.insert(requestId, info); + connect(info, &ThingActionInfo::aborted, this, [this, requestId] {m_asyncActions.remove(requestId);}); } else if(action.actionTypeId() == wallbeEcoChargeCurrentActionTypeId){ uint16_t current = action.param(wallbeEcoChargeCurrentEventChargeCurrentParamTypeId).value().toUInt(); qCDebug(dcWallbe) << "Charging power set to" << current; - wallbe->setChargingCurrent(current); + QUuid requestId = modbusTcpMaster->writeCoil(0xff, WallbeRegisterAddress::ChargingCurrent, current); thing->setStateValue(wallbeEcoChargeCurrentStateTypeId, current); - info->finish(Thing::ThingErrorNoError); - return; - } - Q_ASSERT_X(false, "executeAction", QString("Unhandled action: %1").arg(action.actionTypeId().toString()).toUtf8()); - } - Q_ASSERT_X(false, "executeAction", QString("Unhandled thingClassId: %1").arg(thing->thingClassId().toString()).toUtf8()); -} + m_asyncActions.insert(requestId, info); + connect(info, &ThingActionInfo::aborted, this, [this, requestId] {m_asyncActions.remove(requestId);}); + } else { + Q_ASSERT_X(false, "executeAction", QString("Unhandled action: %1").arg(action.actionTypeId().toString()).toUtf8()); + } + } else { + Q_ASSERT_X(false, "executeAction", QString("Unhandled thingClassId: %1").arg(thing->thingClassId().toString()).toUtf8()); + } +} void IntegrationPluginWallbe::thingRemoved(Thing *thing) { - m_address.removeOne(QHostAddress(thing->paramValue(wallbeEcoThingIpParamTypeId).toString())); - WallBe *wallbe = m_connections.take(thing); - if (wallbe) { - qCDebug(dcWallbe) << "Remove device" << thing->name(); - wallbe->deleteLater(); + if (thing->thingClassId() == wallbeEcoThingClassId) { + if (m_connections.contains(thing)) { + ModbusTCPMaster *modbusTcpMaster = m_connections.take(thing); + qCDebug(dcWallbe) << "Remove device" << thing->name(); + modbusTcpMaster->deleteLater(); + } } if (myThings().isEmpty()) { @@ -167,43 +178,91 @@ void IntegrationPluginWallbe::thingRemoved(Thing *thing) } void IntegrationPluginWallbe::update(Thing *thing) -{ - WallBe * wallbe = m_connections.value(thing); - if(!wallbe->isAvailable()) +{ + ModbusTCPMaster *modbusTCPMaster = m_connections.value(thing); + if(!modbusTCPMaster) + return; + modbusTCPMaster->readHoldingRegister(0xff, WallbeRegisterAddress::EVStatus); + modbusTCPMaster->readHoldingRegister(0xff, WallbeRegisterAddress::ChargingCurrent); + modbusTCPMaster->readHoldingRegister(0xff, WallbeRegisterAddress::ChargingStatus); + modbusTCPMaster->readHoldingRegister(0xff, WallbeRegisterAddress::ChargingTime); +} + +void IntegrationPluginWallbe::onConnectionStateChanged(bool status) +{ + ModbusTCPMaster *modbusTCPMaster = static_cast(sender()); + Thing *thing = m_connections.key(modbusTCPMaster); + if (!thing) + return; + thing->setStateValue(wallbeEcoConnectedStateTypeId, status); +} + +void IntegrationPluginWallbe::onReceivedHoldingRegister(int slaveAddress, int modbusRegister, const QVector &value) +{ + Q_UNUSED(slaveAddress) + ModbusTCPMaster *modbusTCPMaster = static_cast(sender()); + Thing *thing = m_connections.key(modbusTCPMaster); + if (!thing) return; - thing->setStateValue(wallbeEcoConnectedStateTypeId, true); - - //EV state - 16 bit ASCII (8bit) - switch (wallbe->getEvStatus()) { - case 65: - thing->setStateValue(wallbeEcoEvStatusStateTypeId, "A - No car plugged in"); + switch (WallbeRegisterAddress(modbusRegister)) { + case WallbeRegisterAddress::EVStatus: + //EV state - 16 bit ASCII (8bit) + switch (value[0]) { + case 65: + thing->setStateValue(wallbeEcoEvStatusStateTypeId, "A - No car plugged in"); + break; + case 66: + thing->setStateValue(wallbeEcoEvStatusStateTypeId, "B - Supply equipment not yet ready"); + break; + case 67: + thing->setStateValue(wallbeEcoEvStatusStateTypeId, "C - Ready to charge"); + break; + case 68: + thing->setStateValue(wallbeEcoEvStatusStateTypeId, "D - Ready to charge, ventilation needed"); + break; + case 69: + thing->setStateValue(wallbeEcoEvStatusStateTypeId, "E - Short circuit detected"); + break; + case 70: + thing->setStateValue(wallbeEcoEvStatusStateTypeId, "F - Supply equipment not available"); + break; + default: + thing->setStateValue(wallbeEcoEvStatusStateTypeId, "F - Supply equipment not available"); + } break; - case 66: - thing->setStateValue(wallbeEcoEvStatusStateTypeId, "B - Supply equipment not yet ready"); + case WallbeRegisterAddress::ChargingStatus: + thing->setStateValue(wallbeEcoPowerStateTypeId, value[0]); + break; + case WallbeRegisterAddress::ChargingTime: { + // Extract Input Register 102 - load time - 32bit integer + int minutes = (((uint32_t)(value[0]<<16)|(uint32_t)(value[1]))/60); //Converts to minutes + thing->setStateValue(wallbeEcoChargeTimeStateTypeId, minutes); + } + break; + case WallbeRegisterAddress::ChargingCurrent: + thing->setStateValue(wallbeEcoChargeCurrentStateTypeId, value[0]); + break; + case WallbeRegisterAddress::ErrorCode: + qCDebug(dcWallbe()) << "Received Error Code modbus register" << value[0]; break; - case 67: - thing->setStateValue(wallbeEcoEvStatusStateTypeId, "C - Ready to charge"); - break; - case 68: - thing->setStateValue(wallbeEcoEvStatusStateTypeId, "D - Ready to charge, ventilation needed"); - break; - case 69: - thing->setStateValue(wallbeEcoEvStatusStateTypeId, "E - Short circuit detected"); - break; - case 70: - thing->setStateValue(wallbeEcoEvStatusStateTypeId, "F - Supply equipment not available"); - break; - default: - thing->setStateValue(wallbeEcoEvStatusStateTypeId, "F - Supply equipment not available"); } - - qCDebug(dcWallbe) << "EV State:" << thing->stateValue(wallbeEcoEvStatusStateTypeId).toString(); - - // Extract Input Register 102 - load time - 32bit integer - thing->setStateValue(wallbeEcoChargeTimeStateTypeId, wallbe->getChargingTime()); - - // Read the charge current state - thing->setStateValue(wallbeEcoChargeCurrentStateTypeId, wallbe->getChargingCurrent()); - thing->setStateValue(wallbeEcoPowerStateTypeId, wallbe->getChargingStatus()); +} + +void IntegrationPluginWallbe::onWriteRequestExecuted(const QUuid &requestId, bool success) +{ + if (m_asyncActions.contains(requestId)) { + ThingActionInfo *info = m_asyncActions.value(requestId); + if (success) { + info->finish(Thing::ThingErrorNoError); + } else { + info->finish(Thing::ThingErrorHardwareFailure); + } + } +} + +void IntegrationPluginWallbe::onWriteRequestError(const QUuid &requestId, const QString &error) +{ + Q_UNUSED(requestId) + qCWarning(dcWallbe()) << "Could not execute write request" << error; } diff --git a/wallbe/integrationpluginwallbe.h b/wallbe/integrationpluginwallbe.h index 9ebc8c5..fdb8b5f 100644 --- a/wallbe/integrationpluginwallbe.h +++ b/wallbe/integrationpluginwallbe.h @@ -32,10 +32,11 @@ #define INTEGRATIONPLUGINWALLBE_H #include "integrations/integrationplugin.h" -#include "wallbe.h" +#include "plugintimer.h" + #include "host.h" #include "discover.h" -#include "plugintimer.h" +#include "../modbus/modbustcpmaster.h" #include #include @@ -48,6 +49,14 @@ class IntegrationPluginWallbe : public IntegrationPlugin Q_INTERFACES(IntegrationPlugin) public: + enum WallbeRegisterAddress { + EVStatus = 100, + ChargingTime = 102, + ErrorCode = 107, + ChargingCurrent = 300, + ChargingStatus = 400, + }; + explicit IntegrationPluginWallbe(); void discoverThings(ThingDiscoveryInfo *info) override; @@ -57,11 +66,23 @@ public: void thingRemoved(Thing *thing) override; private: - QHash m_connections; - QList m_address; + QHash m_connections; PluginTimer *m_pluginTimer = nullptr; + QHash m_asyncActions; void update(Thing *thing); + +private slots: + void onRefreshTimer(); + + void onConnectionStateChanged(bool status); + void onReceivedCoil(int slaveAddress, int modbusRegister, bool value); + void onReceivedDiscreteInput(int slaveAddress, int modbusRegister, bool value); + void onReceivedHoldingRegister(int slaveAddress, int modbusRegister, const QVector &value); + void onReceivedInputRegister(int slaveAddress, int modbusRegister, int value); + + void onWriteRequestExecuted(const QUuid &requestId, bool success); + void onWriteRequestError(const QUuid &requestId, const QString &error); }; #endif // INTEGRATIONPLUGINWALLBE_H diff --git a/wallbe/wallbe.cpp b/wallbe/wallbe.cpp index 652eaec..f68543f 100644 --- a/wallbe/wallbe.cpp +++ b/wallbe/wallbe.cpp @@ -171,7 +171,7 @@ int WallBe::getChargingTime() if(modbus_read_registers(m_device, 102, 2, reg) == -1) return 0; - return (((uint32_t)(reg[2]<<16)|(uint32_t)(reg[3]))/60); //Converts to minutes + return } void WallBe::setChargingCurrent(int current) diff --git a/wallbe/wallbe.h b/wallbe/wallbe.h index 5abf454..8c0e4e1 100644 --- a/wallbe/wallbe.h +++ b/wallbe/wallbe.h @@ -35,14 +35,15 @@ #include #include -#include +#include "../modbus/modbustcpmaster.h" class WallBe : public QObject { Q_OBJECT public: - WallBe(QHostAddress address, int port, QObject *parent = nullptr); + + WallBe(const QHostAddress &address, int port, QObject *parent = nullptr); ~WallBe(); bool isAvailable(); bool connect(); diff --git a/wallbe/wallbe.pro b/wallbe/wallbe.pro index a140a4b..8edbe70 100644 --- a/wallbe/wallbe.pro +++ b/wallbe/wallbe.pro @@ -6,12 +6,12 @@ QT += \ SOURCES += \ integrationpluginwallbe.cpp \ - wallbe.cpp \ + ../modbus/modbustcpmaster.cpp \ host.cpp \ discover.cpp HEADERS += \ integrationpluginwallbe.h \ - wallbe.h \ + ../modbus/modbustcpmaster.h \ host.h \ discover.h