nymea/plugins/deviceplugins/eq-3/deviceplugineq-3.cpp

374 lines
18 KiB
C++

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* Copyright (C) 2015 Simon Stürz <simon.stuerz@guh.guru> *
* *
* This file is part of guh. *
* *
* Guh is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, version 2 of the License. *
* *
* Guh is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with guh. 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 guh-plugins
This plugin allows to find and controll 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://guh.guru}{guh} 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 programm...).
\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 guh.
\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()
{
m_cubeDiscovery = new MaxCubeDiscovery(this);
connect(m_cubeDiscovery,SIGNAL(cubesDetected(QList<MaxCube*>)),this,SLOT(discoveryDone(QList<MaxCube*>)));
}
DeviceManager::HardwareResources DevicePluginEQ3::requiredHardware() const
{
return DeviceManager::HardwareResourceTimer;
}
DeviceManager::DeviceError DevicePluginEQ3::discoverDevices(const DeviceClassId &deviceClassId, const ParamList &params)
{
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(serialParamTypeId).toString()){
qCDebug(dcEQ3) << cube->serialNumber() << " already exists...";
return DeviceManager::DeviceSetupStatusFailure;
}
}
MaxCube *cube = new MaxCube(this,device->paramValue(serialParamTypeId).toString(),QHostAddress(device->paramValue(hostParamTypeId).toString()),device->paramValue(portParamTypeId).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(serialParamTypeId).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();
}
void DevicePluginEQ3::guhTimer()
{
foreach (MaxCube *cube, m_cubes.keys()){
if(cube->isConnected() && cube->isInitialized()){
cube->refresh();
}
}
}
DeviceManager::DeviceError DevicePluginEQ3::executeAction(Device *device, const Action &action)
{
if(device->deviceClassId() == wallThermostateDeviceClassId || device->deviceClassId() == radiatorThermostateDeviceClassId){
foreach (MaxCube *cube, m_cubes.keys()){
if(cube->serialNumber() == device->paramValue(parentParamTypeId).toString()){
QByteArray rfAddress = device->paramValue(rfParamTypeId).toByteArray();
int roomId = device->paramValue(roomParamTypeId).toInt();
if (action.actionTypeId() == desiredTemperatureActionTypeId){
cube->setDeviceSetpointTemp(rfAddress, roomId, action.param(desiredTemperatureStateParamTypeId).value().toDouble(), action.id());
} else if (action.actionTypeId() == setAutoModeActionTypeId){
cube->setDeviceAutoMode(rfAddress, roomId, action.id());
} else if (action.actionTypeId() == setManualModeActionTypeId){
cube->setDeviceManuelMode(rfAddress, roomId, action.id());
} else if (action.actionTypeId() == setEcoModeActionTypeId){
cube->setDeviceEcoMode(rfAddress, roomId, action.id());
} else if (action.actionTypeId() == displayCurrentTempActionTypeId){
cube->displayCurrentTemperature(rfAddress, roomId, action.param(displayParamTypeId).value().toBool(), action.id());
}
return DeviceManager::DeviceErrorAsync;
}
}
}
return DeviceManager::DeviceErrorActionTypeNotFound;
}
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(connectionStateTypeId,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(connectionStateTypeId,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(hostParamTypeId, cube->hostAddress().toString());
params.append(hostParam);
Param portParam(portParamTypeId, cube->port());
params.append(portParam);
Param firmwareParam(firmwareParamTypeId, cube->firmware());
params.append(firmwareParam);
Param serialNumberParam(serialParamTypeId, 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(serialParamTypeId).toString()){
allreadyAdded = true;
break;
}
}
if(!allreadyAdded){
DeviceDescriptor descriptor(wallThermostateDeviceClassId, wallThermostat->serialNumber());
ParamList params;
params.append(Param(nameParamTypeId, wallThermostat->deviceName()));
params.append(Param(parentParamTypeId, cube->serialNumber()));
params.append(Param(serialParamTypeId, wallThermostat->serialNumber()));
params.append(Param(rfParamTypeId, wallThermostat->rfAddress()));
params.append(Param(roomParamTypeId, wallThermostat->roomId()));
params.append(Param(roomNameParamTypeId, 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(serialParamTypeId).toString()){
allreadyAdded = true;
break;
}
}
if(!allreadyAdded){
DeviceDescriptor descriptor(radiatorThermostateDeviceClassId, radiatorThermostat->serialNumber());
ParamList params;
params.append(Param(nameParamTypeId, radiatorThermostat->deviceName()));
params.append(Param(parentParamTypeId, cube->serialNumber()));
params.append(Param(serialParamTypeId, radiatorThermostat->serialNumber()));
params.append(Param(rfParamTypeId, radiatorThermostat->rfAddress()));
params.append(Param(roomParamTypeId, radiatorThermostat->roomId()));
params.append(Param(roomNameParamTypeId, 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(portalEnabledStateTypeId,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(serialParamTypeId).toString() == wallThermostat->serialNumber()){
device->setStateValue(comfortTempStateTypeId, wallThermostat->comfortTemp());
device->setStateValue(ecoTempStateTypeId, wallThermostat->ecoTemp());
device->setStateValue(maxSetpointTempStateTypeId, wallThermostat->maxSetPointTemp());
device->setStateValue(minSetpointTempStateTypeId, wallThermostat->minSetPointTemp());
device->setStateValue(errorOccurredStateTypeId, wallThermostat->errorOccured());
device->setStateValue(initializedStateTypeId, wallThermostat->initialized());
device->setStateValue(batteryLowStateTypeId, wallThermostat->batteryLow());
device->setStateValue(linkStatusOKStateTypeId, wallThermostat->linkStatusOK());
device->setStateValue(panelLockedStateTypeId, wallThermostat->panelLocked());
device->setStateValue(gatewayKnownStateTypeId, wallThermostat->gatewayKnown());
device->setStateValue(dtsActiveStateTypeId, wallThermostat->dtsActive());
device->setStateValue(deviceModeStateTypeId, wallThermostat->deviceMode());
device->setStateValue(deviceModeStringStateTypeId, wallThermostat->deviceModeString());
device->setStateValue(desiredTemperatureStateTypeId, wallThermostat->setpointTemperature());
device->setStateValue(currentTemperatureStateTypeId, 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(serialParamTypeId).toString() == radiatorThermostat->serialNumber()){
device->setStateValue(comfortTempStateTypeId, radiatorThermostat->comfortTemp());
device->setStateValue(ecoTempStateTypeId, radiatorThermostat->ecoTemp());
device->setStateValue(maxSetpointTempStateTypeId, radiatorThermostat->maxSetPointTemp());
device->setStateValue(minSetpointTempStateTypeId, radiatorThermostat->minSetPointTemp());
device->setStateValue(errorOccurredStateTypeId, radiatorThermostat->errorOccured());
device->setStateValue(initializedStateTypeId, radiatorThermostat->initialized());
device->setStateValue(batteryLowStateTypeId, radiatorThermostat->batteryLow());
device->setStateValue(linkStatusOKStateTypeId, radiatorThermostat->linkStatusOK());
device->setStateValue(panelLockedStateTypeId, radiatorThermostat->panelLocked());
device->setStateValue(gatewayKnownStateTypeId, radiatorThermostat->gatewayKnown());
device->setStateValue(dtsActiveStateTypeId, radiatorThermostat->dtsActive());
device->setStateValue(deviceModeStateTypeId, radiatorThermostat->deviceMode());
device->setStateValue(deviceModeStringStateTypeId, radiatorThermostat->deviceModeString());
device->setStateValue(desiredTemperatureStateTypeId, radiatorThermostat->setpointTemperature());
device->setStateValue(offsetTempStateTypeId, radiatorThermostat->offsetTemp());
device->setStateValue(windowOpenDurationStateTypeId, radiatorThermostat->windowOpenDuration());
device->setStateValue(boostValveValueStateTypeId, radiatorThermostat->boostValveValue());
device->setStateValue(boostDurationStateTypeId, radiatorThermostat->boostDuration());
device->setStateValue(discalcWeekDayStateTypeId, radiatorThermostat->discalcingWeekDay());
device->setStateValue(discalcTimeStateTypeId, radiatorThermostat->discalcingTime().toString("HH:mm"));
device->setStateValue(valveMaximumSettingsStateTypeId, radiatorThermostat->valveMaximumSettings());
device->setStateValue(valveOffsetStateTypeId, radiatorThermostat->valveOffset());
device->setStateValue(valvePositionStateTypeId, radiatorThermostat->valvePosition());
}
}
}
}