Merge PR #38: New plugin: Alpha Innotec heat pumps

pull/48/head
Jenkins nymea 2021-12-13 00:48:08 +01:00
commit eee44a113c
18 changed files with 4525 additions and 0 deletions

23
alphainnotec/README.md Normal file
View File

@ -0,0 +1,23 @@
# alpha innotec
Connect nymea to alpha innotec heat pumps.
In order to use the modbus interface, it is important to enable modbus on the heatpump using the Windows tools from Alpha Innotec.
The instructions for that can be found in the user manual of the heat pump.
Please also make sure all values are configured as readable and writable for modbus, otherwise the heapump can only be monitored, but
not optimized for smart heating.
## Supported Things
* alpha connect
## Requirements
* The package 'nymea-plugin-alphainnotec' must be installed
* Both devices must be in the same local area network.
* Modbus enabled and all values are readable and writable.
## More
https://www.alpha-innotec.de

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,273 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* 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

View File

@ -0,0 +1,401 @@
{
"endianness": "BigEndian",
"enums": [
{
"name": "SystemStatus",
"values": [
{
"key": "HeatingMode",
"value": 0
},
{
"key": "DomesticHotWater",
"value": 1
},
{
"key": "SwimmingPool",
"value": 2
},
{
"key": "EVUOff",
"value": 3
},
{
"key": "Defrost",
"value": 4
},
{
"key": "Off",
"value": 5
},
{
"key": "ExternalEnergySource",
"value": 6
},
{
"key": "CoolingMode",
"value": 7
}
]
},
{
"name": "SmartGridState",
"values": [
{
"key": "Off",
"value": 0
},
{
"key": "Low",
"value": 1
},
{
"key": "Standard",
"value": 2
},
{
"key": "High",
"value": 3
}
]
}
],
"registers": [
{
"id": "flowTemperature",
"address": 1,
"size": 1,
"type": "uint16",
"registerType": "inputRegister",
"readSchedule": "update",
"description": "Flow",
"staticScaleFactor": -1,
"defaultValue": "0",
"unit": "°C",
"access": "RO"
},
{
"id": "returnTemperature",
"address": 2,
"size": 1,
"type": "uint16",
"registerType": "inputRegister",
"readSchedule": "update",
"description": "Return",
"staticScaleFactor": -1,
"defaultValue": "0",
"unit": "°C",
"access": "RO"
},
{
"id": "externalReturnTemperature",
"address": 3,
"size": 1,
"type": "uint16",
"registerType": "inputRegister",
"readSchedule": "update",
"description": "External return",
"staticScaleFactor": -1,
"defaultValue": "0",
"unit": "°C",
"access": "RO"
},
{
"id": "hotWaterTemperature",
"address": 4,
"size": 1,
"type": "uint16",
"registerType": "inputRegister",
"readSchedule": "update",
"description": "Hot water temperature",
"staticScaleFactor": -1,
"defaultValue": "0",
"unit": "°C",
"access": "RO"
},
{
"id": "hotGasTemperature",
"address": 8,
"size": 1,
"type": "uint16",
"registerType": "inputRegister",
"readSchedule": "update",
"description": "Hot gas temperature",
"staticScaleFactor": -1,
"defaultValue": "0",
"unit": "°C",
"access": "RO"
},
{
"id": "heatSourceInletTemperature",
"address": 9,
"size": 1,
"type": "uint16",
"registerType": "inputRegister",
"readSchedule": "update",
"description": "Heat source inlet temperature",
"staticScaleFactor": -1,
"defaultValue": "0",
"unit": "°C",
"access": "RO"
},
{
"id": "heatSourceOutletTemperature",
"address": 10,
"size": 1,
"type": "uint16",
"registerType": "inputRegister",
"readSchedule": "update",
"description": "Heat source outlet temperature",
"staticScaleFactor": -1,
"defaultValue": "0",
"unit": "°C",
"access": "RO"
},
{
"id": "roomTemperature1",
"address": 11,
"size": 1,
"type": "uint16",
"registerType": "inputRegister",
"readSchedule": "update",
"description": "Room remote adjuster 1 temperature",
"staticScaleFactor": -1,
"defaultValue": "0",
"unit": "°C",
"access": "RO"
},
{
"id": "roomTemperature2",
"address": 12,
"size": 1,
"type": "uint16",
"registerType": "inputRegister",
"readSchedule": "update",
"description": "Room remote adjuster 2 temperature",
"staticScaleFactor": -1,
"defaultValue": "0",
"unit": "°C",
"access": "RO"
},
{
"id": "roomTemperature3",
"address": 13,
"size": 1,
"type": "uint16",
"registerType": "inputRegister",
"readSchedule": "update",
"description": "Room remote adjuster 3 temperature",
"staticScaleFactor": -1,
"defaultValue": "0",
"unit": "°C",
"access": "RO"
},
{
"id": "solarCollectorTemperature",
"address": 14,
"size": 1,
"type": "uint16",
"registerType": "inputRegister",
"readSchedule": "update",
"description": "Solar collector temperature",
"staticScaleFactor": -1,
"defaultValue": "0",
"unit": "°C",
"access": "RO"
},
{
"id": "solarStorageTankTemperature",
"address": 15,
"size": 1,
"type": "uint16",
"registerType": "inputRegister",
"readSchedule": "update",
"description": "Solar storage tank temperature",
"staticScaleFactor": -1,
"defaultValue": "0",
"unit": "°C",
"access": "RO"
},
{
"id": "externalEnergySourceTemperature",
"address": 16,
"size": 1,
"type": "uint16",
"registerType": "inputRegister",
"readSchedule": "update",
"description": "External energy source temperature",
"staticScaleFactor": -1,
"defaultValue": "0",
"unit": "°C",
"access": "RO"
},
{
"id": "supplyAirTemperature",
"address": 17,
"size": 1,
"type": "uint16",
"registerType": "inputRegister",
"readSchedule": "update",
"description": "Supply air temperature",
"staticScaleFactor": -1,
"defaultValue": "0",
"unit": "°C",
"access": "RO"
},
{
"id": "externalAirTemperature",
"address": 18,
"size": 1,
"type": "uint16",
"registerType": "inputRegister",
"readSchedule": "update",
"description": "External air temperature",
"staticScaleFactor": -1,
"defaultValue": "0",
"unit": "°C",
"access": "RO"
},
{
"id": "rbeRoomActualTemperature",
"address": 24,
"size": 1,
"type": "uint16",
"registerType": "inputRegister",
"readSchedule": "update",
"description": "RBE actual room temperature",
"staticScaleFactor": -1,
"defaultValue": "0",
"unit": "°C",
"access": "RO"
},
{
"id": "rbeRoomSetpointTemperature",
"address": 24,
"size": 1,
"type": "uint16",
"registerType": "inputRegister",
"readSchedule": "update",
"description": "RBE room temperature setpoint",
"staticScaleFactor": -1,
"defaultValue": "0",
"unit": "°C",
"access": "RO"
},
{
"id": "heatingPumpOperatingHours",
"address": 33,
"size": 1,
"type": "uint16",
"registerType": "inputRegister",
"readSchedule": "update",
"description": "Heating pump operating hours",
"defaultValue": "0",
"unit": "h",
"access": "RO"
},
{
"id": "systemStatus",
"address": 37,
"size": 1,
"type": "uint16",
"enum": "SystemStatus",
"registerType": "inputRegister",
"readSchedule": "update",
"description": "System status",
"defaultValue": "SystemStatusHeatingMode",
"access": "RO"
},
{
"id": "heatingEnergy",
"address": 38,
"size": 2,
"type": "uint32",
"registerType": "inputRegister",
"readSchedule": "update",
"staticScaleFactor": -1,
"defaultValue": "0",
"unit": "kWh",
"description": "Heating energy",
"access": "RO"
},
{
"id": "waterHeatEnergy",
"address": 40,
"size": 2,
"type": "uint32",
"registerType": "inputRegister",
"readSchedule": "update",
"staticScaleFactor": -1,
"defaultValue": "0",
"unit": "kWh",
"description": "Water heat energy",
"access": "RO"
},
{
"id": "totalHeatEnergy",
"address": 44,
"size": 2,
"type": "uint32",
"registerType": "inputRegister",
"readSchedule": "update",
"staticScaleFactor": -1,
"defaultValue": "0",
"unit": "kWh",
"description": "Total energy",
"access": "RO"
},
{
"id": "outdoorTemperature",
"address": 0,
"size": 1,
"type": "uint16",
"registerType": "holdingRegister",
"readSchedule": "update",
"description": "Outdoor temperature",
"staticScaleFactor": -1,
"defaultValue": "0",
"unit": "°C",
"access": "RW"
},
{
"id": "returnSetpointTemperature",
"address": 1,
"size": 1,
"type": "uint16",
"registerType": "holdingRegister",
"readSchedule": "update",
"description": "Return setpoint temperature",
"staticScaleFactor": -1,
"defaultValue": "0",
"unit": "°C",
"access": "RW"
},
{
"id": "hotWaterSetpointTemperature",
"address": 5,
"size": 1,
"type": "uint16",
"registerType": "holdingRegister",
"readSchedule": "update",
"description": "Hot water setpoint temperature",
"staticScaleFactor": -1,
"defaultValue": "0",
"unit": "°C",
"access": "RW"
},
{
"id": "smartGrid",
"address": 14,
"size": 1,
"type": "uint16",
"enum": "SmartGridState",
"registerType": "holdingRegister",
"readSchedule": "update",
"description": "Smart grid control",
"defaultValue": "SmartGridStateStandard",
"access": "RW"
}
]
}

View File

@ -0,0 +1,15 @@
include(../plugins.pri)
QT += network serialbus
SOURCES += \
integrationpluginalphainnotec.cpp \
alphaconnectmodbustcpconnection.cpp \
../modbus/modbustcpmaster.cpp \
../modbus/modbusdatautils.cpp
HEADERS += \
integrationpluginalphainnotec.h \
alphaconnectmodbustcpconnection.h \
../modbus/modbustcpmaster.h \
../modbus/modbusdatautils.h

View File

@ -0,0 +1,474 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* 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
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "integrationpluginalphainnotec.h"
#include "network/networkdevicediscovery.h"
#include "hardwaremanager.h"
#include "plugininfo.h"
IntegrationPluginAlphaInnotec::IntegrationPluginAlphaInnotec()
{
}
void IntegrationPluginAlphaInnotec::discoverThings(ThingDiscoveryInfo *info)
{
if (!hardwareManager()->networkDeviceDiscovery()->available()) {
qCWarning(dcAlphaInnotec()) << "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(dcAlphaInnotec()) << "Found" << networkDeviceInfo;
QString title;
if (networkDeviceInfo.hostName().isEmpty()) {
title = networkDeviceInfo.address().toString();
} else {
title = networkDeviceInfo.hostName() + " (" + networkDeviceInfo.address().toString() + ")";
}
QString description;
if (networkDeviceInfo.macAddressManufacturer().isEmpty()) {
description = networkDeviceInfo.macAddress();
} else {
description = networkDeviceInfo.macAddress() + " (" + networkDeviceInfo.macAddressManufacturer() + ")";
}
ThingDescriptor descriptor(alphaConnectThingClassId, title, description);
ParamList params;
params << Param(alphaConnectThingIpAddressParamTypeId, networkDeviceInfo.address().toString());
params << Param(alphaConnectThingMacAddressParamTypeId, networkDeviceInfo.macAddress());
descriptor.setParams(params);
// Check if we already have set up this device
Things existingThings = myThings().filterByParam(alphaConnectThingMacAddressParamTypeId, networkDeviceInfo.macAddress());
if (existingThings.count() == 1) {
qCDebug(dcAlphaInnotec()) << "This connection already exists in the system:" << networkDeviceInfo;
descriptor.setThingId(existingThings.first()->id());
}
info->addThingDescriptor(descriptor);
}
info->finish(Thing::ThingErrorNoError);
});
}
void IntegrationPluginAlphaInnotec::startMonitoringAutoThings()
{
}
void IntegrationPluginAlphaInnotec::setupThing(ThingSetupInfo *info)
{
Thing *thing = info->thing();
qCDebug(dcAlphaInnotec()) << "Setup" << thing << thing->params();
if (thing->thingClassId() == alphaConnectThingClassId) {
QHostAddress hostAddress = QHostAddress(thing->paramValue(alphaConnectThingIpAddressParamTypeId).toString());
if (hostAddress.isNull()) {
info->finish(Thing::ThingErrorInvalidParameter, QT_TR_NOOP("No IP address given"));
return;
}
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){
qCDebug(dcAlphaInnotec()) << "Connected changed to" << status << "for" << thing;
if (status) {
alphaConnectTcpConnection->update();
}
thing->setStateValue(alphaConnectConnectedStateTypeId, status);
});
// Input registers
// connect(alphaConnectTcpConnection, &AlphaConnectModbusTcpConnection::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){
qCDebug(dcAlphaInnotec()) << thing << "flow temperature changed" << flowTemperature << "°C";
thing->setStateValue(alphaConnectFlowTemperatureStateTypeId, flowTemperature);
});
connect(alphaConnectTcpConnection, &AlphaConnectModbusTcpConnection::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){
qCDebug(dcAlphaInnotec()) << thing << "external return temperature changed" << externalReturnTemperature << "°C";
thing->setStateValue(alphaConnectExternalReturnTemperatureStateTypeId, externalReturnTemperature);
});
connect(alphaConnectTcpConnection, &AlphaConnectModbusTcpConnection::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){
qCDebug(dcAlphaInnotec()) << thing << "hot gas temperature changed" << hotGasTemperature << "°C";
thing->setStateValue(alphaConnectHotGasTemperatureStateTypeId, hotGasTemperature);
});
connect(alphaConnectTcpConnection, &AlphaConnectModbusTcpConnection::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){
qCDebug(dcAlphaInnotec()) << thing << "heat source outlet temperature changed" << heatSourceOutletTemperature << "°C";
thing->setStateValue(alphaConnectHeatSourceOutletTemperatureStateTypeId, heatSourceOutletTemperature);
});
connect(alphaConnectTcpConnection, &AlphaConnectModbusTcpConnection::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){
qCDebug(dcAlphaInnotec()) << thing << "room remote adjuster 2 temperature changed" << roomTemperature2 << "°C";
thing->setStateValue(alphaConnectRoomTemperature2StateTypeId, roomTemperature2);
});
connect(alphaConnectTcpConnection, &AlphaConnectModbusTcpConnection::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){
qCDebug(dcAlphaInnotec()) << thing << "solar collector temperature changed" << solarCollectorTemperature << "°C";
thing->setStateValue(alphaConnectSolarCollectorTemperatureStateTypeId, solarCollectorTemperature);
});
connect(alphaConnectTcpConnection, &AlphaConnectModbusTcpConnection::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){
qCDebug(dcAlphaInnotec()) << thing << "external energy source temperature changed" << externalEnergySourceTemperature << "°C";
thing->setStateValue(alphaConnectExternalEnergySourceTemperatureStateTypeId, externalEnergySourceTemperature);
});
connect(alphaConnectTcpConnection, &AlphaConnectModbusTcpConnection::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){
qCDebug(dcAlphaInnotec()) << thing << "external air temperature changed" << externalAirTemperature << "°C";
thing->setStateValue(alphaConnectExternalAirTemperatureStateTypeId, externalAirTemperature);
});
connect(alphaConnectTcpConnection, &AlphaConnectModbusTcpConnection::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){
qCDebug(dcAlphaInnotec()) << thing << "system status changed" << systemStatus;
switch (systemStatus) {
case AlphaConnectModbusTcpConnection::SystemStatusHeatingMode:
thing->setStateValue(alphaConnectSystemStatusStateTypeId, "Heating mode");
break;
case AlphaConnectModbusTcpConnection::SystemStatusDomesticHotWater:
thing->setStateValue(alphaConnectSystemStatusStateTypeId, "Domestic hot water");
break;
case AlphaConnectModbusTcpConnection::SystemStatusSwimmingPool:
thing->setStateValue(alphaConnectSystemStatusStateTypeId, "Swimming pool");
break;
case AlphaConnectModbusTcpConnection::SystemStatusEVUOff:
thing->setStateValue(alphaConnectSystemStatusStateTypeId, "EUV off");
break;
case AlphaConnectModbusTcpConnection::SystemStatusDefrost:
thing->setStateValue(alphaConnectSystemStatusStateTypeId, "Defrost");
break;
case AlphaConnectModbusTcpConnection::SystemStatusOff:
thing->setStateValue(alphaConnectSystemStatusStateTypeId, "Off");
break;
case AlphaConnectModbusTcpConnection::SystemStatusExternalEnergySource:
thing->setStateValue(alphaConnectSystemStatusStateTypeId, "External energy source");
break;
case AlphaConnectModbusTcpConnection::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);
});
// Energy
connect(alphaConnectTcpConnection, &AlphaConnectModbusTcpConnection::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){
qCDebug(dcAlphaInnotec()) << thing << "heating energy changed" << heatingEnergy << "kWh";
thing->setStateValue(alphaConnectHeatingEnergyStateTypeId, heatingEnergy);
});
connect(alphaConnectTcpConnection, &AlphaConnectModbusTcpConnection::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){
// qCDebug(dcAlphaInnotec()) << thing << "swimming pool heat energy changed" << swimmingPoolHeatEnergy << "kWh";
// thing->setStateValue(alphaConnectSwimmingPoolEnergyStateTypeId, swimmingPoolHeatEnergy);
// });
// Holding registers
connect(alphaConnectTcpConnection, &AlphaConnectModbusTcpConnection::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){
qCDebug(dcAlphaInnotec()) << thing << "return setpoint temperature changed" << returnSetpointTemperature << "°C";
thing->setStateValue(alphaConnectReturnSetpointTemperatureStateTypeId, returnSetpointTemperature);
});
connect(alphaConnectTcpConnection, &AlphaConnectModbusTcpConnection::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){
qCDebug(dcAlphaInnotec()) << thing << "smart grid state changed" << smartGridState;
switch (smartGridState) {
case AlphaConnectModbusTcpConnection::SmartGridStateOff:
thing->setStateValue(alphaConnectSgReadyModeStateTypeId, "Off");
break;
case AlphaConnectModbusTcpConnection::SmartGridStateLow:
thing->setStateValue(alphaConnectSgReadyModeStateTypeId, "Low");
break;
case AlphaConnectModbusTcpConnection::SmartGridStateStandard:
thing->setStateValue(alphaConnectSgReadyModeStateTypeId, "Standard");
break;
case AlphaConnectModbusTcpConnection::SmartGridStateHigh:
thing->setStateValue(alphaConnectSgReadyModeStateTypeId, "High");
break;
}
});
m_alpaConnectTcpThings.insert(thing, alphaConnectTcpConnection);
alphaConnectTcpConnection->connectDevice();
// FIXME: make async and check if this is really an alpha connect
info->finish(Thing::ThingErrorNoError);
}
}
void IntegrationPluginAlphaInnotec::postSetupThing(Thing *thing)
{
if (thing->thingClassId() == alphaConnectThingClassId) {
if (!m_pluginTimer) {
qCDebug(dcAlphaInnotec()) << "Starting plugin timer...";
m_pluginTimer = hardwareManager()->pluginTimerManager()->registerTimer(10);
connect(m_pluginTimer, &PluginTimer::timeout, this, [this] {
foreach (AlphaConnectModbusTcpConnection *connection, m_alpaConnectTcpThings) {
if (connection->connected()) {
connection->update();
}
}
});
m_pluginTimer->start();
}
}
}
void IntegrationPluginAlphaInnotec::thingRemoved(Thing *thing)
{
if (thing->thingClassId() == alphaConnectThingClassId && m_alpaConnectTcpThings.contains(thing)) {
AlphaConnectModbusTcpConnection *connection = m_alpaConnectTcpThings.take(thing);
delete connection;
}
if (myThings().isEmpty() && m_pluginTimer) {
hardwareManager()->pluginTimerManager()->unregisterTimer(m_pluginTimer);
m_pluginTimer = nullptr;
}
}
void IntegrationPluginAlphaInnotec::executeAction(ThingActionInfo *info)
{
Thing *thing = info->thing();
AlphaConnectModbusTcpConnection *connection = m_alpaConnectTcpThings.value(thing);
if (!connection->connected()) {
qCWarning(dcAlphaInnotec()) << "Could not execute action. The modbus connection is currently not available.";
info->finish(Thing::ThingErrorHardwareNotAvailable);
return;
}
if (thing->thingClassId() == alphaConnectThingClassId) {
/* if (info->action().actionTypeId() == alphaConnectOutdoorTemperatureActionTypeId) {
double outdoorTemperature = info->action().paramValue(alphaConnectOutdoorTemperatureActionOutdoorTemperatureParamTypeId).toDouble();
qCDebug(dcAlphaInnotec()) << "Execute action" << info->action().actionTypeId().toString() << info->action().params();
QModbusReply *reply = connection->setOutdoorTemperature(outdoorTemperature);
if (!reply) {
qCWarning(dcAlphaInnotec()) << "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, outdoorTemperature]{
if (reply->error() != QModbusDevice::NoError) {
info->finish(Thing::ThingErrorHardwareFailure);
qCWarning(dcAlphaInnotec()) << "Set outdoor temperature finished with error" << reply->errorString();
return;
}
qCDebug(dcAlphaInnotec()) << "Execute action finished successfully" << info->action().actionTypeId().toString() << info->action().params();
info->thing()->setStateValue(alphaConnectOutdoorTemperatureStateTypeId, outdoorTemperature);
info->finish(Thing::ThingErrorNoError);
});
connect(reply, &QModbusReply::errorOccurred, this, [reply] (QModbusDevice::Error error){
qCWarning(dcAlphaInnotec()) << "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() == alphaConnectHotWaterSetpointTemperatureActionTypeId) {
double temperature = info->action().paramValue(alphaConnectHotWaterSetpointTemperatureActionHotWaterSetpointTemperatureParamTypeId).toDouble();
qCDebug(dcAlphaInnotec()) << "Execute action" << info->action().actionTypeId().toString() << info->action().params();
QModbusReply *reply = connection->setHotWaterSetpointTemperature(temperature);
if (!reply) {
qCWarning(dcAlphaInnotec()) << "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, temperature]{
if (reply->error() != QModbusDevice::NoError) {
qCWarning(dcAlphaInnotec()) << "Set hot water setpoint temperature finished with error" << reply->errorString();
info->finish(Thing::ThingErrorHardwareFailure);
return;
}
qCDebug(dcAlphaInnotec()) << "Execute action finished successfully" << info->action().actionTypeId().toString() << info->action().params();
info->thing()->setStateValue(alphaConnectHotWaterSetpointTemperatureStateTypeId, temperature);
info->finish(Thing::ThingErrorNoError);
});
connect(reply, &QModbusReply::errorOccurred, this, [reply] (QModbusDevice::Error error){
qCWarning(dcAlphaInnotec()) << "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() == alphaConnectReturnSetpointTemperatureActionTypeId) {
double temperature = info->action().paramValue(alphaConnectReturnSetpointTemperatureActionReturnSetpointTemperatureParamTypeId).toDouble();
qCDebug(dcAlphaInnotec()) << "Execute action" << info->action().actionTypeId().toString() << info->action().params();
QModbusReply *reply = connection->setReturnSetpointTemperature(temperature);
if (!reply) {
qCWarning(dcAlphaInnotec()) << "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, temperature]{
if (reply->error() != QModbusDevice::NoError) {
qCWarning(dcAlphaInnotec()) << "Set return setpoint temperature finished with error" << reply->errorString();
info->finish(Thing::ThingErrorHardwareFailure);
return;
}
qCDebug(dcAlphaInnotec()) << "Execute action finished successfully" << info->action().actionTypeId().toString() << info->action().params();
info->thing()->setStateValue(alphaConnectReturnSetpointTemperatureStateTypeId, temperature);
info->finish(Thing::ThingErrorNoError);
});
connect(reply, &QModbusReply::errorOccurred, this, [reply] (QModbusDevice::Error error){
qCWarning(dcAlphaInnotec()) << "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() == alphaConnectSgReadyModeActionTypeId) {
QString sgReadyModeString = info->action().paramValue(alphaConnectSgReadyModeActionSgReadyModeParamTypeId).toString();
qCDebug(dcAlphaInnotec()) << "Execute action" << info->action().actionTypeId().toString() << info->action().params();
AlphaConnectModbusTcpConnection::SmartGridState sgReadyState;
if (sgReadyModeString == "Off") {
sgReadyState = AlphaConnectModbusTcpConnection::SmartGridStateOff;
} else if (sgReadyModeString == "Low") {
sgReadyState = AlphaConnectModbusTcpConnection::SmartGridStateLow;
} else if (sgReadyModeString == "High") {
sgReadyState = AlphaConnectModbusTcpConnection::SmartGridStateHigh;
} else {
sgReadyState = AlphaConnectModbusTcpConnection::SmartGridStateStandard;
}
QModbusReply *reply = connection->setSmartGrid(sgReadyState);
if (!reply) {
qCWarning(dcAlphaInnotec()) << "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(dcAlphaInnotec()) << "Set SG ready mode finished with error" << reply->errorString();
info->finish(Thing::ThingErrorHardwareFailure);
return;
}
qCDebug(dcAlphaInnotec()) << "Execute action finished successfully" << info->action().actionTypeId().toString() << info->action().params();
info->thing()->setStateValue(alphaConnectSgReadyModeStateTypeId, sgReadyModeString);
info->finish(Thing::ThingErrorNoError);
});
connect(reply, &QModbusReply::errorOccurred, this, [reply] (QModbusDevice::Error error){
qCWarning(dcAlphaInnotec()) << "Modbus reply error occurred while execute action" << error << reply->errorString();
emit reply->finished(); // To make sure it will be deleted
});
}
}
info->finish(Thing::ThingErrorNoError);
}

View File

@ -0,0 +1,62 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* Copyright 2013 - 2020, nymea GmbH
* Contact: contact@nymea.io
*
* This file is part of nymea.
* This project including source code and documentation is protected by
* copyright law, and remains the property of nymea GmbH. All rights, including
* reproduction, publication, editing and translation, are reserved. The use of
* this project is subject to the terms of a license agreement to be concluded
* with nymea GmbH in accordance with the terms of use of nymea GmbH, available
* under https://nymea.io/license
*
* GNU Lesser General Public License Usage
* Alternatively, this project may be redistributed and/or modified under the
* terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; version 3. This project is distributed in the hope that
* it will be useful, but WITHOUT ANY WARRANTY; without even the implied
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this project. If not, see <https://www.gnu.org/licenses/>.
*
* For any further details and any questions please contact us under
* contact@nymea.io or see our FAQ/Licensing Information on
* https://nymea.io/license/faq
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef INTEGRATIONPLUGINALPHAINNOTEC_H
#define INTEGRATIONPLUGINALPHAINNOTEC_H
#include "plugintimer.h"
#include "alphaconnectmodbustcpconnection.h"
#include "integrations/integrationplugin.h"
class IntegrationPluginAlphaInnotec: public IntegrationPlugin
{
Q_OBJECT
Q_PLUGIN_METADATA(IID "io.nymea.IntegrationPlugin" FILE "integrationpluginalphainnotec.json")
Q_INTERFACES(IntegrationPlugin)
public:
explicit IntegrationPluginAlphaInnotec();
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 *, AlphaConnectModbusTcpConnection *> m_alpaConnectTcpThings;
};
#endif // INTEGRATIONPLUGINALPHAINNOTEC_H

View File

@ -0,0 +1,343 @@
{
"name": "AlphaInnotec",
"displayName": "alpha innotec",
"id": "b3225a18-e9b0-443e-8c88-802d3132f94d",
"vendors": [
{
"name": "alphaInnotec",
"displayName": "alpha Innotec",
"id": "2c2101ae-7bb8-4012-97ba-cedf4cecd924",
"thingClasses": [
{
"name": "alphaConnect",
"displayName": "alpha connect",
"id": "c5437b68-cfd2-4ec8-bad6-006fb5e8a8da",
"createMethods": ["discovery", "user"],
"interfaces": ["smartgridheatpump", "connectable"],
"paramTypes": [
{
"id": "64a18910-9111-4eaf-986d-f7b64b03b99a",
"name": "ipAddress",
"displayName": "IP address",
"type": "QString",
"inputType": "IPv4Address",
"defaultValue": "127.0.0.1"
},
{
"id": "f791c219-98a5-41ee-8e5f-1bfb5136dc9c",
"name":"macAddress",
"displayName": "MAC address",
"type": "QString",
"inputType": "MacAddress",
"defaultValue": ""
},
{
"id": "b92025c1-8978-4d47-bd3c-4df749dbfd0f",
"name":"port",
"displayName": "Port",
"type": "int",
"defaultValue": 502
},
{
"id": "1d9517ca-680c-49e2-a8d1-320743c27559",
"name":"slaveId",
"displayName": "Modbus slave ID",
"type": "int",
"defaultValue": 1
}
],
"stateTypes": [
{
"id": "01ce0d61-3813-4c1b-a18b-555913d689a2",
"name": "connected",
"displayName": "Connected",
"displayNameEvent": "Connected changed",
"type": "bool",
"defaultValue": false,
"cached": false
},
{
"id": "07465fbb-6949-4bd1-90d5-acf2d80c161d",
"name": "heatingOn",
"displayName": "Heating on",
"displayNameEvent": "Heating turned on/off",
"type": "bool",
"defaultValue": false,
"suggestLogging": true
},
{
"id": "8b407c1d-b84f-48d4-9961-b29bc58fff0e",
"name": "coolingOn",
"displayName": "Cooling on",
"displayNameEvent": "Cooling turned on/off",
"type": "bool",
"defaultValue": false,
"suggestLogging": true
},
{
"id": "fb448191-69d7-4f2e-87bf-6e4fb61e403f",
"name": "flowTemperature",
"displayName": "Flow temperature",
"displayNameEvent": "Flow temperature changed",
"unit": "DegreeCelsius",
"type": "double",
"defaultValue": 0,
"suggestLogging": true
},
{
"id": "6f96706e-67a3-43d3-bf74-e2e3e5fd0d6d",
"name": "returnTemperature",
"displayName": "Return temperature",
"displayNameEvent": "Return temperature changed",
"unit": "DegreeCelsius",
"type": "double",
"defaultValue": 0,
"suggestLogging": true
},
{
"id": "b6702fc5-889b-48b6-9257-64c5ee6e5e95",
"name": "externalReturnTemperature",
"displayName": "External return temperature",
"displayNameEvent": "External return temperature changed",
"unit": "DegreeCelsius",
"type": "double",
"defaultValue": 0,
"suggestLogging": true
},
{
"id": "da7e6bc9-95fd-4c90-931f-5b1cd69d864a",
"name": "hotWaterTemperature",
"displayName": "Hot water temperature",
"displayNameEvent": "Hot water temperature changed",
"unit": "DegreeCelsius",
"type": "double",
"defaultValue": 0,
"suggestLogging": true
},
{
"id": "bea6658e-64bf-4476-b75d-38c34a5fed85",
"name": "hotGasTemperature",
"displayName": "Hot gas temperature",
"displayNameEvent": "Hot gas temperature changed",
"unit": "DegreeCelsius",
"type": "double",
"defaultValue": 0,
"suggestLogging": true
},
{
"id": "e9facc5d-f41c-4256-85aa-b0f777431975",
"name": "heatSourceInletTemperature",
"displayName": "Heat source inlet temperature",
"displayNameEvent": "Heat source inlet temperature changed",
"unit": "DegreeCelsius",
"type": "double",
"defaultValue": 0,
"suggestLogging": true
},
{
"id": "48424285-4bc4-4110-8089-0486292d7371",
"name": "heatSourceOutletTemperature",
"displayName": "Heat source outlet temperature",
"displayNameEvent": "Heat source outlet temperature changed",
"unit": "DegreeCelsius",
"type": "double",
"defaultValue": 0,
"suggestLogging": true
},
{
"id": "52f8a581-7b9c-4c15-8aaa-c083763e7820",
"name": "roomTemperature1",
"displayName": "Room remote adjuster 1 temperature",
"displayNameEvent": "Room remote adjuster 1 temperature changed",
"unit": "DegreeCelsius",
"type": "double",
"defaultValue": 0,
"suggestLogging": true
},
{
"id": "91b57690-5daa-4766-86ae-f205fa0c805a",
"name": "roomTemperature2",
"displayName": "Room remote adjuster 2 temperature",
"displayNameEvent": "Room remote adjuster 2 temperature changed",
"unit": "DegreeCelsius",
"type": "double",
"defaultValue": 0,
"suggestLogging": true
},
{
"id": "a8c7e706-57ba-4572-b6e6-5eec91065ea8",
"name": "roomTemperature3",
"displayName": "Room remote adjuster 3 temperature",
"displayNameEvent": "Room remote adjuster 3 temperature changed",
"unit": "DegreeCelsius",
"type": "double",
"defaultValue": 0,
"suggestLogging": true
},
{
"id": "d4484305-eb0f-418b-bb15-f71b08e6fce1",
"name": "solarCollectorTemperature",
"displayName": "Solar collector temperature",
"displayNameEvent": "Solar collector temperature changed",
"unit": "DegreeCelsius",
"type": "double",
"defaultValue": 0,
"suggestLogging": true
},
{
"id": "75089369-c224-4fe5-91d1-9bdc5578f0a5",
"name": "solarStorageTankTemperature",
"displayName": "Solar storage tank temperature",
"displayNameEvent": "Solar storage tank temperature changed",
"unit": "DegreeCelsius",
"type": "double",
"defaultValue": 0,
"suggestLogging": true
},
{
"id": "519d7d45-1f3d-4118-ade9-3d7508451005",
"name": "externalEnergySourceTemperature",
"displayName": "External energy source temperature",
"displayNameEvent": "External energy source temperature changed",
"unit": "DegreeCelsius",
"type": "double",
"defaultValue": 0,
"suggestLogging": true
},
{
"id": "90d88164-3083-47c7-a396-b338bd9ea54c",
"name": "supplyAirTemperature",
"displayName": "Supply air temperature",
"displayNameEvent": "Supply air temperature changed",
"unit": "DegreeCelsius",
"type": "double",
"defaultValue": 0,
"suggestLogging": true
},
{
"id": "92594f19-8e4c-485b-bfd5-5371a0454267",
"name": "externalAirTemperature",
"displayName": "External air temperature",
"displayNameEvent": "External air temperature changed",
"unit": "DegreeCelsius",
"type": "double",
"defaultValue": 0,
"suggestLogging": true
},
{
"id": "5a21a131-f3a0-4ebd-9b2e-12eb25c84853",
"name": "systemStatus",
"displayName": "System status",
"displayNameEvent": "System status changed",
"type": "QString",
"possibleValues": [
"Heating mode",
"Domestic hot water",
"Swimming pool",
"EUV off",
"Defrost",
"Off",
"External energy source",
"Cooling mode"
],
"defaultValue": "Heating mode",
"suggestLogging": true
},
{
"id": "ef378ce6-f112-4022-8535-78cbd6ccfeeb",
"name": "heatingPumpOperatingHours",
"displayName": "Heating pump operating hours",
"displayNameEvent": "Heating pump operating hours changed",
"unit": "Hours",
"type": "uint",
"defaultValue": 0
},
{
"id": "d0c8f168-49b5-47ca-9988-c9922be38dd5",
"name": "outdoorTemperature",
"displayName": "Outdoor temperature",
"displayNameEvent": "Outdoor temperature changed",
"displayNameAction": "Set outdoor temperature",
"unit": "DegreeCelsius",
"type": "double",
"defaultValue": 0,
"suggestLogging": true
},
{
"id": "1ee6b189-ceff-4912-a577-2e3320307c3f",
"name": "returnSetpointTemperature",
"displayName": "Return temperature setpoint",
"displayNameEvent": "Return temperature setpoint changed",
"displayNameAction": "Set return temperature setpoint",
"unit": "DegreeCelsius",
"type": "double",
"defaultValue": 0,
"writable": true,
"suggestLogging": true
},
{
"id": "a7f1a688-51d3-4f9e-a323-86117c5542a8",
"name": "hotWaterSetpointTemperature",
"displayName": "Hot water temperature setpoint",
"displayNameEvent": "Hot water temperature setpoint changed",
"displayNameAction": "Set hot water temperature setpoint",
"unit": "DegreeCelsius",
"type": "double",
"defaultValue": 0,
"writable": true,
"suggestLogging": true
},
{
"id": "8cc9761f-b30e-4f54-aee7-b64190df57e1",
"name": "sgReadyMode",
"displayName": "Smart grid mode",
"displayNameEvent": "Smart grid mode changed",
"displayNameAction": "Set smart grid mode",
"type": "QString",
"possibleValues": [
"Off",
"Low",
"Standard",
"High"
],
"writable": true,
"defaultValue": "Standard",
"suggestLogging": true
},
{
"id": "c7948cf6-fd1a-44fa-a91b-98f2474ecc62",
"name": "totalEnergy",
"displayName": "Total energy",
"displayNameEvent": "Total energy changed",
"type": "double",
"unit": "KiloWattHour",
"defaultValue": 0,
"suggestLogging": true
},
{
"id": "24367fba-2883-40da-9b92-5d4db3c71c2f",
"name": "heatingEnergy",
"displayName": "Heating energy",
"displayNameEvent": "Heating energy changed",
"type": "double",
"unit": "KiloWattHour",
"defaultValue": 0,
"suggestLogging": true
},
{
"id": "be2430c3-54ef-441e-b684-9aabc1d984d6",
"name": "hotWaterEnergy",
"displayName": "Hot water energy",
"displayNameEvent": "Hot water energy changed",
"type": "double",
"unit": "KiloWattHour",
"defaultValue": 0,
"suggestLogging": true
}
],
"actionTypes": [ ]
}
]
}
]
}

13
alphainnotec/meta.json Normal file
View File

@ -0,0 +1,13 @@
{
"title": "alpha innotec",
"tagline": "Integrate alpha innotec heat pumps into nymea.",
"icon": "alpha-innotec.png",
"stability": "community",
"offline": true,
"technologies": [
"network"
],
"categories": [
"heating"
]
}

View File

@ -0,0 +1,431 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE TS>
<TS version="2.1">
<context>
<name>AlphaInnotec</name>
<message>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/alphainnotec/plugininfo.h" line="106"/>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/alphainnotec/plugininfo.h" line="109"/>
<source>Connected</source>
<extracomment>The name of the ParamType (ThingClass: alphaConnect, EventType: connected, ID: {01ce0d61-3813-4c1b-a18b-555913d689a2})
----------
The name of the StateType ({01ce0d61-3813-4c1b-a18b-555913d689a2}) of ThingClass alphaConnect</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/alphainnotec/plugininfo.h" line="112"/>
<source>Connected changed</source>
<extracomment>The name of the EventType ({01ce0d61-3813-4c1b-a18b-555913d689a2}) of ThingClass alphaConnect</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/alphainnotec/plugininfo.h" line="115"/>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/alphainnotec/plugininfo.h" line="118"/>
<source>Cooling on</source>
<extracomment>The name of the ParamType (ThingClass: alphaConnect, EventType: coolingOn, ID: {8b407c1d-b84f-48d4-9961-b29bc58fff0e})
----------
The name of the StateType ({8b407c1d-b84f-48d4-9961-b29bc58fff0e}) of ThingClass alphaConnect</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/alphainnotec/plugininfo.h" line="121"/>
<source>Cooling turned on/off</source>
<extracomment>The name of the EventType ({8b407c1d-b84f-48d4-9961-b29bc58fff0e}) of ThingClass alphaConnect</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/alphainnotec/plugininfo.h" line="124"/>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/alphainnotec/plugininfo.h" line="127"/>
<source>External air temperature</source>
<extracomment>The name of the ParamType (ThingClass: alphaConnect, EventType: externalAirTemperature, ID: {92594f19-8e4c-485b-bfd5-5371a0454267})
----------
The name of the StateType ({92594f19-8e4c-485b-bfd5-5371a0454267}) of ThingClass alphaConnect</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/alphainnotec/plugininfo.h" line="130"/>
<source>External air temperature changed</source>
<extracomment>The name of the EventType ({92594f19-8e4c-485b-bfd5-5371a0454267}) of ThingClass alphaConnect</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/alphainnotec/plugininfo.h" line="133"/>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/alphainnotec/plugininfo.h" line="136"/>
<source>External energy source temperature</source>
<extracomment>The name of the ParamType (ThingClass: alphaConnect, EventType: externalEnergySourceTemperature, ID: {519d7d45-1f3d-4118-ade9-3d7508451005})
----------
The name of the StateType ({519d7d45-1f3d-4118-ade9-3d7508451005}) of ThingClass alphaConnect</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/alphainnotec/plugininfo.h" line="139"/>
<source>External energy source temperature changed</source>
<extracomment>The name of the EventType ({519d7d45-1f3d-4118-ade9-3d7508451005}) of ThingClass alphaConnect</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/alphainnotec/plugininfo.h" line="142"/>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/alphainnotec/plugininfo.h" line="145"/>
<source>External return temperature</source>
<extracomment>The name of the ParamType (ThingClass: alphaConnect, EventType: externalReturnTemperature, ID: {b6702fc5-889b-48b6-9257-64c5ee6e5e95})
----------
The name of the StateType ({b6702fc5-889b-48b6-9257-64c5ee6e5e95}) of ThingClass alphaConnect</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/alphainnotec/plugininfo.h" line="148"/>
<source>External return temperature changed</source>
<extracomment>The name of the EventType ({b6702fc5-889b-48b6-9257-64c5ee6e5e95}) of ThingClass alphaConnect</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/alphainnotec/plugininfo.h" line="151"/>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/alphainnotec/plugininfo.h" line="154"/>
<source>Flow temperature</source>
<extracomment>The name of the ParamType (ThingClass: alphaConnect, EventType: flowTemperature, ID: {fb448191-69d7-4f2e-87bf-6e4fb61e403f})
----------
The name of the StateType ({fb448191-69d7-4f2e-87bf-6e4fb61e403f}) of ThingClass alphaConnect</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/alphainnotec/plugininfo.h" line="157"/>
<source>Flow temperature changed</source>
<extracomment>The name of the EventType ({fb448191-69d7-4f2e-87bf-6e4fb61e403f}) of ThingClass alphaConnect</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/alphainnotec/plugininfo.h" line="160"/>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/alphainnotec/plugininfo.h" line="163"/>
<source>Heat source inlet temperature</source>
<extracomment>The name of the ParamType (ThingClass: alphaConnect, EventType: heatSourceInletTemperature, ID: {e9facc5d-f41c-4256-85aa-b0f777431975})
----------
The name of the StateType ({e9facc5d-f41c-4256-85aa-b0f777431975}) of ThingClass alphaConnect</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/alphainnotec/plugininfo.h" line="166"/>
<source>Heat source inlet temperature changed</source>
<extracomment>The name of the EventType ({e9facc5d-f41c-4256-85aa-b0f777431975}) of ThingClass alphaConnect</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/alphainnotec/plugininfo.h" line="169"/>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/alphainnotec/plugininfo.h" line="172"/>
<source>Heat source outlet temperature</source>
<extracomment>The name of the ParamType (ThingClass: alphaConnect, EventType: heatSourceOutletTemperature, ID: {48424285-4bc4-4110-8089-0486292d7371})
----------
The name of the StateType ({48424285-4bc4-4110-8089-0486292d7371}) of ThingClass alphaConnect</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/alphainnotec/plugininfo.h" line="175"/>
<source>Heat source outlet temperature changed</source>
<extracomment>The name of the EventType ({48424285-4bc4-4110-8089-0486292d7371}) of ThingClass alphaConnect</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/alphainnotec/plugininfo.h" line="178"/>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/alphainnotec/plugininfo.h" line="181"/>
<source>Heating on</source>
<extracomment>The name of the ParamType (ThingClass: alphaConnect, EventType: heatingOn, ID: {07465fbb-6949-4bd1-90d5-acf2d80c161d})
----------
The name of the StateType ({07465fbb-6949-4bd1-90d5-acf2d80c161d}) of ThingClass alphaConnect</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/alphainnotec/plugininfo.h" line="184"/>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/alphainnotec/plugininfo.h" line="187"/>
<source>Heating pump operating hours</source>
<extracomment>The name of the ParamType (ThingClass: alphaConnect, EventType: heatingPumpOperatingHours, ID: {ef378ce6-f112-4022-8535-78cbd6ccfeeb})
----------
The name of the StateType ({ef378ce6-f112-4022-8535-78cbd6ccfeeb}) of ThingClass alphaConnect</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/alphainnotec/plugininfo.h" line="190"/>
<source>Heating pump operating hours changed</source>
<extracomment>The name of the EventType ({ef378ce6-f112-4022-8535-78cbd6ccfeeb}) of ThingClass alphaConnect</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/alphainnotec/plugininfo.h" line="193"/>
<source>Heating turned on/off</source>
<extracomment>The name of the EventType ({07465fbb-6949-4bd1-90d5-acf2d80c161d}) of ThingClass alphaConnect</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/alphainnotec/plugininfo.h" line="196"/>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/alphainnotec/plugininfo.h" line="199"/>
<source>Hot gas temperature</source>
<extracomment>The name of the ParamType (ThingClass: alphaConnect, EventType: hotGasTemperature, ID: {bea6658e-64bf-4476-b75d-38c34a5fed85})
----------
The name of the StateType ({bea6658e-64bf-4476-b75d-38c34a5fed85}) of ThingClass alphaConnect</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/alphainnotec/plugininfo.h" line="202"/>
<source>Hot gas temperature changed</source>
<extracomment>The name of the EventType ({bea6658e-64bf-4476-b75d-38c34a5fed85}) of ThingClass alphaConnect</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/alphainnotec/plugininfo.h" line="205"/>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/alphainnotec/plugininfo.h" line="208"/>
<source>Hot water temperature</source>
<extracomment>The name of the ParamType (ThingClass: alphaConnect, EventType: hotWaterTemperature, ID: {da7e6bc9-95fd-4c90-931f-5b1cd69d864a})
----------
The name of the StateType ({da7e6bc9-95fd-4c90-931f-5b1cd69d864a}) of ThingClass alphaConnect</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/alphainnotec/plugininfo.h" line="211"/>
<source>Hot water temperature changed</source>
<extracomment>The name of the EventType ({da7e6bc9-95fd-4c90-931f-5b1cd69d864a}) of ThingClass alphaConnect</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/alphainnotec/plugininfo.h" line="214"/>
<source>IP address</source>
<extracomment>The name of the ParamType (ThingClass: alphaConnect, Type: thing, ID: {64a18910-9111-4eaf-986d-f7b64b03b99a})</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/alphainnotec/plugininfo.h" line="217"/>
<source>MAC address</source>
<extracomment>The name of the ParamType (ThingClass: alphaConnect, Type: thing, ID: {f791c219-98a5-41ee-8e5f-1bfb5136dc9c})</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/alphainnotec/plugininfo.h" line="220"/>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/alphainnotec/plugininfo.h" line="223"/>
<source>Mean temperature</source>
<extracomment>The name of the ParamType (ThingClass: alphaConnect, EventType: meanTemperature, ID: {956051a6-8677-4b25-b899-71aa3590d4e5})
----------
The name of the StateType ({956051a6-8677-4b25-b899-71aa3590d4e5}) of ThingClass alphaConnect</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/alphainnotec/plugininfo.h" line="226"/>
<source>Mean temperature changed</source>
<extracomment>The name of the EventType ({956051a6-8677-4b25-b899-71aa3590d4e5}) of ThingClass alphaConnect</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/alphainnotec/plugininfo.h" line="229"/>
<source>Modbus slave ID</source>
<extracomment>The name of the ParamType (ThingClass: alphaConnect, Type: thing, ID: {1d9517ca-680c-49e2-a8d1-320743c27559})</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/alphainnotec/plugininfo.h" line="232"/>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/alphainnotec/plugininfo.h" line="235"/>
<source>Outdoor temperature</source>
<extracomment>The name of the ParamType (ThingClass: alphaConnect, EventType: outdoorTemperature, ID: {d0c8f168-49b5-47ca-9988-c9922be38dd5})
----------
The name of the StateType ({d0c8f168-49b5-47ca-9988-c9922be38dd5}) of ThingClass alphaConnect</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/alphainnotec/plugininfo.h" line="238"/>
<source>Outdoor temperature changed</source>
<extracomment>The name of the EventType ({d0c8f168-49b5-47ca-9988-c9922be38dd5}) of ThingClass alphaConnect</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/alphainnotec/plugininfo.h" line="241"/>
<source>Port</source>
<extracomment>The name of the ParamType (ThingClass: alphaConnect, Type: thing, ID: {b92025c1-8978-4d47-bd3c-4df749dbfd0f})</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/alphainnotec/plugininfo.h" line="244"/>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/alphainnotec/plugininfo.h" line="247"/>
<source>Return temperature</source>
<extracomment>The name of the ParamType (ThingClass: alphaConnect, EventType: returnTemperature, ID: {6f96706e-67a3-43d3-bf74-e2e3e5fd0d6d})
----------
The name of the StateType ({6f96706e-67a3-43d3-bf74-e2e3e5fd0d6d}) of ThingClass alphaConnect</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/alphainnotec/plugininfo.h" line="250"/>
<source>Return temperature changed</source>
<extracomment>The name of the EventType ({6f96706e-67a3-43d3-bf74-e2e3e5fd0d6d}) of ThingClass alphaConnect</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/alphainnotec/plugininfo.h" line="253"/>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/alphainnotec/plugininfo.h" line="256"/>
<source>Room remote adjuster 1 temperature</source>
<extracomment>The name of the ParamType (ThingClass: alphaConnect, EventType: roomTemperature1, ID: {52f8a581-7b9c-4c15-8aaa-c083763e7820})
----------
The name of the StateType ({52f8a581-7b9c-4c15-8aaa-c083763e7820}) of ThingClass alphaConnect</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/alphainnotec/plugininfo.h" line="259"/>
<source>Room remote adjuster 1 temperature changed</source>
<extracomment>The name of the EventType ({52f8a581-7b9c-4c15-8aaa-c083763e7820}) of ThingClass alphaConnect</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/alphainnotec/plugininfo.h" line="262"/>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/alphainnotec/plugininfo.h" line="265"/>
<source>Room remote adjuster 2 temperature</source>
<extracomment>The name of the ParamType (ThingClass: alphaConnect, EventType: roomTemperature2, ID: {91b57690-5daa-4766-86ae-f205fa0c805a})
----------
The name of the StateType ({91b57690-5daa-4766-86ae-f205fa0c805a}) of ThingClass alphaConnect</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/alphainnotec/plugininfo.h" line="268"/>
<source>Room remote adjuster 2 temperature changed</source>
<extracomment>The name of the EventType ({91b57690-5daa-4766-86ae-f205fa0c805a}) of ThingClass alphaConnect</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/alphainnotec/plugininfo.h" line="271"/>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/alphainnotec/plugininfo.h" line="274"/>
<source>Room remote adjuster 3 temperature</source>
<extracomment>The name of the ParamType (ThingClass: alphaConnect, EventType: roomTemperature3, ID: {a8c7e706-57ba-4572-b6e6-5eec91065ea8})
----------
The name of the StateType ({a8c7e706-57ba-4572-b6e6-5eec91065ea8}) of ThingClass alphaConnect</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/alphainnotec/plugininfo.h" line="277"/>
<source>Room remote adjuster 3 temperature changed</source>
<extracomment>The name of the EventType ({a8c7e706-57ba-4572-b6e6-5eec91065ea8}) of ThingClass alphaConnect</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/alphainnotec/plugininfo.h" line="280"/>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/alphainnotec/plugininfo.h" line="283"/>
<source>Room temperature</source>
<extracomment>The name of the ParamType (ThingClass: alphaConnect, EventType: temperature, ID: {0b978a61-4340-443a-8ea6-69217a593508})
----------
The name of the StateType ({0b978a61-4340-443a-8ea6-69217a593508}) of ThingClass alphaConnect</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/alphainnotec/plugininfo.h" line="286"/>
<source>Room temperature changed</source>
<extracomment>The name of the EventType ({0b978a61-4340-443a-8ea6-69217a593508}) of ThingClass alphaConnect</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/alphainnotec/plugininfo.h" line="289"/>
<source>Set target room temperature</source>
<extracomment>The name of the ActionType ({2e8f44c5-c4e3-4539-b85b-45898bbbf6c2}) of ThingClass alphaConnect</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/alphainnotec/plugininfo.h" line="292"/>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/alphainnotec/plugininfo.h" line="295"/>
<source>Solar collector temperature</source>
<extracomment>The name of the ParamType (ThingClass: alphaConnect, EventType: solarCollectorTemperature, ID: {d4484305-eb0f-418b-bb15-f71b08e6fce1})
----------
The name of the StateType ({d4484305-eb0f-418b-bb15-f71b08e6fce1}) of ThingClass alphaConnect</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/alphainnotec/plugininfo.h" line="298"/>
<source>Solar collector temperature changed</source>
<extracomment>The name of the EventType ({d4484305-eb0f-418b-bb15-f71b08e6fce1}) of ThingClass alphaConnect</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/alphainnotec/plugininfo.h" line="301"/>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/alphainnotec/plugininfo.h" line="304"/>
<source>Solar storage tank temperature</source>
<extracomment>The name of the ParamType (ThingClass: alphaConnect, EventType: solarStorageTankTemperature, ID: {75089369-c224-4fe5-91d1-9bdc5578f0a5})
----------
The name of the StateType ({75089369-c224-4fe5-91d1-9bdc5578f0a5}) of ThingClass alphaConnect</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/alphainnotec/plugininfo.h" line="307"/>
<source>Solar storage tank temperature changed</source>
<extracomment>The name of the EventType ({75089369-c224-4fe5-91d1-9bdc5578f0a5}) of ThingClass alphaConnect</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/alphainnotec/plugininfo.h" line="310"/>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/alphainnotec/plugininfo.h" line="313"/>
<source>Supply air temperature</source>
<extracomment>The name of the ParamType (ThingClass: alphaConnect, EventType: supplyAirTemperature, ID: {90d88164-3083-47c7-a396-b338bd9ea54c})
----------
The name of the StateType ({90d88164-3083-47c7-a396-b338bd9ea54c}) of ThingClass alphaConnect</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/alphainnotec/plugininfo.h" line="316"/>
<source>Supply air temperature changed</source>
<extracomment>The name of the EventType ({90d88164-3083-47c7-a396-b338bd9ea54c}) of ThingClass alphaConnect</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/alphainnotec/plugininfo.h" line="319"/>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/alphainnotec/plugininfo.h" line="322"/>
<source>System status</source>
<extracomment>The name of the ParamType (ThingClass: alphaConnect, EventType: systemStatus, ID: {5a21a131-f3a0-4ebd-9b2e-12eb25c84853})
----------
The name of the StateType ({5a21a131-f3a0-4ebd-9b2e-12eb25c84853}) of ThingClass alphaConnect</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/alphainnotec/plugininfo.h" line="325"/>
<source>System status changed</source>
<extracomment>The name of the EventType ({5a21a131-f3a0-4ebd-9b2e-12eb25c84853}) of ThingClass alphaConnect</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/alphainnotec/plugininfo.h" line="328"/>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/alphainnotec/plugininfo.h" line="331"/>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/alphainnotec/plugininfo.h" line="334"/>
<source>Target room temperature</source>
<extracomment>The name of the ParamType (ThingClass: alphaConnect, ActionType: targetTemperature, ID: {2e8f44c5-c4e3-4539-b85b-45898bbbf6c2})
----------
The name of the ParamType (ThingClass: alphaConnect, EventType: targetTemperature, ID: {2e8f44c5-c4e3-4539-b85b-45898bbbf6c2})
----------
The name of the StateType ({2e8f44c5-c4e3-4539-b85b-45898bbbf6c2}) of ThingClass alphaConnect</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/alphainnotec/plugininfo.h" line="337"/>
<source>Target room temperature changed</source>
<extracomment>The name of the EventType ({2e8f44c5-c4e3-4539-b85b-45898bbbf6c2}) of ThingClass alphaConnect</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/alphainnotec/plugininfo.h" line="340"/>
<source>alpha Innotec</source>
<extracomment>The name of the vendor ({2c2101ae-7bb8-4012-97ba-cedf4cecd924})</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/alphainnotec/plugininfo.h" line="343"/>
<source>alpha connect</source>
<extracomment>The name of the ThingClass ({c5437b68-cfd2-4ec8-bad6-006fb5e8a8da})</extracomment>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../../../build-nymea-plugins-modbus-Desktop-Debug/alphainnotec/plugininfo.h" line="346"/>
<source>alpha innotec</source>
<extracomment>The name of the plugin AlphaInnotec ({b3225a18-e9b0-443e-8c88-802d3132f94d})</extracomment>
<translation type="unfinished"></translation>
</message>
</context>
<context>
<name>IntegrationPluginAlphaInnotec</name>
<message>
<location filename="../integrationpluginalphainnotec.cpp" line="46"/>
<source>The network device discovery is not available.</source>
<translation type="unfinished"></translation>
</message>
<message>
<location filename="../integrationpluginalphainnotec.cpp" line="103"/>
<source>No IP address given</source>
<translation type="unfinished"></translation>
</message>
</context>
</TS>

15
debian/control vendored
View File

@ -46,6 +46,21 @@ Description: The main libraries and header files for developing with nymea sunsp
.
This package will install the development files for nymea sunspec.
Package: nymea-plugin-alphainnotec
Architecture: any
Section: libs
Depends: ${shlibs:Depends},
${misc:Depends},
nymea-plugins-modbus-translations
Description: nymea.io plugin for alpha innotec heat pumps
The nymea daemon is a plugin based IoT (Internet of Things) server. The
server works like a translator for devices, things and services and
allows them to interact.
With the powerful rule engine you are able to connect any device available
in the system and create individual scenes and behaviors for your environment.
.
This package will install the nymea.io plugin for alpha innotec heat pumps
Package: nymea-plugin-drexelundweiss
Architecture: any

View File

@ -0,0 +1 @@
usr/lib/@DEB_HOST_MULTIARCH@/nymea/plugins/libnymea_integrationpluginalphainnotec.so

268
modbus/modbusdatautils.cpp Normal file
View File

@ -0,0 +1,268 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* 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
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#include "modbusdatautils.h"
#include <QDataStream>
ModbusDataUtils::ModbusDataUtils()
{
}
quint16 ModbusDataUtils::convertToUInt16(const QVector<quint16> &registers)
{
Q_ASSERT_X(registers.count() == 1, "ModbusDataUtils", "invalid raw data size for converting value to quint16");
return registers.at(0);
}
qint16 ModbusDataUtils::convertToInt16(const QVector<quint16> &registers)
{
Q_ASSERT_X(registers.count() == 1, "ModbusDataUtils", "invalid raw data size for converting value to qint16");
return static_cast<qint16>(registers.at(0));
}
quint32 ModbusDataUtils::convertToUInt32(const QVector<quint16> &registers, ByteOrder byteOrder)
{
Q_ASSERT_X(registers.count() == 2, "ModbusDataUtils", "invalid raw data size for converting value to quint32");
QByteArray data;
QDataStream inputStream(&data, QIODevice::WriteOnly);
if (byteOrder == ByteOrderBigEndian) {
inputStream << registers.at(0);
inputStream << registers.at(1);
} else {
inputStream << registers.at(1);
inputStream << registers.at(0);
}
QDataStream outputStream(&data, QIODevice::ReadOnly);
quint32 result = 0;
outputStream >> result;
return result;
}
qint32 ModbusDataUtils::convertToInt32(const QVector<quint16> &registers, ByteOrder byteOrder)
{
Q_ASSERT_X(registers.count() == 2, "ModbusDataUtils", "invalid raw data size for converting value to quint32");
QByteArray data;
QDataStream inputStream(&data, QIODevice::WriteOnly);
if (byteOrder == ByteOrderBigEndian) {
inputStream << registers.at(0);
inputStream << registers.at(1);
} else {
inputStream << registers.at(1);
inputStream << registers.at(0);
}
QDataStream outputStream(&data, QIODevice::ReadOnly);
qint32 result = 0;
outputStream >> result;
return result;
}
quint64 ModbusDataUtils::convertToUInt64(const QVector<quint16> &registers, ByteOrder byteOrder)
{
Q_ASSERT_X(registers.count() == 4, "ModbusDataUtils", "invalid raw data size for converting value to quint64");
QByteArray data;
QDataStream inputStream(&data, QIODevice::WriteOnly);
if (byteOrder == ByteOrderBigEndian) {
inputStream << registers.at(0);
inputStream << registers.at(1);
inputStream << registers.at(2);
inputStream << registers.at(3);
} else {
inputStream << registers.at(3);
inputStream << registers.at(2);
inputStream << registers.at(1);
inputStream << registers.at(0);
}
QDataStream outputStream(&data, QIODevice::ReadOnly);
quint64 result = 0;
outputStream >> result;
return result;
}
qint64 ModbusDataUtils::convertToInt64(const QVector<quint16> &registers, ByteOrder byteOrder)
{
Q_ASSERT_X(registers.count() == 4, "ModbusDataUtils", "invalid raw data size for converting value to qint64");
QByteArray data;
QDataStream inputStream(&data, QIODevice::WriteOnly);
if (byteOrder == ByteOrderBigEndian) {
inputStream << registers.at(0);
inputStream << registers.at(1);
inputStream << registers.at(2);
inputStream << registers.at(3);
} else {
inputStream << registers.at(3);
inputStream << registers.at(2);
inputStream << registers.at(1);
inputStream << registers.at(0);
}
QDataStream outputStream(&data, QIODevice::ReadOnly);
qint64 result = 0;
outputStream >> result;
return result;
}
QString ModbusDataUtils::convertToString(const QVector<quint16> &registers)
{
QByteArray bytes;
QDataStream stream(&bytes, QIODevice::WriteOnly);
for (int i = 0; i < registers.count(); i++) {
stream << registers.at(i);
}
return QString::fromUtf8(bytes).trimmed();
}
float ModbusDataUtils::convertToFloat32(const QVector<quint16> &registers, ByteOrder byteOrder)
{
Q_ASSERT_X(registers.count() == 2, "ModbusDataUtils", "invalid raw data size for converting value to float32");
quint32 rawValue = ModbusDataUtils::convertToUInt32(registers, byteOrder);
float value = 0;
memcpy(&value, &rawValue, sizeof(quint32));
return value;
}
double ModbusDataUtils::convertToFloat64(const QVector<quint16> &registers, ByteOrder byteOrder)
{
Q_ASSERT_X(registers.count() == 4, "ModbusDataUtils", "invalid raw data size for converting value to float64");
quint64 rawValue = ModbusDataUtils::convertToUInt64(registers, byteOrder);
double value = 0;
memcpy(&value, &rawValue, sizeof(quint64));
return value;
}
QVector<quint16> ModbusDataUtils::convertFromUInt16(quint16 value)
{
return QVector<quint16>() << value;
}
QVector<quint16> ModbusDataUtils::convertFromInt16(qint16 value)
{
return ModbusDataUtils::convertFromUInt16(static_cast<quint16>(value));
}
QVector<quint16> ModbusDataUtils::convertFromUInt32(quint32 value, ByteOrder byteOrder)
{
QByteArray data;
QDataStream inputStream(&data, QIODevice::WriteOnly);
inputStream << value;
QDataStream outputStream(&data, QIODevice::ReadOnly);
QVector<quint16> values;
for (int i = 0; i < 2; i++) {
quint16 registerValue = 0;
outputStream >> registerValue;
if (byteOrder == ByteOrderBigEndian) {
values.append(registerValue);
} else {
values.prepend(registerValue);
}
}
return values;
}
QVector<quint16> ModbusDataUtils::convertFromInt32(qint32 value, ByteOrder byteOrder)
{
return ModbusDataUtils::convertFromUInt32(static_cast<quint32>(value), byteOrder);
}
QVector<quint16> ModbusDataUtils::convertFromUInt64(quint64 value, ByteOrder byteOrder)
{
QByteArray data;
QDataStream inputStream(&data, QIODevice::WriteOnly);
inputStream << value;
QDataStream outputStream(&data, QIODevice::ReadOnly);
QVector<quint16> values;
for (int i = 0; i < 4; i++) {
quint16 registerValue = 0;
outputStream >> registerValue;
if (byteOrder == ByteOrderBigEndian) {
values.append(registerValue);
} else {
values.prepend(registerValue);
}
}
return values;
}
QVector<quint16> ModbusDataUtils::convertFromInt64(qint64 value, ByteOrder byteOrder)
{
QByteArray data;
QDataStream inputStream(&data, QIODevice::WriteOnly);
inputStream << value;
QDataStream outputStream(&data, QIODevice::ReadOnly);
QVector<quint16> values;
for (int i = 0; i < 4; i++) {
quint16 registerValue = 0;
outputStream >> registerValue;
if (byteOrder == ByteOrderBigEndian) {
values.append(registerValue);
} else {
values.prepend(registerValue);
}
}
return values;
}
QVector<quint16> ModbusDataUtils::convertFromString(const QString &value, quint16 stringLength)
{
Q_ASSERT_X(value.length() <= stringLength, "ModbusDataUtils", "cannot convert a string which is bigger than the desired register vector.");
QByteArray data = value.toLatin1() + QByteArray('\0', stringLength - value.count());
QDataStream stream(&data, QIODevice::ReadOnly);
QVector<quint16> values;
for (int i = 0; i < stringLength; i++) {
quint16 registerValue = 0;
stream >> registerValue;
values.append(registerValue);
}
return values;
}
QVector<quint16> ModbusDataUtils::convertFromFloat32(float value, ByteOrder byteOrder)
{
quint32 rawValue = 0;
memcpy(&rawValue, &value, sizeof(float));
return ModbusDataUtils::convertFromUInt32(rawValue, byteOrder);
}
QVector<quint16> ModbusDataUtils::convertFromFloat64(double value, ByteOrder byteOrder)
{
quint64 rawValue = 0;
memcpy(&rawValue, &value, sizeof(double));
return ModbusDataUtils::convertFromUInt64(rawValue, byteOrder);
}

107
modbus/modbusdatautils.h Normal file
View File

@ -0,0 +1,107 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
* 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
*
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
#ifndef MODBUSDATAUTILS_H
#define MODBUSDATAUTILS_H
#include <QVector>
#include <QObject>
class ModbusDataUtils
{
Q_GADGET
public:
enum Access {
AccessReadOnly,
AccessWriteOnly,
AccessReadWrite
};
Q_ENUM(Access)
enum ByteOrder {
ByteOrderLittleEndian,
ByteOrderBigEndian
};
Q_ENUM(ByteOrder)
enum DataType {
UInt8,
UInt16,
Uint32,
Uint64,
Int8,
Int16,
Int32,
Int64,
Float,
Float64,
String,
Bool
};
Q_ENUM(DataType)
typedef struct ModbusRegister {
quint16 address;
quint16 size;
DataType dataType;
Access access;
QString description;
QString unit;
QVector<quint16> rawData;
} ModbusRegister;
typedef QVector<ModbusRegister> ModbusRegisters;
explicit ModbusDataUtils();
// Convert to
static quint16 convertToUInt16(const QVector<quint16> &registers);
static qint16 convertToInt16(const QVector<quint16> &registers);
static quint32 convertToUInt32(const QVector<quint16> &registers, ByteOrder byteOrder = ByteOrderLittleEndian);
static qint32 convertToInt32(const QVector<quint16> &registers, ByteOrder byteOrder = ByteOrderLittleEndian);
static quint64 convertToUInt64(const QVector<quint16> &registers, ByteOrder byteOrder = ByteOrderLittleEndian);
static qint64 convertToInt64(const QVector<quint16> &registers, ByteOrder byteOrder = ByteOrderLittleEndian);
static QString convertToString(const QVector<quint16> &registers);
static float convertToFloat32(const QVector<quint16> &registers, ByteOrder byteOrder = ByteOrderLittleEndian);
static double convertToFloat64(const QVector<quint16> &registers, ByteOrder byteOrder = ByteOrderLittleEndian);
// Convert from
static QVector<quint16> convertFromUInt16(quint16 value);
static QVector<quint16> convertFromInt16(qint16 value);
static QVector<quint16> convertFromUInt32(quint32 value, ByteOrder byteOrder = ByteOrderLittleEndian);
static QVector<quint16> convertFromInt32(qint32 value, ByteOrder byteOrder = ByteOrderLittleEndian);
static QVector<quint16> convertFromUInt64(quint64 value, ByteOrder byteOrder = ByteOrderLittleEndian);
static QVector<quint16> convertFromInt64(qint64 value, ByteOrder byteOrder = ByteOrderLittleEndian);
static QVector<quint16> convertFromString(const QString &value, quint16 stringLength);
static QVector<quint16> convertFromFloat32(float value, ByteOrder byteOrder = ByteOrderLittleEndian);
static QVector<quint16> convertFromFloat64(double value, ByteOrder byteOrder = ByteOrderLittleEndian);
};
#endif // MODBUSDATAUTILS_H

139
modbus/tools/README.md Normal file
View File

@ -0,0 +1,139 @@
# Generate a modbus read class
In order to make the plugin development for modbus TCP devices much easier and faster, a small tool has been developed to generate a modbus TCP master based class providing get and set methods for the registers and property changed signals.
The workflow looks like this:
* Write the `registers.json` file containing all register information you are interested to.
* Run the script and provide the class name, output directory and the path to the JSON file
* Include the generated class in your plugin, connect the `<propertyName>Changed()` signal and update the thing state within the plugin.
The class will provide 2 main methods for fetching information from the modbus device:
* `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.
# JSON format
The basic structure of the modbus register JSON looks like following example:
```
{
"endianness": "BigEndian",
"enums": [
{
"name": "NameOfEnum",
"values": [
{
"key": "EnumValue1",
"value": 0
},
{
"key": "EnumValue2",
"value": 1
},
....
]
}
],
"registers": [
{
"id": "registerPropertyName",
"address": 4,
"size": 1,
"type": "uint16",
"readSchedule": "init",
"description": "Description of the register",
"unit": "V",
"defaultValue": "0",
"access": "RO"
},
{
"id": "registerWithEnumValues",
"address": 5,
"size": 1,
"type": "uint16",
"readSchedule": "update",
"enum": "NameOfEnum",
"defaultValue": "NameOfEnumEnumValue1",
"description": "Description of the enum register like states",
"access": "RO"
},
...
]
}
```
## 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 endiness 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>`.
If a register represets an enum, you simply add the property `"enum": "NameOfEnum"` in the register map and the property will be defined using the resulting enum type. All convertion between enum and resulting modbus register value will be done automatically.
## Registers
Earch register will be defined as a property in the resulting class modbus TCP class providing easy access to the register data.
* `id`: Mandatory. The id defines the name of the property used in the resulting class.
* `address`: Mandatory. The modbus address of the register.
* `size`: Mandatory. The amount of registers to read for the property.
* `type`: Mandatory. The data type of this property. Available data types are:
* `uint16` : will be converted to `quint16`
* `int16` : will be converted to `qint16`
* `uint32` : will be converted to `quint32`
* `int32` : will be converted to `qint32`
* `uint64` : will be converted to `quint64`
* `int64` : will be converted to `qint64`
* `float`: will be converted to `float`
* `float64`: will be converted to `double`
* `string` : will be converted to `QString`
* `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:
* `init`: The register will be fetched during initialization. Once all `init `registers have been fetched, the `initializationFinished()` signal will be emitted.
* `update`: The register will be feched each time the `update()` method will be called.
* `enum`: Optional: If the given data type represents an enum value, this propery can be set to the name of the used enum from the `enum` definition. The class will take care internally about the data convertion from and to the enum values.
* `description`: Mandatory. A clear description of the register.
* `unit`: Optional. Represents the unit of this register value.
* `registerType`: Optional. Represents the type of the register and how to read/write it. Default is `holdingRegister`. Possible values are:
* `holdingRegister`
* `inputRegister`
* `coils`
* `discreteInputs`
* `access`: Mandatory. Describes the access to this register. Possible valies are:
* `RO`: Read only access. Only the get method and the changed singal will be defined.
* `RW`: Read and write access. Also a set mehtod will be defined.
* `WO`: Write only. Only the set method will be defined.
* `scaleFactor`: Optional. The name of the scale factor register to convert this value to float. `floatValue = intValue * 10^scaleFactor value`. The scale factor value is normally a `int16` value, i.e. -10 or 10
* `staticScaleFactor`: Optional. Use this static scale factor to convert this register value to float. `floatValue = registerValue * 10^staticScaleFactor`. The scale factor value is normally a `int16` value, i.e. -10 or 10
* `defaultValue`: Optional. The value for initializing the property.
# Example
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.

View File

@ -0,0 +1,686 @@
#!/usr/bin/env python3
# Copyright (C) 2021 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 shutil
import argparse
import datetime
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()
#print('--> words', words)
finalWords = []
for i in range(len(words)):
camelCaseSplit = splitCamelCase(words[i])
if len(camelCaseSplit) == 0:
finalWords.append(words[i])
else:
#print('--> camel 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:])
#print('Convert camel case:', text, '-->', finalText)
return finalText
def loadJsonFile(filePath):
print('--> Loading JSON file', 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)
def writeEnumDefinition(fileDescriptor, enumDefinition):
print('Writing enum', 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), ModbusDataUtils::ByteOrder%s)' % (propertyTyp, propertyName, endianness))
elif registerDefinition['type'] == 'int32':
return ('ModbusDataUtils::convertFromInt32(static_cast<%s>(%s), ModbusDataUtils::ByteOrder%s)' % (propertyTyp, propertyName, endianness))
# 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)), ModbusDataUtils::ByteOrder%s)' % (propertyTyp, propertyName, scaleFactorProperty, endianness))
elif registerDefinition['type'] == 'int32':
return ('ModbusDataUtils::convertFromInt32(static_cast<%s>(%s * 1.0 / pow(10, %s)), ModbusDataUtils::ByteOrder%s)' % (propertyTyp, propertyName, scaleFactorProperty, endianness))
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)), ModbusDataUtils::ByteOrder%s)' % (propertyTyp, propertyName, scaleFactor, endianness))
elif registerDefinition['type'] == 'int32':
return ('ModbusDataUtils::convertFromInt32(static_cast<%s>(%s * 1.0 / pow(10, %s)), ModbusDataUtils::ByteOrder%s)' % (propertyTyp, propertyName, scaleFactor, endianness))
# 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, ModbusDataUtils::ByteOrder%s)' % (propertyName, endianness))
elif registerDefinition['type'] == 'int32':
return ('ModbusDataUtils::convertFromInt32(%s, ModbusDataUtils::ByteOrder%s)' % (propertyName, endianness))
elif registerDefinition['type'] == 'uint64':
return ('ModbusDataUtils::convertFromUInt64(%s, ModbusDataUtils::ByteOrder%s)' % (propertyName, endianness))
elif registerDefinition['type'] == 'int64':
return ('ModbusDataUtils::convertFromInt64(%s, ModbusDataUtils::ByteOrder%s)' % (propertyName, endianness))
elif registerDefinition['type'] == 'float':
return ('ModbusDataUtils::convertFromFloat32(%s, ModbusDataUtils::ByteOrder%s)' % propertyName, endianness)
elif registerDefinition['type'] == 'float64':
return ('ModbusDataUtils::convertFromFloat64(%s, ModbusDataUtils::ByteOrder%s)' % propertyName, endianness)
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(unit.values()))' % (enumName))
elif registerDefinition['type'] == 'int16':
return ('static_cast<%s>(ModbusDataUtils::convertToInt16(unit.values()))' % (enumName))
elif registerDefinition['type'] == 'uint32':
return ('static_cast<%s>(ModbusDataUtils::convertToUInt32(unit.values(), ModbusDataUtils::ByteOrder%s))' % (enumName, endianness))
elif registerDefinition['type'] == 'int32':
return ('static_cast<%s>(ModbusDataUtils::convertToInt32(unit.values(), ModbusDataUtils::ByteOrder%s))' % (enumName, endianness))
# Handle scale factors
if 'scaleFactor' in registerDefinition:
scaleFactorProperty = 'm_%s' % registerDefinition['scaleFactor']
if registerDefinition['type'] == 'uint16':
return ('ModbusDataUtils::convertToUInt16(unit.values()) * 1.0 * pow(10, %s)' % (scaleFactorProperty))
elif registerDefinition['type'] == 'int16':
return ('ModbusDataUtils::convertToInt16(unit.values()) * 1.0 * pow(10, %s)' % (scaleFactorProperty))
elif registerDefinition['type'] == 'uint32':
return ('ModbusDataUtils::convertToUInt32(unit.values(), ModbusDataUtils::ByteOrder%s) * 1.0 * pow(10, %s)' % (endianness, scaleFactorProperty))
elif registerDefinition['type'] == 'int32':
return ('ModbusDataUtils::convertToInt32(unit.values(), ModbusDataUtils::ByteOrder%s) * 1.0 * pow(10, %s)' % (endianness, scaleFactorProperty))
elif 'staticScaleFactor' in registerDefinition:
scaleFactor = registerDefinition['staticScaleFactor']
if registerDefinition['type'] == 'uint16':
return ('ModbusDataUtils::convertToUInt16(unit.values()) * 1.0 * pow(10, %s)' % (scaleFactor))
elif registerDefinition['type'] == 'int16':
return ('ModbusDataUtils::convertToInt16(unit.values()) * 1.0 * pow(10, %s)' % (scaleFactor))
elif registerDefinition['type'] == 'uint32':
return ('ModbusDataUtils::convertToUInt32(unit.values(), ModbusDataUtils::ByteOrder%s) * 1.0 * pow(10, %s)' % (endianness, scaleFactor))
elif registerDefinition['type'] == 'int32':
return ('ModbusDataUtils::convertToInt32(unit.values(), ModbusDataUtils::ByteOrder%s) * 1.0 * pow(10, %s)' % (endianness, scaleFactor))
# Handle default types
elif registerDefinition['type'] == 'uint16':
return ('ModbusDataUtils::convertToUInt16(unit.values())')
elif registerDefinition['type'] == 'int16':
return ('ModbusDataUtils::convertToInt16(unit.values())')
elif registerDefinition['type'] == 'uint32':
return ('ModbusDataUtils::convertToUInt32(unit.values(), ModbusDataUtils::ByteOrder%s)' % endianness)
elif registerDefinition['type'] == 'int32':
return ('ModbusDataUtils::convertToInt32(unit.values(), ModbusDataUtils::ByteOrder%s)' % endianness)
elif registerDefinition['type'] == 'uint64':
return ('ModbusDataUtils::convertToUInt64(unit.values(), ModbusDataUtils::ByteOrder%s)' % endianness)
elif registerDefinition['type'] == 'int64':
return ('ModbusDataUtils::convertToInt64(unit.values(), ModbusDataUtils::ByteOrder%s)' % endianness)
elif registerDefinition['type'] == 'float':
return ('ModbusDataUtils::convertToFloat32(unit.values(), ModbusDataUtils::ByteOrder%s)' % endianness)
elif registerDefinition['type'] == 'float64':
return ('ModbusDataUtils::convertToFloat64(unit.values(), ModbusDataUtils::ByteOrder%s)' % endianness)
elif registerDefinition['type'] == 'string':
return ('ModbusDataUtils::convertToString(unit.values())')
def writePropertyGetSetMethodDeclarations(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 writePropertyGetSetMethodImplementations(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']))
# TODO: other write methods
writeLine(fileDescriptor, ' request.setValues(values);')
writeLine(fileDescriptor, ' return sendWriteRequest(request, m_slaveId);')
writeLine(fileDescriptor, '}')
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 writePropertyUpdateMethodImplementations(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']))
# FIXME: introduce bool and check register type for parsing
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, ' });')
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 writeInternalPropertyReadMethodDeclarations(fileDescriptor, registerDefinitions):
for registerDefinition in registerDefinitions:
propertyName = registerDefinition['id']
writeLine(fileDescriptor, ' QModbusReply *read%s();' % (propertyName[0].upper() + propertyName[1:]))
def writeInternalPropertyReadMethodImplementations(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 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 writePrivatePropertyMembers(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 writeInitializeMethod(fileDescriptor, className, registerDefinitions):
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
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, ' }')
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, &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, ' %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)
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, ' }')
else:
writeLine(fileDescriptor, ' // No init registers defined. Nothing to be done and we are finished.')
writeLine(fileDescriptor, ' emit initializationFinished();')
writeLine(fileDescriptor, '}')
writeLine(fileDescriptor)
def writeUpdateMethod(fileDescriptor, className, registerDefinitions):
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:]))
writeLine(fileDescriptor, '}')
writeLine(fileDescriptor)
############################################################################################
# Main
############################################################################################
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('-c', '--class-name', metavar='<name>', help='The name of the resulting class.')
args = parser.parse_args()
registerJson = loadJsonFile(args.json)
scriptPath = os.path.dirname(os.path.realpath(sys.argv[0]))
outputDirectory = os.path.realpath(args.output_directory)
className = args.class_name
headerFileName = className.lower() + '.h'
sourceFileName = className.lower() + '.cpp'
headerFilePath = os.path.join(outputDirectory, headerFileName)
sourceFilePath = os.path.join(outputDirectory, sourceFileName)
print('Scrip path: %s' % scriptPath)
print('Output directory: %s' % outputDirectory)
print('Class name: %s' % className)
print('Header file: %s' % headerFileName)
print('Source file: %s' % sourceFileName)
print('Header file path: %s' % headerFilePath)
print('Source file path: %s' % sourceFilePath)
endianness = 'BigEndian'
if 'endianness' in registerJson:
endianness = registerJson['endianness']
#############################################################################
# Write header file
#############################################################################
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 "../modbus/modbusdatautils.h"')
writeLine(headerFile, '#include "../modbus/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:')
# Enum declarations
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)
# Write registers get method declarations
writePropertyGetSetMethodDeclarations(headerFile, registerJson['registers'])
# Write init and update method declarations
writeLine(headerFile, ' virtual void initialize();')
writeLine(headerFile, ' virtual void update();')
writeLine(headerFile)
writePropertyUpdateMethodDeclarations(headerFile, registerJson['registers'])
writeLine(headerFile)
# Write registers value changed signals
writeLine(headerFile, 'signals:')
writeLine(headerFile, ' void initializationFinished();')
writeLine(headerFile)
writePropertyChangedSignals(headerFile, registerJson['registers'])
writeLine(headerFile)
# Private members
writeLine(headerFile, 'private:')
writeLine(headerFile, ' quint16 m_slaveId = 1;')
writeLine(headerFile, ' QVector<QModbusReply *> m_pendingInitReplies;')
writeLine(headerFile)
writePrivatePropertyMembers(headerFile, registerJson['registers'])
writeLine(headerFile)
writeLine(headerFile, ' void verifyInitFinished();')
writeLine(headerFile)
writeInternalPropertyReadMethodDeclarations(headerFile, registerJson['registers'])
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()
#############################################################################
# Write source file
#############################################################################
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)
# Property get methods
writePropertyGetSetMethodImplementations(sourceFile, className, registerJson['registers'])
# Write init and update method implementation
writeInitializeMethod(sourceFile, className, registerJson['registers'])
writeUpdateMethod(sourceFile, className, registerJson['registers'])
# Write update methods
writePropertyUpdateMethodImplementations(sourceFile, className, registerJson['registers'])
# Write property read method implementations
writeInternalPropertyReadMethodImplementations(sourceFile, className, registerJson['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))
for registerDefinition in registerJson['registers']:
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(sourceFile, ' debug.nospace().noquote() << %s << "\\n";' % (line))
writeLine(sourceFile, ' return debug.quote().space();')
writeLine(sourceFile, '}')
writeLine(sourceFile)
sourceFile.close()

View File

@ -5,6 +5,7 @@ CONFIG += ordered
SUBDIRS += libnymea-sunspec
PLUGIN_DIRS = \
alphainnotec \
drexelundweiss \
energymeters \
modbuscommander \