Merge PR #52: New plugin: Stiebel Eltron heatpumps
This commit is contained in:
commit
866f65046d
1
.gitignore
vendored
1
.gitignore
vendored
@ -2,3 +2,4 @@
|
||||
builddir
|
||||
doc/html
|
||||
*.qm
|
||||
__pycache__
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,273 +0,0 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2021, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This fileDescriptor 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 ALPHACONNECTMODBUSTCPCONNECTION_H
|
||||
#define ALPHACONNECTMODBUSTCPCONNECTION_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include "../modbus/modbusdatautils.h"
|
||||
#include "../modbus/modbustcpmaster.h"
|
||||
|
||||
class AlphaConnectModbusTcpConnection : public ModbusTCPMaster
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum SystemStatus {
|
||||
SystemStatusHeatingMode = 0,
|
||||
SystemStatusDomesticHotWater = 1,
|
||||
SystemStatusSwimmingPool = 2,
|
||||
SystemStatusEVUOff = 3,
|
||||
SystemStatusDefrost = 4,
|
||||
SystemStatusOff = 5,
|
||||
SystemStatusExternalEnergySource = 6,
|
||||
SystemStatusCoolingMode = 7
|
||||
};
|
||||
Q_ENUM(SystemStatus)
|
||||
|
||||
enum SmartGridState {
|
||||
SmartGridStateOff = 0,
|
||||
SmartGridStateLow = 1,
|
||||
SmartGridStateStandard = 2,
|
||||
SmartGridStateHigh = 3
|
||||
};
|
||||
Q_ENUM(SmartGridState)
|
||||
|
||||
explicit AlphaConnectModbusTcpConnection(const QHostAddress &hostAddress, uint port, quint16 slaveId, QObject *parent = nullptr);
|
||||
~AlphaConnectModbusTcpConnection() = default;
|
||||
|
||||
/* Flow [°C] - Address: 1, Size: 1 */
|
||||
float flowTemperature() const;
|
||||
|
||||
/* Return [°C] - Address: 2, Size: 1 */
|
||||
float returnTemperature() const;
|
||||
|
||||
/* External return [°C] - Address: 3, Size: 1 */
|
||||
float externalReturnTemperature() const;
|
||||
|
||||
/* Hot water temperature [°C] - Address: 4, Size: 1 */
|
||||
float hotWaterTemperature() const;
|
||||
|
||||
/* Hot gas temperature [°C] - Address: 8, Size: 1 */
|
||||
float hotGasTemperature() const;
|
||||
|
||||
/* Heat source inlet temperature [°C] - Address: 9, Size: 1 */
|
||||
float heatSourceInletTemperature() const;
|
||||
|
||||
/* Heat source outlet temperature [°C] - Address: 10, Size: 1 */
|
||||
float heatSourceOutletTemperature() const;
|
||||
|
||||
/* Room remote adjuster 1 temperature [°C] - Address: 11, Size: 1 */
|
||||
float roomTemperature1() const;
|
||||
|
||||
/* Room remote adjuster 2 temperature [°C] - Address: 12, Size: 1 */
|
||||
float roomTemperature2() const;
|
||||
|
||||
/* Room remote adjuster 3 temperature [°C] - Address: 13, Size: 1 */
|
||||
float roomTemperature3() const;
|
||||
|
||||
/* Solar collector temperature [°C] - Address: 14, Size: 1 */
|
||||
float solarCollectorTemperature() const;
|
||||
|
||||
/* Solar storage tank temperature [°C] - Address: 15, Size: 1 */
|
||||
float solarStorageTankTemperature() const;
|
||||
|
||||
/* External energy source temperature [°C] - Address: 16, Size: 1 */
|
||||
float externalEnergySourceTemperature() const;
|
||||
|
||||
/* Supply air temperature [°C] - Address: 17, Size: 1 */
|
||||
float supplyAirTemperature() const;
|
||||
|
||||
/* External air temperature [°C] - Address: 18, Size: 1 */
|
||||
float externalAirTemperature() const;
|
||||
|
||||
/* RBE actual room temperature [°C] - Address: 24, Size: 1 */
|
||||
float rbeRoomActualTemperature() const;
|
||||
|
||||
/* RBE room temperature setpoint [°C] - Address: 24, Size: 1 */
|
||||
float rbeRoomSetpointTemperature() const;
|
||||
|
||||
/* Heating pump operating hours [h] - Address: 33, Size: 1 */
|
||||
quint16 heatingPumpOperatingHours() const;
|
||||
|
||||
/* System status - Address: 37, Size: 1 */
|
||||
SystemStatus systemStatus() const;
|
||||
|
||||
/* Heating energy [kWh] - Address: 38, Size: 2 */
|
||||
float heatingEnergy() const;
|
||||
|
||||
/* Water heat energy [kWh] - Address: 40, Size: 2 */
|
||||
float waterHeatEnergy() const;
|
||||
|
||||
/* Total energy [kWh] - Address: 44, Size: 2 */
|
||||
float totalHeatEnergy() const;
|
||||
|
||||
/* Outdoor temperature [°C] - Address: 0, Size: 1 */
|
||||
float outdoorTemperature() const;
|
||||
QModbusReply *setOutdoorTemperature(float outdoorTemperature);
|
||||
|
||||
/* Return setpoint temperature [°C] - Address: 1, Size: 1 */
|
||||
float returnSetpointTemperature() const;
|
||||
QModbusReply *setReturnSetpointTemperature(float returnSetpointTemperature);
|
||||
|
||||
/* Hot water setpoint temperature [°C] - Address: 5, Size: 1 */
|
||||
float hotWaterSetpointTemperature() const;
|
||||
QModbusReply *setHotWaterSetpointTemperature(float hotWaterSetpointTemperature);
|
||||
|
||||
/* Smart grid control - Address: 14, Size: 1 */
|
||||
SmartGridState smartGrid() const;
|
||||
QModbusReply *setSmartGrid(SmartGridState smartGrid);
|
||||
|
||||
virtual void initialize();
|
||||
virtual void update();
|
||||
|
||||
void updateFlowTemperature();
|
||||
void updateReturnTemperature();
|
||||
void updateExternalReturnTemperature();
|
||||
void updateHotWaterTemperature();
|
||||
void updateHotGasTemperature();
|
||||
void updateHeatSourceInletTemperature();
|
||||
void updateHeatSourceOutletTemperature();
|
||||
void updateRoomTemperature1();
|
||||
void updateRoomTemperature2();
|
||||
void updateRoomTemperature3();
|
||||
void updateSolarCollectorTemperature();
|
||||
void updateSolarStorageTankTemperature();
|
||||
void updateExternalEnergySourceTemperature();
|
||||
void updateSupplyAirTemperature();
|
||||
void updateExternalAirTemperature();
|
||||
void updateRbeRoomActualTemperature();
|
||||
void updateRbeRoomSetpointTemperature();
|
||||
void updateHeatingPumpOperatingHours();
|
||||
void updateSystemStatus();
|
||||
void updateHeatingEnergy();
|
||||
void updateWaterHeatEnergy();
|
||||
void updateTotalHeatEnergy();
|
||||
void updateOutdoorTemperature();
|
||||
void updateReturnSetpointTemperature();
|
||||
void updateHotWaterSetpointTemperature();
|
||||
void updateSmartGrid();
|
||||
|
||||
signals:
|
||||
void initializationFinished();
|
||||
|
||||
void flowTemperatureChanged(float flowTemperature);
|
||||
void returnTemperatureChanged(float returnTemperature);
|
||||
void externalReturnTemperatureChanged(float externalReturnTemperature);
|
||||
void hotWaterTemperatureChanged(float hotWaterTemperature);
|
||||
void hotGasTemperatureChanged(float hotGasTemperature);
|
||||
void heatSourceInletTemperatureChanged(float heatSourceInletTemperature);
|
||||
void heatSourceOutletTemperatureChanged(float heatSourceOutletTemperature);
|
||||
void roomTemperature1Changed(float roomTemperature1);
|
||||
void roomTemperature2Changed(float roomTemperature2);
|
||||
void roomTemperature3Changed(float roomTemperature3);
|
||||
void solarCollectorTemperatureChanged(float solarCollectorTemperature);
|
||||
void solarStorageTankTemperatureChanged(float solarStorageTankTemperature);
|
||||
void externalEnergySourceTemperatureChanged(float externalEnergySourceTemperature);
|
||||
void supplyAirTemperatureChanged(float supplyAirTemperature);
|
||||
void externalAirTemperatureChanged(float externalAirTemperature);
|
||||
void rbeRoomActualTemperatureChanged(float rbeRoomActualTemperature);
|
||||
void rbeRoomSetpointTemperatureChanged(float rbeRoomSetpointTemperature);
|
||||
void heatingPumpOperatingHoursChanged(quint16 heatingPumpOperatingHours);
|
||||
void systemStatusChanged(SystemStatus systemStatus);
|
||||
void heatingEnergyChanged(float heatingEnergy);
|
||||
void waterHeatEnergyChanged(float waterHeatEnergy);
|
||||
void totalHeatEnergyChanged(float totalHeatEnergy);
|
||||
void outdoorTemperatureChanged(float outdoorTemperature);
|
||||
void returnSetpointTemperatureChanged(float returnSetpointTemperature);
|
||||
void hotWaterSetpointTemperatureChanged(float hotWaterSetpointTemperature);
|
||||
void smartGridChanged(SmartGridState smartGrid);
|
||||
|
||||
private:
|
||||
quint16 m_slaveId = 1;
|
||||
QVector<QModbusReply *> m_pendingInitReplies;
|
||||
|
||||
float m_flowTemperature = 0;
|
||||
float m_returnTemperature = 0;
|
||||
float m_externalReturnTemperature = 0;
|
||||
float m_hotWaterTemperature = 0;
|
||||
float m_hotGasTemperature = 0;
|
||||
float m_heatSourceInletTemperature = 0;
|
||||
float m_heatSourceOutletTemperature = 0;
|
||||
float m_roomTemperature1 = 0;
|
||||
float m_roomTemperature2 = 0;
|
||||
float m_roomTemperature3 = 0;
|
||||
float m_solarCollectorTemperature = 0;
|
||||
float m_solarStorageTankTemperature = 0;
|
||||
float m_externalEnergySourceTemperature = 0;
|
||||
float m_supplyAirTemperature = 0;
|
||||
float m_externalAirTemperature = 0;
|
||||
float m_rbeRoomActualTemperature = 0;
|
||||
float m_rbeRoomSetpointTemperature = 0;
|
||||
quint16 m_heatingPumpOperatingHours = 0;
|
||||
SystemStatus m_systemStatus = SystemStatusHeatingMode;
|
||||
float m_heatingEnergy = 0;
|
||||
float m_waterHeatEnergy = 0;
|
||||
float m_totalHeatEnergy = 0;
|
||||
float m_outdoorTemperature = 0;
|
||||
float m_returnSetpointTemperature = 0;
|
||||
float m_hotWaterSetpointTemperature = 0;
|
||||
SmartGridState m_smartGrid = SmartGridStateStandard;
|
||||
|
||||
void verifyInitFinished();
|
||||
|
||||
QModbusReply *readFlowTemperature();
|
||||
QModbusReply *readReturnTemperature();
|
||||
QModbusReply *readExternalReturnTemperature();
|
||||
QModbusReply *readHotWaterTemperature();
|
||||
QModbusReply *readHotGasTemperature();
|
||||
QModbusReply *readHeatSourceInletTemperature();
|
||||
QModbusReply *readHeatSourceOutletTemperature();
|
||||
QModbusReply *readRoomTemperature1();
|
||||
QModbusReply *readRoomTemperature2();
|
||||
QModbusReply *readRoomTemperature3();
|
||||
QModbusReply *readSolarCollectorTemperature();
|
||||
QModbusReply *readSolarStorageTankTemperature();
|
||||
QModbusReply *readExternalEnergySourceTemperature();
|
||||
QModbusReply *readSupplyAirTemperature();
|
||||
QModbusReply *readExternalAirTemperature();
|
||||
QModbusReply *readRbeRoomActualTemperature();
|
||||
QModbusReply *readRbeRoomSetpointTemperature();
|
||||
QModbusReply *readHeatingPumpOperatingHours();
|
||||
QModbusReply *readSystemStatus();
|
||||
QModbusReply *readHeatingEnergy();
|
||||
QModbusReply *readWaterHeatEnergy();
|
||||
QModbusReply *readTotalHeatEnergy();
|
||||
QModbusReply *readOutdoorTemperature();
|
||||
QModbusReply *readReturnSetpointTemperature();
|
||||
QModbusReply *readHotWaterSetpointTemperature();
|
||||
QModbusReply *readSmartGrid();
|
||||
|
||||
|
||||
};
|
||||
|
||||
QDebug operator<<(QDebug debug, AlphaConnectModbusTcpConnection *alphaConnectModbusTcpConnection);
|
||||
|
||||
#endif // ALPHACONNECTMODBUSTCPCONNECTION_H
|
||||
@ -1,4 +1,6 @@
|
||||
{
|
||||
"className": "AlphaInnotec",
|
||||
"protocol": "TCP",
|
||||
"endianness": "BigEndian",
|
||||
"enums": [
|
||||
{
|
||||
@ -397,5 +399,6 @@
|
||||
"defaultValue": "SmartGridStateStandard",
|
||||
"access": "RW"
|
||||
}
|
||||
]
|
||||
],
|
||||
"blocks": [ ]
|
||||
}
|
||||
|
||||
@ -1,15 +1,12 @@
|
||||
include(../plugins.pri)
|
||||
|
||||
QT += network serialbus
|
||||
# Generate modbus connection
|
||||
MODBUS_CONNECTIONS += alphainnotec-registers.json
|
||||
#MODBUS_TOOLS_CONFIG += VERBOSE
|
||||
include(../modbus.pri)
|
||||
|
||||
SOURCES += \
|
||||
integrationpluginalphainnotec.cpp \
|
||||
alphaconnectmodbustcpconnection.cpp \
|
||||
../modbus/modbustcpmaster.cpp \
|
||||
../modbus/modbusdatautils.cpp
|
||||
integrationpluginalphainnotec.cpp
|
||||
|
||||
HEADERS += \
|
||||
integrationpluginalphainnotec.h \
|
||||
alphaconnectmodbustcpconnection.h \
|
||||
../modbus/modbustcpmaster.h \
|
||||
../modbus/modbusdatautils.h
|
||||
integrationpluginalphainnotec.h
|
||||
|
||||
@ -29,11 +29,11 @@
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#include "integrationpluginalphainnotec.h"
|
||||
|
||||
#include "network/networkdevicediscovery.h"
|
||||
#include "hardwaremanager.h"
|
||||
#include "plugininfo.h"
|
||||
|
||||
#include <network/networkdevicediscovery.h>
|
||||
#include <hardwaremanager.h>
|
||||
|
||||
IntegrationPluginAlphaInnotec::IntegrationPluginAlphaInnotec()
|
||||
{
|
||||
|
||||
@ -107,8 +107,8 @@ void IntegrationPluginAlphaInnotec::setupThing(ThingSetupInfo *info)
|
||||
uint port = thing->paramValue(alphaConnectThingPortParamTypeId).toUInt();
|
||||
quint16 slaveId = thing->paramValue(alphaConnectThingSlaveIdParamTypeId).toUInt();
|
||||
|
||||
AlphaConnectModbusTcpConnection *alphaConnectTcpConnection = new AlphaConnectModbusTcpConnection(hostAddress, port, slaveId, this);
|
||||
connect(alphaConnectTcpConnection, &AlphaConnectModbusTcpConnection::connectionStateChanged, this, [thing, alphaConnectTcpConnection](bool status){
|
||||
AlphaInnotecModbusTcpConnection *alphaConnectTcpConnection = new AlphaInnotecModbusTcpConnection(hostAddress, port, slaveId, this);
|
||||
connect(alphaConnectTcpConnection, &AlphaInnotecModbusTcpConnection::connectionStateChanged, this, [thing, alphaConnectTcpConnection](bool status){
|
||||
qCDebug(dcAlphaInnotec()) << "Connected changed to" << status << "for" << thing;
|
||||
if (status) {
|
||||
alphaConnectTcpConnection->update();
|
||||
@ -119,181 +119,181 @@ void IntegrationPluginAlphaInnotec::setupThing(ThingSetupInfo *info)
|
||||
|
||||
|
||||
// Input registers
|
||||
// connect(alphaConnectTcpConnection, &AlphaConnectModbusTcpConnection::meanTemperatureChanged, this, [thing](float meanTemperature){
|
||||
// connect(alphaConnectTcpConnection, &AlphaInnotecModbusTcpConnection::meanTemperatureChanged, this, [thing](float meanTemperature){
|
||||
// qCDebug(dcAlphaInnotec()) << thing << "mean temperature changed" << meanTemperature << "°C";
|
||||
// thing->setStateValue(alphaConnectMeanTemperatureStateTypeId, meanTemperature);
|
||||
// });
|
||||
|
||||
connect(alphaConnectTcpConnection, &AlphaConnectModbusTcpConnection::flowTemperatureChanged, this, [thing](float flowTemperature){
|
||||
connect(alphaConnectTcpConnection, &AlphaInnotecModbusTcpConnection::flowTemperatureChanged, this, [thing](float flowTemperature){
|
||||
qCDebug(dcAlphaInnotec()) << thing << "flow temperature changed" << flowTemperature << "°C";
|
||||
thing->setStateValue(alphaConnectFlowTemperatureStateTypeId, flowTemperature);
|
||||
});
|
||||
|
||||
connect(alphaConnectTcpConnection, &AlphaConnectModbusTcpConnection::returnTemperatureChanged, this, [thing](float returnTemperature){
|
||||
connect(alphaConnectTcpConnection, &AlphaInnotecModbusTcpConnection::returnTemperatureChanged, this, [thing](float returnTemperature){
|
||||
qCDebug(dcAlphaInnotec()) << thing << "return temperature changed" << returnTemperature << "°C";
|
||||
thing->setStateValue(alphaConnectReturnTemperatureStateTypeId, returnTemperature);
|
||||
});
|
||||
|
||||
connect(alphaConnectTcpConnection, &AlphaConnectModbusTcpConnection::externalReturnTemperatureChanged, this, [thing](float externalReturnTemperature){
|
||||
connect(alphaConnectTcpConnection, &AlphaInnotecModbusTcpConnection::externalReturnTemperatureChanged, this, [thing](float externalReturnTemperature){
|
||||
qCDebug(dcAlphaInnotec()) << thing << "external return temperature changed" << externalReturnTemperature << "°C";
|
||||
thing->setStateValue(alphaConnectExternalReturnTemperatureStateTypeId, externalReturnTemperature);
|
||||
});
|
||||
|
||||
connect(alphaConnectTcpConnection, &AlphaConnectModbusTcpConnection::hotWaterTemperatureChanged, this, [thing](float hotWaterTemperature){
|
||||
connect(alphaConnectTcpConnection, &AlphaInnotecModbusTcpConnection::hotWaterTemperatureChanged, this, [thing](float hotWaterTemperature){
|
||||
qCDebug(dcAlphaInnotec()) << thing << "hot water temperature changed" << hotWaterTemperature << "°C";
|
||||
thing->setStateValue(alphaConnectHotWaterTemperatureStateTypeId, hotWaterTemperature);
|
||||
});
|
||||
|
||||
connect(alphaConnectTcpConnection, &AlphaConnectModbusTcpConnection::hotGasTemperatureChanged, this, [thing](float hotGasTemperature){
|
||||
connect(alphaConnectTcpConnection, &AlphaInnotecModbusTcpConnection::hotGasTemperatureChanged, this, [thing](float hotGasTemperature){
|
||||
qCDebug(dcAlphaInnotec()) << thing << "hot gas temperature changed" << hotGasTemperature << "°C";
|
||||
thing->setStateValue(alphaConnectHotGasTemperatureStateTypeId, hotGasTemperature);
|
||||
});
|
||||
|
||||
connect(alphaConnectTcpConnection, &AlphaConnectModbusTcpConnection::heatSourceInletTemperatureChanged, this, [thing](float heatSourceInletTemperature){
|
||||
connect(alphaConnectTcpConnection, &AlphaInnotecModbusTcpConnection::heatSourceInletTemperatureChanged, this, [thing](float heatSourceInletTemperature){
|
||||
qCDebug(dcAlphaInnotec()) << thing << "heat source inlet temperature changed" << heatSourceInletTemperature << "°C";
|
||||
thing->setStateValue(alphaConnectHeatSourceInletTemperatureStateTypeId, heatSourceInletTemperature);
|
||||
});
|
||||
|
||||
connect(alphaConnectTcpConnection, &AlphaConnectModbusTcpConnection::heatSourceOutletTemperatureChanged, this, [thing](float heatSourceOutletTemperature){
|
||||
connect(alphaConnectTcpConnection, &AlphaInnotecModbusTcpConnection::heatSourceOutletTemperatureChanged, this, [thing](float heatSourceOutletTemperature){
|
||||
qCDebug(dcAlphaInnotec()) << thing << "heat source outlet temperature changed" << heatSourceOutletTemperature << "°C";
|
||||
thing->setStateValue(alphaConnectHeatSourceOutletTemperatureStateTypeId, heatSourceOutletTemperature);
|
||||
});
|
||||
|
||||
connect(alphaConnectTcpConnection, &AlphaConnectModbusTcpConnection::roomTemperature1Changed, this, [thing](float roomTemperature1){
|
||||
connect(alphaConnectTcpConnection, &AlphaInnotecModbusTcpConnection::roomTemperature1Changed, this, [thing](float roomTemperature1){
|
||||
qCDebug(dcAlphaInnotec()) << thing << "room remote adjuster 1 temperature changed" << roomTemperature1 << "°C";
|
||||
thing->setStateValue(alphaConnectRoomTemperature1StateTypeId, roomTemperature1);
|
||||
});
|
||||
|
||||
connect(alphaConnectTcpConnection, &AlphaConnectModbusTcpConnection::roomTemperature2Changed, this, [thing](float roomTemperature2){
|
||||
connect(alphaConnectTcpConnection, &AlphaInnotecModbusTcpConnection::roomTemperature2Changed, this, [thing](float roomTemperature2){
|
||||
qCDebug(dcAlphaInnotec()) << thing << "room remote adjuster 2 temperature changed" << roomTemperature2 << "°C";
|
||||
thing->setStateValue(alphaConnectRoomTemperature2StateTypeId, roomTemperature2);
|
||||
});
|
||||
|
||||
connect(alphaConnectTcpConnection, &AlphaConnectModbusTcpConnection::roomTemperature3Changed, this, [thing](float roomTemperature3){
|
||||
connect(alphaConnectTcpConnection, &AlphaInnotecModbusTcpConnection::roomTemperature3Changed, this, [thing](float roomTemperature3){
|
||||
qCDebug(dcAlphaInnotec()) << thing << "room remote adjuster 3 temperature changed" << roomTemperature3 << "°C";
|
||||
thing->setStateValue(alphaConnectRoomTemperature2StateTypeId, roomTemperature3);
|
||||
});
|
||||
|
||||
connect(alphaConnectTcpConnection, &AlphaConnectModbusTcpConnection::solarCollectorTemperatureChanged, this, [thing](float solarCollectorTemperature){
|
||||
connect(alphaConnectTcpConnection, &AlphaInnotecModbusTcpConnection::solarCollectorTemperatureChanged, this, [thing](float solarCollectorTemperature){
|
||||
qCDebug(dcAlphaInnotec()) << thing << "solar collector temperature changed" << solarCollectorTemperature << "°C";
|
||||
thing->setStateValue(alphaConnectSolarCollectorTemperatureStateTypeId, solarCollectorTemperature);
|
||||
});
|
||||
|
||||
connect(alphaConnectTcpConnection, &AlphaConnectModbusTcpConnection::solarStorageTankTemperatureChanged, this, [thing](float solarStorageTankTemperature){
|
||||
connect(alphaConnectTcpConnection, &AlphaInnotecModbusTcpConnection::solarStorageTankTemperatureChanged, this, [thing](float solarStorageTankTemperature){
|
||||
qCDebug(dcAlphaInnotec()) << thing << "solar storage tank temperature changed" << solarStorageTankTemperature << "°C";
|
||||
thing->setStateValue(alphaConnectSolarCollectorTemperatureStateTypeId, solarStorageTankTemperature);
|
||||
});
|
||||
|
||||
connect(alphaConnectTcpConnection, &AlphaConnectModbusTcpConnection::externalEnergySourceTemperatureChanged, this, [thing](float externalEnergySourceTemperature){
|
||||
connect(alphaConnectTcpConnection, &AlphaInnotecModbusTcpConnection::externalEnergySourceTemperatureChanged, this, [thing](float externalEnergySourceTemperature){
|
||||
qCDebug(dcAlphaInnotec()) << thing << "external energy source temperature changed" << externalEnergySourceTemperature << "°C";
|
||||
thing->setStateValue(alphaConnectExternalEnergySourceTemperatureStateTypeId, externalEnergySourceTemperature);
|
||||
});
|
||||
|
||||
connect(alphaConnectTcpConnection, &AlphaConnectModbusTcpConnection::supplyAirTemperatureChanged, this, [thing](float supplyAirTemperature){
|
||||
connect(alphaConnectTcpConnection, &AlphaInnotecModbusTcpConnection::supplyAirTemperatureChanged, this, [thing](float supplyAirTemperature){
|
||||
qCDebug(dcAlphaInnotec()) << thing << "supply air temperature changed" << supplyAirTemperature << "°C";
|
||||
thing->setStateValue(alphaConnectSupplyAirTemperatureStateTypeId, supplyAirTemperature);
|
||||
});
|
||||
|
||||
connect(alphaConnectTcpConnection, &AlphaConnectModbusTcpConnection::externalAirTemperatureChanged, this, [thing](float externalAirTemperature){
|
||||
connect(alphaConnectTcpConnection, &AlphaInnotecModbusTcpConnection::externalAirTemperatureChanged, this, [thing](float externalAirTemperature){
|
||||
qCDebug(dcAlphaInnotec()) << thing << "external air temperature changed" << externalAirTemperature << "°C";
|
||||
thing->setStateValue(alphaConnectExternalAirTemperatureStateTypeId, externalAirTemperature);
|
||||
});
|
||||
|
||||
connect(alphaConnectTcpConnection, &AlphaConnectModbusTcpConnection::heatingPumpOperatingHoursChanged, this, [thing](quint16 heatingPumpOperatingHours){
|
||||
connect(alphaConnectTcpConnection, &AlphaInnotecModbusTcpConnection::heatingPumpOperatingHoursChanged, this, [thing](quint16 heatingPumpOperatingHours){
|
||||
qCDebug(dcAlphaInnotec()) << thing << "heating pump operating hours changed" << heatingPumpOperatingHours;
|
||||
thing->setStateValue(alphaConnectHeatingPumpOperatingHoursStateTypeId, heatingPumpOperatingHours);
|
||||
});
|
||||
|
||||
connect(alphaConnectTcpConnection, &AlphaConnectModbusTcpConnection::systemStatusChanged, this, [thing](AlphaConnectModbusTcpConnection::SystemStatus systemStatus){
|
||||
connect(alphaConnectTcpConnection, &AlphaInnotecModbusTcpConnection::systemStatusChanged, this, [thing](AlphaInnotecModbusTcpConnection::SystemStatus systemStatus){
|
||||
qCDebug(dcAlphaInnotec()) << thing << "system status changed" << systemStatus;
|
||||
switch (systemStatus) {
|
||||
case AlphaConnectModbusTcpConnection::SystemStatusHeatingMode:
|
||||
case AlphaInnotecModbusTcpConnection::SystemStatusHeatingMode:
|
||||
thing->setStateValue(alphaConnectSystemStatusStateTypeId, "Heating mode");
|
||||
break;
|
||||
case AlphaConnectModbusTcpConnection::SystemStatusDomesticHotWater:
|
||||
case AlphaInnotecModbusTcpConnection::SystemStatusDomesticHotWater:
|
||||
thing->setStateValue(alphaConnectSystemStatusStateTypeId, "Domestic hot water");
|
||||
break;
|
||||
case AlphaConnectModbusTcpConnection::SystemStatusSwimmingPool:
|
||||
case AlphaInnotecModbusTcpConnection::SystemStatusSwimmingPool:
|
||||
thing->setStateValue(alphaConnectSystemStatusStateTypeId, "Swimming pool");
|
||||
break;
|
||||
case AlphaConnectModbusTcpConnection::SystemStatusEVUOff:
|
||||
case AlphaInnotecModbusTcpConnection::SystemStatusEVUOff:
|
||||
thing->setStateValue(alphaConnectSystemStatusStateTypeId, "EUV off");
|
||||
break;
|
||||
case AlphaConnectModbusTcpConnection::SystemStatusDefrost:
|
||||
case AlphaInnotecModbusTcpConnection::SystemStatusDefrost:
|
||||
thing->setStateValue(alphaConnectSystemStatusStateTypeId, "Defrost");
|
||||
break;
|
||||
case AlphaConnectModbusTcpConnection::SystemStatusOff:
|
||||
case AlphaInnotecModbusTcpConnection::SystemStatusOff:
|
||||
thing->setStateValue(alphaConnectSystemStatusStateTypeId, "Off");
|
||||
break;
|
||||
case AlphaConnectModbusTcpConnection::SystemStatusExternalEnergySource:
|
||||
case AlphaInnotecModbusTcpConnection::SystemStatusExternalEnergySource:
|
||||
thing->setStateValue(alphaConnectSystemStatusStateTypeId, "External energy source");
|
||||
break;
|
||||
case AlphaConnectModbusTcpConnection::SystemStatusCoolingMode:
|
||||
case AlphaInnotecModbusTcpConnection::SystemStatusCoolingMode:
|
||||
thing->setStateValue(alphaConnectSystemStatusStateTypeId, "Cooling mode");
|
||||
break;
|
||||
}
|
||||
|
||||
// Set heating and cooling states according to the system state
|
||||
thing->setStateValue(alphaConnectHeatingOnStateTypeId, systemStatus == AlphaConnectModbusTcpConnection::SystemStatusHeatingMode);
|
||||
thing->setStateValue(alphaConnectCoolingOnStateTypeId, systemStatus == AlphaConnectModbusTcpConnection::SystemStatusCoolingMode);
|
||||
thing->setStateValue(alphaConnectHeatingOnStateTypeId, systemStatus == AlphaInnotecModbusTcpConnection::SystemStatusHeatingMode);
|
||||
thing->setStateValue(alphaConnectCoolingOnStateTypeId, systemStatus == AlphaInnotecModbusTcpConnection::SystemStatusCoolingMode);
|
||||
});
|
||||
|
||||
// Energy
|
||||
connect(alphaConnectTcpConnection, &AlphaConnectModbusTcpConnection::totalHeatEnergyChanged, this, [thing](float totalHeatEnergy){
|
||||
connect(alphaConnectTcpConnection, &AlphaInnotecModbusTcpConnection::totalHeatEnergyChanged, this, [thing](float totalHeatEnergy){
|
||||
qCDebug(dcAlphaInnotec()) << thing << "total heating energy changed" << totalHeatEnergy << "kWh";
|
||||
thing->setStateValue(alphaConnectTotalEnergyStateTypeId, totalHeatEnergy);
|
||||
});
|
||||
|
||||
connect(alphaConnectTcpConnection, &AlphaConnectModbusTcpConnection::heatingEnergyChanged, this, [thing](float heatingEnergy){
|
||||
connect(alphaConnectTcpConnection, &AlphaInnotecModbusTcpConnection::heatingEnergyChanged, this, [thing](float heatingEnergy){
|
||||
qCDebug(dcAlphaInnotec()) << thing << "heating energy changed" << heatingEnergy << "kWh";
|
||||
thing->setStateValue(alphaConnectHeatingEnergyStateTypeId, heatingEnergy);
|
||||
});
|
||||
|
||||
connect(alphaConnectTcpConnection, &AlphaConnectModbusTcpConnection::waterHeatEnergyChanged, this, [thing](float waterHeatEnergy){
|
||||
connect(alphaConnectTcpConnection, &AlphaInnotecModbusTcpConnection::waterHeatEnergyChanged, this, [thing](float waterHeatEnergy){
|
||||
qCDebug(dcAlphaInnotec()) << thing << "water heat energy changed" << waterHeatEnergy << "kWh";
|
||||
thing->setStateValue(alphaConnectHotWaterEnergyStateTypeId, waterHeatEnergy);
|
||||
});
|
||||
|
||||
// connect(alphaConnectTcpConnection, &AlphaConnectModbusTcpConnection::swimmingPoolHeatEnergyChanged, this, [thing](float swimmingPoolHeatEnergy){
|
||||
// connect(alphaConnectTcpConnection, &AlphaInnotecModbusTcpConnection::swimmingPoolHeatEnergyChanged, this, [thing](float swimmingPoolHeatEnergy){
|
||||
// qCDebug(dcAlphaInnotec()) << thing << "swimming pool heat energy changed" << swimmingPoolHeatEnergy << "kWh";
|
||||
// thing->setStateValue(alphaConnectSwimmingPoolEnergyStateTypeId, swimmingPoolHeatEnergy);
|
||||
// });
|
||||
|
||||
// Holding registers
|
||||
connect(alphaConnectTcpConnection, &AlphaConnectModbusTcpConnection::outdoorTemperatureChanged, this, [thing](float outdoorTemperature){
|
||||
connect(alphaConnectTcpConnection, &AlphaInnotecModbusTcpConnection::outdoorTemperatureChanged, this, [thing](float outdoorTemperature){
|
||||
qCDebug(dcAlphaInnotec()) << thing << "outdoor temperature changed" << outdoorTemperature << "°C";
|
||||
thing->setStateValue(alphaConnectOutdoorTemperatureStateTypeId, outdoorTemperature);
|
||||
});
|
||||
|
||||
connect(alphaConnectTcpConnection, &AlphaConnectModbusTcpConnection::returnSetpointTemperatureChanged, this, [thing](float returnSetpointTemperature){
|
||||
connect(alphaConnectTcpConnection, &AlphaInnotecModbusTcpConnection::returnSetpointTemperatureChanged, this, [thing](float returnSetpointTemperature){
|
||||
qCDebug(dcAlphaInnotec()) << thing << "return setpoint temperature changed" << returnSetpointTemperature << "°C";
|
||||
thing->setStateValue(alphaConnectReturnSetpointTemperatureStateTypeId, returnSetpointTemperature);
|
||||
});
|
||||
|
||||
connect(alphaConnectTcpConnection, &AlphaConnectModbusTcpConnection::hotWaterSetpointTemperatureChanged, this, [thing](float hotWaterSetpointTemperature){
|
||||
connect(alphaConnectTcpConnection, &AlphaInnotecModbusTcpConnection::hotWaterSetpointTemperatureChanged, this, [thing](float hotWaterSetpointTemperature){
|
||||
qCDebug(dcAlphaInnotec()) << thing << "hot water setpoint temperature changed" << hotWaterSetpointTemperature << "°C";
|
||||
thing->setStateValue(alphaConnectHotWaterSetpointTemperatureStateTypeId, hotWaterSetpointTemperature);
|
||||
});
|
||||
|
||||
connect(alphaConnectTcpConnection, &AlphaConnectModbusTcpConnection::smartGridChanged, this, [thing](AlphaConnectModbusTcpConnection::SmartGridState smartGridState){
|
||||
connect(alphaConnectTcpConnection, &AlphaInnotecModbusTcpConnection::smartGridChanged, this, [thing](AlphaInnotecModbusTcpConnection::SmartGridState smartGridState){
|
||||
qCDebug(dcAlphaInnotec()) << thing << "smart grid state changed" << smartGridState;
|
||||
switch (smartGridState) {
|
||||
case AlphaConnectModbusTcpConnection::SmartGridStateOff:
|
||||
case AlphaInnotecModbusTcpConnection::SmartGridStateOff:
|
||||
thing->setStateValue(alphaConnectSgReadyModeStateTypeId, "Off");
|
||||
break;
|
||||
case AlphaConnectModbusTcpConnection::SmartGridStateLow:
|
||||
case AlphaInnotecModbusTcpConnection::SmartGridStateLow:
|
||||
thing->setStateValue(alphaConnectSgReadyModeStateTypeId, "Low");
|
||||
break;
|
||||
case AlphaConnectModbusTcpConnection::SmartGridStateStandard:
|
||||
case AlphaInnotecModbusTcpConnection::SmartGridStateStandard:
|
||||
thing->setStateValue(alphaConnectSgReadyModeStateTypeId, "Standard");
|
||||
break;
|
||||
case AlphaConnectModbusTcpConnection::SmartGridStateHigh:
|
||||
case AlphaInnotecModbusTcpConnection::SmartGridStateHigh:
|
||||
thing->setStateValue(alphaConnectSgReadyModeStateTypeId, "High");
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
m_alpaConnectTcpThings.insert(thing, alphaConnectTcpConnection);
|
||||
m_connections.insert(thing, alphaConnectTcpConnection);
|
||||
alphaConnectTcpConnection->connectDevice();
|
||||
|
||||
// FIXME: make async and check if this is really an alpha connect
|
||||
@ -308,7 +308,7 @@ void IntegrationPluginAlphaInnotec::postSetupThing(Thing *thing)
|
||||
qCDebug(dcAlphaInnotec()) << "Starting plugin timer...";
|
||||
m_pluginTimer = hardwareManager()->pluginTimerManager()->registerTimer(10);
|
||||
connect(m_pluginTimer, &PluginTimer::timeout, this, [this] {
|
||||
foreach (AlphaConnectModbusTcpConnection *connection, m_alpaConnectTcpThings) {
|
||||
foreach (AlphaInnotecModbusTcpConnection *connection, m_connections) {
|
||||
if (connection->connected()) {
|
||||
connection->update();
|
||||
}
|
||||
@ -322,8 +322,8 @@ void IntegrationPluginAlphaInnotec::postSetupThing(Thing *thing)
|
||||
|
||||
void IntegrationPluginAlphaInnotec::thingRemoved(Thing *thing)
|
||||
{
|
||||
if (thing->thingClassId() == alphaConnectThingClassId && m_alpaConnectTcpThings.contains(thing)) {
|
||||
AlphaConnectModbusTcpConnection *connection = m_alpaConnectTcpThings.take(thing);
|
||||
if (thing->thingClassId() == alphaConnectThingClassId && m_connections.contains(thing)) {
|
||||
AlphaInnotecModbusTcpConnection *connection = m_connections.take(thing);
|
||||
delete connection;
|
||||
}
|
||||
|
||||
@ -336,7 +336,7 @@ void IntegrationPluginAlphaInnotec::thingRemoved(Thing *thing)
|
||||
void IntegrationPluginAlphaInnotec::executeAction(ThingActionInfo *info)
|
||||
{
|
||||
Thing *thing = info->thing();
|
||||
AlphaConnectModbusTcpConnection *connection = m_alpaConnectTcpThings.value(thing);
|
||||
AlphaInnotecModbusTcpConnection *connection = m_connections.value(thing);
|
||||
|
||||
if (!connection->connected()) {
|
||||
qCWarning(dcAlphaInnotec()) << "Could not execute action. The modbus connection is currently not available.";
|
||||
@ -430,15 +430,15 @@ void IntegrationPluginAlphaInnotec::executeAction(ThingActionInfo *info)
|
||||
} else if (info->action().actionTypeId() == alphaConnectSgReadyModeActionTypeId) {
|
||||
QString sgReadyModeString = info->action().paramValue(alphaConnectSgReadyModeActionSgReadyModeParamTypeId).toString();
|
||||
qCDebug(dcAlphaInnotec()) << "Execute action" << info->action().actionTypeId().toString() << info->action().params();
|
||||
AlphaConnectModbusTcpConnection::SmartGridState sgReadyState;
|
||||
AlphaInnotecModbusTcpConnection::SmartGridState sgReadyState;
|
||||
if (sgReadyModeString == "Off") {
|
||||
sgReadyState = AlphaConnectModbusTcpConnection::SmartGridStateOff;
|
||||
sgReadyState = AlphaInnotecModbusTcpConnection::SmartGridStateOff;
|
||||
} else if (sgReadyModeString == "Low") {
|
||||
sgReadyState = AlphaConnectModbusTcpConnection::SmartGridStateLow;
|
||||
sgReadyState = AlphaInnotecModbusTcpConnection::SmartGridStateLow;
|
||||
} else if (sgReadyModeString == "High") {
|
||||
sgReadyState = AlphaConnectModbusTcpConnection::SmartGridStateHigh;
|
||||
sgReadyState = AlphaInnotecModbusTcpConnection::SmartGridStateHigh;
|
||||
} else {
|
||||
sgReadyState = AlphaConnectModbusTcpConnection::SmartGridStateStandard;
|
||||
sgReadyState = AlphaInnotecModbusTcpConnection::SmartGridStateStandard;
|
||||
}
|
||||
|
||||
QModbusReply *reply = connection->setSmartGrid(sgReadyState);
|
||||
|
||||
@ -31,9 +31,10 @@
|
||||
#ifndef INTEGRATIONPLUGINALPHAINNOTEC_H
|
||||
#define INTEGRATIONPLUGINALPHAINNOTEC_H
|
||||
|
||||
#include "plugintimer.h"
|
||||
#include "alphaconnectmodbustcpconnection.h"
|
||||
#include "integrations/integrationplugin.h"
|
||||
#include <plugintimer.h>
|
||||
#include <integrations/integrationplugin.h>
|
||||
|
||||
#include "alphainnotecmodbustcpconnection.h"
|
||||
|
||||
class IntegrationPluginAlphaInnotec: public IntegrationPlugin
|
||||
{
|
||||
@ -54,7 +55,7 @@ public:
|
||||
|
||||
private:
|
||||
PluginTimer *m_pluginTimer = nullptr;
|
||||
QHash<Thing *, AlphaConnectModbusTcpConnection *> m_alpaConnectTcpThings;
|
||||
QHash<Thing *, AlphaInnotecModbusTcpConnection *> m_connections;
|
||||
};
|
||||
|
||||
#endif // INTEGRATIONPLUGINALPHAINNOTEC_H
|
||||
|
||||
@ -1,14 +1,13 @@
|
||||
include(../plugins.pri)
|
||||
|
||||
QT += serialport serialbus
|
||||
# Generate modbus connection
|
||||
MODBUS_CONNECTIONS += sdm630-registers.json
|
||||
#MODBUS_TOOLS_CONFIG += VERBOSE
|
||||
include(../modbus.pri)
|
||||
|
||||
HEADERS += \
|
||||
integrationpluginbgetech.h \
|
||||
sdm630modbusrtuconnection.h \
|
||||
../modbus/modbusdatautils.h
|
||||
integrationpluginbgetech.h
|
||||
|
||||
SOURCES += \
|
||||
integrationpluginbgetech.cpp \
|
||||
sdm630modbusrtuconnection.cpp \
|
||||
../modbus/modbusdatautils.cpp
|
||||
integrationpluginbgetech.cpp
|
||||
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
{
|
||||
"className": "Sdm630",
|
||||
"protocol": "RTU",
|
||||
"endianness": "BigEndian",
|
||||
"registers": [
|
||||
@ -257,4 +258,4 @@
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,455 +0,0 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2021, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This fileDescriptor 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 "sdm630modbusrtuconnection.h"
|
||||
#include "loggingcategories.h"
|
||||
|
||||
NYMEA_LOGGING_CATEGORY(dcSdm630ModbusRtuConnection, "Sdm630ModbusRtuConnection")
|
||||
|
||||
Sdm630ModbusRtuConnection::Sdm630ModbusRtuConnection(ModbusRtuMaster *modbusRtuMaster, quint16 slaveId, QObject *parent) :
|
||||
QObject(parent),
|
||||
m_modbusRtuMaster(modbusRtuMaster),
|
||||
m_slaveId(slaveId)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
ModbusRtuMaster *Sdm630ModbusRtuConnection::modbusRtuMaster() const
|
||||
{
|
||||
return m_modbusRtuMaster;
|
||||
}
|
||||
quint16 Sdm630ModbusRtuConnection::slaveId() const
|
||||
{
|
||||
return m_slaveId;
|
||||
}
|
||||
float Sdm630ModbusRtuConnection::totalCurrentPower() const
|
||||
{
|
||||
return m_totalCurrentPower;
|
||||
}
|
||||
|
||||
float Sdm630ModbusRtuConnection::voltagePhaseA() const
|
||||
{
|
||||
return m_voltagePhaseA;
|
||||
}
|
||||
|
||||
float Sdm630ModbusRtuConnection::voltagePhaseB() const
|
||||
{
|
||||
return m_voltagePhaseB;
|
||||
}
|
||||
|
||||
float Sdm630ModbusRtuConnection::voltagePhaseC() const
|
||||
{
|
||||
return m_voltagePhaseC;
|
||||
}
|
||||
|
||||
float Sdm630ModbusRtuConnection::currentPhaseA() const
|
||||
{
|
||||
return m_currentPhaseA;
|
||||
}
|
||||
|
||||
float Sdm630ModbusRtuConnection::currentPhaseB() const
|
||||
{
|
||||
return m_currentPhaseB;
|
||||
}
|
||||
|
||||
float Sdm630ModbusRtuConnection::currentPhaseC() const
|
||||
{
|
||||
return m_currentPhaseC;
|
||||
}
|
||||
|
||||
float Sdm630ModbusRtuConnection::powerPhaseA() const
|
||||
{
|
||||
return m_powerPhaseA;
|
||||
}
|
||||
|
||||
float Sdm630ModbusRtuConnection::powerPhaseB() const
|
||||
{
|
||||
return m_powerPhaseB;
|
||||
}
|
||||
|
||||
float Sdm630ModbusRtuConnection::powerPhaseC() const
|
||||
{
|
||||
return m_powerPhaseC;
|
||||
}
|
||||
|
||||
float Sdm630ModbusRtuConnection::frequency() const
|
||||
{
|
||||
return m_frequency;
|
||||
}
|
||||
|
||||
float Sdm630ModbusRtuConnection::totalEnergyConsumed() const
|
||||
{
|
||||
return m_totalEnergyConsumed;
|
||||
}
|
||||
|
||||
float Sdm630ModbusRtuConnection::totalEnergyProduced() const
|
||||
{
|
||||
return m_totalEnergyProduced;
|
||||
}
|
||||
|
||||
float Sdm630ModbusRtuConnection::energyProducedPhaseA() const
|
||||
{
|
||||
return m_energyProducedPhaseA;
|
||||
}
|
||||
|
||||
float Sdm630ModbusRtuConnection::energyProducedPhaseB() const
|
||||
{
|
||||
return m_energyProducedPhaseB;
|
||||
}
|
||||
|
||||
float Sdm630ModbusRtuConnection::energyProducedPhaseC() const
|
||||
{
|
||||
return m_energyProducedPhaseC;
|
||||
}
|
||||
|
||||
float Sdm630ModbusRtuConnection::energyConsumedPhaseA() const
|
||||
{
|
||||
return m_energyConsumedPhaseA;
|
||||
}
|
||||
|
||||
float Sdm630ModbusRtuConnection::energyConsumedPhaseB() const
|
||||
{
|
||||
return m_energyConsumedPhaseB;
|
||||
}
|
||||
|
||||
float Sdm630ModbusRtuConnection::energyConsumedPhaseC() const
|
||||
{
|
||||
return m_energyConsumedPhaseC;
|
||||
}
|
||||
|
||||
void Sdm630ModbusRtuConnection::initialize()
|
||||
{
|
||||
// No init registers defined. Nothing to be done and we are finished.
|
||||
emit initializationFinished();
|
||||
}
|
||||
|
||||
void Sdm630ModbusRtuConnection::update()
|
||||
{
|
||||
updateTotalCurrentPower();
|
||||
updatePhaseVoltageAndCurrentBlock();
|
||||
updatePhasePowerBlock();
|
||||
updateFrequencyAndTotalEnergyBlock();
|
||||
updatePhaseEnergyEnergyBlock();
|
||||
}
|
||||
|
||||
void Sdm630ModbusRtuConnection::updateTotalCurrentPower()
|
||||
{
|
||||
// Update registers from Total system power
|
||||
qCDebug(dcSdm630ModbusRtuConnection()) << "--> Read \"Total system power\" register:" << 52 << "size:" << 2;
|
||||
ModbusRtuReply *reply = readTotalCurrentPower();
|
||||
if (reply) {
|
||||
if (!reply->isFinished()) {
|
||||
connect(reply, &ModbusRtuReply::finished, this, [this, reply](){
|
||||
if (reply->error() == ModbusRtuReply::NoError) {
|
||||
QVector<quint16> values = reply->result();
|
||||
qCDebug(dcSdm630ModbusRtuConnection()) << "<-- Response from \"Total system power\" register" << 52 << "size:" << 2 << values;
|
||||
float receivedTotalCurrentPower = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian);
|
||||
if (m_totalCurrentPower != receivedTotalCurrentPower) {
|
||||
m_totalCurrentPower = receivedTotalCurrentPower;
|
||||
emit totalCurrentPowerChanged(m_totalCurrentPower);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
connect(reply, &ModbusRtuReply::errorOccurred, this, [reply] (ModbusRtuReply::Error error){
|
||||
qCWarning(dcSdm630ModbusRtuConnection()) << "ModbusRtu reply error occurred while updating \"Total system power\" registers" << error << reply->errorString();
|
||||
emit reply->finished();
|
||||
});
|
||||
}
|
||||
} else {
|
||||
qCWarning(dcSdm630ModbusRtuConnection()) << "Error occurred while reading \"Total system power\" registers";
|
||||
}
|
||||
}
|
||||
|
||||
void Sdm630ModbusRtuConnection::updatePhaseVoltageAndCurrentBlock()
|
||||
{
|
||||
// Update register block "phaseVoltageAndCurrent"
|
||||
qCDebug(dcSdm630ModbusRtuConnection()) << "--> Read block \"phaseVoltageAndCurrent\" registers from:" << 0 << "size:" << 12;
|
||||
ModbusRtuReply *reply = m_modbusRtuMaster->readInputRegister(m_slaveId, 0, 12);
|
||||
if (reply) {
|
||||
if (!reply->isFinished()) {
|
||||
connect(reply, &ModbusRtuReply::finished, this, [this, reply](){
|
||||
if (reply->error() == ModbusRtuReply::NoError) {
|
||||
QVector<quint16> blockValues = reply->result();
|
||||
QVector<quint16> values;
|
||||
qCDebug(dcSdm630ModbusRtuConnection()) << "<-- Response from reading block \"phaseVoltageAndCurrent\" register" << 0 << "size:" << 12 << blockValues;
|
||||
values = blockValues.mid(0, 2);
|
||||
float receivedVoltagePhaseA = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian);
|
||||
if (m_voltagePhaseA != receivedVoltagePhaseA) {
|
||||
m_voltagePhaseA = receivedVoltagePhaseA;
|
||||
emit voltagePhaseAChanged(m_voltagePhaseA);
|
||||
}
|
||||
|
||||
values = blockValues.mid(2, 2);
|
||||
float receivedVoltagePhaseB = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian);
|
||||
if (m_voltagePhaseB != receivedVoltagePhaseB) {
|
||||
m_voltagePhaseB = receivedVoltagePhaseB;
|
||||
emit voltagePhaseBChanged(m_voltagePhaseB);
|
||||
}
|
||||
|
||||
values = blockValues.mid(4, 2);
|
||||
float receivedVoltagePhaseC = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian);
|
||||
if (m_voltagePhaseC != receivedVoltagePhaseC) {
|
||||
m_voltagePhaseC = receivedVoltagePhaseC;
|
||||
emit voltagePhaseCChanged(m_voltagePhaseC);
|
||||
}
|
||||
|
||||
values = blockValues.mid(6, 2);
|
||||
float receivedCurrentPhaseA = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian);
|
||||
if (m_currentPhaseA != receivedCurrentPhaseA) {
|
||||
m_currentPhaseA = receivedCurrentPhaseA;
|
||||
emit currentPhaseAChanged(m_currentPhaseA);
|
||||
}
|
||||
|
||||
values = blockValues.mid(8, 2);
|
||||
float receivedCurrentPhaseB = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian);
|
||||
if (m_currentPhaseB != receivedCurrentPhaseB) {
|
||||
m_currentPhaseB = receivedCurrentPhaseB;
|
||||
emit currentPhaseBChanged(m_currentPhaseB);
|
||||
}
|
||||
|
||||
values = blockValues.mid(10, 2);
|
||||
float receivedCurrentPhaseC = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian);
|
||||
if (m_currentPhaseC != receivedCurrentPhaseC) {
|
||||
m_currentPhaseC = receivedCurrentPhaseC;
|
||||
emit currentPhaseCChanged(m_currentPhaseC);
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
connect(reply, &ModbusRtuReply::errorOccurred, this, [reply] (ModbusRtuReply::Error error){
|
||||
qCWarning(dcSdm630ModbusRtuConnection()) << "ModbusRtu reply error occurred while updating block \"phaseVoltageAndCurrent\" registers" << error << reply->errorString();
|
||||
emit reply->finished();
|
||||
});
|
||||
}
|
||||
} else {
|
||||
qCWarning(dcSdm630ModbusRtuConnection()) << "Error occurred while reading block \"phaseVoltageAndCurrent\" registers";
|
||||
}
|
||||
}
|
||||
|
||||
void Sdm630ModbusRtuConnection::updatePhasePowerBlock()
|
||||
{
|
||||
// Update register block "phasePower"
|
||||
qCDebug(dcSdm630ModbusRtuConnection()) << "--> Read block \"phasePower\" registers from:" << 12 << "size:" << 6;
|
||||
ModbusRtuReply *reply = m_modbusRtuMaster->readInputRegister(m_slaveId, 12, 6);
|
||||
if (reply) {
|
||||
if (!reply->isFinished()) {
|
||||
connect(reply, &ModbusRtuReply::finished, this, [this, reply](){
|
||||
if (reply->error() == ModbusRtuReply::NoError) {
|
||||
QVector<quint16> blockValues = reply->result();
|
||||
QVector<quint16> values;
|
||||
qCDebug(dcSdm630ModbusRtuConnection()) << "<-- Response from reading block \"phasePower\" register" << 12 << "size:" << 6 << blockValues;
|
||||
values = blockValues.mid(0, 2);
|
||||
float receivedPowerPhaseA = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian);
|
||||
if (m_powerPhaseA != receivedPowerPhaseA) {
|
||||
m_powerPhaseA = receivedPowerPhaseA;
|
||||
emit powerPhaseAChanged(m_powerPhaseA);
|
||||
}
|
||||
|
||||
values = blockValues.mid(2, 2);
|
||||
float receivedPowerPhaseB = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian);
|
||||
if (m_powerPhaseB != receivedPowerPhaseB) {
|
||||
m_powerPhaseB = receivedPowerPhaseB;
|
||||
emit powerPhaseBChanged(m_powerPhaseB);
|
||||
}
|
||||
|
||||
values = blockValues.mid(4, 2);
|
||||
float receivedPowerPhaseC = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian);
|
||||
if (m_powerPhaseC != receivedPowerPhaseC) {
|
||||
m_powerPhaseC = receivedPowerPhaseC;
|
||||
emit powerPhaseCChanged(m_powerPhaseC);
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
connect(reply, &ModbusRtuReply::errorOccurred, this, [reply] (ModbusRtuReply::Error error){
|
||||
qCWarning(dcSdm630ModbusRtuConnection()) << "ModbusRtu reply error occurred while updating block \"phasePower\" registers" << error << reply->errorString();
|
||||
emit reply->finished();
|
||||
});
|
||||
}
|
||||
} else {
|
||||
qCWarning(dcSdm630ModbusRtuConnection()) << "Error occurred while reading block \"phasePower\" registers";
|
||||
}
|
||||
}
|
||||
|
||||
void Sdm630ModbusRtuConnection::updateFrequencyAndTotalEnergyBlock()
|
||||
{
|
||||
// Update register block "frequencyAndTotalEnergy"
|
||||
qCDebug(dcSdm630ModbusRtuConnection()) << "--> Read block \"frequencyAndTotalEnergy\" registers from:" << 70 << "size:" << 6;
|
||||
ModbusRtuReply *reply = m_modbusRtuMaster->readInputRegister(m_slaveId, 70, 6);
|
||||
if (reply) {
|
||||
if (!reply->isFinished()) {
|
||||
connect(reply, &ModbusRtuReply::finished, this, [this, reply](){
|
||||
if (reply->error() == ModbusRtuReply::NoError) {
|
||||
QVector<quint16> blockValues = reply->result();
|
||||
QVector<quint16> values;
|
||||
qCDebug(dcSdm630ModbusRtuConnection()) << "<-- Response from reading block \"frequencyAndTotalEnergy\" register" << 70 << "size:" << 6 << blockValues;
|
||||
values = blockValues.mid(0, 2);
|
||||
float receivedFrequency = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian);
|
||||
if (m_frequency != receivedFrequency) {
|
||||
m_frequency = receivedFrequency;
|
||||
emit frequencyChanged(m_frequency);
|
||||
}
|
||||
|
||||
values = blockValues.mid(2, 2);
|
||||
float receivedTotalEnergyConsumed = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian);
|
||||
if (m_totalEnergyConsumed != receivedTotalEnergyConsumed) {
|
||||
m_totalEnergyConsumed = receivedTotalEnergyConsumed;
|
||||
emit totalEnergyConsumedChanged(m_totalEnergyConsumed);
|
||||
}
|
||||
|
||||
values = blockValues.mid(4, 2);
|
||||
float receivedTotalEnergyProduced = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian);
|
||||
if (m_totalEnergyProduced != receivedTotalEnergyProduced) {
|
||||
m_totalEnergyProduced = receivedTotalEnergyProduced;
|
||||
emit totalEnergyProducedChanged(m_totalEnergyProduced);
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
connect(reply, &ModbusRtuReply::errorOccurred, this, [reply] (ModbusRtuReply::Error error){
|
||||
qCWarning(dcSdm630ModbusRtuConnection()) << "ModbusRtu reply error occurred while updating block \"frequencyAndTotalEnergy\" registers" << error << reply->errorString();
|
||||
emit reply->finished();
|
||||
});
|
||||
}
|
||||
} else {
|
||||
qCWarning(dcSdm630ModbusRtuConnection()) << "Error occurred while reading block \"frequencyAndTotalEnergy\" registers";
|
||||
}
|
||||
}
|
||||
|
||||
void Sdm630ModbusRtuConnection::updatePhaseEnergyEnergyBlock()
|
||||
{
|
||||
// Update register block "phaseEnergyEnergy"
|
||||
qCDebug(dcSdm630ModbusRtuConnection()) << "--> Read block \"phaseEnergyEnergy\" registers from:" << 346 << "size:" << 12;
|
||||
ModbusRtuReply *reply = m_modbusRtuMaster->readInputRegister(m_slaveId, 346, 12);
|
||||
if (reply) {
|
||||
if (!reply->isFinished()) {
|
||||
connect(reply, &ModbusRtuReply::finished, this, [this, reply](){
|
||||
if (reply->error() == ModbusRtuReply::NoError) {
|
||||
QVector<quint16> blockValues = reply->result();
|
||||
QVector<quint16> values;
|
||||
qCDebug(dcSdm630ModbusRtuConnection()) << "<-- Response from reading block \"phaseEnergyEnergy\" register" << 346 << "size:" << 12 << blockValues;
|
||||
values = blockValues.mid(0, 2);
|
||||
float receivedEnergyProducedPhaseA = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian);
|
||||
if (m_energyProducedPhaseA != receivedEnergyProducedPhaseA) {
|
||||
m_energyProducedPhaseA = receivedEnergyProducedPhaseA;
|
||||
emit energyProducedPhaseAChanged(m_energyProducedPhaseA);
|
||||
}
|
||||
|
||||
values = blockValues.mid(2, 2);
|
||||
float receivedEnergyProducedPhaseB = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian);
|
||||
if (m_energyProducedPhaseB != receivedEnergyProducedPhaseB) {
|
||||
m_energyProducedPhaseB = receivedEnergyProducedPhaseB;
|
||||
emit energyProducedPhaseBChanged(m_energyProducedPhaseB);
|
||||
}
|
||||
|
||||
values = blockValues.mid(4, 2);
|
||||
float receivedEnergyProducedPhaseC = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian);
|
||||
if (m_energyProducedPhaseC != receivedEnergyProducedPhaseC) {
|
||||
m_energyProducedPhaseC = receivedEnergyProducedPhaseC;
|
||||
emit energyProducedPhaseCChanged(m_energyProducedPhaseC);
|
||||
}
|
||||
|
||||
values = blockValues.mid(6, 2);
|
||||
float receivedEnergyConsumedPhaseA = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian);
|
||||
if (m_energyConsumedPhaseA != receivedEnergyConsumedPhaseA) {
|
||||
m_energyConsumedPhaseA = receivedEnergyConsumedPhaseA;
|
||||
emit energyConsumedPhaseAChanged(m_energyConsumedPhaseA);
|
||||
}
|
||||
|
||||
values = blockValues.mid(8, 2);
|
||||
float receivedEnergyConsumedPhaseB = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian);
|
||||
if (m_energyConsumedPhaseB != receivedEnergyConsumedPhaseB) {
|
||||
m_energyConsumedPhaseB = receivedEnergyConsumedPhaseB;
|
||||
emit energyConsumedPhaseBChanged(m_energyConsumedPhaseB);
|
||||
}
|
||||
|
||||
values = blockValues.mid(10, 2);
|
||||
float receivedEnergyConsumedPhaseC = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian);
|
||||
if (m_energyConsumedPhaseC != receivedEnergyConsumedPhaseC) {
|
||||
m_energyConsumedPhaseC = receivedEnergyConsumedPhaseC;
|
||||
emit energyConsumedPhaseCChanged(m_energyConsumedPhaseC);
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
connect(reply, &ModbusRtuReply::errorOccurred, this, [reply] (ModbusRtuReply::Error error){
|
||||
qCWarning(dcSdm630ModbusRtuConnection()) << "ModbusRtu reply error occurred while updating block \"phaseEnergyEnergy\" registers" << error << reply->errorString();
|
||||
emit reply->finished();
|
||||
});
|
||||
}
|
||||
} else {
|
||||
qCWarning(dcSdm630ModbusRtuConnection()) << "Error occurred while reading block \"phaseEnergyEnergy\" registers";
|
||||
}
|
||||
}
|
||||
|
||||
ModbusRtuReply *Sdm630ModbusRtuConnection::readTotalCurrentPower()
|
||||
{
|
||||
return m_modbusRtuMaster->readInputRegister(m_slaveId, 52, 2);
|
||||
}
|
||||
|
||||
void Sdm630ModbusRtuConnection::verifyInitFinished()
|
||||
{
|
||||
if (m_pendingInitReplies.isEmpty()) {
|
||||
qCDebug(dcSdm630ModbusRtuConnection()) << "Initialization finished of Sdm630ModbusRtuConnection";
|
||||
emit initializationFinished();
|
||||
}
|
||||
}
|
||||
|
||||
QDebug operator<<(QDebug debug, Sdm630ModbusRtuConnection *sdm630ModbusRtuConnection)
|
||||
{
|
||||
debug.nospace().noquote() << "Sdm630ModbusRtuConnection(" << sdm630ModbusRtuConnection->modbusRtuMaster()->modbusUuid().toString() << ", " << sdm630ModbusRtuConnection->modbusRtuMaster()->serialPort() << ", slave ID:" << sdm630ModbusRtuConnection->slaveId() << ")" << "\n";
|
||||
debug.nospace().noquote() << " - Total system power:" << sdm630ModbusRtuConnection->totalCurrentPower() << " [W]" << "\n";
|
||||
debug.nospace().noquote() << " - Voltage phase L1:" << sdm630ModbusRtuConnection->voltagePhaseA() << " [V]" << "\n";
|
||||
debug.nospace().noquote() << " - Voltage phase L2:" << sdm630ModbusRtuConnection->voltagePhaseB() << " [V]" << "\n";
|
||||
debug.nospace().noquote() << " - Voltage phase L3:" << sdm630ModbusRtuConnection->voltagePhaseC() << " [V]" << "\n";
|
||||
debug.nospace().noquote() << " - Current phase L1:" << sdm630ModbusRtuConnection->currentPhaseA() << " [A]" << "\n";
|
||||
debug.nospace().noquote() << " - Current phase L2:" << sdm630ModbusRtuConnection->currentPhaseB() << " [A]" << "\n";
|
||||
debug.nospace().noquote() << " - Current phase L3:" << sdm630ModbusRtuConnection->currentPhaseC() << " [A]" << "\n";
|
||||
debug.nospace().noquote() << " - Power phase L1:" << sdm630ModbusRtuConnection->powerPhaseA() << " [W]" << "\n";
|
||||
debug.nospace().noquote() << " - Power phase L2:" << sdm630ModbusRtuConnection->powerPhaseB() << " [W]" << "\n";
|
||||
debug.nospace().noquote() << " - Power phase L3:" << sdm630ModbusRtuConnection->powerPhaseC() << " [W]" << "\n";
|
||||
debug.nospace().noquote() << " - Frequency:" << sdm630ModbusRtuConnection->frequency() << " [Hz]" << "\n";
|
||||
debug.nospace().noquote() << " - Total energy consumed:" << sdm630ModbusRtuConnection->totalEnergyConsumed() << " [kWh]" << "\n";
|
||||
debug.nospace().noquote() << " - Total energy produced:" << sdm630ModbusRtuConnection->totalEnergyProduced() << " [kWh]" << "\n";
|
||||
debug.nospace().noquote() << " - Energy produced phase A:" << sdm630ModbusRtuConnection->energyProducedPhaseA() << " [kWh]" << "\n";
|
||||
debug.nospace().noquote() << " - Energy produced phase B:" << sdm630ModbusRtuConnection->energyProducedPhaseB() << " [kWh]" << "\n";
|
||||
debug.nospace().noquote() << " - Energy produced phase C:" << sdm630ModbusRtuConnection->energyProducedPhaseC() << " [kWh]" << "\n";
|
||||
debug.nospace().noquote() << " - Energy consumed phase A:" << sdm630ModbusRtuConnection->energyConsumedPhaseA() << " [kWh]" << "\n";
|
||||
debug.nospace().noquote() << " - Energy consumed phase B:" << sdm630ModbusRtuConnection->energyConsumedPhaseB() << " [kWh]" << "\n";
|
||||
debug.nospace().noquote() << " - Energy consumed phase C:" << sdm630ModbusRtuConnection->energyConsumedPhaseC() << " [kWh]" << "\n";
|
||||
return debug.quote().space();
|
||||
}
|
||||
|
||||
@ -1,199 +0,0 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2021, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This fileDescriptor 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 SDM630MODBUSRTUCONNECTION_H
|
||||
#define SDM630MODBUSRTUCONNECTION_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include "../modbus/modbusdatautils.h"
|
||||
#include <hardware/modbus/modbusrtumaster.h>
|
||||
|
||||
class Sdm630ModbusRtuConnection : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit Sdm630ModbusRtuConnection(ModbusRtuMaster *modbusRtuMaster, quint16 slaveId, QObject *parent = nullptr);
|
||||
~Sdm630ModbusRtuConnection() = default;
|
||||
|
||||
ModbusRtuMaster *modbusRtuMaster() const;
|
||||
quint16 slaveId() const;
|
||||
|
||||
/* Total system power [W] - Address: 52, Size: 2 */
|
||||
float totalCurrentPower() const;
|
||||
|
||||
/* Voltage phase L1 [V] - Address: 0, Size: 2 */
|
||||
float voltagePhaseA() const;
|
||||
|
||||
/* Voltage phase L2 [V] - Address: 2, Size: 2 */
|
||||
float voltagePhaseB() const;
|
||||
|
||||
/* Voltage phase L3 [V] - Address: 4, Size: 2 */
|
||||
float voltagePhaseC() const;
|
||||
|
||||
/* Current phase L1 [A] - Address: 6, Size: 2 */
|
||||
float currentPhaseA() const;
|
||||
|
||||
/* Current phase L2 [A] - Address: 8, Size: 2 */
|
||||
float currentPhaseB() const;
|
||||
|
||||
/* Current phase L3 [A] - Address: 10, Size: 2 */
|
||||
float currentPhaseC() const;
|
||||
|
||||
/* Read block from start addess 0 with size of 12 registers containing following 6 properties:
|
||||
- Voltage phase L1 [V] - Address: 0, Size: 2
|
||||
- Voltage phase L2 [V] - Address: 2, Size: 2
|
||||
- Voltage phase L3 [V] - Address: 4, Size: 2
|
||||
- Current phase L1 [A] - Address: 6, Size: 2
|
||||
- Current phase L2 [A] - Address: 8, Size: 2
|
||||
- Current phase L3 [A] - Address: 10, Size: 2
|
||||
*/
|
||||
void updatePhaseVoltageAndCurrentBlock();
|
||||
/* Power phase L1 [W] - Address: 12, Size: 2 */
|
||||
float powerPhaseA() const;
|
||||
|
||||
/* Power phase L2 [W] - Address: 14, Size: 2 */
|
||||
float powerPhaseB() const;
|
||||
|
||||
/* Power phase L3 [W] - Address: 16, Size: 2 */
|
||||
float powerPhaseC() const;
|
||||
|
||||
/* Read block from start addess 12 with size of 6 registers containing following 3 properties:
|
||||
- Power phase L1 [W] - Address: 12, Size: 2
|
||||
- Power phase L2 [W] - Address: 14, Size: 2
|
||||
- Power phase L3 [W] - Address: 16, Size: 2
|
||||
*/
|
||||
void updatePhasePowerBlock();
|
||||
/* Frequency [Hz] - Address: 70, Size: 2 */
|
||||
float frequency() const;
|
||||
|
||||
/* Total energy consumed [kWh] - Address: 72, Size: 2 */
|
||||
float totalEnergyConsumed() const;
|
||||
|
||||
/* Total energy produced [kWh] - Address: 74, Size: 2 */
|
||||
float totalEnergyProduced() const;
|
||||
|
||||
/* Read block from start addess 70 with size of 6 registers containing following 3 properties:
|
||||
- Frequency [Hz] - Address: 70, Size: 2
|
||||
- Total energy consumed [kWh] - Address: 72, Size: 2
|
||||
- Total energy produced [kWh] - Address: 74, Size: 2
|
||||
*/
|
||||
void updateFrequencyAndTotalEnergyBlock();
|
||||
/* Energy produced phase A [kWh] - Address: 346, Size: 2 */
|
||||
float energyProducedPhaseA() const;
|
||||
|
||||
/* Energy produced phase B [kWh] - Address: 348, Size: 2 */
|
||||
float energyProducedPhaseB() const;
|
||||
|
||||
/* Energy produced phase C [kWh] - Address: 350, Size: 2 */
|
||||
float energyProducedPhaseC() const;
|
||||
|
||||
/* Energy consumed phase A [kWh] - Address: 352, Size: 2 */
|
||||
float energyConsumedPhaseA() const;
|
||||
|
||||
/* Energy consumed phase B [kWh] - Address: 354, Size: 2 */
|
||||
float energyConsumedPhaseB() const;
|
||||
|
||||
/* Energy consumed phase C [kWh] - Address: 356, Size: 2 */
|
||||
float energyConsumedPhaseC() const;
|
||||
|
||||
/* Read block from start addess 346 with size of 12 registers containing following 6 properties:
|
||||
- Energy produced phase A [kWh] - Address: 346, Size: 2
|
||||
- Energy produced phase B [kWh] - Address: 348, Size: 2
|
||||
- Energy produced phase C [kWh] - Address: 350, Size: 2
|
||||
- Energy consumed phase A [kWh] - Address: 352, Size: 2
|
||||
- Energy consumed phase B [kWh] - Address: 354, Size: 2
|
||||
- Energy consumed phase C [kWh] - Address: 356, Size: 2
|
||||
*/
|
||||
void updatePhaseEnergyEnergyBlock();
|
||||
|
||||
void updateTotalCurrentPower();
|
||||
|
||||
virtual void initialize();
|
||||
virtual void update();
|
||||
|
||||
signals:
|
||||
void initializationFinished();
|
||||
|
||||
void totalCurrentPowerChanged(float totalCurrentPower);
|
||||
void voltagePhaseAChanged(float voltagePhaseA);
|
||||
void voltagePhaseBChanged(float voltagePhaseB);
|
||||
void voltagePhaseCChanged(float voltagePhaseC);
|
||||
void currentPhaseAChanged(float currentPhaseA);
|
||||
void currentPhaseBChanged(float currentPhaseB);
|
||||
void currentPhaseCChanged(float currentPhaseC);
|
||||
void powerPhaseAChanged(float powerPhaseA);
|
||||
void powerPhaseBChanged(float powerPhaseB);
|
||||
void powerPhaseCChanged(float powerPhaseC);
|
||||
void frequencyChanged(float frequency);
|
||||
void totalEnergyConsumedChanged(float totalEnergyConsumed);
|
||||
void totalEnergyProducedChanged(float totalEnergyProduced);
|
||||
void energyProducedPhaseAChanged(float energyProducedPhaseA);
|
||||
void energyProducedPhaseBChanged(float energyProducedPhaseB);
|
||||
void energyProducedPhaseCChanged(float energyProducedPhaseC);
|
||||
void energyConsumedPhaseAChanged(float energyConsumedPhaseA);
|
||||
void energyConsumedPhaseBChanged(float energyConsumedPhaseB);
|
||||
void energyConsumedPhaseCChanged(float energyConsumedPhaseC);
|
||||
|
||||
private:
|
||||
ModbusRtuMaster *m_modbusRtuMaster = nullptr;
|
||||
quint16 m_slaveId = 1;
|
||||
QVector<ModbusRtuReply *> m_pendingInitReplies;
|
||||
|
||||
float m_totalCurrentPower = 0;
|
||||
float m_voltagePhaseA = 0;
|
||||
float m_voltagePhaseB = 0;
|
||||
float m_voltagePhaseC = 0;
|
||||
float m_currentPhaseA = 0;
|
||||
float m_currentPhaseB = 0;
|
||||
float m_currentPhaseC = 0;
|
||||
float m_powerPhaseA = 0;
|
||||
float m_powerPhaseB = 0;
|
||||
float m_powerPhaseC = 0;
|
||||
float m_frequency = 0;
|
||||
float m_totalEnergyConsumed = 0;
|
||||
float m_totalEnergyProduced = 0;
|
||||
float m_energyProducedPhaseA = 0;
|
||||
float m_energyProducedPhaseB = 0;
|
||||
float m_energyProducedPhaseC = 0;
|
||||
float m_energyConsumedPhaseA = 0;
|
||||
float m_energyConsumedPhaseB = 0;
|
||||
float m_energyConsumedPhaseC = 0;
|
||||
|
||||
void verifyInitFinished();
|
||||
|
||||
ModbusRtuReply *readTotalCurrentPower();
|
||||
|
||||
|
||||
};
|
||||
|
||||
QDebug operator<<(QDebug debug, Sdm630ModbusRtuConnection *sdm630ModbusRtuConnection);
|
||||
|
||||
#endif // SDM630MODBUSRTUCONNECTION_H
|
||||
39
debian/control
vendored
39
debian/control
vendored
@ -2,6 +2,7 @@ Source: nymea-plugins-modbus
|
||||
Section: utils
|
||||
Priority: options
|
||||
Maintainer: nymea GmbH <developer@nymea.io>
|
||||
Standards-Version: 3.9.3
|
||||
Build-depends: debhelper (>= 9.0.0),
|
||||
libnymea-dev (>= 0.17),
|
||||
libnymea-gpio-dev,
|
||||
@ -10,8 +11,8 @@ Build-depends: debhelper (>= 9.0.0),
|
||||
nymea-dev-tools:native,
|
||||
pkg-config,
|
||||
qtbase5-dev,
|
||||
libi2c-dev
|
||||
Standards-Version: 3.9.3
|
||||
libi2c-dev,
|
||||
python3:native
|
||||
|
||||
|
||||
Package: libnymea-sunspec1
|
||||
@ -22,6 +23,7 @@ Depends: ${shlibs:Depends},
|
||||
Description: nymea.io sunspec library
|
||||
This package contains the nymea sunspec library.
|
||||
|
||||
|
||||
Package: libnymea-sunspec-dev
|
||||
Section: libdevel
|
||||
Architecture: any
|
||||
@ -34,6 +36,30 @@ Depends: ${shlibs:Depends},
|
||||
Description: The main libraries and header files for developing with nymea sunspec.
|
||||
This package contains the nymea sunspec library - development files.
|
||||
|
||||
|
||||
Package: libnymea-modbus
|
||||
Architecture: any
|
||||
Section: libs
|
||||
Depends: ${shlibs:Depends},
|
||||
${misc:Depends}
|
||||
Description: nymea modbus integration plugins library
|
||||
This package contains the nymea modbus library for integration plugins.
|
||||
|
||||
|
||||
Package: libnymea-modbus-dev
|
||||
Section: libdevel
|
||||
Architecture: any
|
||||
Multi-Arch: same
|
||||
Depends: ${shlibs:Depends},
|
||||
${misc:Depends},
|
||||
libnymea-modbus (= ${binary:Version}),
|
||||
pkg-config,
|
||||
qtbase5-dev,
|
||||
python3,
|
||||
Description: The main libraries and header files for developing with modbus based nymea integration plugins.
|
||||
This package contains the nymea modbus integration plugin library - development files.
|
||||
|
||||
|
||||
Package: nymea-plugin-alphainnotec
|
||||
Architecture: any
|
||||
Section: libs
|
||||
@ -130,6 +156,15 @@ Description: nymea integration plugin for Schrack wallboxes
|
||||
This package contains the nymea integration plugin for Schrack wallboxes.
|
||||
|
||||
|
||||
Package: nymea-plugin-stiebeleltron
|
||||
Architecture: any
|
||||
Section: libs
|
||||
Depends: ${shlibs:Depends},
|
||||
${misc:Depends},
|
||||
Description: nymea.io plugin for Stiebel Eltron heat pumps
|
||||
This package will install the nymea.io plugin for Stiebel Eltron heat pumps.
|
||||
|
||||
|
||||
Package: nymea-plugin-sunspec
|
||||
Architecture: any
|
||||
Depends: ${shlibs:Depends},
|
||||
|
||||
4
debian/libnymea-modbus-dev.install.in
vendored
Normal file
4
debian/libnymea-modbus-dev.install.in
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
usr/lib/@DEB_HOST_MULTIARCH@/libnymea-modbus.so
|
||||
usr/include/nymea-modbus/
|
||||
usr/lib/@DEB_HOST_MULTIARCH@/pkgconfig/nymea-modbus.pc
|
||||
|
||||
4
debian/libnymea-modbus.install.in
vendored
Normal file
4
debian/libnymea-modbus.install.in
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
usr/lib/@DEB_HOST_MULTIARCH@/libnymea-modbus.so.1
|
||||
usr/lib/@DEB_HOST_MULTIARCH@/libnymea-modbus.so.1.0
|
||||
usr/lib/@DEB_HOST_MULTIARCH@/libnymea-modbus.so.1.0.0
|
||||
|
||||
2
debian/nymea-plugin-stiebeleltron.install.in
vendored
Normal file
2
debian/nymea-plugin-stiebeleltron.install.in
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
usr/lib/@DEB_HOST_MULTIARCH@/nymea/plugins/libnymea_integrationpluginstiebeleltron.so
|
||||
stiebeleltron/translations/*qm usr/share/nymea/translations/
|
||||
1
debian/rules
vendored
1
debian/rules
vendored
@ -21,5 +21,6 @@ override_dh_auto_clean:
|
||||
dh_auto_clean
|
||||
find -name *plugininfo.h -exec rm {} \;
|
||||
find -name *.qm -exec rm {} \;
|
||||
find -name "autogenerated" -type d -exec rm -rvf {} +
|
||||
rm -rf $(PREPROCESS_FILES:.in=)
|
||||
|
||||
|
||||
@ -31,9 +31,9 @@
|
||||
#include "integrationplugindrexelundweiss.h"
|
||||
#include "plugininfo.h"
|
||||
|
||||
#include "hardwaremanager.h"
|
||||
#include "hardware/modbus/modbusrtumaster.h"
|
||||
#include "hardware/modbus/modbusrtuhardwareresource.h"
|
||||
#include <hardwaremanager.h>
|
||||
#include <hardware/modbus/modbusrtumaster.h>
|
||||
#include <hardware/modbus/modbusrtuhardwareresource.h>
|
||||
|
||||
IntegrationPluginDrexelUndWeiss::IntegrationPluginDrexelUndWeiss()
|
||||
{
|
||||
|
||||
@ -31,9 +31,10 @@
|
||||
#ifndef INTEGRATIONPLUGINDREXELUNDWEISS_H
|
||||
#define INTEGRATIONPLUGINDREXELUNDWEISS_H
|
||||
|
||||
#include "integrations/integrationplugin.h"
|
||||
#include "hardware/modbus/modbusrtumaster.h"
|
||||
#include "plugintimer.h"
|
||||
#include <integrations/integrationplugin.h>
|
||||
#include <hardware/modbus/modbusrtumaster.h>
|
||||
#include <plugintimer.h>
|
||||
|
||||
#include "modbusregisterdefinition.h"
|
||||
|
||||
#include <QDateTime>
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
{
|
||||
"className": "Huawei",
|
||||
"protocol": "TCP",
|
||||
"endianness": "BigEndian",
|
||||
"enums": [
|
||||
|
||||
@ -1,17 +1,14 @@
|
||||
include(../plugins.pri)
|
||||
|
||||
QT += network serialbus
|
||||
# Generate modbus connection
|
||||
MODBUS_CONNECTIONS += huawei-registers.json
|
||||
#MODBUS_TOOLS_CONFIG += VERBOSE
|
||||
include(../modbus.pri)
|
||||
|
||||
HEADERS += \
|
||||
huaweifusionsolar.h \
|
||||
huaweimodbustcpconnection.h \
|
||||
integrationpluginhuawei.h \
|
||||
../modbus/modbustcpmaster.h \
|
||||
../modbus/modbusdatautils.h
|
||||
integrationpluginhuawei.h
|
||||
|
||||
SOURCES += \
|
||||
huaweifusionsolar.cpp \
|
||||
huaweimodbustcpconnection.cpp \
|
||||
integrationpluginhuawei.cpp \
|
||||
../modbus/modbustcpmaster.cpp \
|
||||
../modbus/modbusdatautils.cpp
|
||||
integrationpluginhuawei.cpp
|
||||
|
||||
@ -98,11 +98,7 @@ void HuaweiFusionSolar::readNextRegister()
|
||||
const QModbusDataUnit unit = reply->result();
|
||||
const QVector<quint16> values = unit.values();
|
||||
qCDebug(dcHuaweiFusionSolar()) << "<-- Response from \"Inverter active power\" register" << 32080 << "size:" << 2 << values;
|
||||
float receivedInverterActivePower = ModbusDataUtils::convertToInt32(values, ModbusDataUtils::ByteOrderBigEndian) * 1.0 * pow(10, -3);
|
||||
if (m_inverterActivePower != receivedInverterActivePower) {
|
||||
m_inverterActivePower = receivedInverterActivePower;
|
||||
emit inverterActivePowerChanged(m_inverterActivePower);
|
||||
}
|
||||
processInverterActivePowerRegisterValues(values);
|
||||
}
|
||||
finishRequest();
|
||||
});
|
||||
@ -133,12 +129,8 @@ void HuaweiFusionSolar::readNextRegister()
|
||||
const QModbusDataUnit unit = reply->result();
|
||||
const QVector<quint16> values = unit.values();
|
||||
qCDebug(dcHuaweiFusionSolar()) << "<-- Response from \"Inverter device status\" register" << 32089 << "size:" << 1 << values;
|
||||
InverterDeviceStatus receivedInverterDeviceStatus = static_cast<InverterDeviceStatus>(ModbusDataUtils::convertToUInt16(values));
|
||||
qCDebug(dcHuaweiFusionSolar()) << "Inverter status" << receivedInverterDeviceStatus;
|
||||
if (m_inverterDeviceStatus != receivedInverterDeviceStatus) {
|
||||
m_inverterDeviceStatus = receivedInverterDeviceStatus;
|
||||
emit inverterDeviceStatusChanged(m_inverterDeviceStatus);
|
||||
}
|
||||
processInverterDeviceStatusRegisterValues(values);
|
||||
qCDebug(dcHuaweiFusionSolar()) << "Inverter status" << inverterDeviceStatus();
|
||||
}
|
||||
finishRequest();
|
||||
});
|
||||
@ -169,11 +161,7 @@ void HuaweiFusionSolar::readNextRegister()
|
||||
const QModbusDataUnit unit = reply->result();
|
||||
const QVector<quint16> values = unit.values();
|
||||
qCDebug(dcHuaweiFusionSolar()) << "<-- Response from \"Inverter energy produced\" register" << 32106 << "size:" << 2 << values;
|
||||
float receivedInverterEnergyProduced = ModbusDataUtils::convertToUInt32(values, ModbusDataUtils::ByteOrderBigEndian) * 1.0 * pow(10, -2);
|
||||
if (m_inverterEnergyProduced != receivedInverterEnergyProduced) {
|
||||
m_inverterEnergyProduced = receivedInverterEnergyProduced;
|
||||
emit inverterEnergyProducedChanged(m_inverterEnergyProduced);
|
||||
}
|
||||
processInverterEnergyProducedRegisterValues(values);
|
||||
}
|
||||
finishRequest();
|
||||
});
|
||||
@ -204,18 +192,13 @@ void HuaweiFusionSolar::readNextRegister()
|
||||
const QModbusDataUnit unit = reply->result();
|
||||
const QVector<quint16> values = unit.values();
|
||||
qCDebug(dcHuaweiFusionSolar()) << "<-- Response from \"Luna 2000 Battery 1 status\" register" << 37000 << "size:" << 1 << values;
|
||||
BatteryDeviceStatus receivedLunaBattery1Status = static_cast<BatteryDeviceStatus>(ModbusDataUtils::convertToUInt16(values));
|
||||
qCDebug(dcHuaweiFusionSolar()) << "Battery 1 status" << receivedLunaBattery1Status;
|
||||
if (receivedLunaBattery1Status == BatteryDeviceStatusOffline) {
|
||||
processLunaBattery1StatusRegisterValues(values);
|
||||
qCDebug(dcHuaweiFusionSolar()) << "Battery 1 status" << m_lunaBattery1Status;
|
||||
if (m_lunaBattery1Status == BatteryDeviceStatusOffline) {
|
||||
m_battery1Available = false;
|
||||
} else {
|
||||
m_battery1Available = true;
|
||||
}
|
||||
|
||||
if (m_lunaBattery1Status != receivedLunaBattery1Status) {
|
||||
m_lunaBattery1Status = receivedLunaBattery1Status;
|
||||
emit lunaBattery1StatusChanged(m_lunaBattery1Status);
|
||||
}
|
||||
}
|
||||
finishRequest();
|
||||
});
|
||||
@ -246,11 +229,7 @@ void HuaweiFusionSolar::readNextRegister()
|
||||
const QModbusDataUnit unit = reply->result();
|
||||
const QVector<quint16> values = unit.values();
|
||||
qCDebug(dcHuaweiFusionSolar()) << "<-- Response from \"Luna 2000 Battery 1 power\" register" << 37001 << "size:" << 2 << values;
|
||||
qint32 receivedLunaBattery1Power = ModbusDataUtils::convertToInt32(values, ModbusDataUtils::ByteOrderBigEndian);
|
||||
if (m_lunaBattery1Power != receivedLunaBattery1Power) {
|
||||
m_lunaBattery1Power = receivedLunaBattery1Power;
|
||||
emit lunaBattery1PowerChanged(m_lunaBattery1Power);
|
||||
}
|
||||
processLunaBattery1PowerRegisterValues(values);
|
||||
}
|
||||
finishRequest();
|
||||
});
|
||||
@ -281,11 +260,7 @@ void HuaweiFusionSolar::readNextRegister()
|
||||
const QModbusDataUnit unit = reply->result();
|
||||
const QVector<quint16> values = unit.values();
|
||||
qCDebug(dcHuaweiFusionSolar()) << "<-- Response from \"Luna 2000 Battery 1 state of charge\" register" << 37004 << "size:" << 1 << values;
|
||||
float receivedLunaBattery1Soc = ModbusDataUtils::convertToUInt16(values) * 1.0 * pow(10, -1);
|
||||
if (m_lunaBattery1Soc != receivedLunaBattery1Soc) {
|
||||
m_lunaBattery1Soc = receivedLunaBattery1Soc;
|
||||
emit lunaBattery1SocChanged(m_lunaBattery1Soc);
|
||||
}
|
||||
processLunaBattery1SocRegisterValues(values);
|
||||
}
|
||||
finishRequest();
|
||||
});
|
||||
@ -316,11 +291,7 @@ void HuaweiFusionSolar::readNextRegister()
|
||||
const QModbusDataUnit unit = reply->result();
|
||||
const QVector<quint16> values = unit.values();
|
||||
qCDebug(dcHuaweiFusionSolar()) << "<-- Response from \"Power meter active power\" register" << 37113 << "size:" << 2 << values;
|
||||
qint32 receivedPowerMeterActivePower = ModbusDataUtils::convertToInt32(values, ModbusDataUtils::ByteOrderBigEndian);
|
||||
if (m_powerMeterActivePower != receivedPowerMeterActivePower) {
|
||||
m_powerMeterActivePower = receivedPowerMeterActivePower;
|
||||
emit powerMeterActivePowerChanged(m_powerMeterActivePower);
|
||||
}
|
||||
processPowerMeterActivePowerRegisterValues(values);
|
||||
}
|
||||
finishRequest();
|
||||
});
|
||||
@ -351,17 +322,13 @@ void HuaweiFusionSolar::readNextRegister()
|
||||
const QModbusDataUnit unit = reply->result();
|
||||
const QVector<quint16> values = unit.values();
|
||||
qCDebug(dcHuaweiFusionSolar()) << "<-- Response from \"Luna 2000 Battery 2 status\" register" << 37741 << "size:" << 1 << values;
|
||||
BatteryDeviceStatus receivedLunaBattery2Status = static_cast<BatteryDeviceStatus>(ModbusDataUtils::convertToUInt16(values));
|
||||
qCDebug(dcHuaweiFusionSolar()) << "Battery 2 status" << receivedLunaBattery2Status;
|
||||
if (receivedLunaBattery2Status == BatteryDeviceStatusOffline) {
|
||||
processLunaBattery2StatusRegisterValues(values);
|
||||
qCDebug(dcHuaweiFusionSolar()) << "Battery 2 status" << m_lunaBattery2Status;
|
||||
if (m_lunaBattery2Status == BatteryDeviceStatusOffline) {
|
||||
m_battery2Available = false;
|
||||
} else {
|
||||
m_battery2Available = true;
|
||||
}
|
||||
if (m_lunaBattery2Status != receivedLunaBattery2Status) {
|
||||
m_lunaBattery2Status = receivedLunaBattery2Status;
|
||||
emit lunaBattery2StatusChanged(m_lunaBattery2Status);
|
||||
}
|
||||
}
|
||||
finishRequest();
|
||||
});
|
||||
@ -392,11 +359,7 @@ void HuaweiFusionSolar::readNextRegister()
|
||||
const QModbusDataUnit unit = reply->result();
|
||||
const QVector<quint16> values = unit.values();
|
||||
qCDebug(dcHuaweiFusionSolar()) << "<-- Response from \"Luna 2000 Battery 2 power\" register" << 37743 << "size:" << 2 << values;
|
||||
qint32 receivedLunaBattery2Power = ModbusDataUtils::convertToInt32(values, ModbusDataUtils::ByteOrderBigEndian);
|
||||
if (m_lunaBattery2Power != receivedLunaBattery2Power) {
|
||||
m_lunaBattery2Power = receivedLunaBattery2Power;
|
||||
emit lunaBattery2PowerChanged(m_lunaBattery2Power);
|
||||
}
|
||||
processLunaBattery2PowerRegisterValues(values);
|
||||
}
|
||||
finishRequest();
|
||||
});
|
||||
@ -427,11 +390,7 @@ void HuaweiFusionSolar::readNextRegister()
|
||||
const QModbusDataUnit unit = reply->result();
|
||||
const QVector<quint16> values = unit.values();
|
||||
qCDebug(dcHuaweiFusionSolar()) << "<-- Response from \"Luna 2000 Battery 2 state of charge\" register" << 37738 << "size:" << 1 << values;
|
||||
float receivedLunaBattery2Soc = ModbusDataUtils::convertToUInt16(values) * 1.0 * pow(10, -1);
|
||||
if (m_lunaBattery2Soc != receivedLunaBattery2Soc) {
|
||||
m_lunaBattery2Soc = receivedLunaBattery2Soc;
|
||||
emit lunaBattery2SocChanged(m_lunaBattery2Soc);
|
||||
}
|
||||
processLunaBattery2SocRegisterValues(values);
|
||||
}
|
||||
finishRequest();
|
||||
});
|
||||
|
||||
@ -1,523 +0,0 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2022, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This fileDescriptor 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 "huaweimodbustcpconnection.h"
|
||||
#include "loggingcategories.h"
|
||||
|
||||
NYMEA_LOGGING_CATEGORY(dcHuaweiModbusTcpConnection, "HuaweiModbusTcpConnection")
|
||||
|
||||
HuaweiModbusTcpConnection::HuaweiModbusTcpConnection(const QHostAddress &hostAddress, uint port, quint16 slaveId, QObject *parent) :
|
||||
ModbusTCPMaster(hostAddress, port, parent),
|
||||
m_slaveId(slaveId)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
float HuaweiModbusTcpConnection::inverterActivePower() const
|
||||
{
|
||||
return m_inverterActivePower;
|
||||
}
|
||||
|
||||
HuaweiModbusTcpConnection::InverterDeviceStatus HuaweiModbusTcpConnection::inverterDeviceStatus() const
|
||||
{
|
||||
return m_inverterDeviceStatus;
|
||||
}
|
||||
|
||||
float HuaweiModbusTcpConnection::inverterEnergyProduced() const
|
||||
{
|
||||
return m_inverterEnergyProduced;
|
||||
}
|
||||
|
||||
qint32 HuaweiModbusTcpConnection::powerMeterActivePower() const
|
||||
{
|
||||
return m_powerMeterActivePower;
|
||||
}
|
||||
|
||||
HuaweiModbusTcpConnection::BatteryDeviceStatus HuaweiModbusTcpConnection::lunaBattery1Status() const
|
||||
{
|
||||
return m_lunaBattery1Status;
|
||||
}
|
||||
|
||||
qint32 HuaweiModbusTcpConnection::lunaBattery1Power() const
|
||||
{
|
||||
return m_lunaBattery1Power;
|
||||
}
|
||||
|
||||
float HuaweiModbusTcpConnection::lunaBattery1Soc() const
|
||||
{
|
||||
return m_lunaBattery1Soc;
|
||||
}
|
||||
|
||||
HuaweiModbusTcpConnection::BatteryDeviceStatus HuaweiModbusTcpConnection::lunaBattery2Status() const
|
||||
{
|
||||
return m_lunaBattery2Status;
|
||||
}
|
||||
|
||||
qint32 HuaweiModbusTcpConnection::lunaBattery2Power() const
|
||||
{
|
||||
return m_lunaBattery2Power;
|
||||
}
|
||||
|
||||
float HuaweiModbusTcpConnection::lunaBattery2Soc() const
|
||||
{
|
||||
return m_lunaBattery2Soc;
|
||||
}
|
||||
|
||||
void HuaweiModbusTcpConnection::initialize()
|
||||
{
|
||||
// No init registers defined. Nothing to be done and we are finished.
|
||||
emit initializationFinished();
|
||||
}
|
||||
|
||||
void HuaweiModbusTcpConnection::update()
|
||||
{
|
||||
updateInverterActivePower();
|
||||
updateInverterDeviceStatus();
|
||||
updateInverterEnergyProduced();
|
||||
updatePowerMeterActivePower();
|
||||
updateLunaBattery1Status();
|
||||
updateLunaBattery1Power();
|
||||
updateLunaBattery1Soc();
|
||||
updateLunaBattery2Status();
|
||||
updateLunaBattery2Power();
|
||||
updateLunaBattery2Soc();
|
||||
}
|
||||
|
||||
void HuaweiModbusTcpConnection::updateInverterActivePower()
|
||||
{
|
||||
// Update registers from Inverter active power
|
||||
qCDebug(dcHuaweiModbusTcpConnection()) << "--> Read \"Inverter active power\" register:" << 32080 << "size:" << 2;
|
||||
QModbusReply *reply = readInverterActivePower();
|
||||
if (reply) {
|
||||
if (!reply->isFinished()) {
|
||||
connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater);
|
||||
connect(reply, &QModbusReply::finished, this, [this, reply](){
|
||||
if (reply->error() == QModbusDevice::NoError) {
|
||||
const QModbusDataUnit unit = reply->result();
|
||||
const QVector<quint16> values = unit.values();
|
||||
qCDebug(dcHuaweiModbusTcpConnection()) << "<-- Response from \"Inverter active power\" register" << 32080 << "size:" << 2 << values;
|
||||
float receivedInverterActivePower = ModbusDataUtils::convertToInt32(values, ModbusDataUtils::ByteOrderBigEndian) * 1.0 * pow(10, -3);
|
||||
if (m_inverterActivePower != receivedInverterActivePower) {
|
||||
m_inverterActivePower = receivedInverterActivePower;
|
||||
emit inverterActivePowerChanged(m_inverterActivePower);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){
|
||||
qCWarning(dcHuaweiModbusTcpConnection()) << "Modbus reply error occurred while updating \"Inverter active power\" registers from" << hostAddress().toString() << error << reply->errorString();
|
||||
emit reply->finished(); // To make sure it will be deleted
|
||||
});
|
||||
} else {
|
||||
delete reply; // Broadcast reply returns immediatly
|
||||
}
|
||||
} else {
|
||||
qCWarning(dcHuaweiModbusTcpConnection()) << "Error occurred while reading \"Inverter active power\" registers from" << hostAddress().toString() << errorString();
|
||||
}
|
||||
}
|
||||
|
||||
void HuaweiModbusTcpConnection::updateInverterDeviceStatus()
|
||||
{
|
||||
// Update registers from Inverter device status
|
||||
qCDebug(dcHuaweiModbusTcpConnection()) << "--> Read \"Inverter device status\" register:" << 32089 << "size:" << 1;
|
||||
QModbusReply *reply = readInverterDeviceStatus();
|
||||
if (reply) {
|
||||
if (!reply->isFinished()) {
|
||||
connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater);
|
||||
connect(reply, &QModbusReply::finished, this, [this, reply](){
|
||||
if (reply->error() == QModbusDevice::NoError) {
|
||||
const QModbusDataUnit unit = reply->result();
|
||||
const QVector<quint16> values = unit.values();
|
||||
qCDebug(dcHuaweiModbusTcpConnection()) << "<-- Response from \"Inverter device status\" register" << 32089 << "size:" << 1 << values;
|
||||
InverterDeviceStatus receivedInverterDeviceStatus = static_cast<InverterDeviceStatus>(ModbusDataUtils::convertToUInt16(values));
|
||||
if (m_inverterDeviceStatus != receivedInverterDeviceStatus) {
|
||||
m_inverterDeviceStatus = receivedInverterDeviceStatus;
|
||||
emit inverterDeviceStatusChanged(m_inverterDeviceStatus);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){
|
||||
qCWarning(dcHuaweiModbusTcpConnection()) << "Modbus reply error occurred while updating \"Inverter device status\" registers from" << hostAddress().toString() << error << reply->errorString();
|
||||
emit reply->finished(); // To make sure it will be deleted
|
||||
});
|
||||
} else {
|
||||
delete reply; // Broadcast reply returns immediatly
|
||||
}
|
||||
} else {
|
||||
qCWarning(dcHuaweiModbusTcpConnection()) << "Error occurred while reading \"Inverter device status\" registers from" << hostAddress().toString() << errorString();
|
||||
}
|
||||
}
|
||||
|
||||
void HuaweiModbusTcpConnection::updateInverterEnergyProduced()
|
||||
{
|
||||
// Update registers from Inverter energy produced
|
||||
qCDebug(dcHuaweiModbusTcpConnection()) << "--> Read \"Inverter energy produced\" register:" << 32106 << "size:" << 2;
|
||||
QModbusReply *reply = readInverterEnergyProduced();
|
||||
if (reply) {
|
||||
if (!reply->isFinished()) {
|
||||
connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater);
|
||||
connect(reply, &QModbusReply::finished, this, [this, reply](){
|
||||
if (reply->error() == QModbusDevice::NoError) {
|
||||
const QModbusDataUnit unit = reply->result();
|
||||
const QVector<quint16> values = unit.values();
|
||||
qCDebug(dcHuaweiModbusTcpConnection()) << "<-- Response from \"Inverter energy produced\" register" << 32106 << "size:" << 2 << values;
|
||||
float receivedInverterEnergyProduced = ModbusDataUtils::convertToUInt32(values, ModbusDataUtils::ByteOrderBigEndian) * 1.0 * pow(10, -2);
|
||||
if (m_inverterEnergyProduced != receivedInverterEnergyProduced) {
|
||||
m_inverterEnergyProduced = receivedInverterEnergyProduced;
|
||||
emit inverterEnergyProducedChanged(m_inverterEnergyProduced);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){
|
||||
qCWarning(dcHuaweiModbusTcpConnection()) << "Modbus reply error occurred while updating \"Inverter energy produced\" registers from" << hostAddress().toString() << error << reply->errorString();
|
||||
emit reply->finished(); // To make sure it will be deleted
|
||||
});
|
||||
} else {
|
||||
delete reply; // Broadcast reply returns immediatly
|
||||
}
|
||||
} else {
|
||||
qCWarning(dcHuaweiModbusTcpConnection()) << "Error occurred while reading \"Inverter energy produced\" registers from" << hostAddress().toString() << errorString();
|
||||
}
|
||||
}
|
||||
|
||||
void HuaweiModbusTcpConnection::updatePowerMeterActivePower()
|
||||
{
|
||||
// Update registers from Power meter active power
|
||||
qCDebug(dcHuaweiModbusTcpConnection()) << "--> Read \"Power meter active power\" register:" << 37113 << "size:" << 2;
|
||||
QModbusReply *reply = readPowerMeterActivePower();
|
||||
if (reply) {
|
||||
if (!reply->isFinished()) {
|
||||
connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater);
|
||||
connect(reply, &QModbusReply::finished, this, [this, reply](){
|
||||
if (reply->error() == QModbusDevice::NoError) {
|
||||
const QModbusDataUnit unit = reply->result();
|
||||
const QVector<quint16> values = unit.values();
|
||||
qCDebug(dcHuaweiModbusTcpConnection()) << "<-- Response from \"Power meter active power\" register" << 37113 << "size:" << 2 << values;
|
||||
qint32 receivedPowerMeterActivePower = ModbusDataUtils::convertToInt32(values, ModbusDataUtils::ByteOrderBigEndian);
|
||||
if (m_powerMeterActivePower != receivedPowerMeterActivePower) {
|
||||
m_powerMeterActivePower = receivedPowerMeterActivePower;
|
||||
emit powerMeterActivePowerChanged(m_powerMeterActivePower);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){
|
||||
qCWarning(dcHuaweiModbusTcpConnection()) << "Modbus reply error occurred while updating \"Power meter active power\" registers from" << hostAddress().toString() << error << reply->errorString();
|
||||
emit reply->finished(); // To make sure it will be deleted
|
||||
});
|
||||
} else {
|
||||
delete reply; // Broadcast reply returns immediatly
|
||||
}
|
||||
} else {
|
||||
qCWarning(dcHuaweiModbusTcpConnection()) << "Error occurred while reading \"Power meter active power\" registers from" << hostAddress().toString() << errorString();
|
||||
}
|
||||
}
|
||||
|
||||
void HuaweiModbusTcpConnection::updateLunaBattery1Status()
|
||||
{
|
||||
// Update registers from Luna 2000 Battery 1 status
|
||||
qCDebug(dcHuaweiModbusTcpConnection()) << "--> Read \"Luna 2000 Battery 1 status\" register:" << 37000 << "size:" << 1;
|
||||
QModbusReply *reply = readLunaBattery1Status();
|
||||
if (reply) {
|
||||
if (!reply->isFinished()) {
|
||||
connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater);
|
||||
connect(reply, &QModbusReply::finished, this, [this, reply](){
|
||||
if (reply->error() == QModbusDevice::NoError) {
|
||||
const QModbusDataUnit unit = reply->result();
|
||||
const QVector<quint16> values = unit.values();
|
||||
qCDebug(dcHuaweiModbusTcpConnection()) << "<-- Response from \"Luna 2000 Battery 1 status\" register" << 37000 << "size:" << 1 << values;
|
||||
BatteryDeviceStatus receivedLunaBattery1Status = static_cast<BatteryDeviceStatus>(ModbusDataUtils::convertToUInt16(values));
|
||||
m_lunaBattery1Status = receivedLunaBattery1Status;
|
||||
emit lunaBattery1StatusChanged(m_lunaBattery1Status);
|
||||
}
|
||||
});
|
||||
|
||||
connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){
|
||||
qCWarning(dcHuaweiModbusTcpConnection()) << "Modbus reply error occurred while updating \"Luna 2000 Battery 1 status\" registers from" << hostAddress().toString() << error << reply->errorString();
|
||||
emit reply->finished(); // To make sure it will be deleted
|
||||
});
|
||||
} else {
|
||||
delete reply; // Broadcast reply returns immediatly
|
||||
}
|
||||
} else {
|
||||
qCWarning(dcHuaweiModbusTcpConnection()) << "Error occurred while reading \"Luna 2000 Battery 1 status\" registers from" << hostAddress().toString() << errorString();
|
||||
}
|
||||
}
|
||||
|
||||
void HuaweiModbusTcpConnection::updateLunaBattery1Power()
|
||||
{
|
||||
// Update registers from Luna 2000 Battery 1 power
|
||||
qCDebug(dcHuaweiModbusTcpConnection()) << "--> Read \"Luna 2000 Battery 1 power\" register:" << 37001 << "size:" << 2;
|
||||
QModbusReply *reply = readLunaBattery1Power();
|
||||
if (reply) {
|
||||
if (!reply->isFinished()) {
|
||||
connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater);
|
||||
connect(reply, &QModbusReply::finished, this, [this, reply](){
|
||||
if (reply->error() == QModbusDevice::NoError) {
|
||||
const QModbusDataUnit unit = reply->result();
|
||||
const QVector<quint16> values = unit.values();
|
||||
qCDebug(dcHuaweiModbusTcpConnection()) << "<-- Response from \"Luna 2000 Battery 1 power\" register" << 37001 << "size:" << 2 << values;
|
||||
qint32 receivedLunaBattery1Power = ModbusDataUtils::convertToInt32(values, ModbusDataUtils::ByteOrderBigEndian);
|
||||
if (m_lunaBattery1Power != receivedLunaBattery1Power) {
|
||||
m_lunaBattery1Power = receivedLunaBattery1Power;
|
||||
emit lunaBattery1PowerChanged(m_lunaBattery1Power);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){
|
||||
qCWarning(dcHuaweiModbusTcpConnection()) << "Modbus reply error occurred while updating \"Luna 2000 Battery 1 power\" registers from" << hostAddress().toString() << error << reply->errorString();
|
||||
emit reply->finished(); // To make sure it will be deleted
|
||||
});
|
||||
} else {
|
||||
delete reply; // Broadcast reply returns immediatly
|
||||
}
|
||||
} else {
|
||||
qCWarning(dcHuaweiModbusTcpConnection()) << "Error occurred while reading \"Luna 2000 Battery 1 power\" registers from" << hostAddress().toString() << errorString();
|
||||
}
|
||||
}
|
||||
|
||||
void HuaweiModbusTcpConnection::updateLunaBattery1Soc()
|
||||
{
|
||||
// Update registers from Luna 2000 Battery 1 state of charge
|
||||
qCDebug(dcHuaweiModbusTcpConnection()) << "--> Read \"Luna 2000 Battery 1 state of charge\" register:" << 37004 << "size:" << 1;
|
||||
QModbusReply *reply = readLunaBattery1Soc();
|
||||
if (reply) {
|
||||
if (!reply->isFinished()) {
|
||||
connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater);
|
||||
connect(reply, &QModbusReply::finished, this, [this, reply](){
|
||||
if (reply->error() == QModbusDevice::NoError) {
|
||||
const QModbusDataUnit unit = reply->result();
|
||||
const QVector<quint16> values = unit.values();
|
||||
qCDebug(dcHuaweiModbusTcpConnection()) << "<-- Response from \"Luna 2000 Battery 1 state of charge\" register" << 37004 << "size:" << 1 << values;
|
||||
float receivedLunaBattery1Soc = ModbusDataUtils::convertToUInt16(values) * 1.0 * pow(10, -1);
|
||||
if (m_lunaBattery1Soc != receivedLunaBattery1Soc) {
|
||||
m_lunaBattery1Soc = receivedLunaBattery1Soc;
|
||||
emit lunaBattery1SocChanged(m_lunaBattery1Soc);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){
|
||||
qCWarning(dcHuaweiModbusTcpConnection()) << "Modbus reply error occurred while updating \"Luna 2000 Battery 1 state of charge\" registers from" << hostAddress().toString() << error << reply->errorString();
|
||||
emit reply->finished(); // To make sure it will be deleted
|
||||
});
|
||||
} else {
|
||||
delete reply; // Broadcast reply returns immediatly
|
||||
}
|
||||
} else {
|
||||
qCWarning(dcHuaweiModbusTcpConnection()) << "Error occurred while reading \"Luna 2000 Battery 1 state of charge\" registers from" << hostAddress().toString() << errorString();
|
||||
}
|
||||
}
|
||||
|
||||
void HuaweiModbusTcpConnection::updateLunaBattery2Status()
|
||||
{
|
||||
// Update registers from Luna 2000 Battery 2 status
|
||||
qCDebug(dcHuaweiModbusTcpConnection()) << "--> Read \"Luna 2000 Battery 2 status\" register:" << 37741 << "size:" << 1;
|
||||
QModbusReply *reply = readLunaBattery2Status();
|
||||
if (reply) {
|
||||
if (!reply->isFinished()) {
|
||||
connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater);
|
||||
connect(reply, &QModbusReply::finished, this, [this, reply](){
|
||||
if (reply->error() == QModbusDevice::NoError) {
|
||||
const QModbusDataUnit unit = reply->result();
|
||||
const QVector<quint16> values = unit.values();
|
||||
qCDebug(dcHuaweiModbusTcpConnection()) << "<-- Response from \"Luna 2000 Battery 2 status\" register" << 37741 << "size:" << 1 << values;
|
||||
BatteryDeviceStatus receivedLunaBattery2Status = static_cast<BatteryDeviceStatus>(ModbusDataUtils::convertToUInt16(values));
|
||||
m_lunaBattery2Status = receivedLunaBattery2Status;
|
||||
emit lunaBattery2StatusChanged(m_lunaBattery2Status);
|
||||
}
|
||||
});
|
||||
|
||||
connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){
|
||||
qCWarning(dcHuaweiModbusTcpConnection()) << "Modbus reply error occurred while updating \"Luna 2000 Battery 2 status\" registers from" << hostAddress().toString() << error << reply->errorString();
|
||||
emit reply->finished(); // To make sure it will be deleted
|
||||
});
|
||||
} else {
|
||||
delete reply; // Broadcast reply returns immediatly
|
||||
}
|
||||
} else {
|
||||
qCWarning(dcHuaweiModbusTcpConnection()) << "Error occurred while reading \"Luna 2000 Battery 2 status\" registers from" << hostAddress().toString() << errorString();
|
||||
}
|
||||
}
|
||||
|
||||
void HuaweiModbusTcpConnection::updateLunaBattery2Power()
|
||||
{
|
||||
// Update registers from Luna 2000 Battery 2 power
|
||||
qCDebug(dcHuaweiModbusTcpConnection()) << "--> Read \"Luna 2000 Battery 2 power\" register:" << 37743 << "size:" << 2;
|
||||
QModbusReply *reply = readLunaBattery2Power();
|
||||
if (reply) {
|
||||
if (!reply->isFinished()) {
|
||||
connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater);
|
||||
connect(reply, &QModbusReply::finished, this, [this, reply](){
|
||||
if (reply->error() == QModbusDevice::NoError) {
|
||||
const QModbusDataUnit unit = reply->result();
|
||||
const QVector<quint16> values = unit.values();
|
||||
qCDebug(dcHuaweiModbusTcpConnection()) << "<-- Response from \"Luna 2000 Battery 2 power\" register" << 37743 << "size:" << 2 << values;
|
||||
qint32 receivedLunaBattery2Power = ModbusDataUtils::convertToInt32(values, ModbusDataUtils::ByteOrderBigEndian);
|
||||
if (m_lunaBattery2Power != receivedLunaBattery2Power) {
|
||||
m_lunaBattery2Power = receivedLunaBattery2Power;
|
||||
emit lunaBattery2PowerChanged(m_lunaBattery2Power);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){
|
||||
qCWarning(dcHuaweiModbusTcpConnection()) << "Modbus reply error occurred while updating \"Luna 2000 Battery 2 power\" registers from" << hostAddress().toString() << error << reply->errorString();
|
||||
emit reply->finished(); // To make sure it will be deleted
|
||||
});
|
||||
} else {
|
||||
delete reply; // Broadcast reply returns immediatly
|
||||
}
|
||||
} else {
|
||||
qCWarning(dcHuaweiModbusTcpConnection()) << "Error occurred while reading \"Luna 2000 Battery 2 power\" registers from" << hostAddress().toString() << errorString();
|
||||
}
|
||||
}
|
||||
|
||||
void HuaweiModbusTcpConnection::updateLunaBattery2Soc()
|
||||
{
|
||||
// Update registers from Luna 2000 Battery 2 state of charge
|
||||
qCDebug(dcHuaweiModbusTcpConnection()) << "--> Read \"Luna 2000 Battery 2 state of charge\" register:" << 37738 << "size:" << 1;
|
||||
QModbusReply *reply = readLunaBattery2Soc();
|
||||
if (reply) {
|
||||
if (!reply->isFinished()) {
|
||||
connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater);
|
||||
connect(reply, &QModbusReply::finished, this, [this, reply](){
|
||||
if (reply->error() == QModbusDevice::NoError) {
|
||||
const QModbusDataUnit unit = reply->result();
|
||||
const QVector<quint16> values = unit.values();
|
||||
qCDebug(dcHuaweiModbusTcpConnection()) << "<-- Response from \"Luna 2000 Battery 2 state of charge\" register" << 37738 << "size:" << 1 << values;
|
||||
float receivedLunaBattery2Soc = ModbusDataUtils::convertToUInt16(values) * 1.0 * pow(10, -1);
|
||||
if (m_lunaBattery2Soc != receivedLunaBattery2Soc) {
|
||||
m_lunaBattery2Soc = receivedLunaBattery2Soc;
|
||||
emit lunaBattery2SocChanged(m_lunaBattery2Soc);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){
|
||||
qCWarning(dcHuaweiModbusTcpConnection()) << "Modbus reply error occurred while updating \"Luna 2000 Battery 2 state of charge\" registers from" << hostAddress().toString() << error << reply->errorString();
|
||||
emit reply->finished(); // To make sure it will be deleted
|
||||
});
|
||||
} else {
|
||||
delete reply; // Broadcast reply returns immediatly
|
||||
}
|
||||
} else {
|
||||
qCWarning(dcHuaweiModbusTcpConnection()) << "Error occurred while reading \"Luna 2000 Battery 2 state of charge\" registers from" << hostAddress().toString() << errorString();
|
||||
}
|
||||
}
|
||||
|
||||
QModbusReply *HuaweiModbusTcpConnection::readInverterActivePower()
|
||||
{
|
||||
QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, 32080, 2);
|
||||
return sendReadRequest(request, m_slaveId);
|
||||
}
|
||||
|
||||
QModbusReply *HuaweiModbusTcpConnection::readInverterDeviceStatus()
|
||||
{
|
||||
QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, 32089, 1);
|
||||
return sendReadRequest(request, m_slaveId);
|
||||
}
|
||||
|
||||
QModbusReply *HuaweiModbusTcpConnection::readInverterEnergyProduced()
|
||||
{
|
||||
QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, 32106, 2);
|
||||
return sendReadRequest(request, m_slaveId);
|
||||
}
|
||||
|
||||
QModbusReply *HuaweiModbusTcpConnection::readPowerMeterActivePower()
|
||||
{
|
||||
QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, 37113, 2);
|
||||
return sendReadRequest(request, m_slaveId);
|
||||
}
|
||||
|
||||
QModbusReply *HuaweiModbusTcpConnection::readLunaBattery1Status()
|
||||
{
|
||||
QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, 37000, 1);
|
||||
return sendReadRequest(request, m_slaveId);
|
||||
}
|
||||
|
||||
QModbusReply *HuaweiModbusTcpConnection::readLunaBattery1Power()
|
||||
{
|
||||
QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, 37001, 2);
|
||||
return sendReadRequest(request, m_slaveId);
|
||||
}
|
||||
|
||||
QModbusReply *HuaweiModbusTcpConnection::readLunaBattery1Soc()
|
||||
{
|
||||
QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, 37004, 1);
|
||||
return sendReadRequest(request, m_slaveId);
|
||||
}
|
||||
|
||||
QModbusReply *HuaweiModbusTcpConnection::readLunaBattery2Status()
|
||||
{
|
||||
QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, 37741, 1);
|
||||
return sendReadRequest(request, m_slaveId);
|
||||
}
|
||||
|
||||
QModbusReply *HuaweiModbusTcpConnection::readLunaBattery2Power()
|
||||
{
|
||||
QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, 37743, 2);
|
||||
return sendReadRequest(request, m_slaveId);
|
||||
}
|
||||
|
||||
QModbusReply *HuaweiModbusTcpConnection::readLunaBattery2Soc()
|
||||
{
|
||||
QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, 37738, 1);
|
||||
return sendReadRequest(request, m_slaveId);
|
||||
}
|
||||
|
||||
void HuaweiModbusTcpConnection::verifyInitFinished()
|
||||
{
|
||||
if (m_pendingInitReplies.isEmpty()) {
|
||||
qCDebug(dcHuaweiModbusTcpConnection()) << "Initialization finished of HuaweiModbusTcpConnection" << hostAddress().toString();
|
||||
emit initializationFinished();
|
||||
}
|
||||
}
|
||||
|
||||
QDebug operator<<(QDebug debug, HuaweiModbusTcpConnection *huaweiModbusTcpConnection)
|
||||
{
|
||||
debug.nospace().noquote() << "HuaweiModbusTcpConnection(" << huaweiModbusTcpConnection->hostAddress().toString() << ":" << huaweiModbusTcpConnection->port() << ")" << "\n";
|
||||
debug.nospace().noquote() << " - Inverter active power:" << huaweiModbusTcpConnection->inverterActivePower() << " [kW]" << "\n";
|
||||
debug.nospace().noquote() << " - Inverter device status:" << huaweiModbusTcpConnection->inverterDeviceStatus() << "\n";
|
||||
debug.nospace().noquote() << " - Inverter energy produced:" << huaweiModbusTcpConnection->inverterEnergyProduced() << " [kWh]" << "\n";
|
||||
debug.nospace().noquote() << " - Power meter active power:" << huaweiModbusTcpConnection->powerMeterActivePower() << " [W]" << "\n";
|
||||
debug.nospace().noquote() << " - Luna 2000 Battery 1 status:" << huaweiModbusTcpConnection->lunaBattery1Status() << "\n";
|
||||
debug.nospace().noquote() << " - Luna 2000 Battery 1 power:" << huaweiModbusTcpConnection->lunaBattery1Power() << " [W]" << "\n";
|
||||
debug.nospace().noquote() << " - Luna 2000 Battery 1 state of charge:" << huaweiModbusTcpConnection->lunaBattery1Soc() << " [%]" << "\n";
|
||||
debug.nospace().noquote() << " - Luna 2000 Battery 2 status:" << huaweiModbusTcpConnection->lunaBattery2Status() << "\n";
|
||||
debug.nospace().noquote() << " - Luna 2000 Battery 2 power:" << huaweiModbusTcpConnection->lunaBattery2Power() << " [W]" << "\n";
|
||||
debug.nospace().noquote() << " - Luna 2000 Battery 2 state of charge:" << huaweiModbusTcpConnection->lunaBattery2Soc() << " [%]" << "\n";
|
||||
return debug.quote().space();
|
||||
}
|
||||
|
||||
@ -1,194 +0,0 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2022, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This fileDescriptor 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 HUAWEIMODBUSTCPCONNECTION_H
|
||||
#define HUAWEIMODBUSTCPCONNECTION_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include "../modbus/modbusdatautils.h"
|
||||
#include "../modbus/modbustcpmaster.h"
|
||||
|
||||
class HuaweiModbusTcpConnection : public ModbusTCPMaster
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum Registers {
|
||||
RegisterInverterActivePower = 32080,
|
||||
RegisterInverterDeviceStatus = 32089,
|
||||
RegisterInverterEnergyProduced = 32106,
|
||||
RegisterLunaBattery1Status = 37000,
|
||||
RegisterLunaBattery1Power = 37001,
|
||||
RegisterLunaBattery1Soc = 37004,
|
||||
RegisterPowerMeterActivePower = 37113,
|
||||
RegisterLunaBattery2Soc = 37738,
|
||||
RegisterLunaBattery2Status = 37741,
|
||||
RegisterLunaBattery2Power = 37743
|
||||
};
|
||||
Q_ENUM(Registers)
|
||||
|
||||
enum InverterDeviceStatus {
|
||||
InverterDeviceStatusStandbyInitializing = 0,
|
||||
InverterDeviceStatusStandbyDetectingInsulationResistance = 1,
|
||||
InverterDeviceStatusStandbyDetectingIrradiation = 2,
|
||||
InverterDeviceStatusStandbyDridDetecting = 3,
|
||||
InverterDeviceStatusStarting = 256,
|
||||
InverterDeviceStatusOnGrid = 512,
|
||||
InverterDeviceStatusPowerLimited = 513,
|
||||
InverterDeviceStatusSelfDerating = 514,
|
||||
InverterDeviceStatusShutdownFault = 768,
|
||||
InverterDeviceStatusShutdownCommand = 769,
|
||||
InverterDeviceStatusShutdownOVGR = 770,
|
||||
InverterDeviceStatusShutdownCommunicationDisconnected = 771,
|
||||
InverterDeviceStatusShutdownPowerLimit = 772,
|
||||
InverterDeviceStatusShutdownManualStartupRequired = 773,
|
||||
InverterDeviceStatusShutdownInputUnderpower = 774,
|
||||
InverterDeviceStatusGridSchedulingPCurve = 1025,
|
||||
InverterDeviceStatusGridSchedulingQUCurve = 1026,
|
||||
InverterDeviceStatusGridSchedulingPFUCurve = 1027,
|
||||
InverterDeviceStatusGridSchedulingDryContact = 1028,
|
||||
InverterDeviceStatusGridSchedulingQPCurve = 1029,
|
||||
InverterDeviceStatusSpotCheckReady = 1280,
|
||||
InverterDeviceStatusSpotChecking = 1281,
|
||||
InverterDeviceStatusInspecting = 1536,
|
||||
InverterDeviceStatusAfciSelfCheck = 1792,
|
||||
InverterDeviceStatusIVScanning = 2048,
|
||||
InverterDeviceStatusDCInputDetection = 2304,
|
||||
InverterDeviceStatusRunningOffGridCharging = 2560,
|
||||
InverterDeviceStatusStandbyNoIrradiation = 40960
|
||||
};
|
||||
Q_ENUM(InverterDeviceStatus)
|
||||
|
||||
enum BatteryDeviceStatus {
|
||||
BatteryDeviceStatusOffline = 0,
|
||||
BatteryDeviceStatusStandby = 1,
|
||||
BatteryDeviceStatusRunning = 1,
|
||||
BatteryDeviceStatusFault = 1,
|
||||
BatteryDeviceStatusSleepMode = 1
|
||||
};
|
||||
Q_ENUM(BatteryDeviceStatus)
|
||||
|
||||
explicit HuaweiModbusTcpConnection(const QHostAddress &hostAddress, uint port, quint16 slaveId, QObject *parent = nullptr);
|
||||
~HuaweiModbusTcpConnection() = default;
|
||||
|
||||
/* Inverter active power [kW] - Address: 32080, Size: 2 */
|
||||
float inverterActivePower() const;
|
||||
|
||||
/* Inverter device status - Address: 32089, Size: 1 */
|
||||
InverterDeviceStatus inverterDeviceStatus() const;
|
||||
|
||||
/* Inverter energy produced [kWh] - Address: 32106, Size: 2 */
|
||||
float inverterEnergyProduced() const;
|
||||
|
||||
/* Power meter active power [W] - Address: 37113, Size: 2 */
|
||||
qint32 powerMeterActivePower() const;
|
||||
|
||||
/* Luna 2000 Battery 1 status - Address: 37000, Size: 1 */
|
||||
BatteryDeviceStatus lunaBattery1Status() const;
|
||||
|
||||
/* Luna 2000 Battery 1 power [W] - Address: 37001, Size: 2 */
|
||||
qint32 lunaBattery1Power() const;
|
||||
|
||||
/* Luna 2000 Battery 1 state of charge [%] - Address: 37004, Size: 1 */
|
||||
float lunaBattery1Soc() const;
|
||||
|
||||
/* Luna 2000 Battery 2 status - Address: 37741, Size: 1 */
|
||||
BatteryDeviceStatus lunaBattery2Status() const;
|
||||
|
||||
/* Luna 2000 Battery 2 power [W] - Address: 37743, Size: 2 */
|
||||
qint32 lunaBattery2Power() const;
|
||||
|
||||
/* Luna 2000 Battery 2 state of charge [%] - Address: 37738, Size: 1 */
|
||||
float lunaBattery2Soc() const;
|
||||
|
||||
|
||||
virtual void initialize();
|
||||
virtual void update();
|
||||
|
||||
void updateInverterActivePower();
|
||||
void updateInverterDeviceStatus();
|
||||
void updateInverterEnergyProduced();
|
||||
void updatePowerMeterActivePower();
|
||||
void updateLunaBattery1Status();
|
||||
void updateLunaBattery1Power();
|
||||
void updateLunaBattery1Soc();
|
||||
void updateLunaBattery2Status();
|
||||
void updateLunaBattery2Power();
|
||||
void updateLunaBattery2Soc();
|
||||
|
||||
signals:
|
||||
void initializationFinished();
|
||||
|
||||
void inverterActivePowerChanged(float inverterActivePower);
|
||||
void inverterDeviceStatusChanged(InverterDeviceStatus inverterDeviceStatus);
|
||||
void inverterEnergyProducedChanged(float inverterEnergyProduced);
|
||||
void powerMeterActivePowerChanged(qint32 powerMeterActivePower);
|
||||
void lunaBattery1StatusChanged(BatteryDeviceStatus lunaBattery1Status);
|
||||
void lunaBattery1PowerChanged(qint32 lunaBattery1Power);
|
||||
void lunaBattery1SocChanged(float lunaBattery1Soc);
|
||||
void lunaBattery2StatusChanged(BatteryDeviceStatus lunaBattery2Status);
|
||||
void lunaBattery2PowerChanged(qint32 lunaBattery2Power);
|
||||
void lunaBattery2SocChanged(float lunaBattery2Soc);
|
||||
|
||||
protected:
|
||||
QModbusReply *readInverterActivePower();
|
||||
QModbusReply *readInverterDeviceStatus();
|
||||
QModbusReply *readInverterEnergyProduced();
|
||||
QModbusReply *readPowerMeterActivePower();
|
||||
QModbusReply *readLunaBattery1Status();
|
||||
QModbusReply *readLunaBattery1Power();
|
||||
QModbusReply *readLunaBattery1Soc();
|
||||
QModbusReply *readLunaBattery2Status();
|
||||
QModbusReply *readLunaBattery2Power();
|
||||
QModbusReply *readLunaBattery2Soc();
|
||||
|
||||
float m_inverterActivePower = 0;
|
||||
InverterDeviceStatus m_inverterDeviceStatus = InverterDeviceStatusStandbyInitializing;
|
||||
float m_inverterEnergyProduced = 0;
|
||||
qint32 m_powerMeterActivePower = 0;
|
||||
BatteryDeviceStatus m_lunaBattery1Status = BatteryDeviceStatusOffline;
|
||||
qint32 m_lunaBattery1Power = 0;
|
||||
float m_lunaBattery1Soc = 0;
|
||||
BatteryDeviceStatus m_lunaBattery2Status = BatteryDeviceStatusOffline;
|
||||
qint32 m_lunaBattery2Power = 0;
|
||||
float m_lunaBattery2Soc = 0;
|
||||
|
||||
private:
|
||||
quint16 m_slaveId = 1;
|
||||
QVector<QModbusReply *> m_pendingInitReplies;
|
||||
|
||||
void verifyInitFinished();
|
||||
|
||||
|
||||
};
|
||||
|
||||
QDebug operator<<(QDebug debug, HuaweiModbusTcpConnection *huaweiModbusTcpConnection);
|
||||
|
||||
#endif // HUAWEIMODBUSTCPCONNECTION_H
|
||||
@ -29,11 +29,11 @@
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#include "integrationpluginhuawei.h"
|
||||
|
||||
#include "network/networkdevicediscovery.h"
|
||||
#include "hardwaremanager.h"
|
||||
#include "plugininfo.h"
|
||||
|
||||
#include <network/networkdevicediscovery.h>
|
||||
#include <hardwaremanager.h>
|
||||
|
||||
IntegrationPluginHuawei::IntegrationPluginHuawei()
|
||||
{
|
||||
|
||||
|
||||
@ -31,8 +31,9 @@
|
||||
#ifndef INTEGRATIONPLUGINHUAWEI_H
|
||||
#define INTEGRATIONPLUGINHUAWEI_H
|
||||
|
||||
#include "plugintimer.h"
|
||||
#include "integrations/integrationplugin.h"
|
||||
#include <plugintimer.h>
|
||||
#include <integrations/integrationplugin.h>
|
||||
|
||||
#include "huaweifusionsolar.h"
|
||||
|
||||
class IntegrationPluginHuawei: public IntegrationPlugin
|
||||
|
||||
@ -30,7 +30,7 @@
|
||||
|
||||
#include "idm.h"
|
||||
#include "extern-plugininfo.h"
|
||||
#include "../modbus/modbushelpers.h"
|
||||
#include "modbushelpers.h"
|
||||
|
||||
#include <QTimer>
|
||||
|
||||
|
||||
@ -33,7 +33,7 @@
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include "../modbus/modbustcpmaster.h"
|
||||
#include <modbustcpmaster.h>
|
||||
|
||||
#include "idminfo.h"
|
||||
|
||||
|
||||
11
idm/idm.pro
11
idm/idm.pro
@ -1,19 +1,14 @@
|
||||
include(../plugins.pri)
|
||||
|
||||
QT += \
|
||||
network \
|
||||
serialbus \
|
||||
include(../modbus.pri)
|
||||
|
||||
SOURCES += \
|
||||
idm.cpp \
|
||||
integrationpluginidm.cpp \
|
||||
../modbus/modbustcpmaster.cpp \
|
||||
../modbus/modbushelpers.cpp \
|
||||
modbushelpers.cpp
|
||||
|
||||
HEADERS += \
|
||||
idm.h \
|
||||
idminfo.h \
|
||||
integrationpluginidm.h \
|
||||
../modbus/modbustcpmaster.h \
|
||||
../modbus/modbushelpers.h \
|
||||
modbushelpers.h
|
||||
|
||||
|
||||
@ -28,10 +28,11 @@
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#include "network/networkdevicediscovery.h"
|
||||
#include "integrationpluginidm.h"
|
||||
#include "plugininfo.h"
|
||||
|
||||
#include <network/networkdevicediscovery.h>
|
||||
|
||||
IntegrationPluginIdm::IntegrationPluginIdm()
|
||||
{
|
||||
|
||||
|
||||
@ -31,8 +31,9 @@
|
||||
#ifndef INTEGRATIONPLUGINIDM_H
|
||||
#define INTEGRATIONPLUGINIDM_H
|
||||
|
||||
#include "integrations/integrationplugin.h"
|
||||
#include "plugintimer.h"
|
||||
#include <integrations/integrationplugin.h>
|
||||
#include <plugintimer.h>
|
||||
|
||||
#include "idm.h"
|
||||
|
||||
#include <QUuid>
|
||||
|
||||
@ -1,14 +1,13 @@
|
||||
include(../plugins.pri)
|
||||
|
||||
QT += serialport serialbus
|
||||
# Generate modbus connection
|
||||
MODBUS_CONNECTIONS += pro380-registers.json
|
||||
#MODBUS_TOOLS_CONFIG += VERBOSE
|
||||
include(../modbus.pri)
|
||||
|
||||
HEADERS += \
|
||||
integrationplugininepro.h \
|
||||
pro380modbusrtuconnection.h \
|
||||
../modbus/modbusdatautils.h
|
||||
integrationplugininepro.h
|
||||
|
||||
SOURCES += \
|
||||
integrationplugininepro.cpp \
|
||||
pro380modbusrtuconnection.cpp \
|
||||
../modbus/modbusdatautils.cpp
|
||||
integrationplugininepro.cpp
|
||||
|
||||
|
||||
@ -45,7 +45,7 @@ void IntegrationPluginInepro::init()
|
||||
qCWarning(dcInepro()) << "Modbus RTU hardware resource removed for" << thing << ". The thing will not be functional any more until a new resource has been configured for it.";
|
||||
thing->setStateValue(pro380ConnectedStateTypeId, false);
|
||||
|
||||
delete m_pro380Connections.take(thing);
|
||||
delete m_connections.take(thing);
|
||||
}
|
||||
}
|
||||
});
|
||||
@ -101,9 +101,9 @@ void IntegrationPluginInepro::setupThing(ThingSetupInfo *info)
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_pro380Connections.contains(thing)) {
|
||||
if (m_connections.contains(thing)) {
|
||||
qCDebug(dcInepro()) << "Setup after rediscovery, cleaning up ...";
|
||||
m_pro380Connections.take(thing)->deleteLater();
|
||||
m_connections.take(thing)->deleteLater();
|
||||
}
|
||||
|
||||
Pro380ModbusRtuConnection *proConnection = new Pro380ModbusRtuConnection(hardwareManager()->modbusRtuResource()->getModbusRtuMaster(uuid), address, this);
|
||||
@ -194,7 +194,7 @@ void IntegrationPluginInepro::setupThing(ThingSetupInfo *info)
|
||||
|
||||
|
||||
// FIXME: try to read before setup success
|
||||
m_pro380Connections.insert(thing, proConnection);
|
||||
m_connections.insert(thing, proConnection);
|
||||
info->finish(Thing::ThingErrorNoError);
|
||||
}
|
||||
|
||||
@ -205,7 +205,7 @@ void IntegrationPluginInepro::postSetupThing(Thing *thing)
|
||||
m_refreshTimer = hardwareManager()->pluginTimerManager()->registerTimer(2);
|
||||
connect(m_refreshTimer, &PluginTimer::timeout, this, [this] {
|
||||
foreach (Thing *thing, myThings()) {
|
||||
m_pro380Connections.value(thing)->update();
|
||||
m_connections.value(thing)->update();
|
||||
}
|
||||
});
|
||||
|
||||
@ -218,8 +218,8 @@ void IntegrationPluginInepro::thingRemoved(Thing *thing)
|
||||
{
|
||||
qCDebug(dcInepro()) << "Thing removed" << thing->name();
|
||||
|
||||
if (m_pro380Connections.contains(thing))
|
||||
m_pro380Connections.take(thing)->deleteLater();
|
||||
if (m_connections.contains(thing))
|
||||
m_connections.take(thing)->deleteLater();
|
||||
|
||||
if (myThings().isEmpty() && m_refreshTimer) {
|
||||
qCDebug(dcInepro()) << "Stopping reconnect timer";
|
||||
|
||||
@ -37,8 +37,6 @@
|
||||
|
||||
#include "pro380modbusrtuconnection.h"
|
||||
|
||||
#include "extern-plugininfo.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QTimer>
|
||||
|
||||
@ -59,8 +57,8 @@ public:
|
||||
|
||||
private:
|
||||
PluginTimer *m_refreshTimer = nullptr;
|
||||
QHash<Thing *, Pro380ModbusRtuConnection *> m_connections;
|
||||
|
||||
QHash<Thing *, Pro380ModbusRtuConnection *> m_pro380Connections;
|
||||
};
|
||||
|
||||
#endif // INTEGRATIONPLUGININEPRO_H
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
{
|
||||
"className": "Pro380",
|
||||
"protocol": "RTU",
|
||||
"endianness": "BigEndian",
|
||||
"blocks": [
|
||||
@ -263,4 +264,4 @@
|
||||
"access": "RO"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,537 +0,0 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2021, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This fileDescriptor 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 "pro380modbusrtuconnection.h"
|
||||
#include "loggingcategories.h"
|
||||
|
||||
NYMEA_LOGGING_CATEGORY(dcPro380ModbusRtuConnection, "Pro380ModbusRtuConnection")
|
||||
|
||||
Pro380ModbusRtuConnection::Pro380ModbusRtuConnection(ModbusRtuMaster *modbusRtuMaster, quint16 slaveId, QObject *parent) :
|
||||
QObject(parent),
|
||||
m_modbusRtuMaster(modbusRtuMaster),
|
||||
m_slaveId(slaveId)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
ModbusRtuMaster *Pro380ModbusRtuConnection::modbusRtuMaster() const
|
||||
{
|
||||
return m_modbusRtuMaster;
|
||||
}
|
||||
quint16 Pro380ModbusRtuConnection::slaveId() const
|
||||
{
|
||||
return m_slaveId;
|
||||
}
|
||||
float Pro380ModbusRtuConnection::frequency() const
|
||||
{
|
||||
return m_frequency;
|
||||
}
|
||||
|
||||
float Pro380ModbusRtuConnection::totalEnergyConsumed() const
|
||||
{
|
||||
return m_totalEnergyConsumed;
|
||||
}
|
||||
|
||||
float Pro380ModbusRtuConnection::totalEnergyProduced() const
|
||||
{
|
||||
return m_totalEnergyProduced;
|
||||
}
|
||||
|
||||
float Pro380ModbusRtuConnection::voltagePhaseA() const
|
||||
{
|
||||
return m_voltagePhaseA;
|
||||
}
|
||||
|
||||
float Pro380ModbusRtuConnection::voltagePhaseB() const
|
||||
{
|
||||
return m_voltagePhaseB;
|
||||
}
|
||||
|
||||
float Pro380ModbusRtuConnection::voltagePhaseC() const
|
||||
{
|
||||
return m_voltagePhaseC;
|
||||
}
|
||||
|
||||
float Pro380ModbusRtuConnection::currentPhaseA() const
|
||||
{
|
||||
return m_currentPhaseA;
|
||||
}
|
||||
|
||||
float Pro380ModbusRtuConnection::currentPhaseB() const
|
||||
{
|
||||
return m_currentPhaseB;
|
||||
}
|
||||
|
||||
float Pro380ModbusRtuConnection::currentPhaseC() const
|
||||
{
|
||||
return m_currentPhaseC;
|
||||
}
|
||||
|
||||
float Pro380ModbusRtuConnection::totalCurrentPower() const
|
||||
{
|
||||
return m_totalCurrentPower;
|
||||
}
|
||||
|
||||
float Pro380ModbusRtuConnection::powerPhaseA() const
|
||||
{
|
||||
return m_powerPhaseA;
|
||||
}
|
||||
|
||||
float Pro380ModbusRtuConnection::powerPhaseB() const
|
||||
{
|
||||
return m_powerPhaseB;
|
||||
}
|
||||
|
||||
float Pro380ModbusRtuConnection::powerPhaseC() const
|
||||
{
|
||||
return m_powerPhaseC;
|
||||
}
|
||||
|
||||
float Pro380ModbusRtuConnection::energyConsumedPhaseA() const
|
||||
{
|
||||
return m_energyConsumedPhaseA;
|
||||
}
|
||||
|
||||
float Pro380ModbusRtuConnection::energyConsumedPhaseB() const
|
||||
{
|
||||
return m_energyConsumedPhaseB;
|
||||
}
|
||||
|
||||
float Pro380ModbusRtuConnection::energyConsumedPhaseC() const
|
||||
{
|
||||
return m_energyConsumedPhaseC;
|
||||
}
|
||||
|
||||
float Pro380ModbusRtuConnection::energyProducedPhaseA() const
|
||||
{
|
||||
return m_energyProducedPhaseA;
|
||||
}
|
||||
|
||||
float Pro380ModbusRtuConnection::energyProducedPhaseB() const
|
||||
{
|
||||
return m_energyProducedPhaseB;
|
||||
}
|
||||
|
||||
float Pro380ModbusRtuConnection::energyProducedPhaseC() const
|
||||
{
|
||||
return m_energyProducedPhaseC;
|
||||
}
|
||||
|
||||
void Pro380ModbusRtuConnection::initialize()
|
||||
{
|
||||
// No init registers defined. Nothing to be done and we are finished.
|
||||
emit initializationFinished();
|
||||
}
|
||||
|
||||
void Pro380ModbusRtuConnection::update()
|
||||
{
|
||||
updateFrequency();
|
||||
updateTotalEnergyConsumed();
|
||||
updateTotalEnergyProduced();
|
||||
updatePhasesVoltageBlock();
|
||||
updatePhasesCurrentBlock();
|
||||
updateCurrentPowerBlock();
|
||||
updatePhasesEnergyConsumedBlock();
|
||||
updatePhasesEnergyProducedBlock();
|
||||
}
|
||||
|
||||
void Pro380ModbusRtuConnection::updateFrequency()
|
||||
{
|
||||
// Update registers from Frequency
|
||||
qCDebug(dcPro380ModbusRtuConnection()) << "--> Read \"Frequency\" register:" << 20488 << "size:" << 2;
|
||||
ModbusRtuReply *reply = readFrequency();
|
||||
if (reply) {
|
||||
if (!reply->isFinished()) {
|
||||
connect(reply, &ModbusRtuReply::finished, this, [this, reply](){
|
||||
if (reply->error() == ModbusRtuReply::NoError) {
|
||||
QVector<quint16> values = reply->result();
|
||||
qCDebug(dcPro380ModbusRtuConnection()) << "<-- Response from \"Frequency\" register" << 20488 << "size:" << 2 << values;
|
||||
float receivedFrequency = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian);
|
||||
if (m_frequency != receivedFrequency) {
|
||||
m_frequency = receivedFrequency;
|
||||
emit frequencyChanged(m_frequency);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
connect(reply, &ModbusRtuReply::errorOccurred, this, [reply] (ModbusRtuReply::Error error){
|
||||
qCWarning(dcPro380ModbusRtuConnection()) << "ModbusRtu reply error occurred while updating \"Frequency\" registers" << error << reply->errorString();
|
||||
emit reply->finished();
|
||||
});
|
||||
}
|
||||
} else {
|
||||
qCWarning(dcPro380ModbusRtuConnection()) << "Error occurred while reading \"Frequency\" registers";
|
||||
}
|
||||
}
|
||||
|
||||
void Pro380ModbusRtuConnection::updateTotalEnergyConsumed()
|
||||
{
|
||||
// Update registers from Total energy consumed (Forward active energy)
|
||||
qCDebug(dcPro380ModbusRtuConnection()) << "--> Read \"Total energy consumed (Forward active energy)\" register:" << 24588 << "size:" << 2;
|
||||
ModbusRtuReply *reply = readTotalEnergyConsumed();
|
||||
if (reply) {
|
||||
if (!reply->isFinished()) {
|
||||
connect(reply, &ModbusRtuReply::finished, this, [this, reply](){
|
||||
if (reply->error() == ModbusRtuReply::NoError) {
|
||||
QVector<quint16> values = reply->result();
|
||||
qCDebug(dcPro380ModbusRtuConnection()) << "<-- Response from \"Total energy consumed (Forward active energy)\" register" << 24588 << "size:" << 2 << values;
|
||||
float receivedTotalEnergyConsumed = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian);
|
||||
if (m_totalEnergyConsumed != receivedTotalEnergyConsumed) {
|
||||
m_totalEnergyConsumed = receivedTotalEnergyConsumed;
|
||||
emit totalEnergyConsumedChanged(m_totalEnergyConsumed);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
connect(reply, &ModbusRtuReply::errorOccurred, this, [reply] (ModbusRtuReply::Error error){
|
||||
qCWarning(dcPro380ModbusRtuConnection()) << "ModbusRtu reply error occurred while updating \"Total energy consumed (Forward active energy)\" registers" << error << reply->errorString();
|
||||
emit reply->finished();
|
||||
});
|
||||
}
|
||||
} else {
|
||||
qCWarning(dcPro380ModbusRtuConnection()) << "Error occurred while reading \"Total energy consumed (Forward active energy)\" registers";
|
||||
}
|
||||
}
|
||||
|
||||
void Pro380ModbusRtuConnection::updateTotalEnergyProduced()
|
||||
{
|
||||
// Update registers from Total energy produced (Reverse active energy)
|
||||
qCDebug(dcPro380ModbusRtuConnection()) << "--> Read \"Total energy produced (Reverse active energy)\" register:" << 24600 << "size:" << 2;
|
||||
ModbusRtuReply *reply = readTotalEnergyProduced();
|
||||
if (reply) {
|
||||
if (!reply->isFinished()) {
|
||||
connect(reply, &ModbusRtuReply::finished, this, [this, reply](){
|
||||
if (reply->error() == ModbusRtuReply::NoError) {
|
||||
QVector<quint16> values = reply->result();
|
||||
qCDebug(dcPro380ModbusRtuConnection()) << "<-- Response from \"Total energy produced (Reverse active energy)\" register" << 24600 << "size:" << 2 << values;
|
||||
float receivedTotalEnergyProduced = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian);
|
||||
if (m_totalEnergyProduced != receivedTotalEnergyProduced) {
|
||||
m_totalEnergyProduced = receivedTotalEnergyProduced;
|
||||
emit totalEnergyProducedChanged(m_totalEnergyProduced);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
connect(reply, &ModbusRtuReply::errorOccurred, this, [reply] (ModbusRtuReply::Error error){
|
||||
qCWarning(dcPro380ModbusRtuConnection()) << "ModbusRtu reply error occurred while updating \"Total energy produced (Reverse active energy)\" registers" << error << reply->errorString();
|
||||
emit reply->finished();
|
||||
});
|
||||
}
|
||||
} else {
|
||||
qCWarning(dcPro380ModbusRtuConnection()) << "Error occurred while reading \"Total energy produced (Reverse active energy)\" registers";
|
||||
}
|
||||
}
|
||||
|
||||
void Pro380ModbusRtuConnection::updatePhasesVoltageBlock()
|
||||
{
|
||||
// Update register block "phasesVoltage"
|
||||
qCDebug(dcPro380ModbusRtuConnection()) << "--> Read block \"phasesVoltage\" registers from:" << 20482 << "size:" << 6;
|
||||
ModbusRtuReply *reply = m_modbusRtuMaster->readHoldingRegister(m_slaveId, 20482, 6);
|
||||
if (reply) {
|
||||
if (!reply->isFinished()) {
|
||||
connect(reply, &ModbusRtuReply::finished, this, [this, reply](){
|
||||
if (reply->error() == ModbusRtuReply::NoError) {
|
||||
QVector<quint16> blockValues = reply->result();
|
||||
QVector<quint16> values;
|
||||
qCDebug(dcPro380ModbusRtuConnection()) << "<-- Response from reading block \"phasesVoltage\" register" << 20482 << "size:" << 6 << blockValues;
|
||||
values = blockValues.mid(0, 2);
|
||||
float receivedVoltagePhaseA = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian);
|
||||
if (m_voltagePhaseA != receivedVoltagePhaseA) {
|
||||
m_voltagePhaseA = receivedVoltagePhaseA;
|
||||
emit voltagePhaseAChanged(m_voltagePhaseA);
|
||||
}
|
||||
|
||||
values = blockValues.mid(2, 2);
|
||||
float receivedVoltagePhaseB = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian);
|
||||
if (m_voltagePhaseB != receivedVoltagePhaseB) {
|
||||
m_voltagePhaseB = receivedVoltagePhaseB;
|
||||
emit voltagePhaseBChanged(m_voltagePhaseB);
|
||||
}
|
||||
|
||||
values = blockValues.mid(4, 2);
|
||||
float receivedVoltagePhaseC = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian);
|
||||
if (m_voltagePhaseC != receivedVoltagePhaseC) {
|
||||
m_voltagePhaseC = receivedVoltagePhaseC;
|
||||
emit voltagePhaseCChanged(m_voltagePhaseC);
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
connect(reply, &ModbusRtuReply::errorOccurred, this, [reply] (ModbusRtuReply::Error error){
|
||||
qCWarning(dcPro380ModbusRtuConnection()) << "ModbusRtu reply error occurred while updating block \"phasesVoltage\" registers" << error << reply->errorString();
|
||||
emit reply->finished();
|
||||
});
|
||||
}
|
||||
} else {
|
||||
qCWarning(dcPro380ModbusRtuConnection()) << "Error occurred while reading block \"phasesVoltage\" registers";
|
||||
}
|
||||
}
|
||||
|
||||
void Pro380ModbusRtuConnection::updatePhasesCurrentBlock()
|
||||
{
|
||||
// Update register block "phasesCurrent"
|
||||
qCDebug(dcPro380ModbusRtuConnection()) << "--> Read block \"phasesCurrent\" registers from:" << 20492 << "size:" << 6;
|
||||
ModbusRtuReply *reply = m_modbusRtuMaster->readHoldingRegister(m_slaveId, 20492, 6);
|
||||
if (reply) {
|
||||
if (!reply->isFinished()) {
|
||||
connect(reply, &ModbusRtuReply::finished, this, [this, reply](){
|
||||
if (reply->error() == ModbusRtuReply::NoError) {
|
||||
QVector<quint16> blockValues = reply->result();
|
||||
QVector<quint16> values;
|
||||
qCDebug(dcPro380ModbusRtuConnection()) << "<-- Response from reading block \"phasesCurrent\" register" << 20492 << "size:" << 6 << blockValues;
|
||||
values = blockValues.mid(0, 2);
|
||||
float receivedCurrentPhaseA = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian);
|
||||
if (m_currentPhaseA != receivedCurrentPhaseA) {
|
||||
m_currentPhaseA = receivedCurrentPhaseA;
|
||||
emit currentPhaseAChanged(m_currentPhaseA);
|
||||
}
|
||||
|
||||
values = blockValues.mid(2, 2);
|
||||
float receivedCurrentPhaseB = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian);
|
||||
if (m_currentPhaseB != receivedCurrentPhaseB) {
|
||||
m_currentPhaseB = receivedCurrentPhaseB;
|
||||
emit currentPhaseBChanged(m_currentPhaseB);
|
||||
}
|
||||
|
||||
values = blockValues.mid(4, 2);
|
||||
float receivedCurrentPhaseC = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian);
|
||||
if (m_currentPhaseC != receivedCurrentPhaseC) {
|
||||
m_currentPhaseC = receivedCurrentPhaseC;
|
||||
emit currentPhaseCChanged(m_currentPhaseC);
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
connect(reply, &ModbusRtuReply::errorOccurred, this, [reply] (ModbusRtuReply::Error error){
|
||||
qCWarning(dcPro380ModbusRtuConnection()) << "ModbusRtu reply error occurred while updating block \"phasesCurrent\" registers" << error << reply->errorString();
|
||||
emit reply->finished();
|
||||
});
|
||||
}
|
||||
} else {
|
||||
qCWarning(dcPro380ModbusRtuConnection()) << "Error occurred while reading block \"phasesCurrent\" registers";
|
||||
}
|
||||
}
|
||||
|
||||
void Pro380ModbusRtuConnection::updateCurrentPowerBlock()
|
||||
{
|
||||
// Update register block "currentPower"
|
||||
qCDebug(dcPro380ModbusRtuConnection()) << "--> Read block \"currentPower\" registers from:" << 20498 << "size:" << 8;
|
||||
ModbusRtuReply *reply = m_modbusRtuMaster->readHoldingRegister(m_slaveId, 20498, 8);
|
||||
if (reply) {
|
||||
if (!reply->isFinished()) {
|
||||
connect(reply, &ModbusRtuReply::finished, this, [this, reply](){
|
||||
if (reply->error() == ModbusRtuReply::NoError) {
|
||||
QVector<quint16> blockValues = reply->result();
|
||||
QVector<quint16> values;
|
||||
qCDebug(dcPro380ModbusRtuConnection()) << "<-- Response from reading block \"currentPower\" register" << 20498 << "size:" << 8 << blockValues;
|
||||
values = blockValues.mid(0, 2);
|
||||
float receivedTotalCurrentPower = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian);
|
||||
if (m_totalCurrentPower != receivedTotalCurrentPower) {
|
||||
m_totalCurrentPower = receivedTotalCurrentPower;
|
||||
emit totalCurrentPowerChanged(m_totalCurrentPower);
|
||||
}
|
||||
|
||||
values = blockValues.mid(2, 2);
|
||||
float receivedPowerPhaseA = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian);
|
||||
if (m_powerPhaseA != receivedPowerPhaseA) {
|
||||
m_powerPhaseA = receivedPowerPhaseA;
|
||||
emit powerPhaseAChanged(m_powerPhaseA);
|
||||
}
|
||||
|
||||
values = blockValues.mid(4, 2);
|
||||
float receivedPowerPhaseB = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian);
|
||||
if (m_powerPhaseB != receivedPowerPhaseB) {
|
||||
m_powerPhaseB = receivedPowerPhaseB;
|
||||
emit powerPhaseBChanged(m_powerPhaseB);
|
||||
}
|
||||
|
||||
values = blockValues.mid(6, 2);
|
||||
float receivedPowerPhaseC = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian);
|
||||
if (m_powerPhaseC != receivedPowerPhaseC) {
|
||||
m_powerPhaseC = receivedPowerPhaseC;
|
||||
emit powerPhaseCChanged(m_powerPhaseC);
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
connect(reply, &ModbusRtuReply::errorOccurred, this, [reply] (ModbusRtuReply::Error error){
|
||||
qCWarning(dcPro380ModbusRtuConnection()) << "ModbusRtu reply error occurred while updating block \"currentPower\" registers" << error << reply->errorString();
|
||||
emit reply->finished();
|
||||
});
|
||||
}
|
||||
} else {
|
||||
qCWarning(dcPro380ModbusRtuConnection()) << "Error occurred while reading block \"currentPower\" registers";
|
||||
}
|
||||
}
|
||||
|
||||
void Pro380ModbusRtuConnection::updatePhasesEnergyConsumedBlock()
|
||||
{
|
||||
// Update register block "phasesEnergyConsumed"
|
||||
qCDebug(dcPro380ModbusRtuConnection()) << "--> Read block \"phasesEnergyConsumed\" registers from:" << 24594 << "size:" << 6;
|
||||
ModbusRtuReply *reply = m_modbusRtuMaster->readHoldingRegister(m_slaveId, 24594, 6);
|
||||
if (reply) {
|
||||
if (!reply->isFinished()) {
|
||||
connect(reply, &ModbusRtuReply::finished, this, [this, reply](){
|
||||
if (reply->error() == ModbusRtuReply::NoError) {
|
||||
QVector<quint16> blockValues = reply->result();
|
||||
QVector<quint16> values;
|
||||
qCDebug(dcPro380ModbusRtuConnection()) << "<-- Response from reading block \"phasesEnergyConsumed\" register" << 24594 << "size:" << 6 << blockValues;
|
||||
values = blockValues.mid(0, 2);
|
||||
float receivedEnergyConsumedPhaseA = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian);
|
||||
if (m_energyConsumedPhaseA != receivedEnergyConsumedPhaseA) {
|
||||
m_energyConsumedPhaseA = receivedEnergyConsumedPhaseA;
|
||||
emit energyConsumedPhaseAChanged(m_energyConsumedPhaseA);
|
||||
}
|
||||
|
||||
values = blockValues.mid(2, 2);
|
||||
float receivedEnergyConsumedPhaseB = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian);
|
||||
if (m_energyConsumedPhaseB != receivedEnergyConsumedPhaseB) {
|
||||
m_energyConsumedPhaseB = receivedEnergyConsumedPhaseB;
|
||||
emit energyConsumedPhaseBChanged(m_energyConsumedPhaseB);
|
||||
}
|
||||
|
||||
values = blockValues.mid(4, 2);
|
||||
float receivedEnergyConsumedPhaseC = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian);
|
||||
if (m_energyConsumedPhaseC != receivedEnergyConsumedPhaseC) {
|
||||
m_energyConsumedPhaseC = receivedEnergyConsumedPhaseC;
|
||||
emit energyConsumedPhaseCChanged(m_energyConsumedPhaseC);
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
connect(reply, &ModbusRtuReply::errorOccurred, this, [reply] (ModbusRtuReply::Error error){
|
||||
qCWarning(dcPro380ModbusRtuConnection()) << "ModbusRtu reply error occurred while updating block \"phasesEnergyConsumed\" registers" << error << reply->errorString();
|
||||
emit reply->finished();
|
||||
});
|
||||
}
|
||||
} else {
|
||||
qCWarning(dcPro380ModbusRtuConnection()) << "Error occurred while reading block \"phasesEnergyConsumed\" registers";
|
||||
}
|
||||
}
|
||||
|
||||
void Pro380ModbusRtuConnection::updatePhasesEnergyProducedBlock()
|
||||
{
|
||||
// Update register block "phasesEnergyProduced"
|
||||
qCDebug(dcPro380ModbusRtuConnection()) << "--> Read block \"phasesEnergyProduced\" registers from:" << 24606 << "size:" << 6;
|
||||
ModbusRtuReply *reply = m_modbusRtuMaster->readHoldingRegister(m_slaveId, 24606, 6);
|
||||
if (reply) {
|
||||
if (!reply->isFinished()) {
|
||||
connect(reply, &ModbusRtuReply::finished, this, [this, reply](){
|
||||
if (reply->error() == ModbusRtuReply::NoError) {
|
||||
QVector<quint16> blockValues = reply->result();
|
||||
QVector<quint16> values;
|
||||
qCDebug(dcPro380ModbusRtuConnection()) << "<-- Response from reading block \"phasesEnergyProduced\" register" << 24606 << "size:" << 6 << blockValues;
|
||||
values = blockValues.mid(0, 2);
|
||||
float receivedEnergyProducedPhaseA = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian);
|
||||
if (m_energyProducedPhaseA != receivedEnergyProducedPhaseA) {
|
||||
m_energyProducedPhaseA = receivedEnergyProducedPhaseA;
|
||||
emit energyProducedPhaseAChanged(m_energyProducedPhaseA);
|
||||
}
|
||||
|
||||
values = blockValues.mid(2, 2);
|
||||
float receivedEnergyProducedPhaseB = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian);
|
||||
if (m_energyProducedPhaseB != receivedEnergyProducedPhaseB) {
|
||||
m_energyProducedPhaseB = receivedEnergyProducedPhaseB;
|
||||
emit energyProducedPhaseBChanged(m_energyProducedPhaseB);
|
||||
}
|
||||
|
||||
values = blockValues.mid(4, 2);
|
||||
float receivedEnergyProducedPhaseC = ModbusDataUtils::convertToFloat32(values, ModbusDataUtils::ByteOrderBigEndian);
|
||||
if (m_energyProducedPhaseC != receivedEnergyProducedPhaseC) {
|
||||
m_energyProducedPhaseC = receivedEnergyProducedPhaseC;
|
||||
emit energyProducedPhaseCChanged(m_energyProducedPhaseC);
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
|
||||
connect(reply, &ModbusRtuReply::errorOccurred, this, [reply] (ModbusRtuReply::Error error){
|
||||
qCWarning(dcPro380ModbusRtuConnection()) << "ModbusRtu reply error occurred while updating block \"phasesEnergyProduced\" registers" << error << reply->errorString();
|
||||
emit reply->finished();
|
||||
});
|
||||
}
|
||||
} else {
|
||||
qCWarning(dcPro380ModbusRtuConnection()) << "Error occurred while reading block \"phasesEnergyProduced\" registers";
|
||||
}
|
||||
}
|
||||
|
||||
ModbusRtuReply *Pro380ModbusRtuConnection::readFrequency()
|
||||
{
|
||||
return m_modbusRtuMaster->readHoldingRegister(m_slaveId, 20488, 2);
|
||||
}
|
||||
|
||||
ModbusRtuReply *Pro380ModbusRtuConnection::readTotalEnergyConsumed()
|
||||
{
|
||||
return m_modbusRtuMaster->readHoldingRegister(m_slaveId, 24588, 2);
|
||||
}
|
||||
|
||||
ModbusRtuReply *Pro380ModbusRtuConnection::readTotalEnergyProduced()
|
||||
{
|
||||
return m_modbusRtuMaster->readHoldingRegister(m_slaveId, 24600, 2);
|
||||
}
|
||||
|
||||
void Pro380ModbusRtuConnection::verifyInitFinished()
|
||||
{
|
||||
if (m_pendingInitReplies.isEmpty()) {
|
||||
qCDebug(dcPro380ModbusRtuConnection()) << "Initialization finished of Pro380ModbusRtuConnection";
|
||||
emit initializationFinished();
|
||||
}
|
||||
}
|
||||
|
||||
QDebug operator<<(QDebug debug, Pro380ModbusRtuConnection *pro380ModbusRtuConnection)
|
||||
{
|
||||
debug.nospace().noquote() << "Pro380ModbusRtuConnection(" << pro380ModbusRtuConnection->modbusRtuMaster()->modbusUuid().toString() << ", " << pro380ModbusRtuConnection->modbusRtuMaster()->serialPort() << ", slave ID:" << pro380ModbusRtuConnection->slaveId() << ")" << "\n";
|
||||
debug.nospace().noquote() << " - Frequency:" << pro380ModbusRtuConnection->frequency() << " [Hz]" << "\n";
|
||||
debug.nospace().noquote() << " - Total energy consumed (Forward active energy):" << pro380ModbusRtuConnection->totalEnergyConsumed() << " [kWh]" << "\n";
|
||||
debug.nospace().noquote() << " - Total energy produced (Reverse active energy):" << pro380ModbusRtuConnection->totalEnergyProduced() << " [kWh]" << "\n";
|
||||
debug.nospace().noquote() << " - Voltage phase L1:" << pro380ModbusRtuConnection->voltagePhaseA() << " [V]" << "\n";
|
||||
debug.nospace().noquote() << " - Voltage phase L2:" << pro380ModbusRtuConnection->voltagePhaseB() << " [V]" << "\n";
|
||||
debug.nospace().noquote() << " - Voltage phase L3:" << pro380ModbusRtuConnection->voltagePhaseC() << " [V]" << "\n";
|
||||
debug.nospace().noquote() << " - Current phase L1:" << pro380ModbusRtuConnection->currentPhaseA() << " [A]" << "\n";
|
||||
debug.nospace().noquote() << " - Current phase L2:" << pro380ModbusRtuConnection->currentPhaseB() << " [A]" << "\n";
|
||||
debug.nospace().noquote() << " - Current phase L3:" << pro380ModbusRtuConnection->currentPhaseC() << " [A]" << "\n";
|
||||
debug.nospace().noquote() << " - Total system power:" << pro380ModbusRtuConnection->totalCurrentPower() << " [kW]" << "\n";
|
||||
debug.nospace().noquote() << " - Power phase L1:" << pro380ModbusRtuConnection->powerPhaseA() << " [kW]" << "\n";
|
||||
debug.nospace().noquote() << " - Power phase L2:" << pro380ModbusRtuConnection->powerPhaseB() << " [kW]" << "\n";
|
||||
debug.nospace().noquote() << " - Power phase L3:" << pro380ModbusRtuConnection->powerPhaseC() << " [kW]" << "\n";
|
||||
debug.nospace().noquote() << " - Energy consumed phase A:" << pro380ModbusRtuConnection->energyConsumedPhaseA() << " [kWh]" << "\n";
|
||||
debug.nospace().noquote() << " - Energy consumed phase B:" << pro380ModbusRtuConnection->energyConsumedPhaseB() << " [kWh]" << "\n";
|
||||
debug.nospace().noquote() << " - Energy consumed phase C:" << pro380ModbusRtuConnection->energyConsumedPhaseC() << " [kWh]" << "\n";
|
||||
debug.nospace().noquote() << " - Energy produced phase A:" << pro380ModbusRtuConnection->energyProducedPhaseA() << " [kWh]" << "\n";
|
||||
debug.nospace().noquote() << " - Energy produced phase B:" << pro380ModbusRtuConnection->energyProducedPhaseB() << " [kWh]" << "\n";
|
||||
debug.nospace().noquote() << " - Energy produced phase C:" << pro380ModbusRtuConnection->energyProducedPhaseC() << " [kWh]" << "\n";
|
||||
return debug.quote().space();
|
||||
}
|
||||
|
||||
@ -1,204 +0,0 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2021, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This fileDescriptor 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 PRO380MODBUSRTUCONNECTION_H
|
||||
#define PRO380MODBUSRTUCONNECTION_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include "../modbus/modbusdatautils.h"
|
||||
#include <hardware/modbus/modbusrtumaster.h>
|
||||
|
||||
class Pro380ModbusRtuConnection : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
explicit Pro380ModbusRtuConnection(ModbusRtuMaster *modbusRtuMaster, quint16 slaveId, QObject *parent = nullptr);
|
||||
~Pro380ModbusRtuConnection() = default;
|
||||
|
||||
ModbusRtuMaster *modbusRtuMaster() const;
|
||||
quint16 slaveId() const;
|
||||
|
||||
/* Frequency [Hz] - Address: 20488, Size: 2 */
|
||||
float frequency() const;
|
||||
|
||||
/* Total energy consumed (Forward active energy) [kWh] - Address: 24588, Size: 2 */
|
||||
float totalEnergyConsumed() const;
|
||||
|
||||
/* Total energy produced (Reverse active energy) [kWh] - Address: 24600, Size: 2 */
|
||||
float totalEnergyProduced() const;
|
||||
|
||||
/* Voltage phase L1 [V] - Address: 20482, Size: 2 */
|
||||
float voltagePhaseA() const;
|
||||
|
||||
/* Voltage phase L2 [V] - Address: 20484, Size: 2 */
|
||||
float voltagePhaseB() const;
|
||||
|
||||
/* Voltage phase L3 [V] - Address: 20486, Size: 2 */
|
||||
float voltagePhaseC() const;
|
||||
|
||||
/* Read block from start addess 20482 with size of 6 registers containing following 3 properties:
|
||||
- Voltage phase L1 [V] - Address: 20482, Size: 2
|
||||
- Voltage phase L2 [V] - Address: 20484, Size: 2
|
||||
- Voltage phase L3 [V] - Address: 20486, Size: 2
|
||||
*/
|
||||
void updatePhasesVoltageBlock();
|
||||
/* Current phase L1 [A] - Address: 20492, Size: 2 */
|
||||
float currentPhaseA() const;
|
||||
|
||||
/* Current phase L2 [A] - Address: 20494, Size: 2 */
|
||||
float currentPhaseB() const;
|
||||
|
||||
/* Current phase L3 [A] - Address: 20496, Size: 2 */
|
||||
float currentPhaseC() const;
|
||||
|
||||
/* Read block from start addess 20492 with size of 6 registers containing following 3 properties:
|
||||
- Current phase L1 [A] - Address: 20492, Size: 2
|
||||
- Current phase L2 [A] - Address: 20494, Size: 2
|
||||
- Current phase L3 [A] - Address: 20496, Size: 2
|
||||
*/
|
||||
void updatePhasesCurrentBlock();
|
||||
/* Total system power [kW] - Address: 20498, Size: 2 */
|
||||
float totalCurrentPower() const;
|
||||
|
||||
/* Power phase L1 [kW] - Address: 20500, Size: 2 */
|
||||
float powerPhaseA() const;
|
||||
|
||||
/* Power phase L2 [kW] - Address: 20502, Size: 2 */
|
||||
float powerPhaseB() const;
|
||||
|
||||
/* Power phase L3 [kW] - Address: 20504, Size: 2 */
|
||||
float powerPhaseC() const;
|
||||
|
||||
/* Read block from start addess 20498 with size of 8 registers containing following 4 properties:
|
||||
- Total system power [kW] - Address: 20498, Size: 2
|
||||
- Power phase L1 [kW] - Address: 20500, Size: 2
|
||||
- Power phase L2 [kW] - Address: 20502, Size: 2
|
||||
- Power phase L3 [kW] - Address: 20504, Size: 2
|
||||
*/
|
||||
void updateCurrentPowerBlock();
|
||||
/* Energy consumed phase A [kWh] - Address: 24594, Size: 2 */
|
||||
float energyConsumedPhaseA() const;
|
||||
|
||||
/* Energy consumed phase B [kWh] - Address: 24596, Size: 2 */
|
||||
float energyConsumedPhaseB() const;
|
||||
|
||||
/* Energy consumed phase C [kWh] - Address: 24598, Size: 2 */
|
||||
float energyConsumedPhaseC() const;
|
||||
|
||||
/* Read block from start addess 24594 with size of 6 registers containing following 3 properties:
|
||||
- Energy consumed phase A [kWh] - Address: 24594, Size: 2
|
||||
- Energy consumed phase B [kWh] - Address: 24596, Size: 2
|
||||
- Energy consumed phase C [kWh] - Address: 24598, Size: 2
|
||||
*/
|
||||
void updatePhasesEnergyConsumedBlock();
|
||||
/* Energy produced phase A [kWh] - Address: 24606, Size: 2 */
|
||||
float energyProducedPhaseA() const;
|
||||
|
||||
/* Energy produced phase B [kWh] - Address: 24608, Size: 2 */
|
||||
float energyProducedPhaseB() const;
|
||||
|
||||
/* Energy produced phase C [kWh] - Address: 24610, Size: 2 */
|
||||
float energyProducedPhaseC() const;
|
||||
|
||||
/* Read block from start addess 24606 with size of 6 registers containing following 3 properties:
|
||||
- Energy produced phase A [kWh] - Address: 24606, Size: 2
|
||||
- Energy produced phase B [kWh] - Address: 24608, Size: 2
|
||||
- Energy produced phase C [kWh] - Address: 24610, Size: 2
|
||||
*/
|
||||
void updatePhasesEnergyProducedBlock();
|
||||
|
||||
void updateFrequency();
|
||||
void updateTotalEnergyConsumed();
|
||||
void updateTotalEnergyProduced();
|
||||
|
||||
virtual void initialize();
|
||||
virtual void update();
|
||||
|
||||
signals:
|
||||
void initializationFinished();
|
||||
|
||||
void frequencyChanged(float frequency);
|
||||
void totalEnergyConsumedChanged(float totalEnergyConsumed);
|
||||
void totalEnergyProducedChanged(float totalEnergyProduced);
|
||||
void voltagePhaseAChanged(float voltagePhaseA);
|
||||
void voltagePhaseBChanged(float voltagePhaseB);
|
||||
void voltagePhaseCChanged(float voltagePhaseC);
|
||||
void currentPhaseAChanged(float currentPhaseA);
|
||||
void currentPhaseBChanged(float currentPhaseB);
|
||||
void currentPhaseCChanged(float currentPhaseC);
|
||||
void totalCurrentPowerChanged(float totalCurrentPower);
|
||||
void powerPhaseAChanged(float powerPhaseA);
|
||||
void powerPhaseBChanged(float powerPhaseB);
|
||||
void powerPhaseCChanged(float powerPhaseC);
|
||||
void energyConsumedPhaseAChanged(float energyConsumedPhaseA);
|
||||
void energyConsumedPhaseBChanged(float energyConsumedPhaseB);
|
||||
void energyConsumedPhaseCChanged(float energyConsumedPhaseC);
|
||||
void energyProducedPhaseAChanged(float energyProducedPhaseA);
|
||||
void energyProducedPhaseBChanged(float energyProducedPhaseB);
|
||||
void energyProducedPhaseCChanged(float energyProducedPhaseC);
|
||||
|
||||
private:
|
||||
ModbusRtuMaster *m_modbusRtuMaster = nullptr;
|
||||
quint16 m_slaveId = 1;
|
||||
QVector<ModbusRtuReply *> m_pendingInitReplies;
|
||||
|
||||
float m_frequency = 0;
|
||||
float m_totalEnergyConsumed = 0;
|
||||
float m_totalEnergyProduced = 0;
|
||||
float m_voltagePhaseA = 0;
|
||||
float m_voltagePhaseB = 0;
|
||||
float m_voltagePhaseC = 0;
|
||||
float m_currentPhaseA = 0;
|
||||
float m_currentPhaseB = 0;
|
||||
float m_currentPhaseC = 0;
|
||||
float m_totalCurrentPower = 0;
|
||||
float m_powerPhaseA = 0;
|
||||
float m_powerPhaseB = 0;
|
||||
float m_powerPhaseC = 0;
|
||||
float m_energyConsumedPhaseA = 0;
|
||||
float m_energyConsumedPhaseB = 0;
|
||||
float m_energyConsumedPhaseC = 0;
|
||||
float m_energyProducedPhaseA = 0;
|
||||
float m_energyProducedPhaseB = 0;
|
||||
float m_energyProducedPhaseC = 0;
|
||||
|
||||
void verifyInitFinished();
|
||||
|
||||
ModbusRtuReply *readFrequency();
|
||||
ModbusRtuReply *readTotalEnergyConsumed();
|
||||
ModbusRtuReply *readTotalEnergyProduced();
|
||||
|
||||
|
||||
};
|
||||
|
||||
QDebug operator<<(QDebug debug, Pro380ModbusRtuConnection *pro380ModbusRtuConnection);
|
||||
|
||||
#endif // PRO380MODBUSRTUCONNECTION_H
|
||||
57
libnymea-modbus/libnymea-modbus.pro
Normal file
57
libnymea-modbus/libnymea-modbus.pro
Normal file
@ -0,0 +1,57 @@
|
||||
QMAKE_CXXFLAGS += -Werror -std=c++11 -z defs
|
||||
QMAKE_LFLAGS += -std=c++11 -z defs
|
||||
|
||||
QT += network serialbus
|
||||
|
||||
CONFIG += link_pkgconfig
|
||||
PKGCONFIG += nymea
|
||||
|
||||
TARGET = nymea-modbus
|
||||
TEMPLATE = lib
|
||||
|
||||
gcc {
|
||||
COMPILER_VERSION = $$system($$QMAKE_CXX " -dumpversion")
|
||||
COMPILER_MAJOR_VERSION = $$str_member($$COMPILER_VERSION)
|
||||
greaterThan(COMPILER_MAJOR_VERSION, 7): QMAKE_CXXFLAGS += -Wno-deprecated-copy
|
||||
}
|
||||
|
||||
HEADERS += \
|
||||
modbusdatautils.h \
|
||||
modbustcpmaster.h
|
||||
|
||||
SOURCES += \
|
||||
modbusdatautils.cpp \
|
||||
modbustcpmaster.cpp
|
||||
|
||||
|
||||
# define install target
|
||||
target.path = $$[QT_INSTALL_LIBS]
|
||||
INSTALLS += target
|
||||
|
||||
# install modbustool for external plugins
|
||||
modbustoolpri.files = modbus-tool.pri
|
||||
modbustoolpri.path = $$[QT_INSTALL_PREFIX]/include/nymea-modbus/
|
||||
modbustool.files = tools/generate-connection.py
|
||||
modbustool.path = $$[QT_INSTALL_PREFIX]/include/nymea-modbus/tools/
|
||||
modbustoolmodules.files = tools/connectiontool/*.py
|
||||
modbustoolmodules.path = $$[QT_INSTALL_PREFIX]/include/nymea-modbus/tools/connectiontool/
|
||||
INSTALLS += modbustoolpri modbustool modbustoolmodules
|
||||
|
||||
# install header file with relative subdirectory
|
||||
for (header, HEADERS) {
|
||||
path = $$[QT_INSTALL_PREFIX]/include/nymea-modbus/$${dirname(header)}
|
||||
eval(headers_$${path}.files += $${header})
|
||||
eval(headers_$${path}.path = $${path})
|
||||
eval(INSTALLS *= headers_$${path})
|
||||
}
|
||||
|
||||
# Create pkgconfig file
|
||||
CONFIG += create_pc create_prl no_install_prl
|
||||
QMAKE_PKGCONFIG_NAME = libnymea-modbus
|
||||
QMAKE_PKGCONFIG_DESCRIPTION = nymea modbus integrations development library
|
||||
QMAKE_PKGCONFIG_PREFIX = $$[QT_INSTALL_PREFIX]
|
||||
QMAKE_PKGCONFIG_INCDIR = $$[QT_INSTALL_PREFIX]/include/nymea-modbus/
|
||||
QMAKE_PKGCONFIG_LIBDIR = $$target.path
|
||||
QMAKE_PKGCONFIG_VERSION = 1.0.0
|
||||
QMAKE_PKGCONFIG_FILE = nymea-modbus
|
||||
QMAKE_PKGCONFIG_DESTDIR = pkgconfig
|
||||
56
libnymea-modbus/modbus-tool.pri
Normal file
56
libnymea-modbus/modbus-tool.pri
Normal file
@ -0,0 +1,56 @@
|
||||
# Copyright 2013 - 2021, nymea GmbH
|
||||
# Contact: contact@nymea.io
|
||||
#
|
||||
# This file is part of nymea.
|
||||
# This project including source code and documentation is protected by
|
||||
# copyright law, and remains the property of nymea GmbH. All rights, including
|
||||
# reproduction, publication, editing and translation, are reserved. The use of
|
||||
# this project is subject to the terms of a license agreement to be concluded
|
||||
# with nymea GmbH in accordance with the terms of use of nymea GmbH, available
|
||||
# under https://nymea.io/license
|
||||
#
|
||||
# GNU Lesser General Public License Usage
|
||||
# Alternatively, this project may be redistributed and/or modified under the
|
||||
# terms of the GNU Lesser General Public License as published by the Free
|
||||
# Software Foundation; version 3. This project is distributed in the hope that
|
||||
# it will be useful, but WITHOUT ANY WARRANTY; without even the implied
|
||||
# warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
# Lesser General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Lesser General Public License
|
||||
# along with this project. If not, see <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
|
||||
|
||||
# This project include file is meant to be used by nymea modbus integration plugins.
|
||||
# For external plugins you can generate connection by including this project like following:
|
||||
|
||||
# # Generate modbus connection
|
||||
# MODBUS_CONNECTIONS += modbus-registers.json
|
||||
# MODBUS_TOOLS_CONFIG += VERBOSE
|
||||
# include($$[QT_INSTALL_PREFIX]/include/nymea-modbus/modbus-tool.pri)
|
||||
|
||||
# On each qmake run the classes will be generated in the build directory.
|
||||
|
||||
GENERATE_MODBUS_CONNECTION_BINARY=$${PWD}/tools/generate-connection.py
|
||||
|
||||
for(registerDefinition, MODBUS_CONNECTIONS) {
|
||||
contains(MODBUS_TOOLS_CONFIG, VERBOSE) {
|
||||
message("Generating modbus connection class for $${registerDefinition} (verbose)")
|
||||
system(python3 $${GENERATE_MODBUS_CONNECTION_BINARY} -j $${_PRO_FILE_PWD_}/$${registerDefinition} -o $${OUT_PWD}/autogenerated -v)
|
||||
} else {
|
||||
message("Generating class for $${registerDefinition}")
|
||||
system(python3 $${GENERATE_MODBUS_CONNECTION_BINARY} -j $${_PRO_FILE_PWD_}/$${registerDefinition} -o $${OUT_PWD}/autogenerated)
|
||||
}
|
||||
}
|
||||
|
||||
# Add all generated pri files to the project
|
||||
MODBUS_CONNECTIONS_INCLUDES = $$files($${OUT_PWD}/autogenerated/*.pri)
|
||||
for(MODBUS_CONNECTION, MODBUS_CONNECTIONS_INCLUDES) {
|
||||
message("Adding generated connection to project $${MODBUS_CONNECTION}")
|
||||
include($${MODBUS_CONNECTION})
|
||||
INCLUDEPATH += $${OUT_PWD}/autogenerated
|
||||
}
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2021, nymea GmbH
|
||||
* Copyright 2013 - 2022, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This file is part of nymea.
|
||||
@ -30,8 +30,7 @@
|
||||
|
||||
#include "modbustcpmaster.h"
|
||||
|
||||
#include <loggingcategories.h>
|
||||
NYMEA_LOGGING_CATEGORY(dcModbusTCP, "ModbusTCP")
|
||||
Q_LOGGING_CATEGORY(dcModbusTcpMaster, "ModbusTcpMaster")
|
||||
|
||||
ModbusTCPMaster::ModbusTCPMaster(const QHostAddress &hostAddress, uint port, QObject *parent) :
|
||||
QObject(parent),
|
||||
@ -91,7 +90,7 @@ bool ModbusTCPMaster::connectDevice() {
|
||||
|
||||
// Only connect if we are in the unconnected state
|
||||
if (m_modbusTcpClient->state() == QModbusDevice::UnconnectedState) {
|
||||
qCDebug(dcModbusTCP()) << "Connecting modbus TCP client to" << QString("%1:%2").arg(m_hostAddress.toString()).arg(m_port);
|
||||
qCDebug(dcModbusTcpMaster()) << "Connecting modbus TCP client to" << QString("%1:%2").arg(m_hostAddress.toString()).arg(m_port);
|
||||
m_modbusTcpClient->setConnectionParameter(QModbusDevice::NetworkPortParameter, m_port);
|
||||
m_modbusTcpClient->setConnectionParameter(QModbusDevice::NetworkAddressParameter, m_hostAddress.toString());
|
||||
m_modbusTcpClient->setTimeout(m_timeout);
|
||||
@ -101,7 +100,7 @@ bool ModbusTCPMaster::connectDevice() {
|
||||
// Restart the timer in case of connecting not finished yet or closing
|
||||
m_reconnectTimer->start();
|
||||
} else {
|
||||
qCWarning(dcModbusTCP()) << "Connect modbus TCP device" << QString("%1:%2").arg(m_hostAddress.toString()).arg(m_port) << "called, but the socket is currently in the" << m_modbusTcpClient->state();
|
||||
qCWarning(dcModbusTcpMaster()) << "Connect modbus TCP device" << QString("%1:%2").arg(m_hostAddress.toString()).arg(m_port) << "called, but the socket is currently in the" << m_modbusTcpClient->state();
|
||||
}
|
||||
|
||||
return false;
|
||||
@ -119,7 +118,7 @@ void ModbusTCPMaster::disconnectDevice()
|
||||
|
||||
bool ModbusTCPMaster::reconnectDevice()
|
||||
{
|
||||
qCWarning(dcModbusTCP()) << "Reconnecting modbus TCP device" << QString("%1:%2").arg(m_hostAddress.toString()).arg(m_port);
|
||||
qCWarning(dcModbusTcpMaster()) << "Reconnecting modbus TCP device" << QString("%1:%2").arg(m_hostAddress.toString()).arg(m_port);
|
||||
if (!m_modbusTcpClient)
|
||||
return false;
|
||||
|
||||
@ -184,12 +183,12 @@ QUuid ModbusTCPMaster::readCoil(uint slaveAddress, uint registerAddress, uint si
|
||||
emit receivedCoil(reply->serverAddress(), modbusAddress, unit.values());
|
||||
} else {
|
||||
emit readRequestExecuted(requestId, false);
|
||||
qCWarning(dcModbusTCP()) << "Read response error:" << reply->error();
|
||||
qCWarning(dcModbusTcpMaster()) << "Read response error:" << reply->error();
|
||||
}
|
||||
});
|
||||
|
||||
connect(reply, &QModbusReply::errorOccurred, this, [reply, requestId, this] (QModbusDevice::Error error){
|
||||
qCWarning(dcModbusTCP()) << "Modbus reply error:" << error;
|
||||
qCWarning(dcModbusTcpMaster()) << "Modbus reply error:" << error;
|
||||
emit readRequestError(requestId, reply->errorString());
|
||||
emit reply->finished(); // To make sure it will be deleted
|
||||
});
|
||||
@ -200,7 +199,7 @@ QUuid ModbusTCPMaster::readCoil(uint slaveAddress, uint registerAddress, uint si
|
||||
return QUuid();
|
||||
}
|
||||
} else {
|
||||
qCWarning(dcModbusTCP()) << "Read error: " << m_modbusTcpClient->errorString();
|
||||
qCWarning(dcModbusTcpMaster()) << "Read error: " << m_modbusTcpClient->errorString();
|
||||
return QUuid();
|
||||
}
|
||||
return requestId;
|
||||
@ -226,13 +225,13 @@ QUuid ModbusTCPMaster::writeHoldingRegisters(uint slaveAddress, uint registerAdd
|
||||
emit receivedHoldingRegister(reply->serverAddress(), modbusAddress, unit.values());
|
||||
} else {
|
||||
emit writeRequestExecuted(requestId, false);
|
||||
qCWarning(dcModbusTCP()) << "Read response error:" << reply->error();
|
||||
qCWarning(dcModbusTcpMaster()) << "Read response error:" << reply->error();
|
||||
}
|
||||
reply->deleteLater();
|
||||
});
|
||||
|
||||
connect(reply, &QModbusReply::errorOccurred, this, [reply, requestId, this] (QModbusDevice::Error error){
|
||||
qCWarning(dcModbusTCP()) << "Modbus replay error:" << error;
|
||||
qCWarning(dcModbusTcpMaster()) << "Modbus replay error:" << error;
|
||||
emit writeRequestError(requestId, reply->errorString());
|
||||
emit reply->finished(); // To make sure it will be deleted
|
||||
});
|
||||
@ -243,7 +242,7 @@ QUuid ModbusTCPMaster::writeHoldingRegisters(uint slaveAddress, uint registerAdd
|
||||
return QUuid();
|
||||
}
|
||||
} else {
|
||||
qCWarning(dcModbusTCP()) << "Read error: " << m_modbusTcpClient->errorString();
|
||||
qCWarning(dcModbusTcpMaster()) << "Read error: " << m_modbusTcpClient->errorString();
|
||||
return QUuid();
|
||||
}
|
||||
return requestId;
|
||||
@ -289,12 +288,12 @@ QUuid ModbusTCPMaster::readDiscreteInput(uint slaveAddress, uint registerAddress
|
||||
emit receivedDiscreteInput(reply->serverAddress(), modbusAddress, unit.values());
|
||||
} else {
|
||||
emit readRequestExecuted(requestId, false);
|
||||
qCWarning(dcModbusTCP()) << "Read response error:" << reply->error();
|
||||
qCWarning(dcModbusTcpMaster()) << "Read response error:" << reply->error();
|
||||
}
|
||||
});
|
||||
|
||||
connect(reply, &QModbusReply::errorOccurred, this, [requestId, this] (QModbusDevice::Error error){
|
||||
qCWarning(dcModbusTCP()) << "Modbus replay error:" << error;
|
||||
qCWarning(dcModbusTcpMaster()) << "Modbus replay error:" << error;
|
||||
QModbusReply *reply = qobject_cast<QModbusReply *>(sender());
|
||||
emit readRequestError(requestId, reply->errorString());
|
||||
emit reply->finished(); // To make sure it will be deleted
|
||||
@ -306,7 +305,7 @@ QUuid ModbusTCPMaster::readDiscreteInput(uint slaveAddress, uint registerAddress
|
||||
return QUuid();
|
||||
}
|
||||
} else {
|
||||
qCWarning(dcModbusTCP()) << "Read error: " << m_modbusTcpClient->errorString();
|
||||
qCWarning(dcModbusTcpMaster()) << "Read error: " << m_modbusTcpClient->errorString();
|
||||
return QUuid();
|
||||
}
|
||||
return requestId;
|
||||
@ -333,12 +332,12 @@ QUuid ModbusTCPMaster::readInputRegister(uint slaveAddress, uint registerAddress
|
||||
emit receivedInputRegister(reply->serverAddress(), modbusAddress, unit.values());
|
||||
} else {
|
||||
emit readRequestExecuted(requestId, false);
|
||||
qCWarning(dcModbusTCP()) << "Read response error:" << reply->error();
|
||||
qCWarning(dcModbusTcpMaster()) << "Read response error:" << reply->error();
|
||||
}
|
||||
});
|
||||
|
||||
connect(reply, &QModbusReply::errorOccurred, this, [reply, requestId, this] (QModbusDevice::Error error){
|
||||
qCWarning(dcModbusTCP()) << "Modbus reply error:" << error;
|
||||
qCWarning(dcModbusTcpMaster()) << "Modbus reply error:" << error;
|
||||
emit readRequestError(requestId, reply->errorString());
|
||||
emit reply->finished(); // To make sure it will be deleted
|
||||
});
|
||||
@ -350,7 +349,7 @@ QUuid ModbusTCPMaster::readInputRegister(uint slaveAddress, uint registerAddress
|
||||
return QUuid();
|
||||
}
|
||||
} else {
|
||||
qCWarning(dcModbusTCP()) << "Read error: " << m_modbusTcpClient->errorString();
|
||||
qCWarning(dcModbusTcpMaster()) << "Read error: " << m_modbusTcpClient->errorString();
|
||||
return QUuid();
|
||||
}
|
||||
return requestId;
|
||||
@ -378,7 +377,7 @@ QUuid ModbusTCPMaster::readHoldingRegister(uint slaveAddress, uint registerAddre
|
||||
|
||||
} else {
|
||||
emit writeRequestExecuted(requestId, false);
|
||||
qCWarning(dcModbusTCP()) << "Read response error:" << reply->error();
|
||||
qCWarning(dcModbusTcpMaster()) << "Read response error:" << reply->error();
|
||||
emit readRequestError(requestId, reply->errorString());
|
||||
}
|
||||
reply->deleteLater();
|
||||
@ -386,7 +385,7 @@ QUuid ModbusTCPMaster::readHoldingRegister(uint slaveAddress, uint registerAddre
|
||||
|
||||
connect(reply, &QModbusReply::errorOccurred, this, [reply, requestId, this] (QModbusDevice::Error error){
|
||||
|
||||
qCWarning(dcModbusTCP()) << "Modbus reply error:" << error;
|
||||
qCWarning(dcModbusTcpMaster()) << "Modbus reply error:" << error;
|
||||
emit readRequestError(requestId, reply->errorString());
|
||||
emit reply->finished(); // To make sure it will be deleted
|
||||
});
|
||||
@ -397,7 +396,7 @@ QUuid ModbusTCPMaster::readHoldingRegister(uint slaveAddress, uint registerAddre
|
||||
return QUuid();
|
||||
}
|
||||
} else {
|
||||
qCWarning(dcModbusTCP()) << "Read error: " << m_modbusTcpClient->errorString();
|
||||
qCWarning(dcModbusTcpMaster()) << "Read error: " << m_modbusTcpClient->errorString();
|
||||
return QUuid();
|
||||
}
|
||||
return requestId;
|
||||
@ -431,13 +430,13 @@ QUuid ModbusTCPMaster::writeCoils(uint slaveAddress, uint registerAddress, const
|
||||
|
||||
} else {
|
||||
emit writeRequestExecuted(requestId, false);
|
||||
qCWarning(dcModbusTCP()) << "Write response error:" << reply->error();
|
||||
qCWarning(dcModbusTcpMaster()) << "Write response error:" << reply->error();
|
||||
}
|
||||
reply->deleteLater();
|
||||
});
|
||||
|
||||
connect(reply, &QModbusReply::errorOccurred, this, [reply, requestId, this] (QModbusDevice::Error error){
|
||||
qCWarning(dcModbusTCP()) << "Modbus reply error:" << error;
|
||||
qCWarning(dcModbusTcpMaster()) << "Modbus reply error:" << error;
|
||||
emit writeRequestError(requestId, reply->errorString());
|
||||
emit reply->finished(); // To make sure it will be deleted
|
||||
});
|
||||
@ -448,7 +447,7 @@ QUuid ModbusTCPMaster::writeCoils(uint slaveAddress, uint registerAddress, const
|
||||
return QUuid();
|
||||
}
|
||||
} else {
|
||||
qCWarning(dcModbusTCP()) << "Read error: " << m_modbusTcpClient->errorString();
|
||||
qCWarning(dcModbusTcpMaster()) << "Read error: " << m_modbusTcpClient->errorString();
|
||||
return QUuid();
|
||||
}
|
||||
return requestId;
|
||||
@ -461,12 +460,12 @@ QUuid ModbusTCPMaster::writeHoldingRegister(uint slaveAddress, uint registerAddr
|
||||
|
||||
void ModbusTCPMaster::onModbusErrorOccurred(QModbusDevice::Error error)
|
||||
{
|
||||
qCWarning(dcModbusTCP()) << "An error occured" << error;
|
||||
qCWarning(dcModbusTcpMaster()) << "An error occured" << error;
|
||||
}
|
||||
|
||||
void ModbusTCPMaster::onModbusStateChanged(QModbusDevice::State state)
|
||||
{
|
||||
qCDebug(dcModbusTCP()) << "Connection state changed for" << m_hostAddress << state;
|
||||
qCDebug(dcModbusTcpMaster()) << "Connection state changed for" << m_hostAddress << state;
|
||||
bool connected = (state == QModbusDevice::ConnectedState);
|
||||
if (m_connected != connected) {
|
||||
m_connected = connected;
|
||||
@ -1,6 +1,6 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2021, nymea GmbH
|
||||
* Copyright 2013 - 2022, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This file is part of nymea.
|
||||
@ -31,11 +31,14 @@
|
||||
#ifndef MODBUSTCPMASTER_H
|
||||
#define MODBUSTCPMASTER_H
|
||||
|
||||
#include <QUuid>
|
||||
#include <QTimer>
|
||||
#include <QObject>
|
||||
#include <QHostAddress>
|
||||
#include <QtSerialBus>
|
||||
#include <QTimer>
|
||||
#include <QUuid>
|
||||
#include <QLoggingCategory>
|
||||
|
||||
Q_DECLARE_LOGGING_CATEGORY(dcModbusTcpMaster)
|
||||
|
||||
class ModbusTCPMaster : public QObject
|
||||
{
|
||||
@ -112,6 +115,7 @@ signals:
|
||||
void receivedDiscreteInput(uint slaveAddress, uint modbusRegister, const QVector<quint16> &values);
|
||||
void receivedHoldingRegister(uint slaveAddress, uint modbusRegister, const QVector<quint16> &values);
|
||||
void receivedInputRegister(uint slaveAddress, uint modbusRegister, const QVector<quint16> &values);
|
||||
|
||||
};
|
||||
|
||||
#endif // MODBUSTCPMASTER_H
|
||||
@ -14,7 +14,7 @@ The class will provide 2 main methods for fetching information from the modbus d
|
||||
* `initialize()` will read all registers with `"readSchedule": "init"` and emits the signal `initializationFinished()` once all replies returned.
|
||||
* `update()` can be used to update all registers with `"readSchedule": "update"`. The class will then fetch each register and update the specified value internally. If the value has changed, the `<propertyName>Changed()` signal will be emitted.
|
||||
|
||||
The reulting class will inhert from the `ModbusTCPMaster` class, providing easy access to all possible modbus operations and inform about the connected state.
|
||||
The resulting class will inhert from the `ModbusTCPMaster` class, providing easy access to all possible modbus operations and inform about the connected state.
|
||||
|
||||
|
||||
# JSON format
|
||||
@ -23,6 +23,8 @@ The basic structure of the modbus register JSON looks like following example:
|
||||
|
||||
```
|
||||
{
|
||||
"className": "MyConnection",
|
||||
"protocol": "BOTH",
|
||||
"endianness": "BigEndian",
|
||||
"enums": [
|
||||
{
|
||||
@ -64,29 +66,73 @@ The basic structure of the modbus register JSON looks like following example:
|
||||
"access": "RO"
|
||||
},
|
||||
...
|
||||
],
|
||||
"blocks": [
|
||||
{
|
||||
"id": "blockName",
|
||||
"readSchedule": "update",
|
||||
"registers": [
|
||||
{
|
||||
"id": "registerOne",
|
||||
"address": 0,
|
||||
"size": 2,
|
||||
...
|
||||
},
|
||||
{
|
||||
"id": "registerOne",
|
||||
"address": 0,
|
||||
"size": 2,
|
||||
...
|
||||
},
|
||||
...
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
## Endianness
|
||||
## Class name
|
||||
|
||||
When converting multiple registers to one data type (i.e. 2 registers uint16 values to one uint32), the order of the registers are important to align with the endiness of the data receiving.
|
||||
If no name class name has been passed to the generator script, the classname defined in the JSON file will be used.
|
||||
|
||||
There are 2 possibilities:
|
||||
The naming convention for the classname and the resulting source code files looks like this:
|
||||
|
||||
The class will be defined as
|
||||
|
||||
* `<ClassName><Protocol>Connection`.
|
||||
|
||||
The source code files will be calld:
|
||||
|
||||
* `classnameprotocolconnection.h`
|
||||
* `classnameprotocolconnection.cpp`
|
||||
|
||||
* `BigEndian`: default if not specified: register bytes come in following order `[0, 1, 2, 3]`: `ABCD`
|
||||
* `LittleEndian`: register bytes come in following order `[0, 1, 2, 3]`: `CDAB`
|
||||
|
||||
## Protocol
|
||||
|
||||
Depending on the communication protocol, a different base class will be used for the resulting output class.
|
||||
|
||||
There are 2 possibilities:
|
||||
There are 2 protocol types:
|
||||
|
||||
* `RTU`: a communication based on the RS485 serial RTU transport protocol
|
||||
* `TCP`: a communication based on the TCP transport protocol
|
||||
|
||||
If the modbus device supports both protocols and you want to generate a class for each protocol you can set the protocol to `BOTH` and a class for `RTU` and one for `TCP` will be generated.
|
||||
|
||||
...
|
||||
"protocol": "TCP",
|
||||
...
|
||||
|
||||
|
||||
## Endianness
|
||||
|
||||
When converting multiple registers to one data type (i.e. 2 registers uint16 values to one uint32), the order of the registers are important to align with the endianness of the data receiving.
|
||||
|
||||
There are 2 possibilities:
|
||||
|
||||
* `BigEndian`: default if not specified: register bytes come in following order `[0, 1, 2, 3]`: `ABCD`
|
||||
* `LittleEndian`: register bytes come in following order `[0, 1, 2, 3]`: `CDAB`
|
||||
|
||||
## Enums
|
||||
|
||||
Many modbus devices provide inforation using `Enums`, indicating a special state trough a defined list of values. If a register implements an enum, you can define it in the `enums` section. The `name` property defines the name of the enum, and the script will generate a c++ enum definition from this section. Each enum value will then be generated using `<EnumName><EnumValueName> = <value>`.
|
||||
@ -133,9 +179,9 @@ Earch register will be defined as a property in the resulting class modbus TCP c
|
||||
|
||||
On many device it is possible to read multiple registers in one modbus call. This can improve speed significantly when reading many register addresses which are in a row.
|
||||
|
||||
> Important: all registers within the block must exist, be in a row with no gaps inbetween!
|
||||
> Important: all registers within the block must exist, be in a row with no gaps inbetween and from the same function type!
|
||||
|
||||
A block sequence looks like this and will define a read method for reading the entwire block. Writing multiple blocks is currently not supported since not needed so far, but could be added to. In any case, all registers must be read or written, never have combinations.
|
||||
A block sequence looks like this and will define a read method for reading the entwire block. Writing multiple blocks is currently not supported since not needed so far, but could be added too. In any case, all registers must be read or written, never have combinations.
|
||||
|
||||
* `id`: Mandatory. The id defines the name of the block used in the resulting class.
|
||||
* `readSchedule`: Optional. Defines when the register needs to be fetched. If no read schedule has been defined, the class will provide only the update methods, but will not read the value during `initialize()` or `update()` calls. Possible values are:
|
||||
@ -173,20 +219,16 @@ Example block:
|
||||
]
|
||||
|
||||
|
||||
# Example
|
||||
# Autogenerate modbus classes
|
||||
|
||||
Change into your plugin sub directory.
|
||||
Assuming you wrote the registers.json file you can run now following command to generate your modbus class:
|
||||
|
||||
`$ python3 ../modbus/tools/generate-connection.py -j registers.json -o . -c MyModbusConnection`
|
||||
|
||||
You the result will be a header and a source file called:
|
||||
|
||||
* `mymodbusconnection.h`
|
||||
* `mymodbusconnection.cpp`
|
||||
|
||||
You can include this class in your project and provide one connection per thing.
|
||||
In order to get always the latest generated code from this tool, the entire process can be automated.
|
||||
|
||||
Assuming you have defined the registers in the `my-registers.json` within your plugin directory, and following lines to your plugin project file and run `qmake`.
|
||||
|
||||
# Generate modbus connection
|
||||
MODBUS_CONNECTIONS += my-registers.json
|
||||
include(../modbus.pri)
|
||||
|
||||
If you want to get information about the autogenerating class process, you can add `MODBUS_TOOLS_CONFIG += VERBOSE` in order to get much more information of the process.
|
||||
|
||||
Once you run qmake, in the build directory the autogenerated classes can be found. Also in your project you can find the generated classes for inspection.
|
||||
0
libnymea-modbus/tools/connectiontool/__init__.py
Normal file
0
libnymea-modbus/tools/connectiontool/__init__.py
Normal file
383
libnymea-modbus/tools/connectiontool/modbusrtu.py
Normal file
383
libnymea-modbus/tools/connectiontool/modbusrtu.py
Normal file
@ -0,0 +1,383 @@
|
||||
# Copyright (C) 2021 - 2022 nymea GmbH <developer@nymea.io>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
import logging
|
||||
|
||||
from .toolcommon import *
|
||||
|
||||
##############################################################
|
||||
|
||||
def writePropertyGetSetMethodDeclarationsRtu(fileDescriptor, registerDefinitions):
|
||||
for registerDefinition in registerDefinitions:
|
||||
propertyName = registerDefinition['id']
|
||||
propertyTyp = getCppDataType(registerDefinition)
|
||||
if 'unit' in registerDefinition and registerDefinition['unit'] != '':
|
||||
writeLine(fileDescriptor, ' /* %s [%s] - Address: %s, Size: %s */' % (registerDefinition['description'], registerDefinition['unit'], registerDefinition['address'], registerDefinition['size']))
|
||||
else:
|
||||
writeLine(fileDescriptor, ' /* %s - Address: %s, Size: %s */' % (registerDefinition['description'], registerDefinition['address'], registerDefinition['size']))
|
||||
|
||||
writeLine(fileDescriptor, ' %s %s() const;' % (propertyTyp, propertyName))
|
||||
|
||||
# Check if we require a set method
|
||||
if registerDefinition['access'] == 'RW' or registerDefinition['access'] == 'WO':
|
||||
writeLine(fileDescriptor, ' ModbusRtuReply *set%s(%s %s);' % (propertyName[0].upper() + propertyName[1:], propertyTyp, propertyName))
|
||||
|
||||
writeLine(fileDescriptor)
|
||||
|
||||
|
||||
def writePropertyGetSetMethodImplementationsRtu(fileDescriptor, className, registerDefinitions):
|
||||
for registerDefinition in registerDefinitions:
|
||||
propertyName = registerDefinition['id']
|
||||
propertyTyp = getCppDataType(registerDefinition)
|
||||
# Get
|
||||
if 'enum' in registerDefinition:
|
||||
writeLine(fileDescriptor, '%s::%s %s::%s() const' % (className, propertyTyp, className, propertyName))
|
||||
else:
|
||||
writeLine(fileDescriptor, '%s %s::%s() const' % (propertyTyp, className, propertyName))
|
||||
|
||||
writeLine(fileDescriptor, '{')
|
||||
writeLine(fileDescriptor, ' return m_%s;' % propertyName)
|
||||
writeLine(fileDescriptor, '}')
|
||||
writeLine(fileDescriptor)
|
||||
|
||||
# Check if we require a set method
|
||||
if registerDefinition['access'] == 'RW' or registerDefinition['access'] == 'WO':
|
||||
writeLine(fileDescriptor, 'ModbusRtuReply *%s::set%s(%s %s)' % (className, propertyName[0].upper() + propertyName[1:], propertyTyp, propertyName))
|
||||
writeLine(fileDescriptor, '{')
|
||||
|
||||
writeLine(fileDescriptor, ' QVector<quint16> values = %s;' % getConversionToValueMethod(registerDefinition))
|
||||
writeLine(fileDescriptor, ' qCDebug(dc%s()) << "--> Write \\"%s\\" register:" << %s << "size:" << %s << values;' % (className, registerDefinition['description'], registerDefinition['address'], registerDefinition['size']))
|
||||
if registerDefinition['registerType'] == 'holdingRegister':
|
||||
writeLine(fileDescriptor, ' return m_modbusRtuMaster->writeHoldingRegisters(m_slaveId, %s, values);' % (registerDefinition['address']))
|
||||
elif registerDefinition['registerType'] == 'coils':
|
||||
writeLine(fileDescriptor, ' return m_modbusRtuMaster->writeCoils(m_slaveId, %s, values);' % (registerDefinition['address']))
|
||||
else:
|
||||
logger.warning('Error: invalid register type for writing.')
|
||||
exit(1)
|
||||
|
||||
writeLine(fileDescriptor, '}')
|
||||
writeLine(fileDescriptor)
|
||||
|
||||
##############################################################
|
||||
|
||||
|
||||
def writePropertyUpdateMethodImplementationsRtu(fileDescriptor, className, registerDefinitions):
|
||||
for registerDefinition in registerDefinitions:
|
||||
if 'readSchedule' in registerDefinition and registerDefinition['readSchedule'] == 'init':
|
||||
continue
|
||||
|
||||
propertyName = registerDefinition['id']
|
||||
propertyTyp = getCppDataType(registerDefinition)
|
||||
writeLine(fileDescriptor, 'void %s::update%s()' % (className, propertyName[0].upper() + propertyName[1:]))
|
||||
writeLine(fileDescriptor, '{')
|
||||
writeLine(fileDescriptor, ' // Update registers from %s' % registerDefinition['description'])
|
||||
writeLine(fileDescriptor, ' qCDebug(dc%s()) << "--> Read \\"%s\\" register:" << %s << "size:" << %s;' % (className, registerDefinition['description'], registerDefinition['address'], registerDefinition['size']))
|
||||
writeLine(fileDescriptor, ' ModbusRtuReply *reply = read%s();' % (propertyName[0].upper() + propertyName[1:]))
|
||||
writeLine(fileDescriptor, ' if (reply) {')
|
||||
writeLine(fileDescriptor, ' if (!reply->isFinished()) {')
|
||||
writeLine(fileDescriptor, ' connect(reply, &ModbusRtuReply::finished, this, [this, reply](){')
|
||||
writeLine(fileDescriptor, ' if (reply->error() == ModbusRtuReply::NoError) {')
|
||||
writeLine(fileDescriptor, ' QVector<quint16> values = reply->result();')
|
||||
writeLine(fileDescriptor, ' qCDebug(dc%s()) << "<-- Response from \\"%s\\" register" << %s << "size:" << %s << values;' % (className, registerDefinition['description'], registerDefinition['address'], registerDefinition['size']))
|
||||
writeLine(fileDescriptor, ' process%sRegisterValues(values);' % (propertyName[0].upper() + propertyName[1:]))
|
||||
writeLine(fileDescriptor, ' }')
|
||||
writeLine(fileDescriptor, ' });')
|
||||
writeLine(fileDescriptor)
|
||||
writeLine(fileDescriptor, ' connect(reply, &ModbusRtuReply::errorOccurred, this, [reply] (ModbusRtuReply::Error error){')
|
||||
writeLine(fileDescriptor, ' qCWarning(dc%s()) << "ModbusRtu reply error occurred while updating \\"%s\\" registers" << error << reply->errorString();' % (className, registerDefinition['description']))
|
||||
writeLine(fileDescriptor, ' emit reply->finished();')
|
||||
writeLine(fileDescriptor, ' });')
|
||||
writeLine(fileDescriptor, ' }')
|
||||
writeLine(fileDescriptor, ' } else {')
|
||||
writeLine(fileDescriptor, ' qCWarning(dc%s()) << "Error occurred while reading \\"%s\\" registers";' % (className, registerDefinition['description']))
|
||||
writeLine(fileDescriptor, ' }')
|
||||
writeLine(fileDescriptor, '}')
|
||||
writeLine(fileDescriptor)
|
||||
|
||||
##############################################################
|
||||
|
||||
def writeBlockUpdateMethodImplementationsRtu(fileDescriptor, className, blockDefinitions):
|
||||
for blockDefinition in blockDefinitions:
|
||||
blockName = blockDefinition['id']
|
||||
blockRegisters = blockDefinition['registers']
|
||||
blockStartAddress = 0
|
||||
registerCount = 0
|
||||
blockSize = 0
|
||||
registerType = ""
|
||||
|
||||
for i, blockRegister in enumerate(blockRegisters):
|
||||
if i == 0:
|
||||
blockStartAddress = blockRegister['address']
|
||||
registerType = blockRegister['registerType']
|
||||
|
||||
registerCount += 1
|
||||
blockSize += blockRegister['size']
|
||||
|
||||
writeLine(fileDescriptor, 'void %s::update%sBlock()' % (className, blockName[0].upper() + blockName[1:]))
|
||||
writeLine(fileDescriptor, '{')
|
||||
writeLine(fileDescriptor, ' // Update register block \"%s\"' % blockName)
|
||||
writeLine(fileDescriptor, ' qCDebug(dc%s()) << "--> Read block \\"%s\\" registers from:" << %s << "size:" << %s;' % (className, blockName, blockStartAddress, blockSize))
|
||||
|
||||
|
||||
# Build request depending on the register type
|
||||
if registerType == 'inputRegister':
|
||||
writeLine(fileDescriptor, ' ModbusRtuReply *reply = m_modbusRtuMaster->readInputRegister(m_slaveId, %s, %s);' % (blockStartAddress, blockSize))
|
||||
elif registerType == 'discreteInputs':
|
||||
writeLine(fileDescriptor, ' ModbusRtuReply *reply = m_modbusRtuMaster->readDiscreteInput(m_slaveId, %s, %s);' % (blockStartAddress, blockSize))
|
||||
elif registerType == 'coils':
|
||||
writeLine(fileDescriptor, ' ModbusRtuReply *reply = m_modbusRtuMaster->readCoil(m_slaveId, %s, %s);' % (blockStartAddress, blockSize))
|
||||
else:
|
||||
#Default to holdingRegister
|
||||
writeLine(fileDescriptor, ' ModbusRtuReply *reply = m_modbusRtuMaster->readHoldingRegister(m_slaveId, %s, %s);' % (blockStartAddress, blockSize))
|
||||
|
||||
writeLine(fileDescriptor, ' if (reply) {')
|
||||
writeLine(fileDescriptor, ' if (!reply->isFinished()) {')
|
||||
writeLine(fileDescriptor, ' connect(reply, &ModbusRtuReply::finished, this, [this, reply](){')
|
||||
writeLine(fileDescriptor, ' if (reply->error() == ModbusRtuReply::NoError) {')
|
||||
writeLine(fileDescriptor, ' QVector<quint16> blockValues = reply->result();')
|
||||
writeLine(fileDescriptor, ' qCDebug(dc%s()) << "<-- Response from reading block \\"%s\\" register" << %s << "size:" << %s << blockValues;' % (className, blockName, blockStartAddress, blockSize))
|
||||
|
||||
# Start parsing the registers using offsets
|
||||
offset = 0
|
||||
for i, blockRegister in enumerate(blockRegisters):
|
||||
propertyName = blockRegister['id']
|
||||
writeLine(fileDescriptor, ' process%sRegisterValues(blockValues.mid(%s, %s));' % (propertyName[0].upper() + propertyName[1:], offset, blockRegister['size']))
|
||||
offset += blockRegister['size']
|
||||
|
||||
writeLine(fileDescriptor, ' }')
|
||||
writeLine(fileDescriptor, ' });')
|
||||
writeLine(fileDescriptor)
|
||||
writeLine(fileDescriptor, ' connect(reply, &ModbusRtuReply::errorOccurred, this, [reply] (ModbusRtuReply::Error error){')
|
||||
writeLine(fileDescriptor, ' qCWarning(dc%s()) << "ModbusRtu reply error occurred while updating block \\"%s\\" registers" << error << reply->errorString();' % (className, blockName))
|
||||
writeLine(fileDescriptor, ' emit reply->finished();')
|
||||
writeLine(fileDescriptor, ' });')
|
||||
writeLine(fileDescriptor, ' }')
|
||||
writeLine(fileDescriptor, ' } else {')
|
||||
writeLine(fileDescriptor, ' qCWarning(dc%s()) << "Error occurred while reading block \\"%s\\" registers";' % (className, blockName))
|
||||
writeLine(fileDescriptor, ' }')
|
||||
writeLine(fileDescriptor, '}')
|
||||
writeLine(fileDescriptor)
|
||||
|
||||
##############################################################
|
||||
|
||||
def writeInternalPropertyReadMethodDeclarationsRtu(fileDescriptor, registerDefinitions):
|
||||
for registerDefinition in registerDefinitions:
|
||||
propertyName = registerDefinition['id']
|
||||
writeLine(fileDescriptor, ' ModbusRtuReply *read%s();' % (propertyName[0].upper() + propertyName[1:]))
|
||||
|
||||
|
||||
def writeInternalPropertyReadMethodImplementationsRtu(fileDescriptor, className, registerDefinitions):
|
||||
for registerDefinition in registerDefinitions:
|
||||
propertyName = registerDefinition['id']
|
||||
writeLine(fileDescriptor, 'ModbusRtuReply *%s::read%s()' % (className, propertyName[0].upper() + propertyName[1:]))
|
||||
writeLine(fileDescriptor, '{')
|
||||
|
||||
# Build request depending on the register type
|
||||
if registerDefinition['registerType'] == 'inputRegister':
|
||||
writeLine(fileDescriptor, ' return m_modbusRtuMaster->readInputRegister(m_slaveId, %s, %s);' % (registerDefinition['address'], registerDefinition['size']))
|
||||
elif registerDefinition['registerType'] == 'discreteInputs':
|
||||
writeLine(fileDescriptor, ' return m_modbusRtuMaster->readDiscreteInput(m_slaveId, %s, %s);' % (registerDefinition['address'], registerDefinition['size']))
|
||||
elif registerDefinition['registerType'] == 'coils':
|
||||
writeLine(fileDescriptor, ' return m_modbusRtuMaster->readCoil(m_slaveId, %s, %s);' % (registerDefinition['address'], registerDefinition['size']))
|
||||
else:
|
||||
#Default to holdingRegister
|
||||
writeLine(fileDescriptor, ' return m_modbusRtuMaster->readHoldingRegister(m_slaveId, %s, %s);' % (registerDefinition['address'], registerDefinition['size']))
|
||||
|
||||
writeLine(fileDescriptor, '}')
|
||||
writeLine(fileDescriptor)
|
||||
|
||||
##############################################################
|
||||
|
||||
def writeInternalBlockReadMethodDeclarationsRtu(fileDescriptor, blockDefinitions):
|
||||
for blockDefinition in blockDefinitions:
|
||||
blockName = blockDefinition['id']
|
||||
blockRegisters = blockDefinition['registers']
|
||||
blockStartAddress = 0
|
||||
registerCount = 0
|
||||
blockSize = 0
|
||||
registerType = ""
|
||||
|
||||
for i, blockRegister in enumerate(blockRegisters):
|
||||
if i == 0:
|
||||
blockStartAddress = blockRegister['address']
|
||||
registerType = blockRegister['registerType']
|
||||
|
||||
registerCount += 1
|
||||
blockSize += blockRegister['size']
|
||||
|
||||
writeLine(fileDescriptor, ' /* Read block from start addess %s with size of %s registers containing following %s properties:' % (blockStartAddress, blockSize, registerCount))
|
||||
for i, registerDefinition in enumerate(blockRegisters):
|
||||
if 'unit' in registerDefinition and registerDefinition['unit'] != '':
|
||||
writeLine(fileDescriptor, ' - %s [%s] - Address: %s, Size: %s' % (registerDefinition['description'], registerDefinition['unit'], registerDefinition['address'], registerDefinition['size']))
|
||||
else:
|
||||
writeLine(fileDescriptor, ' -- %s - Address: %s, Size: %s' % (registerDefinition['description'], registerDefinition['address'], registerDefinition['size']))
|
||||
writeLine(fileDescriptor, ' */' )
|
||||
writeLine(fileDescriptor, ' ModbusRtuReply *readBlock%s();' % (blockName[0].upper() + blockName[1:]))
|
||||
writeLine(fileDescriptor)
|
||||
|
||||
|
||||
def writeInternalBlockReadMethodImplementationsRtu(fileDescriptor, className, blockDefinitions):
|
||||
for blockDefinition in blockDefinitions:
|
||||
blockName = blockDefinition['id']
|
||||
blockRegisters = blockDefinition['registers']
|
||||
blockStartAddress = 0
|
||||
registerCount = 0
|
||||
blockSize = 0
|
||||
registerType = ""
|
||||
|
||||
for i, blockRegister in enumerate(blockRegisters):
|
||||
if i == 0:
|
||||
blockStartAddress = blockRegister['address']
|
||||
registerType = blockRegister['registerType']
|
||||
|
||||
registerCount += 1
|
||||
blockSize += blockRegister['size']
|
||||
|
||||
|
||||
writeLine(fileDescriptor, 'ModbusRtuReply *%s::readBlock%s()' % (className, blockName[0].upper() + blockName[1:]))
|
||||
writeLine(fileDescriptor, '{')
|
||||
|
||||
# Build request depending on the register type
|
||||
if registerType == 'inputRegister':
|
||||
writeLine(fileDescriptor, ' return m_modbusRtuMaster->readInputRegister(m_slaveId, %s, %s);' % (blockStartAddress, blockSize))
|
||||
elif registerType == 'discreteInputs':
|
||||
writeLine(fileDescriptor, ' return m_modbusRtuMaster->readDiscreteInput(m_slaveId, %s, %s);' % (blockStartAddress, blockSize))
|
||||
elif registerType == 'coils':
|
||||
writeLine(fileDescriptor, ' return m_modbusRtuMaster->readCoil(m_slaveId, %s, %s);' % (blockStartAddress, blockSize))
|
||||
else:
|
||||
#Default to holdingRegister
|
||||
writeLine(fileDescriptor, ' return m_modbusRtuMaster->readHoldingRegister(m_slaveId, %s, %s);' % (blockStartAddress, blockSize))
|
||||
|
||||
writeLine(fileDescriptor, '}')
|
||||
writeLine(fileDescriptor)
|
||||
|
||||
##############################################################
|
||||
|
||||
def writeInitMethodImplementationRtu(fileDescriptor, className, registerDefinitions, blockDefinitions):
|
||||
writeLine(fileDescriptor, 'void %s::initialize()' % (className))
|
||||
writeLine(fileDescriptor, '{')
|
||||
|
||||
# First check if there are any init registers
|
||||
initRequired = False
|
||||
for registerDefinition in registerDefinitions:
|
||||
if registerDefinition['readSchedule'] == 'init':
|
||||
initRequired = True
|
||||
break
|
||||
|
||||
for blockDefinition in blockDefinitions:
|
||||
if 'readSchedule' in blockDefinition and blockDefinition['readSchedule'] == 'init':
|
||||
initRequired = True
|
||||
break
|
||||
|
||||
if initRequired:
|
||||
writeLine(fileDescriptor, ' ModbusRtuReply *reply = nullptr;')
|
||||
writeLine(fileDescriptor)
|
||||
writeLine(fileDescriptor, ' if (!m_pendingInitReplies.isEmpty()) {')
|
||||
writeLine(fileDescriptor, ' qCWarning(dc%s()) << "Tried to initialize but there are still some init replies pending.";' % className)
|
||||
writeLine(fileDescriptor, ' return;')
|
||||
writeLine(fileDescriptor, ' }')
|
||||
|
||||
# Read individual registers
|
||||
for registerDefinition in registerDefinitions:
|
||||
propertyName = registerDefinition['id']
|
||||
propertyTyp = getCppDataType(registerDefinition)
|
||||
|
||||
if 'readSchedule' in registerDefinition and registerDefinition['readSchedule'] == 'init':
|
||||
writeLine(fileDescriptor)
|
||||
writeLine(fileDescriptor, ' // Read %s' % registerDefinition['description'])
|
||||
writeLine(fileDescriptor, ' reply = read%s();' % (propertyName[0].upper() + propertyName[1:]))
|
||||
writeLine(fileDescriptor, ' if (reply) {')
|
||||
writeLine(fileDescriptor, ' if (!reply->isFinished()) {')
|
||||
writeLine(fileDescriptor, ' m_pendingInitReplies.append(reply);')
|
||||
writeLine(fileDescriptor, ' connect(reply, &ModbusRtuReply::finished, this, [this, reply](){')
|
||||
writeLine(fileDescriptor, ' if (reply->error() == ModbusRtuReply::NoError) {')
|
||||
writeLine(fileDescriptor, ' QVector<quint16> values = reply->result();')
|
||||
writeLine(fileDescriptor, ' qCDebug(dc%s()) << "<-- Response from \\"%s\\" register" << %s << "size:" << %s << values;' % (className, registerDefinition['description'], registerDefinition['address'], registerDefinition['size']))
|
||||
writeLine(fileDescriptor, ' process%sRegisterValues(values);' % (propertyName[0].upper() + propertyName[1:]))
|
||||
writeLine(fileDescriptor, ' }')
|
||||
writeLine(fileDescriptor)
|
||||
writeLine(fileDescriptor, ' m_pendingInitReplies.removeAll(reply);')
|
||||
writeLine(fileDescriptor, ' verifyInitFinished();')
|
||||
writeLine(fileDescriptor, ' });')
|
||||
writeLine(fileDescriptor)
|
||||
writeLine(fileDescriptor, ' connect(reply, &ModbusRtuReply::errorOccurred, this, [reply] (ModbusRtuReply::Error error){')
|
||||
writeLine(fileDescriptor, ' qCWarning(dc%s()) << "ModbusRtu reply error occurred while updating \\"%s\\" registers" << error << reply->errorString();' % (className, registerDefinition['description']))
|
||||
writeLine(fileDescriptor, ' emit reply->finished();')
|
||||
writeLine(fileDescriptor, ' });')
|
||||
writeLine(fileDescriptor, ' }')
|
||||
writeLine(fileDescriptor, ' } else {')
|
||||
writeLine(fileDescriptor, ' qCWarning(dc%s()) << "Error occurred while reading \\"%s\\" registers";' % (className, registerDefinition['description']))
|
||||
writeLine(fileDescriptor, ' }')
|
||||
|
||||
# Read init blocks
|
||||
for blockDefinition in blockDefinitions:
|
||||
blockName = blockDefinition['id']
|
||||
blockRegisters = blockDefinition['registers']
|
||||
|
||||
if 'readSchedule' in blockDefinition and blockDefinition['readSchedule'] == 'init':
|
||||
blockStartAddress = 0
|
||||
registerCount = 0
|
||||
blockSize = 0
|
||||
registerType = ""
|
||||
|
||||
for i, blockRegister in enumerate(blockRegisters):
|
||||
if i == 0:
|
||||
blockStartAddress = blockRegister['address']
|
||||
registerType = blockRegister['registerType']
|
||||
|
||||
registerCount += 1
|
||||
blockSize += blockRegister['size']
|
||||
|
||||
writeLine(fileDescriptor)
|
||||
writeLine(fileDescriptor, ' // Read %s' % blockName)
|
||||
writeLine(fileDescriptor, ' reply = readBlock%s();' % (blockName[0].upper() + blockName[1:]))
|
||||
writeLine(fileDescriptor, ' if (reply) {')
|
||||
writeLine(fileDescriptor, ' if (!reply->isFinished()) {')
|
||||
writeLine(fileDescriptor, ' m_pendingInitReplies.append(reply);')
|
||||
writeLine(fileDescriptor, ' connect(reply, &ModbusRtuReply::finished, this, [this, reply](){')
|
||||
writeLine(fileDescriptor, ' if (reply->error() == ModbusRtuReply::NoError) {')
|
||||
writeLine(fileDescriptor, ' QVector<quint16> blockValues = reply->result();')
|
||||
writeLine(fileDescriptor, ' qCDebug(dc%s()) << "<-- Response from reading block \\"%s\\" register" << %s << "size:" << %s << blockValues;' % (className, blockName, blockStartAddress, blockSize))
|
||||
|
||||
# Start parsing the registers using offsets
|
||||
offset = 0
|
||||
for i, blockRegister in enumerate(blockRegisters):
|
||||
propertyName = blockRegister['id']
|
||||
propertyTyp = getCppDataType(blockRegister)
|
||||
writeLine(fileDescriptor, ' process%sRegisterValues(blockValues.mid(%s, %s));' % (propertyName[0].upper() + propertyName[1:], offset, blockRegister['size']))
|
||||
offset += blockRegister['size']
|
||||
|
||||
writeLine(fileDescriptor, ' m_pendingInitReplies.removeAll(reply);')
|
||||
writeLine(fileDescriptor, ' verifyInitFinished();')
|
||||
writeLine(fileDescriptor, ' }')
|
||||
writeLine(fileDescriptor, ' });')
|
||||
writeLine(fileDescriptor)
|
||||
writeLine(fileDescriptor, ' connect(reply, &ModbusRtuReply::errorOccurred, this, [reply] (ModbusRtuReply::Error error){')
|
||||
writeLine(fileDescriptor, ' qCWarning(dc%s()) << "ModbusRtu reply error occurred while updating block \\"%s\\" registers" << error << reply->errorString();' % (className, blockName))
|
||||
writeLine(fileDescriptor, ' emit reply->finished();')
|
||||
writeLine(fileDescriptor, ' });')
|
||||
writeLine(fileDescriptor, ' }')
|
||||
writeLine(fileDescriptor, ' } else {')
|
||||
writeLine(fileDescriptor, ' qCWarning(dc%s()) << "Error occurred while reading block \\"%s\\" registers";' % (className, blockName))
|
||||
writeLine(fileDescriptor, ' }')
|
||||
writeLine(fileDescriptor)
|
||||
|
||||
else:
|
||||
writeLine(fileDescriptor, ' // No init registers defined. Nothing to be done and we are finished.')
|
||||
writeLine(fileDescriptor, ' emit initializationFinished();')
|
||||
|
||||
writeLine(fileDescriptor, '}')
|
||||
writeLine(fileDescriptor)
|
||||
385
libnymea-modbus/tools/connectiontool/modbustcp.py
Normal file
385
libnymea-modbus/tools/connectiontool/modbustcp.py
Normal file
@ -0,0 +1,385 @@
|
||||
# Copyright (C) 2021 - 2022 nymea GmbH <developer@nymea.io>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
from .toolcommon import *
|
||||
|
||||
##############################################################
|
||||
|
||||
def writePropertyGetSetMethodDeclarationsTcp(fileDescriptor, registerDefinitions):
|
||||
for registerDefinition in registerDefinitions:
|
||||
propertyName = registerDefinition['id']
|
||||
propertyTyp = getCppDataType(registerDefinition)
|
||||
if 'unit' in registerDefinition and registerDefinition['unit'] != '':
|
||||
writeLine(fileDescriptor, ' /* %s [%s] - Address: %s, Size: %s */' % (registerDefinition['description'], registerDefinition['unit'], registerDefinition['address'], registerDefinition['size']))
|
||||
else:
|
||||
writeLine(fileDescriptor, ' /* %s - Address: %s, Size: %s */' % (registerDefinition['description'], registerDefinition['address'], registerDefinition['size']))
|
||||
|
||||
writeLine(fileDescriptor, ' %s %s() const;' % (propertyTyp, propertyName))
|
||||
|
||||
# Check if we require a set method
|
||||
if registerDefinition['access'] == 'RW' or registerDefinition['access'] == 'WO':
|
||||
writeLine(fileDescriptor, ' QModbusReply *set%s(%s %s);' % (propertyName[0].upper() + propertyName[1:], propertyTyp, propertyName))
|
||||
|
||||
writeLine(fileDescriptor)
|
||||
|
||||
|
||||
def writePropertyGetSetMethodImplementationsTcp(fileDescriptor, className, registerDefinitions):
|
||||
for registerDefinition in registerDefinitions:
|
||||
propertyName = registerDefinition['id']
|
||||
propertyTyp = getCppDataType(registerDefinition)
|
||||
# Get
|
||||
if 'enum' in registerDefinition:
|
||||
writeLine(fileDescriptor, '%s::%s %s::%s() const' % (className, propertyTyp, className, propertyName))
|
||||
else:
|
||||
writeLine(fileDescriptor, '%s %s::%s() const' % (propertyTyp, className, propertyName))
|
||||
|
||||
writeLine(fileDescriptor, '{')
|
||||
writeLine(fileDescriptor, ' return m_%s;' % propertyName)
|
||||
writeLine(fileDescriptor, '}')
|
||||
writeLine(fileDescriptor)
|
||||
|
||||
# Check if we require a set method
|
||||
if registerDefinition['access'] == 'RW' or registerDefinition['access'] == 'WO':
|
||||
writeLine(fileDescriptor, 'QModbusReply *%s::set%s(%s %s)' % (className, propertyName[0].upper() + propertyName[1:], propertyTyp, propertyName))
|
||||
writeLine(fileDescriptor, '{')
|
||||
|
||||
writeLine(fileDescriptor, ' QVector<quint16> values = %s;' % getConversionToValueMethod(registerDefinition))
|
||||
writeLine(fileDescriptor, ' qCDebug(dc%s()) << "--> Write \\"%s\\" register:" << %s << "size:" << %s << values;' % (className, registerDefinition['description'], registerDefinition['address'], registerDefinition['size']))
|
||||
if registerDefinition['registerType'] == 'holdingRegister':
|
||||
writeLine(fileDescriptor, ' QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, %s, values.count());' % (registerDefinition['address']))
|
||||
elif registerDefinition['registerType'] == 'coils':
|
||||
writeLine(fileDescriptor, ' QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::Coils, %s, values.count());' % (registerDefinition['address']))
|
||||
else:
|
||||
logger.warning('Error: invalid register type for writing.')
|
||||
exit(1)
|
||||
|
||||
writeLine(fileDescriptor, ' request.setValues(values);')
|
||||
writeLine(fileDescriptor, ' return sendWriteRequest(request, m_slaveId);')
|
||||
writeLine(fileDescriptor, '}')
|
||||
writeLine(fileDescriptor)
|
||||
|
||||
##############################################################
|
||||
|
||||
def writePropertyUpdateMethodImplementationsTcp(fileDescriptor, className, registerDefinitions):
|
||||
for registerDefinition in registerDefinitions:
|
||||
if 'readSchedule' in registerDefinition and registerDefinition['readSchedule'] == 'init':
|
||||
continue
|
||||
|
||||
propertyName = registerDefinition['id']
|
||||
propertyTyp = getCppDataType(registerDefinition)
|
||||
writeLine(fileDescriptor, 'void %s::update%s()' % (className, propertyName[0].upper() + propertyName[1:]))
|
||||
writeLine(fileDescriptor, '{')
|
||||
writeLine(fileDescriptor, ' // Update registers from %s' % registerDefinition['description'])
|
||||
writeLine(fileDescriptor, ' qCDebug(dc%s()) << "--> Read \\"%s\\" register:" << %s << "size:" << %s;' % (className, registerDefinition['description'], registerDefinition['address'], registerDefinition['size']))
|
||||
writeLine(fileDescriptor, ' QModbusReply *reply = read%s();' % (propertyName[0].upper() + propertyName[1:]))
|
||||
writeLine(fileDescriptor, ' if (reply) {')
|
||||
writeLine(fileDescriptor, ' if (!reply->isFinished()) {')
|
||||
writeLine(fileDescriptor, ' connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater);')
|
||||
writeLine(fileDescriptor, ' connect(reply, &QModbusReply::finished, this, [this, reply](){')
|
||||
writeLine(fileDescriptor, ' if (reply->error() == QModbusDevice::NoError) {')
|
||||
writeLine(fileDescriptor, ' const QModbusDataUnit unit = reply->result();')
|
||||
writeLine(fileDescriptor, ' qCDebug(dc%s()) << "<-- Response from \\"%s\\" register" << %s << "size:" << %s << unit.values();' % (className, registerDefinition['description'], registerDefinition['address'], registerDefinition['size']))
|
||||
writeLine(fileDescriptor, ' process%sRegisterValues(unit.values());' % (propertyName[0].upper() + propertyName[1:]))
|
||||
writeLine(fileDescriptor, ' }')
|
||||
writeLine(fileDescriptor, ' });')
|
||||
writeLine(fileDescriptor)
|
||||
writeLine(fileDescriptor, ' connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){')
|
||||
writeLine(fileDescriptor, ' qCWarning(dc%s()) << "Modbus reply error occurred while updating \\"%s\\" registers from" << hostAddress().toString() << error << reply->errorString();' % (className, registerDefinition['description']))
|
||||
writeLine(fileDescriptor, ' emit reply->finished(); // To make sure it will be deleted')
|
||||
writeLine(fileDescriptor, ' });')
|
||||
writeLine(fileDescriptor, ' } else {')
|
||||
writeLine(fileDescriptor, ' delete reply; // Broadcast reply returns immediatly')
|
||||
writeLine(fileDescriptor, ' }')
|
||||
writeLine(fileDescriptor, ' } else {')
|
||||
writeLine(fileDescriptor, ' qCWarning(dc%s()) << "Error occurred while reading \\"%s\\" registers from" << hostAddress().toString() << errorString();' % (className, registerDefinition['description']))
|
||||
writeLine(fileDescriptor, ' }')
|
||||
writeLine(fileDescriptor, '}')
|
||||
writeLine(fileDescriptor)
|
||||
|
||||
##############################################################
|
||||
|
||||
def writeBlockUpdateMethodImplementationsTcp(fileDescriptor, className, blockDefinitions):
|
||||
for blockDefinition in blockDefinitions:
|
||||
blockName = blockDefinition['id']
|
||||
blockRegisters = blockDefinition['registers']
|
||||
blockStartAddress = 0
|
||||
registerCount = 0
|
||||
blockSize = 0
|
||||
registerType = ""
|
||||
|
||||
for i, blockRegister in enumerate(blockRegisters):
|
||||
if i == 0:
|
||||
blockStartAddress = blockRegister['address']
|
||||
registerType = blockRegister['registerType']
|
||||
|
||||
registerCount += 1
|
||||
blockSize += blockRegister['size']
|
||||
|
||||
writeLine(fileDescriptor, 'void %s::update%sBlock()' % (className, blockName[0].upper() + blockName[1:]))
|
||||
writeLine(fileDescriptor, '{')
|
||||
writeLine(fileDescriptor, ' // Update register block \"%s\"' % blockName)
|
||||
writeLine(fileDescriptor, ' qCDebug(dc%s()) << "--> Read block \\"%s\\" registers from:" << %s << "size:" << %s;' % (className, blockName, blockStartAddress, blockSize))
|
||||
writeLine(fileDescriptor, ' QModbusReply *reply = readBlock%s();' % (blockName[0].upper() + blockName[1:]))
|
||||
writeLine(fileDescriptor, ' if (reply) {')
|
||||
writeLine(fileDescriptor, ' if (!reply->isFinished()) {')
|
||||
writeLine(fileDescriptor, ' connect(reply, &QModbusReply::finished, this, [this, reply](){')
|
||||
writeLine(fileDescriptor, ' if (reply->error() == QModbusDevice::NoError) {')
|
||||
writeLine(fileDescriptor, ' const QModbusDataUnit unit = reply->result();')
|
||||
writeLine(fileDescriptor, ' const QVector<quint16> blockValues = unit.values();')
|
||||
writeLine(fileDescriptor, ' qCDebug(dc%s()) << "<-- Response from reading block \\"%s\\" register" << %s << "size:" << %s << blockValues;' % (className, blockName, blockStartAddress, blockSize))
|
||||
|
||||
# Start parsing the registers using offsets
|
||||
offset = 0
|
||||
for i, blockRegister in enumerate(blockRegisters):
|
||||
propertyName = blockRegister['id']
|
||||
propertyTyp = getCppDataType(blockRegister)
|
||||
writeLine(fileDescriptor, ' process%sRegisterValues(blockValues.mid(%s, %s));' % (propertyName[0].upper() + propertyName[1:], offset, blockRegister['size']))
|
||||
offset += blockRegister['size']
|
||||
|
||||
writeLine(fileDescriptor, ' }')
|
||||
writeLine(fileDescriptor, ' });')
|
||||
writeLine(fileDescriptor)
|
||||
writeLine(fileDescriptor, ' connect(reply, &QModbusReply::errorOccurred, this, [reply] (QModbusDevice::Error error){')
|
||||
writeLine(fileDescriptor, ' qCWarning(dc%s()) << "Modbus reply error occurred while updating block \\"%s\\" registers" << error << reply->errorString();' % (className, blockName))
|
||||
writeLine(fileDescriptor, ' emit reply->finished();')
|
||||
writeLine(fileDescriptor, ' });')
|
||||
writeLine(fileDescriptor, ' }')
|
||||
writeLine(fileDescriptor, ' } else {')
|
||||
writeLine(fileDescriptor, ' qCWarning(dc%s()) << "Error occurred while reading block \\"%s\\" registers";' % (className, blockName))
|
||||
writeLine(fileDescriptor, ' }')
|
||||
writeLine(fileDescriptor, '}')
|
||||
writeLine(fileDescriptor)
|
||||
|
||||
##############################################################
|
||||
|
||||
def writeInternalPropertyReadMethodDeclarationsTcp(fileDescriptor, registerDefinitions):
|
||||
for registerDefinition in registerDefinitions:
|
||||
propertyName = registerDefinition['id']
|
||||
writeLine(fileDescriptor, ' QModbusReply *read%s();' % (propertyName[0].upper() + propertyName[1:]))
|
||||
|
||||
|
||||
def writeInternalPropertyReadMethodImplementationsTcp(fileDescriptor, className, registerDefinitions):
|
||||
for registerDefinition in registerDefinitions:
|
||||
propertyName = registerDefinition['id']
|
||||
writeLine(fileDescriptor, 'QModbusReply *%s::read%s()' % (className, propertyName[0].upper() + propertyName[1:]))
|
||||
writeLine(fileDescriptor, '{')
|
||||
|
||||
# Build request depending on the register type
|
||||
if registerDefinition['registerType'] == 'inputRegister':
|
||||
writeLine(fileDescriptor, ' QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::InputRegisters, %s, %s);' % (registerDefinition['address'], registerDefinition['size']))
|
||||
elif registerDefinition['registerType'] == 'discreteInputs':
|
||||
writeLine(fileDescriptor, ' QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::DiscreteInputs, %s, %s);' % (registerDefinition['address'], registerDefinition['size']))
|
||||
elif registerDefinition['registerType'] == 'coils':
|
||||
writeLine(fileDescriptor, ' QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::Coils, %s, %s);' % (registerDefinition['address'], registerDefinition['size']))
|
||||
else:
|
||||
#Default to holdingRegister
|
||||
writeLine(fileDescriptor, ' QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, %s, %s);' % (registerDefinition['address'], registerDefinition['size']))
|
||||
|
||||
writeLine(fileDescriptor, ' return sendReadRequest(request, m_slaveId);')
|
||||
writeLine(fileDescriptor, '}')
|
||||
writeLine(fileDescriptor)
|
||||
|
||||
|
||||
##############################################################
|
||||
|
||||
def writeInternalBlockReadMethodDeclarationsTcp(fileDescriptor, blockDefinitions):
|
||||
for blockDefinition in blockDefinitions:
|
||||
blockName = blockDefinition['id']
|
||||
blockRegisters = blockDefinition['registers']
|
||||
blockStartAddress = 0
|
||||
registerCount = 0
|
||||
blockSize = 0
|
||||
registerType = ""
|
||||
|
||||
for i, blockRegister in enumerate(blockRegisters):
|
||||
if i == 0:
|
||||
blockStartAddress = blockRegister['address']
|
||||
registerType = blockRegister['registerType']
|
||||
|
||||
registerCount += 1
|
||||
blockSize += blockRegister['size']
|
||||
|
||||
writeLine(fileDescriptor, ' /* Read block from start addess %s with size of %s registers containing following %s properties:' % (blockStartAddress, blockSize, registerCount))
|
||||
for i, registerDefinition in enumerate(blockRegisters):
|
||||
if 'unit' in registerDefinition and registerDefinition['unit'] != '':
|
||||
writeLine(fileDescriptor, ' - %s [%s] - Address: %s, Size: %s' % (registerDefinition['description'], registerDefinition['unit'], registerDefinition['address'], registerDefinition['size']))
|
||||
else:
|
||||
writeLine(fileDescriptor, ' - %s - Address: %s, Size: %s' % (registerDefinition['description'], registerDefinition['address'], registerDefinition['size']))
|
||||
writeLine(fileDescriptor, ' */' )
|
||||
writeLine(fileDescriptor, ' QModbusReply *readBlock%s();' % (blockName[0].upper() + blockName[1:]))
|
||||
writeLine(fileDescriptor)
|
||||
|
||||
|
||||
def writeInternalBlockReadMethodImplementationsTcp(fileDescriptor, className, blockDefinitions):
|
||||
for blockDefinition in blockDefinitions:
|
||||
blockName = blockDefinition['id']
|
||||
blockRegisters = blockDefinition['registers']
|
||||
blockStartAddress = 0
|
||||
registerCount = 0
|
||||
blockSize = 0
|
||||
registerType = ""
|
||||
|
||||
for i, blockRegister in enumerate(blockRegisters):
|
||||
if i == 0:
|
||||
blockStartAddress = blockRegister['address']
|
||||
registerType = blockRegister['registerType']
|
||||
|
||||
registerCount += 1
|
||||
blockSize += blockRegister['size']
|
||||
|
||||
|
||||
writeLine(fileDescriptor, 'QModbusReply *%s::readBlock%s()' % (className, blockName[0].upper() + blockName[1:]))
|
||||
writeLine(fileDescriptor, '{')
|
||||
|
||||
# Build request depending on the register type
|
||||
if registerType == 'inputRegister':
|
||||
writeLine(fileDescriptor, ' QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::InputRegisters, %s, %s);' % (blockStartAddress, blockSize))
|
||||
elif registerType == 'discreteInputs':
|
||||
writeLine(fileDescriptor, ' QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::DiscreteInputs, %s, %s);' % (blockStartAddress, blockSize))
|
||||
elif registerType == 'coils':
|
||||
writeLine(fileDescriptor, ' QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::Coils, %s, %s);' % (blockStartAddress, blockSize))
|
||||
else:
|
||||
#Default to holdingRegister
|
||||
writeLine(fileDescriptor, ' QModbusDataUnit request = QModbusDataUnit(QModbusDataUnit::RegisterType::HoldingRegisters, %s, %s);' % (blockStartAddress, blockSize))
|
||||
|
||||
writeLine(fileDescriptor, ' return sendReadRequest(request, m_slaveId);')
|
||||
|
||||
writeLine(fileDescriptor, '}')
|
||||
writeLine(fileDescriptor)
|
||||
|
||||
##############################################################
|
||||
|
||||
def writeInitMethodImplementationTcp(fileDescriptor, className, registerDefinitions, blockDefinitions):
|
||||
writeLine(fileDescriptor, 'void %s::initialize()' % (className))
|
||||
writeLine(fileDescriptor, '{')
|
||||
|
||||
# First check if there are any init registers
|
||||
initRequired = False
|
||||
for registerDefinition in registerDefinitions:
|
||||
if registerDefinition['readSchedule'] == 'init':
|
||||
initRequired = True
|
||||
break
|
||||
|
||||
for blockDefinition in blockDefinitions:
|
||||
if 'readSchedule' in blockDefinition and blockDefinition['readSchedule'] == 'init':
|
||||
initRequired = True
|
||||
break
|
||||
|
||||
if initRequired:
|
||||
writeLine(fileDescriptor, ' QModbusReply *reply = nullptr;')
|
||||
writeLine(fileDescriptor)
|
||||
writeLine(fileDescriptor, ' if (!m_pendingInitReplies.isEmpty()) {')
|
||||
writeLine(fileDescriptor, ' qCWarning(dc%s()) << "Tried to initialize but there are still some init replies pending.";' % className)
|
||||
writeLine(fileDescriptor, ' return;')
|
||||
writeLine(fileDescriptor, ' }')
|
||||
|
||||
# Read individual registers
|
||||
for registerDefinition in registerDefinitions:
|
||||
propertyName = registerDefinition['id']
|
||||
propertyTyp = getCppDataType(registerDefinition)
|
||||
|
||||
if 'readSchedule' in registerDefinition and registerDefinition['readSchedule'] == 'init':
|
||||
writeLine(fileDescriptor)
|
||||
writeLine(fileDescriptor, ' // Read %s' % registerDefinition['description'])
|
||||
writeLine(fileDescriptor, ' qCDebug(dc%s()) << "--> Read init \\"%s\\" register:" << %s << "size:" << %s;' % (className, registerDefinition['description'], registerDefinition['address'], registerDefinition['size']))
|
||||
writeLine(fileDescriptor, ' reply = read%s();' % (propertyName[0].upper() + propertyName[1:]))
|
||||
writeLine(fileDescriptor, ' if (reply) {')
|
||||
writeLine(fileDescriptor, ' if (!reply->isFinished()) {')
|
||||
writeLine(fileDescriptor, ' m_pendingInitReplies.append(reply);')
|
||||
writeLine(fileDescriptor, ' connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater);')
|
||||
writeLine(fileDescriptor, ' connect(reply, &QModbusReply::finished, this, [this, reply](){')
|
||||
writeLine(fileDescriptor, ' if (reply->error() == QModbusDevice::NoError) {')
|
||||
writeLine(fileDescriptor, ' const QModbusDataUnit unit = reply->result();')
|
||||
writeLine(fileDescriptor, ' qCDebug(dc%s()) << "<-- Response from init \\"%s\\" register" << %s << "size:" << %s << unit.values();' % (className, registerDefinition['description'], registerDefinition['address'], registerDefinition['size']))
|
||||
writeLine(fileDescriptor, ' process%sRegisterValues(unit.values());' % (propertyName[0].upper() + propertyName[1:]))
|
||||
writeLine(fileDescriptor, ' }')
|
||||
writeLine(fileDescriptor)
|
||||
writeLine(fileDescriptor, ' m_pendingInitReplies.removeAll(reply);')
|
||||
writeLine(fileDescriptor, ' verifyInitFinished();')
|
||||
writeLine(fileDescriptor, ' });')
|
||||
writeLine(fileDescriptor)
|
||||
writeLine(fileDescriptor, ' connect(reply, &QModbusReply::errorOccurred, this, [this, reply] (QModbusDevice::Error error){')
|
||||
writeLine(fileDescriptor, ' qCWarning(dc%s()) << "Modbus reply error occurred while reading \\"%s\\" registers from" << hostAddress().toString() << error << reply->errorString();' % (className, registerDefinition['description']))
|
||||
writeLine(fileDescriptor, ' emit reply->finished(); // To make sure it will be deleted')
|
||||
writeLine(fileDescriptor, ' });')
|
||||
writeLine(fileDescriptor, ' } else {')
|
||||
writeLine(fileDescriptor, ' delete reply; // Broadcast reply returns immediatly')
|
||||
writeLine(fileDescriptor, ' }')
|
||||
writeLine(fileDescriptor, ' } else {')
|
||||
writeLine(fileDescriptor, ' qCWarning(dc%s()) << "Error occurred while reading \\"%s\\" registers from" << hostAddress().toString() << errorString();' % (className, registerDefinition['description']))
|
||||
writeLine(fileDescriptor, ' }')
|
||||
|
||||
# Read init blocks
|
||||
for blockDefinition in blockDefinitions:
|
||||
blockName = blockDefinition['id']
|
||||
blockRegisters = blockDefinition['registers']
|
||||
|
||||
if 'readSchedule' in blockDefinition and blockDefinition['readSchedule'] == 'init':
|
||||
blockStartAddress = 0
|
||||
registerCount = 0
|
||||
blockSize = 0
|
||||
registerType = ""
|
||||
|
||||
for i, blockRegister in enumerate(blockRegisters):
|
||||
if i == 0:
|
||||
blockStartAddress = blockRegister['address']
|
||||
registerType = blockRegister['registerType']
|
||||
|
||||
registerCount += 1
|
||||
blockSize += blockRegister['size']
|
||||
|
||||
writeLine(fileDescriptor)
|
||||
writeLine(fileDescriptor, ' // Read %s' % blockName)
|
||||
writeLine(fileDescriptor, ' qCDebug(dc%s()) << "--> Read init block \\"%s\\" registers from:" << %s << "size:" << %s;' % (className, blockName, blockStartAddress, blockSize))
|
||||
writeLine(fileDescriptor, ' reply = readBlock%s();' % (blockName[0].upper() + blockName[1:]))
|
||||
writeLine(fileDescriptor, ' if (reply) {')
|
||||
writeLine(fileDescriptor, ' if (!reply->isFinished()) {')
|
||||
writeLine(fileDescriptor, ' m_pendingInitReplies.append(reply);')
|
||||
writeLine(fileDescriptor, ' connect(reply, &QModbusReply::finished, this, [this, reply](){')
|
||||
writeLine(fileDescriptor, ' if (reply->error() == QModbusDevice::NoError) {')
|
||||
writeLine(fileDescriptor, ' const QModbusDataUnit unit = reply->result();')
|
||||
writeLine(fileDescriptor, ' const QVector<quint16> blockValues = unit.values();')
|
||||
writeLine(fileDescriptor, ' qCDebug(dc%s()) << "<-- Response from reading init block \\"%s\\" register" << %s << "size:" << %s << blockValues;' % (className, blockName, blockStartAddress, blockSize))
|
||||
|
||||
# Start parsing the registers using offsets
|
||||
offset = 0
|
||||
for i, blockRegister in enumerate(blockRegisters):
|
||||
propertyName = blockRegister['id']
|
||||
propertyTyp = getCppDataType(blockRegister)
|
||||
writeLine(fileDescriptor, ' process%sRegisterValues(blockValues.mid(%s, %s));' % (propertyName[0].upper() + propertyName[1:], offset, blockRegister['size']))
|
||||
offset += blockRegister['size']
|
||||
|
||||
writeLine(fileDescriptor, ' m_pendingInitReplies.removeAll(reply);')
|
||||
writeLine(fileDescriptor, ' verifyInitFinished();')
|
||||
writeLine(fileDescriptor, ' }')
|
||||
writeLine(fileDescriptor, ' });')
|
||||
writeLine(fileDescriptor)
|
||||
writeLine(fileDescriptor, ' connect(reply, &QModbusReply::errorOccurred, this, [reply] (QModbusDevice::Error error){')
|
||||
writeLine(fileDescriptor, ' qCWarning(dc%s()) << "Modbus reply error occurred while updating block \\"%s\\" registers" << error << reply->errorString();' % (className, blockName))
|
||||
writeLine(fileDescriptor, ' emit reply->finished();')
|
||||
writeLine(fileDescriptor, ' });')
|
||||
writeLine(fileDescriptor, ' }')
|
||||
writeLine(fileDescriptor, ' } else {')
|
||||
writeLine(fileDescriptor, ' qCWarning(dc%s()) << "Error occurred while reading block \\"%s\\" registers";' % (className, blockName))
|
||||
writeLine(fileDescriptor, ' }')
|
||||
writeLine(fileDescriptor)
|
||||
|
||||
else:
|
||||
writeLine(fileDescriptor, ' // No init registers defined. Nothing to be done and we are finished.')
|
||||
writeLine(fileDescriptor, ' emit initializationFinished();')
|
||||
|
||||
writeLine(fileDescriptor, '}')
|
||||
writeLine(fileDescriptor)
|
||||
499
libnymea-modbus/tools/connectiontool/toolcommon.py
Normal file
499
libnymea-modbus/tools/connectiontool/toolcommon.py
Normal file
@ -0,0 +1,499 @@
|
||||
# Copyright (C) 2021 - 2022 nymea GmbH <developer@nymea.io>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import json
|
||||
import shutil
|
||||
import datetime
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger('modbus-tools')
|
||||
|
||||
def convertToAlphaNumeric(text):
|
||||
finalText = ''
|
||||
for character in text:
|
||||
if character.isalnum():
|
||||
finalText += character
|
||||
else:
|
||||
finalText += ' '
|
||||
return finalText
|
||||
|
||||
|
||||
def splitCamelCase(text):
|
||||
return re.sub('([A-Z][a-z]+)', r' \1', re.sub('([A-Z]+)', r' \1', text)).split()
|
||||
|
||||
|
||||
def convertToCamelCase(text, capitalize = False):
|
||||
s = convertToAlphaNumeric(text)
|
||||
s = s.replace("-", " ").replace("_", " ")
|
||||
words = s.split()
|
||||
logger.debug('--> words', words)
|
||||
finalWords = []
|
||||
|
||||
for i in range(len(words)):
|
||||
camelCaseSplit = splitCamelCase(words[i])
|
||||
if len(camelCaseSplit) == 0:
|
||||
finalWords.append(words[i])
|
||||
else:
|
||||
logging.debug('Camel calse split words', camelCaseSplit)
|
||||
for j in range(len(camelCaseSplit)):
|
||||
finalWords.append(camelCaseSplit[j])
|
||||
|
||||
if len(finalWords) == 0:
|
||||
return text
|
||||
|
||||
finalText = ''
|
||||
if capitalize:
|
||||
finalText = finalWords[0].capitalize() + ''.join(i.capitalize() for i in finalWords[1:])
|
||||
else:
|
||||
finalText = finalWords[0].lower() + ''.join(i.capitalize() for i in finalWords[1:])
|
||||
logging.debug('Convert camel case:', text, '-->', finalText)
|
||||
return finalText
|
||||
|
||||
|
||||
def loadJsonFile(filePath):
|
||||
logger.info('Loading JSON file %s', filePath)
|
||||
jsonFile = open(filePath, 'r')
|
||||
return json.load(jsonFile)
|
||||
|
||||
|
||||
def writeLine(fileDescriptor, line = ''):
|
||||
fileDescriptor.write(line + '\n')
|
||||
|
||||
|
||||
def writeLicenseHeader(fileDescriptor):
|
||||
writeLine(fileDescriptor, '/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *')
|
||||
writeLine(fileDescriptor, '*')
|
||||
writeLine(fileDescriptor, '* Copyright 2013 - %s, nymea GmbH' % datetime.datetime.now().year)
|
||||
writeLine(fileDescriptor, '* Contact: contact@nymea.io')
|
||||
writeLine(fileDescriptor, '*')
|
||||
writeLine(fileDescriptor, '* This fileDescriptor is part of nymea.')
|
||||
writeLine(fileDescriptor, '* This project including source code and documentation is protected by')
|
||||
writeLine(fileDescriptor, '* copyright law, and remains the property of nymea GmbH. All rights, including')
|
||||
writeLine(fileDescriptor, '* reproduction, publication, editing and translation, are reserved. The use of')
|
||||
writeLine(fileDescriptor, '* this project is subject to the terms of a license agreement to be concluded')
|
||||
writeLine(fileDescriptor, '* with nymea GmbH in accordance with the terms of use of nymea GmbH, available')
|
||||
writeLine(fileDescriptor, '* under https://nymea.io/license')
|
||||
writeLine(fileDescriptor, '*')
|
||||
writeLine(fileDescriptor, '* GNU Lesser General Public License Usage')
|
||||
writeLine(fileDescriptor, '* Alternatively, this project may be redistributed and/or modified under the')
|
||||
writeLine(fileDescriptor, '* terms of the GNU Lesser General Public License as published by the Free')
|
||||
writeLine(fileDescriptor, '* Software Foundation; version 3. This project is distributed in the hope that')
|
||||
writeLine(fileDescriptor, '* it will be useful, but WITHOUT ANY WARRANTY; without even the implied')
|
||||
writeLine(fileDescriptor, '* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU')
|
||||
writeLine(fileDescriptor, '* Lesser General Public License for more details.')
|
||||
writeLine(fileDescriptor, '*')
|
||||
writeLine(fileDescriptor, '* You should have received a copy of the GNU Lesser General Public License')
|
||||
writeLine(fileDescriptor, '* along with this project. If not, see <https://www.gnu.org/licenses/>.')
|
||||
writeLine(fileDescriptor, '*')
|
||||
writeLine(fileDescriptor, '* For any further details and any questions please contact us under')
|
||||
writeLine(fileDescriptor, '* contact@nymea.io or see our FAQ/Licensing Information on')
|
||||
writeLine(fileDescriptor, '* https://nymea.io/license/faq')
|
||||
writeLine(fileDescriptor, '*')
|
||||
writeLine(fileDescriptor, '* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */')
|
||||
writeLine(fileDescriptor)
|
||||
writeLine(fileDescriptor, '/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *')
|
||||
writeLine(fileDescriptor, '*')
|
||||
writeLine(fileDescriptor, '* WARNING')
|
||||
writeLine(fileDescriptor, '*')
|
||||
writeLine(fileDescriptor, '* This file has been autogenerated. Any changes in this file may be overwritten.')
|
||||
writeLine(fileDescriptor, '* If you want to change something, update the register json or the tool.')
|
||||
writeLine(fileDescriptor, '*')
|
||||
writeLine(fileDescriptor, '* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */')
|
||||
writeLine(fileDescriptor)
|
||||
|
||||
|
||||
def writeRegistersEnum(fileDescriptor, registerJson):
|
||||
logger.debug('Writing enum for all registers')
|
||||
|
||||
registerEnums = {}
|
||||
|
||||
# Read all register names and addresses
|
||||
if 'blocks' in registerJson:
|
||||
for blockDefinition in registerJson['blocks']:
|
||||
blockRegisters = blockDefinition['registers']
|
||||
for blockRegister in blockRegisters:
|
||||
registerName = blockRegister['id']
|
||||
registerAddress = blockRegister['address']
|
||||
registerEnums[registerAddress] = registerName
|
||||
|
||||
for registerDefinition in registerJson['registers']:
|
||||
registerName = registerDefinition['id']
|
||||
registerAddress = registerDefinition['address']
|
||||
registerEnums[registerAddress] = registerName
|
||||
|
||||
|
||||
# Sort the enum map
|
||||
registersKeys = registerEnums.keys()
|
||||
sortedRegistersKeys = sorted(registersKeys)
|
||||
sortedRegisterEnumList = []
|
||||
|
||||
logger.debug('Sorted registers')
|
||||
for registerAddress in sortedRegistersKeys:
|
||||
logger.debug('--> %s : %s' % (registerAddress, registerEnums[registerAddress]))
|
||||
enumData = {}
|
||||
enumData['key'] = registerEnums[registerAddress]
|
||||
enumData['value'] = registerAddress
|
||||
sortedRegisterEnumList.append(enumData)
|
||||
|
||||
enumName = 'Registers'
|
||||
writeLine(fileDescriptor, ' enum %s {' % enumName)
|
||||
for i in range(len(sortedRegisterEnumList)):
|
||||
enumData = sortedRegisterEnumList[i]
|
||||
line = (' Register%s = %s' % (enumData['key'][0].upper() + enumData['key'][1:] , enumData['value']))
|
||||
if i < (len(sortedRegisterEnumList) - 1):
|
||||
line += ','
|
||||
|
||||
writeLine(fileDescriptor, line)
|
||||
|
||||
writeLine(fileDescriptor, ' };')
|
||||
writeLine(fileDescriptor, ' Q_ENUM(%s)' % enumName)
|
||||
writeLine(fileDescriptor)
|
||||
|
||||
|
||||
def writeEnumDefinition(fileDescriptor, enumDefinition):
|
||||
logger.debug('Writing enum %s', enumDefinition)
|
||||
enumName = enumDefinition['name']
|
||||
enumValues = enumDefinition['values']
|
||||
writeLine(fileDescriptor, ' enum %s {' % enumName)
|
||||
for i in range(len(enumValues)):
|
||||
enumData = enumValues[i]
|
||||
line = (' %s%s = %s' % (enumName, enumData['key'], enumData['value']))
|
||||
if i < (len(enumValues) - 1):
|
||||
line += ','
|
||||
|
||||
writeLine(fileDescriptor, line)
|
||||
|
||||
writeLine(fileDescriptor, ' };')
|
||||
writeLine(fileDescriptor, ' Q_ENUM(%s)' % enumName)
|
||||
writeLine(fileDescriptor)
|
||||
|
||||
|
||||
def getCppDataType(registerDefinition, rawType = False):
|
||||
if not rawType:
|
||||
if 'enum' in registerDefinition:
|
||||
return registerDefinition['enum']
|
||||
|
||||
if 'scaleFactor' in registerDefinition or 'staticScaleFactor' in registerDefinition:
|
||||
return 'float'
|
||||
|
||||
if registerDefinition['type'] == 'uint16':
|
||||
return 'quint16'
|
||||
|
||||
if registerDefinition['type'] == 'int16':
|
||||
return 'qint16'
|
||||
|
||||
if registerDefinition['type'] == 'uint32':
|
||||
return 'quint32'
|
||||
|
||||
if registerDefinition['type'] == 'int32':
|
||||
return 'qint32'
|
||||
|
||||
if registerDefinition['type'] == 'uint64':
|
||||
return 'quint64'
|
||||
|
||||
if registerDefinition['type'] == 'int64':
|
||||
return 'qint64'
|
||||
|
||||
if registerDefinition['type'] == 'float':
|
||||
return 'float'
|
||||
|
||||
if registerDefinition['type'] == 'float64':
|
||||
return 'double'
|
||||
|
||||
if registerDefinition['type'] == 'string':
|
||||
return 'QString'
|
||||
|
||||
|
||||
def getConversionToValueMethod(registerDefinition):
|
||||
# Handle enums
|
||||
propertyName = registerDefinition['id']
|
||||
propertyTyp = getCppDataType(registerDefinition, True)
|
||||
|
||||
if 'enum' in registerDefinition:
|
||||
enumName = registerDefinition['enum']
|
||||
if registerDefinition['type'] == 'uint16':
|
||||
return ('ModbusDataUtils::convertFromUInt16(static_cast<%s>(%s))' % (propertyTyp, propertyName))
|
||||
elif registerDefinition['type'] == 'int16':
|
||||
return ('ModbusDataUtils::convertFromInt16(static_cast<%s>(%s))' % (propertyTyp, propertyName))
|
||||
elif registerDefinition['type'] == 'uint32':
|
||||
return ('ModbusDataUtils::convertFromUInt32(static_cast<%s>(%s), m_endianness)' % (propertyTyp, propertyName))
|
||||
elif registerDefinition['type'] == 'int32':
|
||||
return ('ModbusDataUtils::convertFromInt32(static_cast<%s>(%s), m_endianness)' % (propertyTyp, propertyName))
|
||||
|
||||
# Handle scale factors
|
||||
if 'scaleFactor' in registerDefinition:
|
||||
scaleFactorProperty = 'm_%s' % registerDefinition['scaleFactor']
|
||||
if registerDefinition['type'] == 'uint16':
|
||||
return ('ModbusDataUtils::convertFromUInt16(static_cast<%s>(%s * 1.0 / pow(10, %s)))' % (propertyTyp, propertyName, scaleFactorProperty))
|
||||
elif registerDefinition['type'] == 'int16':
|
||||
return ('ModbusDataUtils::convertFromInt16(static_cast<%s>(%s * 1.0 / pow(10, %s)))' % (propertyTyp, propertyName, scaleFactorProperty))
|
||||
elif registerDefinition['type'] == 'uint32':
|
||||
return ('ModbusDataUtils::convertFromUInt32(static_cast<%s>(%s * 1.0 / pow(10, %s)), m_endianness)' % (propertyTyp, propertyName, scaleFactorProperty))
|
||||
elif registerDefinition['type'] == 'int32':
|
||||
return ('ModbusDataUtils::convertFromInt32(static_cast<%s>(%s * 1.0 / pow(10, %s)), m_endianness)' % (propertyTyp, propertyName, scaleFactorProperty))
|
||||
|
||||
elif 'staticScaleFactor' in registerDefinition:
|
||||
scaleFactor = registerDefinition['staticScaleFactor']
|
||||
if registerDefinition['type'] == 'uint16':
|
||||
return ('ModbusDataUtils::convertFromUInt16(static_cast<%s>(%s * 1.0 / pow(10, %s)))' % (propertyTyp, propertyName, scaleFactor))
|
||||
elif registerDefinition['type'] == 'int16':
|
||||
return ('ModbusDataUtils::convertFromInt16(static_cast<%s>(%s * 1.0 / pow(10, %s)))' % (propertyTyp, propertyName, scaleFactor))
|
||||
elif registerDefinition['type'] == 'uint32':
|
||||
return ('ModbusDataUtils::convertFromUInt32(static_cast<%s>(%s * 1.0 / pow(10, %s)), m_endianness)' % (propertyTyp, propertyName, scaleFactor))
|
||||
elif registerDefinition['type'] == 'int32':
|
||||
return ('ModbusDataUtils::convertFromInt32(static_cast<%s>(%s * 1.0 / pow(10, %s)), m_endianness)' % (propertyTyp, propertyName, scaleFactor))
|
||||
|
||||
# Handle default types
|
||||
elif registerDefinition['type'] == 'uint16':
|
||||
return ('ModbusDataUtils::convertFromUInt16(%s)' % propertyName)
|
||||
elif registerDefinition['type'] == 'int16':
|
||||
return ('ModbusDataUtils::convertFromInt16(%s)' % propertyName)
|
||||
elif registerDefinition['type'] == 'uint32':
|
||||
return ('ModbusDataUtils::convertFromUInt32(%s, m_endianness)' % (propertyName))
|
||||
elif registerDefinition['type'] == 'int32':
|
||||
return ('ModbusDataUtils::convertFromInt32(%s, m_endianness)' % (propertyName))
|
||||
elif registerDefinition['type'] == 'uint64':
|
||||
return ('ModbusDataUtils::convertFromUInt64(%s, m_endianness)' % (propertyName))
|
||||
elif registerDefinition['type'] == 'int64':
|
||||
return ('ModbusDataUtils::convertFromInt64(%s, m_endianness)' % (propertyName))
|
||||
elif registerDefinition['type'] == 'float':
|
||||
return ('ModbusDataUtils::convertFromFloat32(%s, m_endianness)' % propertyName)
|
||||
elif registerDefinition['type'] == 'float64':
|
||||
return ('ModbusDataUtils::convertFromFloat64(%s, m_endianness)' % propertyName)
|
||||
elif registerDefinition['type'] == 'string':
|
||||
return ('ModbusDataUtils::convertFromString(%s)' % propertyName)
|
||||
|
||||
|
||||
def getValueConversionMethod(registerDefinition):
|
||||
# Handle enums
|
||||
if 'enum' in registerDefinition:
|
||||
enumName = registerDefinition['enum']
|
||||
if registerDefinition['type'] == 'uint16':
|
||||
return ('static_cast<%s>(ModbusDataUtils::convertToUInt16(values))' % (enumName))
|
||||
elif registerDefinition['type'] == 'int16':
|
||||
return ('static_cast<%s>(ModbusDataUtils::convertToInt16(values))' % (enumName))
|
||||
elif registerDefinition['type'] == 'uint32':
|
||||
return ('static_cast<%s>(ModbusDataUtils::convertToUInt32(values, m_endianness))' % (enumName))
|
||||
elif registerDefinition['type'] == 'int32':
|
||||
return ('static_cast<%s>(ModbusDataUtils::convertToInt32(values, m_endianness))' % (enumName))
|
||||
|
||||
# Handle scale factors
|
||||
if 'scaleFactor' in registerDefinition:
|
||||
scaleFactorProperty = 'm_%s' % registerDefinition['scaleFactor']
|
||||
if registerDefinition['type'] == 'uint16':
|
||||
return ('ModbusDataUtils::convertToUInt16(values) * 1.0 * pow(10, %s)' % (scaleFactorProperty))
|
||||
elif registerDefinition['type'] == 'int16':
|
||||
return ('ModbusDataUtils::convertToInt16(values) * 1.0 * pow(10, %s)' % (scaleFactorProperty))
|
||||
elif registerDefinition['type'] == 'uint32':
|
||||
return ('ModbusDataUtils::convertToUInt32(values, m_endianness) * 1.0 * pow(10, %s)' % (scaleFactorProperty))
|
||||
elif registerDefinition['type'] == 'int32':
|
||||
return ('ModbusDataUtils::convertToInt32(values, m_endianness) * 1.0 * pow(10, %s)' % (scaleFactorProperty))
|
||||
|
||||
elif 'staticScaleFactor' in registerDefinition:
|
||||
scaleFactor = registerDefinition['staticScaleFactor']
|
||||
if registerDefinition['type'] == 'uint16':
|
||||
return ('ModbusDataUtils::convertToUInt16(values) * 1.0 * pow(10, %s)' % (scaleFactor))
|
||||
elif registerDefinition['type'] == 'int16':
|
||||
return ('ModbusDataUtils::convertToInt16(values) * 1.0 * pow(10, %s)' % (scaleFactor))
|
||||
elif registerDefinition['type'] == 'uint32':
|
||||
return ('ModbusDataUtils::convertToUInt32(values, m_endianness) * 1.0 * pow(10, %s)' % (scaleFactor))
|
||||
elif registerDefinition['type'] == 'int32':
|
||||
return ('ModbusDataUtils::convertToInt32(values, m_endianness) * 1.0 * pow(10, %s)' % (scaleFactor))
|
||||
|
||||
# Handle default types
|
||||
elif registerDefinition['type'] == 'uint16':
|
||||
return ('ModbusDataUtils::convertToUInt16(values)')
|
||||
elif registerDefinition['type'] == 'int16':
|
||||
return ('ModbusDataUtils::convertToInt16(values)')
|
||||
elif registerDefinition['type'] == 'uint32':
|
||||
return ('ModbusDataUtils::convertToUInt32(values, m_endianness)')
|
||||
elif registerDefinition['type'] == 'int32':
|
||||
return ('ModbusDataUtils::convertToInt32(values, m_endianness)')
|
||||
elif registerDefinition['type'] == 'uint64':
|
||||
return ('ModbusDataUtils::convertToUInt64(values, m_endianness)')
|
||||
elif registerDefinition['type'] == 'int64':
|
||||
return ('ModbusDataUtils::convertToInt64(values, m_endianness)')
|
||||
elif registerDefinition['type'] == 'float':
|
||||
return ('ModbusDataUtils::convertToFloat32(values, m_endianness)')
|
||||
elif registerDefinition['type'] == 'float64':
|
||||
return ('ModbusDataUtils::convertToFloat64(values, m_endianness)')
|
||||
elif registerDefinition['type'] == 'string':
|
||||
return ('ModbusDataUtils::convertToString(values)')
|
||||
|
||||
|
||||
def writeBlockGetMethodDeclarations(fileDescriptor, registerDefinitions):
|
||||
for registerDefinition in registerDefinitions:
|
||||
propertyName = registerDefinition['id']
|
||||
propertyTyp = getCppDataType(registerDefinition)
|
||||
if 'unit' in registerDefinition and registerDefinition['unit'] != '':
|
||||
writeLine(fileDescriptor, ' /* %s [%s] - Address: %s, Size: %s */' % (registerDefinition['description'], registerDefinition['unit'], registerDefinition['address'], registerDefinition['size']))
|
||||
else:
|
||||
writeLine(fileDescriptor, ' /* %s - Address: %s, Size: %s */' % (registerDefinition['description'], registerDefinition['address'], registerDefinition['size']))
|
||||
|
||||
writeLine(fileDescriptor, ' %s %s() const;' % (propertyTyp, propertyName))
|
||||
writeLine(fileDescriptor)
|
||||
|
||||
|
||||
def writePropertyUpdateMethodDeclarations(fileDescriptor, registerDefinitions):
|
||||
for registerDefinition in registerDefinitions:
|
||||
if 'readSchedule' in registerDefinition and registerDefinition['readSchedule'] == 'init':
|
||||
continue
|
||||
|
||||
propertyName = registerDefinition['id']
|
||||
propertyTyp = getCppDataType(registerDefinition)
|
||||
writeLine(fileDescriptor, ' void update%s();' % (propertyName[0].upper() + propertyName[1:]))
|
||||
|
||||
|
||||
def validateBlocks(blockDefinitions):
|
||||
for blockDefinition in blockDefinitions:
|
||||
blockName = blockDefinition['id']
|
||||
blockRegisters = blockDefinition['registers']
|
||||
|
||||
blockStartAddress = 0
|
||||
registerCount = 0
|
||||
blockSize = 0
|
||||
registerAccess = ""
|
||||
registerType = ""
|
||||
|
||||
for i, blockRegister in enumerate(blockRegisters):
|
||||
if i == 0:
|
||||
blockStartAddress = blockRegister['address']
|
||||
registerAccess = blockRegister['access']
|
||||
registerType = blockRegister['registerType']
|
||||
else:
|
||||
previouseRegisterAddress = blockRegisters[i - 1]['address']
|
||||
previouseRegisterSize = blockRegisters[i - 1]['size']
|
||||
previouseRegisterType = blockRegisters[i - 1]['registerType']
|
||||
if previouseRegisterAddress + previouseRegisterSize != blockRegister['address']:
|
||||
logger.warning('Error: block %s has invalid register order in register %s. There seems to be a gap between the registers.' % (blockName, blockRegister['id']))
|
||||
exit(1)
|
||||
|
||||
if blockRegister['access'] != registerAccess:
|
||||
logger.warning('Error: block %s has inconsistent register access in register %s. The block registers dont seem to have the same access rights.' % (blockName, blockRegister['id']))
|
||||
exit(1)
|
||||
|
||||
if blockRegister['registerType'] != registerType:
|
||||
logger.warning('Error: block %s has inconsistent register type in register %s. The block registers dont seem to be from the same type.' % (blockName, blockRegister['id']))
|
||||
exit(1)
|
||||
|
||||
registerCount += 1
|
||||
blockSize += blockRegister['size']
|
||||
|
||||
logger.debug('Define valid block \"%s\" starting at %s with length %s containing %s properties to read.' % (blockName, blockStartAddress, blockSize, registerCount))
|
||||
|
||||
|
||||
def writeBlocksUpdateMethodDeclarations(fileDescriptor, blockDefinitions):
|
||||
for blockDefinition in blockDefinitions:
|
||||
blockName = blockDefinition['id']
|
||||
blockRegisters = blockDefinition['registers']
|
||||
blockStartAddress = 0
|
||||
blockSize = 0
|
||||
registerCount = 0
|
||||
|
||||
for i, blockRegister in enumerate(blockRegisters):
|
||||
if i == 0:
|
||||
blockStartAddress = blockRegister['address']
|
||||
|
||||
registerCount += 1
|
||||
blockSize += blockRegister['size']
|
||||
|
||||
# Write the block update method
|
||||
writeLine(fileDescriptor, ' /* Read block from start addess %s with size of %s registers containing following %s properties:' % (blockStartAddress, blockSize, registerCount))
|
||||
for i, registerDefinition in enumerate(blockRegisters):
|
||||
if 'unit' in registerDefinition and registerDefinition['unit'] != '':
|
||||
writeLine(fileDescriptor, ' - %s [%s] - Address: %s, Size: %s' % (registerDefinition['description'], registerDefinition['unit'], registerDefinition['address'], registerDefinition['size']))
|
||||
else:
|
||||
writeLine(fileDescriptor, ' - %s - Address: %s, Size: %s' % (registerDefinition['description'], registerDefinition['address'], registerDefinition['size']))
|
||||
writeLine(fileDescriptor, ' */' )
|
||||
writeLine(fileDescriptor, ' void update%sBlock();' % (blockName[0].upper() + blockName[1:]))
|
||||
writeLine(fileDescriptor)
|
||||
|
||||
|
||||
def writeRegistersDebugLine(fileDescriptor, debugObjectParamName, registerDefinitions):
|
||||
for registerDefinition in registerDefinitions:
|
||||
propertyName = registerDefinition['id']
|
||||
propertyTyp = getCppDataType(registerDefinition)
|
||||
line = ('" - %s:" << %s->%s()' % (registerDefinition['description'], debugObjectParamName, propertyName))
|
||||
if 'unit' in registerDefinition and registerDefinition['unit'] != '':
|
||||
line += (' << " [%s]"' % registerDefinition['unit'])
|
||||
writeLine(fileDescriptor, ' debug.nospace().noquote() << %s << "\\n";' % (line))
|
||||
|
||||
|
||||
def writeUpdateMethod(fileDescriptor, className, registerDefinitions, blockDefinitions):
|
||||
writeLine(fileDescriptor, 'void %s::update()' % (className))
|
||||
writeLine(fileDescriptor, '{')
|
||||
for registerDefinition in registerDefinitions:
|
||||
propertyName = registerDefinition['id']
|
||||
if 'readSchedule' in registerDefinition and registerDefinition['readSchedule'] == 'update':
|
||||
writeLine(fileDescriptor, ' update%s();' % (propertyName[0].upper() + propertyName[1:]))
|
||||
|
||||
# Add the update block methods
|
||||
for blockDefinition in blockDefinitions:
|
||||
blockName = blockDefinition['id']
|
||||
if 'readSchedule' in blockDefinition and blockDefinition['readSchedule'] == 'update':
|
||||
writeLine(fileDescriptor, ' update%sBlock();' % (blockName[0].upper() + blockName[1:]))
|
||||
|
||||
writeLine(fileDescriptor, '}')
|
||||
writeLine(fileDescriptor)
|
||||
|
||||
|
||||
def writePropertyChangedSignals(fileDescriptor, registerDefinitions):
|
||||
for registerDefinition in registerDefinitions:
|
||||
propertyName = registerDefinition['id']
|
||||
propertyTyp = getCppDataType(registerDefinition)
|
||||
if propertyTyp == 'QString':
|
||||
writeLine(fileDescriptor, ' void %sChanged(const %s &%s);' % (propertyName, propertyTyp, propertyName))
|
||||
else:
|
||||
writeLine(fileDescriptor, ' void %sChanged(%s %s);' % (propertyName, propertyTyp, propertyName))
|
||||
|
||||
|
||||
def writeProtectedPropertyMembers(fileDescriptor, registerDefinitions):
|
||||
for registerDefinition in registerDefinitions:
|
||||
propertyName = registerDefinition['id']
|
||||
propertyTyp = getCppDataType(registerDefinition)
|
||||
if 'defaultValue' in registerDefinition:
|
||||
writeLine(fileDescriptor, ' %s m_%s = %s;' % (propertyTyp, propertyName, registerDefinition['defaultValue']))
|
||||
else:
|
||||
writeLine(fileDescriptor, ' %s m_%s;' % (propertyTyp, propertyName))
|
||||
|
||||
|
||||
def writePropertyProcessMethodDeclaration(fileDescriptor, registerDefinitions):
|
||||
propertyVariables = []
|
||||
for registerDefinition in registerDefinitions:
|
||||
propertyName = registerDefinition['id']
|
||||
writeLine(fileDescriptor, ' void process%sRegisterValues(const QVector<quint16> values);' % (propertyName[0].upper() + propertyName[1:]))
|
||||
|
||||
writeLine(fileDescriptor)
|
||||
|
||||
|
||||
def writePropertyProcessMethodImplementations(fileDescriptor, className, registerDefinitions):
|
||||
propertyVariables = []
|
||||
for registerDefinition in registerDefinitions:
|
||||
propertyName = registerDefinition['id']
|
||||
propertyTyp = getCppDataType(registerDefinition)
|
||||
|
||||
writeLine(fileDescriptor, 'void %s::process%sRegisterValues(const QVector<quint16> values)' % (className, propertyName[0].upper() + propertyName[1:]))
|
||||
writeLine(fileDescriptor, '{')
|
||||
writeLine(fileDescriptor, ' %s received%s = %s;' % (propertyTyp, propertyName[0].upper() + propertyName[1:], getValueConversionMethod(registerDefinition)))
|
||||
writeLine(fileDescriptor, ' if (m_%s != received%s) {' % (propertyName, propertyName[0].upper() + propertyName[1:]))
|
||||
writeLine(fileDescriptor, ' m_%s = received%s;' % (propertyName, propertyName[0].upper() + propertyName[1:]))
|
||||
writeLine(fileDescriptor, ' emit %sChanged(m_%s);' % (propertyName, propertyName))
|
||||
writeLine(fileDescriptor, ' }')
|
||||
writeLine(fileDescriptor, '}')
|
||||
writeLine(fileDescriptor)
|
||||
114
libnymea-modbus/tools/examples/example-registers.json
Normal file
114
libnymea-modbus/tools/examples/example-registers.json
Normal file
@ -0,0 +1,114 @@
|
||||
{
|
||||
"className": "Example",
|
||||
"protocol": "BOTH",
|
||||
"endianness": "BigEndian",
|
||||
"enums": [
|
||||
{
|
||||
"name": "NameOfEnum",
|
||||
"values": [
|
||||
{
|
||||
"key": "EnumValue1",
|
||||
"value": 0
|
||||
},
|
||||
{
|
||||
"key": "EnumValue2",
|
||||
"value": 1
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"registers": [
|
||||
{
|
||||
"id": "foo",
|
||||
"address": 10,
|
||||
"size": 2,
|
||||
"type": "float",
|
||||
"registerType": "inputRegister",
|
||||
"readSchedule": "update",
|
||||
"description": "Foo register",
|
||||
"unit": "ValueUnit",
|
||||
"defaultValue": "0",
|
||||
"access": "RO"
|
||||
},
|
||||
{
|
||||
"id": "bar",
|
||||
"address": 20,
|
||||
"size": 2,
|
||||
"type": "float",
|
||||
"registerType": "inputRegister",
|
||||
"readSchedule": "update",
|
||||
"description": "Bar register",
|
||||
"unit": "ValueUnit",
|
||||
"defaultValue": "0",
|
||||
"access": "RO"
|
||||
}
|
||||
],
|
||||
"blocks": [
|
||||
{
|
||||
"id": "testBlock",
|
||||
"readSchedule": "update",
|
||||
"registers": [
|
||||
{
|
||||
"id": "A",
|
||||
"address": 0,
|
||||
"size": 2,
|
||||
"type": "float",
|
||||
"registerType": "inputRegister",
|
||||
"readSchedule": "update",
|
||||
"description": "A register",
|
||||
"unit": "X",
|
||||
"defaultValue": "0",
|
||||
"access": "RO"
|
||||
},
|
||||
{
|
||||
"id": "B",
|
||||
"address": 2,
|
||||
"size": 2,
|
||||
"type": "float",
|
||||
"registerType": "inputRegister",
|
||||
"readSchedule": "update",
|
||||
"description": "B register",
|
||||
"unit": "X",
|
||||
"defaultValue": "0",
|
||||
"access": "RO"
|
||||
},
|
||||
{
|
||||
"id": "C",
|
||||
"address": 4,
|
||||
"size": 2,
|
||||
"type": "float",
|
||||
"registerType": "inputRegister",
|
||||
"readSchedule": "update",
|
||||
"description": "C register",
|
||||
"unit": "X",
|
||||
"defaultValue": "0",
|
||||
"access": "RO"
|
||||
},
|
||||
{
|
||||
"id": "D",
|
||||
"address": 6,
|
||||
"size": 2,
|
||||
"type": "float",
|
||||
"registerType": "inputRegister",
|
||||
"readSchedule": "update",
|
||||
"description": "D register",
|
||||
"unit": "X",
|
||||
"defaultValue": "0",
|
||||
"access": "RO"
|
||||
},
|
||||
{
|
||||
"id": "E",
|
||||
"address": 8,
|
||||
"size": 2,
|
||||
"type": "float",
|
||||
"registerType": "inputRegister",
|
||||
"readSchedule": "update",
|
||||
"description": "E register",
|
||||
"unit": "X",
|
||||
"defaultValue": "0",
|
||||
"access": "RO"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
618
libnymea-modbus/tools/generate-connection.py
Normal file
618
libnymea-modbus/tools/generate-connection.py
Normal file
@ -0,0 +1,618 @@
|
||||
#!/usr/bin/env python3
|
||||
|
||||
# Copyright (C) 2021 - 2022 nymea GmbH <developer@nymea.io>
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or
|
||||
# modify it under the terms of the GNU General Public License
|
||||
# as published by the Free Software Foundation; either version 2
|
||||
# of the License, or (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
||||
|
||||
# To lazy to type all those register plugins, let's make live much easier and generate code from a json register definition
|
||||
|
||||
import os
|
||||
import re
|
||||
import sys
|
||||
import json
|
||||
import time
|
||||
import shutil
|
||||
import argparse
|
||||
import datetime
|
||||
import logging
|
||||
|
||||
from connectiontool.toolcommon import *
|
||||
from connectiontool.modbusrtu import *
|
||||
from connectiontool.modbustcp import *
|
||||
|
||||
def writeTcpHeaderFile():
|
||||
logger.info('Writing modbus TCP header file %s' % headerFilePath)
|
||||
headerFile = open(headerFilePath, 'w')
|
||||
|
||||
writeLicenseHeader(headerFile)
|
||||
writeLine(headerFile, '#ifndef %s_H' % className.upper())
|
||||
writeLine(headerFile, '#define %s_H' % className.upper())
|
||||
writeLine(headerFile)
|
||||
writeLine(headerFile, '#include <QObject>')
|
||||
writeLine(headerFile)
|
||||
writeLine(headerFile, '#include <modbusdatautils.h>')
|
||||
writeLine(headerFile, '#include <modbustcpmaster.h>')
|
||||
|
||||
writeLine(headerFile)
|
||||
|
||||
# Begin of class
|
||||
writeLine(headerFile, 'class %s : public ModbusTCPMaster' % className)
|
||||
writeLine(headerFile, '{')
|
||||
writeLine(headerFile, ' Q_OBJECT')
|
||||
|
||||
# Public members
|
||||
writeLine(headerFile, 'public:')
|
||||
|
||||
# Write enum for all register values
|
||||
writeRegistersEnum(headerFile, registerJson)
|
||||
|
||||
# Enum declarations
|
||||
if 'enums' in registerJson:
|
||||
for enumDefinition in registerJson['enums']:
|
||||
writeEnumDefinition(headerFile, enumDefinition)
|
||||
|
||||
# Constructor
|
||||
writeLine(headerFile, ' explicit %s(const QHostAddress &hostAddress, uint port, quint16 slaveId, QObject *parent = nullptr);' % className)
|
||||
writeLine(headerFile, ' ~%s() = default;' % className)
|
||||
writeLine(headerFile)
|
||||
writeLine(headerFile, ' ModbusDataUtils::ByteOrder endianness() const;')
|
||||
writeLine(headerFile, ' void setEndianness(ModbusDataUtils::ByteOrder endianness);')
|
||||
writeLine(headerFile)
|
||||
|
||||
# Write registers get method declarations
|
||||
writePropertyGetSetMethodDeclarationsTcp(headerFile, registerJson['registers'])
|
||||
if 'blocks' in registerJson:
|
||||
for blockDefinition in registerJson['blocks']:
|
||||
writePropertyGetSetMethodDeclarationsTcp(headerFile, blockDefinition['registers'])
|
||||
|
||||
# Write block get/set method declarations
|
||||
writeBlocksUpdateMethodDeclarations(headerFile, registerJson['blocks'])
|
||||
|
||||
# Write init and update method declarations
|
||||
writeLine(headerFile, ' virtual void initialize();')
|
||||
writeLine(headerFile, ' virtual void update();')
|
||||
writeLine(headerFile)
|
||||
|
||||
writePropertyUpdateMethodDeclarations(headerFile, registerJson['registers'])
|
||||
writeLine(headerFile)
|
||||
if 'blocks' in registerJson:
|
||||
for blockDefinition in registerJson['blocks']:
|
||||
writePropertyUpdateMethodDeclarations(headerFile, blockDefinition['registers'])
|
||||
|
||||
writeLine(headerFile)
|
||||
|
||||
writeInternalPropertyReadMethodDeclarationsTcp(headerFile, registerJson['registers'])
|
||||
if 'blocks' in registerJson:
|
||||
for blockDefinition in registerJson['blocks']:
|
||||
writeInternalPropertyReadMethodDeclarationsTcp(headerFile, blockDefinition['registers'])
|
||||
|
||||
writeLine(headerFile)
|
||||
writeInternalBlockReadMethodDeclarationsTcp(headerFile, registerJson['blocks'])
|
||||
|
||||
writeLine(headerFile)
|
||||
|
||||
# Write registers value changed signals
|
||||
writeLine(headerFile, 'signals:')
|
||||
writeLine(headerFile, ' void initializationFinished();')
|
||||
writeLine(headerFile, ' void endiannessChanged(ModbusDataUtils::ByteOrder endianness);')
|
||||
writeLine(headerFile)
|
||||
writePropertyChangedSignals(headerFile, registerJson['registers'])
|
||||
writeLine(headerFile)
|
||||
if 'blocks' in registerJson:
|
||||
for blockDefinition in registerJson['blocks']:
|
||||
writePropertyChangedSignals(headerFile, blockDefinition['registers'])
|
||||
|
||||
writeLine(headerFile)
|
||||
|
||||
# Protected members
|
||||
writeLine(headerFile, 'protected:')
|
||||
|
||||
writeLine(headerFile)
|
||||
writeProtectedPropertyMembers(headerFile, registerJson['registers'])
|
||||
if 'blocks' in registerJson:
|
||||
for blockDefinition in registerJson['blocks']:
|
||||
writeProtectedPropertyMembers(headerFile, blockDefinition['registers'])
|
||||
|
||||
writeLine(headerFile)
|
||||
|
||||
writePropertyProcessMethodDeclaration(headerFile, registerJson['registers'])
|
||||
if 'blocks' in registerJson:
|
||||
for blockDefinition in registerJson['blocks']:
|
||||
writePropertyProcessMethodDeclaration(headerFile, blockDefinition['registers'])
|
||||
|
||||
writeLine(headerFile)
|
||||
|
||||
# Private members
|
||||
writeLine(headerFile, 'private:')
|
||||
writeLine(headerFile, ' quint16 m_slaveId = 1;')
|
||||
writeLine(headerFile, ' QVector<QModbusReply *> m_pendingInitReplies;')
|
||||
writeLine(headerFile, ' ModbusDataUtils::ByteOrder m_endianness = ModbusDataUtils::ByteOrder%s;' % endianness)
|
||||
writeLine(headerFile)
|
||||
writeLine(headerFile, ' void verifyInitFinished();')
|
||||
writeLine(headerFile)
|
||||
|
||||
# End of class
|
||||
writeLine(headerFile)
|
||||
writeLine(headerFile, '};')
|
||||
writeLine(headerFile)
|
||||
writeLine(headerFile, 'QDebug operator<<(QDebug debug, %s *%s);' % (className, className[0].lower() + className[1:]))
|
||||
writeLine(headerFile)
|
||||
writeLine(headerFile, '#endif // %s_H' % className.upper())
|
||||
|
||||
headerFile.close()
|
||||
|
||||
|
||||
def writeTcpSourceFile():
|
||||
logger.info('Writing modbus TCP source file %s' % sourceFilePath)
|
||||
sourceFile = open(sourceFilePath, 'w')
|
||||
writeLicenseHeader(sourceFile)
|
||||
writeLine(sourceFile)
|
||||
writeLine(sourceFile, '#include "%s"' % headerFileName)
|
||||
writeLine(sourceFile, '#include <loggingcategories.h>')
|
||||
writeLine(sourceFile)
|
||||
writeLine(sourceFile, 'NYMEA_LOGGING_CATEGORY(dc%s, "%s")' % (className, className))
|
||||
writeLine(sourceFile)
|
||||
|
||||
# Constructor
|
||||
writeLine(sourceFile, '%s::%s(const QHostAddress &hostAddress, uint port, quint16 slaveId, QObject *parent) :' % (className, className))
|
||||
writeLine(sourceFile, ' ModbusTCPMaster(hostAddress, port, parent),')
|
||||
writeLine(sourceFile, ' m_slaveId(slaveId)')
|
||||
writeLine(sourceFile, '{')
|
||||
writeLine(sourceFile, ' ')
|
||||
writeLine(sourceFile, '}')
|
||||
writeLine(sourceFile)
|
||||
|
||||
writeLine(sourceFile, 'ModbusDataUtils::ByteOrder %s::endianness() const' % (className))
|
||||
writeLine(sourceFile, '{')
|
||||
writeLine(sourceFile, ' return m_endianness;')
|
||||
writeLine(sourceFile, '}')
|
||||
writeLine(sourceFile)
|
||||
|
||||
writeLine(sourceFile, 'void %s::setEndianness(ModbusDataUtils::ByteOrder endianness)' % (className))
|
||||
writeLine(sourceFile, '{')
|
||||
writeLine(sourceFile, ' if (m_endianness == endianness)')
|
||||
writeLine(sourceFile, ' return;')
|
||||
writeLine(sourceFile,)
|
||||
writeLine(sourceFile, ' m_endianness = endianness;')
|
||||
writeLine(sourceFile, ' emit endiannessChanged(m_endianness);')
|
||||
writeLine(sourceFile, '}')
|
||||
writeLine(sourceFile)
|
||||
|
||||
# Property get methods
|
||||
writePropertyGetSetMethodImplementationsTcp(sourceFile, className, registerJson['registers'])
|
||||
if 'blocks' in registerJson:
|
||||
for blockDefinition in registerJson['blocks']:
|
||||
writePropertyGetSetMethodImplementationsTcp(sourceFile, className, blockDefinition['registers'])
|
||||
|
||||
# Write init and update method implementation
|
||||
writeInitMethodImplementationTcp(sourceFile, className, registerJson['registers'], registerJson['blocks'])
|
||||
writeUpdateMethod(sourceFile, className, registerJson['registers'], registerJson['blocks'])
|
||||
|
||||
# Write update methods
|
||||
writePropertyUpdateMethodImplementationsTcp(sourceFile, className, registerJson['registers'])
|
||||
if 'blocks' in registerJson:
|
||||
for blockDefinition in registerJson['blocks']:
|
||||
writePropertyUpdateMethodImplementationsTcp(sourceFile, className, blockDefinition['registers'])
|
||||
|
||||
# Write block update method
|
||||
writeBlockUpdateMethodImplementationsTcp(sourceFile, className, registerJson['blocks'])
|
||||
|
||||
# Write internal protected property read method implementations
|
||||
writeInternalPropertyReadMethodImplementationsTcp(sourceFile, className, registerJson['registers'])
|
||||
if 'blocks' in registerJson:
|
||||
for blockDefinition in registerJson['blocks']:
|
||||
writeInternalPropertyReadMethodImplementationsTcp(sourceFile, className, blockDefinition['registers'])
|
||||
|
||||
writeInternalBlockReadMethodImplementationsTcp(sourceFile, className, registerJson['blocks'])
|
||||
|
||||
# Write internal processors of properties
|
||||
writePropertyProcessMethodImplementations(sourceFile, className, registerJson['registers'])
|
||||
if 'blocks' in registerJson:
|
||||
for blockDefinition in registerJson['blocks']:
|
||||
writePropertyProcessMethodImplementations(sourceFile, className, blockDefinition['registers'])
|
||||
|
||||
writeLine(sourceFile, 'void %s::verifyInitFinished()' % (className))
|
||||
writeLine(sourceFile, '{')
|
||||
writeLine(sourceFile, ' if (m_pendingInitReplies.isEmpty()) {')
|
||||
writeLine(sourceFile, ' qCDebug(dc%s()) << "Initialization finished of %s" << hostAddress().toString();' % (className, className))
|
||||
writeLine(sourceFile, ' emit initializationFinished();')
|
||||
writeLine(sourceFile, ' }')
|
||||
writeLine(sourceFile, '}')
|
||||
writeLine(sourceFile)
|
||||
|
||||
# Write the debug print
|
||||
debugObjectParamName = className[0].lower() + className[1:]
|
||||
writeLine(sourceFile, 'QDebug operator<<(QDebug debug, %s *%s)' % (className, debugObjectParamName))
|
||||
writeLine(sourceFile, '{')
|
||||
writeLine(sourceFile, ' debug.nospace().noquote() << "%s(" << %s->hostAddress().toString() << ":" << %s->port() << ")" << "\\n";' % (className, debugObjectParamName, debugObjectParamName))
|
||||
writeRegistersDebugLine(sourceFile, debugObjectParamName, registerJson['registers'])
|
||||
if 'blocks' in registerJson:
|
||||
for blockDefinition in registerJson['blocks']:
|
||||
writeRegistersDebugLine(sourceFile, debugObjectParamName, blockDefinition['registers'])
|
||||
|
||||
writeLine(sourceFile, ' return debug.quote().space();')
|
||||
writeLine(sourceFile, '}')
|
||||
writeLine(sourceFile)
|
||||
|
||||
sourceFile.close()
|
||||
|
||||
|
||||
##########################################################################################################
|
||||
def writeRtuHeaderFile():
|
||||
logger.info('Writing modbus RTU header file %s' % headerFilePath)
|
||||
headerFile = open(headerFilePath, 'w')
|
||||
|
||||
writeLicenseHeader(headerFile)
|
||||
writeLine(headerFile, '#ifndef %s_H' % className.upper())
|
||||
writeLine(headerFile, '#define %s_H' % className.upper())
|
||||
writeLine(headerFile)
|
||||
writeLine(headerFile, '#include <QObject>')
|
||||
writeLine(headerFile)
|
||||
writeLine(headerFile, '#include <modbusdatautils.h>')
|
||||
writeLine(headerFile, '#include <hardware/modbus/modbusrtumaster.h>')
|
||||
|
||||
writeLine(headerFile)
|
||||
|
||||
# Begin of class
|
||||
writeLine(headerFile, 'class %s : public QObject' % className)
|
||||
writeLine(headerFile, '{')
|
||||
writeLine(headerFile, ' Q_OBJECT')
|
||||
|
||||
# Public members
|
||||
writeLine(headerFile, 'public:')
|
||||
|
||||
# Write enum for all register values
|
||||
writeRegistersEnum(headerFile, registerJson)
|
||||
|
||||
# Enum declarations
|
||||
if 'enums' in registerJson:
|
||||
for enumDefinition in registerJson['enums']:
|
||||
writeEnumDefinition(headerFile, enumDefinition)
|
||||
|
||||
# Constructor
|
||||
writeLine(headerFile, ' explicit %s(ModbusRtuMaster *modbusRtuMaster, quint16 slaveId, QObject *parent = nullptr);' % className)
|
||||
writeLine(headerFile, ' ~%s() = default;' % className)
|
||||
writeLine(headerFile)
|
||||
|
||||
writeLine(headerFile, ' ModbusRtuMaster *modbusRtuMaster() const;')
|
||||
writeLine(headerFile, ' quint16 slaveId() const;')
|
||||
writeLine(headerFile)
|
||||
writeLine(headerFile, ' ModbusDataUtils::ByteOrder endianness() const;')
|
||||
writeLine(headerFile, ' void setEndianness(ModbusDataUtils::ByteOrder endianness);')
|
||||
writeLine(headerFile)
|
||||
|
||||
# Write registers get method declarations
|
||||
writePropertyGetSetMethodDeclarationsRtu(headerFile, registerJson['registers'])
|
||||
if 'blocks' in registerJson:
|
||||
for blockDefinition in registerJson['blocks']:
|
||||
writePropertyGetSetMethodDeclarationsRtu(headerFile, blockDefinition['registers'])
|
||||
|
||||
# Write block get/set method declarations
|
||||
writeBlocksUpdateMethodDeclarations(headerFile, registerJson['blocks'])
|
||||
|
||||
# Write init and update method declarations
|
||||
writeLine(headerFile, ' virtual void initialize();')
|
||||
writeLine(headerFile, ' virtual void update();')
|
||||
writeLine(headerFile)
|
||||
|
||||
writePropertyUpdateMethodDeclarations(headerFile, registerJson['registers'])
|
||||
writeLine(headerFile)
|
||||
if 'blocks' in registerJson:
|
||||
for blockDefinition in registerJson['blocks']:
|
||||
writePropertyUpdateMethodDeclarations(headerFile, blockDefinition['registers'])
|
||||
|
||||
writeLine(headerFile)
|
||||
|
||||
writeInternalPropertyReadMethodDeclarationsRtu(headerFile, registerJson['registers'])
|
||||
if 'blocks' in registerJson:
|
||||
for blockDefinition in registerJson['blocks']:
|
||||
writeInternalPropertyReadMethodDeclarationsRtu(headerFile, blockDefinition['registers'])
|
||||
|
||||
writeLine(headerFile)
|
||||
writeInternalBlockReadMethodDeclarationsRtu(headerFile, registerJson['blocks'])
|
||||
|
||||
|
||||
# Write registers value changed signals
|
||||
writeLine(headerFile, 'signals:')
|
||||
writeLine(headerFile, ' void initializationFinished();')
|
||||
writeLine(headerFile, ' void endiannessChanged(ModbusDataUtils::ByteOrder endianness);')
|
||||
writeLine(headerFile)
|
||||
writePropertyChangedSignals(headerFile, registerJson['registers'])
|
||||
if 'blocks' in registerJson:
|
||||
for blockDefinition in registerJson['blocks']:
|
||||
writePropertyChangedSignals(headerFile, blockDefinition['registers'])
|
||||
|
||||
writeLine(headerFile)
|
||||
|
||||
# Protected members
|
||||
writeLine(headerFile, 'protected:')
|
||||
|
||||
writeProtectedPropertyMembers(headerFile, registerJson['registers'])
|
||||
if 'blocks' in registerJson:
|
||||
for blockDefinition in registerJson['blocks']:
|
||||
writeProtectedPropertyMembers(headerFile, blockDefinition['registers'])
|
||||
|
||||
writeLine(headerFile)
|
||||
|
||||
writePropertyProcessMethodDeclaration(headerFile, registerJson['registers'])
|
||||
if 'blocks' in registerJson:
|
||||
for blockDefinition in registerJson['blocks']:
|
||||
writePropertyProcessMethodDeclaration(headerFile, blockDefinition['registers'])
|
||||
|
||||
writeLine(headerFile)
|
||||
|
||||
# Private members
|
||||
writeLine(headerFile, 'private:')
|
||||
writeLine(headerFile, ' ModbusRtuMaster *m_modbusRtuMaster = nullptr;')
|
||||
writeLine(headerFile, ' quint16 m_slaveId = 1;')
|
||||
writeLine(headerFile, ' QVector<ModbusRtuReply *> m_pendingInitReplies;')
|
||||
writeLine(headerFile, ' ModbusDataUtils::ByteOrder m_endianness = ModbusDataUtils::ByteOrder%s;' % endianness)
|
||||
writeLine(headerFile)
|
||||
writeLine(headerFile, ' void verifyInitFinished();')
|
||||
writeLine(headerFile)
|
||||
|
||||
# End of class
|
||||
writeLine(headerFile)
|
||||
writeLine(headerFile, '};')
|
||||
writeLine(headerFile)
|
||||
writeLine(headerFile, 'QDebug operator<<(QDebug debug, %s *%s);' % (className, className[0].lower() + className[1:]))
|
||||
writeLine(headerFile)
|
||||
writeLine(headerFile, '#endif // %s_H' % className.upper())
|
||||
|
||||
headerFile.close()
|
||||
|
||||
|
||||
def writeRtuSourceFile():
|
||||
logger.info('Writing modbus RTU source file %s' % sourceFilePath)
|
||||
sourceFile = open(sourceFilePath, 'w')
|
||||
writeLicenseHeader(sourceFile)
|
||||
|
||||
writeLine(sourceFile, '#include "%s"' % headerFileName)
|
||||
writeLine(sourceFile, '#include <loggingcategories.h>')
|
||||
writeLine(sourceFile, '#include <math.h>')
|
||||
writeLine(sourceFile)
|
||||
writeLine(sourceFile, 'NYMEA_LOGGING_CATEGORY(dc%s, "%s")' % (className, className))
|
||||
writeLine(sourceFile)
|
||||
|
||||
# Constructor
|
||||
writeLine(sourceFile, '%s::%s(ModbusRtuMaster *modbusRtuMaster, quint16 slaveId, QObject *parent) :' % (className, className))
|
||||
writeLine(sourceFile, ' QObject(parent),')
|
||||
writeLine(sourceFile, ' m_modbusRtuMaster(modbusRtuMaster),')
|
||||
writeLine(sourceFile, ' m_slaveId(slaveId)')
|
||||
writeLine(sourceFile, '{')
|
||||
writeLine(sourceFile, ' ')
|
||||
writeLine(sourceFile, '}')
|
||||
writeLine(sourceFile)
|
||||
|
||||
writeLine(sourceFile, 'ModbusRtuMaster *%s::modbusRtuMaster() const' % (className))
|
||||
writeLine(sourceFile, '{')
|
||||
writeLine(sourceFile, ' return m_modbusRtuMaster;')
|
||||
writeLine(sourceFile, '}')
|
||||
|
||||
writeLine(sourceFile, 'quint16 %s::slaveId() const' % (className))
|
||||
writeLine(sourceFile, '{')
|
||||
writeLine(sourceFile, ' return m_slaveId;')
|
||||
writeLine(sourceFile, '}')
|
||||
|
||||
writeLine(sourceFile, 'ModbusDataUtils::ByteOrder %s::endianness() const' % (className))
|
||||
writeLine(sourceFile, '{')
|
||||
writeLine(sourceFile, ' return m_endianness;')
|
||||
writeLine(sourceFile, '}')
|
||||
|
||||
writeLine(sourceFile, 'void %s::setEndianness(ModbusDataUtils::ByteOrder endianness)' % (className))
|
||||
writeLine(sourceFile, '{')
|
||||
writeLine(sourceFile, ' if (m_endianness == endianness)')
|
||||
writeLine(sourceFile, ' return;')
|
||||
writeLine(sourceFile,)
|
||||
writeLine(sourceFile, ' m_endianness = endianness;')
|
||||
writeLine(sourceFile, ' emit endiannessChanged(m_endianness);')
|
||||
writeLine(sourceFile, '}')
|
||||
|
||||
# Property get methods
|
||||
writePropertyGetSetMethodImplementationsRtu(sourceFile, className, registerJson['registers'])
|
||||
if 'blocks' in registerJson:
|
||||
for blockDefinition in registerJson['blocks']:
|
||||
writePropertyGetSetMethodImplementationsRtu(sourceFile, className, blockDefinition['registers'])
|
||||
|
||||
# Write init and update method implementation
|
||||
writeInitMethodImplementationRtu(sourceFile, className, registerJson['registers'], registerJson['blocks'])
|
||||
writeUpdateMethod(sourceFile, className, registerJson['registers'], registerJson['blocks'])
|
||||
|
||||
# Write update methods
|
||||
writePropertyUpdateMethodImplementationsRtu(sourceFile, className, registerJson['registers'])
|
||||
if 'blocks' in registerJson:
|
||||
for blockDefinition in registerJson['blocks']:
|
||||
writePropertyUpdateMethodImplementationsRtu(sourceFile, className, blockDefinition['registers'])
|
||||
|
||||
# Write block update method
|
||||
writeBlockUpdateMethodImplementationsRtu(sourceFile, className, registerJson['blocks'])
|
||||
|
||||
# Write internal protected property read method implementations
|
||||
writeInternalPropertyReadMethodImplementationsRtu(sourceFile, className, registerJson['registers'])
|
||||
if 'blocks' in registerJson:
|
||||
for blockDefinition in registerJson['blocks']:
|
||||
writeInternalPropertyReadMethodImplementationsRtu(sourceFile, className, blockDefinition['registers'])
|
||||
|
||||
writeInternalBlockReadMethodImplementationsRtu(sourceFile, className, registerJson['blocks'])
|
||||
|
||||
# Write internal processors of properties
|
||||
writePropertyProcessMethodImplementations(sourceFile, className, registerJson['registers'])
|
||||
if 'blocks' in registerJson:
|
||||
for blockDefinition in registerJson['blocks']:
|
||||
writePropertyProcessMethodImplementations(sourceFile, className, blockDefinition['registers'])
|
||||
|
||||
writeLine(sourceFile, 'void %s::verifyInitFinished()' % (className))
|
||||
writeLine(sourceFile, '{')
|
||||
writeLine(sourceFile, ' if (m_pendingInitReplies.isEmpty()) {')
|
||||
writeLine(sourceFile, ' qCDebug(dc%s()) << "Initialization finished of %s";' % (className, className))
|
||||
writeLine(sourceFile, ' emit initializationFinished();')
|
||||
writeLine(sourceFile, ' }')
|
||||
writeLine(sourceFile, '}')
|
||||
writeLine(sourceFile)
|
||||
|
||||
# Write the debug print
|
||||
debugObjectParamName = className[0].lower() + className[1:]
|
||||
writeLine(sourceFile, 'QDebug operator<<(QDebug debug, %s *%s)' % (className, debugObjectParamName))
|
||||
writeLine(sourceFile, '{')
|
||||
writeLine(sourceFile, ' debug.nospace().noquote() << "%s(" << %s->modbusRtuMaster()->modbusUuid().toString() << ", " << %s->modbusRtuMaster()->serialPort() << ", slave ID:" << %s->slaveId() << ")" << "\\n";' % (className, debugObjectParamName, debugObjectParamName, debugObjectParamName))
|
||||
writeRegistersDebugLine(sourceFile, debugObjectParamName, registerJson['registers'])
|
||||
if 'blocks' in registerJson:
|
||||
for blockDefinition in registerJson['blocks']:
|
||||
writeRegistersDebugLine(sourceFile, debugObjectParamName, blockDefinition['registers'])
|
||||
|
||||
writeLine(sourceFile, ' return debug.quote().space();')
|
||||
writeLine(sourceFile, '}')
|
||||
writeLine(sourceFile)
|
||||
|
||||
sourceFile.close()
|
||||
|
||||
|
||||
############################################################################################
|
||||
# Main
|
||||
############################################################################################
|
||||
|
||||
logger = logging.getLogger('modbus-tools')
|
||||
logger.setLevel(logging.INFO)
|
||||
ch = logging.StreamHandler(sys.stdout)
|
||||
ch.setLevel(logging.INFO)
|
||||
formatter = logging.Formatter('%(name)s: %(message)s')
|
||||
ch.setFormatter(formatter)
|
||||
logger.addHandler(ch)
|
||||
|
||||
parser = argparse.ArgumentParser(description='Generate modbus tcp connection class from JSON register definitions file.')
|
||||
parser.add_argument('-j', '--json', metavar='<file>', help='The JSON file containing the register definitions.')
|
||||
parser.add_argument('-o', '--output-directory', metavar='<directory>', help='The output directory for the resulting class.')
|
||||
parser.add_argument('-v', '--verbose', dest='verboseOutput', action='store_true', help='More verbose output.')
|
||||
args = parser.parse_args()
|
||||
|
||||
registerJsonFilePath = os.path.realpath(args.json)
|
||||
registerJson = loadJsonFile(registerJsonFilePath)
|
||||
scriptPath = os.path.dirname(os.path.realpath(sys.argv[0]))
|
||||
outputDirectory = os.path.realpath(args.output_directory)
|
||||
|
||||
if not os.path.exists(outputDirectory):
|
||||
logger.debug("Output directory does not exist. Creating directory %s", outputDirectory)
|
||||
os.makedirs(outputDirectory)
|
||||
|
||||
if args.verboseOutput:
|
||||
logger.setLevel(logging.DEBUG)
|
||||
ch.setLevel(logging.DEBUG)
|
||||
|
||||
logger.debug("Verbose output enabled")
|
||||
|
||||
if not 'className' in registerJson:
|
||||
logger.warning('Classname missing. Please specify the classname in the json file or pass it to the generatori using -c .')
|
||||
exit(1)
|
||||
|
||||
classNamePrefix = registerJson['className']
|
||||
|
||||
endianness = 'BigEndian'
|
||||
if 'endianness' in registerJson:
|
||||
endianness = registerJson['endianness']
|
||||
|
||||
logger.debug('Scrip path: %s' % scriptPath)
|
||||
logger.debug('Output directory: %s' % outputDirectory)
|
||||
logger.debug('Class name prefix: %s' % classNamePrefix)
|
||||
logger.debug('Endianness: %s' % endianness)
|
||||
|
||||
protocol = 'TCP'
|
||||
if 'protocol' in registerJson:
|
||||
protocol = registerJson['protocol']
|
||||
|
||||
if 'blocks' in registerJson:
|
||||
validateBlocks(registerJson['blocks'])
|
||||
|
||||
# Create classes depending on the protocol
|
||||
writeTcp = protocol in ["TCP", "BOTH"]
|
||||
writeRtu = protocol in ["RTU", "BOTH"]
|
||||
if not writeTcp and not writeRtu:
|
||||
logger.warning('Invalid protocol definition. Please use TCP, RTU or BOTH.')
|
||||
exit(1)
|
||||
|
||||
headerFiles = []
|
||||
sourceFiles = []
|
||||
|
||||
if writeTcp:
|
||||
className = classNamePrefix + 'ModbusTcpConnection'
|
||||
headerFileName = className.lower() + '.h'
|
||||
headerFiles.append(headerFileName)
|
||||
sourceFileName = className.lower() + '.cpp'
|
||||
sourceFiles.append(sourceFileName)
|
||||
|
||||
headerFilePath = os.path.join(outputDirectory, headerFileName)
|
||||
sourceFilePath = os.path.join(outputDirectory, sourceFileName)
|
||||
logger.debug('=======================================================')
|
||||
logger.debug('Class name: %s' % className)
|
||||
logger.debug('Header file: %s' % headerFileName)
|
||||
logger.debug('Source file: %s' % sourceFileName)
|
||||
logger.debug('Header file path: %s' % headerFilePath)
|
||||
logger.debug('Source file path: %s' % sourceFilePath)
|
||||
writeTcpHeaderFile()
|
||||
writeTcpSourceFile()
|
||||
|
||||
if writeRtu:
|
||||
className = classNamePrefix + 'ModbusRtuConnection'
|
||||
headerFileName = className.lower() + '.h'
|
||||
headerFiles.append(headerFileName)
|
||||
sourceFileName = className.lower() + '.cpp'
|
||||
sourceFiles.append(sourceFileName)
|
||||
headerFilePath = os.path.join(outputDirectory, headerFileName)
|
||||
sourceFilePath = os.path.join(outputDirectory, sourceFileName)
|
||||
logger.debug('=======================================================')
|
||||
logger.debug('Class name: %s' % className)
|
||||
logger.debug('Header file: %s' % headerFileName)
|
||||
logger.debug('Source file: %s' % sourceFileName)
|
||||
logger.debug('Header file path: %s' % headerFilePath)
|
||||
logger.debug('Source file path: %s' % sourceFilePath)
|
||||
writeRtuHeaderFile()
|
||||
writeRtuSourceFile()
|
||||
|
||||
# Write pri file
|
||||
projectIncludeFileName = classNamePrefix.lower() + '.pri'
|
||||
projectIncludeFilePath = os.path.join(outputDirectory, projectIncludeFileName)
|
||||
|
||||
# Note: we write the project file only if the registers
|
||||
# file has been modified since the project has been modified the last time.
|
||||
# This prevents qt-creator to retrigger qmake runs on it's own by changing the
|
||||
# project file which retriggers a qmake run and so on...
|
||||
if os.path.exists(projectIncludeFilePath):
|
||||
timestampRegistersJson = os.path.getmtime(registerJsonFilePath)
|
||||
timestampProjectInclude = os.path.getmtime(projectIncludeFilePath)
|
||||
if timestampRegistersJson > timestampProjectInclude:
|
||||
logger.debug('Registers modified %s' % time.ctime(timestampRegistersJson))
|
||||
logger.debug('Project file modified %s' % time.ctime(timestampProjectInclude))
|
||||
logger.debug('Register JSON file has changed since last project file update. %s' % time.ctime(timestampRegistersJson))
|
||||
logger.debug('Regenerating project file %s ...' % projectIncludeFileName)
|
||||
else:
|
||||
logger.debug('The register JSON file has not changed since the last run. Skip writing the project file %s ...' % projectIncludeFileName)
|
||||
exit(0)
|
||||
|
||||
logger.info('Writing connection project include file %s' % projectIncludeFileName)
|
||||
projectIncludeFile = open(projectIncludeFilePath, 'w')
|
||||
writeLine(projectIncludeFile, '# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #')
|
||||
writeLine(projectIncludeFile, '#')
|
||||
writeLine(projectIncludeFile, '# This file has been autogenerated.')
|
||||
writeLine(projectIncludeFile, '# Any changes in this file may be overwritten from qmake.')
|
||||
writeLine(projectIncludeFile, '#')
|
||||
writeLine(projectIncludeFile, '# # # # # # # # # # # # # # # # # # # # # # # # # # # # # # #')
|
||||
writeLine(projectIncludeFile)
|
||||
writeLine(projectIncludeFile, 'HEADERS = \\')
|
||||
for generatedHeaderFileName in headerFiles:
|
||||
writeLine(projectIncludeFile, ' $${PWD}/%s \\' % generatedHeaderFileName)
|
||||
|
||||
writeLine(projectIncludeFile)
|
||||
writeLine(projectIncludeFile, "SOURCES = \\")
|
||||
for generatedSourceFileName in sourceFiles:
|
||||
writeLine(projectIncludeFile, ' $${PWD}/%s \\' % generatedSourceFileName)
|
||||
12
modbus.pri
Normal file
12
modbus.pri
Normal file
@ -0,0 +1,12 @@
|
||||
QT += network serialport serialbus
|
||||
|
||||
top_srcdir=$$PWD
|
||||
top_builddir=$$shadowed($$PWD)
|
||||
|
||||
INCLUDEPATH += $$top_srcdir/libnymea-modbus
|
||||
LIBS += -L$$top_builddir/libnymea-modbus/ -lnymea-modbus
|
||||
|
||||
OTHER_FILES += $${MODBUS_CONNECTIONS}
|
||||
|
||||
include(libnymea-modbus/modbus-tool.pri)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -31,12 +31,10 @@
|
||||
#include "integrationpluginmodbuscommander.h"
|
||||
#include "plugininfo.h"
|
||||
|
||||
#include "hardwaremanager.h"
|
||||
#include "network/networkdevicediscovery.h"
|
||||
#include "hardware/modbus/modbusrtumaster.h"
|
||||
#include "hardware/modbus/modbusrtuhardwareresource.h"
|
||||
|
||||
#include <QSerialPort>
|
||||
#include <hardwaremanager.h>
|
||||
#include <network/networkdevicediscovery.h>
|
||||
#include <hardware/modbus/modbusrtumaster.h>
|
||||
#include <hardware/modbus/modbusrtuhardwareresource.h>
|
||||
|
||||
IntegrationPluginModbusCommander::IntegrationPluginModbusCommander()
|
||||
{
|
||||
|
||||
@ -31,14 +31,15 @@
|
||||
#ifndef INTEGRATIONPLUGINMODBUSCOMMANDER_H
|
||||
#define INTEGRATIONPLUGINMODBUSCOMMANDER_H
|
||||
|
||||
#include "plugintimer.h"
|
||||
#include "integrations/integrationplugin.h"
|
||||
#include "hardware/modbus/modbusrtumaster.h"
|
||||
#include <plugintimer.h>
|
||||
#include <integrations/integrationplugin.h>
|
||||
#include <hardware/modbus/modbusrtumaster.h>
|
||||
|
||||
#include "../modbus/modbustcpmaster.h"
|
||||
#include <modbustcpmaster.h>
|
||||
|
||||
#include <QSerialPortInfo>
|
||||
#include <QUuid>
|
||||
#include <QSerialPort>
|
||||
#include <QSerialPortInfo>
|
||||
|
||||
class IntegrationPluginModbusCommander: public IntegrationPlugin
|
||||
{
|
||||
@ -60,7 +61,6 @@ public:
|
||||
private:
|
||||
PluginTimer *m_refreshTimer = nullptr;
|
||||
|
||||
//QHash<Thing*, ModbusRTUMaster*> m_modbusRTUMasters;
|
||||
QHash<Thing*, ModbusTCPMaster*> m_modbusTCPMasters;
|
||||
QHash<Thing *, ModbusRtuMaster *> m_modbusRtuMasters;
|
||||
QHash<QUuid, ThingActionInfo*> m_asyncActions;
|
||||
|
||||
@ -1,15 +1,9 @@
|
||||
include(../plugins.pri)
|
||||
|
||||
QT += \
|
||||
serialport \
|
||||
network \
|
||||
serialbus \
|
||||
include(../modbus.pri)
|
||||
|
||||
SOURCES += \
|
||||
integrationpluginmodbuscommander.cpp \
|
||||
../modbus/modbustcpmaster.cpp
|
||||
integrationpluginmodbuscommander.cpp
|
||||
|
||||
HEADERS += \
|
||||
integrationpluginmodbuscommander.h \
|
||||
../modbus/modbustcpmaster.h
|
||||
integrationpluginmodbuscommander.h
|
||||
|
||||
|
||||
@ -28,7 +28,8 @@
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#include "network/networkdevicediscovery.h"
|
||||
#include <network/networkdevicediscovery.h>
|
||||
|
||||
#include "integrationpluginmtec.h"
|
||||
#include "plugininfo.h"
|
||||
|
||||
|
||||
@ -30,8 +30,8 @@
|
||||
#ifndef INTEGRATIONPLUGINMTEC_H
|
||||
#define INTEGRATIONPLUGINMTEC_H
|
||||
|
||||
#include "integrations/integrationplugin.h"
|
||||
#include "plugintimer.h"
|
||||
#include <integrations/integrationplugin.h>
|
||||
#include <plugintimer.h>
|
||||
|
||||
#include "mtec.h"
|
||||
|
||||
|
||||
@ -34,7 +34,7 @@
|
||||
#include <QDateTime>
|
||||
#include <QObject>
|
||||
|
||||
#include "../modbus/modbustcpmaster.h"
|
||||
#include <modbustcpmaster.h>
|
||||
|
||||
class MTec : public QObject
|
||||
{
|
||||
|
||||
@ -1,16 +1,11 @@
|
||||
include(../plugins.pri)
|
||||
|
||||
QT += \
|
||||
network \
|
||||
serialbus \
|
||||
include(../modbus.pri)
|
||||
|
||||
SOURCES += \
|
||||
mtec.cpp \
|
||||
integrationpluginmtec.cpp \
|
||||
../modbus/modbustcpmaster.cpp
|
||||
integrationpluginmtec.cpp
|
||||
|
||||
HEADERS += \
|
||||
mtec.h \
|
||||
integrationpluginmtec.h \
|
||||
../modbus/modbustcpmaster.h \
|
||||
integrationpluginmtec.h
|
||||
|
||||
|
||||
@ -31,10 +31,10 @@
|
||||
#ifndef INTEGRATIONPLUGINMYPV_H
|
||||
#define INTEGRATIONPLUGINMYPV_H
|
||||
|
||||
#include "integrations/integrationplugin.h"
|
||||
#include "plugintimer.h"
|
||||
#include <integrations/integrationplugin.h>
|
||||
#include <plugintimer.h>
|
||||
|
||||
#include "../modbus/modbustcpmaster.h"
|
||||
#include <modbustcpmaster.h>
|
||||
|
||||
#include <QUdpSocket>
|
||||
#include <QUuid>
|
||||
|
||||
@ -1,13 +1,8 @@
|
||||
include(../plugins.pri)
|
||||
|
||||
QT += \
|
||||
network \
|
||||
serialbus \
|
||||
include(../modbus.pri)
|
||||
|
||||
SOURCES += \
|
||||
integrationpluginmypv.cpp \
|
||||
../modbus/modbustcpmaster.cpp \
|
||||
integrationpluginmypv.cpp
|
||||
|
||||
HEADERS += \
|
||||
integrationpluginmypv.h \
|
||||
../modbus/modbustcpmaster.h \
|
||||
integrationpluginmypv.h
|
||||
|
||||
@ -1,8 +1,8 @@
|
||||
TEMPLATE = subdirs
|
||||
|
||||
# Note keep it ordered so the lib will be built first
|
||||
CONFIG += ordered
|
||||
SUBDIRS += libnymea-sunspec
|
||||
# Note: In the loop at the end of this file the plugin
|
||||
# dependency on the libs will be defined
|
||||
SUBDIRS += libnymea-modbus libnymea-sunspec
|
||||
|
||||
PLUGIN_DIRS = \
|
||||
alphainnotec \
|
||||
@ -15,6 +15,7 @@ PLUGIN_DIRS = \
|
||||
mtec \
|
||||
mypv \
|
||||
schrack \
|
||||
stiebeleltron \
|
||||
sunspec \
|
||||
unipi \
|
||||
wallbe \
|
||||
@ -63,6 +64,12 @@ for(plugin, PLUGINS) {
|
||||
exists($${plugin}) {
|
||||
SUBDIRS*= $${plugin}
|
||||
message("- $${plugin}")
|
||||
# Make sure the libs will be built before the plugins
|
||||
equals(plugin, "sunspec") {
|
||||
$${plugin}.depends += libnymea-sunspec
|
||||
} else {
|
||||
$${plugin}.depends += libnymea-modbus
|
||||
}
|
||||
} else {
|
||||
error("Invalid plugin \"$${plugin}\".")
|
||||
}
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
{
|
||||
"className": "Cion",
|
||||
"protocol": "RTU",
|
||||
"endianness": "LittleEndian",
|
||||
"blocks": [
|
||||
|
||||
@ -1,723 +0,0 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2022, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This fileDescriptor 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
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* WARNING
|
||||
*
|
||||
* This file has been autogenerated. Any changes in this file may be overwritten.
|
||||
* If you want to change something, update the register json or the tool.
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#include "cionmodbusrtuconnection.h"
|
||||
#include "loggingcategories.h"
|
||||
#include "math.h"
|
||||
|
||||
NYMEA_LOGGING_CATEGORY(dcCionModbusRtuConnection, "CionModbusRtuConnection")
|
||||
|
||||
CionModbusRtuConnection::CionModbusRtuConnection(ModbusRtuMaster *modbusRtuMaster, quint16 slaveId, QObject *parent) :
|
||||
QObject(parent),
|
||||
m_modbusRtuMaster(modbusRtuMaster),
|
||||
m_slaveId(slaveId)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
ModbusRtuMaster *CionModbusRtuConnection::modbusRtuMaster() const
|
||||
{
|
||||
return m_modbusRtuMaster;
|
||||
}
|
||||
quint16 CionModbusRtuConnection::slaveId() const
|
||||
{
|
||||
return m_slaveId;
|
||||
}
|
||||
ModbusDataUtils::ByteOrder CionModbusRtuConnection::endianness() const
|
||||
{
|
||||
return m_endianness;
|
||||
}
|
||||
void CionModbusRtuConnection::setEndianness(ModbusDataUtils::ByteOrder endianness)
|
||||
{
|
||||
if (m_endianness == endianness)
|
||||
return;
|
||||
|
||||
m_endianness = endianness;
|
||||
emit endiannessChanged(m_endianness);
|
||||
}
|
||||
quint16 CionModbusRtuConnection::chargingEnabled() const
|
||||
{
|
||||
return m_chargingEnabled;
|
||||
}
|
||||
|
||||
ModbusRtuReply *CionModbusRtuConnection::setChargingEnabled(quint16 chargingEnabled)
|
||||
{
|
||||
QVector<quint16> values = ModbusDataUtils::convertFromUInt16(chargingEnabled);
|
||||
qCDebug(dcCionModbusRtuConnection()) << "--> Write \"Charging enabled\" register:" << 100 << "size:" << 1 << values;
|
||||
return m_modbusRtuMaster->writeHoldingRegisters(m_slaveId, 100, values);
|
||||
}
|
||||
|
||||
quint16 CionModbusRtuConnection::chargingCurrentSetpoint() const
|
||||
{
|
||||
return m_chargingCurrentSetpoint;
|
||||
}
|
||||
|
||||
ModbusRtuReply *CionModbusRtuConnection::setChargingCurrentSetpoint(quint16 chargingCurrentSetpoint)
|
||||
{
|
||||
QVector<quint16> values = ModbusDataUtils::convertFromUInt16(chargingCurrentSetpoint);
|
||||
qCDebug(dcCionModbusRtuConnection()) << "--> Write \"Charging current setpoint\" register:" << 101 << "size:" << 1 << values;
|
||||
return m_modbusRtuMaster->writeHoldingRegisters(m_slaveId, 101, values);
|
||||
}
|
||||
|
||||
quint16 CionModbusRtuConnection::statusBits() const
|
||||
{
|
||||
return m_statusBits;
|
||||
}
|
||||
|
||||
quint16 CionModbusRtuConnection::cpSignalState() const
|
||||
{
|
||||
return m_cpSignalState;
|
||||
}
|
||||
|
||||
float CionModbusRtuConnection::u1Voltage() const
|
||||
{
|
||||
return m_u1Voltage;
|
||||
}
|
||||
|
||||
float CionModbusRtuConnection::gridVoltage() const
|
||||
{
|
||||
return m_gridVoltage;
|
||||
}
|
||||
|
||||
quint16 CionModbusRtuConnection::minChargingCurrent() const
|
||||
{
|
||||
return m_minChargingCurrent;
|
||||
}
|
||||
|
||||
quint16 CionModbusRtuConnection::currentChargingCurrentE3() const
|
||||
{
|
||||
return m_currentChargingCurrentE3;
|
||||
}
|
||||
|
||||
quint16 CionModbusRtuConnection::maxChargingCurrentE3() const
|
||||
{
|
||||
return m_maxChargingCurrentE3;
|
||||
}
|
||||
|
||||
quint16 CionModbusRtuConnection::maxChargingCurrentCableE3() const
|
||||
{
|
||||
return m_maxChargingCurrentCableE3;
|
||||
}
|
||||
|
||||
quint32 CionModbusRtuConnection::chargingDuration() const
|
||||
{
|
||||
return m_chargingDuration;
|
||||
}
|
||||
|
||||
quint32 CionModbusRtuConnection::pluggedInDuration() const
|
||||
{
|
||||
return m_pluggedInDuration;
|
||||
}
|
||||
|
||||
void CionModbusRtuConnection::initialize()
|
||||
{
|
||||
// No init registers defined. Nothing to be done and we are finished.
|
||||
emit initializationFinished();
|
||||
}
|
||||
|
||||
void CionModbusRtuConnection::update()
|
||||
{
|
||||
updateChargingEnabled();
|
||||
updateChargingCurrentSetpoint();
|
||||
updateStatusBits();
|
||||
updateCpSignalState();
|
||||
updateU1Voltage();
|
||||
updateGridVoltage();
|
||||
updateMinChargingCurrent();
|
||||
updateE3Block();
|
||||
updateDurationsBlock();
|
||||
}
|
||||
|
||||
void CionModbusRtuConnection::updateChargingEnabled()
|
||||
{
|
||||
// Update registers from Charging enabled
|
||||
qCDebug(dcCionModbusRtuConnection()) << "--> Read \"Charging enabled\" register:" << 100 << "size:" << 1;
|
||||
ModbusRtuReply *reply = readChargingEnabled();
|
||||
if (reply) {
|
||||
if (!reply->isFinished()) {
|
||||
connect(reply, &ModbusRtuReply::finished, this, [this, reply](){
|
||||
if (reply->error() == ModbusRtuReply::NoError) {
|
||||
QVector<quint16> values = reply->result();
|
||||
qCDebug(dcCionModbusRtuConnection()) << "<-- Response from \"Charging enabled\" register" << 100 << "size:" << 1 << values;
|
||||
processChargingEnabledRegisterValues(values);
|
||||
}
|
||||
});
|
||||
|
||||
connect(reply, &ModbusRtuReply::errorOccurred, this, [reply] (ModbusRtuReply::Error error){
|
||||
qCWarning(dcCionModbusRtuConnection()) << "ModbusRtu reply error occurred while updating \"Charging enabled\" registers" << error << reply->errorString();
|
||||
emit reply->finished();
|
||||
});
|
||||
}
|
||||
} else {
|
||||
qCWarning(dcCionModbusRtuConnection()) << "Error occurred while reading \"Charging enabled\" registers";
|
||||
}
|
||||
}
|
||||
|
||||
void CionModbusRtuConnection::updateChargingCurrentSetpoint()
|
||||
{
|
||||
// Update registers from Charging current setpoint
|
||||
qCDebug(dcCionModbusRtuConnection()) << "--> Read \"Charging current setpoint\" register:" << 101 << "size:" << 1;
|
||||
ModbusRtuReply *reply = readChargingCurrentSetpoint();
|
||||
if (reply) {
|
||||
if (!reply->isFinished()) {
|
||||
connect(reply, &ModbusRtuReply::finished, this, [this, reply](){
|
||||
if (reply->error() == ModbusRtuReply::NoError) {
|
||||
QVector<quint16> values = reply->result();
|
||||
qCDebug(dcCionModbusRtuConnection()) << "<-- Response from \"Charging current setpoint\" register" << 101 << "size:" << 1 << values;
|
||||
processChargingCurrentSetpointRegisterValues(values);
|
||||
}
|
||||
});
|
||||
|
||||
connect(reply, &ModbusRtuReply::errorOccurred, this, [reply] (ModbusRtuReply::Error error){
|
||||
qCWarning(dcCionModbusRtuConnection()) << "ModbusRtu reply error occurred while updating \"Charging current setpoint\" registers" << error << reply->errorString();
|
||||
emit reply->finished();
|
||||
});
|
||||
}
|
||||
} else {
|
||||
qCWarning(dcCionModbusRtuConnection()) << "Error occurred while reading \"Charging current setpoint\" registers";
|
||||
}
|
||||
}
|
||||
|
||||
void CionModbusRtuConnection::updateStatusBits()
|
||||
{
|
||||
// Update registers from Mode3-State A, B, C, D, U
|
||||
qCDebug(dcCionModbusRtuConnection()) << "--> Read \"Mode3-State A, B, C, D, U\" register:" << 121 << "size:" << 1;
|
||||
ModbusRtuReply *reply = readStatusBits();
|
||||
if (reply) {
|
||||
if (!reply->isFinished()) {
|
||||
connect(reply, &ModbusRtuReply::finished, this, [this, reply](){
|
||||
if (reply->error() == ModbusRtuReply::NoError) {
|
||||
QVector<quint16> values = reply->result();
|
||||
qCDebug(dcCionModbusRtuConnection()) << "<-- Response from \"Mode3-State A, B, C, D, U\" register" << 121 << "size:" << 1 << values;
|
||||
processStatusBitsRegisterValues(values);
|
||||
}
|
||||
});
|
||||
|
||||
connect(reply, &ModbusRtuReply::errorOccurred, this, [reply] (ModbusRtuReply::Error error){
|
||||
qCWarning(dcCionModbusRtuConnection()) << "ModbusRtu reply error occurred while updating \"Mode3-State A, B, C, D, U\" registers" << error << reply->errorString();
|
||||
emit reply->finished();
|
||||
});
|
||||
}
|
||||
} else {
|
||||
qCWarning(dcCionModbusRtuConnection()) << "Error occurred while reading \"Mode3-State A, B, C, D, U\" registers";
|
||||
}
|
||||
}
|
||||
|
||||
void CionModbusRtuConnection::updateCpSignalState()
|
||||
{
|
||||
// Update registers from Status bits
|
||||
qCDebug(dcCionModbusRtuConnection()) << "--> Read \"Status bits\" register:" << 139 << "size:" << 1;
|
||||
ModbusRtuReply *reply = readCpSignalState();
|
||||
if (reply) {
|
||||
if (!reply->isFinished()) {
|
||||
connect(reply, &ModbusRtuReply::finished, this, [this, reply](){
|
||||
if (reply->error() == ModbusRtuReply::NoError) {
|
||||
QVector<quint16> values = reply->result();
|
||||
qCDebug(dcCionModbusRtuConnection()) << "<-- Response from \"Status bits\" register" << 139 << "size:" << 1 << values;
|
||||
processCpSignalStateRegisterValues(values);
|
||||
}
|
||||
});
|
||||
|
||||
connect(reply, &ModbusRtuReply::errorOccurred, this, [reply] (ModbusRtuReply::Error error){
|
||||
qCWarning(dcCionModbusRtuConnection()) << "ModbusRtu reply error occurred while updating \"Status bits\" registers" << error << reply->errorString();
|
||||
emit reply->finished();
|
||||
});
|
||||
}
|
||||
} else {
|
||||
qCWarning(dcCionModbusRtuConnection()) << "Error occurred while reading \"Status bits\" registers";
|
||||
}
|
||||
}
|
||||
|
||||
void CionModbusRtuConnection::updateU1Voltage()
|
||||
{
|
||||
// Update registers from U1 voltage
|
||||
qCDebug(dcCionModbusRtuConnection()) << "--> Read \"U1 voltage\" register:" << 167 << "size:" << 1;
|
||||
ModbusRtuReply *reply = readU1Voltage();
|
||||
if (reply) {
|
||||
if (!reply->isFinished()) {
|
||||
connect(reply, &ModbusRtuReply::finished, this, [this, reply](){
|
||||
if (reply->error() == ModbusRtuReply::NoError) {
|
||||
QVector<quint16> values = reply->result();
|
||||
qCDebug(dcCionModbusRtuConnection()) << "<-- Response from \"U1 voltage\" register" << 167 << "size:" << 1 << values;
|
||||
processU1VoltageRegisterValues(values);
|
||||
}
|
||||
});
|
||||
|
||||
connect(reply, &ModbusRtuReply::errorOccurred, this, [reply] (ModbusRtuReply::Error error){
|
||||
qCWarning(dcCionModbusRtuConnection()) << "ModbusRtu reply error occurred while updating \"U1 voltage\" registers" << error << reply->errorString();
|
||||
emit reply->finished();
|
||||
});
|
||||
}
|
||||
} else {
|
||||
qCWarning(dcCionModbusRtuConnection()) << "Error occurred while reading \"U1 voltage\" registers";
|
||||
}
|
||||
}
|
||||
|
||||
void CionModbusRtuConnection::updateGridVoltage()
|
||||
{
|
||||
// Update registers from Voltage of the power supply grid
|
||||
qCDebug(dcCionModbusRtuConnection()) << "--> Read \"Voltage of the power supply grid\" register:" << 302 << "size:" << 1;
|
||||
ModbusRtuReply *reply = readGridVoltage();
|
||||
if (reply) {
|
||||
if (!reply->isFinished()) {
|
||||
connect(reply, &ModbusRtuReply::finished, this, [this, reply](){
|
||||
if (reply->error() == ModbusRtuReply::NoError) {
|
||||
QVector<quint16> values = reply->result();
|
||||
qCDebug(dcCionModbusRtuConnection()) << "<-- Response from \"Voltage of the power supply grid\" register" << 302 << "size:" << 1 << values;
|
||||
processGridVoltageRegisterValues(values);
|
||||
}
|
||||
});
|
||||
|
||||
connect(reply, &ModbusRtuReply::errorOccurred, this, [reply] (ModbusRtuReply::Error error){
|
||||
qCWarning(dcCionModbusRtuConnection()) << "ModbusRtu reply error occurred while updating \"Voltage of the power supply grid\" registers" << error << reply->errorString();
|
||||
emit reply->finished();
|
||||
});
|
||||
}
|
||||
} else {
|
||||
qCWarning(dcCionModbusRtuConnection()) << "Error occurred while reading \"Voltage of the power supply grid\" registers";
|
||||
}
|
||||
}
|
||||
|
||||
void CionModbusRtuConnection::updateMinChargingCurrent()
|
||||
{
|
||||
// Update registers from Minimum charging current
|
||||
qCDebug(dcCionModbusRtuConnection()) << "--> Read \"Minimum charging current\" register:" << 507 << "size:" << 1;
|
||||
ModbusRtuReply *reply = readMinChargingCurrent();
|
||||
if (reply) {
|
||||
if (!reply->isFinished()) {
|
||||
connect(reply, &ModbusRtuReply::finished, this, [this, reply](){
|
||||
if (reply->error() == ModbusRtuReply::NoError) {
|
||||
QVector<quint16> values = reply->result();
|
||||
qCDebug(dcCionModbusRtuConnection()) << "<-- Response from \"Minimum charging current\" register" << 507 << "size:" << 1 << values;
|
||||
processMinChargingCurrentRegisterValues(values);
|
||||
}
|
||||
});
|
||||
|
||||
connect(reply, &ModbusRtuReply::errorOccurred, this, [reply] (ModbusRtuReply::Error error){
|
||||
qCWarning(dcCionModbusRtuConnection()) << "ModbusRtu reply error occurred while updating \"Minimum charging current\" registers" << error << reply->errorString();
|
||||
emit reply->finished();
|
||||
});
|
||||
}
|
||||
} else {
|
||||
qCWarning(dcCionModbusRtuConnection()) << "Error occurred while reading \"Minimum charging current\" registers";
|
||||
}
|
||||
}
|
||||
|
||||
void CionModbusRtuConnection::updateCurrentChargingCurrentE3()
|
||||
{
|
||||
// Update registers from Current charging Ampere
|
||||
qCDebug(dcCionModbusRtuConnection()) << "--> Read \"Current charging Ampere\" register:" << 126 << "size:" << 1;
|
||||
ModbusRtuReply *reply = readCurrentChargingCurrentE3();
|
||||
if (reply) {
|
||||
if (!reply->isFinished()) {
|
||||
connect(reply, &ModbusRtuReply::finished, this, [this, reply](){
|
||||
if (reply->error() == ModbusRtuReply::NoError) {
|
||||
QVector<quint16> values = reply->result();
|
||||
qCDebug(dcCionModbusRtuConnection()) << "<-- Response from \"Current charging Ampere\" register" << 126 << "size:" << 1 << values;
|
||||
processCurrentChargingCurrentE3RegisterValues(values);
|
||||
}
|
||||
});
|
||||
|
||||
connect(reply, &ModbusRtuReply::errorOccurred, this, [reply] (ModbusRtuReply::Error error){
|
||||
qCWarning(dcCionModbusRtuConnection()) << "ModbusRtu reply error occurred while updating \"Current charging Ampere\" registers" << error << reply->errorString();
|
||||
emit reply->finished();
|
||||
});
|
||||
}
|
||||
} else {
|
||||
qCWarning(dcCionModbusRtuConnection()) << "Error occurred while reading \"Current charging Ampere\" registers";
|
||||
}
|
||||
}
|
||||
|
||||
void CionModbusRtuConnection::updateMaxChargingCurrentE3()
|
||||
{
|
||||
// Update registers from Maximum charging current
|
||||
qCDebug(dcCionModbusRtuConnection()) << "--> Read \"Maximum charging current\" register:" << 127 << "size:" << 1;
|
||||
ModbusRtuReply *reply = readMaxChargingCurrentE3();
|
||||
if (reply) {
|
||||
if (!reply->isFinished()) {
|
||||
connect(reply, &ModbusRtuReply::finished, this, [this, reply](){
|
||||
if (reply->error() == ModbusRtuReply::NoError) {
|
||||
QVector<quint16> values = reply->result();
|
||||
qCDebug(dcCionModbusRtuConnection()) << "<-- Response from \"Maximum charging current\" register" << 127 << "size:" << 1 << values;
|
||||
processMaxChargingCurrentE3RegisterValues(values);
|
||||
}
|
||||
});
|
||||
|
||||
connect(reply, &ModbusRtuReply::errorOccurred, this, [reply] (ModbusRtuReply::Error error){
|
||||
qCWarning(dcCionModbusRtuConnection()) << "ModbusRtu reply error occurred while updating \"Maximum charging current\" registers" << error << reply->errorString();
|
||||
emit reply->finished();
|
||||
});
|
||||
}
|
||||
} else {
|
||||
qCWarning(dcCionModbusRtuConnection()) << "Error occurred while reading \"Maximum charging current\" registers";
|
||||
}
|
||||
}
|
||||
|
||||
void CionModbusRtuConnection::updateMaxChargingCurrentCableE3()
|
||||
{
|
||||
// Update registers from Maximum charging current of connected cable
|
||||
qCDebug(dcCionModbusRtuConnection()) << "--> Read \"Maximum charging current of connected cable\" register:" << 128 << "size:" << 1;
|
||||
ModbusRtuReply *reply = readMaxChargingCurrentCableE3();
|
||||
if (reply) {
|
||||
if (!reply->isFinished()) {
|
||||
connect(reply, &ModbusRtuReply::finished, this, [this, reply](){
|
||||
if (reply->error() == ModbusRtuReply::NoError) {
|
||||
QVector<quint16> values = reply->result();
|
||||
qCDebug(dcCionModbusRtuConnection()) << "<-- Response from \"Maximum charging current of connected cable\" register" << 128 << "size:" << 1 << values;
|
||||
processMaxChargingCurrentCableE3RegisterValues(values);
|
||||
}
|
||||
});
|
||||
|
||||
connect(reply, &ModbusRtuReply::errorOccurred, this, [reply] (ModbusRtuReply::Error error){
|
||||
qCWarning(dcCionModbusRtuConnection()) << "ModbusRtu reply error occurred while updating \"Maximum charging current of connected cable\" registers" << error << reply->errorString();
|
||||
emit reply->finished();
|
||||
});
|
||||
}
|
||||
} else {
|
||||
qCWarning(dcCionModbusRtuConnection()) << "Error occurred while reading \"Maximum charging current of connected cable\" registers";
|
||||
}
|
||||
}
|
||||
|
||||
void CionModbusRtuConnection::updateChargingDuration()
|
||||
{
|
||||
// Update registers from Charging duration
|
||||
qCDebug(dcCionModbusRtuConnection()) << "--> Read \"Charging duration\" register:" << 151 << "size:" << 2;
|
||||
ModbusRtuReply *reply = readChargingDuration();
|
||||
if (reply) {
|
||||
if (!reply->isFinished()) {
|
||||
connect(reply, &ModbusRtuReply::finished, this, [this, reply](){
|
||||
if (reply->error() == ModbusRtuReply::NoError) {
|
||||
QVector<quint16> values = reply->result();
|
||||
qCDebug(dcCionModbusRtuConnection()) << "<-- Response from \"Charging duration\" register" << 151 << "size:" << 2 << values;
|
||||
processChargingDurationRegisterValues(values);
|
||||
}
|
||||
});
|
||||
|
||||
connect(reply, &ModbusRtuReply::errorOccurred, this, [reply] (ModbusRtuReply::Error error){
|
||||
qCWarning(dcCionModbusRtuConnection()) << "ModbusRtu reply error occurred while updating \"Charging duration\" registers" << error << reply->errorString();
|
||||
emit reply->finished();
|
||||
});
|
||||
}
|
||||
} else {
|
||||
qCWarning(dcCionModbusRtuConnection()) << "Error occurred while reading \"Charging duration\" registers";
|
||||
}
|
||||
}
|
||||
|
||||
void CionModbusRtuConnection::updatePluggedInDuration()
|
||||
{
|
||||
// Update registers from Plugged in duration
|
||||
qCDebug(dcCionModbusRtuConnection()) << "--> Read \"Plugged in duration\" register:" << 153 << "size:" << 2;
|
||||
ModbusRtuReply *reply = readPluggedInDuration();
|
||||
if (reply) {
|
||||
if (!reply->isFinished()) {
|
||||
connect(reply, &ModbusRtuReply::finished, this, [this, reply](){
|
||||
if (reply->error() == ModbusRtuReply::NoError) {
|
||||
QVector<quint16> values = reply->result();
|
||||
qCDebug(dcCionModbusRtuConnection()) << "<-- Response from \"Plugged in duration\" register" << 153 << "size:" << 2 << values;
|
||||
processPluggedInDurationRegisterValues(values);
|
||||
}
|
||||
});
|
||||
|
||||
connect(reply, &ModbusRtuReply::errorOccurred, this, [reply] (ModbusRtuReply::Error error){
|
||||
qCWarning(dcCionModbusRtuConnection()) << "ModbusRtu reply error occurred while updating \"Plugged in duration\" registers" << error << reply->errorString();
|
||||
emit reply->finished();
|
||||
});
|
||||
}
|
||||
} else {
|
||||
qCWarning(dcCionModbusRtuConnection()) << "Error occurred while reading \"Plugged in duration\" registers";
|
||||
}
|
||||
}
|
||||
|
||||
void CionModbusRtuConnection::updateE3Block()
|
||||
{
|
||||
// Update register block "e3"
|
||||
qCDebug(dcCionModbusRtuConnection()) << "--> Read block \"e3\" registers from:" << 126 << "size:" << 3;
|
||||
ModbusRtuReply *reply = m_modbusRtuMaster->readHoldingRegister(m_slaveId, 126, 3);
|
||||
if (reply) {
|
||||
if (!reply->isFinished()) {
|
||||
connect(reply, &ModbusRtuReply::finished, this, [this, reply](){
|
||||
if (reply->error() == ModbusRtuReply::NoError) {
|
||||
QVector<quint16> blockValues = reply->result();
|
||||
qCDebug(dcCionModbusRtuConnection()) << "<-- Response from reading block \"e3\" register" << 126 << "size:" << 3 << blockValues;
|
||||
processCurrentChargingCurrentE3RegisterValues(blockValues.mid(0, 1));
|
||||
processMaxChargingCurrentE3RegisterValues(blockValues.mid(1, 1));
|
||||
processMaxChargingCurrentCableE3RegisterValues(blockValues.mid(2, 1));
|
||||
}
|
||||
});
|
||||
|
||||
connect(reply, &ModbusRtuReply::errorOccurred, this, [reply] (ModbusRtuReply::Error error){
|
||||
qCWarning(dcCionModbusRtuConnection()) << "ModbusRtu reply error occurred while updating block \"e3\" registers" << error << reply->errorString();
|
||||
emit reply->finished();
|
||||
});
|
||||
}
|
||||
} else {
|
||||
qCWarning(dcCionModbusRtuConnection()) << "Error occurred while reading block \"e3\" registers";
|
||||
}
|
||||
}
|
||||
|
||||
void CionModbusRtuConnection::updateDurationsBlock()
|
||||
{
|
||||
// Update register block "durations"
|
||||
qCDebug(dcCionModbusRtuConnection()) << "--> Read block \"durations\" registers from:" << 151 << "size:" << 4;
|
||||
ModbusRtuReply *reply = m_modbusRtuMaster->readHoldingRegister(m_slaveId, 151, 4);
|
||||
if (reply) {
|
||||
if (!reply->isFinished()) {
|
||||
connect(reply, &ModbusRtuReply::finished, this, [this, reply](){
|
||||
if (reply->error() == ModbusRtuReply::NoError) {
|
||||
QVector<quint16> blockValues = reply->result();
|
||||
qCDebug(dcCionModbusRtuConnection()) << "<-- Response from reading block \"durations\" register" << 151 << "size:" << 4 << blockValues;
|
||||
processChargingDurationRegisterValues(blockValues.mid(0, 2));
|
||||
processPluggedInDurationRegisterValues(blockValues.mid(2, 2));
|
||||
}
|
||||
});
|
||||
|
||||
connect(reply, &ModbusRtuReply::errorOccurred, this, [reply] (ModbusRtuReply::Error error){
|
||||
qCWarning(dcCionModbusRtuConnection()) << "ModbusRtu reply error occurred while updating block \"durations\" registers" << error << reply->errorString();
|
||||
emit reply->finished();
|
||||
});
|
||||
}
|
||||
} else {
|
||||
qCWarning(dcCionModbusRtuConnection()) << "Error occurred while reading block \"durations\" registers";
|
||||
}
|
||||
}
|
||||
|
||||
ModbusRtuReply *CionModbusRtuConnection::readChargingEnabled()
|
||||
{
|
||||
return m_modbusRtuMaster->readHoldingRegister(m_slaveId, 100, 1);
|
||||
}
|
||||
|
||||
ModbusRtuReply *CionModbusRtuConnection::readChargingCurrentSetpoint()
|
||||
{
|
||||
return m_modbusRtuMaster->readHoldingRegister(m_slaveId, 101, 1);
|
||||
}
|
||||
|
||||
ModbusRtuReply *CionModbusRtuConnection::readStatusBits()
|
||||
{
|
||||
return m_modbusRtuMaster->readHoldingRegister(m_slaveId, 121, 1);
|
||||
}
|
||||
|
||||
ModbusRtuReply *CionModbusRtuConnection::readCpSignalState()
|
||||
{
|
||||
return m_modbusRtuMaster->readHoldingRegister(m_slaveId, 139, 1);
|
||||
}
|
||||
|
||||
ModbusRtuReply *CionModbusRtuConnection::readU1Voltage()
|
||||
{
|
||||
return m_modbusRtuMaster->readHoldingRegister(m_slaveId, 167, 1);
|
||||
}
|
||||
|
||||
ModbusRtuReply *CionModbusRtuConnection::readGridVoltage()
|
||||
{
|
||||
return m_modbusRtuMaster->readHoldingRegister(m_slaveId, 302, 1);
|
||||
}
|
||||
|
||||
ModbusRtuReply *CionModbusRtuConnection::readMinChargingCurrent()
|
||||
{
|
||||
return m_modbusRtuMaster->readHoldingRegister(m_slaveId, 507, 1);
|
||||
}
|
||||
|
||||
ModbusRtuReply *CionModbusRtuConnection::readCurrentChargingCurrentE3()
|
||||
{
|
||||
return m_modbusRtuMaster->readHoldingRegister(m_slaveId, 126, 1);
|
||||
}
|
||||
|
||||
ModbusRtuReply *CionModbusRtuConnection::readMaxChargingCurrentE3()
|
||||
{
|
||||
return m_modbusRtuMaster->readHoldingRegister(m_slaveId, 127, 1);
|
||||
}
|
||||
|
||||
ModbusRtuReply *CionModbusRtuConnection::readMaxChargingCurrentCableE3()
|
||||
{
|
||||
return m_modbusRtuMaster->readHoldingRegister(m_slaveId, 128, 1);
|
||||
}
|
||||
|
||||
ModbusRtuReply *CionModbusRtuConnection::readChargingDuration()
|
||||
{
|
||||
return m_modbusRtuMaster->readHoldingRegister(m_slaveId, 151, 2);
|
||||
}
|
||||
|
||||
ModbusRtuReply *CionModbusRtuConnection::readPluggedInDuration()
|
||||
{
|
||||
return m_modbusRtuMaster->readHoldingRegister(m_slaveId, 153, 2);
|
||||
}
|
||||
|
||||
ModbusRtuReply *CionModbusRtuConnection::readBlockE3()
|
||||
{
|
||||
return m_modbusRtuMaster->readHoldingRegister(m_slaveId, 126, 3);
|
||||
}
|
||||
|
||||
ModbusRtuReply *CionModbusRtuConnection::readBlockDurations()
|
||||
{
|
||||
return m_modbusRtuMaster->readHoldingRegister(m_slaveId, 151, 4);
|
||||
}
|
||||
|
||||
void CionModbusRtuConnection::processChargingEnabledRegisterValues(const QVector<quint16> values)
|
||||
{
|
||||
quint16 receivedChargingEnabled = ModbusDataUtils::convertToUInt16(values);
|
||||
if (m_chargingEnabled != receivedChargingEnabled) {
|
||||
m_chargingEnabled = receivedChargingEnabled;
|
||||
emit chargingEnabledChanged(m_chargingEnabled);
|
||||
}
|
||||
}
|
||||
|
||||
void CionModbusRtuConnection::processChargingCurrentSetpointRegisterValues(const QVector<quint16> values)
|
||||
{
|
||||
quint16 receivedChargingCurrentSetpoint = ModbusDataUtils::convertToUInt16(values);
|
||||
if (m_chargingCurrentSetpoint != receivedChargingCurrentSetpoint) {
|
||||
m_chargingCurrentSetpoint = receivedChargingCurrentSetpoint;
|
||||
emit chargingCurrentSetpointChanged(m_chargingCurrentSetpoint);
|
||||
}
|
||||
}
|
||||
|
||||
void CionModbusRtuConnection::processStatusBitsRegisterValues(const QVector<quint16> values)
|
||||
{
|
||||
quint16 receivedStatusBits = ModbusDataUtils::convertToUInt16(values);
|
||||
if (m_statusBits != receivedStatusBits) {
|
||||
m_statusBits = receivedStatusBits;
|
||||
emit statusBitsChanged(m_statusBits);
|
||||
}
|
||||
}
|
||||
|
||||
void CionModbusRtuConnection::processCpSignalStateRegisterValues(const QVector<quint16> values)
|
||||
{
|
||||
quint16 receivedCpSignalState = ModbusDataUtils::convertToUInt16(values);
|
||||
if (m_cpSignalState != receivedCpSignalState) {
|
||||
m_cpSignalState = receivedCpSignalState;
|
||||
emit cpSignalStateChanged(m_cpSignalState);
|
||||
}
|
||||
}
|
||||
|
||||
void CionModbusRtuConnection::processU1VoltageRegisterValues(const QVector<quint16> values)
|
||||
{
|
||||
float receivedU1Voltage = ModbusDataUtils::convertToUInt16(values) * 1.0 * pow(10, -2);
|
||||
if (m_u1Voltage != receivedU1Voltage) {
|
||||
m_u1Voltage = receivedU1Voltage;
|
||||
emit u1VoltageChanged(m_u1Voltage);
|
||||
}
|
||||
}
|
||||
|
||||
void CionModbusRtuConnection::processGridVoltageRegisterValues(const QVector<quint16> values)
|
||||
{
|
||||
float receivedGridVoltage = ModbusDataUtils::convertToUInt16(values) * 1.0 * pow(10, -2);
|
||||
if (m_gridVoltage != receivedGridVoltage) {
|
||||
m_gridVoltage = receivedGridVoltage;
|
||||
emit gridVoltageChanged(m_gridVoltage);
|
||||
}
|
||||
}
|
||||
|
||||
void CionModbusRtuConnection::processMinChargingCurrentRegisterValues(const QVector<quint16> values)
|
||||
{
|
||||
quint16 receivedMinChargingCurrent = ModbusDataUtils::convertToUInt16(values);
|
||||
if (m_minChargingCurrent != receivedMinChargingCurrent) {
|
||||
m_minChargingCurrent = receivedMinChargingCurrent;
|
||||
emit minChargingCurrentChanged(m_minChargingCurrent);
|
||||
}
|
||||
}
|
||||
|
||||
void CionModbusRtuConnection::processCurrentChargingCurrentE3RegisterValues(const QVector<quint16> values)
|
||||
{
|
||||
quint16 receivedCurrentChargingCurrentE3 = ModbusDataUtils::convertToUInt16(values);
|
||||
if (m_currentChargingCurrentE3 != receivedCurrentChargingCurrentE3) {
|
||||
m_currentChargingCurrentE3 = receivedCurrentChargingCurrentE3;
|
||||
emit currentChargingCurrentE3Changed(m_currentChargingCurrentE3);
|
||||
}
|
||||
}
|
||||
|
||||
void CionModbusRtuConnection::processMaxChargingCurrentE3RegisterValues(const QVector<quint16> values)
|
||||
{
|
||||
quint16 receivedMaxChargingCurrentE3 = ModbusDataUtils::convertToUInt16(values);
|
||||
if (m_maxChargingCurrentE3 != receivedMaxChargingCurrentE3) {
|
||||
m_maxChargingCurrentE3 = receivedMaxChargingCurrentE3;
|
||||
emit maxChargingCurrentE3Changed(m_maxChargingCurrentE3);
|
||||
}
|
||||
}
|
||||
|
||||
void CionModbusRtuConnection::processMaxChargingCurrentCableE3RegisterValues(const QVector<quint16> values)
|
||||
{
|
||||
quint16 receivedMaxChargingCurrentCableE3 = ModbusDataUtils::convertToUInt16(values);
|
||||
if (m_maxChargingCurrentCableE3 != receivedMaxChargingCurrentCableE3) {
|
||||
m_maxChargingCurrentCableE3 = receivedMaxChargingCurrentCableE3;
|
||||
emit maxChargingCurrentCableE3Changed(m_maxChargingCurrentCableE3);
|
||||
}
|
||||
}
|
||||
|
||||
void CionModbusRtuConnection::processChargingDurationRegisterValues(const QVector<quint16> values)
|
||||
{
|
||||
quint32 receivedChargingDuration = ModbusDataUtils::convertToUInt32(values, m_endianness);
|
||||
if (m_chargingDuration != receivedChargingDuration) {
|
||||
m_chargingDuration = receivedChargingDuration;
|
||||
emit chargingDurationChanged(m_chargingDuration);
|
||||
}
|
||||
}
|
||||
|
||||
void CionModbusRtuConnection::processPluggedInDurationRegisterValues(const QVector<quint16> values)
|
||||
{
|
||||
quint32 receivedPluggedInDuration = ModbusDataUtils::convertToUInt32(values, m_endianness);
|
||||
if (m_pluggedInDuration != receivedPluggedInDuration) {
|
||||
m_pluggedInDuration = receivedPluggedInDuration;
|
||||
emit pluggedInDurationChanged(m_pluggedInDuration);
|
||||
}
|
||||
}
|
||||
|
||||
void CionModbusRtuConnection::verifyInitFinished()
|
||||
{
|
||||
if (m_pendingInitReplies.isEmpty()) {
|
||||
qCDebug(dcCionModbusRtuConnection()) << "Initialization finished of CionModbusRtuConnection";
|
||||
emit initializationFinished();
|
||||
}
|
||||
}
|
||||
|
||||
QDebug operator<<(QDebug debug, CionModbusRtuConnection *cionModbusRtuConnection)
|
||||
{
|
||||
debug.nospace().noquote() << "CionModbusRtuConnection(" << cionModbusRtuConnection->modbusRtuMaster()->modbusUuid().toString() << ", " << cionModbusRtuConnection->modbusRtuMaster()->serialPort() << ", slave ID:" << cionModbusRtuConnection->slaveId() << ")" << "\n";
|
||||
debug.nospace().noquote() << " - Charging enabled:" << cionModbusRtuConnection->chargingEnabled() << "\n";
|
||||
debug.nospace().noquote() << " - Charging current setpoint:" << cionModbusRtuConnection->chargingCurrentSetpoint() << " [A]" << "\n";
|
||||
debug.nospace().noquote() << " - Mode3-State A, B, C, D, U:" << cionModbusRtuConnection->statusBits() << "\n";
|
||||
debug.nospace().noquote() << " - Status bits:" << cionModbusRtuConnection->cpSignalState() << "\n";
|
||||
debug.nospace().noquote() << " - U1 voltage:" << cionModbusRtuConnection->u1Voltage() << " [V]" << "\n";
|
||||
debug.nospace().noquote() << " - Voltage of the power supply grid:" << cionModbusRtuConnection->gridVoltage() << " [V]" << "\n";
|
||||
debug.nospace().noquote() << " - Minimum charging current:" << cionModbusRtuConnection->minChargingCurrent() << " [A]" << "\n";
|
||||
debug.nospace().noquote() << " - Current charging Ampere:" << cionModbusRtuConnection->currentChargingCurrentE3() << " [A]" << "\n";
|
||||
debug.nospace().noquote() << " - Maximum charging current:" << cionModbusRtuConnection->maxChargingCurrentE3() << " [A]" << "\n";
|
||||
debug.nospace().noquote() << " - Maximum charging current of connected cable:" << cionModbusRtuConnection->maxChargingCurrentCableE3() << " [A]" << "\n";
|
||||
debug.nospace().noquote() << " - Charging duration:" << cionModbusRtuConnection->chargingDuration() << " [ms]" << "\n";
|
||||
debug.nospace().noquote() << " - Plugged in duration:" << cionModbusRtuConnection->pluggedInDuration() << " [ms]" << "\n";
|
||||
return debug.quote().space();
|
||||
}
|
||||
|
||||
@ -1,231 +0,0 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2022, nymea GmbH
|
||||
* Contact: contact@nymea.io
|
||||
*
|
||||
* This fileDescriptor 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
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* WARNING
|
||||
*
|
||||
* This file has been autogenerated. Any changes in this file may be overwritten.
|
||||
* If you want to change something, update the register json or the tool.
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#ifndef CIONMODBUSRTUCONNECTION_H
|
||||
#define CIONMODBUSRTUCONNECTION_H
|
||||
|
||||
#include <QObject>
|
||||
|
||||
#include "../modbus/modbusdatautils.h"
|
||||
#include <hardware/modbus/modbusrtumaster.h>
|
||||
|
||||
class CionModbusRtuConnection : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
enum Registers {
|
||||
RegisterChargingEnabled = 100,
|
||||
RegisterChargingCurrentSetpoint = 101,
|
||||
RegisterStatusBits = 121,
|
||||
RegisterCurrentChargingCurrentE3 = 126,
|
||||
RegisterMaxChargingCurrentE3 = 127,
|
||||
RegisterMaxChargingCurrentCableE3 = 128,
|
||||
RegisterCpSignalState = 139,
|
||||
RegisterChargingDuration = 151,
|
||||
RegisterPluggedInDuration = 153,
|
||||
RegisterU1Voltage = 167,
|
||||
RegisterGridVoltage = 302,
|
||||
RegisterMinChargingCurrent = 507
|
||||
};
|
||||
Q_ENUM(Registers)
|
||||
|
||||
explicit CionModbusRtuConnection(ModbusRtuMaster *modbusRtuMaster, quint16 slaveId, QObject *parent = nullptr);
|
||||
~CionModbusRtuConnection() = default;
|
||||
|
||||
ModbusRtuMaster *modbusRtuMaster() const;
|
||||
quint16 slaveId() const;
|
||||
|
||||
ModbusDataUtils::ByteOrder endianness() const;
|
||||
void setEndianness(ModbusDataUtils::ByteOrder endianness);
|
||||
|
||||
/* Charging enabled - Address: 100, Size: 1 */
|
||||
quint16 chargingEnabled() const;
|
||||
ModbusRtuReply *setChargingEnabled(quint16 chargingEnabled);
|
||||
|
||||
/* Charging current setpoint [A] - Address: 101, Size: 1 */
|
||||
quint16 chargingCurrentSetpoint() const;
|
||||
ModbusRtuReply *setChargingCurrentSetpoint(quint16 chargingCurrentSetpoint);
|
||||
|
||||
/* Mode3-State A, B, C, D, U - Address: 121, Size: 1 */
|
||||
quint16 statusBits() const;
|
||||
|
||||
/* Status bits - Address: 139, Size: 1 */
|
||||
quint16 cpSignalState() const;
|
||||
|
||||
/* U1 voltage [V] - Address: 167, Size: 1 */
|
||||
float u1Voltage() const;
|
||||
|
||||
/* Voltage of the power supply grid [V] - Address: 302, Size: 1 */
|
||||
float gridVoltage() const;
|
||||
|
||||
/* Minimum charging current [A] - Address: 507, Size: 1 */
|
||||
quint16 minChargingCurrent() const;
|
||||
|
||||
/* Current charging Ampere [A] - Address: 126, Size: 1 */
|
||||
quint16 currentChargingCurrentE3() const;
|
||||
|
||||
/* Maximum charging current [A] - Address: 127, Size: 1 */
|
||||
quint16 maxChargingCurrentE3() const;
|
||||
|
||||
/* Maximum charging current of connected cable [A] - Address: 128, Size: 1 */
|
||||
quint16 maxChargingCurrentCableE3() const;
|
||||
|
||||
/* Charging duration [ms] - Address: 151, Size: 2 */
|
||||
quint32 chargingDuration() const;
|
||||
|
||||
/* Plugged in duration [ms] - Address: 153, Size: 2 */
|
||||
quint32 pluggedInDuration() const;
|
||||
|
||||
/* Read block from start addess 126 with size of 3 registers containing following 3 properties:
|
||||
- Current charging Ampere [A] - Address: 126, Size: 1
|
||||
- Maximum charging current [A] - Address: 127, Size: 1
|
||||
- Maximum charging current of connected cable [A] - Address: 128, Size: 1
|
||||
*/
|
||||
void updateE3Block();
|
||||
|
||||
/* Read block from start addess 151 with size of 4 registers containing following 2 properties:
|
||||
- Charging duration [ms] - Address: 151, Size: 2
|
||||
- Plugged in duration [ms] - Address: 153, Size: 2
|
||||
*/
|
||||
void updateDurationsBlock();
|
||||
|
||||
virtual void initialize();
|
||||
virtual void update();
|
||||
|
||||
void updateChargingEnabled();
|
||||
void updateChargingCurrentSetpoint();
|
||||
void updateStatusBits();
|
||||
void updateCpSignalState();
|
||||
void updateU1Voltage();
|
||||
void updateGridVoltage();
|
||||
void updateMinChargingCurrent();
|
||||
|
||||
void updateCurrentChargingCurrentE3();
|
||||
void updateMaxChargingCurrentE3();
|
||||
void updateMaxChargingCurrentCableE3();
|
||||
void updateChargingDuration();
|
||||
void updatePluggedInDuration();
|
||||
|
||||
ModbusRtuReply *readChargingEnabled();
|
||||
ModbusRtuReply *readChargingCurrentSetpoint();
|
||||
ModbusRtuReply *readStatusBits();
|
||||
ModbusRtuReply *readCpSignalState();
|
||||
ModbusRtuReply *readU1Voltage();
|
||||
ModbusRtuReply *readGridVoltage();
|
||||
ModbusRtuReply *readMinChargingCurrent();
|
||||
ModbusRtuReply *readCurrentChargingCurrentE3();
|
||||
ModbusRtuReply *readMaxChargingCurrentE3();
|
||||
ModbusRtuReply *readMaxChargingCurrentCableE3();
|
||||
ModbusRtuReply *readChargingDuration();
|
||||
ModbusRtuReply *readPluggedInDuration();
|
||||
|
||||
/* Read block from start addess 126 with size of 3 registers containing following 3 properties:
|
||||
- Current charging Ampere [A] - Address: 126, Size: 1
|
||||
- Maximum charging current [A] - Address: 127, Size: 1
|
||||
- Maximum charging current of connected cable [A] - Address: 128, Size: 1
|
||||
*/
|
||||
ModbusRtuReply *readBlockE3();
|
||||
|
||||
/* Read block from start addess 151 with size of 4 registers containing following 2 properties:
|
||||
- Charging duration [ms] - Address: 151, Size: 2
|
||||
- Plugged in duration [ms] - Address: 153, Size: 2
|
||||
*/
|
||||
ModbusRtuReply *readBlockDurations();
|
||||
|
||||
signals:
|
||||
void initializationFinished();
|
||||
void endiannessChanged(ModbusDataUtils::ByteOrder endianness);
|
||||
|
||||
void chargingEnabledChanged(quint16 chargingEnabled);
|
||||
void chargingCurrentSetpointChanged(quint16 chargingCurrentSetpoint);
|
||||
void statusBitsChanged(quint16 statusBits);
|
||||
void cpSignalStateChanged(quint16 cpSignalState);
|
||||
void u1VoltageChanged(float u1Voltage);
|
||||
void gridVoltageChanged(float gridVoltage);
|
||||
void minChargingCurrentChanged(quint16 minChargingCurrent);
|
||||
void currentChargingCurrentE3Changed(quint16 currentChargingCurrentE3);
|
||||
void maxChargingCurrentE3Changed(quint16 maxChargingCurrentE3);
|
||||
void maxChargingCurrentCableE3Changed(quint16 maxChargingCurrentCableE3);
|
||||
void chargingDurationChanged(quint32 chargingDuration);
|
||||
void pluggedInDurationChanged(quint32 pluggedInDuration);
|
||||
|
||||
protected:
|
||||
quint16 m_chargingEnabled = 0;
|
||||
quint16 m_chargingCurrentSetpoint = 6;
|
||||
quint16 m_statusBits = 85;
|
||||
quint16 m_cpSignalState = 0;
|
||||
float m_u1Voltage = 32;
|
||||
float m_gridVoltage = 0;
|
||||
quint16 m_minChargingCurrent = 13;
|
||||
quint16 m_currentChargingCurrentE3 = 6;
|
||||
quint16 m_maxChargingCurrentE3 = 32;
|
||||
quint16 m_maxChargingCurrentCableE3 = 32;
|
||||
quint32 m_chargingDuration = 0;
|
||||
quint32 m_pluggedInDuration = 0;
|
||||
|
||||
void processChargingEnabledRegisterValues(const QVector<quint16> values);
|
||||
void processChargingCurrentSetpointRegisterValues(const QVector<quint16> values);
|
||||
void processStatusBitsRegisterValues(const QVector<quint16> values);
|
||||
void processCpSignalStateRegisterValues(const QVector<quint16> values);
|
||||
void processU1VoltageRegisterValues(const QVector<quint16> values);
|
||||
void processGridVoltageRegisterValues(const QVector<quint16> values);
|
||||
void processMinChargingCurrentRegisterValues(const QVector<quint16> values);
|
||||
|
||||
void processCurrentChargingCurrentE3RegisterValues(const QVector<quint16> values);
|
||||
void processMaxChargingCurrentE3RegisterValues(const QVector<quint16> values);
|
||||
void processMaxChargingCurrentCableE3RegisterValues(const QVector<quint16> values);
|
||||
|
||||
void processChargingDurationRegisterValues(const QVector<quint16> values);
|
||||
void processPluggedInDurationRegisterValues(const QVector<quint16> values);
|
||||
|
||||
|
||||
private:
|
||||
ModbusRtuMaster *m_modbusRtuMaster = nullptr;
|
||||
quint16 m_slaveId = 1;
|
||||
QVector<ModbusRtuReply *> m_pendingInitReplies;
|
||||
ModbusDataUtils::ByteOrder m_endianness = ModbusDataUtils::ByteOrderBigEndian;
|
||||
|
||||
void verifyInitFinished();
|
||||
|
||||
|
||||
};
|
||||
|
||||
QDebug operator<<(QDebug debug, CionModbusRtuConnection *cionModbusRtuConnection);
|
||||
|
||||
#endif // CIONMODBUSRTUCONNECTION_H
|
||||
@ -1,20 +1,13 @@
|
||||
include(../plugins.pri)
|
||||
|
||||
QT += serialport serialbus
|
||||
# Generate modbus connection
|
||||
MODBUS_CONNECTIONS += cion-registers.json
|
||||
#MODBUS_TOOLS_CONFIG += VERBOSE
|
||||
include(../modbus.pri)
|
||||
|
||||
SOURCES += \
|
||||
integrationpluginschrack.cpp \
|
||||
cionmodbusrtuconnection.cpp \
|
||||
../modbus/modbusdatautils.cpp
|
||||
integrationpluginschrack.cpp
|
||||
|
||||
HEADERS += \
|
||||
integrationpluginschrack.h \
|
||||
cionmodbusrtuconnection.h \
|
||||
../modbus/modbusdatautils.h
|
||||
integrationpluginschrack.h
|
||||
|
||||
OTHER_FILES += cion-registers.json
|
||||
|
||||
modbusconnection.commands = python $${top_srcdir}/modbus/tools/generate-connection.py -j $${_PRO_FILE_PWD_}/cion-registers.json -o $${_PRO_FILE_PWD_} -c CionModbusRtuConnection
|
||||
QMAKE_EXTRA_TARGETS += modbusconnection
|
||||
|
||||
#target.depends += modbusconnection
|
||||
|
||||
21
stiebeleltron/README.md
Normal file
21
stiebeleltron/README.md
Normal file
@ -0,0 +1,21 @@
|
||||
# Stiebel Eltron
|
||||
|
||||
Connect nymea to Stiebel Eltron heat pumps.
|
||||
|
||||
This plugin communicates via Modbus/TCP with a Stiebel Eltron Internet-Service-Gateway (ISG). The ISG is usually connected to a WPM/WPM3/WPM3i heatpump controller which again is connected via CAN to the heatpump.
|
||||
Make sure the ISG firmware is up to date to ensure the Modbus/TCP connection is working. Contact Stiebel Eltron service for a remote update of your ISG.
|
||||
|
||||
|
||||
## Supported Things
|
||||
|
||||
* Stiebel Eltron Heatpump
|
||||
|
||||
## Requirements
|
||||
|
||||
* The package `nymea-plugin-stiebeleltron` must be installed
|
||||
* Both devices must be in the same local area network.
|
||||
* Modbus enabled (may conflict with an installed SMA EMI).
|
||||
|
||||
## More
|
||||
|
||||
https://www.stiebel-eltron.de/
|
||||
395
stiebeleltron/integrationpluginstiebeleltron.cpp
Normal file
395
stiebeleltron/integrationpluginstiebeleltron.cpp
Normal file
@ -0,0 +1,395 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2021, nymea GmbH, Consolinno Energy GmbH, L. Heizinger
|
||||
* 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 "integrationpluginstiebeleltron.h"
|
||||
#include "plugininfo.h"
|
||||
|
||||
#include <hardwaremanager.h>
|
||||
#include <network/networkdevicediscovery.h>
|
||||
|
||||
IntegrationPluginStiebelEltron::IntegrationPluginStiebelEltron() {}
|
||||
|
||||
void IntegrationPluginStiebelEltron::discoverThings(ThingDiscoveryInfo *info) {
|
||||
if (!hardwareManager()->networkDeviceDiscovery()->available()) {
|
||||
qCWarning(dcStiebelEltron()) << "The network discovery is not available on this platform.";
|
||||
info->finish(Thing::ThingErrorUnsupportedFeature,
|
||||
QT_TR_NOOP("The network device discovery is not available."));
|
||||
return;
|
||||
}
|
||||
|
||||
NetworkDeviceDiscoveryReply *discoveryReply = hardwareManager()->networkDeviceDiscovery()->discover();
|
||||
connect(discoveryReply, &NetworkDeviceDiscoveryReply::finished, this, [=]() {
|
||||
foreach (const NetworkDeviceInfo &networkDeviceInfo, discoveryReply->networkDeviceInfos()) {
|
||||
qCDebug(dcStiebelEltron()) << "Found" << networkDeviceInfo;
|
||||
|
||||
QString title;
|
||||
if (networkDeviceInfo.hostName().isEmpty()) {
|
||||
title = networkDeviceInfo.address().toString();
|
||||
} else {
|
||||
if (!networkDeviceInfo.hostName().contains("StiebelEltronISG")) continue;
|
||||
title = networkDeviceInfo.hostName() + " (" + networkDeviceInfo.address().toString() + ")";
|
||||
}
|
||||
|
||||
QString description;
|
||||
if (networkDeviceInfo.macAddressManufacturer().isEmpty()) {
|
||||
description = networkDeviceInfo.macAddress();
|
||||
} else {
|
||||
description =
|
||||
networkDeviceInfo.macAddress() + " (" + networkDeviceInfo.macAddressManufacturer() + ")";
|
||||
}
|
||||
|
||||
ThingDescriptor descriptor(stiebelEltronThingClassId, title, description);
|
||||
ParamList params;
|
||||
params << Param(stiebelEltronThingIpAddressParamTypeId, networkDeviceInfo.address().toString());
|
||||
params << Param(stiebelEltronThingMacAddressParamTypeId, networkDeviceInfo.macAddress());
|
||||
descriptor.setParams(params);
|
||||
|
||||
// Check if we already have set up this device
|
||||
Things existingThings = myThings().filterByParam(stiebelEltronThingMacAddressParamTypeId,
|
||||
networkDeviceInfo.macAddress());
|
||||
if (existingThings.count() == 1) {
|
||||
qCDebug(dcStiebelEltron())
|
||||
<< "This connection already exists in the system:" << networkDeviceInfo;
|
||||
descriptor.setThingId(existingThings.first()->id());
|
||||
}
|
||||
|
||||
info->addThingDescriptor(descriptor);
|
||||
}
|
||||
|
||||
info->finish(Thing::ThingErrorNoError);
|
||||
});
|
||||
}
|
||||
|
||||
void IntegrationPluginStiebelEltron::startMonitoringAutoThings() {}
|
||||
|
||||
void IntegrationPluginStiebelEltron::setupThing(ThingSetupInfo *info) {
|
||||
Thing *thing = info->thing();
|
||||
qCDebug(dcStiebelEltron()) << "Setup" << thing << thing->params();
|
||||
|
||||
if (thing->thingClassId() == stiebelEltronThingClassId) {
|
||||
QHostAddress address(thing->paramValue(stiebelEltronThingIpAddressParamTypeId).toString());
|
||||
quint16 port = thing->paramValue(stiebelEltronThingPortParamTypeId).toUInt();
|
||||
quint16 slaveId = thing->paramValue(stiebelEltronThingSlaveIdParamTypeId).toUInt();
|
||||
|
||||
StiebelEltronModbusTcpConnection *connection =
|
||||
new StiebelEltronModbusTcpConnection(address, port, slaveId, this);
|
||||
|
||||
connect(connection, &StiebelEltronModbusTcpConnection::connectionStateChanged, thing,
|
||||
[thing, connection](bool status) {
|
||||
qCDebug(dcStiebelEltron()) << "Connected changed to" << status << "for" << thing;
|
||||
if (status) {
|
||||
connection->update();
|
||||
}
|
||||
|
||||
thing->setStateValue(stiebelEltronConnectedStateTypeId, status);
|
||||
});
|
||||
|
||||
connect(connection, &StiebelEltronModbusTcpConnection::outdoorTemperatureChanged, thing,
|
||||
[thing](float outdoorTemperature) {
|
||||
qCDebug(dcStiebelEltron())
|
||||
<< thing << "outdoor temperature changed" << outdoorTemperature << "°C";
|
||||
thing->setStateValue(stiebelEltronOutdoorTemperatureStateTypeId, outdoorTemperature);
|
||||
});
|
||||
|
||||
connect(connection, &StiebelEltronModbusTcpConnection::flowTemperatureChanged, thing,
|
||||
[thing](float flowTemperature) {
|
||||
qCDebug(dcStiebelEltron())
|
||||
<< thing << "flow temperature changed" << flowTemperature << "°C";
|
||||
thing->setStateValue(stiebelEltronFlowTemperatureStateTypeId, flowTemperature);
|
||||
});
|
||||
|
||||
connect(connection, &StiebelEltronModbusTcpConnection::hotWaterTemperatureChanged, thing,
|
||||
[thing](float hotWaterTemperature) {
|
||||
qCDebug(dcStiebelEltron())
|
||||
<< thing << "hot water temperature changed" << hotWaterTemperature << "°C";
|
||||
thing->setStateValue(stiebelEltronHotWaterTemperatureStateTypeId, hotWaterTemperature);
|
||||
});
|
||||
|
||||
connect(connection, &StiebelEltronModbusTcpConnection::storageTankTemperatureChanged, thing,
|
||||
[thing](float storageTankTemperature) {
|
||||
qCDebug(dcStiebelEltron())
|
||||
<< thing << "Storage tank temperature changed" << storageTankTemperature << "°C";
|
||||
thing->setStateValue(stiebelEltronStorageTankTemperatureStateTypeId,
|
||||
storageTankTemperature);
|
||||
});
|
||||
|
||||
connect(connection, &StiebelEltronModbusTcpConnection::returnTemperatureChanged, thing,
|
||||
[thing](float returnTemperature) {
|
||||
qCDebug(dcStiebelEltron())
|
||||
<< thing << "return temperature changed" << returnTemperature << "°C";
|
||||
thing->setStateValue(stiebelEltronReturnTemperatureStateTypeId, returnTemperature);
|
||||
});
|
||||
|
||||
connect(connection, &StiebelEltronModbusTcpConnection::heatingEnergyChanged, thing,
|
||||
[thing](quint32 heatingEnergy) {
|
||||
// kWh and MWh of energy are stored in two registers an read as
|
||||
// an uint32. The following arithmetic splits the uint32 into
|
||||
// two uint16 and sums up the MWh and kWh values.
|
||||
quint32 correctedEnergy = (heatingEnergy >> 16) + (heatingEnergy & 0xFFFF) * 1000;
|
||||
qCDebug(dcStiebelEltron())
|
||||
<< thing << "Heating energy changed" << correctedEnergy << "kWh";
|
||||
thing->setStateValue(stiebelEltronHeatingEnergyStateTypeId, correctedEnergy);
|
||||
});
|
||||
|
||||
connect(connection, &StiebelEltronModbusTcpConnection::hotWaterEnergyChanged, thing,
|
||||
[thing](quint32 hotWaterEnergy) {
|
||||
// see comment in heatingEnergyChanged
|
||||
quint32 correctedEnergy = (hotWaterEnergy >> 16) + (hotWaterEnergy & 0xFFFF) * 1000;
|
||||
qCDebug(dcStiebelEltron())
|
||||
<< thing << "Hot Water energy changed" << correctedEnergy << "kWh";
|
||||
thing->setStateValue(stiebelEltronHotWaterEnergyStateTypeId, correctedEnergy);
|
||||
});
|
||||
|
||||
connect(connection, &StiebelEltronModbusTcpConnection::consumedEnergyHeatingChanged, thing,
|
||||
[thing](quint32 consumedEnergyHeatingEnergy) {
|
||||
// see comment in heatingEnergyChanged
|
||||
quint32 correctedEnergy =
|
||||
(consumedEnergyHeatingEnergy >> 16) + (consumedEnergyHeatingEnergy & 0xFFFF) * 1000;
|
||||
qCDebug(dcStiebelEltron())
|
||||
<< thing << "Consumed energy Heating changed" << correctedEnergy << "kWh";
|
||||
thing->setStateValue(stiebelEltronConsumedEnergyHeatingStateTypeId, correctedEnergy);
|
||||
});
|
||||
|
||||
connect(connection, &StiebelEltronModbusTcpConnection::consumedEnergyHotWaterChanged, thing,
|
||||
[thing](quint32 consumedEnergyHotWaterEnergy) {
|
||||
// see comment in heatingEnergyChanged
|
||||
quint32 correctedEnergy =
|
||||
(consumedEnergyHotWaterEnergy >> 16) + (consumedEnergyHotWaterEnergy & 0xFFFF) * 1000;
|
||||
qCDebug(dcStiebelEltron())
|
||||
<< thing << "Consumed energy hot water changed" << correctedEnergy << "kWh";
|
||||
thing->setStateValue(stiebelEltronConsumedEnergyHotWaterStateTypeId, correctedEnergy);
|
||||
});
|
||||
|
||||
connect(connection, &StiebelEltronModbusTcpConnection::operatingModeChanged, thing,
|
||||
[thing](StiebelEltronModbusTcpConnection::OperatingMode operatingMode) {
|
||||
qCDebug(dcStiebelEltron()) << thing << "operating mode changed " << operatingMode;
|
||||
switch (operatingMode) {
|
||||
case StiebelEltronModbusTcpConnection::OperatingModeEmergency:
|
||||
thing->setStateValue(stiebelEltronOperatingModeStateTypeId, "Emergency");
|
||||
break;
|
||||
case StiebelEltronModbusTcpConnection::OperatingModeStandby:
|
||||
thing->setStateValue(stiebelEltronOperatingModeStateTypeId, "Standby");
|
||||
break;
|
||||
case StiebelEltronModbusTcpConnection::OperatingModeProgram:
|
||||
thing->setStateValue(stiebelEltronOperatingModeStateTypeId, "Program");
|
||||
break;
|
||||
case StiebelEltronModbusTcpConnection::OperatingModeComfort:
|
||||
thing->setStateValue(stiebelEltronOperatingModeStateTypeId, "Comfort");
|
||||
break;
|
||||
case StiebelEltronModbusTcpConnection::OperatingModeEco:
|
||||
thing->setStateValue(stiebelEltronOperatingModeStateTypeId, "Eco");
|
||||
break;
|
||||
case StiebelEltronModbusTcpConnection::OperatingModeHotWater:
|
||||
thing->setStateValue(stiebelEltronOperatingModeStateTypeId, "Hot water");
|
||||
break;
|
||||
}
|
||||
});
|
||||
|
||||
connect(connection, &StiebelEltronModbusTcpConnection::systemStatusChanged, thing,
|
||||
[thing](uint16_t systemStatus) {
|
||||
qCDebug(dcStiebelEltron()) << thing << "System status changed " << systemStatus;
|
||||
thing->setStateValue(stiebelEltronPumpOneStateTypeId, systemStatus & (1 << 0));
|
||||
thing->setStateValue(stiebelEltronPumpTwoStateTypeId, systemStatus & (1 << 1));
|
||||
thing->setStateValue(stiebelEltronHeatingUpStateTypeId, systemStatus & (1 << 2));
|
||||
thing->setStateValue(stiebelEltronAuxHeatingStateTypeId, systemStatus & (1 << 3));
|
||||
thing->setStateValue(stiebelEltronHeatingStateTypeId, systemStatus & (1 << 4));
|
||||
thing->setStateValue(stiebelEltronHotWaterStateTypeId, systemStatus & (1 << 5));
|
||||
thing->setStateValue(stiebelEltronCompressorStateTypeId, systemStatus & (1 << 6));
|
||||
thing->setStateValue(stiebelEltronSummerModeStateTypeId, systemStatus & (1 << 7));
|
||||
thing->setStateValue(stiebelEltronCoolingModeStateTypeId, systemStatus & (1 << 8));
|
||||
thing->setStateValue(stiebelEltronDefrostingStateTypeId, systemStatus & (1 << 9));
|
||||
thing->setStateValue(stiebelEltronSilentModeStateTypeId, systemStatus & (1 << 10));
|
||||
thing->setStateValue(stiebelEltronSilentMode2StateTypeId, systemStatus & (1 << 11));
|
||||
});
|
||||
|
||||
connect(connection, &StiebelEltronModbusTcpConnection::sgReadyStateChanged, thing,
|
||||
[thing](StiebelEltronModbusTcpConnection::SmartGridState smartGridState) {
|
||||
qCDebug(dcStiebelEltron()) << thing << "SG Ready mode changed" << smartGridState;
|
||||
switch (smartGridState) {
|
||||
case StiebelEltronModbusTcpConnection::SmartGridStateModeOne:
|
||||
thing->setStateValue(stiebelEltronSgReadyModeStateTypeId, "Off");
|
||||
break;
|
||||
case StiebelEltronModbusTcpConnection::SmartGridStateModeTwo:
|
||||
thing->setStateValue(stiebelEltronSgReadyModeStateTypeId, "Low");
|
||||
break;
|
||||
case StiebelEltronModbusTcpConnection::SmartGridStateModeThree:
|
||||
thing->setStateValue(stiebelEltronSgReadyModeStateTypeId, "Standard");
|
||||
break;
|
||||
case StiebelEltronModbusTcpConnection::SmartGridStateModeFour:
|
||||
thing->setStateValue(stiebelEltronSgReadyModeStateTypeId, "High");
|
||||
break;
|
||||
}
|
||||
});
|
||||
connect(connection, &StiebelEltronModbusTcpConnection::sgReadyActiveChanged, thing,
|
||||
[thing](bool smartGridActive) {
|
||||
qCDebug(dcStiebelEltron()) << thing << "SG Ready activation changed" << smartGridActive;
|
||||
thing->setStateValue(stiebelEltronSgReadyActiveStateTypeId, smartGridActive);
|
||||
});
|
||||
|
||||
m_connections.insert(thing, connection);
|
||||
connection->connectDevice();
|
||||
|
||||
info->finish(Thing::ThingErrorNoError);
|
||||
}
|
||||
}
|
||||
|
||||
void IntegrationPluginStiebelEltron::postSetupThing(Thing *thing) {
|
||||
if (thing->thingClassId() == stiebelEltronThingClassId) {
|
||||
if (!m_pluginTimer) {
|
||||
qCDebug(dcStiebelEltron()) << "Starting plugin timer...";
|
||||
m_pluginTimer = hardwareManager()->pluginTimerManager()->registerTimer(10);
|
||||
connect(m_pluginTimer, &PluginTimer::timeout, this, [this] {
|
||||
foreach (StiebelEltronModbusTcpConnection *connection, m_connections) {
|
||||
if (connection->connected()) {
|
||||
connection->update();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
m_pluginTimer->start();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void IntegrationPluginStiebelEltron::thingRemoved(Thing *thing) {
|
||||
if (thing->thingClassId() == stiebelEltronThingClassId && m_connections.contains(thing)) {
|
||||
m_connections.take(thing)->deleteLater();
|
||||
}
|
||||
|
||||
if (myThings().isEmpty() && m_pluginTimer) {
|
||||
hardwareManager()->pluginTimerManager()->unregisterTimer(m_pluginTimer);
|
||||
m_pluginTimer = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void IntegrationPluginStiebelEltron::executeAction(ThingActionInfo *info) {
|
||||
Thing *thing = info->thing();
|
||||
StiebelEltronModbusTcpConnection *connection = m_connections.value(thing);
|
||||
|
||||
if (!connection->connected()) {
|
||||
qCWarning(dcStiebelEltron()) << "Could not execute action. The modbus connection is currently "
|
||||
"not available.";
|
||||
info->finish(Thing::ThingErrorHardwareNotAvailable);
|
||||
return;
|
||||
}
|
||||
|
||||
// Got this from StiebelEltron plugin, not sure if necessary
|
||||
if (thing->thingClassId() != stiebelEltronThingClassId) {
|
||||
info->finish(Thing::ThingErrorNoError);
|
||||
}
|
||||
|
||||
if (info->action().actionTypeId() == stiebelEltronSgReadyActiveActionTypeId) {
|
||||
bool sgReadyActiveBool =
|
||||
info->action().paramValue(stiebelEltronSgReadyActiveActionSgReadyActiveParamTypeId).toBool();
|
||||
qCDebug(dcStiebelEltron()) << "Execute action" << info->action().actionTypeId().toString()
|
||||
<< info->action().params();
|
||||
qCDebug(dcStiebelEltron()) << "Value: " << sgReadyActiveBool;
|
||||
|
||||
QModbusReply *reply = connection->setSgReadyActive(sgReadyActiveBool);
|
||||
if (!reply) {
|
||||
qCWarning(dcStiebelEltron()) << "Execute action failed because the "
|
||||
"reply could not be created.";
|
||||
info->finish(Thing::ThingErrorHardwareFailure);
|
||||
return;
|
||||
}
|
||||
|
||||
connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater);
|
||||
connect(reply, &QModbusReply::finished, info, [info, reply, sgReadyActiveBool] {
|
||||
if (reply->error() != QModbusDevice::NoError) {
|
||||
qCWarning(dcStiebelEltron())
|
||||
<< "Set SG ready activation finished with error" << reply->errorString();
|
||||
info->finish(Thing::ThingErrorHardwareFailure);
|
||||
return;
|
||||
}
|
||||
|
||||
qCDebug(dcStiebelEltron()) << "Execute action finished successfully"
|
||||
<< info->action().actionTypeId().toString() << info->action().params();
|
||||
info->thing()->setStateValue(stiebelEltronSgReadyActiveStateTypeId, sgReadyActiveBool);
|
||||
info->finish(Thing::ThingErrorNoError);
|
||||
});
|
||||
|
||||
connect(reply, &QModbusReply::errorOccurred, this, [reply](QModbusDevice::Error error) {
|
||||
qCWarning(dcStiebelEltron())
|
||||
<< "Modbus reply error occurred while execute action" << error << reply->errorString();
|
||||
emit reply->finished(); // To make sure it will be deleted
|
||||
});
|
||||
} else if (info->action().actionTypeId() == stiebelEltronSgReadyModeActionTypeId) {
|
||||
QString sgReadyModeString =
|
||||
info->action().paramValue(stiebelEltronSgReadyModeActionSgReadyModeParamTypeId).toString();
|
||||
qCDebug(dcStiebelEltron()) << "Execute action" << info->action().actionTypeId().toString()
|
||||
<< info->action().params();
|
||||
StiebelEltronModbusTcpConnection::SmartGridState sgReadyState;
|
||||
if (sgReadyModeString == "Off") {
|
||||
sgReadyState = StiebelEltronModbusTcpConnection::SmartGridStateModeOne;
|
||||
} else if (sgReadyModeString == "Low") {
|
||||
sgReadyState = StiebelEltronModbusTcpConnection::SmartGridStateModeTwo;
|
||||
} else if (sgReadyModeString == "Standard") {
|
||||
sgReadyState = StiebelEltronModbusTcpConnection::SmartGridStateModeThree;
|
||||
} else if (sgReadyModeString == "High") {
|
||||
sgReadyState = StiebelEltronModbusTcpConnection::SmartGridStateModeFour;
|
||||
} else {
|
||||
qCWarning(dcStiebelEltron())
|
||||
<< "Failed to set SG Ready mode. An unknown SG Ready mode was passed: " << sgReadyModeString;
|
||||
info->finish(Thing::ThingErrorHardwareFailure); // TODO better matching error type?
|
||||
return;
|
||||
}
|
||||
|
||||
QModbusReply *reply = connection->setSgReadyState(sgReadyState);
|
||||
if (!reply) {
|
||||
qCWarning(dcStiebelEltron()) << "Execute action failed because the "
|
||||
"reply could not be created.";
|
||||
info->finish(Thing::ThingErrorHardwareFailure);
|
||||
return;
|
||||
}
|
||||
|
||||
connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater);
|
||||
connect(reply, &QModbusReply::finished, info, [info, reply, sgReadyModeString] {
|
||||
if (reply->error() != QModbusDevice::NoError) {
|
||||
qCWarning(dcStiebelEltron())
|
||||
<< "Set SG ready mode finished with error" << reply->errorString();
|
||||
info->finish(Thing::ThingErrorHardwareFailure);
|
||||
return;
|
||||
}
|
||||
|
||||
qCDebug(dcStiebelEltron()) << "Execute action finished successfully"
|
||||
<< info->action().actionTypeId().toString() << info->action().params();
|
||||
info->thing()->setStateValue(stiebelEltronSgReadyModeStateTypeId, sgReadyModeString);
|
||||
info->finish(Thing::ThingErrorNoError);
|
||||
});
|
||||
|
||||
connect(reply, &QModbusReply::errorOccurred, this, [reply](QModbusDevice::Error error) {
|
||||
qCWarning(dcStiebelEltron())
|
||||
<< "Modbus reply error occurred while execute action" << error << reply->errorString();
|
||||
emit reply->finished(); // To make sure it will be deleted
|
||||
});
|
||||
}
|
||||
info->finish(Thing::ThingErrorNoError);
|
||||
}
|
||||
|
||||
66
stiebeleltron/integrationpluginstiebeleltron.h
Normal file
66
stiebeleltron/integrationpluginstiebeleltron.h
Normal file
@ -0,0 +1,66 @@
|
||||
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
||||
*
|
||||
* Copyright 2013 - 2021, nymea GmbH, Consolinno Energy GmbH, L. Heizinger
|
||||
* 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 INTEGRATIONPLUGINSTIEBELELTRON_H
|
||||
#define INTEGRATIONPLUGINSTIEBELELTRON_H
|
||||
|
||||
#include <plugintimer.h>
|
||||
#include <integrations/integrationplugin.h>
|
||||
|
||||
#include "stiebeleltronmodbustcpconnection.h"
|
||||
|
||||
class IntegrationPluginStiebelEltron: public IntegrationPlugin
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_PLUGIN_METADATA(IID "io.nymea.IntegrationPlugin" FILE "integrationpluginstiebeleltron.json")
|
||||
Q_INTERFACES(IntegrationPlugin)
|
||||
|
||||
public:
|
||||
explicit IntegrationPluginStiebelEltron();
|
||||
|
||||
void discoverThings(ThingDiscoveryInfo *info) override;
|
||||
void startMonitoringAutoThings() override;
|
||||
void setupThing(ThingSetupInfo *info) override;
|
||||
void postSetupThing(Thing *thing) override;
|
||||
void thingRemoved(Thing *thing) override;
|
||||
void executeAction(ThingActionInfo *info) override;
|
||||
|
||||
private:
|
||||
PluginTimer *m_pluginTimer = nullptr;
|
||||
|
||||
QHash<Thing *, StiebelEltronModbusTcpConnection *> m_connections;
|
||||
|
||||
|
||||
};
|
||||
|
||||
#endif // INTEGRATIONPLUGINSTIEBELELTRON_H
|
||||
|
||||
|
||||
331
stiebeleltron/integrationpluginstiebeleltron.json
Normal file
331
stiebeleltron/integrationpluginstiebeleltron.json
Normal file
@ -0,0 +1,331 @@
|
||||
{
|
||||
"name": "StiebelEltron",
|
||||
"displayName": "Stiebel Eltron",
|
||||
"id": "956c848b-b538-4b8f-8cdb-7bbecfc9d361",
|
||||
"vendors": [
|
||||
{
|
||||
"name": "stiebelEltron",
|
||||
"displayName": "Stiebel Eltron",
|
||||
"id": "c8607f85-a81e-40e0-bc95-1b7199cd2d99",
|
||||
"thingClasses": [
|
||||
{
|
||||
"name": "stiebelEltron",
|
||||
"displayName": "Stiebel Eltron Heatpump",
|
||||
"id": "e02ecf61-7d28-43c2-b87e-e7e98a48fbfd",
|
||||
"createMethods": ["discovery", "user"],
|
||||
"interfaces": ["smartgridheatpump", "connectable"],
|
||||
"paramTypes": [
|
||||
{
|
||||
"id": "47d221fa-f6d2-400e-b80f-bb90abccb72c",
|
||||
"name": "ipAddress",
|
||||
"displayName": "IP address",
|
||||
"type": "QString",
|
||||
"inputType": "IPv4Address",
|
||||
"defaultValue": "127.0.0.1"
|
||||
},
|
||||
{
|
||||
"id": "05cd59b8-3068-460f-b0d2-6d49f27458df",
|
||||
"name":"macAddress",
|
||||
"displayName": "MAC address",
|
||||
"type": "QString",
|
||||
"inputType": "MacAddress",
|
||||
"defaultValue": ""
|
||||
},
|
||||
{
|
||||
"id": "6842321f-1f1a-47e2-b12d-59ee322eb8a6",
|
||||
"name":"port",
|
||||
"displayName": "Port",
|
||||
"type": "int",
|
||||
"defaultValue": 502
|
||||
},
|
||||
{
|
||||
"id": "732de6da-bd0a-4215-b320-602117ebc75c",
|
||||
"name":"slaveId",
|
||||
"displayName": "Modbus slave ID",
|
||||
"type": "int",
|
||||
"defaultValue": 1
|
||||
}
|
||||
],
|
||||
"stateTypes": [
|
||||
{
|
||||
"id": "8d952a5e-87bd-492e-a213-277948521652",
|
||||
"name": "connected",
|
||||
"displayName": "Connected",
|
||||
"displayNameEvent": "Connected changed",
|
||||
"type": "bool",
|
||||
"defaultValue": false,
|
||||
"cached": false
|
||||
},
|
||||
{
|
||||
"id": "1ec958c8-7bf1-469e-b35e-b71fa2099e91",
|
||||
"name": "flowTemperature",
|
||||
"displayName": "Flow temperature",
|
||||
"displayNameEvent": "Flow temperature changed",
|
||||
"unit": "DegreeCelsius",
|
||||
"type": "double",
|
||||
"defaultValue": 0,
|
||||
"suggestLogging": true
|
||||
},
|
||||
{
|
||||
"id": "ce25e3fd-6544-40e9-bd39-032306553e32",
|
||||
"name": "returnTemperature",
|
||||
"displayName": "Return temperature",
|
||||
"displayNameEvent": "Return temperature changed",
|
||||
"unit": "DegreeCelsius",
|
||||
"type": "double",
|
||||
"defaultValue": 0,
|
||||
"suggestLogging": true
|
||||
},
|
||||
|
||||
{
|
||||
"id": "e86cbac5-c2c3-4fcf-8caa-dbfc0df2584d",
|
||||
"name": "outdoorTemperature",
|
||||
"displayName": "Outdoor temperature",
|
||||
"displayNameEvent": "Outdoor temperature changed",
|
||||
"unit": "DegreeCelsius",
|
||||
"type": "double",
|
||||
"defaultValue": 0,
|
||||
"suggestLogging": true
|
||||
},
|
||||
{
|
||||
"id": "27c56897-75f1-45af-9a14-b0620053d2d2",
|
||||
"name": "hotWaterTemperature",
|
||||
"displayName": "Hot water temperature",
|
||||
"displayNameEvent": "Hot water changed",
|
||||
"unit": "DegreeCelsius",
|
||||
"type": "double",
|
||||
"defaultValue": 0,
|
||||
"suggestLogging": true
|
||||
},
|
||||
{
|
||||
"id": "43dd25b3-8782-4faa-a9e0-2fb10892fa0c",
|
||||
"name": "storageTankTemperature",
|
||||
"displayName": "Storage tank temperature",
|
||||
"displayNameEvent": "Storage tank temperature changed",
|
||||
"unit": "DegreeCelsius",
|
||||
"type": "double",
|
||||
"defaultValue": 0,
|
||||
"suggestLogging": true
|
||||
},
|
||||
{
|
||||
"id": "d0597f21-2c0e-4db6-92e0-4a3b66474f87",
|
||||
"name": "heatingEnergy",
|
||||
"displayName": "Heating energy",
|
||||
"displayNameEvent": "Heating energy changed",
|
||||
"unit": "KiloWattHour",
|
||||
"type": "uint",
|
||||
"defaultValue": 0,
|
||||
"suggestLogging": true
|
||||
},
|
||||
{
|
||||
"id": "9761060e-f364-466e-8661-d28f01b862fc",
|
||||
"name": "hotWaterEnergy",
|
||||
"displayName": "Hot water energy",
|
||||
"displayNameEvent": "Hot water energy changed",
|
||||
"unit": "KiloWattHour",
|
||||
"type": "uint",
|
||||
"defaultValue": 0,
|
||||
"suggestLogging": true
|
||||
},
|
||||
{
|
||||
"id": "11f91606-d550-4918-9fca-69e3303389c8",
|
||||
"name": "consumedEnergyHotWater",
|
||||
"displayName": "Consumed energy hot water",
|
||||
"displayNameEvent": "Consumed energy hot water changed",
|
||||
"unit": "KiloWattHour",
|
||||
"type": "uint",
|
||||
"defaultValue": 0,
|
||||
"suggestLogging": true
|
||||
},
|
||||
{
|
||||
"id": "6816dfef-3f54-4bf1-b0d5-641f06785991",
|
||||
"name": "consumedEnergyHeating",
|
||||
"displayName": "Consumed energy heating",
|
||||
"displayNameEvent": "Consumed energy heating changed",
|
||||
"unit": "KiloWattHour",
|
||||
"type": "uint",
|
||||
"defaultValue": 0,
|
||||
"suggestLogging": true
|
||||
},
|
||||
{
|
||||
"id": "932cc41e-53ae-48ae-baa2-6f385f5aa791",
|
||||
"name": "operatingMode",
|
||||
"displayName": "Operating mode",
|
||||
"displayNameEvent": "Operating mode changed",
|
||||
"displayNameAction": "Set operating mode",
|
||||
"type": "QString",
|
||||
"possibleValues": [
|
||||
"Emergency",
|
||||
"Standby",
|
||||
"Program",
|
||||
"Comfort",
|
||||
"Eco",
|
||||
"Hot water"
|
||||
],
|
||||
"writable": false,
|
||||
"defaultValue": "Standby",
|
||||
"suggestLogging": true
|
||||
},
|
||||
{
|
||||
"id": "0ad36f3e-96ff-49d0-8b12-b8c6fed1bf4b",
|
||||
"name": "pumpOne",
|
||||
"displayName": "Pump 1",
|
||||
"displayNameEvent": "Pump 1 status changed",
|
||||
"type": "bool",
|
||||
"defaultValue": false,
|
||||
"suggestLogging": true
|
||||
},
|
||||
{
|
||||
"id": "1c211fb2-da78-41ad-b7d0-e404141a3dd5",
|
||||
"name": "pumpTwo",
|
||||
"displayName": "Pump 2",
|
||||
"displayNameEvent": "Pump 2 status changed",
|
||||
"type": "bool",
|
||||
"defaultValue": false,
|
||||
"suggestLogging": true
|
||||
},
|
||||
{
|
||||
"id": "ad0b8df8-1eaa-409d-b5e2-a76d7c17c2b9",
|
||||
"name": "heatingUp",
|
||||
"displayName": "Heating up",
|
||||
"displayNameEvent": "Heating up status changed",
|
||||
"type": "bool",
|
||||
"defaultValue": false,
|
||||
"suggestLogging": true
|
||||
},
|
||||
{
|
||||
"id": "44d5f18b-0389-4a7d-9cb8-f760ce06814e",
|
||||
"name": "auxHeating",
|
||||
"displayName": "Electric auxiliary heating",
|
||||
"displayNameEvent": "Electric auxiliary heating status changed",
|
||||
"type": "bool",
|
||||
"defaultValue": false,
|
||||
"suggestLogging": true
|
||||
},
|
||||
{
|
||||
"id": "3e44e580-f515-47ae-984b-109b507a5db2",
|
||||
"name": "heating",
|
||||
"displayName": "Heating mode",
|
||||
"displayNameEvent": "Heating mode status changed",
|
||||
"type": "bool",
|
||||
"defaultValue": false,
|
||||
"suggestLogging": true
|
||||
},
|
||||
{
|
||||
"id": "b6338cdb-863e-4191-adc4-bc6da5a67351",
|
||||
"name": "hotWater",
|
||||
"displayName": "Hot water mode",
|
||||
"displayNameEvent": "Hot water mode status changed",
|
||||
"type": "bool",
|
||||
"defaultValue": false,
|
||||
"suggestLogging": true
|
||||
},
|
||||
{
|
||||
"id": "c957cef8-b3a7-4626-ab95-db5439fbdf7f",
|
||||
"name": "compressor",
|
||||
"displayName": "Compressor",
|
||||
"displayNameEvent": "Compressor status changed",
|
||||
"type": "bool",
|
||||
"defaultValue": false,
|
||||
"suggestLogging": true
|
||||
},
|
||||
{
|
||||
"id": "7a287cfb-9088-4aad-a991-3e43714dc64e",
|
||||
"name": "summerMode",
|
||||
"displayName": "Summer mode",
|
||||
"displayNameEvent": "Sommer mode status changed",
|
||||
"type": "bool",
|
||||
"defaultValue": false,
|
||||
"suggestLogging": true
|
||||
},
|
||||
{
|
||||
"id": "1bfd99ee-1477-4f70-8717-a3a2930b137f",
|
||||
"name": "coolingMode",
|
||||
"displayName": "Cooling mode",
|
||||
"displayNameEvent": "Cooling mode status changed",
|
||||
"type": "bool",
|
||||
"defaultValue": false,
|
||||
"suggestLogging": true
|
||||
},
|
||||
{
|
||||
"id": "5c47d9bb-66de-48aa-b90e-caa3ca8d44a5",
|
||||
"name": "defrosting",
|
||||
"displayName": "Defrosting mode",
|
||||
"displayNameEvent": "Defrosting mode status changed",
|
||||
"type": "bool",
|
||||
"defaultValue": false,
|
||||
"suggestLogging": true
|
||||
},
|
||||
{
|
||||
"id": "047fcb7d-9080-4b45-9a6e-5060fa43f7c2",
|
||||
"name": "silentMode",
|
||||
"displayName": "Silent mode",
|
||||
"displayNameEvent": "Silent mode status changed",
|
||||
"type": "bool",
|
||||
"defaultValue": false,
|
||||
"suggestLogging": true
|
||||
},
|
||||
{
|
||||
"id": "d77a30d9-98f7-40ec-bc55-77c547f24145",
|
||||
"name": "silentMode2",
|
||||
"displayName": "Silent mode 2 (Off)",
|
||||
"displayNameEvent": "Silent mode 2 status changed",
|
||||
"type": "bool",
|
||||
"defaultValue": false,
|
||||
"suggestLogging": true
|
||||
},
|
||||
{
|
||||
"id": "798458bb-d38e-4028-880a-6dcba409a2f5",
|
||||
"name": "sgReadyActive",
|
||||
"displayName": "SG Ready enabled",
|
||||
"displayNameEvent": "SG Ready activation changed",
|
||||
"displayNameAction": "Switch SG Ready on/off",
|
||||
"type": "bool",
|
||||
"writable": true,
|
||||
"defaultValue": false,
|
||||
"suggestLogging": true
|
||||
},
|
||||
{
|
||||
"id": "7d474fb5-aa37-4f21-8166-b20f5bf84fb4",
|
||||
"name": "sgReadyMode",
|
||||
"displayName": "SG Ready mode",
|
||||
"displayNameEvent": "SG Ready mode changed",
|
||||
"displayNameAction": "Set SG Ready mode",
|
||||
"type": "QString",
|
||||
"possibleValues": [
|
||||
"Off",
|
||||
"Low",
|
||||
"Standard",
|
||||
"High"
|
||||
],
|
||||
"writable": true,
|
||||
"defaultValue": "Standard",
|
||||
"suggestLogging": true
|
||||
},
|
||||
{
|
||||
"id": "5833ceb6-5e7c-437b-a44a-e9f5eb42b6ac",
|
||||
"name": "sourceTemperature",
|
||||
"displayName": "Source temperature (tbd)",
|
||||
"displayNameEvent": "Source temperature changed",
|
||||
"unit": "DegreeCelsius",
|
||||
"type": "double",
|
||||
"defaultValue": 0,
|
||||
"suggestLogging": true
|
||||
},
|
||||
{
|
||||
"id": "d1959819-9e56-47f7-b619-a393ce50738a",
|
||||
"name": "roomTemperature1",
|
||||
"displayName": "Room temperature (tbd)",
|
||||
"displayNameEvent": "Room temperature changed",
|
||||
"unit": "DegreeCelsius",
|
||||
"type": "double",
|
||||
"defaultValue": 0,
|
||||
"suggestLogging": true
|
||||
}
|
||||
],
|
||||
"actionTypes": [ ]
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
14
stiebeleltron/meta.json
Normal file
14
stiebeleltron/meta.json
Normal file
@ -0,0 +1,14 @@
|
||||
{
|
||||
"title": "Stiebel Eltron",
|
||||
"tagline": "Integrate Stiebel Eltron heat pumps into nymea.",
|
||||
"icon": "stiebel-eltron.png",
|
||||
"stability": "community",
|
||||
"offline": true,
|
||||
"technologies": [
|
||||
"network",
|
||||
"modbus"
|
||||
],
|
||||
"categories": [
|
||||
"heating"
|
||||
]
|
||||
}
|
||||
325
stiebeleltron/stiebel-eltron-registers.json
Normal file
325
stiebeleltron/stiebel-eltron-registers.json
Normal file
@ -0,0 +1,325 @@
|
||||
{
|
||||
"className": "StiebelEltron",
|
||||
"protocol": "TCP",
|
||||
"endianness": "BigEndian",
|
||||
"enums": [
|
||||
{
|
||||
"name": "OperatingMode",
|
||||
"values": [
|
||||
{
|
||||
"key": "Emergency",
|
||||
"value": 0
|
||||
},
|
||||
{
|
||||
"key": "Standby",
|
||||
"value": 1
|
||||
},
|
||||
{
|
||||
"key": "Program",
|
||||
"value": 2
|
||||
},
|
||||
{
|
||||
"key": "Comfort",
|
||||
"value": 3
|
||||
},
|
||||
{
|
||||
"key": "Eco",
|
||||
"value": 4
|
||||
},
|
||||
{
|
||||
"key": "HotWater",
|
||||
"value": 5
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"name": "SmartGridState",
|
||||
"values": [
|
||||
{
|
||||
"key": "ModeOne",
|
||||
"value": 1,
|
||||
"comment": "0x00000001"
|
||||
},
|
||||
{
|
||||
"key": "ModeTwo",
|
||||
"value": 0,
|
||||
"comment": "0x00000000"
|
||||
},
|
||||
{
|
||||
"key": "ModeThree",
|
||||
"value": 65536,
|
||||
"comment": "0x00010000"
|
||||
},
|
||||
{
|
||||
"key": "ModeFour",
|
||||
"value": 65537,
|
||||
"comment": "0x00010001"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"registers": [
|
||||
{
|
||||
"id": "outdoorTemperature",
|
||||
"address": 506,
|
||||
"size": 1,
|
||||
"type": "int16",
|
||||
"registerType": "inputRegister",
|
||||
"readSchedule": "update",
|
||||
"description": "Outdoor temperature",
|
||||
"staticScaleFactor": -1,
|
||||
"defaultValue": 0,
|
||||
"unit": "°C",
|
||||
"access": "RO"
|
||||
},
|
||||
{
|
||||
"id": "flowTemperature",
|
||||
"address": 514,
|
||||
"size": 1,
|
||||
"type": "int16",
|
||||
"registerType": "inputRegister",
|
||||
"readSchedule": "update",
|
||||
"description": "Flow temperature",
|
||||
"staticScaleFactor": -1,
|
||||
"defaultValue": 0,
|
||||
"unit": "°C",
|
||||
"access": "RO"
|
||||
},
|
||||
{
|
||||
"id": "hotWaterTemperature",
|
||||
"address": 521,
|
||||
"size": 1,
|
||||
"type": "uint16",
|
||||
"registerType": "inputRegister",
|
||||
"readSchedule": "update",
|
||||
"description": "Hot water temperature",
|
||||
"staticScaleFactor": -1,
|
||||
"defaultValue": "0",
|
||||
"unit": "°C",
|
||||
"access": "RO"
|
||||
},
|
||||
{
|
||||
"id": "hotGasTemperature1",
|
||||
"address": 543,
|
||||
"size": 1,
|
||||
"type": "uint16",
|
||||
"registerType": "inputRegister",
|
||||
"readSchedule": "update",
|
||||
"description": "Hot gas temperature HP 1",
|
||||
"staticScaleFactor": -1,
|
||||
"defaultValue": "0",
|
||||
"unit": "°C",
|
||||
"access": "RO"
|
||||
},
|
||||
{
|
||||
"id": "hotGasTemperature2",
|
||||
"address": 550,
|
||||
"size": 1,
|
||||
"type": "uint16",
|
||||
"registerType": "inputRegister",
|
||||
"readSchedule": "update",
|
||||
"description": "Hot gas temperature HP 2",
|
||||
"staticScaleFactor": -1,
|
||||
"defaultValue": "0",
|
||||
"unit": "°C",
|
||||
"access": "RO"
|
||||
},
|
||||
{
|
||||
"id": "SourceTemperature",
|
||||
"address": 562,
|
||||
"size": 1,
|
||||
"type": "uint16",
|
||||
"registerType": "inputRegister",
|
||||
"readSchedule": "update",
|
||||
"description": "Source temperature",
|
||||
"staticScaleFactor": -1,
|
||||
"defaultValue": "0",
|
||||
"unit": "°C",
|
||||
"access": "RO"
|
||||
},
|
||||
{
|
||||
"id": "roomTemperatureFEK",
|
||||
"address": 502,
|
||||
"size": 1,
|
||||
"type": "uint16",
|
||||
"registerType": "inputRegister",
|
||||
"readSchedule": "update",
|
||||
"description": "Room temperature FEK",
|
||||
"staticScaleFactor": -1,
|
||||
"defaultValue": "0",
|
||||
"unit": "°C",
|
||||
"access": "RO"
|
||||
},
|
||||
{
|
||||
"id": "returnTemperature",
|
||||
"address": 515,
|
||||
"size": 1,
|
||||
"type": "int16",
|
||||
"registerType": "inputRegister",
|
||||
"readSchedule": "update",
|
||||
"description": "Return temperature",
|
||||
"staticScaleFactor": -1,
|
||||
"defaultValue": 0,
|
||||
"unit": "°C",
|
||||
"access": "RO"
|
||||
},
|
||||
{
|
||||
"id": "solarCollectorTemperature",
|
||||
"address": 527,
|
||||
"size": 1,
|
||||
"type": "uint16",
|
||||
"registerType": "inputRegister",
|
||||
"readSchedule": "update",
|
||||
"description": "Solar collector temperature",
|
||||
"staticScaleFactor": -1,
|
||||
"defaultValue": "0",
|
||||
"unit": "°C",
|
||||
"access": "RO"
|
||||
},
|
||||
{
|
||||
"id": "solarStorageTankTemperature",
|
||||
"address": 528,
|
||||
"size": 1,
|
||||
"type": "uint16",
|
||||
"registerType": "inputRegister",
|
||||
"readSchedule": "update",
|
||||
"description": "Solar storage tank temperature",
|
||||
"staticScaleFactor": -1,
|
||||
"defaultValue": "0",
|
||||
"unit": "°C",
|
||||
"access": "RO"
|
||||
},
|
||||
{
|
||||
"id": "storageTankTemperature",
|
||||
"address": 517,
|
||||
"size": 1,
|
||||
"type": "uint16",
|
||||
"registerType": "inputRegister",
|
||||
"readSchedule": "update",
|
||||
"description": "Storage tank temperature",
|
||||
"staticScaleFactor": -1,
|
||||
"defaultValue": "0",
|
||||
"unit": "°C",
|
||||
"access": "RO"
|
||||
},
|
||||
{
|
||||
"id": "externalHeatSourceTemperature",
|
||||
"address": 530,
|
||||
"size": 1,
|
||||
"type": "uint16",
|
||||
"registerType": "inputRegister",
|
||||
"readSchedule": "update",
|
||||
"description": "External heat source temperature",
|
||||
"staticScaleFactor": -1,
|
||||
"defaultValue": "0",
|
||||
"unit": "°C",
|
||||
"access": "RO"
|
||||
},
|
||||
{
|
||||
"id": "heatingEnergy",
|
||||
"address": 3501,
|
||||
"size": 2,
|
||||
"type": "uint32",
|
||||
"registerType": "inputRegister",
|
||||
"readSchedule": "update",
|
||||
"defaultValue": "0",
|
||||
"unit": "kWh",
|
||||
"description": "Heating energy",
|
||||
"access": "RO"
|
||||
},
|
||||
{
|
||||
"id": "hotWaterEnergy",
|
||||
"address": 3504,
|
||||
"size": 2,
|
||||
"type": "uint32",
|
||||
"registerType": "inputRegister",
|
||||
"readSchedule": "update",
|
||||
"defaultValue": "0",
|
||||
"unit": "kWh",
|
||||
"description": "Hot water energy",
|
||||
"access": "RO"
|
||||
},
|
||||
{
|
||||
"id": "consumedEnergyHeating",
|
||||
"address": 3511,
|
||||
"size": 2,
|
||||
"type": "uint32",
|
||||
"registerType": "inputRegister",
|
||||
"readSchedule": "update",
|
||||
"defaultValue": "0",
|
||||
"unit": "kWh",
|
||||
"description": "Consumed energy heating",
|
||||
"access": "RO"
|
||||
},
|
||||
{
|
||||
"id": "consumedEnergyHotWater",
|
||||
"address": 3514,
|
||||
"size": 2,
|
||||
"type": "uint32",
|
||||
"registerType": "inputRegister",
|
||||
"readSchedule": "update",
|
||||
"defaultValue": "0",
|
||||
"unit": "kWh",
|
||||
"description": "Consumed energy hot water",
|
||||
"access": "RO"
|
||||
},
|
||||
{
|
||||
"id": "operatingMode",
|
||||
"address": 1500,
|
||||
"size": 1,
|
||||
"type": "uint16",
|
||||
"enum": "OperatingMode",
|
||||
"registerType": "holdingRegister",
|
||||
"readSchedule": "update",
|
||||
"description": "Operating mode",
|
||||
"defaultValue": "OperatingModeStandby",
|
||||
"access": "RO"
|
||||
},
|
||||
{
|
||||
"id": "systemStatus",
|
||||
"address": 2500,
|
||||
"size": 1,
|
||||
"type": "uint16",
|
||||
"registerType": "inputRegister",
|
||||
"readSchedule": "update",
|
||||
"description": "System status",
|
||||
"defaultValue": 0,
|
||||
"access": "RO"
|
||||
},
|
||||
{
|
||||
"id": "sgReadyStateRO",
|
||||
"address": 5000,
|
||||
"size": 1,
|
||||
"type": "uint16",
|
||||
"registerType": "inputRegister",
|
||||
"readSchedule": "update",
|
||||
"description": "Smart grid status",
|
||||
"defaultValue": 3,
|
||||
"access": "RO"
|
||||
},
|
||||
{
|
||||
"id": "sgReadyActive",
|
||||
"address": 4000,
|
||||
"size": 1,
|
||||
"type": "uint16",
|
||||
"registerType": "holdingRegister",
|
||||
"readSchedule": "update",
|
||||
"description": "SG ready active",
|
||||
"defaultValue": 0,
|
||||
"access": "RW"
|
||||
},
|
||||
{
|
||||
"id": "sgReadyState",
|
||||
"address": 4001,
|
||||
"size": 2,
|
||||
"type": "uint32",
|
||||
"registerType": "holdingRegister",
|
||||
"enum": "SmartGridState",
|
||||
"readSchedule": "update",
|
||||
"description": "SG Ready mode",
|
||||
"defaultValue": "SmartGridStateModeThree",
|
||||
"access": "RW"
|
||||
}
|
||||
],
|
||||
"blocks": [ ]
|
||||
}
|
||||
BIN
stiebeleltron/stiebel-eltron.png
Normal file
BIN
stiebeleltron/stiebel-eltron.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.0 KiB |
13
stiebeleltron/stiebeleltron.pro
Normal file
13
stiebeleltron/stiebeleltron.pro
Normal file
@ -0,0 +1,13 @@
|
||||
include(../plugins.pri)
|
||||
|
||||
# Generate modbus connection
|
||||
MODBUS_CONNECTIONS += stiebel-eltron-registers.json
|
||||
#MODBUS_TOOLS_CONFIG += VERBOSE
|
||||
include(../modbus.pri)
|
||||
|
||||
HEADERS += \
|
||||
integrationpluginstiebeleltron.h
|
||||
|
||||
SOURCES += \
|
||||
integrationpluginstiebeleltron.cpp
|
||||
|
||||
@ -0,0 +1,477 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE TS>
|
||||
<TS version="2.1">
|
||||
<context>
|
||||
<name>IntegrationPluginStiebelEltron</name>
|
||||
<message>
|
||||
<location filename="../integrationpluginstiebeleltron.cpp" line="43"/>
|
||||
<source>The network device discovery is not available.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>StiebelEltron</name>
|
||||
<message>
|
||||
<location filename="../plugininfo.h" line="117"/>
|
||||
<location filename="../plugininfo.h" line="120"/>
|
||||
<source>Compressor</source>
|
||||
<extracomment>The name of the ParamType (ThingClass: stiebelEltron, EventType: compressor, ID: {c957cef8-b3a7-4626-ab95-db5439fbdf7f})
|
||||
----------
|
||||
The name of the StateType ({c957cef8-b3a7-4626-ab95-db5439fbdf7f}) of ThingClass stiebelEltron</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../plugininfo.h" line="123"/>
|
||||
<source>Compressor status changed</source>
|
||||
<extracomment>The name of the EventType ({c957cef8-b3a7-4626-ab95-db5439fbdf7f}) of ThingClass stiebelEltron</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../plugininfo.h" line="126"/>
|
||||
<location filename="../plugininfo.h" line="129"/>
|
||||
<source>Connected</source>
|
||||
<extracomment>The name of the ParamType (ThingClass: stiebelEltron, EventType: connected, ID: {8d952a5e-87bd-492e-a213-277948521652})
|
||||
----------
|
||||
The name of the StateType ({8d952a5e-87bd-492e-a213-277948521652}) of ThingClass stiebelEltron</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../plugininfo.h" line="132"/>
|
||||
<source>Connected changed</source>
|
||||
<extracomment>The name of the EventType ({8d952a5e-87bd-492e-a213-277948521652}) of ThingClass stiebelEltron</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../plugininfo.h" line="135"/>
|
||||
<location filename="../plugininfo.h" line="138"/>
|
||||
<source>Consumed energy heating</source>
|
||||
<extracomment>The name of the ParamType (ThingClass: stiebelEltron, EventType: consumedEnergyHeating, ID: {6816dfef-3f54-4bf1-b0d5-641f06785991})
|
||||
----------
|
||||
The name of the StateType ({6816dfef-3f54-4bf1-b0d5-641f06785991}) of ThingClass stiebelEltron</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../plugininfo.h" line="141"/>
|
||||
<source>Consumed energy heating changed</source>
|
||||
<extracomment>The name of the EventType ({6816dfef-3f54-4bf1-b0d5-641f06785991}) of ThingClass stiebelEltron</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../plugininfo.h" line="144"/>
|
||||
<location filename="../plugininfo.h" line="147"/>
|
||||
<source>Consumed energy hot water</source>
|
||||
<extracomment>The name of the ParamType (ThingClass: stiebelEltron, EventType: consumedEnergyHotWater, ID: {11f91606-d550-4918-9fca-69e3303389c8})
|
||||
----------
|
||||
The name of the StateType ({11f91606-d550-4918-9fca-69e3303389c8}) of ThingClass stiebelEltron</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../plugininfo.h" line="150"/>
|
||||
<source>Consumed energy hot water changed</source>
|
||||
<extracomment>The name of the EventType ({11f91606-d550-4918-9fca-69e3303389c8}) of ThingClass stiebelEltron</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../plugininfo.h" line="153"/>
|
||||
<location filename="../plugininfo.h" line="156"/>
|
||||
<source>Cooling mode</source>
|
||||
<extracomment>The name of the ParamType (ThingClass: stiebelEltron, EventType: coolingMode, ID: {1bfd99ee-1477-4f70-8717-a3a2930b137f})
|
||||
----------
|
||||
The name of the StateType ({1bfd99ee-1477-4f70-8717-a3a2930b137f}) of ThingClass stiebelEltron</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../plugininfo.h" line="159"/>
|
||||
<source>Cooling mode status changed</source>
|
||||
<extracomment>The name of the EventType ({1bfd99ee-1477-4f70-8717-a3a2930b137f}) of ThingClass stiebelEltron</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../plugininfo.h" line="162"/>
|
||||
<location filename="../plugininfo.h" line="165"/>
|
||||
<source>Defrosting mode</source>
|
||||
<extracomment>The name of the ParamType (ThingClass: stiebelEltron, EventType: defrosting, ID: {5c47d9bb-66de-48aa-b90e-caa3ca8d44a5})
|
||||
----------
|
||||
The name of the StateType ({5c47d9bb-66de-48aa-b90e-caa3ca8d44a5}) of ThingClass stiebelEltron</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../plugininfo.h" line="168"/>
|
||||
<source>Defrosting mode status changed</source>
|
||||
<extracomment>The name of the EventType ({5c47d9bb-66de-48aa-b90e-caa3ca8d44a5}) of ThingClass stiebelEltron</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../plugininfo.h" line="171"/>
|
||||
<location filename="../plugininfo.h" line="174"/>
|
||||
<source>Electric auxiliary heating</source>
|
||||
<extracomment>The name of the ParamType (ThingClass: stiebelEltron, EventType: auxHeating, ID: {44d5f18b-0389-4a7d-9cb8-f760ce06814e})
|
||||
----------
|
||||
The name of the StateType ({44d5f18b-0389-4a7d-9cb8-f760ce06814e}) of ThingClass stiebelEltron</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../plugininfo.h" line="177"/>
|
||||
<source>Electric auxiliary heating status changed</source>
|
||||
<extracomment>The name of the EventType ({44d5f18b-0389-4a7d-9cb8-f760ce06814e}) of ThingClass stiebelEltron</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../plugininfo.h" line="180"/>
|
||||
<location filename="../plugininfo.h" line="183"/>
|
||||
<source>Flow temperature</source>
|
||||
<extracomment>The name of the ParamType (ThingClass: stiebelEltron, EventType: flowTemperature, ID: {1ec958c8-7bf1-469e-b35e-b71fa2099e91})
|
||||
----------
|
||||
The name of the StateType ({1ec958c8-7bf1-469e-b35e-b71fa2099e91}) of ThingClass stiebelEltron</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../plugininfo.h" line="186"/>
|
||||
<source>Flow temperature changed</source>
|
||||
<extracomment>The name of the EventType ({1ec958c8-7bf1-469e-b35e-b71fa2099e91}) of ThingClass stiebelEltron</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../plugininfo.h" line="189"/>
|
||||
<location filename="../plugininfo.h" line="192"/>
|
||||
<source>Heating energy</source>
|
||||
<extracomment>The name of the ParamType (ThingClass: stiebelEltron, EventType: heatingEnergy, ID: {d0597f21-2c0e-4db6-92e0-4a3b66474f87})
|
||||
----------
|
||||
The name of the StateType ({d0597f21-2c0e-4db6-92e0-4a3b66474f87}) of ThingClass stiebelEltron</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../plugininfo.h" line="195"/>
|
||||
<source>Heating energy changed</source>
|
||||
<extracomment>The name of the EventType ({d0597f21-2c0e-4db6-92e0-4a3b66474f87}) of ThingClass stiebelEltron</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../plugininfo.h" line="198"/>
|
||||
<location filename="../plugininfo.h" line="201"/>
|
||||
<source>Heating mode</source>
|
||||
<extracomment>The name of the ParamType (ThingClass: stiebelEltron, EventType: heating, ID: {3e44e580-f515-47ae-984b-109b507a5db2})
|
||||
----------
|
||||
The name of the StateType ({3e44e580-f515-47ae-984b-109b507a5db2}) of ThingClass stiebelEltron</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../plugininfo.h" line="204"/>
|
||||
<source>Heating mode status changed</source>
|
||||
<extracomment>The name of the EventType ({3e44e580-f515-47ae-984b-109b507a5db2}) of ThingClass stiebelEltron</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../plugininfo.h" line="207"/>
|
||||
<location filename="../plugininfo.h" line="210"/>
|
||||
<source>Heating up</source>
|
||||
<extracomment>The name of the ParamType (ThingClass: stiebelEltron, EventType: heatingUp, ID: {ad0b8df8-1eaa-409d-b5e2-a76d7c17c2b9})
|
||||
----------
|
||||
The name of the StateType ({ad0b8df8-1eaa-409d-b5e2-a76d7c17c2b9}) of ThingClass stiebelEltron</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../plugininfo.h" line="213"/>
|
||||
<source>Heating up status changed</source>
|
||||
<extracomment>The name of the EventType ({ad0b8df8-1eaa-409d-b5e2-a76d7c17c2b9}) of ThingClass stiebelEltron</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../plugininfo.h" line="216"/>
|
||||
<source>Hot water changed</source>
|
||||
<extracomment>The name of the EventType ({27c56897-75f1-45af-9a14-b0620053d2d2}) of ThingClass stiebelEltron</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../plugininfo.h" line="219"/>
|
||||
<location filename="../plugininfo.h" line="222"/>
|
||||
<source>Hot water energy</source>
|
||||
<extracomment>The name of the ParamType (ThingClass: stiebelEltron, EventType: hotWaterEnergy, ID: {9761060e-f364-466e-8661-d28f01b862fc})
|
||||
----------
|
||||
The name of the StateType ({9761060e-f364-466e-8661-d28f01b862fc}) of ThingClass stiebelEltron</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../plugininfo.h" line="225"/>
|
||||
<source>Hot water energy changed</source>
|
||||
<extracomment>The name of the EventType ({9761060e-f364-466e-8661-d28f01b862fc}) of ThingClass stiebelEltron</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../plugininfo.h" line="228"/>
|
||||
<location filename="../plugininfo.h" line="231"/>
|
||||
<source>Hot water mode</source>
|
||||
<extracomment>The name of the ParamType (ThingClass: stiebelEltron, EventType: hotWater, ID: {b6338cdb-863e-4191-adc4-bc6da5a67351})
|
||||
----------
|
||||
The name of the StateType ({b6338cdb-863e-4191-adc4-bc6da5a67351}) of ThingClass stiebelEltron</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../plugininfo.h" line="234"/>
|
||||
<source>Hot water mode status changed</source>
|
||||
<extracomment>The name of the EventType ({b6338cdb-863e-4191-adc4-bc6da5a67351}) of ThingClass stiebelEltron</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../plugininfo.h" line="237"/>
|
||||
<location filename="../plugininfo.h" line="240"/>
|
||||
<source>Hot water temperature</source>
|
||||
<extracomment>The name of the ParamType (ThingClass: stiebelEltron, EventType: hotWaterTemperature, ID: {27c56897-75f1-45af-9a14-b0620053d2d2})
|
||||
----------
|
||||
The name of the StateType ({27c56897-75f1-45af-9a14-b0620053d2d2}) of ThingClass stiebelEltron</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../plugininfo.h" line="243"/>
|
||||
<source>IP address</source>
|
||||
<extracomment>The name of the ParamType (ThingClass: stiebelEltron, Type: thing, ID: {47d221fa-f6d2-400e-b80f-bb90abccb72c})</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../plugininfo.h" line="246"/>
|
||||
<source>MAC address</source>
|
||||
<extracomment>The name of the ParamType (ThingClass: stiebelEltron, Type: thing, ID: {05cd59b8-3068-460f-b0d2-6d49f27458df})</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../plugininfo.h" line="249"/>
|
||||
<source>Modbus slave ID</source>
|
||||
<extracomment>The name of the ParamType (ThingClass: stiebelEltron, Type: thing, ID: {732de6da-bd0a-4215-b320-602117ebc75c})</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../plugininfo.h" line="252"/>
|
||||
<location filename="../plugininfo.h" line="255"/>
|
||||
<source>Operating mode</source>
|
||||
<extracomment>The name of the ParamType (ThingClass: stiebelEltron, EventType: operatingMode, ID: {932cc41e-53ae-48ae-baa2-6f385f5aa791})
|
||||
----------
|
||||
The name of the StateType ({932cc41e-53ae-48ae-baa2-6f385f5aa791}) of ThingClass stiebelEltron</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../plugininfo.h" line="258"/>
|
||||
<source>Operating mode changed</source>
|
||||
<extracomment>The name of the EventType ({932cc41e-53ae-48ae-baa2-6f385f5aa791}) of ThingClass stiebelEltron</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../plugininfo.h" line="261"/>
|
||||
<location filename="../plugininfo.h" line="264"/>
|
||||
<source>Outdoor temperature</source>
|
||||
<extracomment>The name of the ParamType (ThingClass: stiebelEltron, EventType: outdoorTemperature, ID: {e86cbac5-c2c3-4fcf-8caa-dbfc0df2584d})
|
||||
----------
|
||||
The name of the StateType ({e86cbac5-c2c3-4fcf-8caa-dbfc0df2584d}) of ThingClass stiebelEltron</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../plugininfo.h" line="267"/>
|
||||
<source>Outdoor temperature changed</source>
|
||||
<extracomment>The name of the EventType ({e86cbac5-c2c3-4fcf-8caa-dbfc0df2584d}) of ThingClass stiebelEltron</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../plugininfo.h" line="270"/>
|
||||
<source>Port</source>
|
||||
<extracomment>The name of the ParamType (ThingClass: stiebelEltron, Type: thing, ID: {6842321f-1f1a-47e2-b12d-59ee322eb8a6})</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../plugininfo.h" line="273"/>
|
||||
<location filename="../plugininfo.h" line="276"/>
|
||||
<source>Pump 1</source>
|
||||
<extracomment>The name of the ParamType (ThingClass: stiebelEltron, EventType: pumpOne, ID: {0ad36f3e-96ff-49d0-8b12-b8c6fed1bf4b})
|
||||
----------
|
||||
The name of the StateType ({0ad36f3e-96ff-49d0-8b12-b8c6fed1bf4b}) of ThingClass stiebelEltron</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../plugininfo.h" line="279"/>
|
||||
<source>Pump 1 status changed</source>
|
||||
<extracomment>The name of the EventType ({0ad36f3e-96ff-49d0-8b12-b8c6fed1bf4b}) of ThingClass stiebelEltron</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../plugininfo.h" line="282"/>
|
||||
<location filename="../plugininfo.h" line="285"/>
|
||||
<source>Pump 2</source>
|
||||
<extracomment>The name of the ParamType (ThingClass: stiebelEltron, EventType: pumpTwo, ID: {1c211fb2-da78-41ad-b7d0-e404141a3dd5})
|
||||
----------
|
||||
The name of the StateType ({1c211fb2-da78-41ad-b7d0-e404141a3dd5}) of ThingClass stiebelEltron</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../plugininfo.h" line="288"/>
|
||||
<source>Pump 2 status changed</source>
|
||||
<extracomment>The name of the EventType ({1c211fb2-da78-41ad-b7d0-e404141a3dd5}) of ThingClass stiebelEltron</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../plugininfo.h" line="291"/>
|
||||
<location filename="../plugininfo.h" line="294"/>
|
||||
<source>Return temperature</source>
|
||||
<extracomment>The name of the ParamType (ThingClass: stiebelEltron, EventType: returnTemperature, ID: {ce25e3fd-6544-40e9-bd39-032306553e32})
|
||||
----------
|
||||
The name of the StateType ({ce25e3fd-6544-40e9-bd39-032306553e32}) of ThingClass stiebelEltron</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../plugininfo.h" line="297"/>
|
||||
<source>Return temperature changed</source>
|
||||
<extracomment>The name of the EventType ({ce25e3fd-6544-40e9-bd39-032306553e32}) of ThingClass stiebelEltron</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../plugininfo.h" line="300"/>
|
||||
<location filename="../plugininfo.h" line="303"/>
|
||||
<source>Room temperature (tbd)</source>
|
||||
<extracomment>The name of the ParamType (ThingClass: stiebelEltron, EventType: roomTemperature1, ID: {d1959819-9e56-47f7-b619-a393ce50738a})
|
||||
----------
|
||||
The name of the StateType ({d1959819-9e56-47f7-b619-a393ce50738a}) of ThingClass stiebelEltron</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../plugininfo.h" line="306"/>
|
||||
<source>Room temperature changed</source>
|
||||
<extracomment>The name of the EventType ({d1959819-9e56-47f7-b619-a393ce50738a}) of ThingClass stiebelEltron</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../plugininfo.h" line="309"/>
|
||||
<source>SG Ready activation changed</source>
|
||||
<extracomment>The name of the EventType ({798458bb-d38e-4028-880a-6dcba409a2f5}) of ThingClass stiebelEltron</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../plugininfo.h" line="312"/>
|
||||
<location filename="../plugininfo.h" line="315"/>
|
||||
<location filename="../plugininfo.h" line="318"/>
|
||||
<source>SG Ready enabled</source>
|
||||
<extracomment>The name of the ParamType (ThingClass: stiebelEltron, ActionType: sgReadyActive, ID: {798458bb-d38e-4028-880a-6dcba409a2f5})
|
||||
----------
|
||||
The name of the ParamType (ThingClass: stiebelEltron, EventType: sgReadyActive, ID: {798458bb-d38e-4028-880a-6dcba409a2f5})
|
||||
----------
|
||||
The name of the StateType ({798458bb-d38e-4028-880a-6dcba409a2f5}) of ThingClass stiebelEltron</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../plugininfo.h" line="321"/>
|
||||
<location filename="../plugininfo.h" line="324"/>
|
||||
<location filename="../plugininfo.h" line="327"/>
|
||||
<source>SG Ready mode</source>
|
||||
<extracomment>The name of the ParamType (ThingClass: stiebelEltron, ActionType: sgReadyMode, ID: {7d474fb5-aa37-4f21-8166-b20f5bf84fb4})
|
||||
----------
|
||||
The name of the ParamType (ThingClass: stiebelEltron, EventType: sgReadyMode, ID: {7d474fb5-aa37-4f21-8166-b20f5bf84fb4})
|
||||
----------
|
||||
The name of the StateType ({7d474fb5-aa37-4f21-8166-b20f5bf84fb4}) of ThingClass stiebelEltron</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../plugininfo.h" line="330"/>
|
||||
<source>SG Ready mode changed</source>
|
||||
<extracomment>The name of the EventType ({7d474fb5-aa37-4f21-8166-b20f5bf84fb4}) of ThingClass stiebelEltron</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../plugininfo.h" line="333"/>
|
||||
<source>Set SG Ready mode</source>
|
||||
<extracomment>The name of the ActionType ({7d474fb5-aa37-4f21-8166-b20f5bf84fb4}) of ThingClass stiebelEltron</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../plugininfo.h" line="336"/>
|
||||
<location filename="../plugininfo.h" line="339"/>
|
||||
<source>Silent mode</source>
|
||||
<extracomment>The name of the ParamType (ThingClass: stiebelEltron, EventType: silentMode, ID: {047fcb7d-9080-4b45-9a6e-5060fa43f7c2})
|
||||
----------
|
||||
The name of the StateType ({047fcb7d-9080-4b45-9a6e-5060fa43f7c2}) of ThingClass stiebelEltron</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../plugininfo.h" line="342"/>
|
||||
<location filename="../plugininfo.h" line="345"/>
|
||||
<source>Silent mode 2 (Off)</source>
|
||||
<extracomment>The name of the ParamType (ThingClass: stiebelEltron, EventType: silentMode2, ID: {d77a30d9-98f7-40ec-bc55-77c547f24145})
|
||||
----------
|
||||
The name of the StateType ({d77a30d9-98f7-40ec-bc55-77c547f24145}) of ThingClass stiebelEltron</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../plugininfo.h" line="348"/>
|
||||
<source>Silent mode 2 status changed</source>
|
||||
<extracomment>The name of the EventType ({d77a30d9-98f7-40ec-bc55-77c547f24145}) of ThingClass stiebelEltron</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../plugininfo.h" line="351"/>
|
||||
<source>Silent mode status changed</source>
|
||||
<extracomment>The name of the EventType ({047fcb7d-9080-4b45-9a6e-5060fa43f7c2}) of ThingClass stiebelEltron</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../plugininfo.h" line="354"/>
|
||||
<source>Sommer mode status changed</source>
|
||||
<extracomment>The name of the EventType ({7a287cfb-9088-4aad-a991-3e43714dc64e}) of ThingClass stiebelEltron</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../plugininfo.h" line="357"/>
|
||||
<location filename="../plugininfo.h" line="360"/>
|
||||
<source>Source temperature (tbd)</source>
|
||||
<extracomment>The name of the ParamType (ThingClass: stiebelEltron, EventType: sourceTemperature, ID: {5833ceb6-5e7c-437b-a44a-e9f5eb42b6ac})
|
||||
----------
|
||||
The name of the StateType ({5833ceb6-5e7c-437b-a44a-e9f5eb42b6ac}) of ThingClass stiebelEltron</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../plugininfo.h" line="363"/>
|
||||
<source>Source temperature changed</source>
|
||||
<extracomment>The name of the EventType ({5833ceb6-5e7c-437b-a44a-e9f5eb42b6ac}) of ThingClass stiebelEltron</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../plugininfo.h" line="366"/>
|
||||
<location filename="../plugininfo.h" line="369"/>
|
||||
<source>Stiebel Eltron</source>
|
||||
<extracomment>The name of the vendor ({c8607f85-a81e-40e0-bc95-1b7199cd2d99})
|
||||
----------
|
||||
The name of the plugin StiebelEltron ({956c848b-b538-4b8f-8cdb-7bbecfc9d361})</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../plugininfo.h" line="372"/>
|
||||
<source>Stiebel Eltron Heatpump</source>
|
||||
<extracomment>The name of the ThingClass ({e02ecf61-7d28-43c2-b87e-e7e98a48fbfd})</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../plugininfo.h" line="375"/>
|
||||
<location filename="../plugininfo.h" line="378"/>
|
||||
<source>Storage tank temperature</source>
|
||||
<extracomment>The name of the ParamType (ThingClass: stiebelEltron, EventType: storageTankTemperature, ID: {43dd25b3-8782-4faa-a9e0-2fb10892fa0c})
|
||||
----------
|
||||
The name of the StateType ({43dd25b3-8782-4faa-a9e0-2fb10892fa0c}) of ThingClass stiebelEltron</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../plugininfo.h" line="381"/>
|
||||
<source>Storage tank temperature changed</source>
|
||||
<extracomment>The name of the EventType ({43dd25b3-8782-4faa-a9e0-2fb10892fa0c}) of ThingClass stiebelEltron</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../plugininfo.h" line="384"/>
|
||||
<location filename="../plugininfo.h" line="387"/>
|
||||
<source>Summer mode</source>
|
||||
<extracomment>The name of the ParamType (ThingClass: stiebelEltron, EventType: summerMode, ID: {7a287cfb-9088-4aad-a991-3e43714dc64e})
|
||||
----------
|
||||
The name of the StateType ({7a287cfb-9088-4aad-a991-3e43714dc64e}) of ThingClass stiebelEltron</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="../plugininfo.h" line="390"/>
|
||||
<source>Switch SG Ready on/off</source>
|
||||
<extracomment>The name of the ActionType ({798458bb-d38e-4028-880a-6dcba409a2f5}) of ThingClass stiebelEltron</extracomment>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
||||
@ -28,9 +28,10 @@
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#include "plugininfo.h"
|
||||
#include "integrationpluginsunspec.h"
|
||||
#include "network/networkdevicediscovery.h"
|
||||
#include "plugininfo.h"
|
||||
|
||||
#include <network/networkdevicediscovery.h>
|
||||
|
||||
#include <sunspecmodel.h>
|
||||
#include <models/sunspecmodelfactory.h>
|
||||
|
||||
@ -31,8 +31,8 @@
|
||||
#ifndef INTEGRATIONPLUGINSUNSPEC_H
|
||||
#define INTEGRATIONPLUGINSUNSPEC_H
|
||||
|
||||
#include "integrations/integrationplugin.h"
|
||||
#include "plugintimer.h"
|
||||
#include <integrations/integrationplugin.h>
|
||||
#include <plugintimer.h>
|
||||
|
||||
#include <sunspecconnection.h>
|
||||
#include <models/sunspecmodelfactory.h>
|
||||
|
||||
@ -34,7 +34,8 @@
|
||||
#include <QObject>
|
||||
|
||||
#include "extern-plugininfo.h"
|
||||
#include "integrations/integrationplugin.h"
|
||||
|
||||
#include <integrations/integrationplugin.h>
|
||||
|
||||
#include <sunspecmodel.h>
|
||||
#include <sunspecconnection.h>
|
||||
|
||||
@ -30,8 +30,9 @@
|
||||
|
||||
#include "integrationpluginwallbe.h"
|
||||
#include "plugininfo.h"
|
||||
#include "network/networkdevicediscovery.h"
|
||||
#include "types/param.h"
|
||||
|
||||
#include <network/networkdevicediscovery.h>
|
||||
#include <types/param.h>
|
||||
|
||||
#include <QDebug>
|
||||
#include <QStringList>
|
||||
|
||||
@ -31,10 +31,10 @@
|
||||
#ifndef INTEGRATIONPLUGINWALLBE_H
|
||||
#define INTEGRATIONPLUGINWALLBE_H
|
||||
|
||||
#include "integrations/integrationplugin.h"
|
||||
#include "plugintimer.h"
|
||||
#include <integrations/integrationplugin.h>
|
||||
#include <plugintimer.h>
|
||||
|
||||
#include "../modbus/modbustcpmaster.h"
|
||||
#include <modbustcpmaster.h>
|
||||
|
||||
#include <QObject>
|
||||
#include <QHostAddress>
|
||||
|
||||
@ -1,13 +1,8 @@
|
||||
include(../plugins.pri)
|
||||
|
||||
QT += \
|
||||
network \
|
||||
serialbus \
|
||||
include(../modbus.pri)
|
||||
|
||||
SOURCES += \
|
||||
integrationpluginwallbe.cpp \
|
||||
../modbus/modbustcpmaster.cpp
|
||||
integrationpluginwallbe.cpp
|
||||
|
||||
HEADERS += \
|
||||
integrationpluginwallbe.h \
|
||||
../modbus/modbustcpmaster.h
|
||||
integrationpluginwallbe.h
|
||||
|
||||
@ -28,11 +28,11 @@
|
||||
*
|
||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||
|
||||
#include "network/networkdevicediscovery.h"
|
||||
#include "integrationpluginwebasto.h"
|
||||
#include "plugininfo.h"
|
||||
|
||||
#include "types/param.h"
|
||||
#include <network/networkdevicediscovery.h>
|
||||
#include <types/param.h>
|
||||
|
||||
#include <QDebug>
|
||||
#include <QStringList>
|
||||
|
||||
@ -31,10 +31,10 @@
|
||||
#ifndef INTEGRATIONPLUGINWEBASTO_H
|
||||
#define INTEGRATIONPLUGINWEBASTO_H
|
||||
|
||||
#include "integrations/integrationplugin.h"
|
||||
#include "plugintimer.h"
|
||||
#include <integrations/integrationplugin.h>
|
||||
#include <plugintimer.h>
|
||||
|
||||
#include "webasto.h"
|
||||
#include "../modbus/modbustcpmaster.h"
|
||||
|
||||
#include <QObject>
|
||||
#include <QHostAddress>
|
||||
|
||||
@ -36,7 +36,7 @@
|
||||
#include <QTimer>
|
||||
#include <QUuid>
|
||||
|
||||
#include "../modbus/modbustcpmaster.h"
|
||||
#include <modbustcpmaster.h>
|
||||
|
||||
class Webasto : public QObject
|
||||
{
|
||||
|
||||
@ -1,13 +1,10 @@
|
||||
include(../plugins.pri)
|
||||
|
||||
QT += serialbus network
|
||||
include(../modbus.pri)
|
||||
|
||||
SOURCES += \
|
||||
integrationpluginwebasto.cpp \
|
||||
webasto.cpp \
|
||||
../modbus/modbustcpmaster.cpp
|
||||
webasto.cpp
|
||||
|
||||
HEADERS += \
|
||||
integrationpluginwebasto.h \
|
||||
webasto.h \
|
||||
../modbus/modbustcpmaster.h
|
||||
webasto.h
|
||||
|
||||
Reference in New Issue
Block a user