Wallbe changed to QModbus
This commit is contained in:
parent
5ffe45baff
commit
78c30f54da
@ -6,11 +6,9 @@ QT += \
|
|||||||
|
|
||||||
SOURCES += \
|
SOURCES += \
|
||||||
integrationplugindrexelundweiss.cpp \
|
integrationplugindrexelundweiss.cpp \
|
||||||
modbusrtumaster.cpp \
|
../modbus/modbusrtumaster.cpp \
|
||||||
|
|
||||||
HEADERS += \
|
HEADERS += \
|
||||||
integrationplugindrexelundweiss.h \
|
integrationplugindrexelundweiss.h \
|
||||||
modbusrtumaster.h \
|
modbusdegisterdefinition.h \
|
||||||
modbusdegisterdefinition.h
|
../modbus/modbusrtumaster.h \
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -34,8 +34,9 @@
|
|||||||
#include "integrations/integrationplugin.h"
|
#include "integrations/integrationplugin.h"
|
||||||
#include "plugintimer.h"
|
#include "plugintimer.h"
|
||||||
|
|
||||||
#include <QDateTime>
|
|
||||||
#include "modbusrtumaster.h"
|
#include "modbusrtumaster.h"
|
||||||
|
|
||||||
|
#include <QDateTime>
|
||||||
#include <QSerialPortInfo>
|
#include <QSerialPortInfo>
|
||||||
|
|
||||||
class IntegrationPluginDrexelUndWeiss : public IntegrationPlugin
|
class IntegrationPluginDrexelUndWeiss : public IntegrationPlugin
|
||||||
|
|||||||
@ -11,7 +11,8 @@ SOURCES += \
|
|||||||
froniusinverter.cpp \
|
froniusinverter.cpp \
|
||||||
froniusstorage.cpp \
|
froniusstorage.cpp \
|
||||||
froniusmeter.cpp \
|
froniusmeter.cpp \
|
||||||
sunspecthing.cpp
|
sunspecthing.cpp \
|
||||||
|
../modbus/modbustcpmaster.h \
|
||||||
|
|
||||||
HEADERS += \
|
HEADERS += \
|
||||||
integrationpluginfronius.h \
|
integrationpluginfronius.h \
|
||||||
@ -20,4 +21,5 @@ HEADERS += \
|
|||||||
froniusinverter.h \
|
froniusinverter.h \
|
||||||
froniusstorage.h \
|
froniusstorage.h \
|
||||||
froniusmeter.h \
|
froniusmeter.h \
|
||||||
sunspecthing.h
|
sunspecthing.h \
|
||||||
|
../modbus/modbustcpmaster.h \
|
||||||
|
|||||||
@ -28,7 +28,6 @@
|
|||||||
*
|
*
|
||||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||||
|
|
||||||
|
|
||||||
#include "integrationpluginmodbuscommander.h"
|
#include "integrationpluginmodbuscommander.h"
|
||||||
#include "plugininfo.h"
|
#include "plugininfo.h"
|
||||||
|
|
||||||
@ -70,20 +69,20 @@ void IntegrationPluginModbusCommander::setupThing(ThingSetupInfo *info)
|
|||||||
Thing *thing = info->thing();
|
Thing *thing = info->thing();
|
||||||
|
|
||||||
if (thing->thingClassId() == modbusTCPClientThingClassId) {
|
if (thing->thingClassId() == modbusTCPClientThingClassId) {
|
||||||
QString ipAddress = thing->paramValue(modbusTCPClientThingIpv4addressParamTypeId).toString();
|
QHostAddress hostAddress = QHostAddress(thing->paramValue(modbusTCPClientThingIpv4addressParamTypeId).toString());
|
||||||
uint port = thing->paramValue(modbusTCPClientThingPortParamTypeId).toUInt();
|
uint port = thing->paramValue(modbusTCPClientThingPortParamTypeId).toUInt();
|
||||||
|
|
||||||
foreach (ModbusTCPMaster *modbusTCPMaster, m_modbusTCPMasters.values()) {
|
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);
|
m_modbusTCPMasters.insert(thing, modbusTCPMaster);
|
||||||
return info->finish(Thing::ThingErrorNoError);
|
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::connectionStateChanged, this, &IntegrationPluginModbusCommander::onConnectionStateChanged);
|
||||||
connect(modbusTCPMaster, &ModbusTCPMaster::requestExecuted, this, &IntegrationPluginModbusCommander::onRequestExecuted);
|
connect(modbusTCPMaster, &ModbusTCPMaster::writeRequestExecuted, this, &IntegrationPluginModbusCommander::onRequestExecuted);
|
||||||
connect(modbusTCPMaster, &ModbusTCPMaster::requestError, this, &IntegrationPluginModbusCommander::onRequestError);
|
connect(modbusTCPMaster, &ModbusTCPMaster::writeRequestError, this, &IntegrationPluginModbusCommander::onRequestError);
|
||||||
connect(modbusTCPMaster, &ModbusTCPMaster::receivedCoil, this, &IntegrationPluginModbusCommander::onReceivedCoil);
|
connect(modbusTCPMaster, &ModbusTCPMaster::receivedCoil, this, &IntegrationPluginModbusCommander::onReceivedCoil);
|
||||||
connect(modbusTCPMaster, &ModbusTCPMaster::receivedDiscreteInput, this, &IntegrationPluginModbusCommander::onReceivedDiscreteInput);
|
connect(modbusTCPMaster, &ModbusTCPMaster::receivedDiscreteInput, this, &IntegrationPluginModbusCommander::onReceivedDiscreteInput);
|
||||||
connect(modbusTCPMaster, &ModbusTCPMaster::receivedHoldingRegister, this, &IntegrationPluginModbusCommander::onReceivedHoldingRegister);
|
connect(modbusTCPMaster, &ModbusTCPMaster::receivedHoldingRegister, this, &IntegrationPluginModbusCommander::onReceivedHoldingRegister);
|
||||||
|
|||||||
@ -33,8 +33,9 @@
|
|||||||
|
|
||||||
#include "integrations/integrationplugin.h"
|
#include "integrations/integrationplugin.h"
|
||||||
#include "plugintimer.h"
|
#include "plugintimer.h"
|
||||||
#include "modbustcpmaster.h"
|
|
||||||
#include "modbusrtumaster.h"
|
#include "../modbus/modbustcpmaster.h"
|
||||||
|
#include "../modbus/modbusrtumaster.h"
|
||||||
|
|
||||||
#include <QSerialPortInfo>
|
#include <QSerialPortInfo>
|
||||||
#include <QUuid>
|
#include <QUuid>
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
include(../plugin.pri)
|
include(../plugins.pri)
|
||||||
|
|
||||||
QT += \
|
QT += \
|
||||||
serialport \
|
serialport \
|
||||||
@ -7,10 +7,9 @@ QT += \
|
|||||||
|
|
||||||
SOURCES += \
|
SOURCES += \
|
||||||
integrationpluginmodbuscommander.cpp \
|
integrationpluginmodbuscommander.cpp \
|
||||||
modbustcpmaster.cpp \
|
../modbus/modbustcpmaster.cpp \
|
||||||
modbusrtumaster.cpp \
|
|
||||||
|
|
||||||
HEADERS += \
|
HEADERS += \
|
||||||
integrationpluginmodbuscommander.h \
|
integrationpluginmodbuscommander.h \
|
||||||
modbustcpmaster.h \
|
../modbus/modbustcpmaster.h \
|
||||||
modbusrtumaster.h \
|
|
||||||
|
|||||||
@ -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 <https://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
* For any further details and any questions please contact us under
|
|
||||||
* contact@nymea.io or see our FAQ/Licensing Information on
|
|
||||||
* https://nymea.io/license/faq
|
|
||||||
*
|
|
||||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
|
||||||
|
|
||||||
#include "modbusrtumaster.h"
|
|
||||||
#include "extern-plugininfo.h"
|
|
||||||
|
|
||||||
#include <QSerialPortInfo>
|
|
||||||
|
|
||||||
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<uint16_t>(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<uint16_t>(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);
|
|
||||||
}
|
|
||||||
@ -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 <https://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
* For any further details and any questions please contact us under
|
|
||||||
* contact@nymea.io or see our FAQ/Licensing Information on
|
|
||||||
* https://nymea.io/license/faq
|
|
||||||
*
|
|
||||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
|
||||||
|
|
||||||
#ifndef MODBUSRTUMASTER_H
|
|
||||||
#define MODBUSRTUMASTER_H
|
|
||||||
|
|
||||||
#include <QObject>
|
|
||||||
#include <QtSerialBus>
|
|
||||||
#include <QSerialPort>
|
|
||||||
#include <QTimer>
|
|
||||||
#include <QUuid>
|
|
||||||
|
|
||||||
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
|
|
||||||
@ -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 <https://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
* For any further details and any questions please contact us under
|
|
||||||
* contact@nymea.io or see our FAQ/Licensing Information on
|
|
||||||
* https://nymea.io/license/faq
|
|
||||||
*
|
|
||||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
|
||||||
|
|
||||||
#include "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<uint16_t>(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<QModbusReply *>(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<uint16_t>(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);
|
|
||||||
}
|
|
||||||
@ -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 <https://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
* For any further details and any questions please contact us under
|
|
||||||
* contact@nymea.io or see our FAQ/Licensing Information on
|
|
||||||
* https://nymea.io/license/faq
|
|
||||||
*
|
|
||||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
|
||||||
|
|
||||||
#ifndef MODBUSTCPMASTER_H
|
|
||||||
#define MODBUSTCPMASTER_H
|
|
||||||
|
|
||||||
#include <QObject>
|
|
||||||
#include <QHostAddress>
|
|
||||||
#include <QtSerialBus>
|
|
||||||
#include <QTimer>
|
|
||||||
#include <QUuid>
|
|
||||||
|
|
||||||
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
|
|
||||||
@ -36,7 +36,6 @@
|
|||||||
|
|
||||||
IntegrationPluginMyPv::IntegrationPluginMyPv()
|
IntegrationPluginMyPv::IntegrationPluginMyPv()
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -162,14 +161,14 @@ void IntegrationPluginMyPv::executeAction(ThingActionInfo *info)
|
|||||||
if (action.actionTypeId() == elwaHeatingPowerActionTypeId) {
|
if (action.actionTypeId() == elwaHeatingPowerActionTypeId) {
|
||||||
int heatingPower = action.param(elwaHeatingPowerActionHeatingPowerParamTypeId).value().toInt();
|
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 info->finish(Thing::ThingErrorHardwareFailure);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
} else if (action.actionTypeId() == elwaPowerActionTypeId) {
|
} else if (action.actionTypeId() == elwaPowerActionTypeId) {
|
||||||
bool power = action.param(elwaHeatingPowerActionHeatingPowerParamTypeId).value().toBool();
|
bool power = action.param(elwaHeatingPowerActionHeatingPowerParamTypeId).value().toBool();
|
||||||
if(power) {
|
if(power) {
|
||||||
if(!modbusTCPMaster->setRegister(0xff, ElwaModbusRegisters::ManuelStart, 1)){
|
if(!modbusTCPMaster->writeHoldingRegister(0xff, ElwaModbusRegisters::ManuelStart, 1)){
|
||||||
return info->finish(Thing::ThingErrorHardwareFailure);
|
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) {
|
void IntegrationPluginMyPv::update(Thing *thing) {
|
||||||
if (thing->thingClassId() == elwaThingClassId)
|
if (thing->thingClassId() == elwaThingClassId)
|
||||||
{
|
{
|
||||||
ModbusTCPMaster *modbusTCPMaster = m_modbusTcpMasters.value(thing);
|
ModbusTCPMaster *modbusTCPMaster = m_modbusTcpMasters.value(thing);
|
||||||
|
|
||||||
int data;
|
int data;
|
||||||
if (modbusTCPMaster->getRegister(0xff, ElwaModbusRegisters::Status, &data)) {
|
if (modbusTCPMaster->readHoldingRegister(0xff, ElwaModbusRegisters::Status, &data)) {
|
||||||
switch (data) {
|
switch (data) {
|
||||||
case Heating: {
|
case Heating: {
|
||||||
thing->setStateValue(elwaStatusStateTypeId, "Heating");
|
thing->setStateValue(elwaStatusStateTypeId, "Heating");
|
||||||
|
|||||||
@ -33,7 +33,8 @@
|
|||||||
|
|
||||||
#include "integrations/integrationplugin.h"
|
#include "integrations/integrationplugin.h"
|
||||||
#include "plugintimer.h"
|
#include "plugintimer.h"
|
||||||
#include "modbustcpmaster.h"
|
|
||||||
|
#include "../modbus/modbustcpmaster.h"
|
||||||
|
|
||||||
#include <QUdpSocket>
|
#include <QUdpSocket>
|
||||||
|
|
||||||
@ -84,6 +85,16 @@ private:
|
|||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void onRefreshTimer();
|
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
|
#endif // INTEGRATIONPLUGINMYPV_H
|
||||||
|
|||||||
@ -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 <https://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
* For any further details and any questions please contact us under
|
|
||||||
* contact@nymea.io or see our FAQ/Licensing Information on
|
|
||||||
* https://nymea.io/license/faq
|
|
||||||
*
|
|
||||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
|
||||||
|
|
||||||
#include "modbustcpmaster.h"
|
|
||||||
#include "extern-plugininfo.h"
|
|
||||||
#include <QLoggingCategory>
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
@ -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 <https://www.gnu.org/licenses/>.
|
|
||||||
*
|
|
||||||
* For any further details and any questions please contact us under
|
|
||||||
* contact@nymea.io or see our FAQ/Licensing Information on
|
|
||||||
* https://nymea.io/license/faq
|
|
||||||
*
|
|
||||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
|
||||||
|
|
||||||
#ifndef MODBUSTCPMASTER_H
|
|
||||||
#define MODBUSTCPMASTER_H
|
|
||||||
|
|
||||||
#include <QObject>
|
|
||||||
#include <QHostAddress>
|
|
||||||
#include <modbus/modbus.h>
|
|
||||||
|
|
||||||
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
|
|
||||||
@ -6,10 +6,9 @@ QT += \
|
|||||||
|
|
||||||
SOURCES += \
|
SOURCES += \
|
||||||
integrationpluginmypv.cpp \
|
integrationpluginmypv.cpp \
|
||||||
modbustcpmaster.cpp \
|
../modbus/modbustcpmaster.cpp \
|
||||||
|
|
||||||
HEADERS += \
|
HEADERS += \
|
||||||
integrationpluginmypv.h \
|
integrationpluginmypv.h \
|
||||||
modbustcpmaster.h \
|
../modbus/modbustcpmaster.h \
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@ -52,15 +52,24 @@ void IntegrationPluginWallbe::setupThing(ThingSetupInfo *info)
|
|||||||
QHostAddress address(thing->paramValue(wallbeEcoThingIpParamTypeId).toString());
|
QHostAddress address(thing->paramValue(wallbeEcoThingIpParamTypeId).toString());
|
||||||
|
|
||||||
if (address.isNull()){
|
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"));
|
info->finish(Thing::ThingErrorSetupFailed, tr("IP address parameter not valid"));
|
||||||
return;
|
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, modbusTcpMaster);
|
||||||
m_connections.insert(thing, wallbe);
|
connect(modbusTcpMaster, &ModbusTCPMaster::connectionStateChanged, info, [this, modbusTcpMaster](bool connected) {
|
||||||
|
if(connected) {
|
||||||
info->finish(Thing::ThingErrorNoError);
|
info->finish(Thing::ThingErrorNoError);
|
||||||
|
} else {
|
||||||
|
info->finish(Thing::ThingErrorHardwareNotAvailable);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -85,12 +94,11 @@ void IntegrationPluginWallbe::discoverThings(ThingDiscoveryInfo *info)
|
|||||||
}
|
}
|
||||||
info->finish(Thing::ThingErrorNoError);
|
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)
|
void IntegrationPluginWallbe::postSetupThing(Thing *thing)
|
||||||
{
|
{
|
||||||
if (!m_pluginTimer) {
|
if (!m_pluginTimer) {
|
||||||
@ -115,9 +123,9 @@ void IntegrationPluginWallbe::executeAction(ThingActionInfo *info)
|
|||||||
Thing *thing = info->thing();
|
Thing *thing = info->thing();
|
||||||
Action action = info->action();
|
Action action = info->action();
|
||||||
|
|
||||||
WallBe *wallbe = m_connections.value(thing);
|
ModbusTCPMaster *modbusTcpMaster = m_connections.value(thing);
|
||||||
if (!wallbe) {
|
if (!modbusTcpMaster) {
|
||||||
qCWarning(dcWallbe()) << "Wallbe object not available";
|
qCWarning(dcWallbe()) << "Modbus connection not available";
|
||||||
info->finish(Thing::ThingErrorHardwareFailure);
|
info->finish(Thing::ThingErrorHardwareFailure);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -130,34 +138,37 @@ void IntegrationPluginWallbe::executeAction(ThingActionInfo *info)
|
|||||||
// get the param value of the charging action
|
// get the param value of the charging action
|
||||||
bool charging = action.param(wallbeEcoPowerActionPowerParamTypeId).value().toBool();
|
bool charging = action.param(wallbeEcoPowerActionPowerParamTypeId).value().toBool();
|
||||||
qCDebug(dcWallbe) << "start Charging button" << thing->name() << "set power to" << charging;
|
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
|
// Set the "power" state
|
||||||
thing->setStateValue(wallbeEcoPowerStateTypeId, charging);
|
thing->setStateValue(wallbeEcoPowerStateTypeId, charging);
|
||||||
info->finish(Thing::ThingErrorNoError);
|
m_asyncActions.insert(requestId, info);
|
||||||
return;
|
connect(info, &ThingActionInfo::aborted, this, [this, requestId] {m_asyncActions.remove(requestId);});
|
||||||
|
|
||||||
} else if(action.actionTypeId() == wallbeEcoChargeCurrentActionTypeId){
|
} else if(action.actionTypeId() == wallbeEcoChargeCurrentActionTypeId){
|
||||||
|
|
||||||
uint16_t current = action.param(wallbeEcoChargeCurrentEventChargeCurrentParamTypeId).value().toUInt();
|
uint16_t current = action.param(wallbeEcoChargeCurrentEventChargeCurrentParamTypeId).value().toUInt();
|
||||||
qCDebug(dcWallbe) << "Charging power set to" << current;
|
qCDebug(dcWallbe) << "Charging power set to" << current;
|
||||||
wallbe->setChargingCurrent(current);
|
QUuid requestId = modbusTcpMaster->writeCoil(0xff, WallbeRegisterAddress::ChargingCurrent, current);
|
||||||
thing->setStateValue(wallbeEcoChargeCurrentStateTypeId, current);
|
thing->setStateValue(wallbeEcoChargeCurrentStateTypeId, current);
|
||||||
info->finish(Thing::ThingErrorNoError);
|
m_asyncActions.insert(requestId, info);
|
||||||
return;
|
connect(info, &ThingActionInfo::aborted, this, [this, requestId] {m_asyncActions.remove(requestId);});
|
||||||
}
|
|
||||||
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());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
} 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)
|
void IntegrationPluginWallbe::thingRemoved(Thing *thing)
|
||||||
{
|
{
|
||||||
m_address.removeOne(QHostAddress(thing->paramValue(wallbeEcoThingIpParamTypeId).toString()));
|
if (thing->thingClassId() == wallbeEcoThingClassId) {
|
||||||
WallBe *wallbe = m_connections.take(thing);
|
if (m_connections.contains(thing)) {
|
||||||
if (wallbe) {
|
ModbusTCPMaster *modbusTcpMaster = m_connections.take(thing);
|
||||||
qCDebug(dcWallbe) << "Remove device" << thing->name();
|
qCDebug(dcWallbe) << "Remove device" << thing->name();
|
||||||
wallbe->deleteLater();
|
modbusTcpMaster->deleteLater();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (myThings().isEmpty()) {
|
if (myThings().isEmpty()) {
|
||||||
@ -168,42 +179,90 @@ void IntegrationPluginWallbe::thingRemoved(Thing *thing)
|
|||||||
|
|
||||||
void IntegrationPluginWallbe::update(Thing *thing)
|
void IntegrationPluginWallbe::update(Thing *thing)
|
||||||
{
|
{
|
||||||
WallBe * wallbe = m_connections.value(thing);
|
ModbusTCPMaster *modbusTCPMaster = m_connections.value(thing);
|
||||||
if(!wallbe->isAvailable())
|
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<ModbusTCPMaster *>(sender());
|
||||||
|
Thing *thing = m_connections.key(modbusTCPMaster);
|
||||||
|
if (!thing)
|
||||||
|
return;
|
||||||
|
thing->setStateValue(wallbeEcoConnectedStateTypeId, status);
|
||||||
|
}
|
||||||
|
|
||||||
|
void IntegrationPluginWallbe::onReceivedHoldingRegister(int slaveAddress, int modbusRegister, const QVector<quint16> &value)
|
||||||
|
{
|
||||||
|
Q_UNUSED(slaveAddress)
|
||||||
|
ModbusTCPMaster *modbusTCPMaster = static_cast<ModbusTCPMaster *>(sender());
|
||||||
|
Thing *thing = m_connections.key(modbusTCPMaster);
|
||||||
|
if (!thing)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
thing->setStateValue(wallbeEcoConnectedStateTypeId, true);
|
switch (WallbeRegisterAddress(modbusRegister)) {
|
||||||
|
case WallbeRegisterAddress::EVStatus:
|
||||||
//EV state - 16 bit ASCII (8bit)
|
//EV state - 16 bit ASCII (8bit)
|
||||||
switch (wallbe->getEvStatus()) {
|
switch (value[0]) {
|
||||||
case 65:
|
case 65:
|
||||||
thing->setStateValue(wallbeEcoEvStatusStateTypeId, "A - No car plugged in");
|
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;
|
break;
|
||||||
case 66:
|
case WallbeRegisterAddress::ChargingStatus:
|
||||||
thing->setStateValue(wallbeEcoEvStatusStateTypeId, "B - Supply equipment not yet ready");
|
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;
|
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();
|
|
||||||
|
void IntegrationPluginWallbe::onWriteRequestExecuted(const QUuid &requestId, bool success)
|
||||||
// Extract Input Register 102 - load time - 32bit integer
|
{
|
||||||
thing->setStateValue(wallbeEcoChargeTimeStateTypeId, wallbe->getChargingTime());
|
if (m_asyncActions.contains(requestId)) {
|
||||||
|
ThingActionInfo *info = m_asyncActions.value(requestId);
|
||||||
// Read the charge current state
|
if (success) {
|
||||||
thing->setStateValue(wallbeEcoChargeCurrentStateTypeId, wallbe->getChargingCurrent());
|
info->finish(Thing::ThingErrorNoError);
|
||||||
thing->setStateValue(wallbeEcoPowerStateTypeId, wallbe->getChargingStatus());
|
} 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;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -32,10 +32,11 @@
|
|||||||
#define INTEGRATIONPLUGINWALLBE_H
|
#define INTEGRATIONPLUGINWALLBE_H
|
||||||
|
|
||||||
#include "integrations/integrationplugin.h"
|
#include "integrations/integrationplugin.h"
|
||||||
#include "wallbe.h"
|
#include "plugintimer.h"
|
||||||
|
|
||||||
#include "host.h"
|
#include "host.h"
|
||||||
#include "discover.h"
|
#include "discover.h"
|
||||||
#include "plugintimer.h"
|
#include "../modbus/modbustcpmaster.h"
|
||||||
|
|
||||||
#include <QObject>
|
#include <QObject>
|
||||||
#include <QHostAddress>
|
#include <QHostAddress>
|
||||||
@ -48,6 +49,14 @@ class IntegrationPluginWallbe : public IntegrationPlugin
|
|||||||
Q_INTERFACES(IntegrationPlugin)
|
Q_INTERFACES(IntegrationPlugin)
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
enum WallbeRegisterAddress {
|
||||||
|
EVStatus = 100,
|
||||||
|
ChargingTime = 102,
|
||||||
|
ErrorCode = 107,
|
||||||
|
ChargingCurrent = 300,
|
||||||
|
ChargingStatus = 400,
|
||||||
|
};
|
||||||
|
|
||||||
explicit IntegrationPluginWallbe();
|
explicit IntegrationPluginWallbe();
|
||||||
|
|
||||||
void discoverThings(ThingDiscoveryInfo *info) override;
|
void discoverThings(ThingDiscoveryInfo *info) override;
|
||||||
@ -57,11 +66,23 @@ public:
|
|||||||
void thingRemoved(Thing *thing) override;
|
void thingRemoved(Thing *thing) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QHash<Thing *, WallBe *> m_connections;
|
QHash<Thing *, ModbusTCPMaster *> m_connections;
|
||||||
QList<QHostAddress> m_address;
|
|
||||||
PluginTimer *m_pluginTimer = nullptr;
|
PluginTimer *m_pluginTimer = nullptr;
|
||||||
|
QHash<QUuid, ThingActionInfo *> m_asyncActions;
|
||||||
|
|
||||||
void update(Thing *thing);
|
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<quint16> &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
|
#endif // INTEGRATIONPLUGINWALLBE_H
|
||||||
|
|||||||
@ -171,7 +171,7 @@ int WallBe::getChargingTime()
|
|||||||
if(modbus_read_registers(m_device, 102, 2, reg) == -1)
|
if(modbus_read_registers(m_device, 102, 2, reg) == -1)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return (((uint32_t)(reg[2]<<16)|(uint32_t)(reg[3]))/60); //Converts to minutes
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
void WallBe::setChargingCurrent(int current)
|
void WallBe::setChargingCurrent(int current)
|
||||||
|
|||||||
@ -35,14 +35,15 @@
|
|||||||
#include <QHostAddress>
|
#include <QHostAddress>
|
||||||
#include <QProcess>
|
#include <QProcess>
|
||||||
|
|
||||||
#include <modbus/modbus.h>
|
#include "../modbus/modbustcpmaster.h"
|
||||||
|
|
||||||
class WallBe : public QObject
|
class WallBe : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
|
|
||||||
WallBe(QHostAddress address, int port, QObject *parent = nullptr);
|
|
||||||
|
WallBe(const QHostAddress &address, int port, QObject *parent = nullptr);
|
||||||
~WallBe();
|
~WallBe();
|
||||||
bool isAvailable();
|
bool isAvailable();
|
||||||
bool connect();
|
bool connect();
|
||||||
|
|||||||
@ -6,12 +6,12 @@ QT += \
|
|||||||
|
|
||||||
SOURCES += \
|
SOURCES += \
|
||||||
integrationpluginwallbe.cpp \
|
integrationpluginwallbe.cpp \
|
||||||
wallbe.cpp \
|
../modbus/modbustcpmaster.cpp \
|
||||||
host.cpp \
|
host.cpp \
|
||||||
discover.cpp
|
discover.cpp
|
||||||
|
|
||||||
HEADERS += \
|
HEADERS += \
|
||||||
integrationpluginwallbe.h \
|
integrationpluginwallbe.h \
|
||||||
wallbe.h \
|
../modbus/modbustcpmaster.h \
|
||||||
host.h \
|
host.h \
|
||||||
discover.h
|
discover.h
|
||||||
|
|||||||
Reference in New Issue
Block a user