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

542 lines
27 KiB
C++

/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* *
* 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 wemo.html
\title eQ-3 Max!
\ingroup plugins
\ingroup services
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
\section1 Max! Cube LAN Gateway
In order to use this plugin, you need a \l{http://www.eq-3.de/max-heizungssteuerung-produktdetail/
items/bc-lgw-o-tw.html}{Max! Cube LAN Gateway}. This device can be discovered and has following propertys:
\section2 Device propertys
\section3 Device parameters
Following list contains all cube params:
\table
\header
\li Name
\li Description
\li Data Type
\row
\li host address
\li Holds the ip address from the cube
\li string
\row
\li serial number
\li Holds the serial number of the cube. This number is written on the cube.
\li string
\row
\li port
\li Holds the port, over which the cube is reachable
\li int
\row
\li firmware version
\li Holds the firmware version of the cube
\li int
\endtable
\section3 Device states
Following list contains all cube \l{State}s:
\table
\header
\li Name
\li Description
\li UUID
\li Data Type
\row
\li connected
\li This state holds connection status of the cube. If the cube is connected, this state will be true.
\li d0a9a369-cf8c-47c4-a12e-f2d076bf12fd
\li bool
\row
\li portal enabled
\li This state shows if the web portal of the cube is enabled. You can enable with the original
Max! software an login into the cube over \l{https://max.eq-3.de/login.jsp}
\li 2c2367da-c229-40ed-9d47-a6e73cd6dc3b
\li bool
\endtable
\section1 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 automaticaly in the device list, once you add it to the cube. A \l{http://www.eq-3.de/max-raumloesung-produktdetail/items/bc-tc-c-wm.html}{MAX! Wall Thermostat}
has following propertys:
\section2 Device propertys
\section3 Device parameters
Following list contains all device params:
\table
\header
\li Name
\li Description
\li Data Type
\row
\li name
\li Holds the name of the device, given during the setup in the cube
\li string
\row
\li parent cube
\li Holds the serial number of the cube, where this device is added
\li string
\row
\li rfAddress
\li Holds the RF address of the device. This parameter is not important for the user,
but for the actions.
\li string
\row
\li room number
\li Holds the room number, where the device was added. This number represents the room
from the cube-room management. Is not a guh paramter.
\li int
\row
\li room name
\li Holds the room name, where the device was added. This is the room name, which was given
during the setup on the Cube.
\li string
\endtable
\section3 Device states
Following list contains all device \l{State}s:
\table
\header
\li Name
\li Description
\li UUID
\li Data Type
\row
\li setpoint temperature [Celsius]
\li Describes the setpoint temperature. The setpoint temperatur represents the whished
temperature, which influences the radiator. This temperature can be controlled also
with the +/- Buttons on the device.
\li 579aa8c6-8814-491b-9e7c-b98108c323d1
\li double
\row
\li current temperature [Celsius]
\li Describes the current measured temperature in the room.
\li 852e7708-db1d-42d1-96e4-19c13598262c
\li double
\row
\li confort temperature [Celsius]
\li Describes the configured confort temperature. When the device goes into confort mode,
than this will be te setpoint temperature.
\li 850380ee-a787-43e7-adb8-768a21a6e64d
\li double
\row
\li eco temperature [Celsius]
\li Describes the configured eco temperature. When the device goes into eco mode,
than this will be te setpoint temperature.
\li 24dfd20d-bc8d-48e4-8162-b20ae0465c41
\li double
\row
\li max setpoint temperature [Celsius]
\li Describes the highest configurable temperature.
\li a8536ddf-a6e4-41c2-89c1-e7102608f5f6
\li double
\row
\li min setpoint temperature [Celsius]
\li Describes the lowest configurable temperature.
\li ceb0ad05-37ad-4b79-a4d9-540c34a7e3e4
\li double
\endtable
\section3 Device actions
Following list contains all device \l{Action}s:
\table
\header
\li Name
\li Description
\li UUID
\row
\li
\li With this action you can switch WeMo ON (true) or OFF (false).
\li 269f25eb-d0b7-4144-b9ef-801f4ff3e90c
\endtable
*/
#include "deviceplugineq-3.h"
#include "plugin/device.h"
#include "devicemanager.h"
#include "types/param.h"
#include <QDebug>
DeviceClassId cubeDeviceClassId = DeviceClassId("1e892268-8bd7-442c-a001-bd4e2e6b2949");
StateTypeId connectionStateTypeId = StateTypeId("d0a9a369-cf8c-47c4-a12e-f2d076bf12fd");
StateTypeId portalEnabeldStateTypeId = StateTypeId("2c2367da-c229-40ed-9d47-a6e73cd6dc3b");
DeviceClassId wallThermostateDeviceClassId = DeviceClassId("ffbfec5d-06e8-4082-b62b-92cc5c3e8c4e");
StateTypeId confortTempStateTypeId = StateTypeId("850380ee-a787-43e7-adb8-768a21a6e64d");
StateTypeId ecoTempStateTypeId = StateTypeId("24dfd20d-bc8d-48e4-8162-b20ae0465c41");
StateTypeId maxSetpointTempStateTypeId = StateTypeId("a8536ddf-a6e4-41c2-89c1-e7102608f5f6");
StateTypeId minSetpointTempStateTypeId = StateTypeId("ceb0ad05-37ad-4b79-a4d9-540c34a7e3e4");
StateTypeId errorOccuredStateTypeId = StateTypeId("9880247b-cf9a-453c-b0c3-d910eba8a253");
StateTypeId initializedStateTypeId = StateTypeId("a9e29f03-063e-4686-8aac-2f6d8f8a4937");
StateTypeId batteryLowStateTypeId = StateTypeId("53b89f32-8894-4290-92a0-6a470c6b69ab");
StateTypeId linkStatusOKStateTypeId = StateTypeId("aff38be8-7ea6-4fd8-b0fa-e987ab05c719");
StateTypeId panelLockedStateTypeId = StateTypeId("979df197-09a1-46f9-9217-9d323b1062bd");
StateTypeId gatewayKnownStateTypeId = StateTypeId("1d6bd962-5c31-47ad-80a4-dda87bff98f5");
StateTypeId dtsActiveStateTypeId = StateTypeId("1b402ba6-a8ae-45b1-8acf-2b0a89f71889");
StateTypeId deviceModeStateTypeId = StateTypeId("639360f0-bb65-43e6-b227-50ae0ac39d6c");
StateTypeId deviceModeStringStateTypeId = StateTypeId("ff5194e3-5641-4ac2-92c7-48c431b4a2eb");
StateTypeId setpointTempStateTypeId = StateTypeId("579aa8c6-8814-491b-9e7c-b98108c323d1");
StateTypeId currentTemperatureStateTypeId = StateTypeId("852e7708-db1d-42d1-96e4-19c13598262c");
ActionTypeId setSetpointTemperatureActionTypeId = ActionTypeId("9c1968ba-39f9-493d-9fe2-848fa86bd2f0");
ActionTypeId setAutoModeActionTypeId = ActionTypeId("162b4b3d-9923-4f2c-a755-b50c8a06a6f0");
ActionTypeId setManuelModeActionTypeId = ActionTypeId("8e604437-9f5b-4c17-b5b0-e2db6007af5b");
ActionTypeId setEcoModeActionTypeId = ActionTypeId("27a981e8-ec23-4ba8-921e-33b911a7dd89");
ActionTypeId displayCurrentTempActionTypeId = ActionTypeId("184fb112-7a03-4560-8634-0257c969c26e");
DeviceClassId radiatorThermostateDeviceClassId = DeviceClassId("f80d9481-4827-45ee-a013-b97b22412d92");
StateTypeId offsetTempStateTypeId = StateTypeId("576da571-9a65-478f-96bf-19256c8b9ece");
StateTypeId windowOpenDurationStateTypeId = StateTypeId("81c6c74a-b0cd-4daa-9eb9-f1cd68f328af");
StateTypeId boostValueValueStateTypeId = StateTypeId("7c41fa64-b1a1-48d2-9d03-67aa16cd83ad");
StateTypeId boostDurationStateTypeId = StateTypeId("e75c1398-9ad7-466c-b3b9-b03bbb686a30");
StateTypeId discalcWeekDayStateTypeId = StateTypeId("bd6f5947-d4b4-444b-81c8-77eec46957e4");
StateTypeId discalcTimeStateTypeId = StateTypeId("e78235ee-affc-41e3-a463-9f0512b4a6c3");
StateTypeId valveMaximumSettingsStateTypeId = StateTypeId("e367fa3a-b30f-49bd-af3f-cff92360ad32");
StateTypeId valveOffsetStateTypeId = StateTypeId("ffaff87b-b741-4db8-9875-3380af4f1885");
StateTypeId valvePositionStateTypeId = StateTypeId("72956000-0203-4c32-a6b6-3bb7e46c03ca");
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;
}
QList<ParamType> DevicePluginEQ3::configurationDescription() const
{
QList<ParamType> params;
return params;
}
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)
{
qDebug() << "setupDevice" << device->params();
if(device->deviceClassId() == cubeDeviceClassId){
foreach (MaxCube *cube, m_cubes.keys()) {
if(cube->serialNumber() == device->paramValue("serial number").toString()){
qDebug() << cube->serialNumber() << " allready exists...";
return DeviceManager::DeviceSetupStatusFailure;
}
}
MaxCube *cube = new MaxCube(this,device->paramValue("serial number").toString(),QHostAddress(device->paramValue("host address").toString()),device->paramValue("port").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("serial number").toString() + ")");
}
return DeviceManager::DeviceSetupStatusSuccess;
}
void DevicePluginEQ3::deviceRemoved(Device *device)
{
if (!m_cubes.values().contains(device)) {
return;
}
MaxCube *cube = m_cubes.key(device);
cube->disconnectFromCube();
qDebug() << "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("parent cube").toString()){
QByteArray rfAddress = device->paramValue("rf address").toByteArray();
int roomId = device->paramValue("room id").toInt();
if (action.actionTypeId() == setSetpointTemperatureActionTypeId){
cube->setDeviceSetpointTemp(rfAddress, roomId, action.param("setpoint temperature").value().toDouble(), action.id());
} else if (action.actionTypeId() == setAutoModeActionTypeId){
cube->setDeviceAutoMode(rfAddress, roomId, action.id());
} else if (action.actionTypeId() == setManuelModeActionTypeId){
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("display").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("host address", cube->hostAddress().toString());
params.append(hostParam);
Param portParam("port", cube->port());
params.append(portParam);
Param firmwareParam("firmware version", cube->firmware());
params.append(firmwareParam);
Param serialNumberParam("serial number", 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("serial number").toString()){
allreadyAdded = true;
break;
}
}
if(!allreadyAdded){
DeviceDescriptor descriptor(wallThermostateDeviceClassId, wallThermostat->serialNumber());
ParamList params;
params.append(Param("name", wallThermostat->deviceName()));
params.append(Param("parent cube", cube->serialNumber()));
params.append(Param("serial number", wallThermostat->serialNumber()));
params.append(Param("rf address", wallThermostat->rfAddress()));
params.append(Param("room id", wallThermostat->roomId()));
params.append(Param("room name", 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("serial number").toString()){
allreadyAdded = true;
break;
}
}
if(!allreadyAdded){
DeviceDescriptor descriptor(radiatorThermostateDeviceClassId, radiatorThermostat->serialNumber());
ParamList params;
params.append(Param("name", radiatorThermostat->deviceName()));
params.append(Param("parent cube", cube->serialNumber()));
params.append(Param("serial number", radiatorThermostat->serialNumber()));
params.append(Param("rf address", radiatorThermostat->rfAddress()));
params.append(Param("room id", radiatorThermostat->roomId()));
params.append(Param("room name", 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(portalEnabeldStateTypeId,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("serial number").toString() == wallThermostat->serialNumber()){
device->setStateValue(confortTempStateTypeId, wallThermostat->confortTemp());
device->setStateValue(ecoTempStateTypeId, wallThermostat->ecoTemp());
device->setStateValue(maxSetpointTempStateTypeId, wallThermostat->maxSetPointTemp());
device->setStateValue(minSetpointTempStateTypeId, wallThermostat->minSetPointTemp());
device->setStateValue(errorOccuredStateTypeId, 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(setpointTempStateTypeId, 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("serial number").toString() == radiatorThermostat->serialNumber()){
device->setStateValue(confortTempStateTypeId, radiatorThermostat->confortTemp());
device->setStateValue(ecoTempStateTypeId, radiatorThermostat->ecoTemp());
device->setStateValue(maxSetpointTempStateTypeId, radiatorThermostat->maxSetPointTemp());
device->setStateValue(minSetpointTempStateTypeId, radiatorThermostat->minSetPointTemp());
device->setStateValue(errorOccuredStateTypeId, 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(setpointTempStateTypeId, radiatorThermostat->setpointTemperature());
device->setStateValue(offsetTempStateTypeId, radiatorThermostat->offsetTemp());
device->setStateValue(windowOpenDurationStateTypeId, radiatorThermostat->windowOpenDuration());
device->setStateValue(boostValueValueStateTypeId, 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());
}
}
}
}