From 3a8908c982eae0aa53abafb962e190d53cb08a01 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Simon=20St=C3=BCrz?= Date: Mon, 28 Jul 2014 23:26:11 +0200 Subject: [PATCH] added eQ-3 plugin pluginstatus: can be discovered, still not refreshing auto generate devices from cube missing some errors in message parsing --- libguh/hardware/gpio.cpp | 1 - libguh/hardware/radio433receiver.cpp | 22 +- libguh/hardware/radio433receiver.h | 2 +- libguh/hardware/radio433transmitter.cpp | 2 +- plugins/deviceplugins/deviceplugins.pro | 1 + .../deviceplugins/eq-3/deviceplugineq-3.cpp | 184 +++++++ plugins/deviceplugins/eq-3/deviceplugineq-3.h | 69 +++ .../deviceplugins/eq-3/deviceplugineq-3.json | 1 + plugins/deviceplugins/eq-3/eq-3.pro | 20 + plugins/deviceplugins/eq-3/maxcube.cpp | 467 ++++++++++++++++++ plugins/deviceplugins/eq-3/maxcube.h | 96 ++++ .../deviceplugins/eq-3/maxcubediscovery.cpp | 74 +++ plugins/deviceplugins/eq-3/maxcubediscovery.h | 38 ++ plugins/deviceplugins/eq-3/maxdevice.cpp | 96 ++++ plugins/deviceplugins/eq-3/maxdevice.h | 58 +++ plugins/deviceplugins/eq-3/room.cpp | 36 ++ plugins/deviceplugins/eq-3/room.h | 34 ++ server/main.cpp | 1 + server/server.pro | 1 + 19 files changed, 1189 insertions(+), 14 deletions(-) create mode 100644 plugins/deviceplugins/eq-3/deviceplugineq-3.cpp create mode 100644 plugins/deviceplugins/eq-3/deviceplugineq-3.h create mode 100644 plugins/deviceplugins/eq-3/deviceplugineq-3.json create mode 100644 plugins/deviceplugins/eq-3/eq-3.pro create mode 100644 plugins/deviceplugins/eq-3/maxcube.cpp create mode 100644 plugins/deviceplugins/eq-3/maxcube.h create mode 100644 plugins/deviceplugins/eq-3/maxcubediscovery.cpp create mode 100644 plugins/deviceplugins/eq-3/maxcubediscovery.h create mode 100644 plugins/deviceplugins/eq-3/maxdevice.cpp create mode 100644 plugins/deviceplugins/eq-3/maxdevice.h create mode 100644 plugins/deviceplugins/eq-3/room.cpp create mode 100644 plugins/deviceplugins/eq-3/room.h diff --git a/libguh/hardware/gpio.cpp b/libguh/hardware/gpio.cpp index 6ce72cbd..8951ed1c 100644 --- a/libguh/hardware/gpio.cpp +++ b/libguh/hardware/gpio.cpp @@ -42,7 +42,6 @@ Gpio::Gpio(QObject *parent, int gpio) : QObject(parent),m_gpio(gpio) { - exportGpio(); } /*! Destroys the Gpio object and unexports the GPIO. */ diff --git a/libguh/hardware/radio433receiver.cpp b/libguh/hardware/radio433receiver.cpp index 67d2c107..0f27fcff 100644 --- a/libguh/hardware/radio433receiver.cpp +++ b/libguh/hardware/radio433receiver.cpp @@ -36,6 +36,17 @@ Radio433Receiver::~Radio433Receiver() { } +bool Radio433Receiver::setUpGpio() +{ + if(!m_gpio->exportGpio()){ + return false; + }else{ + m_gpio->setDirection(INPUT); + m_gpio->setEdgeInterrupt(EDGE_BOTH); + } + return true; +} + bool Radio433Receiver::startReceiver() { if(setUpGpio()){ @@ -99,17 +110,6 @@ void Radio433Receiver::run() } } -bool Radio433Receiver::setUpGpio() -{ - if(!m_gpio->openGpio()){ - return false; - }else{ - m_gpio->setDirection(INPUT); - m_gpio->setEdgeInterrupt(EDGE_BOTH); - } - return true; -} - int Radio433Receiver::micros() { struct timeval tv ; diff --git a/libguh/hardware/radio433receiver.h b/libguh/hardware/radio433receiver.h index 78c4c308..525448f5 100644 --- a/libguh/hardware/radio433receiver.h +++ b/libguh/hardware/radio433receiver.h @@ -36,6 +36,7 @@ public: ProtocolNone }; + bool setUpGpio(); bool startReceiver(); bool stopReceiver(); @@ -54,7 +55,6 @@ private: bool m_reading; void run(); - bool setUpGpio(); int micros(); bool valueInTolerance(int value, int sollValue); bool checkValue(int value); diff --git a/libguh/hardware/radio433transmitter.cpp b/libguh/hardware/radio433transmitter.cpp index f08e24f4..ce44b9ae 100644 --- a/libguh/hardware/radio433transmitter.cpp +++ b/libguh/hardware/radio433transmitter.cpp @@ -50,7 +50,7 @@ bool Radio433Trasmitter::stopTransmitter() bool Radio433Trasmitter::setUpGpio() { - if(!m_gpio->openGpio()){ + if(!m_gpio->exportGpio()){ return false; }else{ m_gpio->setDirection(OUTPUT); diff --git a/plugins/deviceplugins/deviceplugins.pro b/plugins/deviceplugins/deviceplugins.pro index 71c9d2ba..58efbd9a 100644 --- a/plugins/deviceplugins/deviceplugins.pro +++ b/plugins/deviceplugins/deviceplugins.pro @@ -10,6 +10,7 @@ SUBDIRS += elro \ wakeonlan \ mailnotification \ philipshue \ + eq-3 \ boblight { SUBDIRS += boblight diff --git a/plugins/deviceplugins/eq-3/deviceplugineq-3.cpp b/plugins/deviceplugins/eq-3/deviceplugineq-3.cpp new file mode 100644 index 00000000..b705f0e1 --- /dev/null +++ b/plugins/deviceplugins/eq-3/deviceplugineq-3.cpp @@ -0,0 +1,184 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * * + * 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 . * + * * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#include "deviceplugineq-3.h" + +#include "plugin/device.h" +#include "devicemanager.h" +#include "types/param.h" + +#include + +VendorId maxVendorId = VendorId("2cac0645-855e-44fa-837e-1cab0ae4304c"); + +PluginId eq3PluginUuid = PluginId("f324c43c-9680-48d8-852a-93b2227139b9"); + +DeviceClassId cubeDeviceClassId = DeviceClassId("1e892268-8bd7-442c-a001-bd4e2e6b2949"); +StateTypeId dateTimeStateTypeId = StateTypeId("78aed123-ca8e-4e11-a823-52043c4a4370"); + +DevicePluginEQ3::DevicePluginEQ3() +{ + m_cubeDiscovery = new MaxCubeDiscovery(this); + connect(m_cubeDiscovery,SIGNAL(cubesDetected(QList)),this,SLOT(discoveryDone(QList))); +} + +QList DevicePluginEQ3::supportedVendors() const +{ + QList ret; + Vendor max(maxVendorId, "Max!"); + ret.append(max); + return ret; +} + +QList DevicePluginEQ3::supportedDevices() const +{ + QList ret; + + // Cube + DeviceClass cubeDeviceClass(pluginId(),maxVendorId,cubeDeviceClassId); + cubeDeviceClass.setName("Max! Cube LAN Gateway"); + cubeDeviceClass.setCreateMethod(DeviceClass::CreateMethodDiscovery); + cubeDeviceClass.setSetupMethod(DeviceClass::SetupMethodJustAdd); + + // Params + QList params; + ParamType hostParam("host address", QVariant::String); + params.append(hostParam); + + ParamType portParam("port", QVariant::Int); + params.append(portParam); + + ParamType serialNumberParam("serial number", QVariant::String); + params.append(serialNumberParam); + + ParamType firmwareParam("firmware version", QVariant::Int); + params.append(firmwareParam); + + cubeDeviceClass.setParamTypes(params); + + // States + QList states; + StateType dateTimeState(dateTimeStateTypeId); + dateTimeState.setName("cube time [unixtime]"); + dateTimeState.setType(QVariant::UInt); + dateTimeState.setDefaultValue(0); + states.append(dateTimeState); + + cubeDeviceClass.setStateTypes(states); + + ret.append(cubeDeviceClass); + + return ret; +} + +DeviceManager::HardwareResources DevicePluginEQ3::requiredHardware() const +{ + return DeviceManager::HardwareResourceTimer; +} + +QString DevicePluginEQ3::pluginName() const +{ + return "eQ-3"; +} + +PluginId DevicePluginEQ3::pluginId() const +{ + return eq3PluginUuid; +} + +QList DevicePluginEQ3::configurationDescription() const +{ + QList params; + return params; +} + +DeviceManager::DeviceError DevicePluginEQ3::discoverDevices(const DeviceClassId &deviceClassId, const QList ¶ms) const +{ + if(deviceClassId == cubeDeviceClassId){ + m_cubeDiscovery->detectCubes(); + return DeviceManager::DeviceErrorAsync; + } + return DeviceManager::DeviceErrorDeviceClassNotFound; +} + +QPair DevicePluginEQ3::setupDevice(Device *device) +{ + qDebug() << "setupDevice" << device->params(); + + foreach (MaxCube *cube, m_cubes.keys()) { + if(cube->serialNumber() == device->paramValue("serial number").toString()){ + qDebug() << cube->serialNumber() << " allready exists..."; + return reportDeviceSetup(DeviceManager::DeviceSetupStatusFailure,QString("Cube allready in added")); + } + } + + MaxCube *cube = new MaxCube(this,device->paramValue("serial number").toString(),QHostAddress(device->paramValue("host address").toString()),device->paramValue("port").toInt()); + connect(cube,SIGNAL(cubeConnectionStatusChanged(bool)),this,SLOT(cubeConnectionStatusChanged(bool))); + + m_cubes.insert(cube,device); + + cube->connectToCube(); + + return reportDeviceSetup(DeviceManager::DeviceSetupStatusAsync); +} + +void DevicePluginEQ3::guhTimer() +{ + foreach (MaxCube *cube, m_cubes.keys()) { + cube->refresh(); + } +} + +QPair DevicePluginEQ3::executeAction(Device *device, const Action &action) +{ + +} + +void DevicePluginEQ3::cubeConnectionStatusChanged(const bool &connected) +{ + if(connected){ + MaxCube *cube = static_cast(sender()); + Device *device; + if (m_cubes.contains(cube)) { + device = m_cubes.take(cube); + device->setName("Max! Cube " + cube->serialNumber()); + emit deviceSetupFinished(device, DeviceManager::DeviceSetupStatusSuccess, QString()); + } + } +} + +void DevicePluginEQ3::discoveryDone(const QList &cubeList) +{ + QList retList; + foreach (MaxCube *cube, cubeList) { + DeviceDescriptor descriptor(cubeDeviceClassId, "Max! Cube LAN Gateway",cube->serialNumber()); + QList params; + Param hostParam("host address", cube->hostAddress().toString()); + params.append(hostParam); + Param portParam("port", cube->port()); + params.append(portParam); + Param firmwareParam("firmware version", QString::number(cube->firmware())); + params.append(firmwareParam); + Param serialNumberParam("serial number", cube->serialNumber()); + params.append(serialNumberParam); + + descriptor.setParams(params); + retList.append(descriptor); + } + emit devicesDiscovered(cubeDeviceClassId,retList); +} diff --git a/plugins/deviceplugins/eq-3/deviceplugineq-3.h b/plugins/deviceplugins/eq-3/deviceplugineq-3.h new file mode 100644 index 00000000..6d771758 --- /dev/null +++ b/plugins/deviceplugins/eq-3/deviceplugineq-3.h @@ -0,0 +1,69 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * * + * 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 . * + * * + * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ + +#ifndef DEVICEPLUGINEQ3_H +#define DEVICEPLUGINEQ3_H + +#include "plugin/deviceplugin.h" +#include "maxcubediscovery.h" + +#include + +class QNetworkReply; + +class DevicePluginEQ3: public DevicePlugin +{ + Q_OBJECT + + Q_PLUGIN_METADATA(IID "guru.guh.DevicePlugin" FILE "deviceplugineq-3.json") + Q_INTERFACES(DevicePlugin) + +public: + explicit DevicePluginEQ3(); + + QList supportedVendors() const override; + QList supportedDevices() const override; + DeviceManager::HardwareResources requiredHardware() const override; + + QString pluginName() const override; + PluginId pluginId() const override; + + QList configurationDescription() const override; + DeviceManager::DeviceError discoverDevices(const DeviceClassId &deviceClassId, const QList ¶ms) const override; + + QPair setupDevice(Device *device) override; + + void guhTimer() override; + +private: + QList m_config; + MaxCubeDiscovery *m_cubeDiscovery; + QHash m_cubes; + + +public slots: + QPair executeAction(Device *device, const Action &action); + void cubeConnectionStatusChanged(const bool &connected); + +private slots: + void discoveryDone(const QList &cubeList); + + +}; + +#endif // DEVICEPLUGINEQ3_H diff --git a/plugins/deviceplugins/eq-3/deviceplugineq-3.json b/plugins/deviceplugins/eq-3/deviceplugineq-3.json new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/plugins/deviceplugins/eq-3/deviceplugineq-3.json @@ -0,0 +1 @@ +{} diff --git a/plugins/deviceplugins/eq-3/eq-3.pro b/plugins/deviceplugins/eq-3/eq-3.pro new file mode 100644 index 00000000..8d0f868d --- /dev/null +++ b/plugins/deviceplugins/eq-3/eq-3.pro @@ -0,0 +1,20 @@ +include(../../plugins.pri) + +TARGET = $$qtLibraryTarget(guh_deviceplugineq3) + +QT += network + +SOURCES += \ + deviceplugineq-3.cpp \ + maxcubediscovery.cpp \ + maxcube.cpp \ + maxdevice.cpp \ + room.cpp \ + +HEADERS += \ + deviceplugineq-3.h \ + maxcubediscovery.h \ + maxcube.h \ + maxdevice.h \ + room.h \ + diff --git a/plugins/deviceplugins/eq-3/maxcube.cpp b/plugins/deviceplugins/eq-3/maxcube.cpp new file mode 100644 index 00000000..2a5ec565 --- /dev/null +++ b/plugins/deviceplugins/eq-3/maxcube.cpp @@ -0,0 +1,467 @@ +#include "maxcube.h" + +MaxCube::MaxCube(QObject *parent, QString serialNumber, QHostAddress hostAdress, quint16 port): + QTcpSocket(parent), m_serialNumber(serialNumber), m_hostAddress(hostAdress), m_port(port) +{ + connect(this,SIGNAL(connected()),this,SLOT(connected())); + connect(this,SIGNAL(disconnected()),this,SLOT(disconnected())); + connect(this,SIGNAL(readyRead()),this,SLOT(readData())); + connect(this,SIGNAL(error(QAbstractSocket::SocketError)),this,SLOT(error(QAbstractSocket::SocketError))); + + connect(this,SIGNAL(cubeDataAvailable(QByteArray)),this,SLOT(processCubeData(QByteArray))); +} + +QString MaxCube::serialNumber() +{ + return m_serialNumber; +} + +void MaxCube::setSerialNumber(QString serialNumber) +{ + m_serialNumber = serialNumber; +} + +QByteArray MaxCube::rfAddress() +{ + return m_rfAddress; +} + +void MaxCube::setRfAddress(QByteArray rfAddress) +{ + m_rfAddress = rfAddress; +} + +int MaxCube::firmware() +{ + return m_firmware; +} + +void MaxCube::setFirmware(int firmware) +{ + m_firmware = firmware; +} + +QHostAddress MaxCube::hostAddress() +{ + return m_hostAddress; +} + +void MaxCube::setHostAddress(QHostAddress hostAddress) +{ + m_hostAddress = hostAddress; +} + +quint16 MaxCube::port() +{ + return m_port; +} + +void MaxCube::setPort(quint16 port) +{ + m_port = port; +} + +QByteArray MaxCube::httpConnectionId() +{ + return m_httpConnectionId; +} + +void MaxCube::setHttpConnectionId(QByteArray httpConnectionId) +{ + m_httpConnectionId = httpConnectionId; +} + +int MaxCube::freeMemorySlots() +{ + return m_freeMemorySlots; +} + +void MaxCube::setFreeMemorySlots(int freeMemorySlots) +{ + m_freeMemorySlots = freeMemorySlots; +} + +QList MaxCube::deviceList() +{ + return m_deviceList; +} + +QList MaxCube::roomList() +{ + return m_roomList; +} + +void MaxCube::connectToCube() +{ + connectToHost(m_hostAddress,m_port); +} + +void MaxCube::disconnectFromCube() +{ + disconnectFromHost(); +} + +bool MaxCube::sendData(QByteArray data) +{ + if(write(data) < 0){ + return false; + } + return true; +} + +void MaxCube::parseHelloMessage(QByteArray data) +{ + + QList list = data.split(','); + m_cubeDateTime = calculateDateTime(list.at(7),list.at(8)); + qDebug() << "===================================================="; + qDebug() << "HELLO message:"; + qDebug() << "===================================================="; + qDebug() << " serial number | " << list.at(0); + qDebug() << " RF address (hex) | " << list.at(1); + qDebug() << " firmware | " << QString::number(list.at(2).toInt()); + qDebug() << " ? | " << list.at(3); + qDebug() << " HTTP connection id | " << list.at(4); + qDebug() << " duty cycle (hex) | " << list.at(5); + qDebug() << " free memory slots (hex) | " << list.at(6); + qDebug() << " Cube date | " << m_cubeDateTime.date().toString("dd.MM.yyyy"); + qDebug() << " Cube time | " << m_cubeDateTime.time().toString("HH:mm"); + qDebug() << " State Cube Time | " << list.at(9); + qDebug() << " NTP counter | " << list.at(10); +} + +void MaxCube::parseMetadataMessage(QByteArray data) +{ + QList list = data.left(data.length()-2).split(','); + QByteArray dataDecoded = QByteArray::fromBase64(list.at(2)); + qDebug() << "===================================================="; + qDebug() << "METADATA message:"; + qDebug() << "===================================================="; + // qDebug() << " Index | " << list.at(0); + // qDebug() << " Count | " << list.at(1); + // qDebug() << " Data Base64 encoded | " << list.at(2); + // qDebug() << " Data Base64 decoded | " << dataDecoded; + // qDebug() << " Data Base64 decoded hex | " << dataDecoded.toHex(); + + + // parse room list + int roomCount = dataDecoded.toHex().mid(4,2).toInt(0,16); + + QByteArray roomRawData = dataDecoded.toHex(); + roomRawData = roomRawData.right(roomRawData.length()-6); + + for(int i = 0; i < roomCount; i++){ + Room *room = new Room(this); + room->setRoomId(roomRawData.left(2).toInt(0,16)); + int roomNameLength = roomRawData.mid(2,2).toInt(0,16); + room->setRoomName(QByteArray::fromHex(roomRawData.mid(4,roomNameLength*2))); + room->setGroupRfAddress(roomRawData.mid(roomNameLength*2 + 4, 6)); + m_roomList.append(room); + roomRawData = roomRawData.right(roomRawData.length() - ((roomNameLength*2) + 10)); + } + qDebug() << "-------------------------|-------------------------"; + qDebug() << "found " << m_roomList.count() << "rooms"; + qDebug() << "-------------------------|-------------------------"; + + foreach (Room *room, m_roomList) { + qDebug() << " Room Name | " << room->roomName(); + qDebug() << " Room ID | " << room->roomId(); + qDebug() << " Group RF Address | " << room->groupRfAddress(); + qDebug() << "-------------------------|-------------------------"; + } + + // parse device list + int deviceCount = roomRawData.left(2).toInt(0,16); + QByteArray deviceRawData = roomRawData.right(roomRawData.length() - 2); + + for(int i = 0; i < deviceCount; i++){ + MaxDevice* device = new MaxDevice(this); + device->setDeviceType(deviceRawData.left(2).toInt(0,16)); + device->setRfAddress(deviceRawData.mid(2,6)); + device->setSerialNumber(QByteArray::fromHex(deviceRawData.mid(8,20))); + int deviceNameLenght = deviceRawData.mid(28,2).toInt(0,16); + device->setDeviceName(QByteArray::fromHex(deviceRawData.mid(30,deviceNameLenght*2))); + device->setRoomId(deviceRawData.mid(30 + deviceNameLenght*2,2).toInt(0,16)); + deviceRawData = deviceRawData.right(deviceRawData.length() - (30 + deviceNameLenght*2)); + //qDebug() << "rawdata left :" << deviceRawData; + m_deviceList.append(device); + } + + qDebug() << "-------------------------|-------------------------"; + qDebug() << "found " << m_deviceList.count() << "devices"; + qDebug() << "-------------------------|-------------------------"; + + foreach (MaxDevice *device, m_deviceList) { + qDebug() << " Device Name | " << device->deviceName(); + qDebug() << " Serial Number| " << device->serialNumber(); + qDebug() << " Device Type String | " << device->deviceTypeString(); + qDebug() << " RF address (hex) | " << device->rfAddress(); + //qDebug() << " Device Type | " << device->deviceType(); + qDebug() << " Room ID | " << device->roomId(); + qDebug() << "-------------------------|-------------------------"; + } +} + +void MaxCube::parseConfigMessage(QByteArray data) +{ + QList list = data.split(','); + QByteArray rfAddress = list.at(0); + QByteArray dataRaw = QByteArray::fromBase64(list.at(1)).toHex(); + //int lengthData = dataRaw.left(2).toInt(0,16); + //QByteArray rfAddress = dataRaw.mid(2,6); + int deviceType = dataRaw.mid(8,2).toInt(0,16); + int roomId = dataRaw.mid(10,2).toInt(0,16); + //QByteArray unknown = dataRaw.mid(12,6); + + QByteArray serialNumber = QByteArray::fromHex(dataRaw.mid(16,20)); + qDebug() << "===================================================="; + qDebug() << "CONFIG message:"; + qDebug() << "===================================================="; + qDebug() << " device Type | " << deviceTypeString(deviceType); + qDebug() << " Serial Number | " << serialNumber; + qDebug() << " RF address (hex) | " << rfAddress; + qDebug() << " Room ID | " << roomId; + qDebug() << "-------------------------|-------------------------"; + + switch (deviceType) { + case MaxDevice::DeviceCube:{ + qDebug() << QByteArray::fromHex(dataRaw.mid(dataRaw.length() - 32)); + break; + } + case MaxDevice::DeviceEcoButton: + break; + case MaxDevice::DeviceWallThermostat: + break; + case MaxDevice::DeviceRadiatorThermostatPlus: + break; + case MaxDevice::DeviceRadiatorThermostat:{ + double confortTemp = dataRaw.mid(36,2).toInt(0,16)/2; + double ecoTemp = dataRaw.mid(38,2).toInt(0,16)/2; + double maxSetPointTemp = dataRaw.mid(40,2).toInt(0,16)/2; + double minSetPointTemp = dataRaw.mid(42,2).toInt(0,16)/2; + double offsetTemp = (dataRaw.mid(44,2).toInt(0,16) / 2 ) - 3.5; + double windowOpenTemp = dataRaw.mid(46,2).toInt(0,16)/2; + int windowOpenDuration = dataRaw.mid(48,2).toInt(0,16); + // boost code + QByteArray boostDurationCode = QByteArray::number(dataRaw.mid(50,2).toInt(0,16),2); + qDebug() << boostDurationCode; + int boostDuration = boostDurationCode.left(3).toInt(0,2); + if(boostDuration = 7){ + boostDuration = 30; + }else{ + boostDuration *= 5; + } + int valveValue = boostDurationCode.right(5).toInt(0,2); + // day of week an time + QByteArray dowTime = QByteArray::number(dataRaw.mid(52,2).toInt(0,16),2); + double valveMaximumSettings = dataRaw.mid(54,2).toInt(0,16)*(double)100/255; + double valveOffset = dataRaw.mid(56,2).toInt(0,16)*(double)100/255; + + qDebug() << " Serial Number | " << serialNumber; + qDebug() << " Confort Temp. | " << confortTemp; + qDebug() << " Eco Temp. | " << ecoTemp; + qDebug() << " Max. Set Point Temp. | " << maxSetPointTemp; + qDebug() << " Min. Set Point Temp. | " << minSetPointTemp; + qDebug() << " Temp. Offset | " << offsetTemp; + qDebug() << " Window Open Temp. | " << windowOpenTemp; + qDebug() << " Window Open Duration | " << windowOpenDuration; + qDebug() << " Boost Duration | " << boostDuration << "min"; + qDebug() << " Valve value | " << valveValue << "%"; + qDebug() << " Day of week and time | " << dowTime; + qDebug() << " Valve Maximum Settings | " << valveMaximumSettings << "%"; + qDebug() << " Valve Offset | " << valveOffset << "%"; + parseWeeklyProgram(dataRaw.right(dataRaw.length() - 58)); + + break; + } + default: + qWarning() << "unknown device type: " << deviceType; + break; + } +} + +void MaxCube::parseDevicelistMessage(QByteArray data) +{ + QList list = data.split(','); + qDebug() << "===================================================="; + qDebug() << "DEVICELIST message:"; + qDebug() << "===================================================="; + foreach (const QByteArray &code, list) { + QByteArray rawData = QByteArray::fromBase64(code).toHex(); + qDebug() << " Code | " << rawData.toBase64(); + qDebug() << " Code (Hex) | " << rawData; + qDebug() << " Length of data | " << rawData.left(2).toInt(0,16); + qDebug() << " RF address (hex) | " << rawData.mid(2,6); + qDebug() << " Initialization | " << QByteArray::number(rawData.mid(10,2).toInt(0,16),2); + qDebug() << " Battery, ... , | " << QByteArray::number(rawData.mid(12,2).toInt(0,16),2); + qDebug() << " Valve Position | " << QByteArray::number(rawData.mid(14,2).toInt(0,16),2) << "%"; + qDebug() << " Temperatur Setpoint | " << (double)rawData.mid(16,2).toInt(0,16) / 2.0 << "%"; + QDateTime dateTime = calculateDateTime(rawData.mid(18,4), rawData.mid(22,2)); + qDebug() << " Cube date | " << dateTime.date().toString("dd.MM.yyyy"); + qDebug() << " Cube time | " << dateTime.time().toString("HH:mm"); + } +} + +void MaxCube::parseWeeklyProgram(QByteArray data) +{ + for(int i=0; i<7; i++){ + QByteArray dayData = data.left(52); + qDebug() << dayData; + data = data.right(data.length() - 52); + } + qDebug() << "data left" << data; +} + +void MaxCube::parseNewDeviceFoundMessage(QByteArray data) +{ + if(data.isEmpty()){ + return; + } + + qDebug() << "===================================================="; + qDebug() << "NEW DEVICE message:"; + qDebug() << "===================================================="; + + qDebug() << " Serial Number | " << QByteArray::fromBase64(data); + +} + +QDateTime MaxCube::calculateDateTime(QByteArray dateRaw, QByteArray timeRaw) +{ + QDate date; + QTime time; + date.setDate(dateRaw.left(2).toInt(0,16) + 2000, dateRaw.mid(2,2).toInt(0,16), dateRaw.right(2).toInt(0,16)); + time.setHMS(timeRaw.left(2).toInt(0,16), timeRaw.right(2).toInt(0,16), 0); + + return QDateTime(date,time); +} + +QString MaxCube::deviceTypeString(int deviceType) +{ + QString deviceTypeString; + + switch (deviceType) { + case MaxDevice::DeviceCube: + deviceTypeString = "Cube"; + break; + case MaxDevice::DeviceRadiatorThermostat: + deviceTypeString = "Radiator Thermostat"; + break; + case MaxDevice::DeviceRadiatorThermostatPlus: + deviceTypeString = "Radiator Thermostat Plus"; + break; + case MaxDevice::DeviceEcoButton: + deviceTypeString = "Eco Button"; + break; + case MaxDevice::DeviceWindowContact: + deviceTypeString = "Window Contact"; + break; + case MaxDevice::DeviceWallThermostat: + deviceTypeString = "Wall Thermostat"; + break; + default: + deviceTypeString = "-"; + break; + } + + return deviceTypeString; +} + +QByteArray MaxCube::fillBin(QByteArray data, int dataLength) +{ + +} + +void MaxCube::connected() +{ + qDebug() << "-> connected to cube " << m_serialNumber << m_hostAddress.toString(); + emit cubeConnectionStatusChanged(true); +} + +void MaxCube::disconnected() +{ + qDebug() << "-> disconnected from cube " << m_serialNumber << m_hostAddress.toString(); + emit cubeConnectionStatusChanged(false); +} + +void MaxCube::error(QAbstractSocket::SocketError error) +{ + qDebug() << "connection error (" << m_serialNumber << "): " << error; + emit cubeConnectionStatusChanged(false); +} + +void MaxCube::readData() +{ + QByteArray message; + while(canReadLine()){ + QByteArray dataLine = readLine(); + message.append(dataLine); + } + emit cubeDataAvailable(message); +} + +void MaxCube::processCubeData(const QByteArray &data) +{ + //qDebug() << "data" << data; + if(data.startsWith("H")){ + parseHelloMessage(data.right(data.length() -2 )); + return; + } + // METADATA message + if(data.startsWith("M")){ + parseMetadataMessage(data.right(data.length() -2 )); + return; + } + // CONFIG message + if(data.startsWith("C")){ + parseConfigMessage(data.right(data.length() -2 )); + return; + } + // DEVICELIST message + if(data.startsWith("L")){ + //customRequest("g:"); + parseDevicelistMessage(data.right(data.length() -2 )); + return; + } + // NEWDEVICEFOUND message + if(data.startsWith("N")){ + parseNewDeviceFoundMessage(data.right(data.length() -2)); + return; + } + // ACK message + if(data.startsWith("A")){ + qDebug() << "cube ACK!"; + emit cubeACK(); + return; + } + qDebug() << " -> unknown message!!!!!!! from cube:" << data; +} + +void MaxCube::enablePairingMode() +{ + qDebug() << "-------> enable pairing mode! press the boost button for min. 3 seconds"; + write("n:003c\r\n"); +} + +void MaxCube::disablePairingMode() +{ + qDebug() << " ----> disable pairing mode!"; + write("x:\r\n"); +} + +void MaxCube::refresh() +{ + qDebug() << "refresh cube " << m_serialNumber; + if(isWritable()){ + write("l:\r\n"); + }else{ + qDebug() << "ERROR: could not send to " << m_hostAddress.toString(); + } +} + +void MaxCube::customRequest(QByteArray data) +{ + qDebug() << " ----> custom request" << data; + write(data + "\r\n"); +} + diff --git a/plugins/deviceplugins/eq-3/maxcube.h b/plugins/deviceplugins/eq-3/maxcube.h new file mode 100644 index 00000000..9d22228b --- /dev/null +++ b/plugins/deviceplugins/eq-3/maxcube.h @@ -0,0 +1,96 @@ +#ifndef MAXCUBE_H +#define MAXCUBE_H + +#include +#include +#include +#include + +#include "maxdevice.h" +#include "room.h" + +class MaxCube : public QTcpSocket +{ + Q_OBJECT +public: + MaxCube(QObject *parent = 0, QString serialNumber = QString(), QHostAddress hostAdress = QHostAddress(), quint16 port = 0); + + // cube data access functions + QString serialNumber(); + void setSerialNumber(QString serialNumber); + + QByteArray rfAddress(); + void setRfAddress(QByteArray rfAddress); + + int firmware(); + void setFirmware(int firmware); + + QHostAddress hostAddress(); + void setHostAddress(QHostAddress hostAddress); + + quint16 port(); + void setPort(quint16 port); + + QByteArray httpConnectionId(); + void setHttpConnectionId(QByteArray httpConnectionId); + + int freeMemorySlots(); + void setFreeMemorySlots(int freeMemorySlots); + + QDateTime cubeDateTime(); + void setCubeDateTime(QDateTime cubeDateTime); + + QList deviceList(); + QList roomList(); + + void connectToCube(); + void disconnectFromCube(); + bool sendData(QByteArray data); + +private: + // cube data + QString m_serialNumber; + QByteArray m_rfAddress; + int m_firmware; + QHostAddress m_hostAddress; + quint16 m_port; + QByteArray m_httpConnectionId; + int m_freeMemorySlots; + QDateTime m_cubeDateTime; + + QList m_roomList; + QList m_deviceList; + + void parseHelloMessage(QByteArray data); + void parseMetadataMessage(QByteArray data); + void parseConfigMessage(QByteArray data); + void parseDevicelistMessage(QByteArray data); + void parseWeeklyProgram(QByteArray data); + void parseNewDeviceFoundMessage(QByteArray data); + + QDateTime calculateDateTime(QByteArray dateRaw, QByteArray timeRaw); + QString deviceTypeString(int deviceType); + QByteArray fillBin(QByteArray data, int dataLength); + +signals: + void cubeDataAvailable(const QByteArray &data); + void cubeACK(); + void cubeConnectionStatusChanged(const bool &connected); + +private slots: + void connected(); + void disconnected(); + void error(QAbstractSocket::SocketError error); + void readData(); + void processCubeData(const QByteArray &data); + + +public slots: + void enablePairingMode(); + void disablePairingMode(); + void refresh(); + void customRequest(QByteArray data); + +}; + +#endif // MAXCUBE_H diff --git a/plugins/deviceplugins/eq-3/maxcubediscovery.cpp b/plugins/deviceplugins/eq-3/maxcubediscovery.cpp new file mode 100644 index 00000000..acc50c7f --- /dev/null +++ b/plugins/deviceplugins/eq-3/maxcubediscovery.cpp @@ -0,0 +1,74 @@ +#include "maxcubediscovery.h" + +MaxCubeDiscovery::MaxCubeDiscovery(QObject *parent) : + QObject(parent) +{ + // UDP broadcast for cube detection in the network + m_udpSocket = new QUdpSocket(this); + m_port = 23272; + m_udpSocket->bind(m_port,QUdpSocket::ShareAddress); + + m_timeout = new QTimer(this); + m_timeout->setSingleShot(true); + + connect(m_udpSocket,SIGNAL(readyRead()),this,SLOT(readData())); + connect(m_timeout,SIGNAL(timeout()),this,SLOT(discoverTimeout())); +} + +void MaxCubeDiscovery::detectCubes() +{ + qDebug() << "===================================================="; + qDebug() << " searching for cubes...."; + + m_cubeList.clear(); + + // broadcast the hello message, every cube should respond with a 26 byte message + m_udpSocket->writeDatagram("eQ3Max*.**********I", QHostAddress::Broadcast, m_port); + + m_timeout->start(1500); +} + +void MaxCubeDiscovery::readData() +{ + QByteArray data; + QHostAddress sender; + quint16 udpPort; + + // read the answere from the + while (m_udpSocket->hasPendingDatagrams()) { + data.resize(m_udpSocket->pendingDatagramSize()); + m_udpSocket->readDatagram(data.data(), data.size(), &sender, &udpPort); + } + if(!data.isEmpty() && data.contains("eQ3MaxAp")){ + + QString serialNumber = data.mid(8,10); + QByteArray rfAddress = data.mid(21,3).toHex(); + int firmware = data.mid(24,2).toHex().toInt(); + qint16 port; + // set port depending on the firmware + if(firmware < 109){ + port= 80; + }else{ + port = 62910; + } + + MaxCube *cube = new MaxCube(this, serialNumber, sender, port); + cube->setRfAddress(rfAddress); + qDebug() << "===================================================="; + qDebug() << " cube detected..."; + qDebug() << "===================================================="; + qDebug() << " serial number | " << cube->serialNumber(); + qDebug() << " host address | " << cube->hostAddress().toString(); + qDebug() << " port | " << QString::number(cube->port()); + qDebug() << " rf address | " << cube->rfAddress(); + qDebug() << " firmware | " << QString::number(cube->firmware()); + qDebug() << "===================================================="; + + m_cubeList.append(cube); + } +} + +void MaxCubeDiscovery::discoverTimeout() +{ + emit cubesDetected(m_cubeList); +} diff --git a/plugins/deviceplugins/eq-3/maxcubediscovery.h b/plugins/deviceplugins/eq-3/maxcubediscovery.h new file mode 100644 index 00000000..03699084 --- /dev/null +++ b/plugins/deviceplugins/eq-3/maxcubediscovery.h @@ -0,0 +1,38 @@ +#ifndef MAXCUBEDISCOVERY_H +#define MAXCUBEDISCOVERY_H + +#include +#include +#include +#include + +#include "maxcube.h" + +class MaxCubeDiscovery : public QObject +{ + Q_OBJECT +public: + explicit MaxCubeDiscovery(QObject *parent = 0); + + void detectCubes(); + +private: + QUdpSocket *m_udpSocket; + QTimer *m_timeout; + + quint16 m_port; + + QList m_cubeList; + +private slots: + void readData(); + void discoverTimeout(); + +signals: + void cubesDetected(const QList &cubeList); + +public slots: + +}; + +#endif // MAXCUBEDISCOVERY_H diff --git a/plugins/deviceplugins/eq-3/maxdevice.cpp b/plugins/deviceplugins/eq-3/maxdevice.cpp new file mode 100644 index 00000000..c5c86b09 --- /dev/null +++ b/plugins/deviceplugins/eq-3/maxdevice.cpp @@ -0,0 +1,96 @@ +#include "maxdevice.h" + +MaxDevice::MaxDevice(QObject *parent) : + QObject(parent) +{ +} + +int MaxDevice::deviceType() +{ + return m_deviceType; +} + +void MaxDevice::setDeviceType(int deviceType) +{ + m_deviceType = deviceType; + + switch (m_deviceType) { + case DeviceCube: + m_deviceTypeString = "Cube"; + break; + case DeviceRadiatorThermostat: + m_deviceTypeString = "Radiator Thermostat"; + break; + case DeviceRadiatorThermostatPlus: + m_deviceTypeString = "Radiator Thermostat Plus"; + break; + case DeviceEcoButton: + m_deviceTypeString = "Eco Button"; + break; + case DeviceWindowContact: + m_deviceTypeString = "Window Contact"; + break; + case DeviceWallThermostat: + m_deviceTypeString = "Wall Thermostat"; + break; + default: + m_deviceTypeString = "-"; + break; + } +} + +QString MaxDevice::deviceTypeString() +{ + return m_deviceTypeString; +} + +QByteArray MaxDevice::rfAddress() +{ + return m_rfAddress; +} + +void MaxDevice::setRfAddress(QByteArray rfAddress) +{ + m_rfAddress = rfAddress; +} + +QString MaxDevice::serialNumber() +{ + return m_serialNumber; +} + +void MaxDevice::setSerialNumber(QString serialNumber) +{ + m_serialNumber = serialNumber; +} + +QString MaxDevice::deviceName() +{ + return m_deviceName; +} + +void MaxDevice::setDeviceName(QString deviceName) +{ + m_deviceName = deviceName; +} + +int MaxDevice::roomId() +{ + return m_roomId; +} + +void MaxDevice::setRoomId(int roomId) +{ + m_roomId = roomId; +} + +Room *MaxDevice::room() +{ + return m_room; +} + +void MaxDevice::setRoom(Room *room) +{ + m_room = room; +} + diff --git a/plugins/deviceplugins/eq-3/maxdevice.h b/plugins/deviceplugins/eq-3/maxdevice.h new file mode 100644 index 00000000..2efd4442 --- /dev/null +++ b/plugins/deviceplugins/eq-3/maxdevice.h @@ -0,0 +1,58 @@ +#ifndef MAXDEVICE_H +#define MAXDEVICE_H + +#include + +#include "room.h" + +class MaxDevice : public QObject +{ + Q_OBJECT +public: + explicit MaxDevice(QObject *parent = 0); + + enum MaxDeviceType{ + DeviceCube = 0, + DeviceRadiatorThermostat = 1, + DeviceRadiatorThermostatPlus = 2, + DeviceWallThermostat = 3, + DeviceWindowContact = 4, + DeviceEcoButton = 5 + }; + + int deviceType(); + void setDeviceType(int deviceType); + + QString deviceTypeString(); + + QByteArray rfAddress(); + void setRfAddress(QByteArray rfAddress); + + QString serialNumber(); + void setSerialNumber(QString serialNumber); + + QString deviceName(); + void setDeviceName(QString deviceName); + + int roomId(); + void setRoomId(int roomId); + + Room *room(); + void setRoom(Room *room); +private: + int m_deviceType; + QString m_deviceTypeString; + QByteArray m_rfAddress; + QString m_serialNumber; + QString m_deviceName; + int m_roomId; + Room *m_room; + bool m_batteryOk; + +signals: + +public slots: + +}; + +#endif // MAXDEVICE_H diff --git a/plugins/deviceplugins/eq-3/room.cpp b/plugins/deviceplugins/eq-3/room.cpp new file mode 100644 index 00000000..dc94cfb6 --- /dev/null +++ b/plugins/deviceplugins/eq-3/room.cpp @@ -0,0 +1,36 @@ +#include "room.h" + +Room::Room(QObject *parent) : + QObject(parent) +{ +} + +int Room::roomId() +{ + return m_roomId; +} + +void Room::setRoomId(int roomId) +{ + m_roomId = roomId; +} + +QString Room::roomName() +{ + return m_roomName; +} + +void Room::setRoomName(QString roomName) +{ + m_roomName = roomName; +} + +QByteArray Room::groupRfAddress() +{ + return m_groupRfAddress; +} + +void Room::setGroupRfAddress(QByteArray groupRfAddress) +{ + m_groupRfAddress = groupRfAddress; +} diff --git a/plugins/deviceplugins/eq-3/room.h b/plugins/deviceplugins/eq-3/room.h new file mode 100644 index 00000000..750c6405 --- /dev/null +++ b/plugins/deviceplugins/eq-3/room.h @@ -0,0 +1,34 @@ +#ifndef ROOM_H +#define ROOM_H + +#include + +class Room : public QObject +{ + Q_OBJECT +public: + explicit Room(QObject *parent = 0); + + int roomId(); + void setRoomId(int roomId); + + QString roomName(); + void setRoomName(QString roomName); + + QByteArray groupRfAddress(); + void setGroupRfAddress(QByteArray groupRfAddress); + +private: + int m_roomId; + QString m_roomName; + QByteArray m_groupRfAddress; + +signals: + + + +public slots: + +}; + +#endif // ROOM_H diff --git a/server/main.cpp b/server/main.cpp index 38cd4b99..590c021b 100644 --- a/server/main.cpp +++ b/server/main.cpp @@ -32,6 +32,7 @@ Q_IMPORT_PLUGIN(DevicePluginLircd) Q_IMPORT_PLUGIN(DevicePluginWakeOnLan) Q_IMPORT_PLUGIN(DevicePluginMailNotification) Q_IMPORT_PLUGIN(DevicePluginPhilipsHue) +Q_IMPORT_PLUGIN(DevicePluginEQ3) #if USE_BOBLIGHT Q_IMPORT_PLUGIN(DevicePluginBoblight) diff --git a/server/server.pro b/server/server.pro index f17a03d0..1b7d4e4e 100644 --- a/server/server.pro +++ b/server/server.pro @@ -30,6 +30,7 @@ LIBS += -L../plugins/deviceplugins/lircd -lguh_devicepluginlircd LIBS += -L../plugins/deviceplugins/mailnotification -lguh_devicepluginmailnotification LIBS += -L../plugins/deviceplugins/wakeonlan -lguh_devicepluginwakeonlan LIBS += -L../plugins/deviceplugins/philipshue -lguh_devicepluginphilipshue +LIBS += -L../plugins/deviceplugins/eq-3 -lguh_deviceplugineq3 boblight { xcompile {