From 9b346848a2b0d183983baca04f2402954bfe9329 Mon Sep 17 00:00:00 2001 From: Hermann Detz Date: Fri, 16 Oct 2020 11:28:31 +0200 Subject: [PATCH] Readout working --- idm/idm.cpp | 118 +++++++++++++++++++++++++++++------ idm/idm.h | 62 ++++++++++++++---- idm/idm.pro | 3 + idm/idminfo.h | 21 +++++++ idm/integrationpluginidm.cpp | 10 +-- idm/integrationpluginidm.h | 9 +-- 6 files changed, 179 insertions(+), 44 deletions(-) diff --git a/idm/idm.cpp b/idm/idm.cpp index 2acb9ee..c9d930d 100644 --- a/idm/idm.cpp +++ b/idm/idm.cpp @@ -29,16 +29,21 @@ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ #include "idm.h" +#include "../modbus/modbushelpers.h" + +#include Idm::Idm(const QHostAddress &address, QObject *parent) : QObject(parent), m_hostAddress(address) { - /* qCDebug(dcIdm()) << "Creating Idm with addr: " << address; */ - m_modbusMaster = new ModbusTCPMaster(address, 502, this); - connect(m_modbusMaster, &ModbusTCPMaster::receivedHoldingRegister, this, &Idm::onReceivedHoldingRegister); + if (m_modbusMaster) { + m_modbusMaster->connectDevice(); + + connect(m_modbusMaster, &ModbusTCPMaster::receivedHoldingRegister, this, &Idm::onReceivedHoldingRegister); + } } Idm::~Idm() @@ -48,31 +53,104 @@ Idm::~Idm() } } -double Idm::getOutsideTemperature() -{ - //m_modbusMaster-> - return 0.0; -} - void Idm::onReceivedHoldingRegister(int slaveAddress, int modbusRegister, const QVector &value) { - /* qCDebug(dcIdm()) << "Idm::onReceivedHoldingRegister"; */ - Q_UNUSED(slaveAddress); - Q_UNUSED(modbusRegister); - Q_UNUSED(value); - IdmInfo *info = new IdmInfo; - info->m_outsideTemperature = 24.3; + switch (modbusRegister) { + case Idm::OutsideTemperature: + if (value.length() == 2) { + m_info->m_roomTemperature = ModbusHelpers::convertRegisterToFloat(&value[RegisterList::OutsideTemperature - modbusRegister]); + } + m_modbusMaster->readHoldingRegister(Idm::ModbusUnitID, Idm::CurrentFaultNumber, 1); + break; + case Idm::CurrentFaultNumber: + if (value.length() == 1) { + if (value[0] > 0) { + m_info->m_error = true; + } else { + m_info->m_error = false; + } + } + m_modbusMaster->readHoldingRegister(Idm::ModbusUnitID, Idm::TargetHotWaterTemperature, 2); + break; + case Idm::TargetHotWaterTemperature: + if (value.length() == 2) { + m_info->m_targetWaterTemperature = ModbusHelpers::convertRegisterToFloat(&value[RegisterList::TargetHotWaterTemperature - modbusRegister]); + } + m_modbusMaster->readHoldingRegister(Idm::ModbusUnitID, Idm::HeatPumpOperatingMode, 1); + break; + case Idm::HeatPumpOperatingMode: + if (value.length() == 1) { + printf("read heat pump operation mode: %d\n", value[0]); + m_info->m_mode = heatPumpOperationModeToString((Idm::IdmHeatPumpMode)value[RegisterList::HeatPumpOperatingMode-modbusRegister]); + } + m_modbusMaster->readHoldingRegister(Idm::ModbusUnitID, Idm::ExternalOutsideTemperature, 2); + break; + case Idm::ExternalOutsideTemperature: + if (value.length() == 2) { + m_info->m_outsideTemperature = ModbusHelpers::convertRegisterToFloat(&value[RegisterList::ExternalOutsideTemperature - modbusRegister]); + } - emit statusUpdated(info); + emit statusUpdated(m_info); + break; + } } void Idm::onRequestStatus() { - /* Reading a total of 16 bytes, starting from address 1000. - * This covers the following parameters: - * */ - m_modbusMaster->readHoldingRegister(0xff, RegisterList::OutsideTemperature, 16); + m_info = new IdmInfo; + + m_modbusMaster->readHoldingRegister(Idm::ModbusUnitID, Idm::OutsideTemperature, 2); +} + +QString Idm::systemOperationModeToString(IdmSysMode mode) { + QString result{}; + + /* Operation modes according to table of manual p. 13 */ + switch (mode) { + case IdmSysModeStandby: + result = "Standby"; + break; + case IdmSysModeAutomatic: + result = "Automatik"; + break; + case IdmSysModeAway: + result = "Abwesend"; + break; + case IdmSysModeOnlyHotwater: + result = "Nur Warmwasser"; + break; + case IdmSysModeOnlyRoomHeating: + result = "Nur Heizung/Kühlung"; + break; + } + + return result; +} + +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 index 0792fff..8b83544 100644 --- a/idm/idm.h +++ b/idm/idm.h @@ -41,13 +41,23 @@ class Idm : public QObject { Q_OBJECT public: + /** Constructor */ explicit Idm(const QHostAddress &address, QObject *parent = nullptr); - ~Idm(); - double getOutsideTemperature(); - //void getCurrentFaultNumber(); + /** Destructor */ + ~Idm(); private: + /* 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. + */ + + /** Modbus Unit ID of Idm device */ + static const quint16 ModbusUnitID = 1; enum IscModus { KeineAbwarme = 0, @@ -56,11 +66,29 @@ private: 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 { - /* 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. */ OutsideTemperature = 1000, // Außentemperatur (B31) MeanOutsideTemperature = 1002, // Gemittelte Außentemperature CurrentFaultNumber = 1004, // Aktuelle Störungsnummer @@ -75,6 +103,7 @@ private: HeatPumpOperatingMode = 1090, // Betriebsart Wärmepumpe SummationFaultHeatPump = 1099, // Summenstörung Wärepumpe Humiditysensor = 1392, // Feuchtesensor + RoomTemperatureTargetHeatingHKA = 1401, // Raumsolltemperatur Heizen Normal HK A ExternalOutsideTemperature = 1690, // Externe Außentemperatur ExternalHumidity = 1692, // Externe Feuchte ExternalRequestTemperatureHeating = 1694, // Externe Anforderungstemperatur Heizen @@ -97,6 +126,7 @@ private: 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 CurrentPowerConsumption = 4122, // Aktuelle Leistungsaufnahme Wärmepumpe @@ -106,18 +136,26 @@ private: * TCP Modbus connection. Multiple devices are managed * within the IntegrationPluginIdm class. */ QHostAddress m_hostAddress; + + /** Pointer to ModbusTCPMaster object, responseible for low-level communicaiton */ ModbusTCPMaster *m_modbusMaster = nullptr; + /** This structure is allocated within onRequestStatus and filled + * by the receivedStatusGroupx functions */ + IdmInfo *m_info = nullptr; + + /** Converts a system operation mode code to a string (according to manual p. 13) */ + QString systemOperationModeToString(IdmSysMode mode); + + /** Converts a heat pump operation mode code to a string (according to manual p. 14) */ + QString heatPumpOperationModeToString(IdmHeatPumpMode mode); + signals: void statusUpdated(IdmInfo *info); -private slots: - void onRequestStatus(); - -// only public for debugging! public slots: + void onRequestStatus(); void onReceivedHoldingRegister(int slaveAddress, int modbusRegister, const QVector &value); - }; #endif // IDM_H diff --git a/idm/idm.pro b/idm/idm.pro index 63867ed..6bc6551 100644 --- a/idm/idm.pro +++ b/idm/idm.pro @@ -8,9 +8,12 @@ SOURCES += \ idm.cpp \ integrationpluginidm.cpp \ ../modbus/modbustcpmaster.cpp \ + ../modbus/modbushelpers.cpp \ HEADERS += \ idm.h \ idminfo.h \ integrationpluginidm.h \ ../modbus/modbustcpmaster.h \ + ../modbus/modbushelpers.h \ + diff --git a/idm/idminfo.h b/idm/idminfo.h index 115c49b..e43438f 100644 --- a/idm/idminfo.h +++ b/idm/idminfo.h @@ -31,19 +31,40 @@ #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 { bool m_connected; bool m_power; + + /** RegisterList::OutsideTemperature */ double m_roomTemperature; + + /** RegisterList::ExternalOutsideTemperature */ double m_outsideTemperature; + + /** RegisterList::HeatStorageTemperature */ double m_waterTemperature; + + /** RegisterList::TargetRoomTemperatureZ1R1 (zone 1, room 1) */ double m_targetRoomTemperature; + + /** RegisterList::TargetHotWaterTemperature */ double m_targetWaterTemperature; + + /** RegisterList::OperationModeSystem */ QString m_mode; + + /** True if there is an error code set + * (RegisterList::CurrentFaultNumber != 0) */ bool m_error; }; +Q_DECLARE_METATYPE(IdmInfo); + #endif diff --git a/idm/integrationpluginidm.cpp b/idm/integrationpluginidm.cpp index cd3e113..840e25e 100644 --- a/idm/integrationpluginidm.cpp +++ b/idm/integrationpluginidm.cpp @@ -43,7 +43,7 @@ void IntegrationPluginIdm::discoverThings(ThingDiscoveryInfo *info) // The plugin has a parameter for the IP address QString description = "Navigator 2"; - ThingDescriptor descriptor(info->thingClassId(), "", description); + ThingDescriptor descriptor(info->thingClassId(), "Idm", description); info->addThingDescriptor(descriptor); // Just report no error for now, until the above question @@ -58,8 +58,12 @@ void IntegrationPluginIdm::setupThing(ThingSetupInfo *info) if (thing->thingClassId() == navigator2ThingClassId) { QHostAddress hostAddress = QHostAddress(thing->paramValue(navigator2ThingIpAddressParamTypeId).toString()); + + /* Create new Idm object and store it in hash table */ Idm *idm = new Idm(hostAddress, this); m_idmConnections.insert(thing, idm); + + /* Store thing info in hash table */ m_idmInfos.insert(thing, info); info->finish(Thing::ThingErrorNoError); @@ -119,10 +123,8 @@ void IntegrationPluginIdm::update(Thing *thing) QVector val{}; - idm->onReceivedHoldingRegister(0, 1021, val); - //idm->onRequestStatus(); + idm->onRequestStatus(); - //idm->readHoldingRegister(0xff, RegisterList::OutsideTemperature); if (m_idmInfos.contains(thing)) { ThingSetupInfo *info = m_idmInfos.take(thing); info->finish(Thing::ThingErrorNoError); diff --git a/idm/integrationpluginidm.h b/idm/integrationpluginidm.h index 3da5ef6..81de0e1 100644 --- a/idm/integrationpluginidm.h +++ b/idm/integrationpluginidm.h @@ -48,6 +48,7 @@ class IntegrationPluginIdm: public IntegrationPlugin public: + /** Constructor */ explicit IntegrationPluginIdm(); void discoverThings(ThingDiscoveryInfo *info) override; @@ -59,14 +60,6 @@ public: private: - enum IdmSysMode { - IdmSysModeStandby = 0, - IdmSysModeAutomatic, - IdmSysModeAway, - IdmSysModeOnlyWarmwater, - IdmSysModeOnlyRoomHeating - }; - enum IdmSmartGridMode { EVUSperreKeinPVErtrag, EVUBezugKeinPVErtrag,