400 lines
21 KiB
C++
400 lines
21 KiB
C++
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
|
|
* *
|
|
* Copyright (C) 2015 Simon Stürz <simon.stuerz@guh.io> *
|
|
* *
|
|
* This file is part of nymea. *
|
|
* *
|
|
* This library is free software; you can redistribute it and/or *
|
|
* modify it under the terms of the GNU Lesser General Public *
|
|
* License as published by the Free Software Foundation; either *
|
|
* version 2.1 of the License, or (at your option) any later version. *
|
|
* *
|
|
* This library 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 library; If not, see *
|
|
* <http://www.gnu.org/licenses/>. *
|
|
* *
|
|
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
|
|
|
|
/*!
|
|
\page eq3.html
|
|
\title eQ-3 Max!
|
|
\brief Plugin for the eQ-3 heating system.
|
|
|
|
\ingroup plugins
|
|
\ingroup nymea-plugins
|
|
|
|
This plugin allows to find and control devices from Max!(eQ-3). To use this devices, you need at least
|
|
one \l{http://www.eq-3.de/max-heizungssteuerung-produktdetail/items/bc-lgw-o-tw.html}{Max! Cube LAN Gateway}
|
|
in you local network. Once the cube is connected (DHCP), you can auto detect the cube in the network and
|
|
add it to your \l{https://nymea.io}{nymea} devices. Also more than one cube in the network is supported. All
|
|
devices, which are connected to a cube, will be autogenerated. For the setup of a cube, the original
|
|
software is recomanded (min/max setpoint temperature, weekly program...).
|
|
|
|
\chapter Supported devices
|
|
\section2 Max! Cube LAN Gateway
|
|
This \l{http://www.eq-3.de/max-heizungssteuerung-produktdetail/
|
|
items/bc-lgw-o-tw.html}{cube} can be discovered in the network. Every
|
|
device, which is connected with the cube, will be appear automatically, once the cube is configrued and
|
|
added to nymea.
|
|
|
|
\section2 Max! Wall Thermostat
|
|
In order to use this device, you need a \l{http://www.eq-3.de/max-heizungssteuerung-produktdetail/
|
|
items/bc-lgw-o-tw.html}{Max! Cube LAN Gateway}. A \l{http://www.eq-3.de/max-raumloesung-produktdetail/items/bc-tc-c-wm.html}{MAX! Wall Thermostat} can not be added,
|
|
it will appear automatically in the device list, once you add it to the cube.
|
|
|
|
\section2 Max! Radiator Thermostat
|
|
In order to use this device, you need a \l{http://www.eq-3.de/max-heizungssteuerung-produktdetail/
|
|
items/bc-lgw-o-tw.html}{Max! Cube LAN Gateway}. A \l{http://www.eq-3.de/max-heizungssteuerung-produktdetail/items/bc-rt-trx-cyg.html}{MAX! Radiator Thermostat} can not be added,
|
|
it will appear automatically in the device list, once you add it to the cube.
|
|
|
|
\chapter Plugin properties
|
|
Following JSON file contains the definition and the description of all available \l{DeviceClass}{DeviceClasses}
|
|
and \l{Vendor}{Vendors} of this \l{DevicePlugin}.
|
|
|
|
For more details how to read this JSON file please check out the documentation for \l{The plugin JSON File}.
|
|
|
|
\quotefile plugins/deviceplugins/eq-3/deviceplugineq-3.json
|
|
*/
|
|
|
|
|
|
#include "deviceplugineq-3.h"
|
|
|
|
#include "plugin/device.h"
|
|
#include "devicemanager.h"
|
|
#include "types/param.h"
|
|
#include "plugininfo.h"
|
|
|
|
#include <QDebug>
|
|
|
|
DevicePluginEQ3::DevicePluginEQ3()
|
|
{
|
|
|
|
}
|
|
|
|
DevicePluginEQ3::~DevicePluginEQ3()
|
|
{
|
|
hardwareManager()->pluginTimerManager()->unregisterTimer(m_pluginTimer);
|
|
}
|
|
|
|
void DevicePluginEQ3::init()
|
|
{
|
|
m_cubeDiscovery = new MaxCubeDiscovery(this);
|
|
connect(m_cubeDiscovery, &MaxCubeDiscovery::cubesDetected, this, &DevicePluginEQ3::discoveryDone);
|
|
|
|
m_pluginTimer = hardwareManager()->pluginTimerManager()->registerTimer(10);
|
|
connect(m_pluginTimer, &PluginTimer::timeout, this, &DevicePluginEQ3::onPluginTimer);
|
|
}
|
|
|
|
DeviceManager::DeviceError DevicePluginEQ3::discoverDevices(const DeviceClassId &deviceClassId, const ParamList ¶ms)
|
|
{
|
|
Q_UNUSED(params)
|
|
if(deviceClassId == cubeDeviceClassId){
|
|
m_cubeDiscovery->detectCubes();
|
|
return DeviceManager::DeviceErrorAsync;
|
|
}
|
|
return DeviceManager::DeviceErrorDeviceClassNotFound;
|
|
}
|
|
|
|
void DevicePluginEQ3::startMonitoringAutoDevices()
|
|
{
|
|
|
|
}
|
|
|
|
DeviceManager::DeviceSetupStatus DevicePluginEQ3::setupDevice(Device *device)
|
|
{
|
|
qCDebug(dcEQ3) << "Setup device" << device->params();
|
|
|
|
if(device->deviceClassId() == cubeDeviceClassId){
|
|
foreach (MaxCube *cube, m_cubes.keys()) {
|
|
if(cube->serialNumber() == device->paramValue(cubeDeviceSerialParamTypeId).toString()){
|
|
qCDebug(dcEQ3) << cube->serialNumber() << " already exists...";
|
|
return DeviceManager::DeviceSetupStatusFailure;
|
|
}
|
|
}
|
|
|
|
MaxCube *cube = new MaxCube(this,device->paramValue(cubeDeviceSerialParamTypeId).toString(),QHostAddress(device->paramValue(cubeDeviceHostParamTypeId).toString()),device->paramValue(cubeDevicePortParamTypeId).toInt());
|
|
m_cubes.insert(cube,device);
|
|
|
|
connect(cube,SIGNAL(cubeConnectionStatusChanged(bool)),this,SLOT(cubeConnectionStatusChanged(bool)));
|
|
connect(cube,SIGNAL(commandActionFinished(bool,ActionId)),this,SLOT(commandActionFinished(bool,ActionId)));
|
|
connect(cube,SIGNAL(cubeConfigReady()),this,SLOT(updateCubeConfig()));
|
|
connect(cube,SIGNAL(wallThermostatFound()),this,SLOT(wallThermostatFound()));
|
|
connect(cube,SIGNAL(wallThermostatDataUpdated()),this,SLOT(wallThermostatDataUpdated()));
|
|
connect(cube,SIGNAL(radiatorThermostatFound()),this,SLOT(radiatorThermostatFound()));
|
|
connect(cube,SIGNAL(radiatorThermostatDataUpdated()),this,SLOT(radiatorThermostatDataUpdated()));
|
|
|
|
cube->connectToCube();
|
|
|
|
return DeviceManager::DeviceSetupStatusAsync;
|
|
}
|
|
if(device->deviceClassId() == wallThermostateDeviceClassId){
|
|
device->setName("Max! Wall Thermostat (" + device->paramValue(wallThermostateDeviceSerialParamTypeId).toString() + ")");
|
|
}
|
|
|
|
return DeviceManager::DeviceSetupStatusSuccess;
|
|
}
|
|
|
|
void DevicePluginEQ3::deviceRemoved(Device *device)
|
|
{
|
|
if (!m_cubes.values().contains(device)) {
|
|
return;
|
|
}
|
|
|
|
MaxCube *cube = m_cubes.key(device);
|
|
cube->disconnectFromCube();
|
|
qCDebug(dcEQ3) << "remove cube " << cube->serialNumber();
|
|
m_cubes.remove(cube);
|
|
cube->deleteLater();
|
|
}
|
|
|
|
DeviceManager::DeviceError DevicePluginEQ3::executeAction(Device *device, const Action &action)
|
|
{
|
|
if(device->deviceClassId() == wallThermostateDeviceClassId){
|
|
foreach (MaxCube *cube, m_cubes.keys()){
|
|
if(cube->serialNumber() == device->paramValue(wallThermostateDeviceParentParamTypeId).toString()){
|
|
|
|
QByteArray rfAddress = device->paramValue(wallThermostateDeviceRfParamTypeId).toByteArray();
|
|
int roomId = device->paramValue(wallThermostateDeviceRoomParamTypeId).toInt();
|
|
|
|
if (action.actionTypeId() == wallThermostateDesiredTemperatureActionTypeId){
|
|
cube->setDeviceSetpointTemp(rfAddress, roomId, action.param(wallThermostateDesiredTemperatureActionDesiredTemperatureParamTypeId).value().toDouble(), action.id());
|
|
} else if (action.actionTypeId() == wallThermostateSetAutoModeActionTypeId){
|
|
cube->setDeviceAutoMode(rfAddress, roomId, action.id());
|
|
} else if (action.actionTypeId() == wallThermostateSetManualModeActionTypeId){
|
|
cube->setDeviceManuelMode(rfAddress, roomId, action.id());
|
|
} else if (action.actionTypeId() == wallThermostateSetEcoModeActionTypeId){
|
|
cube->setDeviceEcoMode(rfAddress, roomId, action.id());
|
|
} else if (action.actionTypeId() == wallThermostateDisplayCurrentTempActionTypeId){
|
|
cube->displayCurrentTemperature(rfAddress, roomId, action.param(wallThermostateDisplayCurrentTempActionDisplayParamTypeId).value().toBool(), action.id());
|
|
}
|
|
return DeviceManager::DeviceErrorAsync;
|
|
}
|
|
}
|
|
} else if (device->deviceClassId() == radiatorThermostateDeviceClassId){
|
|
foreach (MaxCube *cube, m_cubes.keys()){
|
|
if(cube->serialNumber() == device->paramValue(radiatorThermostateDeviceParentParamTypeId).toString()){
|
|
|
|
QByteArray rfAddress = device->paramValue(radiatorThermostateDeviceRfParamTypeId).toByteArray();
|
|
int roomId = device->paramValue(radiatorThermostateDeviceRoomParamTypeId).toInt();
|
|
|
|
if (action.actionTypeId() == radiatorThermostateDesiredTemperatureActionTypeId){
|
|
cube->setDeviceSetpointTemp(rfAddress, roomId, action.param(radiatorThermostateDesiredTemperatureActionDesiredTemperatureParamTypeId).value().toDouble(), action.id());
|
|
} else if (action.actionTypeId() == radiatorThermostateSetAutoModeActionTypeId){
|
|
cube->setDeviceAutoMode(rfAddress, roomId, action.id());
|
|
} else if (action.actionTypeId() == radiatorThermostateSetManualModeActionTypeId){
|
|
cube->setDeviceManuelMode(rfAddress, roomId, action.id());
|
|
} else if (action.actionTypeId() == radiatorThermostateSetEcoModeActionTypeId){
|
|
cube->setDeviceEcoMode(rfAddress, roomId, action.id());
|
|
}
|
|
return DeviceManager::DeviceErrorAsync;
|
|
}
|
|
}
|
|
}
|
|
|
|
return DeviceManager::DeviceErrorActionTypeNotFound;
|
|
}
|
|
|
|
void DevicePluginEQ3::onPluginTimer()
|
|
{
|
|
foreach (MaxCube *cube, m_cubes.keys()){
|
|
if(cube->isConnected() && cube->isInitialized()){
|
|
cube->refresh();
|
|
}
|
|
}
|
|
}
|
|
|
|
void DevicePluginEQ3::cubeConnectionStatusChanged(const bool &connected)
|
|
{
|
|
if(connected){
|
|
MaxCube *cube = static_cast<MaxCube*>(sender());
|
|
Device *device;
|
|
if (m_cubes.contains(cube)) {
|
|
device = m_cubes.value(cube);
|
|
device->setName("Max! Cube " + cube->serialNumber());
|
|
device->setStateValue(cubeConnectionStateTypeId,true);
|
|
emit deviceSetupFinished(device, DeviceManager::DeviceSetupStatusSuccess);
|
|
}
|
|
}else{
|
|
MaxCube *cube = static_cast<MaxCube*>(sender());
|
|
Device *device;
|
|
if (m_cubes.contains(cube)){
|
|
device = m_cubes.value(cube);
|
|
device->setStateValue(cubeConnectionStateTypeId,false);
|
|
emit deviceSetupFinished(device, DeviceManager::DeviceSetupStatusFailure);
|
|
}
|
|
}
|
|
}
|
|
|
|
void DevicePluginEQ3::discoveryDone(const QList<MaxCube *> &cubeList)
|
|
{
|
|
QList<DeviceDescriptor> retList;
|
|
foreach (MaxCube *cube, cubeList) {
|
|
DeviceDescriptor descriptor(cubeDeviceClassId, "Max! Cube LAN Gateway",cube->serialNumber());
|
|
ParamList params;
|
|
Param hostParam(cubeDeviceHostParamTypeId, cube->hostAddress().toString());
|
|
params.append(hostParam);
|
|
Param portParam(cubeDevicePortParamTypeId, cube->port());
|
|
params.append(portParam);
|
|
Param firmwareParam(cubeDeviceFirmwareParamTypeId, cube->firmware());
|
|
params.append(firmwareParam);
|
|
Param serialNumberParam(cubeDeviceSerialParamTypeId, cube->serialNumber());
|
|
params.append(serialNumberParam);
|
|
|
|
descriptor.setParams(params);
|
|
retList.append(descriptor);
|
|
}
|
|
emit devicesDiscovered(cubeDeviceClassId,retList);
|
|
}
|
|
|
|
void DevicePluginEQ3::commandActionFinished(const bool &succeeded, const ActionId &actionId)
|
|
{
|
|
if(succeeded){
|
|
emit actionExecutionFinished(actionId, DeviceManager::DeviceErrorNoError);
|
|
}else{
|
|
emit actionExecutionFinished(actionId, DeviceManager::DeviceErrorSetupFailed);
|
|
}
|
|
}
|
|
|
|
void DevicePluginEQ3::wallThermostatFound()
|
|
{
|
|
MaxCube *cube = static_cast<MaxCube*>(sender());
|
|
|
|
QList<DeviceDescriptor> descriptorList;
|
|
|
|
foreach (WallThermostat *wallThermostat, cube->wallThermostatList()) {
|
|
bool allreadyAdded = false;
|
|
foreach (Device *device, deviceManager()->findConfiguredDevices(wallThermostateDeviceClassId)){
|
|
if(wallThermostat->serialNumber() == device->paramValue(wallThermostateDeviceSerialParamTypeId).toString()){
|
|
allreadyAdded = true;
|
|
break;
|
|
}
|
|
}
|
|
if(!allreadyAdded){
|
|
DeviceDescriptor descriptor(wallThermostateDeviceClassId, wallThermostat->serialNumber());
|
|
ParamList params;
|
|
params.append(Param(wallThermostateDeviceNameParamTypeId, wallThermostat->deviceName()));
|
|
params.append(Param(wallThermostateDeviceParentParamTypeId, cube->serialNumber()));
|
|
params.append(Param(wallThermostateDeviceSerialParamTypeId, wallThermostat->serialNumber()));
|
|
params.append(Param(wallThermostateDeviceRfParamTypeId, wallThermostat->rfAddress()));
|
|
params.append(Param(wallThermostateDeviceRoomParamTypeId, wallThermostat->roomId()));
|
|
params.append(Param(wallThermostateDeviceRoomNameParamTypeId, wallThermostat->roomName()));
|
|
descriptor.setParams(params);
|
|
descriptorList.append(descriptor);
|
|
}
|
|
}
|
|
|
|
if(!descriptorList.isEmpty()){
|
|
metaObject()->invokeMethod(this, "autoDevicesAppeared", Qt::QueuedConnection, Q_ARG(DeviceClassId, wallThermostateDeviceClassId), Q_ARG(QList<DeviceDescriptor>, descriptorList));
|
|
}
|
|
|
|
}
|
|
|
|
void DevicePluginEQ3::radiatorThermostatFound()
|
|
{
|
|
MaxCube *cube = static_cast<MaxCube*>(sender());
|
|
|
|
QList<DeviceDescriptor> descriptorList;
|
|
|
|
foreach (RadiatorThermostat *radiatorThermostat, cube->radiatorThermostatList()) {
|
|
bool allreadyAdded = false;
|
|
foreach (Device *device, deviceManager()->findConfiguredDevices(radiatorThermostateDeviceClassId)){
|
|
if(radiatorThermostat->serialNumber() == device->paramValue(radiatorThermostateDeviceSerialParamTypeId).toString()){
|
|
allreadyAdded = true;
|
|
break;
|
|
}
|
|
}
|
|
if(!allreadyAdded){
|
|
DeviceDescriptor descriptor(radiatorThermostateDeviceClassId, radiatorThermostat->serialNumber());
|
|
ParamList params;
|
|
params.append(Param(radiatorThermostateDeviceNameParamTypeId, radiatorThermostat->deviceName()));
|
|
params.append(Param(radiatorThermostateDeviceParentParamTypeId, cube->serialNumber()));
|
|
params.append(Param(radiatorThermostateDeviceSerialParamTypeId, radiatorThermostat->serialNumber()));
|
|
params.append(Param(radiatorThermostateDeviceRfParamTypeId, radiatorThermostat->rfAddress()));
|
|
params.append(Param(radiatorThermostateDeviceRoomParamTypeId, radiatorThermostat->roomId()));
|
|
params.append(Param(radiatorThermostateDeviceRoomNameParamTypeId, radiatorThermostat->roomName()));
|
|
descriptor.setParams(params);
|
|
descriptorList.append(descriptor);
|
|
}
|
|
}
|
|
|
|
if(!descriptorList.isEmpty()){
|
|
metaObject()->invokeMethod(this, "autoDevicesAppeared", Qt::QueuedConnection, Q_ARG(DeviceClassId, radiatorThermostateDeviceClassId), Q_ARG(QList<DeviceDescriptor>, descriptorList));
|
|
}
|
|
}
|
|
|
|
void DevicePluginEQ3::updateCubeConfig()
|
|
{
|
|
MaxCube *cube = static_cast<MaxCube*>(sender());
|
|
Device *device;
|
|
if (m_cubes.contains(cube)) {
|
|
device = m_cubes.value(cube);
|
|
device->setStateValue(cubePortalEnabledStateTypeId,cube->portalEnabeld());
|
|
return;
|
|
}
|
|
}
|
|
|
|
void DevicePluginEQ3::wallThermostatDataUpdated()
|
|
{
|
|
MaxCube *cube = static_cast<MaxCube*>(sender());
|
|
|
|
foreach (WallThermostat *wallThermostat, cube->wallThermostatList()) {
|
|
foreach (Device *device, deviceManager()->findConfiguredDevices(wallThermostateDeviceClassId)){
|
|
if(device->paramValue(wallThermostateDeviceSerialParamTypeId).toString() == wallThermostat->serialNumber()){
|
|
device->setStateValue(wallThermostateComfortTempStateTypeId, wallThermostat->comfortTemp());
|
|
device->setStateValue(wallThermostateEcoTempStateTypeId, wallThermostat->ecoTemp());
|
|
device->setStateValue(wallThermostateMaxSetpointTempStateTypeId, wallThermostat->maxSetPointTemp());
|
|
device->setStateValue(wallThermostateMinSetpointTempStateTypeId, wallThermostat->minSetPointTemp());
|
|
device->setStateValue(wallThermostateErrorOccurredStateTypeId, wallThermostat->errorOccurred());
|
|
device->setStateValue(wallThermostateInitializedStateTypeId, wallThermostat->initialized());
|
|
device->setStateValue(wallThermostateBatteryLowStateTypeId, wallThermostat->batteryLow());
|
|
device->setStateValue(wallThermostateLinkStatusOKStateTypeId, wallThermostat->linkStatusOK());
|
|
device->setStateValue(wallThermostatePanelLockedStateTypeId, wallThermostat->panelLocked());
|
|
device->setStateValue(wallThermostateGatewayKnownStateTypeId, wallThermostat->gatewayKnown());
|
|
device->setStateValue(wallThermostateDtsActiveStateTypeId, wallThermostat->dtsActive());
|
|
device->setStateValue(wallThermostateDeviceModeStateTypeId, wallThermostat->deviceMode());
|
|
device->setStateValue(wallThermostateDeviceModeStringStateTypeId, wallThermostat->deviceModeString());
|
|
device->setStateValue(wallThermostateDesiredTemperatureStateTypeId, wallThermostat->setpointTemperature());
|
|
device->setStateValue(wallThermostateCurrentTemperatureStateTypeId, wallThermostat->currentTemperature());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void DevicePluginEQ3::radiatorThermostatDataUpdated()
|
|
{
|
|
MaxCube *cube = static_cast<MaxCube*>(sender());
|
|
|
|
foreach (RadiatorThermostat *radiatorThermostat, cube->radiatorThermostatList()) {
|
|
foreach (Device *device, deviceManager()->findConfiguredDevices(radiatorThermostateDeviceClassId)){
|
|
if(device->paramValue(radiatorThermostateDeviceSerialParamTypeId).toString() == radiatorThermostat->serialNumber()){
|
|
device->setStateValue(radiatorThermostateComfortTempStateTypeId, radiatorThermostat->comfortTemp());
|
|
device->setStateValue(radiatorThermostateMaxSetpointTempStateTypeId, radiatorThermostat->maxSetPointTemp());
|
|
device->setStateValue(radiatorThermostateMinSetpointTempStateTypeId, radiatorThermostat->minSetPointTemp());
|
|
device->setStateValue(radiatorThermostateErrorOccurredStateTypeId, radiatorThermostat->errorOccurred());
|
|
device->setStateValue(radiatorThermostateInitializedStateTypeId, radiatorThermostat->initialized());
|
|
device->setStateValue(radiatorThermostateBatteryLowStateTypeId, radiatorThermostat->batteryLow());
|
|
device->setStateValue(radiatorThermostatePanelLockedStateTypeId, radiatorThermostat->panelLocked());
|
|
device->setStateValue(radiatorThermostateGatewayKnownStateTypeId, radiatorThermostat->gatewayKnown());
|
|
device->setStateValue(radiatorThermostateDtsActiveStateTypeId, radiatorThermostat->dtsActive());
|
|
device->setStateValue(radiatorThermostateDeviceModeStateTypeId, radiatorThermostat->deviceMode());
|
|
device->setStateValue(radiatorThermostateDeviceModeStringStateTypeId, radiatorThermostat->deviceModeString());
|
|
device->setStateValue(radiatorThermostateDesiredTemperatureStateTypeId, radiatorThermostat->setpointTemperature());
|
|
device->setStateValue(radiatorThermostateOffsetTempStateTypeId, radiatorThermostat->offsetTemp());
|
|
device->setStateValue(radiatorThermostateWindowOpenDurationStateTypeId, radiatorThermostat->windowOpenDuration());
|
|
device->setStateValue(radiatorThermostateBoostValveValueStateTypeId, radiatorThermostat->boostValveValue());
|
|
device->setStateValue(radiatorThermostateBoostDurationStateTypeId, radiatorThermostat->boostDuration());
|
|
device->setStateValue(radiatorThermostateDiscalcWeekDayStateTypeId, radiatorThermostat->discalcingWeekDay());
|
|
device->setStateValue(radiatorThermostateDiscalcTimeStateTypeId, radiatorThermostat->discalcingTime().toString("HH:mm"));
|
|
device->setStateValue(radiatorThermostateValveMaximumSettingsStateTypeId, radiatorThermostat->valveMaximumSettings());
|
|
device->setStateValue(radiatorThermostateValveOffsetStateTypeId, radiatorThermostat->valveOffset());
|
|
device->setStateValue(radiatorThermostateValvePositionStateTypeId, radiatorThermostat->valvePosition());
|
|
}
|
|
}
|
|
}
|
|
}
|