Wallbe changed to QModbus
This commit is contained in:
parent
5ffe45baff
commit
78c30f54da
@ -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 \
|
||||
|
||||
@ -34,8 +34,9 @@
|
||||
#include "integrations/integrationplugin.h"
|
||||
#include "plugintimer.h"
|
||||
|
||||
#include <QDateTime>
|
||||
#include "modbusrtumaster.h"
|
||||
|
||||
#include <QDateTime>
|
||||
#include <QSerialPortInfo>
|
||||
|
||||
class IntegrationPluginDrexelUndWeiss : public IntegrationPlugin
|
||||
|
||||
@ -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 \
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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 <QSerialPortInfo>
|
||||
#include <QUuid>
|
||||
|
||||
@ -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 \
|
||||
|
||||
|
||||
@ -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()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -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");
|
||||
|
||||
@ -33,7 +33,8 @@
|
||||
|
||||
#include "integrations/integrationplugin.h"
|
||||
#include "plugintimer.h"
|
||||
#include "modbustcpmaster.h"
|
||||
|
||||
#include "../modbus/modbustcpmaster.h"
|
||||
|
||||
#include <QUdpSocket>
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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 += \
|
||||
integrationpluginmypv.cpp \
|
||||
modbustcpmaster.cpp \
|
||||
../modbus/modbustcpmaster.cpp \
|
||||
|
||||
HEADERS += \
|
||||
integrationpluginmypv.h \
|
||||
modbustcpmaster.h \
|
||||
|
||||
../modbus/modbustcpmaster.h \
|
||||
|
||||
|
||||
@ -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<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;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@ -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 <QObject>
|
||||
#include <QHostAddress>
|
||||
@ -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<Thing *, WallBe *> m_connections;
|
||||
QList<QHostAddress> m_address;
|
||||
QHash<Thing *, ModbusTCPMaster *> m_connections;
|
||||
PluginTimer *m_pluginTimer = nullptr;
|
||||
QHash<QUuid, ThingActionInfo *> 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<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
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -35,14 +35,15 @@
|
||||
#include <QHostAddress>
|
||||
#include <QProcess>
|
||||
|
||||
#include <modbus/modbus.h>
|
||||
#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();
|
||||
|
||||
@ -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
|
||||
|
||||
Reference in New Issue
Block a user