Update mtec plugin with network device discovery and internal connection mechanism
This commit is contained in:
parent
82dc46cd3b
commit
446b3e3dda
@ -28,6 +28,7 @@
|
|||||||
*
|
*
|
||||||
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
||||||
|
|
||||||
|
#include "network/networkdevicediscovery.h"
|
||||||
#include "integrationpluginmtec.h"
|
#include "integrationpluginmtec.h"
|
||||||
#include "plugininfo.h"
|
#include "plugininfo.h"
|
||||||
|
|
||||||
@ -38,81 +39,96 @@ IntegrationPluginMTec::IntegrationPluginMTec()
|
|||||||
|
|
||||||
void IntegrationPluginMTec::discoverThings(ThingDiscoveryInfo *info)
|
void IntegrationPluginMTec::discoverThings(ThingDiscoveryInfo *info)
|
||||||
{
|
{
|
||||||
qCDebug(dcMTec()) << "Discover M-Tec heat pumps";
|
if (!hardwareManager()->networkDeviceDiscovery()->available()) {
|
||||||
|
qCWarning(dcMTec()) << "The network discovery is not available on this platform.";
|
||||||
if (info->thingClassId() == mtecThingClassId) {
|
info->finish(Thing::ThingErrorUnsupportedFeature, QT_TR_NOOP("The network device discovery is not available."));
|
||||||
QString description = "Heatpump";
|
return;
|
||||||
ThingDescriptor descriptor(info->thingClassId(), "M-Tec", description);
|
|
||||||
info->addThingDescriptor(descriptor);
|
|
||||||
|
|
||||||
// TODO Find out, if a discovery is possible/needed
|
|
||||||
// Otherwise, just report no error for now
|
|
||||||
info->finish(Thing::ThingErrorNoError);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Perform a network device discovery and filter for "go-eCharger" hosts
|
||||||
|
NetworkDeviceDiscoveryReply *discoveryReply = hardwareManager()->networkDeviceDiscovery()->discover();
|
||||||
|
connect(discoveryReply, &NetworkDeviceDiscoveryReply::finished, this, [=](){
|
||||||
|
foreach (const NetworkDevice &networkDevice, discoveryReply->networkDevices()) {
|
||||||
|
|
||||||
|
qCDebug(dcMTec()) << "Found" << networkDevice;
|
||||||
|
|
||||||
|
QString title;
|
||||||
|
if (networkDevice.hostName().isEmpty()) {
|
||||||
|
title = networkDevice.address().toString();
|
||||||
|
} else {
|
||||||
|
title = networkDevice.hostName() + " (" + networkDevice.address().toString() + ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
QString description;
|
||||||
|
if (networkDevice.macAddressManufacturer().isEmpty()) {
|
||||||
|
description = networkDevice.macAddress();
|
||||||
|
} else {
|
||||||
|
description = networkDevice.macAddress() + " (" + networkDevice.macAddressManufacturer() + ")";
|
||||||
|
}
|
||||||
|
|
||||||
|
ThingDescriptor descriptor(mtecThingClassId, title, description);
|
||||||
|
ParamList params;
|
||||||
|
params << Param(mtecThingIpAddressParamTypeId, networkDevice.address().toString());
|
||||||
|
params << Param(mtecThingMacAddressParamTypeId, networkDevice.macAddress());
|
||||||
|
descriptor.setParams(params);
|
||||||
|
|
||||||
|
// Check if we already have set up this device
|
||||||
|
Things existingThings = myThings().filterByParam(mtecThingMacAddressParamTypeId, networkDevice.macAddress());
|
||||||
|
if (existingThings.count() == 1) {
|
||||||
|
qCDebug(dcMTec()) << "This heat pump already exists in the system!" << networkDevice;
|
||||||
|
descriptor.setThingId(existingThings.first()->id());
|
||||||
|
}
|
||||||
|
|
||||||
|
info->addThingDescriptor(descriptor);
|
||||||
|
}
|
||||||
|
|
||||||
|
info->finish(Thing::ThingErrorNoError);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntegrationPluginMTec::setupThing(ThingSetupInfo *info)
|
void IntegrationPluginMTec::setupThing(ThingSetupInfo *info)
|
||||||
{
|
{
|
||||||
qCDebug(dcMTec()) << "Setup" << info->thing();
|
|
||||||
|
|
||||||
Thing *thing = info->thing();
|
Thing *thing = info->thing();
|
||||||
|
qCDebug(dcMTec()) << "Setup" << thing;
|
||||||
|
|
||||||
if (thing->thingClassId() == mtecThingClassId) {
|
if (thing->thingClassId() == mtecThingClassId) {
|
||||||
QHostAddress hostAddress = QHostAddress(thing->paramValue(mtecThingIpAddressParamTypeId).toString());
|
QHostAddress hostAddress = QHostAddress(thing->paramValue(mtecThingIpAddressParamTypeId).toString());
|
||||||
|
|
||||||
if (hostAddress.isNull()) {
|
if (hostAddress.isNull()) {
|
||||||
info->finish(Thing::ThingErrorInvalidParameter, QT_TR_NOOP("No IP address given"));
|
info->finish(Thing::ThingErrorInvalidParameter, QT_TR_NOOP("No IP address given"));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
qCDebug(dcMTec()) << "User entered address: " << hostAddress.toString();
|
qCDebug(dcMTec()) << "Using ip address" << hostAddress.toString();
|
||||||
|
if (myThings().filterByParam(mtecThingIpAddressParamTypeId, hostAddress.toString()).count() > 0) {
|
||||||
/* Check, if address is already in use for another device */
|
info->finish(Thing::ThingErrorThingInUse, QT_TR_NOOP("IP address already in use by another thing."));
|
||||||
/* for (QHash<Thing *, MTec *>::iterator item=m_mtecConnections.begin(); item != m_mtecConnections.end(); item++) { */
|
return;
|
||||||
/* if (hostAddress.isEqual(item.value()->getHostAddress())) { */
|
|
||||||
/* qCDebug(dcMTec()) << "Address of thing: " << item.value()->getHostAddress().toString(); */
|
|
||||||
|
|
||||||
/* qCDebug(dcMTec()) << "Address in use already"; */
|
|
||||||
/* } else { */
|
|
||||||
/* qCDebug(dcMTec()) << "Different address of other thing: " << item.value()->getHostAddress().toString(); */
|
|
||||||
|
|
||||||
/* } */
|
|
||||||
/* } */
|
|
||||||
|
|
||||||
foreach (MTec *mtecConnection, m_mtecConnections.values()) {
|
|
||||||
if (mtecConnection->getHostAddress().isEqual(hostAddress)) {
|
|
||||||
qCWarning(dcMTec()) << "Address" << hostAddress.toString() << "already in use by" << m_mtecConnections.key(mtecConnection);
|
|
||||||
info->finish(Thing::ThingErrorThingInUse, QT_TR_NOOP("IP address already in use by another thing."));
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
qCDebug(dcMTec()) << "Creating M-Tec object";
|
// TODO: start timer and give 15 seconds until connected, since the controler is down for ~10 seconds after a disconnect
|
||||||
|
|
||||||
/* Create new MTec object and store it in hash table */
|
|
||||||
MTec *mtec = new MTec(hostAddress, this);
|
MTec *mtec = new MTec(hostAddress, this);
|
||||||
m_mtecConnections.insert(thing, mtec);
|
connect(mtec, &MTec::statusUpdated, this, &IntegrationPluginMTec::onStatusUpdated);
|
||||||
|
connect(mtec, &MTec::connectedChanged, thing, [=](bool connected){
|
||||||
|
qCDebug(dcMTec()) << "Connected changed to" << connected;
|
||||||
|
thing->setStateValue(mtecConnectedStateTypeId, connected);
|
||||||
|
});
|
||||||
|
|
||||||
|
m_mtecConnections.insert(thing, mtec);
|
||||||
|
if (!mtec->connectDevice()) {
|
||||||
|
qCWarning(dcMTec()) << "Initial connect returned false. Lets wait 15 seconds until the connection can be established.";
|
||||||
|
}
|
||||||
|
|
||||||
info->thing()->setStateValue(mtecConnectedStateTypeId, true);
|
|
||||||
info->finish(Thing::ThingErrorNoError);
|
info->finish(Thing::ThingErrorNoError);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntegrationPluginMTec::postSetupThing(Thing *thing)
|
void IntegrationPluginMTec::postSetupThing(Thing *thing)
|
||||||
{
|
{
|
||||||
qCDebug(dcMTec()) << "PostSetup called for" << thing;
|
|
||||||
|
|
||||||
if (thing->thingClassId() == mtecThingClassId) {
|
if (thing->thingClassId() == mtecThingClassId) {
|
||||||
MTec *mtec = m_mtecConnections.value(thing);
|
MTec *mtec = m_mtecConnections.value(thing);
|
||||||
|
|
||||||
if (mtec) {
|
if (mtec) {
|
||||||
connect(mtec, &MTec::statusUpdated, this, &IntegrationPluginMTec::onStatusUpdated);
|
|
||||||
connect(mtec, &MTec::connectedChanged, this, &IntegrationPluginMTec::onConnectedChanged);
|
|
||||||
|
|
||||||
qCDebug(dcMTec()) << "Thing set up, calling update";
|
|
||||||
update(thing);
|
update(thing);
|
||||||
|
//thing->setStateValue(mtecConnectedStateTypeId, true);
|
||||||
thing->setStateValue(mtecConnectedStateTypeId, true);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -126,63 +142,38 @@ void IntegrationPluginMTec::thingRemoved(Thing *thing)
|
|||||||
|
|
||||||
void IntegrationPluginMTec::executeAction(ThingActionInfo *info)
|
void IntegrationPluginMTec::executeAction(ThingActionInfo *info)
|
||||||
{
|
{
|
||||||
Thing *thing = info->thing();
|
// Thing *thing = info->thing();
|
||||||
Action action = info->action();
|
// Action action = info->action();
|
||||||
|
info->finish(Thing::ThingErrorNoError);
|
||||||
|
|
||||||
if (thing->thingClassId() == mtecThingClassId) {
|
// if (thing->thingClassId() == mtecThingClassId) {
|
||||||
/* if (action.actionTypeId() == mtecPowerActionTypeId) { */
|
// /* if (action.actionTypeId() == mtecPowerActionTypeId) { */
|
||||||
|
|
||||||
/* } else { */
|
// } else {
|
||||||
/* Q_ASSERT_X(false, "executeAction", QString("Unhandled action: %1").arg(action.actionTypeId().toString()).toUtf8()); */
|
// Q_ASSERT_X(false, "executeAction", QString("Unhandled thingClassId: %1").arg(thing->thingClassId().toString()).toUtf8());
|
||||||
/* } */
|
// }
|
||||||
} else {
|
|
||||||
Q_ASSERT_X(false, "executeAction", QString("Unhandled thingClassId: %1").arg(thing->thingClassId().toString()).toUtf8());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntegrationPluginMTec::update(Thing *thing)
|
void IntegrationPluginMTec::update(Thing *thing)
|
||||||
{
|
{
|
||||||
if (thing->thingClassId() == mtecThingClassId) {
|
if (thing->thingClassId() == mtecThingClassId) {
|
||||||
qCDebug(dcMTec()) << "Updating thing" << thing;
|
qCDebug(dcMTec()) << "Updating thing" << thing;
|
||||||
|
|
||||||
MTec *mtec = m_mtecConnections.value(thing);
|
MTec *mtec = m_mtecConnections.value(thing);
|
||||||
|
if (!mtec) return;
|
||||||
if (mtec) {
|
mtec->requestStatus();
|
||||||
mtec->onRequestStatus();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void IntegrationPluginMTec::onConnectedChanged(MTecHelpers::ConnectionState state)
|
|
||||||
{
|
|
||||||
MTec *mtec = qobject_cast<MTec *>(sender());
|
|
||||||
Thing *thing = m_mtecConnections.key(mtec);
|
|
||||||
|
|
||||||
qCDebug(dcMTec()) << "Received connection change event from heat pump" << thing;
|
|
||||||
|
|
||||||
if (!thing)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (state == MTecHelpers::ConnectionState::Online) {
|
|
||||||
thing->setStateValue(mtecConnectedStateTypeId, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
thing->setStateValue(mtecStatusStateTypeId, MTecHelpers::connectionStateToString(state));
|
|
||||||
}
|
|
||||||
|
|
||||||
void IntegrationPluginMTec::onStatusUpdated(const MTecInfo &info)
|
void IntegrationPluginMTec::onStatusUpdated(const MTecInfo &info)
|
||||||
{
|
{
|
||||||
MTec *mtec = qobject_cast<MTec *>(sender());
|
MTec *mtec = qobject_cast<MTec *>(sender());
|
||||||
Thing *thing = m_mtecConnections.key(mtec);
|
Thing *thing = m_mtecConnections.key(mtec);
|
||||||
|
|
||||||
qCDebug(dcMTec()) << "Received status from heat pump" << thing;
|
|
||||||
|
|
||||||
if (!thing)
|
if (!thing)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
qCDebug(dcMTec()) << "Received status from heat pump" << thing;
|
||||||
/* Received a structure holding the status info of the
|
/* Received a structure holding the status info of the
|
||||||
* heat pump. Update the thing states with the individual fields. */
|
* heat pump. Update the thing states with the individual fields. */
|
||||||
thing->setStateValue(mtecStatusStateTypeId, info.status);
|
|
||||||
thing->setStateValue(mtecActualPowerConsumptionStateTypeId, info.actualPowerConsumption);
|
thing->setStateValue(mtecActualPowerConsumptionStateTypeId, info.actualPowerConsumption);
|
||||||
thing->setStateValue(mtecActualExcessEnergySmartHomeStateTypeId, info.actualExcessEnergySmartHome);
|
thing->setStateValue(mtecActualExcessEnergySmartHomeStateTypeId, info.actualExcessEnergySmartHome);
|
||||||
thing->setStateValue(mtecActualExcessEnergyElectricityMeterStateTypeId, info.actualExcessEnergyElectricityMeter);
|
thing->setStateValue(mtecActualExcessEnergyElectricityMeterStateTypeId, info.actualExcessEnergyElectricityMeter);
|
||||||
@ -192,8 +183,6 @@ void IntegrationPluginMTec::onStatusUpdated(const MTecInfo &info)
|
|||||||
|
|
||||||
void IntegrationPluginMTec::onRefreshTimer()
|
void IntegrationPluginMTec::onRefreshTimer()
|
||||||
{
|
{
|
||||||
qCDebug(dcMTec()) << "onRefreshTimer called";
|
|
||||||
|
|
||||||
foreach (Thing *thing, myThings().filterByThingClassId(mtecThingClassId)) {
|
foreach (Thing *thing, myThings().filterByThingClassId(mtecThingClassId)) {
|
||||||
update(thing);
|
update(thing);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -51,19 +51,16 @@ public:
|
|||||||
|
|
||||||
void discoverThings(ThingDiscoveryInfo *info) override;
|
void discoverThings(ThingDiscoveryInfo *info) override;
|
||||||
void setupThing(ThingSetupInfo *info) override;
|
void setupThing(ThingSetupInfo *info) override;
|
||||||
|
|
||||||
|
|
||||||
private:
|
|
||||||
void postSetupThing(Thing *thing) override;
|
void postSetupThing(Thing *thing) override;
|
||||||
void thingRemoved(Thing *thing) override;
|
void thingRemoved(Thing *thing) override;
|
||||||
void executeAction(ThingActionInfo *info) override;
|
void executeAction(ThingActionInfo *info) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QHash<Thing *, MTec *> m_mtecConnections;
|
||||||
|
|
||||||
void update(Thing *thing);
|
void update(Thing *thing);
|
||||||
|
|
||||||
QHash<Thing *, MTec *> m_mtecConnections;
|
|
||||||
QHash<QUuid, ThingActionInfo *> m_asyncActions;
|
|
||||||
|
|
||||||
private slots:
|
private slots:
|
||||||
void onConnectedChanged(MTecHelpers::ConnectionState state);
|
|
||||||
void onRefreshTimer();
|
void onRefreshTimer();
|
||||||
void onStatusUpdated(const MTecInfo &info);
|
void onStatusUpdated(const MTecInfo &info);
|
||||||
|
|
||||||
|
|||||||
@ -8,98 +8,94 @@
|
|||||||
"displayName": "M-Tec",
|
"displayName": "M-Tec",
|
||||||
"id": "04d3fa7c-e469-4a79-a119-155426e5a846",
|
"id": "04d3fa7c-e469-4a79-a119-155426e5a846",
|
||||||
"thingClasses": [
|
"thingClasses": [
|
||||||
{
|
|
||||||
"name": "mtec",
|
|
||||||
"displayName": "MTec",
|
|
||||||
"id": "451e38d8-50d5-4ae9-8d9f-21af9347128d",
|
|
||||||
"createMethods": ["user"],
|
|
||||||
"interfaces": ["connectable"],
|
|
||||||
"paramTypes": [
|
|
||||||
{
|
{
|
||||||
"id": "f1c43b1e-cffe-4d30-bda0-c23ed648dd71",
|
"name": "mtec",
|
||||||
"name": "ipAddress",
|
"displayName": "MTec",
|
||||||
"displayName": "IP address",
|
"id": "451e38d8-50d5-4ae9-8d9f-21af9347128d",
|
||||||
"type": "QString"
|
"createMethods": ["discovery", "user"],
|
||||||
}
|
"interfaces": ["connectable"],
|
||||||
],
|
"paramTypes": [
|
||||||
"stateTypes": [
|
{
|
||||||
{
|
"id": "f1c43b1e-cffe-4d30-bda0-c23ed648dd71",
|
||||||
"id": "8d64954a-855d-44ea-8bc9-88a71ab47b6b",
|
"name": "ipAddress",
|
||||||
"name": "connected",
|
"displayName": "IP address",
|
||||||
"displayName": "Connected",
|
"type": "QString",
|
||||||
"displayNameEvent": "Connected changed",
|
"inputType": "IPv4Address",
|
||||||
"type": "bool",
|
"defaultValue": "127.0.0.1"
|
||||||
"defaultValue": false,
|
},
|
||||||
"cached": false
|
{
|
||||||
},
|
"id": "906f6099-d0e1-4297-a2b3-f8ec4482c578",
|
||||||
{
|
"name":"macAddress",
|
||||||
"id": "9bf5f8d6-116a-4399-a728-51470a3a5620",
|
"displayName": "MAC address",
|
||||||
"name": "status",
|
"type": "QString",
|
||||||
"displayName": "Status",
|
"inputType": "MacAddress",
|
||||||
"displayNameEvent": "Status changed",
|
"defaultValue": ""
|
||||||
"type": "QString",
|
}
|
||||||
"defaultValue": "Off",
|
],
|
||||||
"possibleValues": [
|
"stateTypes": [
|
||||||
"Off",
|
{
|
||||||
"Connecting",
|
"id": "8d64954a-855d-44ea-8bc9-88a71ab47b6b",
|
||||||
"Connected",
|
"name": "connected",
|
||||||
"Error"
|
"displayName": "Connected",
|
||||||
]
|
"displayNameEvent": "Connected changed",
|
||||||
},
|
"type": "bool",
|
||||||
{
|
"defaultValue": false,
|
||||||
"id": "c67c79cf-7369-409f-b170-16c4ece9d25a",
|
"cached": false
|
||||||
"name": "actualPowerConsumption",
|
},
|
||||||
"displayName": "Actual power consumption",
|
{
|
||||||
"displayNameEvent": "Actual power consumption changed",
|
"id": "c67c79cf-7369-409f-b170-16c4ece9d25a",
|
||||||
"type": "double",
|
"name": "actualPowerConsumption",
|
||||||
"unit": "Watt",
|
"displayName": "Actual power consumption",
|
||||||
"defaultValue": 0
|
"displayNameEvent": "Actual power consumption changed",
|
||||||
},
|
"type": "double",
|
||||||
{
|
"unit": "Watt",
|
||||||
"id": "663718fa-807e-4d85-bd78-61a65f8c0b5e",
|
"defaultValue": 0
|
||||||
"name": "actualExcessEnergySmartHome",
|
},
|
||||||
"displayName": "Actual excess energy from Smart home System",
|
{
|
||||||
"displayNameEvent": "Actual excess energy from Smart home System changed",
|
"id": "663718fa-807e-4d85-bd78-61a65f8c0b5e",
|
||||||
"displayNameAction": "Change actual excess energy from Smart home System",
|
"name": "actualExcessEnergySmartHome",
|
||||||
"type": "double",
|
"displayName": "Actual excess energy from Smart home System",
|
||||||
"unit": "Watt",
|
"displayNameEvent": "Actual excess energy from Smart home System changed",
|
||||||
"defaultValue": 0
|
"displayNameAction": "Change actual excess energy from Smart home System",
|
||||||
},
|
"type": "double",
|
||||||
{
|
"unit": "Watt",
|
||||||
"id": "fd94d39c-0db6-497f-a0a5-6c5452cbcaaf",
|
"defaultValue": 0
|
||||||
"name": "actualExcessEnergyElectricityMeter",
|
},
|
||||||
"displayName": "Actual excess energy from Electricity Meter",
|
{
|
||||||
"displayNameEvent": "Actual excess energy from Electricity Meter changed",
|
"id": "fd94d39c-0db6-497f-a0a5-6c5452cbcaaf",
|
||||||
"type": "double",
|
"name": "actualExcessEnergyElectricityMeter",
|
||||||
"unit": "Watt",
|
"displayName": "Actual excess energy from Electricity Meter",
|
||||||
"defaultValue": 0
|
"displayNameEvent": "Actual excess energy from Electricity Meter changed",
|
||||||
},
|
"type": "double",
|
||||||
{
|
"unit": "Watt",
|
||||||
"id": "087c0296-705b-483a-b1e9-7ce08202c035",
|
"defaultValue": 0
|
||||||
"name": "externalSetValueScaling",
|
},
|
||||||
"displayName": "Control of the heat source by an external control [100%]",
|
{
|
||||||
"displayNameEvent": "Control of the heat source by an external control [100%] changed",
|
"id": "087c0296-705b-483a-b1e9-7ce08202c035",
|
||||||
"type": "double",
|
"name": "externalSetValueScaling",
|
||||||
"unit": "Percentage",
|
"displayName": "Control of the heat source by an external control [100%]",
|
||||||
"defaultValue": 100
|
"displayNameEvent": "Control of the heat source by an external control [100%] changed",
|
||||||
},
|
"type": "double",
|
||||||
{
|
"unit": "Percentage",
|
||||||
"id": "90b17788-ce63-47e3-b97d-1b025a41ce35",
|
"defaultValue": 100
|
||||||
"name": "requestExternalHeatSource",
|
},
|
||||||
"displayName": "Request external heat source",
|
{
|
||||||
"displayNameEvent": "Request external heat source changed",
|
"id": "90b17788-ce63-47e3-b97d-1b025a41ce35",
|
||||||
"type": "QString",
|
"name": "requestExternalHeatSource",
|
||||||
"defaultValue": "No request, external heat source must be turned off",
|
"displayName": "Request external heat source",
|
||||||
"possibleValues": [
|
"displayNameEvent": "Request external heat source changed",
|
||||||
"No request, external heat source must be turned off",
|
"type": "QString",
|
||||||
"External heat source is released and can be switched on",
|
"defaultValue": "No request, external heat source must be turned off",
|
||||||
"External heat source is required and must be turned on"
|
"possibleValues": [
|
||||||
|
"No request, external heat source must be turned off",
|
||||||
|
"External heat source is released and can be switched on",
|
||||||
|
"External heat source is required and must be turned on"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"actionTypes": [
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
],
|
|
||||||
"actionTypes": [
|
|
||||||
]
|
|
||||||
}
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
@ -39,13 +39,11 @@ MTec::MTec(const QHostAddress &address, QObject *parent) :
|
|||||||
m_hostAddress(address)
|
m_hostAddress(address)
|
||||||
{
|
{
|
||||||
m_modbusMaster = new ModbusTCPMaster(address, 502, this);
|
m_modbusMaster = new ModbusTCPMaster(address, 502, this);
|
||||||
|
m_modbusMaster->setTimeout(2000);
|
||||||
|
m_modbusMaster->setNumberOfRetries(5);
|
||||||
|
|
||||||
qCDebug(dcMTec()) << "created ModbusTCPMaster";
|
qCDebug(dcMTec()) << "Created ModbusTCPMaster for" << address.toString();
|
||||||
|
connect(m_modbusMaster, &ModbusTCPMaster::connectionStateChanged, this, &MTec::connectedChanged);
|
||||||
if (m_modbusMaster->connectDevice()) {
|
|
||||||
emit connectedChanged(MTecHelpers::ConnectionState::Connecting);
|
|
||||||
}
|
|
||||||
|
|
||||||
connect(m_modbusMaster, &ModbusTCPMaster::receivedHoldingRegister, this, &MTec::onReceivedHoldingRegister);
|
connect(m_modbusMaster, &ModbusTCPMaster::receivedHoldingRegister, this, &MTec::onReceivedHoldingRegister);
|
||||||
connect(m_modbusMaster, &ModbusTCPMaster::readRequestError, this, &MTec::onModbusError);
|
connect(m_modbusMaster, &ModbusTCPMaster::readRequestError, this, &MTec::onModbusError);
|
||||||
connect(m_modbusMaster, &ModbusTCPMaster::writeRequestError, this, &MTec::onModbusError);
|
connect(m_modbusMaster, &ModbusTCPMaster::writeRequestError, this, &MTec::onModbusError);
|
||||||
@ -55,59 +53,35 @@ MTec::~MTec()
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
void MTec::onModbusError()
|
bool MTec::connectDevice()
|
||||||
{
|
{
|
||||||
qCWarning(dcMTec()) << "MTec: Received modbus error";
|
return m_modbusMaster->connectDevice();
|
||||||
|
|
||||||
/* Only emit connected changed signal, if a soft connection
|
|
||||||
* had already been established.
|
|
||||||
* This avoids a series of possibly fake connection state changes,
|
|
||||||
* while the modbus server in the heatpump is starting up. */
|
|
||||||
if (m_softConnection) {
|
|
||||||
m_softConnection = false;
|
|
||||||
emit connectedChanged(MTecHelpers::ConnectionState::Offline);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MTec::onRequestStatus()
|
void MTec::disconnectDevice()
|
||||||
{
|
{
|
||||||
if ((m_softConnection) ||
|
m_modbusMaster->disconnectDevice();
|
||||||
((m_connected) && (m_requestsSent < MTec::ConnectionRetries))) {
|
}
|
||||||
|
|
||||||
if (m_requestsSent < MTec::ConnectionRetries) {
|
void MTec::requestStatus()
|
||||||
m_firstTimeout = QDateTime::currentDateTime();
|
{
|
||||||
m_firstTimeout = m_firstTimeout.addSecs(MTec::FirstConnectionTimeout);
|
if (!m_modbusMaster->connected()) {
|
||||||
|
|
||||||
/* Save original modbus timeout, will be set again
|
|
||||||
* after first response is received */
|
|
||||||
m_modbusTimeout = m_modbusMaster->timeout();
|
|
||||||
|
|
||||||
/* The M-Tec heatpump requires a longer timeout to
|
|
||||||
* start-up the modbus communication */
|
|
||||||
m_modbusMaster->setTimeout(MTec::FirstConnectionTimeout);
|
|
||||||
} else {
|
|
||||||
/* Set back original modbus timeout */
|
|
||||||
m_modbusMaster->setTimeout(m_modbusTimeout);
|
|
||||||
}
|
|
||||||
|
|
||||||
} else {
|
|
||||||
qCDebug(dcMTec()) << "Max number of modbus connects reached, giving up";
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
m_modbusMaster->readHoldingRegister(MTec::ModbusUnitID, MTec::ActualPowerConsumption, 1);
|
m_modbusMaster->readHoldingRegister(MTec::ModbusUnitID, MTec::ActualPowerConsumption, 1);
|
||||||
m_requestsSent ++;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void MTec::onModbusError()
|
||||||
|
{
|
||||||
|
qCWarning(dcMTec()) << "MTec: Received modbus error";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void MTec::onReceivedHoldingRegister(int slaveAddress, int modbusRegister, const QVector<quint16> &value)
|
void MTec::onReceivedHoldingRegister(int slaveAddress, int modbusRegister, const QVector<quint16> &value)
|
||||||
{
|
{
|
||||||
Q_UNUSED(slaveAddress);
|
Q_UNUSED(slaveAddress);
|
||||||
|
|
||||||
/* Some response was received, so the modbus communication is
|
|
||||||
* established. */
|
|
||||||
m_softConnection = true;
|
|
||||||
emit connectedChanged(MTecHelpers::ConnectionState::Online);
|
|
||||||
|
|
||||||
switch (modbusRegister) {
|
switch (modbusRegister) {
|
||||||
case ActualPowerConsumption:
|
case ActualPowerConsumption:
|
||||||
if (value.length() == 1) {
|
if (value.length() == 1) {
|
||||||
|
|||||||
30
mtec/mtec.h
30
mtec/mtec.h
@ -49,23 +49,17 @@ public:
|
|||||||
/** Destructor */
|
/** Destructor */
|
||||||
~MTec();
|
~MTec();
|
||||||
|
|
||||||
inline QHostAddress getHostAddress() const { return m_hostAddress; };
|
inline QHostAddress hostAddress() const { return m_hostAddress; };
|
||||||
|
|
||||||
|
bool connectDevice();
|
||||||
|
void disconnectDevice();
|
||||||
|
|
||||||
|
void requestStatus();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/**
|
|
||||||
* The first response of the M-Tec heatpump may be delayed
|
|
||||||
* by 10 s. The plugin will wait for the defined time in milliseconds
|
|
||||||
* for a response before sending an additional request or setting
|
|
||||||
* an error code.
|
|
||||||
*/
|
|
||||||
static const int FirstConnectionTimeout = 15000;
|
|
||||||
|
|
||||||
/** Modbus Unit ID (undocumented, guessing 1 for now) */
|
/** Modbus Unit ID (undocumented, guessing 1 for now) */
|
||||||
static const quint16 ModbusUnitID = 1;
|
static const quint16 ModbusUnitID = 1;
|
||||||
|
|
||||||
/** Number of retries to establish a modbus connection with the heat pump */
|
|
||||||
static const int ConnectionRetries = 3;
|
|
||||||
|
|
||||||
/** The following modbus addresses can be read: */
|
/** The following modbus addresses can be read: */
|
||||||
enum RegisterList {
|
enum RegisterList {
|
||||||
/**
|
/**
|
||||||
@ -112,21 +106,13 @@ private:
|
|||||||
/** This structure is filled by the receivedStatus... functions */
|
/** This structure is filled by the receivedStatus... functions */
|
||||||
MTecInfo m_info ;
|
MTecInfo m_info ;
|
||||||
|
|
||||||
int m_requestsSent = 0;
|
|
||||||
bool m_connected = false;
|
|
||||||
bool m_softConnection = false;
|
|
||||||
|
|
||||||
QDateTime m_firstTimeout;
|
|
||||||
|
|
||||||
int m_modbusTimeout;
|
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void connectedChanged(MTecHelpers::ConnectionState state);
|
void connectedChanged(bool connected);
|
||||||
void statusUpdated(const MTecInfo &info);
|
void statusUpdated(const MTecInfo &info);
|
||||||
|
|
||||||
public slots:
|
private slots:
|
||||||
void onModbusError();
|
void onModbusError();
|
||||||
void onRequestStatus();
|
|
||||||
void onReceivedHoldingRegister(int slaveAddress, int modbusRegister, const QVector<quint16> &value);
|
void onReceivedHoldingRegister(int slaveAddress, int modbusRegister, const QVector<quint16> &value);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user