diff --git a/nymea-plugins.pro b/nymea-plugins.pro index 28248d30..6ccdf0ee 100644 --- a/nymea-plugins.pro +++ b/nymea-plugins.pro @@ -36,11 +36,13 @@ PLUGIN_DIRS = \ tasmota \ tcpcommander \ udpcommander \ + unipi \ unitec \ wakeonlan \ wemo \ ws2812 \ + CONFIG+=all message(============================================) diff --git a/unipi/devicepluginunipi.cpp b/unipi/devicepluginunipi.cpp new file mode 100644 index 00000000..99764251 --- /dev/null +++ b/unipi/devicepluginunipi.cpp @@ -0,0 +1,392 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * * + * Copyright (C) 2017 Bernhard Trinnes * + * * + * 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 "devicepluginunipi.h" +#include "plugininfo.h" +#include + + + +DevicePluginUniPi::DevicePluginUniPi() +{ +} + + +void DevicePluginUniPi::init() +{ + +} + + +void DevicePluginUniPi::createAutoDevice(GPIOType gpioType, DeviceId parentDeviceId, QString deviceName) +{ + ParamList params; + + switch(gpioType){ + case relay : { + QList relayOutputDescriptors; + DeviceDescriptor descriptor(relayOutputDeviceClassId, "Relay Output", deviceName); + params.append(Param(relayOutputRelayNumberParamTypeId, deviceName)); + params.append(Param(relayOutputParentIdParamTypeId, parentDeviceId)); + descriptor.setParams(params); + relayOutputDescriptors.append(descriptor); + emit autoDevicesAppeared(relayOutputDeviceClassId, relayOutputDescriptors); + break; + } + + case digitalOutput : { + QList digitalOutputDescriptors; + DeviceDescriptor descriptor(digitalOutputDeviceClassId, "Digital Output", deviceName); + params.append(Param(digitalOutputDigitalOutputNumberParamTypeId, deviceName)); + params.append(Param(digitalOutputParentIdParamTypeId, parentDeviceId)); + descriptor.setParams(params); + digitalOutputDescriptors.append(descriptor); + emit autoDevicesAppeared(digitalOutputDeviceClassId, digitalOutputDescriptors); + break; + } + + case digitalInput: { + QList digitalInputDescriptors; + DeviceDescriptor descriptor(digitalInputDeviceClassId, "Digital Input", deviceName); + params.append(Param(digitalInputDigitalInputNumberParamTypeId, deviceName)); + params.append(Param(digitalInputParentIdParamTypeId, parentDeviceId)); + descriptor.setParams(params); + digitalInputDescriptors.append(descriptor); + emit autoDevicesAppeared(digitalInputDeviceClassId, digitalInputDescriptors); + break; + } + + case analogOutput: { + QList analogOutputDescriptors; + DeviceDescriptor descriptor(analogOutputDeviceClassId, "Analog Output", deviceName); + params.append(Param(analogOutputAnalogOutputNumberParamTypeId, deviceName)); + params.append(Param(analogOutputParentIdParamTypeId, parentDeviceId)); + descriptor.setParams(params); + analogOutputDescriptors.append(descriptor); + emit autoDevicesAppeared(analogOutputDeviceClassId, analogOutputDescriptors); + break; + } + + case analogInput: { + QList analogInputDescriptors; + DeviceDescriptor descriptor(analogInputDeviceClassId, "Analog Input", deviceName); + params.append(Param(analogInputAnalogInputNumberParamTypeId, deviceName)); + params.append(Param(analogInputParentIdParamTypeId, parentDeviceId)); + descriptor.setParams(params); + analogInputDescriptors.append(descriptor); + emit autoDevicesAppeared(analogInputDeviceClassId, analogInputDescriptors); + break; + } + + default: + break; + + } +} + +DeviceManager::DeviceSetupStatus DevicePluginUniPi::setupDevice(Device *device) +{ + if (device->deviceClassId() == neuronDeviceClassId) { + + int port = device->paramValue(neuronPortParamTypeId).toInt(); + + m_webSocket = new QWebSocket(); + connect(m_webSocket, &QWebSocket::connected, this, &DevicePluginUniPi::onWebSocketConnected); + connect(m_webSocket, &QWebSocket::disconnected, this, &DevicePluginUniPi::onWebSocketDisconnected); + + QUrl url = QUrl("ws://localhost/ws"); + url.setPort(port); + qDebug(dcUniPi()) << "Conneting to:" << url.toString(); + m_webSocket->open(url); + m_parentId = device->id(); + + return DeviceManager::DeviceSetupStatusSuccess; + } + + if (device->deviceClassId() == relayOutputDeviceClassId) { + + device->setName(QString("Relay Ouput %1").arg(device->paramValue(relayOutputRelayNumberParamTypeId).toString())); + device->setParentId(device->paramValue(relayOutputParentIdParamTypeId).toString()); + return DeviceManager::DeviceSetupStatusSuccess; + } + + if (device->deviceClassId() == digitalOutputDeviceClassId) { + + device->setName(QString("Digital Output %1").arg(device->paramValue(digitalOutputDigitalOutputNumberParamTypeId).toString())); + device->setParentId(device->paramValue(digitalOutputParentIdParamTypeId).toString()); + return DeviceManager::DeviceSetupStatusSuccess; + } + + if (device->deviceClassId() == digitalInputDeviceClassId) { + + device->setName(QString("Digital Input %1").arg(device->paramValue(digitalInputDigitalInputNumberParamTypeId).toString())); + device->setParentId(device->paramValue(digitalInputParentIdParamTypeId).toString()); + return DeviceManager::DeviceSetupStatusSuccess; + } + + if (device->deviceClassId() == analogInputDeviceClassId) { + + device->setName(QString("Analog Input %1").arg(device->paramValue(analogInputAnalogInputNumberParamTypeId).toString())); + device->setParentId(device->paramValue(analogInputParentIdParamTypeId).toString()); + return DeviceManager::DeviceSetupStatusSuccess; + } + + if (device->deviceClassId() == analogOutputDeviceClassId) { + + device->setName(QString("Analog Output %1").arg(device->paramValue(analogOutputAnalogOutputNumberParamTypeId).toString())); + device->setParentId(device->paramValue(analogOutputParentIdParamTypeId).toString()); + return DeviceManager::DeviceSetupStatusSuccess; + } + + return DeviceManager::DeviceSetupStatusFailure; +} + +void DevicePluginUniPi::postSetupDevice(Device *device) +{ + Q_UNUSED(device); +} + +DeviceManager::DeviceError DevicePluginUniPi::executeAction(Device *device, const Action &action) +{ + + if (device->deviceClassId() == relayOutputDeviceClassId) { + + if (action.actionTypeId() == relayOutputRelayStatusActionTypeId) { + QString relayNumber = device->paramValue(relayOutputRelayNumberParamTypeId).toString(); + int stateValue = action.param(relayOutputRelayStatusStateParamTypeId).value().toInt(); + + QJsonObject json; + json["cmd"] = "set"; + json["dev"] = "relay"; + json["circuit"] = relayNumber; + json["value"] = stateValue; + + QJsonDocument doc(json); + QByteArray bytes = doc.toJson(QJsonDocument::Compact); + qDebug(dcUniPi()) << "Send command" << bytes; + m_webSocket->sendBinaryMessage(bytes); + return DeviceManager::DeviceErrorNoError; + } + return DeviceManager::DeviceErrorActionTypeNotFound; + } + + + if (device->deviceClassId() == digitalOutputDeviceClassId) { + if (action.actionTypeId() == digitalOutputDigitalOutputStatusActionTypeId) { + int digitalOutputNumber = device->paramValue(digitalOutputDigitalOutputNumberParamTypeId).toInt(); + int stateValue = action.param(digitalOutputDigitalOutputStatusStateParamTypeId).value().toInt(); + + QJsonObject json; + json["cmd"] = "set"; + json["dev"] = "do"; + json["circuit"] = digitalOutputNumber; + json["value"] = stateValue; + + QJsonDocument doc(json); + QByteArray bytes = doc.toJson(); + m_webSocket->sendTextMessage(bytes); + return DeviceManager::DeviceErrorNoError; + } + return DeviceManager::DeviceErrorActionTypeNotFound; + } + + if (device->deviceClassId() == analogOutputDeviceClassId) { + + if (action.actionTypeId() == analogOutputAnalogOutputValueActionTypeId) { + int analogOutputNumber = device->paramValue(analogOutputAnalogOutputNumberParamTypeId).toInt(); + double analogValue = device->paramValue(analogOutputAnalogOutputValueStateParamTypeId).toDouble(); + + QJsonObject json; + json["cmd"] = "set"; + json["dev"] = "ao"; + json["circuit"] = analogOutputNumber; + json["value"] = analogValue; + + QJsonDocument doc(json); + QByteArray bytes = doc.toJson(); + m_webSocket->sendTextMessage(bytes); + return DeviceManager::DeviceErrorNoError; + } + return DeviceManager::DeviceErrorActionTypeNotFound; + } + return DeviceManager::DeviceErrorDeviceClassNotFound; +} + + +void DevicePluginUniPi::deviceRemoved(Device *device) +{ + Q_UNUSED(device); + + m_webSocket->close(); + m_webSocket->deleteLater(); +} + + +void DevicePluginUniPi::onWebSocketConnected() +{ + qDebug(dcUniPi()) << "WebSocket connected"; + + connect(m_webSocket, &QWebSocket::textMessageReceived, + this, &DevicePluginUniPi::onWebSocketTextMessageReceived); + + QJsonObject json; + json["cmd"] = "all"; + + QJsonDocument doc(json); + QByteArray bytes = doc.toJson(); + m_webSocket->sendTextMessage(bytes); +} + +void DevicePluginUniPi::onWebSocketDisconnected() +{ + qDebug(dcUniPi()) << "WebSocket disconnected"; + + //send signal device Setup was successfull +} + + +void DevicePluginUniPi::onWebSocketTextMessageReceived(QString message) +{ + QJsonArray array; + QJsonObject obj; + QJsonDocument doc = QJsonDocument::fromJson(message.toUtf8()); + + // check validity of the document + if(!doc.isNull()) { + if(doc.isObject()) { + obj = doc.object(); + } else if (doc.isArray()){ + array = doc.array(); + }else { + qDebug(dcUniPi()) << "Document is not an object nor an array"; + } + } else { + qDebug(dcUniPi()) << "Invalid JSON"; + } + + for (int levelIndex = 0; levelIndex < array.size(); ++levelIndex) { + obj = array[levelIndex].toObject(); + + if (obj["cmd"] == "all") { + //read model number + qDebug(dcUniPi()) << message; + + } + + if (obj["dev"] == "relay") { + qDebug(dcUniPi()) << "Relay:" << obj["dev"].toString() << "Circuit:" << obj["circuit"].toString() << "Value:" << obj["value"].toInt(); + + bool newDevice = true; + foreach (Device *device, myDevices()) { + if (device->deviceClassId() == relayOutputDeviceClassId) { + if (obj["circuit"] == device->paramValue(relayOutputRelayNumberParamTypeId).toString()) { + device->setStateValue(relayOutputRelayStatusStateTypeId, QVariant(obj["value"].toInt()).toBool()); + newDevice = false; + break; + } + } + } + if (newDevice) { + qDebug(dcUniPi()) << "New Device detected"; + createAutoDevice(GPIOType::relay, m_parentId, obj["circuit"].toString()); + } + } + + if (obj["dev"] == "input") { + qDebug(dcUniPi()) << "Input:" << obj["dev"].toString() << "Circuit:" << obj["circuit"].toString() << "Value:" << obj["value"].toInt(); + + bool newDevice = true; + foreach (Device *device, myDevices()) { + if (device->deviceClassId() == digitalInputDeviceClassId) { + if (obj["circuit"] == device->paramValue(digitalInputDigitalInputNumberParamTypeId).toString()) { + device->setStateValue(digitalInputDigitalInputStatusStateTypeId, QVariant(obj["value"].toInt()).toBool()); + newDevice = false; + break; + } + } + } + if (newDevice){ + //New Device detected + createAutoDevice(GPIOType::digitalInput, m_parentId, obj["circuit"].toString()); + } + } + + if (obj["dev"] == "output") { + qDebug(dcUniPi()) << "Output:" << obj["dev"].toString() << "Circuit:" << obj["circuit"].toString() << "Value:" << obj["value"].toInt(); + + bool newDevice = true; + foreach (Device *device, myDevices()) { + if (device->deviceClassId() == digitalOutputDeviceClassId) { + + if (obj["circuit"] == device->paramValue(digitalOutputDigitalOutputNumberParamTypeId).toString()) { + device->setStateValue(digitalOutputDigitalOutputStatusStateTypeId, QVariant(obj["value"].toInt()).toBool()); + newDevice = false; + break; + } + } + } + if (newDevice){ + //New Device detected + createAutoDevice(GPIOType::digitalOutput, m_parentId, obj["circuit"].toString()); + } + } + + if (obj["dev"] == "ao") { + qDebug(dcUniPi()) << "Analog Output:" << obj["dev"] << "Circuit:" << obj["circuit"].toString() << "Value:" << obj["value"].toDouble(); + + bool newDevice = true; + foreach (Device *device, myDevices()) { + if (device->deviceClassId() == analogOutputDeviceClassId) { + + if (obj["circuit"] == device->paramValue(analogOutputAnalogOutputNumberParamTypeId).toString()) { + device->setStateValue(analogOutputAnalogOutputValueStateTypeId, obj["value"].toDouble()); + newDevice = false; + break; + } + } + } + if (newDevice){ + //New Device detected + createAutoDevice(GPIOType::analogOutput, m_parentId, obj["circuit"].toString()); + } + } + + if (obj["dev"] == "ai") { + qDebug(dcUniPi()) << "Analog Input:" << obj["dev"] << "Circuit:" << obj["circuit"].toString() << "Value:" << obj["value"].toDouble(); + + bool newDevice = true; + foreach (Device *device, myDevices()) { + if (device->deviceClassId() == analogInputDeviceClassId) { + + if (obj["circuit"] == device->paramValue(analogInputAnalogInputNumberParamTypeId).toString()) { + device->setStateValue(analogInputAnalogInputValueStateTypeId, obj["value"].toDouble()); + newDevice = false; + break; + } + } + } + if (newDevice){ + //New Device detected + createAutoDevice(GPIOType::analogInput, m_parentId, obj["circuit"].toString()); + } + } + } +} + diff --git a/unipi/devicepluginunipi.h b/unipi/devicepluginunipi.h new file mode 100644 index 00000000..da7798a8 --- /dev/null +++ b/unipi/devicepluginunipi.h @@ -0,0 +1,66 @@ +/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * + * * + * Copyright (C) 2017 Bernhard Trinnes * + * * + * 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 DEVICEPLUGINUNIPI_H +#define DEVICEPLUGINUNIPI_H + +#include "plugin/deviceplugin.h" +#include "devicemanager.h" +#include + +class DevicePluginUniPi : public DevicePlugin +{ + Q_OBJECT + + Q_PLUGIN_METADATA(IID "guru.guh.DevicePlugin" FILE "devicepluginunipi.json") + Q_INTERFACES(DevicePlugin) + +public: + + explicit DevicePluginUniPi(); + + DeviceManager::DeviceSetupStatus setupDevice(Device *device) override; + void postSetupDevice(Device *device) override; + void deviceRemoved(Device *device) override; + void init() override; + DeviceManager::DeviceError executeAction(Device *device, const Action &action) override; + +private: + + enum GPIOType { + relay, + digitalInput, + digitalOutput, + analogInput, + analogOutput + }; + + DeviceId m_parentId; + QWebSocket *m_webSocket; + + void createAutoDevice(GPIOType gpioType, DeviceId parentDeviceId, QString deviceName); + +private slots: + void onWebSocketConnected(); + void onWebSocketDisconnected(); + void onWebSocketTextMessageReceived(QString message); +}; + +#endif // DEVICEPLUGINUNIPI_H diff --git a/unipi/devicepluginunipi.json b/unipi/devicepluginunipi.json new file mode 100644 index 00000000..1e3da1f2 --- /dev/null +++ b/unipi/devicepluginunipi.json @@ -0,0 +1,224 @@ +{ + "displayName": "uni pi", + "name": "UniPi", + "id": "26cba644-35ae-40a6-9c48-924198893a5f", + "vendors": [ + { + "displayName": "UniPi", + "name": "unipi", + "id": "c82bfe27-d14d-40bd-b12f-ddba214b5fc5", + "deviceClasses": [ + { + "id": "f1663756-657d-4dbd-9568-e2edf513589f", + "name": "neuron", + "displayName": "Neuron", + "deviceIcon": "Gateway", + "createMethods": ["user"], + "interface": [], + "basicTags": [ + "Device", + "Gateway" + ], + "paramTypes": [ + { + "id": "5329655d-7e91-4b16-9abf-2abc82bf1b3c", + "name": "port", + "displayName": "port", + "type": "int", + "defaultValue": "8080" + } + ], + "actionTypes": [ + ], + "stateTypes": [ + ] + }, + { + "id": "58f9db7f-fd33-45af-8c98-047b67ae5267", + "name": "relayOutput", + "displayName": "Relay Output", + "deviceIcon": "Power", + "createMethods": ["auto"], + "interface": [], + "basicTags": [ + "Device" + ], + "paramTypes": [ + { + "id": "7a09e3ad-452c-4bf4-a00c-f8114ed9a7a1", + "name": "relayNumber", + "displayName": "relay number", + "type": "QString" + }, + { + "id": "ebbf4c9c-25a9-45c1-be72-cc01aaea959c", + "name": "parentId", + "displayName": "parent ID", + "type": "QString" + } + ], + "stateTypes": [ + { + "id": "f9c01e7b-0523-4cac-905a-d5b20028e021", + "name": "relayStatus", + "displayName": "relay", + "type": "bool", + "displayNameAction": "set relay", + "displayNameEvent": "relay changed", + "defaultValue": false, + "writable": true + } + ] + }, + { + "id": "0bec278a-98f1-416b-b496-6d00740f178a", + "name": "digitalInput", + "displayName": "digital input", + "deviceIcon": "Switch", + "createMethods": ["auto"], + "interface": [], + "basicTags": [ + "Sensor" + ], + "paramTypes": [ + { + "id": "9c84d9b8-fdc7-41c1-9559-08f061ffc7a6", + "name": "digitalInputNumber", + "displayName": "input number", + "type": "int" + }, + { + "id": "ebbf4c9c-25a9-45c1-be72-cc01aaea959c", + "name": "parentId", + "displayName": "parent ID", + "type": "QString" + } + ], + "stateTypes": [ + { + "id": "fa4f2764-b7ff-45e7-993b-b6af1840fd3d", + "name": "digitalInputStatus", + "displayName": "input", + "type": "bool", + "defaultValue": false, + "displayNameEvent": "input changed" + } + ] + }, + { + "id": "f3a3c5ed-461a-4ca8-930b-df3af821b9e0", + "name": "digitalOutput", + "displayName": "digital output", + "deviceIcon": "Power", + "createMethods": ["auto"], + "interface": [], + "basicTags": [ + "Device" + ], + "paramTypes": [ + { + "id": "c01d5bde-de5d-42c5-b462-79745827875a", + "name": "digitalOutputNumber", + "displayName": "input number", + "type": "QString" + }, + { + "id": "ebbf4c9c-25a9-45c1-be72-cc01aaea959c", + "name": "parentId", + "displayName": "parent ID", + "type": "QString" + } + ], + "stateTypes": [ + { + "id": "470a0e30-a170-47ed-9ed3-c41db919555f", + "name": "digitalOutputStatus", + "displayName": "digital output", + "type": "bool", + "displayNameAction": "set digital output", + "displayNameEvent": "digital output changed", + "defaultValue": false, + "writable": true + } + ] + }, + { + "id": "9094a69f-f475-4050-a345-5ab52cb19774", + "name": "analogOutput", + "displayName": "Analog Output", + "deviceIcon": "Power", + "createMethods": ["auto"], + "interface": [], + "basicTags": [ + "Device" + ], + "paramTypes": [ + { + "id": "46e606cc-67ee-4891-bc39-8fb0565c87da", + "name": "analogOutputNumber", + "displayName": "analog output number", + "type": "QString" + }, + { + "id": "ebbf4c9c-25a9-45c1-be72-cc01aaea959c", + "name": "parentId", + "displayName": "parent ID", + "type": "QString" + } + ], + "stateTypes": [ + { + "id": "6d825eb8-6d2a-4ac3-9125-9df8173116c9", + "name": "analogOutputValue", + "displayName": "analog output", + "type": "double", + "unit": "Volt", + "displayNameAction": "set analog output", + "displayNameEvent": "analog output changed", + "minValue": 0.00, + "maxValue": 10.00, + "defaultValue": 0.00, + "writable": true + } + ] + }, + { + "id": "06abd6a4-e655-4243-bc9c-9bd4ef5be2e6", + "name": "analogInput", + "displayName": "Analog Input", + "deviceIcon": "Power", + "createMethods": ["auto"], + "interface": [], + "basicTags": [ + "Sensor" + ], + "paramTypes": [ + { + "id": "cc6eb664-9fd2-457d-9d0d-0eb9703db4a2", + "name": "analogInputNumber", + "displayName": "analog input number", + "type": "QString" + }, + { + "id": "ebbf4c9c-25a9-45c1-be72-cc01aaea959c", + "name": "parentId", + "displayName": "parent ID", + "type": "QString" + } + ], + "stateTypes": [ + { + "id": "2296f575-cc53-48ef-9086-6a412abfdde5", + "name": "analogInputValue", + "displayName": "analog output", + "type": "double", + "unit": "Volt", + "displayNameEvent": "analog input changed", + "defaultValue": 0.00 + } + ] + } + ] + } + ] +} diff --git a/unipi/unipi.pro b/unipi/unipi.pro new file mode 100644 index 00000000..94d4be58 --- /dev/null +++ b/unipi/unipi.pro @@ -0,0 +1,11 @@ +include(../plugins.pri) + +TARGET = $$qtLibraryTarget(guh_devicepluginunipi) + +SOURCES += \ + devicepluginunipi.cpp \ + +HEADERS += \ + devicepluginunipi.h \ + +