diff --git a/idm/idm-registers.json b/idm/idm-registers.json
new file mode 100644
index 0000000..790ea64
--- /dev/null
+++ b/idm/idm-registers.json
@@ -0,0 +1,247 @@
+{
+ "className": "Idm",
+ "protocol": "TCP",
+ "endianness": "LittleEndian",
+ "errorLimitUntilNotReachable": 20,
+ "checkReachableRegister": "outdoorTemperature",
+ "enums": [
+ {
+ "name": "SystemOperationMode",
+ "values": [
+ {
+ "key": "Standby",
+ "value": 0
+ },
+ {
+ "key": "Automatic",
+ "value": 1
+ },
+ {
+ "key": "Absent",
+ "value": 2
+ },
+ {
+ "key": "WarmWaterOnly",
+ "value": 4
+ },
+ {
+ "key": "HeatingCoolingOnly",
+ "value": 5
+ }
+ ]
+ },
+ {
+ "name": "HeatPumpOperationMode",
+ "values": [
+ {
+ "key": "Off",
+ "value": 0
+ },
+ {
+ "key": "Heating",
+ "value": 1
+ },
+ {
+ "key": "Cooling",
+ "value": 2
+ },
+ {
+ "key": "HotWater",
+ "value": 4
+ },
+ {
+ "key": "Defrost",
+ "value": 8
+ }
+ ]
+ }
+ ],
+ "blocks": [
+ {
+ "id": "status",
+ "readSchedule": "update",
+ "registers": [
+ {
+ "id": "currentFaultNumber",
+ "address": 1004,
+ "size": 1,
+ "type": "uint16",
+ "registerType": "holdingRegister",
+ "description": "Current fault number",
+ "defaultValue": "0",
+ "access": "RO"
+ },
+ {
+ "id": "systemOperationMode",
+ "address": 1005,
+ "size": 1,
+ "type": "uint16",
+ "registerType": "holdingRegister",
+ "description": "Operation mode",
+ "enum": "SystemOperationMode",
+ "defaultValue": "SystemOperationModeStandby",
+ "access": "RO"
+ },
+ {
+ "id": "smartGridStatus",
+ "address": 1006,
+ "size": 1,
+ "type": "uint16",
+ "registerType": "holdingRegister",
+ "description": "Smart grid status",
+ "defaultValue": "0",
+ "access": "RO"
+ }
+ ]
+ },
+ {
+ "id": "energyProduced",
+ "readSchedule": "update",
+ "registers": [
+ {
+ "id": "energyHeating",
+ "address": 1750,
+ "size": 2,
+ "type": "float",
+ "registerType": "holdingRegister",
+ "description": "Energy heating",
+ "unit": "kWh",
+ "defaultValue": "0",
+ "access": "RO"
+ },
+ {
+ "id": "energyCooling",
+ "address": 1752,
+ "size": 2,
+ "type": "float",
+ "registerType": "holdingRegister",
+ "description": "Energy cooling",
+ "unit": "kWh",
+ "defaultValue": "0",
+ "access": "RO"
+ },
+ {
+ "id": "energyHotWater",
+ "address": 1754,
+ "size": 2,
+ "type": "float",
+ "registerType": "holdingRegister",
+ "description": "Energy hot water",
+ "unit": "kWh",
+ "defaultValue": "0",
+ "access": "RO"
+ }
+ ]
+ }
+ ],
+ "registers": [
+ {
+ "id": "currentPvSurplus",
+ "address": 74,
+ "size": 2,
+ "type": "float",
+ "registerType": "holdingRegister",
+ "readSchedule": "update",
+ "description": "Current PV surplus ",
+ "unit": "kW",
+ "defaultValue": "0",
+ "access": "RW"
+ },
+ {
+ "id": "currentPvProduction",
+ "address": 78,
+ "size": 2,
+ "type": "float",
+ "registerType": "holdingRegister",
+ "readSchedule": "update",
+ "description": "Current PV production ",
+ "unit": "kW",
+ "defaultValue": "0",
+ "access": "RW"
+ },
+ {
+ "id": "outdoorTemperature",
+ "address": 1000,
+ "size": 2,
+ "type": "float",
+ "readSchedule": "update",
+ "registerType": "holdingRegister",
+ "description": "Outdoor temperature",
+ "unit": "°C",
+ "defaultValue": "0",
+ "access": "RO"
+ },
+ {
+ "id": "heatStorageTemperature",
+ "address": 1008,
+ "size": 2,
+ "type": "float",
+ "registerType": "holdingRegister",
+ "readSchedule": "update",
+ "description": "Heat storage temperature",
+ "defaultValue": "0",
+ "unit": "°C",
+ "access": "RO"
+ },
+ {
+ "id": "targetHotWaterTemperature",
+ "address": 1032,
+ "size": 1,
+ "type": "uint16",
+ "registerType": "holdingRegister",
+ "readSchedule": "update",
+ "description": "Target hot water temperature",
+ "defaultValue": "0",
+ "unit": "°C",
+ "access": "RO"
+ },
+ {
+ "id": "roomTemperature",
+ "address": 1364,
+ "size": 2,
+ "type": "float",
+ "readSchedule": "update",
+ "registerType": "holdingRegister",
+ "description": "Room temperature",
+ "defaultValue": "0",
+ "unit": "°C",
+ "access": "RO"
+ },
+ {
+ "id": "roomTemperatureTargetHeatingEco",
+ "address": 1415,
+ "size": 2,
+ "type": "float",
+ "readSchedule": "update",
+ "registerType": "holdingRegister",
+ "description": "Room target temperature",
+ "defaultValue": "0",
+ "unit": "°C",
+ "access": "RW"
+ },
+ {
+ "id": "heatPumpOperatingMode",
+ "address": 1090,
+ "size": 1,
+ "type": "uint16",
+ "registerType": "holdingRegister",
+ "readSchedule": "update",
+ "description": "Heat pump operation mode",
+ "enum": "HeatPumpOperationMode",
+ "defaultValue": "HeatPumpOperationModeOff",
+ "access": "RO"
+ },
+ {
+ "id": "currentPowerConsumption",
+ "address": 4122,
+ "size": 2,
+ "type": "float",
+ "readSchedule": "update",
+ "registerType": "holdingRegister",
+ "description": "Current power consumption",
+ "unit": "kW",
+ "defaultValue": "0",
+ "access": "RO"
+ }
+ ]
+}
diff --git a/idm/idm.cpp b/idm/idm.cpp
deleted file mode 100644
index 9ea769e..0000000
--- a/idm/idm.cpp
+++ /dev/null
@@ -1,194 +0,0 @@
-/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
-*
-* 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 .
-*
-* 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 "idm.h"
-#include "extern-plugininfo.h"
-#include "modbushelpers.h"
-
-#include
-
-Idm::Idm(const QHostAddress &address, QObject *parent) :
- QObject(parent),
- m_hostAddress(address)
-{
- qCDebug(dcIdm()) << "iDM: Creating iDM connection" << m_hostAddress.toString();
- m_modbusMaster = new ModbusTCPMaster(address, 502, this);
- connect(m_modbusMaster, &ModbusTCPMaster::receivedHoldingRegister, this, &Idm::onReceivedHoldingRegister);
- connect(m_modbusMaster, &ModbusTCPMaster::readRequestError, this, &Idm::onModbusError);
- connect(m_modbusMaster, &ModbusTCPMaster::writeRequestError, this, &Idm::onModbusError);
- connect(m_modbusMaster, &ModbusTCPMaster::writeRequestExecuted, this, &Idm::writeRequestExecuted);
-}
-
-Idm::~Idm()
-{
- qCDebug(dcIdm()) << "iDM: Deleting iDM connection" << m_hostAddress.toString();
-}
-
-bool Idm::connectDevice()
-{
- qCDebug(dcIdm()) << "iDM: Connecting device";
- return m_modbusMaster->connectDevice();
-}
-
-QHostAddress Idm::address() const
-{
- return m_hostAddress;
-}
-
-void Idm::getStatus()
-{
- // This request starts an update cycle
- m_modbusMaster->readHoldingRegister(Idm::modbusUnitID, Idm::OutsideTemperature, 2);
-}
-
-QUuid Idm::setTargetTemperature(double targetTemperature)
-{
- QVector value = ModbusHelpers::convertFloatToRegister(targetTemperature);
- return m_modbusMaster->writeHoldingRegisters(Idm::modbusUnitID, Idm::RegisterList::RoomTemperatureTargetHeatingEcoHKA, value);
-}
-
-void Idm::onReceivedHoldingRegister(int slaveAddress, int modbusRegister, const QVector &value)
-{
- Q_UNUSED(slaveAddress);
- /* qCDebug(dcIdm()) << "receivedHoldingRegister " << modbusRegister << "(length: " << value.length() << ")"; */
-
- switch (modbusRegister) {
- case Idm::OutsideTemperature:
- /* qCDebug(dcIdm()) << "received outside temperature"; */
- if (value.length() == 2) {
- m_idmInfo.outsideTemperature = ModbusHelpers::convertRegisterToFloat(&value[RegisterList::OutsideTemperature - modbusRegister]);
- }
- QTimer::singleShot(200, this, [this] {
- m_modbusMaster->readHoldingRegister(Idm::modbusUnitID, Idm::CurrentFaultNumber, 1);
- });
- break;
- case Idm::CurrentFaultNumber:
- /* qCDebug(dcIdm()) << "current fault number"; */
- if (value.length() == 1) {
- if (value[0] > 0) {
- m_idmInfo.error = true;
- } else {
- m_idmInfo.error = false;
- }
- }
- QTimer::singleShot(200, this, [this] {
- m_modbusMaster->readHoldingRegister(Idm::modbusUnitID, Idm::HeatStorageTemperature, 2);
- });
- break;
- case Idm::HeatStorageTemperature:
- /* qCDebug(dcIdm()) << "received storage temperature"; */
- if (value.length() == 2) {
- m_idmInfo.waterTemperature = ModbusHelpers::convertRegisterToFloat(&value[RegisterList::HeatStorageTemperature - modbusRegister]);
- }
- QTimer::singleShot(200, this, [this] {
- m_modbusMaster->readHoldingRegister(Idm::modbusUnitID, Idm::TargetHotWaterTemperature, 1);
- });
- break;
- case Idm::TargetHotWaterTemperature:
- /* qCDebug(dcIdm()) << "received target hot water temperature"; */
- if (value.length() == 1) {
- /* The hot water target temperature is stored as UCHAR (manual p. 13) */
- m_idmInfo.targetWaterTemperature = (double)value[RegisterList::TargetHotWaterTemperature - modbusRegister];
- }
- QTimer::singleShot(200, this, [this] {
- m_modbusMaster->readHoldingRegister(Idm::modbusUnitID, Idm::HeatPumpOperatingMode, 1);
- });
- break;
- case Idm::HeatPumpOperatingMode:
- /* qCDebug(dcIdm()) << "received heat pump operating mode"; */
- if (value.length() == 1) {
- m_idmInfo.mode = heatPumpOperationModeToString((Idm::IdmHeatPumpMode)value[RegisterList::HeatPumpOperatingMode-modbusRegister]);
- }
- QTimer::singleShot(200, this, [this] {
- m_modbusMaster->readHoldingRegister(Idm::modbusUnitID, Idm::RoomTemperatureHKA, 2);
- });
- break;
- case Idm::RoomTemperatureHKA:
- /* qCDebug(dcIdm()) << "received room temperature hka"; */
- if (value.length() == 2) {
- m_idmInfo.roomTemperature = ModbusHelpers::convertRegisterToFloat(&value[RegisterList::RoomTemperatureHKA - modbusRegister]);
- }
- QTimer::singleShot(200, this, [this] {
- m_modbusMaster->readHoldingRegister(Idm::modbusUnitID, Idm::RoomTemperatureTargetHeatingEcoHKA, 2);
- });
- break;
- case Idm::RoomTemperatureTargetHeatingEcoHKA:
- /* qCDebug(dcIdm()) << "received room temprature hka eco"; */
- if (value.length() == 2) {
- m_idmInfo.targetRoomTemperature = ModbusHelpers::convertRegisterToFloat(&value[RegisterList::RoomTemperatureTargetHeatingEcoHKA - modbusRegister]);
- }
- QTimer::singleShot(200, this, [this] {
- m_modbusMaster->readHoldingRegister(Idm::modbusUnitID, Idm::CurrentPowerConsumptionHeatPump, 2);
- });
- break;
- case Idm::CurrentPowerConsumptionHeatPump:
- /* qCDebug(dcIdm()) << "received power consumption heat pump"; */
- if (value.length() == 2) {
- m_idmInfo.powerConsumptionHeatPump = ModbusHelpers::convertRegisterToFloat(&value[RegisterList::CurrentPowerConsumptionHeatPump - modbusRegister]);
- }
-
- /* Everything read without an error
- * -> set connected to true */
- m_idmInfo.connected = true;
- emit statusUpdated(m_idmInfo);
- break;
- }
-}
-
-void Idm::onModbusError()
-{
- qCDebug(dcIdm()) << "iDM: Received modbus error" << m_modbusMaster->errorString();
- m_idmInfo.connected = false;
- emit statusUpdated(m_idmInfo);
-}
-
-QString Idm::heatPumpOperationModeToString(IdmHeatPumpMode mode)
-{
- QString result{};
- /* Operation modes according to table of manual p. 14 */
- switch (mode) {
- case IdmHeatPumpModeOff:
- result = "Off";
- break;
- case IdmHeatPumpModeHeating:
- result = "Heating";
- break;
- case IdmHeatPumpModeCooling:
- result = "Cooling";
- break;
- case IdmHeatPumpModeHotWater:
- result = "Hot water";
- break;
- case IdmHeatPumpModeDefrost:
- result = "Defrost";
- break;
- }
- return result;
-}
diff --git a/idm/idm.h b/idm/idm.h
deleted file mode 100644
index 7c78d21..0000000
--- a/idm/idm.h
+++ /dev/null
@@ -1,183 +0,0 @@
-/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
-*
-* 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 .
-*
-* 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 IDM_H
-#define IDM_H
-
-#include
-
-#include
-
-#include "idminfo.h"
-
-/*
- * Functionality:
- * The current version allows read access to selected
- * modbus registers:
- * + Room temperature (HK A)
- * + Water temperature
- * + Outside air temperature
- * + Target room temperature eco mode (HK A)
- * + Target water temperature
- * + Current power consumption
- * + Operation mode
- * + Error
- *
- * At present there is no write access for target
- * room temperature and target water temperature. These
- * result in an "invalid data access" error from the
- * device.
- */
-
-/* Note: It would be desirable to read the modbus registers
- * of the Idm heat pump in groups to minimize the number
- * of read requests. However, a maximum of 6 registers
- * can be read simultaneously. With the given set of
- * addresses it is not possible to reasonably group the
- * registers, therefore they are read individually.
- */
-
-class Idm : public QObject
-{
- Q_OBJECT
-public:
- explicit Idm(const QHostAddress &address, QObject *parent = nullptr);
- ~Idm();
-
- bool connectDevice();
- QHostAddress address() const;
- QUuid setTargetTemperature(double targetTemperature);
- void getStatus();
-
-private:
- /** Modbus Unit ID of Idm device */
- static const quint16 modbusUnitID = 1;
-
- enum IscModus {
- KeineAbwarme = 0,
- Heizung = 1,
- Warmwasser = 4,
- Warmequelle = 8,
- };
-
- /** System operation modes according to manual p. 13 */
- enum IdmSysMode {
- IdmSysModeStandby = 0,
- IdmSysModeAutomatic = 1,
- IdmSysModeAway = 2,
- IdmSysModeOnlyHotwater = 4,
- IdmSysModeOnlyRoomHeating = 5
- };
-
- /** Heat pump operation modes according to manual p. 14 */
- enum IdmHeatPumpMode {
- IdmHeatPumpModeOff = 0,
- IdmHeatPumpModeHeating = 1,
- IdmHeatPumpModeCooling = 2,
- IdmHeatPumpModeHotWater = 4,
- IdmHeatPumpModeDefrost = 8
- };
-
- /** The following modbus addresses are according to the manual
- * Modbus TCP Navigatorregelung 2.0 pages 13-31.
- * Comments at the end of each line give their original name
- * in the German manual. */
- enum RegisterList {
- OutsideTemperature = 1000, // Außentemperatur (B31)
- MeanOutsideTemperature = 1002, // Gemittelte Außentemperature
- CurrentFaultNumber = 1004, // Aktuelle Störungsnummer
- OperationModeSystem = 1005, // Betriebsart System
- SmartGridStatus = 1006, // Smart Grid Status
- HeatStorageTemperature = 1008, // Wärmespeichertemperatur (B38)
- ColdStorageTemperature = 1010, // Kältespeichertemperatur (B40)
- DrinkingWaterHeaterTempBottom = 1012, // Trinkwassererwärmertmp. unten (B41)
- DrinkingWaterHeaterTempTop = 1014, // Trinkwassererwärmertmp. oben (B48)
- HotWaterTapTemperature = 1030, // Warmwasserzapftemperatur (B42)
- TargetHotWaterTemperature = 1032, // Warmwasser-Solltemperatur
- HeatPumpOperatingMode = 1090, // Betriebsart Wärmepumpe
- SummationFaultHeatPump = 1099, // Summenstörung Wärepumpe
- RoomTemperatureHKA = 1364, // Heizkreis A Raumtemperature (B61)
- HumiditySensor = 1392, // Feuchtesensor
- RoomTemperatureTargetHeatingHKA = 1401, // Raumsolltemperatur Heizen Normal HK A
- RoomTemperatureTargetHeatingEcoHKA = 1415, // Raumsolltemperatur Heizen Eco HK A
- ExternalOutsideTemperature = 1690, // Externe Außentemperatur
- ExternalHumidity = 1692, // Externe Feuchte
- ExternalRequestTemperatureHeating = 1694, // Externe Anforderungstemperatur Heizen
- ExternalRequestTemperatureCooling = 1695, // Externe Anforderungstemperatur Kühlen
- HeatingRequirement = 1710, // Anforderung Heizen
- CoolingRequirement = 1711, // Anforderung Kühlen
- HotWaterChargingRequirement = 1712, // Anforderung Warmwasserladung
- HeatQuantityHeating = 1750, // Wärmemenge Heizen
- HeatQuantityCooling = 1752, // Wärmemenge Kühlen
- HeatQuantityHotWater = 1754, // Wärmemenge Warmwasser
- HeatQuantityDefrosting = 1756, // Wärmemenge Abtauung
- HeatQuantityPassiveCooling = 1758, // Wärmemenge Passive Kühlung,
- HeatQuantityPhotovolatics = 1760, // Wärmemenge Solar
- HeatQuantityHeatingElemetn = 1762, // Wärmemenge Elektroheizeinsatz,
- CurrentPower = 1790, // Momentanleistung
- CurrentPowerSolar = 1792, // MomentanleistungSolar
- SolarCollectorTemperature = 1850, // SolarKollektortemperatur (B73)
- SolarCollectorReturnTemperature = 1852, // SolarKollektorruecklauftemperatur (B75)
- SolarChargeTemperature = 1854, // SolarLadetemperatur (B74)
- SolarOperatingMode = 1856, // Betriebsart Solar
- ISCMode = 1875, // ISCModus
- AcknowledgeFaultMessages = 1999, // Störmeldungen quittieren
- TargetRoomTemperatureZ1R1 = 2004, // Zonenmodul 1 Raumsolltemperatur Raum 1
- CurrentPhotovoltaicsSurplus = 74, // Aktueller PV-Überschuss
- CurrentPhotovoltaicsProduction = 78, // Aktueller PV Produktion
- CurrentPowerConsumptionHeatPump = 4122, // Aktuelle Leistungsaufnahme Wärmepumpe
- };
-
- /* Note: This class only requires one IP address and one
- * TCP Modbus connection. Multiple devices are managed
- * within the IntegrationPluginIdm class. */
- QHostAddress m_hostAddress;
-
- /** Pointer to ModbusTCPMaster object, responsible for low-level communicaiton */
- ModbusTCPMaster *m_modbusMaster = nullptr;
-
- /** This structure is allocated within onRequestStatus and filled
- * by the receivedStatusGroupx functions */
- IdmInfo m_idmInfo;
-
- /** Converts a heat pump operation mode code to a string (according to manual p. 14) */
- QString heatPumpOperationModeToString(IdmHeatPumpMode mode);
-
-signals:
- void statusUpdated(const IdmInfo &info);
- void targetRoomTemperatureChanged();
- void writeRequestExecuted(const QUuid &requestId, bool success);
-
-private slots:
- void onModbusError();
- void onReceivedHoldingRegister(int slaveAddress, int modbusRegister, const QVector &value);
-};
-
-#endif // IDM_H
diff --git a/idm/idm.pro b/idm/idm.pro
index d8a1e12..c5c3cc4 100644
--- a/idm/idm.pro
+++ b/idm/idm.pro
@@ -1,14 +1,12 @@
include(../plugins.pri)
+
+# Generate modbus connection
+MODBUS_CONNECTIONS += idm-registers.json
+#MODBUS_TOOLS_CONFIG += VERBOSE
include(../modbus.pri)
SOURCES += \
- idm.cpp \
- integrationpluginidm.cpp \
- modbushelpers.cpp
+ integrationpluginidm.cpp
HEADERS += \
- idm.h \
- idminfo.h \
- integrationpluginidm.h \
- modbushelpers.h
-
+ integrationpluginidm.h
diff --git a/idm/idminfo.h b/idm/idminfo.h
deleted file mode 100644
index 6e8d7f1..0000000
--- a/idm/idminfo.h
+++ /dev/null
@@ -1,79 +0,0 @@
-/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
-*
-* 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 .
-*
-* 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 IDMINFO_H
-#define IDMINFO_H
-
-#include
-#include
-
-/** This struct holds the status information that is read from the IDM device
- * and passed to the nymea framework within this plugin.
- */
-struct IdmInfo {
- /** Set to true, if register values can be read,
- * false in case of communication problems */
- bool connected;
-
- bool power;
-
- /** RegisterList::OutsideTemperature */
- double roomTemperature;
-
- /** RegisterList::ExternalOutsideTemperature */
- double outsideTemperature;
-
- /** RegisterList::HeatStorageTemperature */
- double waterTemperature;
-
- /** RegisterList::TargetRoomTemperatureZ1R1 (zone 1, room 1) */
- double targetRoomTemperature;
-
- /** RegisterList::TargetHotWaterTemperature */
- double targetWaterTemperature;
-
- /** RegisterList::HumiditySensor */
- double humidity;
-
- /** RegisterList::CurrentPowerConsumptionHeatPump */
- double powerConsumptionHeatPump;
-
- /** RegisterList::OperationModeSystem */
- QString mode;
-
- /** True if there is an error code set
- * (RegisterList::CurrentFaultNumber != 0) */
- bool error;
-};
-
-Q_DECLARE_METATYPE(IdmInfo);
-
-#endif
-
diff --git a/idm/integrationpluginidm.cpp b/idm/integrationpluginidm.cpp
index 8913958..b613895 100644
--- a/idm/integrationpluginidm.cpp
+++ b/idm/integrationpluginidm.cpp
@@ -1,6 +1,6 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
-* Copyright 2013 - 2021, nymea GmbH
+* Copyright 2013 - 2022, nymea GmbH
* Contact: contact@nymea.io
*
* This file is part of nymea.
@@ -32,6 +32,7 @@
#include "plugininfo.h"
#include
+#include
IntegrationPluginIdm::IntegrationPluginIdm()
{
@@ -79,7 +80,6 @@ void IntegrationPluginIdm::discoverThings(ThingDiscoveryInfo *info)
ParamList params;
params << Param(navigator2ThingMacAddressParamTypeId, networkDeviceInfo.macAddress());
- params << Param(navigator2ThingIpAddressParamTypeId, networkDeviceInfo.address().toString());
descriptor.setParams(params);
info->addThingDescriptor(descriptor);
}
@@ -90,77 +90,80 @@ void IntegrationPluginIdm::discoverThings(ThingDiscoveryInfo *info)
void IntegrationPluginIdm::setupThing(ThingSetupInfo *info)
{
Thing *thing = info->thing();
- qCDebug(dcIdm()) << "setupThing called" << thing->name();
+ qCDebug(dcIdm()) << "Setup" << thing << thing->params();
+ // Inverter (connection)
if (thing->thingClassId() == navigator2ThingClassId) {
- QHostAddress hostAddress = QHostAddress(thing->paramValue(navigator2ThingIpAddressParamTypeId).toString());
- if (hostAddress.isNull()) {
- qCWarning(dcIdm()) << "Setup failed, IP address not valid";
- info->finish(Thing::ThingErrorInvalidParameter, QT_TR_NOOP("No IP address given"));
- return;
- }
- if (m_idmConnections.contains(thing)) {
- qCDebug(dcIdm()) << "Cleaning up after reconfiguration";
- m_idmConnections.take(thing)->deleteLater();
- }
+ // Handle reconfigure
+ if (m_connections.contains(thing)) {
+ qCDebug(dcIdm()) << "Reconfiguring existing thing" << thing->name();
+ m_connections.take(thing)->deleteLater();
- qCDebug(dcIdm()) << "User entered address: " << hostAddress.toString();
-
- /* Check, if address is already in use for another device */
- foreach (Idm *idm, m_idmConnections) {
- if (hostAddress.isEqual(idm->address())) {
- qCWarning(dcIdm()) << "Address already in use";
- info->finish(Thing::ThingErrorSetupFailed, QT_TR_NOOP("IP address already in use"));
- return;
+ if (m_monitors.contains(thing)) {
+ hardwareManager()->networkDeviceDiscovery()->unregisterMonitor(m_monitors.take(thing));
}
}
- qCDebug(dcIdm()) << "Creating Idm object";
- /* Create new Idm object and store it in hash table */
- Idm *idm = new Idm(hostAddress, this);
- if (idm->connectDevice()) {
- qCWarning(dcIdm()) << "Could not connect to thing";
- info->finish(Thing::ThingErrorHardwareNotAvailable);
+ MacAddress macAddress = MacAddress(thing->paramValue(navigator2ThingMacAddressParamTypeId).toString());
+ if (!macAddress.isValid()) {
+ qCWarning(dcIdm()) << "The configured mac address is not valid" << thing->params();
+ info->finish(Thing::ThingErrorInvalidParameter, QT_TR_NOOP("The MAC address is not known. Please reconfigure the thing."));
return;
}
- connect(idm, &Idm::statusUpdated, info, [info, thing, idm, this] (const IdmInfo &idmInfo) {
- if (idmInfo.connected) {
- m_idmConnections.insert(thing, idm);
- connect(idm, &Idm::statusUpdated, this, &IntegrationPluginIdm::onStatusUpdated);
- connect(idm, &Idm::writeRequestExecuted, this, &IntegrationPluginIdm::onWriteRequestExecuted);
- info->finish(Thing::ThingErrorNoError);
+ // Create the monitor
+ NetworkDeviceMonitor *monitor = hardwareManager()->networkDeviceDiscovery()->registerMonitor(macAddress);
+ m_monitors.insert(thing, monitor);
+
+ QHostAddress address = monitor->networkDeviceInfo().address();
+ if (address.isNull()) {
+ qCWarning(dcIdm()) << "Cannot set up thing. The host address is not known yet. Maybe it will be available in the next run...";
+ hardwareManager()->networkDeviceDiscovery()->unregisterMonitor(m_monitors.take(thing));
+ info->finish(Thing::ThingErrorHardwareFailure, QT_TR_NOOP("The host address is not known yet. Trying later again."));
+ return;
+ }
+
+ // Clean up in case the setup gets aborted
+ connect(info, &ThingSetupInfo::aborted, monitor, [=](){
+ if (m_monitors.contains(thing)) {
+ qCDebug(dcIdm()) << "Unregister monitor because setup has been aborted.";
+ hardwareManager()->networkDeviceDiscovery()->unregisterMonitor(m_monitors.take(thing));
}
});
- connect(idm, &Idm::destroyed, this, [thing, this] {m_idmConnections.remove(thing);});
- connect(info, &ThingSetupInfo::aborted, idm, &Idm::deleteLater);
+ // Wait for the monitor to be ready
+ if (monitor->reachable()) {
+ // Thing already reachable...let's continue with the setup
+ setupConnection(info);
+ } else {
+ qCDebug(dcIdm()) << "Waiting for the network monitor to get reachable before continue to set up the connection" << thing->name() << address.toString() << "...";
+ connect(monitor, &NetworkDeviceMonitor::reachableChanged, info, [=](bool reachable){
+ if (reachable) {
+ qCDebug(dcIdm()) << "The monitor for thing setup" << thing->name() << "is now reachable. Continue setup...";
+ setupConnection(info);
+ }
+ });
+ }
- } else {
- Q_ASSERT_X(false, "setupThing", QString("Unhandled thingClassId: %1").arg(thing->thingClassId().toString()).toUtf8());
+ return;
}
}
void IntegrationPluginIdm::postSetupThing(Thing *thing)
{
- qCDebug(dcIdm()) << "postSetupThing called" << thing->name();
+ Q_UNUSED(thing)
if (!m_refreshTimer) {
qCDebug(dcIdm()) << "Starting refresh timer";
m_refreshTimer = hardwareManager()->pluginTimerManager()->registerTimer(10);
- connect(m_refreshTimer, &PluginTimer::timeout, this, &IntegrationPluginIdm::onRefreshTimer);
- }
+ connect(m_refreshTimer, &PluginTimer::timeout, this, [this](){
+ foreach (IdmModbusTcpConnection *connection, m_connections) {
+ connection->update();
+ }
+ });
- if (thing->thingClassId() == navigator2ThingClassId) {
- Idm *idm = m_idmConnections.value(thing);
- if (!idm) {
- qCWarning(dcIdm()) << "Could not find any iDM connection for" << thing->name();
- return;
- }
-
- thing->setStateValue(navigator2ConnectedStateTypeId, true);
- update(thing);
+ m_refreshTimer->start();
}
}
@@ -169,11 +172,15 @@ void IntegrationPluginIdm::thingRemoved(Thing *thing)
qCDebug(dcIdm()) << "thingRemoved called" << thing->name();
if (thing->thingClassId() == navigator2ThingClassId) {
- if (m_idmConnections.contains(thing)) {
- m_idmConnections.take(thing)->deleteLater();
+ if (m_connections.contains(thing)) {
+ m_connections.take(thing)->deleteLater();
}
}
+ // Unregister related hardware resources
+ if (m_monitors.contains(thing))
+ hardwareManager()->networkDeviceDiscovery()->unregisterMonitor(m_monitors.take(thing));
+
if (myThings().isEmpty()) {
qCDebug(dcIdm()) << "Stopping refresh timer";
hardwareManager()->pluginTimerManager()->unregisterTimer(m_refreshTimer);
@@ -187,15 +194,37 @@ void IntegrationPluginIdm::executeAction(ThingActionInfo *info)
Action action = info->action();
if (thing->thingClassId() == navigator2ThingClassId) {
- Idm *idm = m_idmConnections.value(thing);
- if (!idm) {
- return info->finish(Thing::ThingErrorHardwareFailure);
+ IdmModbusTcpConnection *connection = m_connections.value(thing);
+ if (!connection) {
+ qCWarning(dcIdm()) << "Failed to execute action. Could not find connection for" << thing;
+ info->finish(Thing::ThingErrorHardwareFailure);
+ return;
}
+
+ if (!connection->connected())
+ info->finish(Thing::ThingErrorHardwareNotAvailable);
+
+
if (action.actionTypeId() == navigator2TargetTemperatureActionTypeId) {
- double targetTemperature = thing->stateValue(navigator2TargetTemperatureStateTypeId).toDouble();
- QUuid requestId = idm->setTargetTemperature(targetTemperature);
- m_asyncActions.insert(requestId, info);
- connect(info, &ThingActionInfo::aborted, [requestId, this] (){ m_asyncActions.remove(requestId); });
+ float targetTemperature = action.paramValue(navigator2TargetTemperatureActionTargetTemperatureParamTypeId).toDouble();
+ qCDebug(dcIdm()) << "Setting room target temperature to" << targetTemperature << "°C";
+ QModbusReply *reply = connection->setRoomTemperatureTargetHeatingEco(targetTemperature);
+ if (!reply) {
+ info->finish(Thing::ThingErrorHardwareFailure);
+ return;
+ }
+
+ connect(reply, &QModbusReply::finished, reply, &QModbusReply::deleteLater);
+ connect(reply, &QModbusReply::finished, info, [info, reply, thing, targetTemperature]{
+ if (reply->error() != QModbusDevice::NoError) {
+ info->finish(Thing::ThingErrorHardwareFailure);
+ return;
+ }
+
+ qCDebug(dcIdm()) << "Room target temperature set successfully to" << targetTemperature << "°C";
+ thing->setStateValue(navigator2TargetTemperatureStateTypeId, targetTemperature);
+ info->finish(Thing::ThingErrorNoError);
+ });
} else {
Q_ASSERT_X(false, "executeAction", QString("Unhandled action: %1").arg(action.actionTypeId().toString()).toUtf8());
}
@@ -204,55 +233,144 @@ void IntegrationPluginIdm::executeAction(ThingActionInfo *info)
}
}
-void IntegrationPluginIdm::update(Thing *thing)
+void IntegrationPluginIdm::setupConnection(ThingSetupInfo *info)
{
- if (thing->thingClassId() == navigator2ThingClassId) {
- qCDebug(dcIdm()) << "Updating thing" << thing->name();
- Idm *idm = m_idmConnections.value(thing);
- if (!idm) { return; };
- idm->getStatus();
- }
-}
+ Thing *thing = info->thing();
-void IntegrationPluginIdm::onStatusUpdated(const IdmInfo &info)
-{
- qCDebug(dcIdm()) << "Received status from heat pump";
- Idm *idm = qobject_cast(sender());
- Thing *thing = m_idmConnections.key(idm);
+ QHostAddress address = m_monitors.value(thing)->networkDeviceInfo().address();
- if (!thing)
- return;
+ qCDebug(dcIdm()) << "Setting up IDM on" << address.toString() << 502 << "unit ID:" << 1;
+ IdmModbusTcpConnection *connection = new IdmModbusTcpConnection(address, 502, 1, this);
+ connect(info, &ThingSetupInfo::aborted, connection, &IdmModbusTcpConnection::deleteLater);
- /* Received a structure holding the status info of the
- * heat pump. Update the thing states with the individual fields. */
- thing->setStateValue(navigator2ConnectedStateTypeId, info.connected);
- thing->setStateValue(navigator2PowerStateTypeId, info.power);
- thing->setStateValue(navigator2TemperatureStateTypeId, info.roomTemperature);
- thing->setStateValue(navigator2OutsideAirTemperatureStateTypeId, info.outsideTemperature);
- thing->setStateValue(navigator2WaterTemperatureStateTypeId, info.waterTemperature);
- thing->setStateValue(navigator2TargetTemperatureStateTypeId, info.targetRoomTemperature);
- thing->setStateValue(navigator2TargetWaterTemperatureStateTypeId, info.targetWaterTemperature);
- thing->setStateValue(navigator2CurrentPowerConsumptionHeatPumpStateTypeId, info.powerConsumptionHeatPump);
- thing->setStateValue(navigator2ModeStateTypeId, info.mode);
- thing->setStateValue(navigator2ErrorStateTypeId, info.error);
-}
+ // Reconnect on monitor reachable changed
+ NetworkDeviceMonitor *monitor = m_monitors.value(thing);
+ connect(monitor, &NetworkDeviceMonitor::reachableChanged, thing, [=](bool reachable){
+ qCDebug(dcIdm()) << "Network device monitor reachable changed for" << thing->name() << reachable;
+ if (!thing->setupComplete())
+ return;
-void IntegrationPluginIdm::onWriteRequestExecuted(const QUuid &requestId, bool success)
-{
- if (m_asyncActions.contains(requestId)) {
- ThingActionInfo *info = m_asyncActions.value(requestId);
- if (success) {
- info->finish(Thing::ThingErrorNoError);
- } else {
- info->finish(Thing::ThingErrorHardwareNotAvailable);
+ if (reachable && !thing->stateValue("connected").toBool()) {
+ connection->setHostAddress(monitor->networkDeviceInfo().address());
+ connection->connectDevice();
+ } else if (!reachable) {
+ // Note: We disable autoreconnect explicitly and we will
+ // connect the device once the monitor says it is reachable again
+ connection->disconnectDevice();
}
- }
+ });
+
+ connect(connection, &IdmModbusTcpConnection::reachableChanged, thing, [this, thing, connection](bool reachable){
+ qCDebug(dcIdm()) << "Reachable changed to" << reachable << "for" << thing;
+ if (reachable) {
+ // Connected true will be set after successfull init
+ connection->initialize();
+ } else {
+ thing->setStateValue("connected", false);
+ foreach (Thing *childThing, myThings().filterByParentId(thing->id())) {
+ childThing->setStateValue("connected", false);
+ }
+ }
+ });
+
+ connect(connection, &IdmModbusTcpConnection::initializationFinished, thing, [=](bool success){
+ if (!thing->setupComplete())
+ return;
+
+ thing->setStateValue("connected", success);
+ foreach (Thing *childThing, myThings().filterByParentId(thing->id())) {
+ childThing->setStateValue("connected", success);
+ }
+
+ if (!success) {
+ // Try once to reconnect the device
+ connection->reconnectDevice();
+ }
+ });
+
+ connect(connection, &IdmModbusTcpConnection::initializationFinished, info, [=](bool success){
+ if (!success) {
+ qCWarning(dcIdm()) << "Connection init finished with errors" << thing->name() << connection->hostAddress().toString();
+ hardwareManager()->networkDeviceDiscovery()->unregisterMonitor(monitor);
+ connection->deleteLater();
+ info->finish(Thing::ThingErrorHardwareFailure, QT_TR_NOOP("Could not initialize the communication with the device."));
+ return;
+ }
+
+ qCDebug(dcIdm()) << "Connection init finished successfully" << connection;
+ m_connections.insert(thing, connection);
+ info->finish(Thing::ThingErrorNoError);
+
+ // Set connected true
+ thing->setStateValue("connected", true);
+ foreach (Thing *childThing, myThings().filterByParentId(thing->id())) {
+ childThing->setStateValue("connected", true);
+ }
+
+
+ connect(connection, &IdmModbusTcpConnection::updateFinished, thing, [=](){
+ qCDebug(dcIdm()) << "Updated" << connection;
+
+ thing->setStateValue(navigator2ConnectedStateTypeId, connection->reachable());
+ thing->setStateValue(navigator2TemperatureStateTypeId, connection->roomTemperature());
+ thing->setStateValue(navigator2OutsideTemperatureStateTypeId, connection->outdoorTemperature());
+ thing->setStateValue(navigator2WaterTemperatureStateTypeId, connection->heatStorageTemperature());
+ thing->setStateValue(navigator2TargetTemperatureStateTypeId, connection->roomTemperatureTargetHeatingEco());
+ thing->setStateValue(navigator2TargetWaterTemperatureStateTypeId, connection->targetHotWaterTemperature());
+ thing->setStateValue(navigator2CurrentPowerStateTypeId, connection->currentPowerConsumption() * 1000.0);
+ thing->setStateValue(navigator2EnergyProducedHeatingStateTypeId, connection->energyHeating());
+ thing->setStateValue(navigator2EnergyProducedCoolingStateTypeId, connection->energyCooling());
+ thing->setStateValue(navigator2EnergyProducedHotWaterStateTypeId, connection->energyHotWater());
+
+ switch (connection->heatPumpOperatingMode()) {
+ case IdmModbusTcpConnection::HeatPumpOperationModeOff:
+ thing->setStateValue(navigator2ModeStateTypeId, "Off");
+ break;
+ case IdmModbusTcpConnection::HeatPumpOperationModeHeating:
+ thing->setStateValue(navigator2ModeStateTypeId, "Heating");
+ break;
+ case IdmModbusTcpConnection::HeatPumpOperationModeCooling:
+ thing->setStateValue(navigator2ModeStateTypeId, "Cooling");
+ break;
+ case IdmModbusTcpConnection::HeatPumpOperationModeHotWater:
+ thing->setStateValue(navigator2ModeStateTypeId, "Hot water");
+ break;
+ case IdmModbusTcpConnection::HeatPumpOperationModeDefrost:
+ thing->setStateValue(navigator2ModeStateTypeId, "Defrost");
+ break;
+ }
+
+ thing->setStateValue(navigator2HeatingOnStateTypeId, connection->heatPumpOperatingMode() == IdmModbusTcpConnection::HeatPumpOperationModeHeating);
+ thing->setStateValue(navigator2CoolingOnStateTypeId, connection->heatPumpOperatingMode() == IdmModbusTcpConnection::HeatPumpOperationModeCooling);
+
+ switch (connection->systemOperationMode()) {
+ case IdmModbusTcpConnection::SystemOperationModeStandby:
+ thing->setStateValue(navigator2OperationModeStateTypeId, "Standby");
+ break;
+ case IdmModbusTcpConnection::SystemOperationModeAutomatic:
+ thing->setStateValue(navigator2OperationModeStateTypeId, "Automatic");
+ break;
+ case IdmModbusTcpConnection::SystemOperationModeAbsent:
+ thing->setStateValue(navigator2OperationModeStateTypeId, "Absent");
+ break;
+ case IdmModbusTcpConnection::SystemOperationModeWarmWaterOnly:
+ thing->setStateValue(navigator2OperationModeStateTypeId, "Hot water only");
+ break;
+ case IdmModbusTcpConnection::SystemOperationModeHeatingCoolingOnly:
+ thing->setStateValue(navigator2OperationModeStateTypeId, "Heating cooling only");
+ break;
+ }
+
+ thing->setStateValue(navigator2ErrorStateTypeId, connection->currentFaultNumber());
+
+ });
+
+ // Update registers
+ connection->update();
+ });
+
+ connection->connectDevice();
}
-void IntegrationPluginIdm::onRefreshTimer()
-{
- foreach (Thing *thing, myThings().filterByThingClassId(navigator2ThingClassId)) {
- update(thing);
- }
-}
+
diff --git a/idm/integrationpluginidm.h b/idm/integrationpluginidm.h
index 860196c..8671330 100644
--- a/idm/integrationpluginidm.h
+++ b/idm/integrationpluginidm.h
@@ -1,6 +1,6 @@
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*
-* Copyright 2013 - 2020, nymea GmbH
+* Copyright 2013 - 2022, nymea GmbH
* Contact: contact@nymea.io
*
* This file is part of nymea.
@@ -32,11 +32,10 @@
#define INTEGRATIONPLUGINIDM_H
#include
+#include
#include
-#include "idm.h"
-
-#include
+#include "idmmodbustcpconnection.h"
class IntegrationPluginIdm: public IntegrationPlugin
{
@@ -56,16 +55,10 @@ public:
private:
PluginTimer *m_refreshTimer = nullptr;
- QHash m_idmConnections;
- QHash m_asyncActions;
-
- void update(Thing *thing);
- void onRefreshTimer();
-
-private slots:
- void onStatusUpdated(const IdmInfo &info);
- void onWriteRequestExecuted(const QUuid &requestId, bool success);
+ QHash m_connections;
+ QHash m_monitors;
+ void setupConnection(ThingSetupInfo *info);
};
#endif // INTEGRATIONPLUGINIDM_H
diff --git a/idm/integrationpluginidm.json b/idm/integrationpluginidm.json
index a17f4d4..3fb1bff 100644
--- a/idm/integrationpluginidm.json
+++ b/idm/integrationpluginidm.json
@@ -13,16 +13,8 @@
"displayName": "Navigator 2.0",
"id": "1c95ac91-4eca-4cbf-b0f4-d60d35d069ed",
"createMethods": ["user", "discovery"],
- "interfaces": ["thermostat", "connectable"],
+ "interfaces": ["thermostat", "smartmeterconsumer", "connectable" ],
"paramTypes": [
- {
- "id": "05714e5c-d66a-4095-bbff-a0eb96fb035b",
- "name":"ipAddress",
- "displayName": "IP address",
- "inputType": "IPv4Address",
- "type": "QString",
- "defaultValue": "0.0.0.0"
- },
{
"id": "d178ca29-41a1-4f56-82ec-76a833c1de50",
"name": "macAddress",
@@ -36,42 +28,14 @@
"id": "cfd71e64-b666-45ef-8db0-8213acd82c5f",
"name": "connected",
"displayName": "Connected",
- "displayNameEvent": "Connected changed",
"type": "bool",
"defaultValue": false,
"cached": false
},
- {
- "id": "33c27167-8e24-4cc5-943c-d17cd03e0f68",
- "name": "power",
- "displayName": "Power",
- "displayNameEvent": "Power changed",
- "type": "bool",
- "defaultValue": false
- },
{
"id": "f0f596bf-7e45-43ea-b3d4-767b82dd422a",
"name": "temperature",
"displayName": "Room temperature",
- "displayNameEvent": "Room temperature changed",
- "type": "double",
- "unit": "DegreeCelsius",
- "defaultValue": 0
- },
- {
- "id": "fcf8e97f-a672-407f-94ae-30df15b310f4",
- "name": "waterTemperature",
- "displayName": "Water temperature",
- "displayNameEvent": "Water temperature changed",
- "type": "double",
- "unit": "DegreeCelsius",
- "defaultValue": 0
- },
- {
- "id": "9f3462c2-7c42-4eeb-afc4-092e1e41a25d",
- "name": "outsideAirTemperature",
- "displayName": "Outside air temperature",
- "displayNameEvent": "Outside air temperature changed",
"type": "double",
"unit": "DegreeCelsius",
"defaultValue": 0
@@ -81,39 +45,99 @@
"name": "targetTemperature",
"displayName": "Target room temperature",
"displayNameAction": "Set target room temperature",
- "displayNameEvent": "Target room temperature changed",
"type": "double",
"unit": "DegreeCelsius",
"minValue": "18",
"maxValue": "28",
- "defaultValue": 22.00,
+ "defaultValue": 21.00,
"writable": true
},
+ {
+ "id": "fcf8e97f-a672-407f-94ae-30df15b310f4",
+ "name": "waterTemperature",
+ "displayName": "Water temperature",
+ "type": "double",
+ "unit": "DegreeCelsius",
+ "defaultValue": 0
+ },
+ {
+ "id": "22543424-6f4f-4200-9f90-111df28d50c9",
+ "name": "heatingOn",
+ "displayName": "Heating",
+ "type": "bool",
+ "defaultValue": false,
+ "cached": false
+ },
+ {
+ "id": "5719b9f6-6581-4ea8-b000-4ae6a852bb2d",
+ "name": "coolingOn",
+ "displayName": "Heating",
+ "type": "bool",
+ "defaultValue": false,
+ "cached": false
+ },
+ {
+ "id": "9f3462c2-7c42-4eeb-afc4-092e1e41a25d",
+ "name": "outsideTemperature",
+ "displayName": "Outside temperature",
+ "type": "double",
+ "unit": "DegreeCelsius",
+ "defaultValue": 0,
+ "cached": false
+ },
{
"id": "746244d6-dd37-4af8-b2ae-a7d8463e51e2",
"name": "targetWaterTemperature",
"displayName": "Target water temperature",
- "displayNameEvent": "Target water temperature changed",
"type": "double",
"unit": "DegreeCelsius",
"defaultValue": 0.00
},
{
-
"id": "b98fb325-100d-4eae-bf8d-97e8f7e1eb00",
- "name": "currentPowerConsumptionHeatPump",
- "displayName": "Current power consumption",
- "displayNameEvent": "Current power consumption heat pump changed",
- "displayNameAction": "Change current power consumption het pump",
+ "name": "currentPower",
+ "displayName": "Current power",
"type": "double",
- "unit": "KiloWatt",
+ "unit": "Watt",
+ "defaultValue": 0.00,
+ "cached": false
+ },
+ {
+ "id": "b457dc5a-920a-4c92-9956-a703e69f6084",
+ "name": "totalEnergyConsumed",
+ "displayName": "Total energy consumed",
+ "type": "double",
+ "unit": "KiloWattHour",
+ "defaultValue": 0.00
+ },
+ {
+ "id": "bfad9bbe-063d-497e-b13e-5de0f4738c91",
+ "name": "energyProducedHeating",
+ "displayName": "Total heating energy",
+ "type": "double",
+ "unit": "KiloWattHour",
+ "defaultValue": 0.00
+ },
+ {
+ "id": "9bef3a6c-4a6b-4023-a82e-c5263765310d",
+ "name": "energyProducedCooling",
+ "displayName": "Total cooling energy",
+ "type": "double",
+ "unit": "KiloWattHour",
+ "defaultValue": 0.00
+ },
+ {
+ "id": "0b5114ec-295f-42e6-a058-3e61f6da46b0",
+ "name": "energyProducedHotWater",
+ "displayName": "Total hot water energy",
+ "type": "double",
+ "unit": "KiloWattHour",
"defaultValue": 0.00
},
{
"id": "e539366b-44da-4119-b11b-497bcdb1f522",
"name": "mode",
"displayName": "Mode",
- "displayNameEvent": "Mode changed",
"type": "QString",
"defaultValue": "Off",
"possibleValues": [
@@ -124,13 +148,27 @@
"Defrost"
]
},
+ {
+ "id": "fb71c8f1-2b77-403d-b2ad-f3cba9baf237",
+ "name": "operationMode",
+ "displayName": "Operation mode",
+ "type": "QString",
+ "defaultValue": "Automatic",
+ "possibleValues": [
+ "Standby",
+ "Automatic",
+ "Absent",
+ "Hot water only",
+ "Heating cooling only"
+ ],
+ "cached": false
+ },
{
"id": "49fd83ee-ddf3-4477-9ee4-e01c53283b43",
"name": "error",
"displayName": "Error",
- "displayNameEvent": "Error changed",
- "type": "bool",
- "defaultValue": false
+ "type": "int",
+ "defaultValue": 0
}
]
}
diff --git a/idm/modbushelpers.cpp b/idm/modbushelpers.cpp
deleted file mode 100644
index 043b671..0000000
--- a/idm/modbushelpers.cpp
+++ /dev/null
@@ -1,61 +0,0 @@
-/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
-*
-* 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 .
-*
-* 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 "modbushelpers.h"
-
-float ModbusHelpers::convertRegisterToFloat(const quint16 *reg) {
-
- float result = 0.0;
-
- if (reg != nullptr) {
- /* low-order byte is sent first, so swap order */
- quint32 tmp = 0;
-
- tmp |= ((quint32)(reg[1]) << 16) & 0xFFFF0000;
- tmp |= reg[0];
-
- /* copy value over to float variable without any conversion */
- /* needs to be done with char * to avoid pedantic compiler errors */
- memcpy((char *)&result, (char *)&tmp, sizeof(result));
- }
- return result;
-}
-
-QVector ModbusHelpers::convertFloatToRegister(float value)
-{
- quint32 tmp = 0;
- memcpy((char *)&tmp, (char *)&value, sizeof(value));
-
- QVector reg;
- reg.append((quint16)(tmp));
- reg.append((quint16)((tmp & 0xFFFF0000) >> 16));
- return reg;
-}
-
diff --git a/idm/modbushelpers.h b/idm/modbushelpers.h
deleted file mode 100644
index bae33f3..0000000
--- a/idm/modbushelpers.h
+++ /dev/null
@@ -1,44 +0,0 @@
-/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
-*
-* 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 .
-*
-* 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 MODBUSHELPERS_H
-#define MODBUSHELPERS_H
-
-#include
-#include
-
-class ModbusHelpers {
-public:
- static float convertRegisterToFloat(const quint16 *reg);
- static QVector convertFloatToRegister(float value);
-};
-
-#endif
-
diff --git a/idm/translations/3968d86d-d51a-4ad1-a185-91faa017e38f-en_US.ts b/idm/translations/3968d86d-d51a-4ad1-a185-91faa017e38f-en_US.ts
index 3511917..19fe9d3 100644
--- a/idm/translations/3968d86d-d51a-4ad1-a185-91faa017e38f-en_US.ts
+++ b/idm/translations/3968d86d-d51a-4ad1-a185-91faa017e38f-en_US.ts
@@ -2,198 +2,151 @@
- Idm
+ IntegrationPluginIdm
-
-
+
+ The discovery is not available.
+
+
+
+
+ The MAC address is not known. Please reconfigure the thing.
+
+
+
+
+ The host address is not known yet. Trying later again.
+
+
+
+
+ Could not initialize the communication with the device.
+
+
+
+
+ idm
+
+
Connected
- The name of the ParamType (ThingClass: navigator2, EventType: connected, ID: {cfd71e64-b666-45ef-8db0-8213acd82c5f})
-----------
-The name of the StateType ({cfd71e64-b666-45ef-8db0-8213acd82c5f}) of ThingClass navigator2
+ The name of the StateType ({cfd71e64-b666-45ef-8db0-8213acd82c5f}) of ThingClass navigator2
-
- Connected changed
- The name of the EventType ({cfd71e64-b666-45ef-8db0-8213acd82c5f}) of ThingClass navigator2
+
+ Current power
+ The name of the StateType ({b98fb325-100d-4eae-bf8d-97e8f7e1eb00}) of ThingClass navigator2
-
-
- Current power consumption
- The name of the ParamType (ThingClass: navigator2, EventType: currentPowerConsumptionHeatPump, ID: {b98fb325-100d-4eae-bf8d-97e8f7e1eb00})
-----------
-The name of the StateType ({b98fb325-100d-4eae-bf8d-97e8f7e1eb00}) of ThingClass navigator2
-
-
-
-
- Current power consumption heat pump changed
- The name of the EventType ({b98fb325-100d-4eae-bf8d-97e8f7e1eb00}) of ThingClass navigator2
-
-
-
-
-
+
Error
- The name of the ParamType (ThingClass: navigator2, EventType: error, ID: {49fd83ee-ddf3-4477-9ee4-e01c53283b43})
+ The name of the StateType ({49fd83ee-ddf3-4477-9ee4-e01c53283b43}) of ThingClass navigator2
+
+
+
+
+
+ Heating
+ The name of the StateType ({5719b9f6-6581-4ea8-b000-4ae6a852bb2d}) of ThingClass navigator2
----------
-The name of the StateType ({49fd83ee-ddf3-4477-9ee4-e01c53283b43}) of ThingClass navigator2
+The name of the StateType ({22543424-6f4f-4200-9f90-111df28d50c9}) of ThingClass navigator2
-
- Error changed
- The name of the EventType ({49fd83ee-ddf3-4477-9ee4-e01c53283b43}) of ThingClass navigator2
+
+ MAC address
+ The name of the ParamType (ThingClass: navigator2, Type: thing, ID: {d178ca29-41a1-4f56-82ec-76a833c1de50})
-
- IP address
- The name of the ParamType (ThingClass: navigator2, Type: thing, ID: {05714e5c-d66a-4095-bbff-a0eb96fb035b})
-
-
-
-
-
+
Mode
- The name of the ParamType (ThingClass: navigator2, EventType: mode, ID: {e539366b-44da-4119-b11b-497bcdb1f522})
-----------
-The name of the StateType ({e539366b-44da-4119-b11b-497bcdb1f522}) of ThingClass navigator2
+ The name of the StateType ({e539366b-44da-4119-b11b-497bcdb1f522}) of ThingClass navigator2
-
- Mode changed
- The name of the EventType ({e539366b-44da-4119-b11b-497bcdb1f522}) of ThingClass navigator2
-
-
-
-
+
Navigator 2.0
The name of the ThingClass ({1c95ac91-4eca-4cbf-b0f4-d60d35d069ed})
-
-
- Outside air temperature
- The name of the ParamType (ThingClass: navigator2, EventType: outsideAirTemperature, ID: {9f3462c2-7c42-4eeb-afc4-092e1e41a25d})
-----------
-The name of the StateType ({9f3462c2-7c42-4eeb-afc4-092e1e41a25d}) of ThingClass navigator2
+
+ Operation mode
+ The name of the StateType ({fb71c8f1-2b77-403d-b2ad-f3cba9baf237}) of ThingClass navigator2
-
- Outside air temperature changed
- The name of the EventType ({9f3462c2-7c42-4eeb-afc4-092e1e41a25d}) of ThingClass navigator2
+
+ Outside temperature
+ The name of the StateType ({9f3462c2-7c42-4eeb-afc4-092e1e41a25d}) of ThingClass navigator2
-
-
- Power
- The name of the ParamType (ThingClass: navigator2, EventType: power, ID: {33c27167-8e24-4cc5-943c-d17cd03e0f68})
-----------
-The name of the StateType ({33c27167-8e24-4cc5-943c-d17cd03e0f68}) of ThingClass navigator2
-
-
-
-
- Power changed
- The name of the EventType ({33c27167-8e24-4cc5-943c-d17cd03e0f68}) of ThingClass navigator2
-
-
-
-
-
+
Room temperature
- The name of the ParamType (ThingClass: navigator2, EventType: temperature, ID: {f0f596bf-7e45-43ea-b3d4-767b82dd422a})
-----------
-The name of the StateType ({f0f596bf-7e45-43ea-b3d4-767b82dd422a}) of ThingClass navigator2
+ The name of the StateType ({f0f596bf-7e45-43ea-b3d4-767b82dd422a}) of ThingClass navigator2
-
- Room temperature changed
- The name of the EventType ({f0f596bf-7e45-43ea-b3d4-767b82dd422a}) of ThingClass navigator2
-
-
-
-
+
Set target room temperature
The name of the ActionType ({efae7493-68c3-4cb9-853c-81011bdf09ca}) of ThingClass navigator2
-
-
-
+
+
Target room temperature
The name of the ParamType (ThingClass: navigator2, ActionType: targetTemperature, ID: {efae7493-68c3-4cb9-853c-81011bdf09ca})
----------
-The name of the ParamType (ThingClass: navigator2, EventType: targetTemperature, ID: {efae7493-68c3-4cb9-853c-81011bdf09ca})
-----------
The name of the StateType ({efae7493-68c3-4cb9-853c-81011bdf09ca}) of ThingClass navigator2
-
- Target room temperature changed
- The name of the EventType ({efae7493-68c3-4cb9-853c-81011bdf09ca}) of ThingClass navigator2
-
-
-
-
-
+
Target water temperature
- The name of the ParamType (ThingClass: navigator2, EventType: targetWaterTemperature, ID: {746244d6-dd37-4af8-b2ae-a7d8463e51e2})
-----------
-The name of the StateType ({746244d6-dd37-4af8-b2ae-a7d8463e51e2}) of ThingClass navigator2
+ The name of the StateType ({746244d6-dd37-4af8-b2ae-a7d8463e51e2}) of ThingClass navigator2
-
- Target water temperature changed
- The name of the EventType ({746244d6-dd37-4af8-b2ae-a7d8463e51e2}) of ThingClass navigator2
+
+ Total cooling energy
+ The name of the StateType ({9bef3a6c-4a6b-4023-a82e-c5263765310d}) of ThingClass navigator2
-
-
+
+ Total energy consumed
+ The name of the StateType ({b457dc5a-920a-4c92-9956-a703e69f6084}) of ThingClass navigator2
+
+
+
+
+ Total heating energy
+ The name of the StateType ({bfad9bbe-063d-497e-b13e-5de0f4738c91}) of ThingClass navigator2
+
+
+
+
+ Total hot water energy
+ The name of the StateType ({0b5114ec-295f-42e6-a058-3e61f6da46b0}) of ThingClass navigator2
+
+
+
+
Water temperature
- The name of the ParamType (ThingClass: navigator2, EventType: waterTemperature, ID: {fcf8e97f-a672-407f-94ae-30df15b310f4})
-----------
-The name of the StateType ({fcf8e97f-a672-407f-94ae-30df15b310f4}) of ThingClass navigator2
+ The name of the StateType ({fcf8e97f-a672-407f-94ae-30df15b310f4}) of ThingClass navigator2
-
- Water temperature changed
- The name of the EventType ({fcf8e97f-a672-407f-94ae-30df15b310f4}) of ThingClass navigator2
-
-
-
-
-
+
+
iDM
The name of the vendor ({6f54e4b0-1057-4004-87a9-97fdf4581625})
----------
-The name of the plugin Idm ({3968d86d-d51a-4ad1-a185-91faa017e38f})
-
-
-
-
- IntegrationPluginIdm
-
-
- No IP address given
-
-
-
-
- IP address already in use
+The name of the plugin idm ({3968d86d-d51a-4ad1-a185-91faa017e38f})